46# pragma fenv_access(on)
117 return expr !=
nullptr && expr->
ops.
size() > 0;
129 if (expr ==
nullptr) {
149 const double *param_values,
150 int param_values_len,
159#define FAIL_IF(condition) \
161 return EXPR_PYLIKE_FATAL_ERROR; \
174 feclearexcept(FE_ALL_EXCEPT);
176 for (pc = 0; pc >= 0 && pc < expr->
ops.
size(); pc++) {
177 switch (ops[pc].opcode) {
181 stack[sp++] = ops[pc].
arg.
dval;
185 stack[sp++] = param_values[ops[pc].
arg.
ival];
189 stack[sp - 1] = ops[pc].arg.func1(stack[sp - 1]);
193 stack[sp - 2] = ops[pc].arg.func2(stack[sp - 2], stack[sp - 1]);
198 stack[sp - 3] = ops[pc].arg.func3(stack[sp - 3], stack[sp - 2], stack[sp - 1]);
202 FAIL_IF(sp < ops[pc].arg.ival);
203 for (
int j = 1; j < ops[pc].arg.ival; j++, sp--) {
208 FAIL_IF(sp < ops[pc].arg.ival);
209 for (
int j = 1; j < ops[pc].arg.ival; j++, sp--) {
216 pc += ops[pc].jmp_offset;
221 pc += ops[pc].jmp_offset;
228 pc += ops[pc].jmp_offset;
239 if (!ops[pc].arg.func2(stack[sp - 2], stack[sp - 1])) {
241 pc += ops[pc].jmp_offset;
245 stack[sp - 2] = stack[sp - 1];
259 *r_result = stack[0];
262 int flags = fetestexcept(FE_DIVBYZERO | FE_INVALID);
303 return arg *
M_PI / 180.0;
308 return arg * 180.0 /
M_PI;
318 return a * (1.0 -
x) +
b *
x;
323 CLAMP(arg, 0.0, 1.0);
327static double op_clamp3(
double arg,
double minv,
double maxv)
329 CLAMP(arg, minv, maxv);
335 double t = (
x - a) / (
b - a);
337 return t * t * (3.0 - 2.0 * t);
342 return a ? 0.0 : 1.0;
347 return a ==
b ? 1.0 : 0.0;
352 return a !=
b ? 1.0 : 0.0;
357 return a <
b ? 1.0 : 0.0;
362 return a <=
b ? 1.0 : 0.0;
367 return a >
b ? 1.0 : 0.0;
372 return a >=
b ? 1.0 : 0.0;
381 {
"pi",
M_PI}, {
"True", 1.0}, {
"False", 0.0}, {
nullptr, 0.0}};
385 std::variant<UnaryOpFunc, BinaryOpFunc, TernaryOpFunc>
funcptr;
390 if (std::holds_alternative<UnaryOpFunc>(
funcptr)) {
393 if (std::holds_alternative<BinaryOpFunc>(
funcptr)) {
396 if (std::holds_alternative<TernaryOpFunc>(
funcptr)) {
408# pragma function(ceil)
409# pragma function(floor)
448#define MAKE_CHAR2(a, b) (((a) << 8) | (b))
450#define CHECK_ERROR(condition) \
451 if (!(condition)) { \
458#define TOKEN_ID MAKE_CHAR2('I', 'D')
459#define TOKEN_NUMBER MAKE_CHAR2('0', '0')
460#define TOKEN_GE MAKE_CHAR2('>', '=')
461#define TOKEN_LE MAKE_CHAR2('<', '=')
462#define TOKEN_NE MAKE_CHAR2('!', '=')
463#define TOKEN_EQ MAKE_CHAR2('=', '=')
464#define TOKEN_AND MAKE_CHAR2('A', 'N')
465#define TOKEN_OR MAKE_CHAR2('O', 'R')
466#define TOKEN_NOT MAKE_CHAR2('N', 'O')
467#define TOKEN_IF MAKE_CHAR2('I', 'F')
468#define TOKEN_ELSE MAKE_CHAR2('E', 'L')
493 const char *
cur =
nullptr;
513 state->stack_ptr += stack_delta;
519 state->ops.append(op);
520 return &
state->ops.last();
539 std::variant<UnaryOpFunc, BinaryOpFunc, TernaryOpFunc> funcptr)
542 int jmp_gap =
state->ops.size() -
state->last_jmp;
544 feclearexcept(FE_ALL_EXCEPT);
546 if (std::holds_alternative<UnaryOpFunc>(funcptr)) {
549 if (jmp_gap >= 1 && prev_ops[-1].opcode ==
OPCODE_CONST) {
552 volatile double result = func(prev_ops[-1].arg.
dval);
554 if (fetestexcept(FE_DIVBYZERO | FE_INVALID) == 0) {
562 else if (std::holds_alternative<BinaryOpFunc>(funcptr)) {
571 if (fetestexcept(FE_DIVBYZERO | FE_INVALID) == 0) {
581 else if (std::holds_alternative<TernaryOpFunc>(funcptr)) {
584 if (jmp_gap >= 3 && prev_ops[-3].opcode ==
OPCODE_CONST &&
589 volatile double result = func(
592 if (fetestexcept(FE_DIVBYZERO | FE_INVALID) == 0) {
595 state->stack_ptr -= 2;
614 while (isspace(*
state->cur)) {
619 if (*
state->cur == 0) {
625 if (isdigit(*
state->cur) || (
state->cur[0] ==
'.' && isdigit(
state->cur[1]))) {
626 char *end, *
out =
state->tokenbuf.data();
627 bool is_float =
false;
629 while (isdigit(*
state->cur)) {
633 if (*
state->cur ==
'.') {
637 while (isdigit(*
state->cur)) {
652 while (isdigit(*
state->cur)) {
660 if (!is_float &&
state->tokenbuf[0] ==
'0') {
661 for (
char *p =
state->tokenbuf.data() + 1; *p; p++) {
669 state->tokenval = strtod(
state->tokenbuf.data(), &end);
733 switch (
state->token) {
756 switch (
state->token) {
776 for (
i =
state->param_names_len - 1;
i >= 0;
i--) {
843 switch (
state->token) {
865 switch (
state->token) {
981 int prev_last_jmp =
state->last_jmp;
982 int start =
state->last_jmp =
state->ops.size();
989 const int size =
state->ops.size() - start;
994 state->ops.resize(start);
995 state->last_jmp = start;
1008 const size_t body_offset =
state->ops.size();
1010 std::copy_n(body.
data(),
size,
state->ops.data() + body_offset);
1025 else if (
state->last_jmp == start) {
1026 state->last_jmp = prev_last_jmp;
1039 const char **param_names,
1040 int param_names_len)
1047 state.param_names_len = param_names_len;
1048 state.param_names = param_names;
1050 state.tokenbuf.resize(strlen(expression) + 1);
1053 ExprPyLike_Parsed *expr = MEM_new<ExprPyLike_Parsed>(
"ExprPyLike_Parsed(empty)");
#define BLI_array_alloca(arr, realsize)
#define BLI_assert_msg(a, msg)
@ EXPR_PYLIKE_FATAL_ERROR
@ EXPR_PYLIKE_DIV_BY_ZERO
Read Guarded memory(de)allocation.
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
void jump(const btVector3 &v=btVector3(0, 0, 0))
double(*)(double, double, double) TernaryOpFunc
static double op_negate(double arg)
static bool parse_next_token(ExprParseState *state)
static double op_clamp3(double arg, double minv, double maxv)
static int parse_add_jump(ExprParseState *state, eOpCode code)
static double op_lt(double a, double b)
static int parse_function_args(ExprParseState *state)
static BinaryOpFunc parse_get_cmp_func(short token)
static bool parse_mul(ExprParseState *state)
static double op_smoothstep(double a, double b, double x)
static double op_mul(double a, double b)
static BuiltinOpDef builtin_ops[]
static bool parse_add_func(ExprParseState *state, std::variant< UnaryOpFunc, BinaryOpFunc, TernaryOpFunc > funcptr)
static bool parse_and(ExprParseState *state)
void BLI_expr_pylike_free(ExprPyLike_Parsed *expr)
static bool parse_expr(ExprParseState *state)
static const char * token_characters
eExprPyLike_EvalStatus BLI_expr_pylike_eval(ExprPyLike_Parsed *expr, const double *param_values, int param_values_len, double *r_result)
static bool parse_add(ExprParseState *state)
static double op_gt(double a, double b)
#define FAIL_IF(condition)
static double op_ne(double a, double b)
#define CHECK_ERROR(condition)
static BuiltinConstDef builtin_consts[]
static double op_div(double a, double b)
static double op_eq(double a, double b)
static void parse_set_jump(ExprParseState *state, int jump)
bool BLI_expr_pylike_is_constant(const ExprPyLike_Parsed *expr)
static double op_lerp(double a, double b, double x)
static ExprOp * parse_add_op(ExprParseState *state, eOpCode code, int stack_delta)
static bool parse_unary(ExprParseState *state)
static bool parse_not(ExprParseState *state)
static double op_le(double a, double b)
static const char * token_eq_characters
static double op_ge(double a, double b)
double(*)(double, double) BinaryOpFunc
static double op_add(double a, double b)
static double op_not(double a)
bool BLI_expr_pylike_is_using_param(const ExprPyLike_Parsed *expr, int index)
bool BLI_expr_pylike_is_valid(const ExprPyLike_Parsed *expr)
static double op_sub(double a, double b)
ExprPyLike_Parsed * BLI_expr_pylike_parse(const char *expression, const char **param_names, int param_names_len)
static double op_degrees(double arg)
static double op_log2(double a, double b)
static bool parse_cmp_chain(ExprParseState *state, BinaryOpFunc cur_func)
static KeywordTokenDef keyword_list[]
static double op_clamp(double arg)
double(*)(double) UnaryOpFunc
static double op_radians(double arg)
static bool parse_cmp(ExprParseState *state)
static bool parse_or(ExprParseState *state)
ccl_device_inline float2 fmod(const float2 a, const float b)
ccl_device_inline float2 fabs(const float2 a)
ccl_device_inline float3 atan2(const float3 y, const float3 x)
std::variant< UnaryOpFunc, BinaryOpFunc, TernaryOpFunc > funcptr
union ExprOp::@022142020106211234351036361136331370136343206132 arg
blender::Vector< ExprOp > ops
blender::Vector< char > tokenbuf
const char ** param_names
blender::Vector< ExprOp > ops