diff options
author | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:17:24 +0300 |
---|---|---|
committer | Campbell Barton <ideasman42@gmail.com> | 2019-04-17 07:21:24 +0300 |
commit | e12c08e8d170b7ca40f204a5b0423c23a9fbc2c1 (patch) | |
tree | 8cf3453d12edb177a218ef8009357518ec6cab6a /source/blender/blenlib/intern/expr_pylike_eval.c | |
parent | b3dabc200a4b0399ec6b81f2ff2730d07b44fcaa (diff) |
ClangFormat: apply to source, most of intern
Apply clang format as proposed in T53211.
For details on usage and instructions for migrating branches
without conflicts, see:
https://wiki.blender.org/wiki/Tools/ClangFormat
Diffstat (limited to 'source/blender/blenlib/intern/expr_pylike_eval.c')
-rw-r--r-- | source/blender/blenlib/intern/expr_pylike_eval.c | 1238 |
1 files changed, 618 insertions, 620 deletions
diff --git a/source/blender/blenlib/intern/expr_pylike_eval.c b/source/blender/blenlib/intern/expr_pylike_eval.c index 51a004f846f..40df9711ef1 100644 --- a/source/blender/blenlib/intern/expr_pylike_eval.c +++ b/source/blender/blenlib/intern/expr_pylike_eval.c @@ -58,7 +58,7 @@ #include "BLI_alloca.h" #ifdef _MSC_VER -#pragma fenv_access (on) +# pragma fenv_access(on) #endif /* -------------------------------------------------------------------- */ @@ -66,52 +66,52 @@ * \{ */ typedef enum eOpCode { - /* Double constant: (-> dval) */ - OPCODE_CONST, - /* 1 argument function call: (a -> func1(a)) */ - OPCODE_FUNC1, - /* 2 argument function call: (a b -> func2(a,b)) */ - OPCODE_FUNC2, - /* Parameter access: (-> params[ival]) */ - OPCODE_PARAMETER, - /* Minimum of multiple inputs: (a b c... -> min); ival = arg count */ - OPCODE_MIN, - /* Maximum of multiple inputs: (a b c... -> max); ival = arg count */ - OPCODE_MAX, - /* Jump (pc += jmp_offset) */ - OPCODE_JMP, - /* Pop and jump if zero: (a -> ); JUMP IF NOT a */ - OPCODE_JMP_ELSE, - /* Jump if nonzero, or pop: (a -> a JUMP) IF a ELSE (a -> ) */ - OPCODE_JMP_OR, - /* Jump if zero, or pop: (a -> a JUMP) IF NOT a ELSE (a -> ) */ - OPCODE_JMP_AND, - /* For comparison chaining: (a b -> 0 JUMP) IF NOT func2(a,b) ELSE (a b -> b) */ - OPCODE_CMP_CHAIN, + /* Double constant: (-> dval) */ + OPCODE_CONST, + /* 1 argument function call: (a -> func1(a)) */ + OPCODE_FUNC1, + /* 2 argument function call: (a b -> func2(a,b)) */ + OPCODE_FUNC2, + /* Parameter access: (-> params[ival]) */ + OPCODE_PARAMETER, + /* Minimum of multiple inputs: (a b c... -> min); ival = arg count */ + OPCODE_MIN, + /* Maximum of multiple inputs: (a b c... -> max); ival = arg count */ + OPCODE_MAX, + /* Jump (pc += jmp_offset) */ + OPCODE_JMP, + /* Pop and jump if zero: (a -> ); JUMP IF NOT a */ + OPCODE_JMP_ELSE, + /* Jump if nonzero, or pop: (a -> a JUMP) IF a ELSE (a -> ) */ + OPCODE_JMP_OR, + /* Jump if zero, or pop: (a -> a JUMP) IF NOT a ELSE (a -> ) */ + OPCODE_JMP_AND, + /* For comparison chaining: (a b -> 0 JUMP) IF NOT func2(a,b) ELSE (a b -> b) */ + OPCODE_CMP_CHAIN, } eOpCode; typedef double (*UnaryOpFunc)(double); typedef double (*BinaryOpFunc)(double, double); typedef struct ExprOp { - eOpCode opcode; + eOpCode opcode; - int jmp_offset; + int jmp_offset; - union { - int ival; - double dval; - void *ptr; - UnaryOpFunc func1; - BinaryOpFunc func2; - } arg; + union { + int ival; + double dval; + void *ptr; + UnaryOpFunc func1; + BinaryOpFunc func2; + } arg; } ExprOp; struct ExprPyLike_Parsed { - int ops_count; - int max_stack; + int ops_count; + int max_stack; - ExprOp ops[]; + ExprOp ops[]; }; /** \} */ @@ -123,21 +123,21 @@ struct ExprPyLike_Parsed { /** Free the parsed data; NULL argument is ok. */ void BLI_expr_pylike_free(ExprPyLike_Parsed *expr) { - if (expr != NULL) { - MEM_freeN(expr); - } + if (expr != NULL) { + MEM_freeN(expr); + } } /** Check if the parsing result is valid for evaluation. */ bool BLI_expr_pylike_is_valid(ExprPyLike_Parsed *expr) { - return expr != NULL && expr->ops_count > 0; + return expr != NULL && expr->ops_count > 0; } /** Check if the parsed expression always evaluates to the same value. */ bool BLI_expr_pylike_is_constant(ExprPyLike_Parsed *expr) { - return expr != NULL && expr->ops_count == 1 && expr->ops[0].opcode == OPCODE_CONST; + return expr != NULL && expr->ops_count == 1 && expr->ops[0].opcode == OPCODE_CONST; } /** \} */ @@ -150,117 +150,120 @@ bool BLI_expr_pylike_is_constant(ExprPyLike_Parsed *expr) * Evaluate the expression with the given parameters. * The order and number of parameters must match the names given to parse. */ -eExprPyLike_EvalStatus BLI_expr_pylike_eval( - ExprPyLike_Parsed *expr, - const double *param_values, int param_values_len, - double *r_result) -{ - *r_result = 0.0; - - if (!BLI_expr_pylike_is_valid(expr)) { - return EXPR_PYLIKE_INVALID; - } - -#define FAIL_IF(condition) if (condition) { return EXPR_PYLIKE_FATAL_ERROR; } - - /* Check the stack requirement is at least remotely sane and allocate on the actual stack. */ - FAIL_IF(expr->max_stack <= 0 || expr->max_stack > 1000); - - double *stack = BLI_array_alloca(stack, expr->max_stack); - - /* Evaluate expression. */ - ExprOp *ops = expr->ops; - int sp = 0, pc; - - feclearexcept(FE_ALL_EXCEPT); - - for (pc = 0; pc >= 0 && pc < expr->ops_count; pc++) { - switch (ops[pc].opcode) { - /* Arithmetic */ - case OPCODE_CONST: - FAIL_IF(sp >= expr->max_stack); - stack[sp++] = ops[pc].arg.dval; - break; - case OPCODE_PARAMETER: - FAIL_IF(sp >= expr->max_stack || ops[pc].arg.ival >= param_values_len); - stack[sp++] = param_values[ops[pc].arg.ival]; - break; - case OPCODE_FUNC1: - FAIL_IF(sp < 1); - stack[sp - 1] = ops[pc].arg.func1(stack[sp - 1]); - break; - case OPCODE_FUNC2: - FAIL_IF(sp < 2); - stack[sp - 2] = ops[pc].arg.func2(stack[sp - 2], stack[sp - 1]); - sp--; - break; - case OPCODE_MIN: - FAIL_IF(sp < ops[pc].arg.ival); - for (int j = 1; j < ops[pc].arg.ival; j++, sp--) { - CLAMP_MAX(stack[sp - 2], stack[sp - 1]); - } - break; - case OPCODE_MAX: - FAIL_IF(sp < ops[pc].arg.ival); - for (int j = 1; j < ops[pc].arg.ival; j++, sp--) { - CLAMP_MIN(stack[sp - 2], stack[sp - 1]); - } - break; - - /* Jumps */ - case OPCODE_JMP: - pc += ops[pc].jmp_offset; - break; - case OPCODE_JMP_ELSE: - FAIL_IF(sp < 1); - if (!stack[--sp]) { - pc += ops[pc].jmp_offset; - } - break; - case OPCODE_JMP_OR: - case OPCODE_JMP_AND: - FAIL_IF(sp < 1); - if (!stack[sp - 1] == !(ops[pc].opcode == OPCODE_JMP_OR)) { - pc += ops[pc].jmp_offset; - } - else { - sp--; - } - break; - - /* For chaining comparisons, i.e. "a < b < c" as "a < b and b < c" */ - case OPCODE_CMP_CHAIN: - FAIL_IF(sp < 2); - /* If comparison fails, return 0 and jump to end. */ - if (!ops[pc].arg.func2(stack[sp - 2], stack[sp - 1])) { - stack[sp - 2] = 0.0; - pc += ops[pc].jmp_offset; - } - /* Otherwise keep b on the stack and proceed. */ - else { - stack[sp - 2] = stack[sp - 1]; - } - sp--; - break; - - default: - return EXPR_PYLIKE_FATAL_ERROR; - } - } - - FAIL_IF(sp != 1 || pc != expr->ops_count); +eExprPyLike_EvalStatus BLI_expr_pylike_eval(ExprPyLike_Parsed *expr, + const double *param_values, + int param_values_len, + double *r_result) +{ + *r_result = 0.0; + + if (!BLI_expr_pylike_is_valid(expr)) { + return EXPR_PYLIKE_INVALID; + } + +#define FAIL_IF(condition) \ + if (condition) { \ + return EXPR_PYLIKE_FATAL_ERROR; \ + } + + /* Check the stack requirement is at least remotely sane and allocate on the actual stack. */ + FAIL_IF(expr->max_stack <= 0 || expr->max_stack > 1000); + + double *stack = BLI_array_alloca(stack, expr->max_stack); + + /* Evaluate expression. */ + ExprOp *ops = expr->ops; + int sp = 0, pc; + + feclearexcept(FE_ALL_EXCEPT); + + for (pc = 0; pc >= 0 && pc < expr->ops_count; pc++) { + switch (ops[pc].opcode) { + /* Arithmetic */ + case OPCODE_CONST: + FAIL_IF(sp >= expr->max_stack); + stack[sp++] = ops[pc].arg.dval; + break; + case OPCODE_PARAMETER: + FAIL_IF(sp >= expr->max_stack || ops[pc].arg.ival >= param_values_len); + stack[sp++] = param_values[ops[pc].arg.ival]; + break; + case OPCODE_FUNC1: + FAIL_IF(sp < 1); + stack[sp - 1] = ops[pc].arg.func1(stack[sp - 1]); + break; + case OPCODE_FUNC2: + FAIL_IF(sp < 2); + stack[sp - 2] = ops[pc].arg.func2(stack[sp - 2], stack[sp - 1]); + sp--; + break; + case OPCODE_MIN: + FAIL_IF(sp < ops[pc].arg.ival); + for (int j = 1; j < ops[pc].arg.ival; j++, sp--) { + CLAMP_MAX(stack[sp - 2], stack[sp - 1]); + } + break; + case OPCODE_MAX: + FAIL_IF(sp < ops[pc].arg.ival); + for (int j = 1; j < ops[pc].arg.ival; j++, sp--) { + CLAMP_MIN(stack[sp - 2], stack[sp - 1]); + } + break; + + /* Jumps */ + case OPCODE_JMP: + pc += ops[pc].jmp_offset; + break; + case OPCODE_JMP_ELSE: + FAIL_IF(sp < 1); + if (!stack[--sp]) { + pc += ops[pc].jmp_offset; + } + break; + case OPCODE_JMP_OR: + case OPCODE_JMP_AND: + FAIL_IF(sp < 1); + if (!stack[sp - 1] == !(ops[pc].opcode == OPCODE_JMP_OR)) { + pc += ops[pc].jmp_offset; + } + else { + sp--; + } + break; + + /* For chaining comparisons, i.e. "a < b < c" as "a < b and b < c" */ + case OPCODE_CMP_CHAIN: + FAIL_IF(sp < 2); + /* If comparison fails, return 0 and jump to end. */ + if (!ops[pc].arg.func2(stack[sp - 2], stack[sp - 1])) { + stack[sp - 2] = 0.0; + pc += ops[pc].jmp_offset; + } + /* Otherwise keep b on the stack and proceed. */ + else { + stack[sp - 2] = stack[sp - 1]; + } + sp--; + break; + + default: + return EXPR_PYLIKE_FATAL_ERROR; + } + } + + FAIL_IF(sp != 1 || pc != expr->ops_count); #undef FAIL_IF - *r_result = stack[0]; + *r_result = stack[0]; - /* Detect floating point evaluation errors. */ - int flags = fetestexcept(FE_DIVBYZERO | FE_INVALID); - if (flags) { - return (flags & FE_INVALID) ? EXPR_PYLIKE_MATH_ERROR : EXPR_PYLIKE_DIV_BY_ZERO; - } + /* Detect floating point evaluation errors. */ + int flags = fetestexcept(FE_DIVBYZERO | FE_INVALID); + if (flags) { + return (flags & FE_INVALID) ? EXPR_PYLIKE_MATH_ERROR : EXPR_PYLIKE_DIV_BY_ZERO; + } - return EXPR_PYLIKE_SUCCESS; + return EXPR_PYLIKE_SUCCESS; } /** \} */ @@ -271,115 +274,109 @@ eExprPyLike_EvalStatus BLI_expr_pylike_eval( static double op_negate(double arg) { - return -arg; + return -arg; } static double op_mul(double a, double b) { - return a * b; + return a * b; } static double op_div(double a, double b) { - return a / b; + return a / b; } static double op_add(double a, double b) { - return a + b; + return a + b; } static double op_sub(double a, double b) { - return a - b; + return a - b; } static double op_radians(double arg) { - return arg * M_PI / 180.0; + return arg * M_PI / 180.0; } static double op_degrees(double arg) { - return arg * 180.0 / M_PI; + return arg * 180.0 / M_PI; } static double op_not(double a) { - return a ? 0.0 : 1.0; + return a ? 0.0 : 1.0; } static double op_eq(double a, double b) { - return a == b ? 1.0 : 0.0; + return a == b ? 1.0 : 0.0; } static double op_ne(double a, double b) { - return a != b ? 1.0 : 0.0; + return a != b ? 1.0 : 0.0; } static double op_lt(double a, double b) { - return a < b ? 1.0 : 0.0; + return a < b ? 1.0 : 0.0; } static double op_le(double a, double b) { - return a <= b ? 1.0 : 0.0; + return a <= b ? 1.0 : 0.0; } static double op_gt(double a, double b) { - return a > b ? 1.0 : 0.0; + return a > b ? 1.0 : 0.0; } static double op_ge(double a, double b) { - return a >= b ? 1.0 : 0.0; + return a >= b ? 1.0 : 0.0; } typedef struct BuiltinConstDef { - const char *name; - double value; + const char *name; + double value; } BuiltinConstDef; static BuiltinConstDef builtin_consts[] = { - { "pi", M_PI }, - { "True", 1.0 }, - { "False", 0.0 }, - { NULL, 0.0 } -}; + {"pi", M_PI}, {"True", 1.0}, {"False", 0.0}, {NULL, 0.0}}; typedef struct BuiltinOpDef { - const char *name; - eOpCode op; - void *funcptr; + const char *name; + eOpCode op; + void *funcptr; } BuiltinOpDef; -static BuiltinOpDef builtin_ops[] = { - { "radians", OPCODE_FUNC1, op_radians }, - { "degrees", OPCODE_FUNC1, op_degrees }, - { "abs", OPCODE_FUNC1, fabs }, - { "fabs", OPCODE_FUNC1, fabs }, - { "floor", OPCODE_FUNC1, floor }, - { "ceil", OPCODE_FUNC1, ceil }, - { "trunc", OPCODE_FUNC1, trunc }, - { "int", OPCODE_FUNC1, trunc }, - { "sin", OPCODE_FUNC1, sin }, - { "cos", OPCODE_FUNC1, cos }, - { "tan", OPCODE_FUNC1, tan }, - { "asin", OPCODE_FUNC1, asin }, - { "acos", OPCODE_FUNC1, acos }, - { "atan", OPCODE_FUNC1, atan }, - { "atan2", OPCODE_FUNC2, atan2 }, - { "exp", OPCODE_FUNC1, exp }, - { "log", OPCODE_FUNC1, log }, - { "sqrt", OPCODE_FUNC1, sqrt }, - { "pow", OPCODE_FUNC2, pow }, - { "fmod", OPCODE_FUNC2, fmod }, - { NULL, OPCODE_CONST, NULL } -}; +static BuiltinOpDef builtin_ops[] = {{"radians", OPCODE_FUNC1, op_radians}, + {"degrees", OPCODE_FUNC1, op_degrees}, + {"abs", OPCODE_FUNC1, fabs}, + {"fabs", OPCODE_FUNC1, fabs}, + {"floor", OPCODE_FUNC1, floor}, + {"ceil", OPCODE_FUNC1, ceil}, + {"trunc", OPCODE_FUNC1, trunc}, + {"int", OPCODE_FUNC1, trunc}, + {"sin", OPCODE_FUNC1, sin}, + {"cos", OPCODE_FUNC1, cos}, + {"tan", OPCODE_FUNC1, tan}, + {"asin", OPCODE_FUNC1, asin}, + {"acos", OPCODE_FUNC1, acos}, + {"atan", OPCODE_FUNC1, atan}, + {"atan2", OPCODE_FUNC2, atan2}, + {"exp", OPCODE_FUNC1, exp}, + {"log", OPCODE_FUNC1, log}, + {"sqrt", OPCODE_FUNC1, sqrt}, + {"pow", OPCODE_FUNC2, pow}, + {"fmod", OPCODE_FUNC2, fmod}, + {NULL, OPCODE_CONST, NULL}}; /** \} */ @@ -389,250 +386,252 @@ static BuiltinOpDef builtin_ops[] = { #define MAKE_CHAR2(a, b) (((a) << 8) | (b)) -#define CHECK_ERROR(condition) if (!(condition)) { return false; } +#define CHECK_ERROR(condition) \ + if (!(condition)) { \ + return false; \ + } /* For simplicity simple token types are represented by their own character; * these are special identifiers for multi-character tokens. */ -#define TOKEN_ID MAKE_CHAR2('I', 'D') -#define TOKEN_NUMBER MAKE_CHAR2('0', '0') -#define TOKEN_GE MAKE_CHAR2('>', '=') -#define TOKEN_LE MAKE_CHAR2('<', '=') -#define TOKEN_NE MAKE_CHAR2('!', '=') -#define TOKEN_EQ MAKE_CHAR2('=', '=') -#define TOKEN_AND MAKE_CHAR2('A', 'N') -#define TOKEN_OR MAKE_CHAR2('O', 'R') -#define TOKEN_NOT MAKE_CHAR2('N', 'O') -#define TOKEN_IF MAKE_CHAR2('I', 'F') -#define TOKEN_ELSE MAKE_CHAR2('E', 'L') +#define TOKEN_ID MAKE_CHAR2('I', 'D') +#define TOKEN_NUMBER MAKE_CHAR2('0', '0') +#define TOKEN_GE MAKE_CHAR2('>', '=') +#define TOKEN_LE MAKE_CHAR2('<', '=') +#define TOKEN_NE MAKE_CHAR2('!', '=') +#define TOKEN_EQ MAKE_CHAR2('=', '=') +#define TOKEN_AND MAKE_CHAR2('A', 'N') +#define TOKEN_OR MAKE_CHAR2('O', 'R') +#define TOKEN_NOT MAKE_CHAR2('N', 'O') +#define TOKEN_IF MAKE_CHAR2('I', 'F') +#define TOKEN_ELSE MAKE_CHAR2('E', 'L') static const char *token_eq_characters = "!=><"; static const char *token_characters = "~`!@#$%^&*+-=/\\?:;<>(){}[]|.,\"'"; typedef struct KeywordTokenDef { - const char *name; - short token; + const char *name; + short token; } KeywordTokenDef; -static KeywordTokenDef keyword_list[] = { - { "and", TOKEN_AND }, - { "or", TOKEN_OR }, - { "not", TOKEN_NOT }, - { "if", TOKEN_IF }, - { "else", TOKEN_ELSE }, - { NULL, TOKEN_ID } -}; +static KeywordTokenDef keyword_list[] = {{"and", TOKEN_AND}, + {"or", TOKEN_OR}, + {"not", TOKEN_NOT}, + {"if", TOKEN_IF}, + {"else", TOKEN_ELSE}, + {NULL, TOKEN_ID}}; typedef struct ExprParseState { - int param_names_len; - const char **param_names; + int param_names_len; + const char **param_names; - /* Original expression */ - const char *expr; - const char *cur; + /* Original expression */ + const char *expr; + const char *cur; - /* Current token */ - short token; - char *tokenbuf; - double tokenval; + /* Current token */ + short token; + char *tokenbuf; + double tokenval; - /* Opcode buffer */ - int ops_count, max_ops, last_jmp; - ExprOp *ops; + /* Opcode buffer */ + int ops_count, max_ops, last_jmp; + ExprOp *ops; - /* Stack space requirement tracking */ - int stack_ptr, max_stack; + /* Stack space requirement tracking */ + int stack_ptr, max_stack; } ExprParseState; /* Reserve space for the specified number of operations in the buffer. */ static ExprOp *parse_alloc_ops(ExprParseState *state, int count) { - if (state->ops_count + count > state->max_ops) { - state->max_ops = power_of_2_max_i(state->ops_count + count); - state->ops = MEM_reallocN(state->ops, state->max_ops * sizeof(ExprOp)); - } + if (state->ops_count + count > state->max_ops) { + state->max_ops = power_of_2_max_i(state->ops_count + count); + state->ops = MEM_reallocN(state->ops, state->max_ops * sizeof(ExprOp)); + } - ExprOp *op = &state->ops[state->ops_count]; - state->ops_count += count; - return op; + ExprOp *op = &state->ops[state->ops_count]; + state->ops_count += count; + return op; } /* Add one operation and track stack usage. */ static ExprOp *parse_add_op(ExprParseState *state, eOpCode code, int stack_delta) { - /* track evaluation stack depth */ - state->stack_ptr += stack_delta; - CLAMP_MIN(state->stack_ptr, 0); - CLAMP_MIN(state->max_stack, state->stack_ptr); + /* track evaluation stack depth */ + state->stack_ptr += stack_delta; + CLAMP_MIN(state->stack_ptr, 0); + CLAMP_MIN(state->max_stack, state->stack_ptr); - /* allocate the new instruction */ - ExprOp *op = parse_alloc_ops(state, 1); - memset(op, 0, sizeof(ExprOp)); - op->opcode = code; - return op; + /* allocate the new instruction */ + ExprOp *op = parse_alloc_ops(state, 1); + memset(op, 0, sizeof(ExprOp)); + op->opcode = code; + return op; } /* Add one jump operation and return an index for parse_set_jump. */ static int parse_add_jump(ExprParseState *state, eOpCode code) { - parse_add_op(state, code, -1); - return state->last_jmp = state->ops_count; + parse_add_op(state, code, -1); + return state->last_jmp = state->ops_count; } /* Set the jump offset in a previously added jump operation. */ static void parse_set_jump(ExprParseState *state, int jump) { - state->last_jmp = state->ops_count; - state->ops[jump - 1].jmp_offset = state->ops_count - jump; + state->last_jmp = state->ops_count; + state->ops[jump - 1].jmp_offset = state->ops_count - jump; } /* Add a function call operation, applying constant folding when possible. */ static bool parse_add_func(ExprParseState *state, eOpCode code, int args, void *funcptr) { - ExprOp *prev_ops = &state->ops[state->ops_count]; - int jmp_gap = state->ops_count - state->last_jmp; + ExprOp *prev_ops = &state->ops[state->ops_count]; + int jmp_gap = state->ops_count - state->last_jmp; - feclearexcept(FE_ALL_EXCEPT); + feclearexcept(FE_ALL_EXCEPT); - switch (code) { - case OPCODE_FUNC1: - CHECK_ERROR(args == 1); + switch (code) { + case OPCODE_FUNC1: + CHECK_ERROR(args == 1); - if (jmp_gap >= 1 && prev_ops[-1].opcode == OPCODE_CONST) { - UnaryOpFunc func = funcptr; + if (jmp_gap >= 1 && prev_ops[-1].opcode == OPCODE_CONST) { + UnaryOpFunc func = funcptr; - double result = func(prev_ops[-1].arg.dval); + double result = func(prev_ops[-1].arg.dval); - if (fetestexcept(FE_DIVBYZERO | FE_INVALID) == 0) { - prev_ops[-1].arg.dval = result; - return true; - } - } - break; + if (fetestexcept(FE_DIVBYZERO | FE_INVALID) == 0) { + prev_ops[-1].arg.dval = result; + return true; + } + } + break; - case OPCODE_FUNC2: - CHECK_ERROR(args == 2); + case OPCODE_FUNC2: + CHECK_ERROR(args == 2); - if (jmp_gap >= 2 && prev_ops[-2].opcode == OPCODE_CONST && prev_ops[-1].opcode == OPCODE_CONST) { - BinaryOpFunc func = funcptr; + if (jmp_gap >= 2 && prev_ops[-2].opcode == OPCODE_CONST && + prev_ops[-1].opcode == OPCODE_CONST) { + BinaryOpFunc func = funcptr; - double result = func(prev_ops[-2].arg.dval, prev_ops[-1].arg.dval); + double result = func(prev_ops[-2].arg.dval, prev_ops[-1].arg.dval); - if (fetestexcept(FE_DIVBYZERO | FE_INVALID) == 0) { - prev_ops[-2].arg.dval = result; - state->ops_count--; - state->stack_ptr--; - return true; - } - } - break; + if (fetestexcept(FE_DIVBYZERO | FE_INVALID) == 0) { + prev_ops[-2].arg.dval = result; + state->ops_count--; + state->stack_ptr--; + return true; + } + } + break; - default: - BLI_assert(false); - return false; - } + default: + BLI_assert(false); + return false; + } - parse_add_op(state, code, 1 - args)->arg.ptr = funcptr; - return true; + parse_add_op(state, code, 1 - args)->arg.ptr = funcptr; + return true; } /* Extract the next token from raw characters. */ static bool parse_next_token(ExprParseState *state) { - /* Skip whitespace. */ - while (isspace(*state->cur)) { - state->cur++; - } - - /* End of string. */ - if (*state->cur == 0) { - state->token = 0; - return true; - } - - /* Floating point numbers. */ - if (isdigit(*state->cur) || (state->cur[0] == '.' && isdigit(state->cur[1]))) { - char *end, *out = state->tokenbuf; - bool is_float = false; - - while (isdigit(*state->cur)) { - *out++ = *state->cur++; - } - - if (*state->cur == '.') { - is_float = true; - *out++ = *state->cur++; - - while (isdigit(*state->cur)) { - *out++ = *state->cur++; - } - } - - if (ELEM(*state->cur, 'e', 'E')) { - is_float = true; - *out++ = *state->cur++; - - if (ELEM(*state->cur, '+', '-')) { - *out++ = *state->cur++; - } - - CHECK_ERROR(isdigit(*state->cur)); - - while (isdigit(*state->cur)) { - *out++ = *state->cur++; - } - } - - *out = 0; - - /* Forbid C-style octal constants. */ - if (!is_float && state->tokenbuf[0] == '0') { - for (char *p = state->tokenbuf + 1; *p; p++) { - if (*p != '0') { - return false; - } - } - } - - state->token = TOKEN_NUMBER; - state->tokenval = strtod(state->tokenbuf, &end); - return (end == out); - } - - /* ?= tokens */ - if (state->cur[1] == '=' && strchr(token_eq_characters, state->cur[0])) { - state->token = MAKE_CHAR2(state->cur[0], state->cur[1]); - state->cur += 2; - return true; - } - - /* Special characters (single character tokens) */ - if (strchr(token_characters, *state->cur)) { - state->token = *state->cur++; - return true; - } - - /* Identifiers */ - if (isalpha(*state->cur) || ELEM(*state->cur, '_')) { - char *out = state->tokenbuf; - - while (isalnum(*state->cur) || ELEM(*state->cur, '_')) { - *out++ = *state->cur++; - } - - *out = 0; - - for (int i = 0; keyword_list[i].name; i++) { - if (STREQ(state->tokenbuf, keyword_list[i].name)) { - state->token = keyword_list[i].token; - return true; - } - } - - state->token = TOKEN_ID; - return true; - } - - return false; + /* Skip whitespace. */ + while (isspace(*state->cur)) { + state->cur++; + } + + /* End of string. */ + if (*state->cur == 0) { + state->token = 0; + return true; + } + + /* Floating point numbers. */ + if (isdigit(*state->cur) || (state->cur[0] == '.' && isdigit(state->cur[1]))) { + char *end, *out = state->tokenbuf; + bool is_float = false; + + while (isdigit(*state->cur)) { + *out++ = *state->cur++; + } + + if (*state->cur == '.') { + is_float = true; + *out++ = *state->cur++; + + while (isdigit(*state->cur)) { + *out++ = *state->cur++; + } + } + + if (ELEM(*state->cur, 'e', 'E')) { + is_float = true; + *out++ = *state->cur++; + + if (ELEM(*state->cur, '+', '-')) { + *out++ = *state->cur++; + } + + CHECK_ERROR(isdigit(*state->cur)); + + while (isdigit(*state->cur)) { + *out++ = *state->cur++; + } + } + + *out = 0; + + /* Forbid C-style octal constants. */ + if (!is_float && state->tokenbuf[0] == '0') { + for (char *p = state->tokenbuf + 1; *p; p++) { + if (*p != '0') { + return false; + } + } + } + + state->token = TOKEN_NUMBER; + state->tokenval = strtod(state->tokenbuf, &end); + return (end == out); + } + + /* ?= tokens */ + if (state->cur[1] == '=' && strchr(token_eq_characters, state->cur[0])) { + state->token = MAKE_CHAR2(state->cur[0], state->cur[1]); + state->cur += 2; + return true; + } + + /* Special characters (single character tokens) */ + if (strchr(token_characters, *state->cur)) { + state->token = *state->cur++; + return true; + } + + /* Identifiers */ + if (isalpha(*state->cur) || ELEM(*state->cur, '_')) { + char *out = state->tokenbuf; + + while (isalnum(*state->cur) || ELEM(*state->cur, '_')) { + *out++ = *state->cur++; + } + + *out = 0; + + for (int i = 0; keyword_list[i].name; i++) { + if (STREQ(state->tokenbuf, keyword_list[i].name)) { + state->token = keyword_list[i].token; + return true; + } + } + + state->token = TOKEN_ID; + return true; + } + + return false; } /** \} */ @@ -645,303 +644,300 @@ static bool parse_expr(ExprParseState *state); static int parse_function_args(ExprParseState *state) { - if (!parse_next_token(state) || state->token != '(' || !parse_next_token(state)) { - return -1; - } + if (!parse_next_token(state) || state->token != '(' || !parse_next_token(state)) { + return -1; + } - int arg_count = 0; + int arg_count = 0; - for (;;) { - if (!parse_expr(state)) { - return -1; - } + for (;;) { + if (!parse_expr(state)) { + return -1; + } - arg_count++; + arg_count++; - switch (state->token) { - case ',': - if (!parse_next_token(state)) { - return -1; - } - break; + switch (state->token) { + case ',': + if (!parse_next_token(state)) { + return -1; + } + break; - case ')': - if (!parse_next_token(state)) { - return -1; - } - return arg_count; + case ')': + if (!parse_next_token(state)) { + return -1; + } + return arg_count; - default: - return -1; - } - } + default: + return -1; + } + } } static bool parse_unary(ExprParseState *state) { - int i; - - switch (state->token) { - case '+': - return parse_next_token(state) && parse_unary(state); - - case '-': - CHECK_ERROR(parse_next_token(state) && parse_unary(state)); - parse_add_func(state, OPCODE_FUNC1, 1, op_negate); - return true; - - case '(': - return parse_next_token(state) && - parse_expr(state) && - state->token == ')' && - parse_next_token(state); - - case TOKEN_NUMBER: - parse_add_op(state, OPCODE_CONST, 1)->arg.dval = state->tokenval; - return parse_next_token(state); - - case TOKEN_ID: - /* Parameters: search in reverse order in case of duplicate names - - * the last one should win. */ - for (i = state->param_names_len - 1; i >= 0; i--) { - if (STREQ(state->tokenbuf, state->param_names[i])) { - parse_add_op(state, OPCODE_PARAMETER, 1)->arg.ival = i; - return parse_next_token(state); - } - } - - /* Ordinary builtin constants. */ - for (i = 0; builtin_consts[i].name; i++) { - if (STREQ(state->tokenbuf, builtin_consts[i].name)) { - parse_add_op(state, OPCODE_CONST, 1)->arg.dval = builtin_consts[i].value; - return parse_next_token(state); - } - } - - /* Ordinary builtin functions. */ - for (i = 0; builtin_ops[i].name; i++) { - if (STREQ(state->tokenbuf, builtin_ops[i].name)) { - int args = parse_function_args(state); - - return parse_add_func(state, builtin_ops[i].op, args, builtin_ops[i].funcptr); - } - } - - /* Specially supported functions. */ - if (STREQ(state->tokenbuf, "min")) { - int cnt = parse_function_args(state); - CHECK_ERROR(cnt > 0); - - parse_add_op(state, OPCODE_MIN, 1 - cnt)->arg.ival = cnt; - return true; - } - - if (STREQ(state->tokenbuf, "max")) { - int cnt = parse_function_args(state); - CHECK_ERROR(cnt > 0); - - parse_add_op(state, OPCODE_MAX, 1 - cnt)->arg.ival = cnt; - return true; - } - - return false; - - default: - return false; - } + int i; + + switch (state->token) { + case '+': + return parse_next_token(state) && parse_unary(state); + + case '-': + CHECK_ERROR(parse_next_token(state) && parse_unary(state)); + parse_add_func(state, OPCODE_FUNC1, 1, op_negate); + return true; + + case '(': + return parse_next_token(state) && parse_expr(state) && state->token == ')' && + parse_next_token(state); + + case TOKEN_NUMBER: + parse_add_op(state, OPCODE_CONST, 1)->arg.dval = state->tokenval; + return parse_next_token(state); + + case TOKEN_ID: + /* Parameters: search in reverse order in case of duplicate names - + * the last one should win. */ + for (i = state->param_names_len - 1; i >= 0; i--) { + if (STREQ(state->tokenbuf, state->param_names[i])) { + parse_add_op(state, OPCODE_PARAMETER, 1)->arg.ival = i; + return parse_next_token(state); + } + } + + /* Ordinary builtin constants. */ + for (i = 0; builtin_consts[i].name; i++) { + if (STREQ(state->tokenbuf, builtin_consts[i].name)) { + parse_add_op(state, OPCODE_CONST, 1)->arg.dval = builtin_consts[i].value; + return parse_next_token(state); + } + } + + /* Ordinary builtin functions. */ + for (i = 0; builtin_ops[i].name; i++) { + if (STREQ(state->tokenbuf, builtin_ops[i].name)) { + int args = parse_function_args(state); + + return parse_add_func(state, builtin_ops[i].op, args, builtin_ops[i].funcptr); + } + } + + /* Specially supported functions. */ + if (STREQ(state->tokenbuf, "min")) { + int cnt = parse_function_args(state); + CHECK_ERROR(cnt > 0); + + parse_add_op(state, OPCODE_MIN, 1 - cnt)->arg.ival = cnt; + return true; + } + + if (STREQ(state->tokenbuf, "max")) { + int cnt = parse_function_args(state); + CHECK_ERROR(cnt > 0); + + parse_add_op(state, OPCODE_MAX, 1 - cnt)->arg.ival = cnt; + return true; + } + + return false; + + default: + return false; + } } static bool parse_mul(ExprParseState *state) { - CHECK_ERROR(parse_unary(state)); + CHECK_ERROR(parse_unary(state)); - for (;;) { - switch (state->token) { - case '*': - CHECK_ERROR(parse_next_token(state) && parse_unary(state)); - parse_add_func(state, OPCODE_FUNC2, 2, op_mul); - break; + for (;;) { + switch (state->token) { + case '*': + CHECK_ERROR(parse_next_token(state) && parse_unary(state)); + parse_add_func(state, OPCODE_FUNC2, 2, op_mul); + break; - case '/': - CHECK_ERROR(parse_next_token(state) && parse_unary(state)); - parse_add_func(state, OPCODE_FUNC2, 2, op_div); - break; + case '/': + CHECK_ERROR(parse_next_token(state) && parse_unary(state)); + parse_add_func(state, OPCODE_FUNC2, 2, op_div); + break; - default: - return true; - } - } + default: + return true; + } + } } static bool parse_add(ExprParseState *state) { - CHECK_ERROR(parse_mul(state)); + CHECK_ERROR(parse_mul(state)); - for (;;) { - switch (state->token) { - case '+': - CHECK_ERROR(parse_next_token(state) && parse_mul(state)); - parse_add_func(state, OPCODE_FUNC2, 2, op_add); - break; + for (;;) { + switch (state->token) { + case '+': + CHECK_ERROR(parse_next_token(state) && parse_mul(state)); + parse_add_func(state, OPCODE_FUNC2, 2, op_add); + break; - case '-': - CHECK_ERROR(parse_next_token(state) && parse_mul(state)); - parse_add_func(state, OPCODE_FUNC2, 2, op_sub); - break; + case '-': + CHECK_ERROR(parse_next_token(state) && parse_mul(state)); + parse_add_func(state, OPCODE_FUNC2, 2, op_sub); + break; - default: - return true; - } - } + default: + return true; + } + } } static BinaryOpFunc parse_get_cmp_func(short token) { - switch (token) { - case TOKEN_EQ: - return op_eq; - case TOKEN_NE: - return op_ne; - case '>': - return op_gt; - case TOKEN_GE: - return op_ge; - case '<': - return op_lt; - case TOKEN_LE: - return op_le; - default: - return NULL; - } + switch (token) { + case TOKEN_EQ: + return op_eq; + case TOKEN_NE: + return op_ne; + case '>': + return op_gt; + case TOKEN_GE: + return op_ge; + case '<': + return op_lt; + case TOKEN_LE: + return op_le; + default: + return NULL; + } } static bool parse_cmp_chain(ExprParseState *state, BinaryOpFunc cur_func) { - BinaryOpFunc next_func = parse_get_cmp_func(state->token); + BinaryOpFunc next_func = parse_get_cmp_func(state->token); - if (next_func) { - parse_add_op(state, OPCODE_CMP_CHAIN, -1)->arg.func2 = cur_func; - int jump = state->last_jmp = state->ops_count; + if (next_func) { + parse_add_op(state, OPCODE_CMP_CHAIN, -1)->arg.func2 = cur_func; + int jump = state->last_jmp = state->ops_count; - CHECK_ERROR(parse_next_token(state) && parse_add(state)); - CHECK_ERROR(parse_cmp_chain(state, next_func)); + CHECK_ERROR(parse_next_token(state) && parse_add(state)); + CHECK_ERROR(parse_cmp_chain(state, next_func)); - parse_set_jump(state, jump); - } - else { - parse_add_func(state, OPCODE_FUNC2, 2, cur_func); - } + parse_set_jump(state, jump); + } + else { + parse_add_func(state, OPCODE_FUNC2, 2, cur_func); + } - return true; + return true; } static bool parse_cmp(ExprParseState *state) { - CHECK_ERROR(parse_add(state)); + CHECK_ERROR(parse_add(state)); - BinaryOpFunc func = parse_get_cmp_func(state->token); + BinaryOpFunc func = parse_get_cmp_func(state->token); - if (func) { - CHECK_ERROR(parse_next_token(state) && parse_add(state)); + if (func) { + CHECK_ERROR(parse_next_token(state) && parse_add(state)); - return parse_cmp_chain(state, func); - } + return parse_cmp_chain(state, func); + } - return true; + return true; } static bool parse_not(ExprParseState *state) { - if (state->token == TOKEN_NOT) { - CHECK_ERROR(parse_next_token(state) && parse_not(state)); - parse_add_func(state, OPCODE_FUNC1, 1, op_not); - return true; - } + if (state->token == TOKEN_NOT) { + CHECK_ERROR(parse_next_token(state) && parse_not(state)); + parse_add_func(state, OPCODE_FUNC1, 1, op_not); + return true; + } - return parse_cmp(state); + return parse_cmp(state); } static bool parse_and(ExprParseState *state) { - CHECK_ERROR(parse_not(state)); + CHECK_ERROR(parse_not(state)); - if (state->token == TOKEN_AND) { - int jump = parse_add_jump(state, OPCODE_JMP_AND); + if (state->token == TOKEN_AND) { + int jump = parse_add_jump(state, OPCODE_JMP_AND); - CHECK_ERROR(parse_next_token(state) && parse_and(state)); + CHECK_ERROR(parse_next_token(state) && parse_and(state)); - parse_set_jump(state, jump); - } + parse_set_jump(state, jump); + } - return true; + return true; } static bool parse_or(ExprParseState *state) { - CHECK_ERROR(parse_and(state)); + CHECK_ERROR(parse_and(state)); - if (state->token == TOKEN_OR) { - int jump = parse_add_jump(state, OPCODE_JMP_OR); + if (state->token == TOKEN_OR) { + int jump = parse_add_jump(state, OPCODE_JMP_OR); - CHECK_ERROR(parse_next_token(state) && parse_or(state)); + CHECK_ERROR(parse_next_token(state) && parse_or(state)); - parse_set_jump(state, jump); - } + parse_set_jump(state, jump); + } - return true; + return true; } static bool parse_expr(ExprParseState *state) { - /* Temporarily set the constant expression evaluation barrier */ - int prev_last_jmp = state->last_jmp; - int start = state->last_jmp = state->ops_count; + /* Temporarily set the constant expression evaluation barrier */ + int prev_last_jmp = state->last_jmp; + int start = state->last_jmp = state->ops_count; - CHECK_ERROR(parse_or(state)); + CHECK_ERROR(parse_or(state)); - if (state->token == TOKEN_IF) { - /* Ternary IF expression in python requires swapping the - * main body with condition, so stash the body opcodes. */ - int size = state->ops_count - start; - int bytes = size * sizeof(ExprOp); + if (state->token == TOKEN_IF) { + /* Ternary IF expression in python requires swapping the + * main body with condition, so stash the body opcodes. */ + int size = state->ops_count - start; + int bytes = size * sizeof(ExprOp); - ExprOp *body = MEM_mallocN(bytes, "driver if body"); - memcpy(body, state->ops + start, bytes); + ExprOp *body = MEM_mallocN(bytes, "driver if body"); + memcpy(body, state->ops + start, bytes); - state->last_jmp = state->ops_count = start; - state->stack_ptr--; + state->last_jmp = state->ops_count = start; + state->stack_ptr--; - /* Parse condition. */ - if (!parse_next_token(state) || !parse_or(state) || - state->token != TOKEN_ELSE || !parse_next_token(state)) - { - MEM_freeN(body); - return false; - } + /* Parse condition. */ + if (!parse_next_token(state) || !parse_or(state) || state->token != TOKEN_ELSE || + !parse_next_token(state)) { + MEM_freeN(body); + return false; + } - int jmp_else = parse_add_jump(state, OPCODE_JMP_ELSE); + int jmp_else = parse_add_jump(state, OPCODE_JMP_ELSE); - /* Add body back. */ - memcpy(parse_alloc_ops(state, size), body, bytes); - MEM_freeN(body); + /* Add body back. */ + memcpy(parse_alloc_ops(state, size), body, bytes); + MEM_freeN(body); - state->stack_ptr++; + state->stack_ptr++; - int jmp_end = parse_add_jump(state, OPCODE_JMP); + int jmp_end = parse_add_jump(state, OPCODE_JMP); - /* Parse the else block. */ - parse_set_jump(state, jmp_else); + /* Parse the else block. */ + parse_set_jump(state, jmp_else); - CHECK_ERROR(parse_expr(state)); + CHECK_ERROR(parse_expr(state)); - parse_set_jump(state, jmp_end); - } - /* If no actual jumps happened, restore previous barrier */ - else if (state->last_jmp == start) { - state->last_jmp = prev_last_jmp; - } + parse_set_jump(state, jmp_end); + } + /* If no actual jumps happened, restore previous barrier */ + else if (state->last_jmp == start) { + state->last_jmp = prev_last_jmp; + } - return true; + return true; } /** \} */ @@ -956,44 +952,46 @@ static bool parse_expr(ExprParseState *state) * Parse the expression for evaluation later. * Returns non-NULL even on failure; use is_valid to check. */ -ExprPyLike_Parsed *BLI_expr_pylike_parse(const char *expression, const char **param_names, int param_names_len) +ExprPyLike_Parsed *BLI_expr_pylike_parse(const char *expression, + const char **param_names, + int param_names_len) { - /* Prepare the parser state. */ - ExprParseState state; - memset(&state, 0, sizeof(state)); + /* Prepare the parser state. */ + ExprParseState state; + memset(&state, 0, sizeof(state)); - state.cur = state.expr = expression; + state.cur = state.expr = expression; - state.param_names_len = param_names_len; - state.param_names = param_names; + state.param_names_len = param_names_len; + state.param_names = param_names; - state.tokenbuf = MEM_mallocN(strlen(expression) + 1, __func__); + state.tokenbuf = MEM_mallocN(strlen(expression) + 1, __func__); - state.max_ops = 16; - state.ops = MEM_mallocN(state.max_ops * sizeof(ExprOp), __func__); + state.max_ops = 16; + state.ops = MEM_mallocN(state.max_ops * sizeof(ExprOp), __func__); - /* Parse the expression. */ - ExprPyLike_Parsed *expr; + /* Parse the expression. */ + ExprPyLike_Parsed *expr; - if (parse_next_token(&state) && parse_expr(&state) && state.token == 0) { - BLI_assert(state.stack_ptr == 1); + if (parse_next_token(&state) && parse_expr(&state) && state.token == 0) { + BLI_assert(state.stack_ptr == 1); - int bytesize = sizeof(ExprPyLike_Parsed) + state.ops_count * sizeof(ExprOp); + int bytesize = sizeof(ExprPyLike_Parsed) + state.ops_count * sizeof(ExprOp); - expr = MEM_mallocN(bytesize, "ExprPyLike_Parsed"); - expr->ops_count = state.ops_count; - expr->max_stack = state.max_stack; + expr = MEM_mallocN(bytesize, "ExprPyLike_Parsed"); + expr->ops_count = state.ops_count; + expr->max_stack = state.max_stack; - memcpy(expr->ops, state.ops, state.ops_count * sizeof(ExprOp)); - } - else { - /* Always return a non-NULL object so that parse failure can be cached. */ - expr = MEM_callocN(sizeof(ExprPyLike_Parsed), "ExprPyLike_Parsed(empty)"); - } + memcpy(expr->ops, state.ops, state.ops_count * sizeof(ExprOp)); + } + else { + /* Always return a non-NULL object so that parse failure can be cached. */ + expr = MEM_callocN(sizeof(ExprPyLike_Parsed), "ExprPyLike_Parsed(empty)"); + } - MEM_freeN(state.tokenbuf); - MEM_freeN(state.ops); - return expr; + MEM_freeN(state.tokenbuf); + MEM_freeN(state.ops); + return expr; } /** \} */ |