Cleanup: rename BLI_simple_expr -> BLI_expr_pylike_eval
authorCampbell Barton <ideasman42@gmail.com>
Wed, 19 Sep 2018 00:40:35 +0000 (10:40 +1000)
committerCampbell Barton <ideasman42@gmail.com>
Wed, 19 Sep 2018 01:08:04 +0000 (11:08 +1000)
Simple isn't a good prefix for library names since
lots of unrelated modules could be called 'simple'.

Include 'py' in module name since this is a subset of Python,
one of the main motivations for this is to be Python like/compatible.

source/blender/blenkernel/intern/fcurve.c
source/blender/blenlib/BLI_expr_pylike_eval.h [new file with mode: 0644]
source/blender/blenlib/BLI_simple_expr.h [deleted file]
source/blender/blenlib/CMakeLists.txt
source/blender/blenlib/intern/expr_pylike_eval.c [moved from source/blender/blenlib/intern/simple_expr.c with 86% similarity]
source/blender/makesdna/DNA_anim_types.h
tests/gtests/blenlib/BLI_expr_pylike_eval_test.cc [moved from tests/gtests/blenlib/BLI_simple_expr_test.cc with 60% similarity]
tests/gtests/blenlib/CMakeLists.txt

index bf8d259..ddbe203 100644 (file)
@@ -49,7 +49,7 @@
 #include "BLI_threads.h"
 #include "BLI_string_utils.h"
 #include "BLI_utildefines.h"
-#include "BLI_simple_expr.h"
+#include "BLI_expr_pylike_eval.h"
 #include "BLI_alloca.h"
 
 #include "BLT_translation.h"
@@ -1866,7 +1866,7 @@ void fcurve_free_driver(FCurve *fcu)
                BPY_DECREF(driver->expr_comp);
 #endif
 
-       BLI_simple_expr_free(driver->expr_simple);
+       BLI_expr_pylike_free(driver->expr_simple);
 
        /* free driver itself, then set F-Curve's point to this to NULL (as the curve may still be used) */
        MEM_freeN(driver);
@@ -1897,7 +1897,7 @@ ChannelDriver *fcurve_copy_driver(const ChannelDriver *driver)
 
 /* Driver Expression Evaluation --------------- */
 
-static ParsedSimpleExpr *driver_compile_simple_expr_impl(ChannelDriver *driver)
+static ExprPyLike_Parsed *driver_compile_simple_expr_impl(ChannelDriver *driver)
 {
        /* Prepare parameter names. */
        int num_vars = BLI_listbase_count(&driver->variables);
@@ -1910,10 +1910,10 @@ static ParsedSimpleExpr *driver_compile_simple_expr_impl(ChannelDriver *driver)
                names[i++] = dvar->name;
        }
 
-       return BLI_simple_expr_parse(driver->expression, num_vars + 1, names);
+       return BLI_expr_pylike_parse(driver->expression, num_vars + 1, names);
 }
 
