Welcome to mirror list, hosted at ThFree Co, Russian Federation.

git.blender.org/blender.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'source/blender/blenlib/intern/expr_pylike_eval.c')
-rw-r--r--source/blender/blenlib/intern/expr_pylike_eval.c1238
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;
}
/** \} */