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:
authorCampbell Barton <ideasman42@gmail.com>2018-09-19 03:40:35 +0300
committerCampbell Barton <ideasman42@gmail.com>2018-09-19 04:08:04 +0300
commit3aea5695bbdcf83c5c7769a629e0a2e4db0c85bc (patch)
tree6825ecce4a5a937f03bbd0b8dcb79faddd3be7be /source/blender/blenlib
parent345c34826296907d85b4b367a830ff4f73ab293f (diff)
Cleanup: rename BLI_simple_expr -> BLI_expr_pylike_eval
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.
Diffstat (limited to 'source/blender/blenlib')
-rw-r--r--source/blender/blenlib/BLI_expr_pylike_eval.h63
-rw-r--r--source/blender/blenlib/BLI_simple_expr.h96
-rw-r--r--source/blender/blenlib/CMakeLists.txt3
-rw-r--r--source/blender/blenlib/intern/expr_pylike_eval.c (renamed from source/blender/blenlib/intern/simple_expr.c)116
4 files changed, 140 insertions, 138 deletions
diff --git a/source/blender/blenlib/BLI_expr_pylike_eval.h b/source/blender/blenlib/BLI_expr_pylike_eval.h
new file mode 100644
index 00000000000..b627664cc14
--- /dev/null
+++ b/source/blender/blenlib/BLI_expr_pylike_eval.h
@@ -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
index 8498f1a02e7..00000000000
--- a/source/blender/blenlib/BLI_simple_expr.h
+++ /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__*/
diff --git a/source/blender/blenlib/CMakeLists.txt b/source/blender/blenlib/CMakeLists.txt
index 9dd89834bbd..6c56b06bc0e 100644
--- a/source/blender/blenlib/CMakeLists.txt
+++ b/source/blender/blenlib/CMakeLists.txt
@@ -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
diff --git a/source/blender/blenlib/intern/simple_expr.c b/source/blender/blenlib/intern/expr_pylike_eval.c
index cfab74f9681..c80cd505efa 100644
--- a/source/blender/blenlib/intern/simple_expr.c
+++ b/source/blender/blenlib/intern/expr_pylike_eval.c
@@ -25,8 +25,30 @@
* ***** 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);