-static bool driver_evaluate_simple_expr(ChannelDriver *driver, ParsedSimpleExpr *expr, float *result, float time)
+static bool driver_evaluate_simple_expr(ChannelDriver *driver, ExprPyLike_Parsed *expr, float *result, float time)
 {
        /* Prepare parameter values. */
        int num_vars = BLI_listbase_count(&driver->variables);
@@ -1928,19 +1928,19 @@ static bool driver_evaluate_simple_expr(ChannelDriver *driver, ParsedSimpleExpr
 
        /* Evaluate expression. */
        double result_val;
-       eSimpleExpr_EvalStatus status = BLI_simple_expr_evaluate(expr, &result_val, num_vars + 1, vars);
+       eExprPyLike_EvalStatus status = BLI_expr_pylike_eval(expr, &result_val, num_vars + 1, vars);
        const char *message;
 
        switch (status) {
-               case SIMPLE_EXPR_SUCCESS:
+               case EXPR_PYLIKE_SUCCESS:
                        if (isfinite(result_val)) {
                                *result = (float)result_val;
                        }
                        return true;
 
-               case SIMPLE_EXPR_DIV_BY_ZERO:
-               case SIMPLE_EXPR_MATH_ERROR:
-                       message = (status == SIMPLE_EXPR_DIV_BY_ZERO) ? "Division by Zero" : "Math Domain Error";
+               case EXPR_PYLIKE_DIV_BY_ZERO:
+               case EXPR_PYLIKE_MATH_ERROR:
+                       message = (status == EXPR_PYLIKE_DIV_BY_ZERO) ? "Division by Zero" : "Math Domain Error";
                        fprintf(stderr, "\n%s in Driver: '%s'\n", message, driver->expression);
 
                        driver->flag |= DRIVER_FLAG_INVALID;
@@ -1966,12 +1966,12 @@ static bool driver_compile_simple_expr(ChannelDriver *driver)
 
        /* It's safe to parse in multiple threads; at worst it'll
         * waste some effort, but in return avoids mutex contention. */
-       ParsedSimpleExpr *expr = driver_compile_simple_expr_impl(driver);
+       ExprPyLike_Parsed *expr = driver_compile_simple_expr_impl(driver);
 
        /* Store the result if the field is still NULL, or discard
         * it if another thread got here first. */
        if (atomic_cas_ptr((void **)&driver->expr_simple, NULL, expr) != NULL) {
-               BLI_simple_expr_free(expr);
+               BLI_expr_pylike_free(expr);
        }
 
        return true;
@@ -1984,21 +1984,21 @@ static bool driver_try_evaluate_simple_expr(ChannelDriver *driver, ChannelDriver
        *result = 0.0f;
 
        return driver_compile_simple_expr(driver_orig) &&
-              BLI_simple_expr_is_valid(driver_orig->expr_simple) &&
+              BLI_expr_pylike_is_valid(driver_orig->expr_simple) &&
               driver_evaluate_simple_expr(driver, driver_orig->expr_simple, result, time);
 }
 
 /* Check if the expression in the driver conforms to the simple subset. */
 bool BKE_driver_has_simple_expression(ChannelDriver *driver)
 {
-       return driver_compile_simple_expr(driver) && BLI_simple_expr_is_valid(driver->expr_simple);
+       return driver_compile_simple_expr(driver) && BLI_expr_pylike_is_valid(driver->expr_simple);
 }
 
 /* Reset cached compiled expression data */
 void BKE_driver_invalidate_expression(ChannelDriver *driver, bool expr_changed, bool varname_changed)
 {
        if (expr_changed || varname_changed) {
-               BLI_simple_expr_free(driver->expr_simple);
+               BLI_expr_pylike_free(driver->expr_simple);
                driver->expr_simple = NULL;
        }
 
diff --git a/source/blender/blenlib/BLI_expr_pylike_eval.h b/source/blender/blenlib/BLI_expr_pylike_eval.h
new file mode 100644 (file)
index 0000000..b627664
--- /dev/null
@@ -0,0 +1,63 @@
+/*
+ * ***** BEGIN GPL LICENSE BLOCK *****
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software Foundation,
+ * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * The Original Code is Copyright (C) 2018 Blender Foundation, Alexander Gavrilov
+ * All rights reserved.
+ *
+ * Contributor(s): Alexander Gavrilov
+ *
+ * ***** END GPL LICENSE BLOCK *****
+ */
+
+#ifndef __BLI_EXPR_PYLIKE_EVAL_H__
+#define __BLI_EXPR_PYLIKE_EVAL_H__
+
+/** \file BLI_expr_pylike_eval.h
+ *  \ingroup bli
+ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** Opaque structure containing pre-parsed data for evaluation. */
+typedef struct ExprPyLike_Parsed ExprPyLike_Parsed;
+
+/** Expression evaluation return code. */
+typedef enum eExprPyLike_EvalStatus {
+       EXPR_PYLIKE_SUCCESS = 0,
+       /* Computation errors; result is still set, but may be NaN */
+       EXPR_PYLIKE_DIV_BY_ZERO,
+       EXPR_PYLIKE_MATH_ERROR,
+       /* Expression dependent errors or bugs; result is 0 */
+       EXPR_PYLIKE_INVALID,
+       EXPR_PYLIKE_FATAL_ERROR,
+} eExprPyLike_EvalStatus;
+
+void BLI_expr_pylike_free(struct ExprPyLike_Parsed *expr);
+bool BLI_expr_pylike_is_valid(struct ExprPyLike_Parsed *expr);
+bool BLI_expr_pylike_is_constant(struct ExprPyLike_Parsed *expr);
+ExprPyLike_Parsed *BLI_expr_pylike_parse(
+        const char *expression, int num_params, const char **param_names);
+eExprPyLike_EvalStatus BLI_expr_pylike_eval(
+        struct ExprPyLike_Parsed *expr, double *result, int num_params, const double *params);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* __BLI_EXPR_PYLIKE_EVALUATE_H__ */
diff --git a/source/blender/blenlib/BLI_simple_expr.h b/source/blender/blenlib/BLI_simple_expr.h
deleted file mode 100644 (file)
index 8498f1a..0000000
+++ /dev/null
@@ -1,96 +0,0 @@
-/*
- * ***** BEGIN GPL LICENSE BLOCK *****
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software Foundation,
- * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
- *
- * The Original Code is Copyright (C) 2018 Blender Foundation, Alexander Gavrilov
- * All rights reserved.
- *
- * Contributor(s): Alexander Gavrilov
- *
- * ***** END GPL LICENSE BLOCK *****
- */
-
-#ifndef __BLI_SIMPLE_EXPR_H__
-#define __BLI_SIMPLE_EXPR_H__
-
-/** \file BLI_simple_expr.h
- *  \ingroup bli
- *  \author Alexander Gavrilov
- *  \since 2018
- *
- * Simple evaluator for a subset of Python expressions that can be
- * computed using purely double precision floating point values.
- *
- * Supported subset:
- *
- *  - Identifiers use only ASCII characters.
- *  - Literals:
- *      floating point and decimal integer.
- *  - Constants:
- *      pi, True, False
- *  - Operators:
- *      +, -, *, /, ==, !=, <, <=, >, >=, and, or, not, ternary if
- *  - Functions:
- *      radians, degrees,
- *      abs, fabs, floor, ceil, trunc, int,
- *      sin, cos, tan, asin, acos, atan, atan2,
- *      exp, log, sqrt, pow, fmod
- *
- * The implementation has no global state and can be used multithreaded.
- */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-/** Opaque structure containing pre-parsed data for evaluation. */
-typedef struct ParsedSimpleExpr ParsedSimpleExpr;
-
-/** Simple expression evaluation return code. */
-typedef enum eSimpleExpr_EvalStatus {
-       SIMPLE_EXPR_SUCCESS = 0,
-       /* Computation errors; result is still set, but may be NaN */
-       SIMPLE_EXPR_DIV_BY_ZERO,
-       SIMPLE_EXPR_MATH_ERROR,
-       /* Expression dependent errors or bugs; result is 0 */
-       SIMPLE_EXPR_INVALID,
-       SIMPLE_EXPR_FATAL_ERROR,
-} eSimpleExpr_EvalStatus;
-
-/** Free the parsed data; NULL argument is ok. */
-void BLI_simple_expr_free(struct ParsedSimpleExpr *expr);
-
-/** Check if the parsing result is valid for evaluation. */
-bool BLI_simple_expr_is_valid(struct ParsedSimpleExpr *expr);
-
-/** Check if the parsed expression always evaluates to the same value. */
-bool BLI_simple_expr_is_constant(struct ParsedSimpleExpr *expr);
-
-/** Parse the expression for evaluation later.
- *  Returns non-NULL even on failure; use is_valid to check.
- */
-ParsedSimpleExpr *BLI_simple_expr_parse(const char *expression, int num_params, const char **param_names);
-
-/** Evaluate the expression with the given parameters.
- *  The order and number of parameters must match the names given to parse.
- */
-eSimpleExpr_EvalStatus BLI_simple_expr_evaluate(struct ParsedSimpleExpr *expr, double *result, int num_params, const double *params);
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* __BLI_SIMPLE_EXPR_H__*/
index 9dd8983..6c56b06 100644 (file)
@@ -68,6 +68,7 @@ set(SRC
        intern/easing.c
        intern/edgehash.c
        intern/endian_switch.c
+       intern/expr_pylike_eval.c
        intern/fileops.c
        intern/fnmatch.c
        intern/freetypefont.c
@@ -104,7 +105,6 @@ set(SRC
        intern/rct.c
        intern/scanfill.c
        intern/scanfill_utils.c
-       intern/simple_expr.c
        intern/smallhash.c
        intern/sort.c
        intern/sort_utils.c
@@ -152,6 +152,7 @@ set(SRC
        BLI_edgehash.h
        BLI_endian_switch.h
        BLI_endian_switch_inline.h
+       BLI_expr_pylike_eval.h
        BLI_fileops.h
        BLI_fileops_types.h
        BLI_fnmatch.h
  * ***** END GPL LICENSE BLOCK *****
  */
 
-/** \file blender/blenlib/intern/simple_expr.c
+/** \file blender/blenlib/intern/expr_pylike_eval.c
  *  \ingroup bli
+ *  \author Alexander Gavrilov
+ *  \since 2018
+ *
+ * Simple evaluator for a subset of Python expressions that can be
+ * computed using purely double precision floating point values.
+ *
+ * Supported subset:
+ *
+ *  - Identifiers use only ASCII characters.
+ *  - Literals:
+ *      floating point and decimal integer.
+ *  - Constants:
+ *      pi, True, False
+ *  - Operators:
+ *      +, -, *, /, ==, !=, <, <=, >, >=, and, or, not, ternary if
+ *  - Functions:
+ *      radians, degrees,
+ *      abs, fabs, floor, ceil, trunc, int,
+ *      sin, cos, tan, asin, acos, atan, atan2,
+ *      exp, log, sqrt, pow, fmod
+ *
+ * The implementation has no global state and can be used multithreaded.
  */
 
 #include <math.h>
@@ -40,7 +62,7 @@
 
 #include "MEM_guardedalloc.h"
 
-#include "BLI_simple_expr.h"
+#include "BLI_expr_pylike_eval.h"
 #include "BLI_blenlib.h"
 #include "BLI_math.h"
 #include "BLI_string_utils.h"
@@ -53,7 +75,7 @@
 
 /* Simple Expression Stack Machine ------------------------- */
 
-typedef enum eSimpleExpr_Opcode {
+typedef enum eOpCode {
        /* Double constant: (-> dval) */
        OPCODE_CONST,
        /* 1 argument function call: (a -> func1(a)) */
@@ -76,13 +98,13 @@ typedef enum eSimpleExpr_Opcode {
        OPCODE_JMP_AND,
        /* For comparison chaining: (a b -> 0 JUMP) IF NOT func2(a,b) ELSE (a b -> b) */
        OPCODE_CMP_CHAIN,
-} eSimpleExpr_Opcode;
+} eOpCode;
 
 typedef double (*UnaryOpFunc)(double);
 typedef double (*BinaryOpFunc)(double, double);
 
-typedef struct SimpleExprOp {
-       eSimpleExpr_Opcode opcode;
+typedef struct ExprOp {
+       eOpCode opcode;
 
        int jmp_offset;
 
@@ -93,43 +115,50 @@ typedef struct SimpleExprOp {
                UnaryOpFunc func1;
                BinaryOpFunc func2;
        } arg;
-} SimpleExprOp;
+} ExprOp;
 
-struct ParsedSimpleExpr {
+struct ExprPyLike_Parsed {
        int ops_count;
        int max_stack;
 
-       SimpleExprOp ops[];
+       ExprOp ops[];
 };
 
-void BLI_simple_expr_free(ParsedSimpleExpr *expr)
+/** Free the parsed data; NULL argument is ok. */
+void BLI_expr_pylike_free(ExprPyLike_Parsed *expr)
 {
        if (expr != NULL) {
                MEM_freeN(expr);
        }
 }
 
-bool BLI_simple_expr_is_valid(ParsedSimpleExpr *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;
 }
 
-bool BLI_simple_expr_is_constant(ParsedSimpleExpr *expr)
+/** 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;
 }
 
 /* Stack Machine Evaluation -------------------------------- */
 
-eSimpleExpr_EvalStatus BLI_simple_expr_evaluate(ParsedSimpleExpr *expr, double *result, int num_params, const double *params)
+/**
+ * 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, double *result, int num_params, const double *params)
 {
        *result = 0.0;
 
-       if (!BLI_simple_expr_is_valid(expr)) {
-               return SIMPLE_EXPR_INVALID;
+       if (!BLI_expr_pylike_is_valid(expr)) {
+               return EXPR_PYLIKE_INVALID;
        }
 
-#define FAIL_IF(condition) if (condition) { return SIMPLE_EXPR_FATAL_ERROR; }
+#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);
@@ -137,7 +166,7 @@ eSimpleExpr_EvalStatus BLI_simple_expr_evaluate(ParsedSimpleExpr *expr, double *
        double *stack = BLI_array_alloca(stack, expr->max_stack);
 
        /* Evaluate expression. */
-       SimpleExprOp *ops = expr->ops;
+       ExprOp *ops = expr->ops;
        int sp = 0, pc;
 
        feclearexcept(FE_ALL_EXCEPT);
@@ -212,7 +241,7 @@ eSimpleExpr_EvalStatus BLI_simple_expr_evaluate(ParsedSimpleExpr *expr, double *
                                break;
 
                        default:
-                               return SIMPLE_EXPR_FATAL_ERROR;
+                               return EXPR_PYLIKE_FATAL_ERROR;
                }
        }
 
@@ -225,10 +254,10 @@ eSimpleExpr_EvalStatus BLI_simple_expr_evaluate(ParsedSimpleExpr *expr, double *
        /* Detect floating point evaluation errors. */
        int flags = fetestexcept(FE_DIVBYZERO | FE_INVALID);
        if (flags) {
-               return (flags & FE_INVALID) ? SIMPLE_EXPR_MATH_ERROR : SIMPLE_EXPR_DIV_BY_ZERO;
+               return (flags & FE_INVALID) ? EXPR_PYLIKE_MATH_ERROR : EXPR_PYLIKE_DIV_BY_ZERO;
        }
 
-       return SIMPLE_EXPR_SUCCESS;
+       return EXPR_PYLIKE_SUCCESS;
 }
 
 /* Simple Expression Built-In Operations ------------------- */
@@ -317,7 +346,7 @@ static BuiltinConstDef builtin_consts[] = {
 
 typedef struct BuiltinOpDef {
        const char *name;
-       eSimpleExpr_Opcode op;
+       eOpCode op;
        void *funcptr;
 } BuiltinOpDef;
 
@@ -397,27 +426,27 @@ typedef struct SimpleExprParseState {
 
        /* Opcode buffer */
        int ops_count, max_ops, last_jmp;
-       SimpleExprOp *ops;
+       ExprOp *ops;
 
        /* Stack space requirement tracking */
        int stack_ptr, max_stack;
 } SimpleExprParseState;
 
 /* Reserve space for the specified number of operations in the buffer. */
-static SimpleExprOp *parse_alloc_ops(SimpleExprParseState *state, int count)
+static ExprOp *parse_alloc_ops(SimpleExprParseState *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(SimpleExprOp));
+               state->ops = MEM_reallocN(state->ops, state->max_ops * sizeof(ExprOp));
        }
 
-       SimpleExprOp *op = &state->ops[state->ops_count];
+       ExprOp *op = &state->ops[state->ops_count];
        state->ops_count += count;
        return op;
 }
 
 /* Add one operation and track stack usage. */
-static SimpleExprOp *parse_add_op(SimpleExprParseState *state, eSimpleExpr_Opcode code, int stack_delta)
+static ExprOp *parse_add_op(SimpleExprParseState *state, eOpCode code, int stack_delta)
 {
        /* track evaluation stack depth */
        state->stack_ptr += stack_delta;
@@ -425,14 +454,14 @@ static SimpleExprOp *parse_add_op(SimpleExprParseState *state, eSimpleExpr_Opcod
        CLAMP_MIN(state->max_stack, state->stack_ptr);
 
        /* allocate the new instruction */
-       SimpleExprOp *op = parse_alloc_ops(state, 1);
-       memset(op, 0, sizeof(SimpleExprOp));
+       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(SimpleExprParseState *state, eSimpleExpr_Opcode code)
+static int parse_add_jump(SimpleExprParseState *state, eOpCode code)
 {
        parse_add_op(state, code, -1);
        return state->last_jmp = state->ops_count;
@@ -446,9 +475,9 @@ static void parse_set_jump(SimpleExprParseState *state, int jump)
 }
 
 /* Add a function call operation, applying constant folding when possible. */
-static bool parse_add_func(SimpleExprParseState *state, eSimpleExpr_Opcode code, int args, void *funcptr)
+static bool parse_add_func(SimpleExprParseState *state, eOpCode code, int args, void *funcptr)
 {
-       SimpleExprOp *prev_ops = &state->ops[state->ops_count];
+       ExprOp *prev_ops = &state->ops[state->ops_count];
        int jmp_gap = state->ops_count - state->last_jmp;
 
        feclearexcept(FE_ALL_EXCEPT);
@@ -853,9 +882,9 @@ static bool parse_expr(SimpleExprParseState *state)
                /* 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(SimpleExprOp);
+               int bytes = size * sizeof(ExprOp);
 
-               SimpleExprOp *body = MEM_mallocN(bytes, "driver if body");
+               ExprOp *body = MEM_mallocN(bytes, "driver if body");
                memcpy(body, state->ops + start, bytes);
 
                state->last_jmp = state->ops_count = start;
@@ -896,8 +925,13 @@ static bool parse_expr(SimpleExprParseState *state)
 
 /* Main Parsing Function ----------------------------------- */
 
-/* Compile the expression and return the result. */
-ParsedSimpleExpr *BLI_simple_expr_parse(const char *expression, int num_params, const char **param_names)
+/**
+ * Compile the expression and return the result.
+ *
+ * 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, int num_params, const char **param_names)
 {
        /* Prepare the parser state. */
        SimpleExprParseState state;
@@ -911,25 +945,25 @@ ParsedSimpleExpr *BLI_simple_expr_parse(const char *expression, int num_params,
        state.tokenbuf = MEM_mallocN(strlen(expression) + 1, __func__);
 
        state.max_ops = 16;
-       state.ops = MEM_mallocN(state.max_ops * sizeof(SimpleExprOp), __func__);
+       state.ops = MEM_mallocN(state.max_ops * sizeof(ExprOp), __func__);
 
        /* Parse the expression. */
-       ParsedSimpleExpr *expr;
+       ExprPyLike_Parsed *expr;
 
        if (parse_next_token(&state) && parse_expr(&state) && state.token == 0) {
                BLI_assert(state.stack_ptr == 1);
 
-               int bytesize = sizeof(ParsedSimpleExpr) + state.ops_count * sizeof(SimpleExprOp);
+               int bytesize = sizeof(ExprPyLike_Parsed) + state.ops_count * sizeof(ExprOp);
 
-               expr = MEM_mallocN(bytesize, "ParsedSimpleExpr");
+               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(SimpleExprOp));
+               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(ParsedSimpleExpr), "ParsedSimpleExpr(empty)");
+               expr = MEM_callocN(sizeof(ExprPyLike_Parsed), "ExprPyLike_Parsed(empty)");
        }
 
        MEM_freeN(state.tokenbuf);
index edf137c..eed84ac 100644 (file)
@@ -415,7 +415,7 @@ typedef struct ChannelDriver {
        char expression[256];   /* expression to compile for evaluation */
        void *expr_comp;                /* PyObject - compiled expression, don't save this */
 
-       struct ParsedSimpleExpr *expr_simple; /* compiled simple arithmetic expression */
+       struct ExprPyLike_Parsed *expr_simple; /* compiled simple arithmetic expression */
 
        float curval;           /* result of previous evaluation */
        float influence;        /* influence of driver on result */ // XXX to be implemented... this is like the constraint influence setting
@@ -5,87 +5,87 @@
 #include <string.h>
 
 extern "C" {
-#include "BLI_simple_expr.h"
+#include "BLI_expr_pylike_eval.h"
 #include "BLI_math.h"
 };
 
 #define TRUE_VAL 1.0
 #define FALSE_VAL 0.0
 
-static void simple_expr_parse_fail_test(const char *str)
+static void expr_pylike_parse_fail_test(const char *str)
 {
-       ParsedSimpleExpr *expr = BLI_simple_expr_parse(str, 0, NULL);
+       ExprPyLike_Parsed *expr = BLI_expr_pylike_parse(str, 0, NULL);
 
-       EXPECT_FALSE(BLI_simple_expr_is_valid(expr));
+       EXPECT_FALSE(BLI_expr_pylike_is_valid(expr));
 
-       BLI_simple_expr_free(expr);
+       BLI_expr_pylike_free(expr);
 }
 
-static void simple_expr_const_test(const char *str, double value, bool force_const)
+static void expr_pylike_const_test(const char *str, double value, bool force_const)
 {
-       ParsedSimpleExpr *expr = BLI_simple_expr_parse(str, 0, NULL);
+       ExprPyLike_Parsed *expr = BLI_expr_pylike_parse(str, 0, NULL);
 
        if (force_const) {
-               EXPECT_TRUE(BLI_simple_expr_is_constant(expr));
+               EXPECT_TRUE(BLI_expr_pylike_is_constant(expr));
        }
        else {
-               EXPECT_TRUE(BLI_simple_expr_is_valid(expr));
-               EXPECT_FALSE(BLI_simple_expr_is_constant(expr));
+               EXPECT_TRUE(BLI_expr_pylike_is_valid(expr));
+               EXPECT_FALSE(BLI_expr_pylike_is_constant(expr));
        }
 
        double result;
-       eSimpleExpr_EvalStatus status = BLI_simple_expr_evaluate(expr, &result, 0, NULL);
+       eExprPyLike_EvalStatus status = BLI_expr_pylike_eval(expr, &result, 0, NULL);
 
-       EXPECT_EQ(status, SIMPLE_EXPR_SUCCESS);
+       EXPECT_EQ(status, EXPR_PYLIKE_SUCCESS);
        EXPECT_EQ(result, value);
 
-       BLI_simple_expr_free(expr);
+       BLI_expr_pylike_free(expr);
 }
 
-static ParsedSimpleExpr *parse_for_eval(const char *str, bool nonconst)
+static ExprPyLike_Parsed *parse_for_eval(const char *str, bool nonconst)
 {
        const char *names[1] = { "x" };
-       ParsedSimpleExpr *expr = BLI_simple_expr_parse(str, 1, names);
+       ExprPyLike_Parsed *expr = BLI_expr_pylike_parse(str, 1, names);
 
-       EXPECT_TRUE(BLI_simple_expr_is_valid(expr));
+       EXPECT_TRUE(BLI_expr_pylike_is_valid(expr));
 
        if (nonconst) {
-               EXPECT_FALSE(BLI_simple_expr_is_constant(expr));
+               EXPECT_FALSE(BLI_expr_pylike_is_constant(expr));
        }
 
        return expr;
 }
 
-static void verify_eval_result(ParsedSimpleExpr *expr, double x, double value)
+static void verify_eval_result(ExprPyLike_Parsed *expr, double x, double value)
 {
        double result;
-       eSimpleExpr_EvalStatus status = BLI_simple_expr_evaluate(expr, &result, 1, &x);
+       eExprPyLike_EvalStatus status = BLI_expr_pylike_eval(expr, &result, 1, &x);
 
-       EXPECT_EQ(status, SIMPLE_EXPR_SUCCESS);
+       EXPECT_EQ(status, EXPR_PYLIKE_SUCCESS);
        EXPECT_EQ(result, value);
 }
 
-static void simple_expr_eval_test(const char *str, double x, double value)
+static void expr_pylike_eval_test(const char *str, double x, double value)
 {
-       ParsedSimpleExpr *expr = parse_for_eval(str, true);
+       ExprPyLike_Parsed *expr = parse_for_eval(str, true);
        verify_eval_result(expr, x, value);
-       BLI_simple_expr_free(expr);
+       BLI_expr_pylike_free(expr);
 }
 
-static void simple_expr_error_test(const char *str, double x, eSimpleExpr_EvalStatus error)
+static void expr_pylike_error_test(const char *str, double x, eExprPyLike_EvalStatus error)
 {
-       ParsedSimpleExpr *expr = parse_for_eval(str, false);
+       ExprPyLike_Parsed *expr = parse_for_eval(str, false);
 
        double result;
-       eSimpleExpr_EvalStatus status = BLI_simple_expr_evaluate(expr, &result, 1, &x);
+       eExprPyLike_EvalStatus status = BLI_expr_pylike_eval(expr, &result, 1, &x);
 
        EXPECT_EQ(status, error);
 
-       BLI_simple_expr_free(expr);
+       BLI_expr_pylike_free(expr);
 }
 
 #define TEST_PARSE_FAIL(name, str) \
-       TEST(simple_expr, ParseFail_##name) { simple_expr_parse_fail_test(str); }
+       TEST(expr_pylike, ParseFail_##name) { expr_pylike_parse_fail_test(str); }
 
 TEST_PARSE_FAIL(Empty, "")
 TEST_PARSE_FAIL(ConstHex, "0x0")
@@ -113,15 +113,15 @@ TEST_PARSE_FAIL(Truncated10, "fmod(1,")
 
 /* Constant expression with working constant folding */
 #define TEST_CONST(name, str, value) \
-       TEST(simple_expr, Const_##name) { simple_expr_const_test(str, value, true); }
+       TEST(expr_pylike, Const_##name) { expr_pylike_const_test(str, value, true); }
 
 /* Constant expression but constant folding is not supported */
 #define TEST_RESULT(name, str, value) \
-       TEST(simple_expr, Result_##name) { simple_expr_const_test(str, value, false); }
+       TEST(expr_pylike, Result_##name) { expr_pylike_const_test(str, value, false); }
 
 /* Expression with an argument */
 #define TEST_EVAL(name, str, x, value) \
-       TEST(simple_expr, Eval_##name) { simple_expr_eval_test(str, x, value); }
+       TEST(expr_pylike, Eval_##name) { expr_pylike_eval_test(str, x, value); }
 
 TEST_CONST(Zero, "0", 0.0)
 TEST_CONST(Zero2, "00", 0.0)
@@ -237,9 +237,9 @@ TEST_RESULT(Or2, "0 or 3", 3.0)
 TEST_RESULT(Bool1, "2 or 3 and 4", 2.0)
 TEST_RESULT(Bool2, "not 2 or 3 and 4", 4.0)
 
-TEST(simple_expr, Eval_Ternary1)
+TEST(expr_pylike, Eval_Ternary1)
 {
-       ParsedSimpleExpr *expr = parse_for_eval("x / 2 if x < 4 else x - 2 if x < 8 else x*2 - 12", true);
+       ExprPyLike_Parsed *expr = parse_for_eval("x / 2 if x < 4 else x - 2 if x < 8 else x*2 - 12", true);
 
        for (int i = 0; i <= 10; i++) {
                double x = i;
@@ -248,63 +248,63 @@ TEST(simple_expr, Eval_Ternary1)
                verify_eval_result(expr, x, v);
        }
 
-       BLI_simple_expr_free(expr);
+       BLI_expr_pylike_free(expr);
 }
 
-TEST(simple_expr, MultipleArgs)
+TEST(expr_pylike, MultipleArgs)
 {
        const char* names[3] = { "x", "y", "x" };
        double values[3] = { 1.0, 2.0, 3.0 };
 
-       ParsedSimpleExpr *expr = BLI_simple_expr_parse("x*10 + y", 3, names);
+       ExprPyLike_Parsed *expr = BLI_expr_pylike_parse("x*10 + y", 3, names);
 
-       EXPECT_TRUE(BLI_simple_expr_is_valid(expr));
+       EXPECT_TRUE(BLI_expr_pylike_is_valid(expr));
 
        double result;
-       eSimpleExpr_EvalStatus status = BLI_simple_expr_evaluate(expr, &result, 3, values);
+       eExprPyLike_EvalStatus status = BLI_expr_pylike_eval(expr, &result, 3, values);
 
-       EXPECT_EQ(status, SIMPLE_EXPR_SUCCESS);
+       EXPECT_EQ(status, EXPR_PYLIKE_SUCCESS);
        EXPECT_EQ(result, 32.0);
 
-       BLI_simple_expr_free(expr);
+       BLI_expr_pylike_free(expr);
 }
 
 #define TEST_ERROR(name, str, x, code) \
-       TEST(simple_expr, Error_##name) { simple_expr_error_test(str, x, code); }
+       TEST(expr_pylike, Error_##name) { expr_pylike_error_test(str, x, code); }
 
-TEST_ERROR(DivZero1, "0 / 0", 0.0, SIMPLE_EXPR_MATH_ERROR)
-TEST_ERROR(DivZero2, "1 / 0", 0.0, SIMPLE_EXPR_DIV_BY_ZERO)
-TEST_ERROR(DivZero3, "1 / x", 0.0, SIMPLE_EXPR_DIV_BY_ZERO)
-TEST_ERROR(DivZero4, "1 / x", 1.0, SIMPLE_EXPR_SUCCESS)
+TEST_ERROR(DivZero1, "0 / 0", 0.0, EXPR_PYLIKE_MATH_ERROR)
+TEST_ERROR(DivZero2, "1 / 0", 0.0, EXPR_PYLIKE_DIV_BY_ZERO)
+TEST_ERROR(DivZero3, "1 / x", 0.0, EXPR_PYLIKE_DIV_BY_ZERO)
+TEST_ERROR(DivZero4, "1 / x", 1.0, EXPR_PYLIKE_SUCCESS)
 
-TEST_ERROR(SqrtDomain1, "sqrt(-1)", 0.0, SIMPLE_EXPR_MATH_ERROR)
-TEST_ERROR(SqrtDomain2, "sqrt(x)", -1.0, SIMPLE_EXPR_MATH_ERROR)
-TEST_ERROR(SqrtDomain3, "sqrt(x)", 0.0, SIMPLE_EXPR_SUCCESS)
+TEST_ERROR(SqrtDomain1, "sqrt(-1)", 0.0, EXPR_PYLIKE_MATH_ERROR)
+TEST_ERROR(SqrtDomain2, "sqrt(x)", -1.0, EXPR_PYLIKE_MATH_ERROR)
+TEST_ERROR(SqrtDomain3, "sqrt(x)", 0.0, EXPR_PYLIKE_SUCCESS)
 
-TEST_ERROR(PowDomain1, "pow(-1, 0.5)", 0.0, SIMPLE_EXPR_MATH_ERROR)
-TEST_ERROR(PowDomain2, "pow(-1, x)", 0.5, SIMPLE_EXPR_MATH_ERROR)
-TEST_ERROR(PowDomain3, "pow(-1, x)", 2.0, SIMPLE_EXPR_SUCCESS)
+TEST_ERROR(PowDomain1, "pow(-1, 0.5)", 0.0, EXPR_PYLIKE_MATH_ERROR)
+TEST_ERROR(PowDomain2, "pow(-1, x)", 0.5, EXPR_PYLIKE_MATH_ERROR)
+TEST_ERROR(PowDomain3, "pow(-1, x)", 2.0, EXPR_PYLIKE_SUCCESS)
 
-TEST_ERROR(Mixed1, "sqrt(x) + 1 / max(0, x)", -1.0, SIMPLE_EXPR_MATH_ERROR)
-TEST_ERROR(Mixed2, "sqrt(x) + 1 / max(0, x)", 0.0, SIMPLE_EXPR_DIV_BY_ZERO)
-TEST_ERROR(Mixed3, "sqrt(x) + 1 / max(0, x)", 1.0, SIMPLE_EXPR_SUCCESS)
+TEST_ERROR(Mixed1, "sqrt(x) + 1 / max(0, x)", -1.0, EXPR_PYLIKE_MATH_ERROR)
+TEST_ERROR(Mixed2, "sqrt(x) + 1 / max(0, x)", 0.0, EXPR_PYLIKE_DIV_BY_ZERO)
+TEST_ERROR(Mixed3, "sqrt(x) + 1 / max(0, x)", 1.0, EXPR_PYLIKE_SUCCESS)
 
-TEST(simple_expr, Error_Invalid)
+TEST(expr_pylike, Error_Invalid)
 {
-       ParsedSimpleExpr *expr = BLI_simple_expr_parse("", 0, NULL);
+       ExprPyLike_Parsed *expr = BLI_expr_pylike_parse("", 0, NULL);
        double result;
 
-       EXPECT_EQ(BLI_simple_expr_evaluate(expr, &result, 0, NULL), SIMPLE_EXPR_INVALID);
+       EXPECT_EQ(BLI_expr_pylike_eval(expr, &result, 0, NULL), EXPR_PYLIKE_INVALID);
 
-       BLI_simple_expr_free(expr);
+       BLI_expr_pylike_free(expr);
 }
 
-TEST(simple_expr, Error_ArgumentCount)
+TEST(expr_pylike, Error_ArgumentCount)
 {
-       ParsedSimpleExpr *expr = parse_for_eval("x", false);
+       ExprPyLike_Parsed *expr = parse_for_eval("x", false);
        double result;
 
-       EXPECT_EQ(BLI_simple_expr_evaluate(expr, &result, 0, NULL), SIMPLE_EXPR_FATAL_ERROR);
+       EXPECT_EQ(BLI_expr_pylike_eval(expr, &result, 0, NULL), EXPR_PYLIKE_FATAL_ERROR);
 
-       BLI_simple_expr_free(expr);
+       BLI_expr_pylike_free(expr);
 }
index 1db7949..7574d42 100644 (file)
@@ -43,6 +43,7 @@ endif()
 
 BLENDER_TEST(BLI_array_store "bf_blenlib")
 BLENDER_TEST(BLI_array_utils "bf_blenlib")
+BLENDER_TEST(BLI_expr_pylike_eval "bf_blenlib")
 BLENDER_TEST(BLI_ghash "bf_blenlib")
 BLENDER_TEST(BLI_hash_mm2a "bf_blenlib")
 BLENDER_TEST(BLI_heap "bf_blenlib")
@@ -55,7 +56,6 @@ BLENDER_TEST(BLI_math_geom "bf_blenlib")
 BLENDER_TEST(BLI_memiter "bf_blenlib")
 BLENDER_TEST(BLI_path_util "${BLI_path_util_extra_libs}")
 BLENDER_TEST(BLI_polyfill_2d "bf_blenlib")
-BLENDER_TEST(BLI_simple_expr "bf_blenlib")
 BLENDER_TEST(BLI_stack "bf_blenlib")
 BLENDER_TEST(BLI_string "bf_blenlib")
 BLENDER_TEST(BLI_string_utf8 "bf_blenlib")