Blender V5.0
expr_pylike_eval.cc File Reference
#include <cctype>
#include <cfenv>
#include <cmath>
#include <cstddef>
#include <cstdlib>
#include <cstring>
#include <variant>
#include "MEM_guardedalloc.h"
#include "BLI_alloca.h"
#include "BLI_expr_pylike_eval.h"
#include "BLI_math_base.h"
#include "BLI_utildefines.h"
#include "BLI_vector.hh"

Go to the source code of this file.

Classes

struct  ExprOp
struct  ExprPyLike_Parsed
struct  BuiltinConstDef
struct  BuiltinOpDef
struct  KeywordTokenDef
struct  ExprParseState

Macros

#define FAIL_IF(condition)

Functions

Public API
void BLI_expr_pylike_free (ExprPyLike_Parsed *expr)
bool BLI_expr_pylike_is_valid (const ExprPyLike_Parsed *expr)
bool BLI_expr_pylike_is_constant (const ExprPyLike_Parsed *expr)
bool BLI_expr_pylike_is_using_param (const ExprPyLike_Parsed *expr, int index)
Stack Machine Evaluation
eExprPyLike_EvalStatus BLI_expr_pylike_eval (ExprPyLike_Parsed *expr, const double *param_values, int param_values_len, double *r_result)
Recursive Descent Parser
static bool parse_expr (ExprParseState *state)
static int parse_function_args (ExprParseState *state)
static bool parse_unary (ExprParseState *state)
static bool parse_mul (ExprParseState *state)
static bool parse_add (ExprParseState *state)
static BinaryOpFunc parse_get_cmp_func (short token)
static bool parse_cmp_chain (ExprParseState *state, BinaryOpFunc cur_func)
static bool parse_cmp (ExprParseState *state)
static bool parse_not (ExprParseState *state)
static bool parse_and (ExprParseState *state)
static bool parse_or (ExprParseState *state)
Main Parsing Function
ExprPyLike_ParsedBLI_expr_pylike_parse (const char *expression, const char **param_names, int param_names_len)

Expression Parser State

#define MAKE_CHAR2(a, b)
#define CHECK_ERROR(condition)
#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 = "~`!@#$%^&*+-=/\\?:;<>(){}[]|.,\"'"
static KeywordTokenDef keyword_list []
static ExprOpparse_add_op (ExprParseState *state, eOpCode code, int stack_delta)
static int parse_add_jump (ExprParseState *state, eOpCode code)
static void parse_set_jump (ExprParseState *state, int jump)
static bool parse_add_func (ExprParseState *state, std::variant< UnaryOpFunc, BinaryOpFunc, TernaryOpFunc > funcptr)
static bool parse_next_token (ExprParseState *state)

Internal Types

enum  eOpCode {
  OPCODE_CONST , OPCODE_FUNC1 , OPCODE_FUNC2 , OPCODE_FUNC3 ,
  OPCODE_PARAMETER , OPCODE_MIN , OPCODE_MAX , OPCODE_JMP ,
  OPCODE_JMP_ELSE , OPCODE_JMP_OR , OPCODE_JMP_AND , OPCODE_CMP_CHAIN
}
using UnaryOpFunc = double (*)(double)
using BinaryOpFunc = double (*)(double, double)
using TernaryOpFunc = double (*)(double, double, double)

Built-In Operations

static BuiltinConstDef builtin_consts []
static BuiltinOpDef builtin_ops []
static double op_negate (double arg)
static double op_mul (double a, double b)
static double op_div (double a, double b)
static double op_add (double a, double b)
static double op_sub (double a, double b)
static double op_radians (double arg)
static double op_degrees (double arg)
static double op_log2 (double a, double b)
static double op_lerp (double a, double b, double x)
static double op_clamp (double arg)
static double op_clamp3 (double arg, double minv, double maxv)
static double op_smoothstep (double a, double b, double x)
static double op_not (double a)
static double op_eq (double a, double b)
static double op_ne (double a, double b)
static double op_lt (double a, double b)
static double op_le (double a, double b)
static double op_gt (double a, double b)
static double op_ge (double a, double b)

Detailed Description

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: min, max, 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 multi-threaded.

Definition in file expr_pylike_eval.cc.

Macro Definition Documentation

◆ CHECK_ERROR

#define CHECK_ERROR ( condition)
Value:
if (!(condition)) { \
return false; \
} \
((void)0)

Definition at line 450 of file expr_pylike_eval.cc.

Referenced by parse_add(), parse_and(), parse_cmp(), parse_cmp_chain(), parse_expr(), parse_mul(), parse_next_token(), parse_not(), parse_or(), and parse_unary().

◆ FAIL_IF

#define FAIL_IF ( condition)
Value:
if (condition) { \
} \
((void)0)
@ EXPR_PYLIKE_FATAL_ERROR

Referenced by BLI_expr_pylike_eval().

◆ MAKE_CHAR2

#define MAKE_CHAR2 ( a,
b )
Value:

Definition at line 448 of file expr_pylike_eval.cc.

Referenced by parse_next_token().

◆ TOKEN_AND

#define TOKEN_AND   MAKE_CHAR2('A', 'N')

Definition at line 464 of file expr_pylike_eval.cc.

Referenced by parse_and().

◆ TOKEN_ELSE

#define TOKEN_ELSE   MAKE_CHAR2('E', 'L')

Definition at line 468 of file expr_pylike_eval.cc.

Referenced by parse_expr().

◆ TOKEN_EQ

#define TOKEN_EQ   MAKE_CHAR2('=', '=')

Definition at line 463 of file expr_pylike_eval.cc.

Referenced by parse_get_cmp_func().

◆ TOKEN_GE

#define TOKEN_GE   MAKE_CHAR2('>', '=')

Definition at line 460 of file expr_pylike_eval.cc.

Referenced by parse_get_cmp_func().

◆ TOKEN_ID

#define TOKEN_ID   MAKE_CHAR2('I', 'D')

Definition at line 458 of file expr_pylike_eval.cc.

Referenced by parse_next_token(), and parse_unary().

◆ TOKEN_IF

#define TOKEN_IF   MAKE_CHAR2('I', 'F')

Definition at line 467 of file expr_pylike_eval.cc.

Referenced by parse_expr().

◆ TOKEN_LE

#define TOKEN_LE   MAKE_CHAR2('<', '=')

Definition at line 461 of file expr_pylike_eval.cc.

Referenced by parse_get_cmp_func().

◆ TOKEN_NE

#define TOKEN_NE   MAKE_CHAR2('!', '=')

Definition at line 462 of file expr_pylike_eval.cc.

Referenced by parse_get_cmp_func().

◆ TOKEN_NOT

#define TOKEN_NOT   MAKE_CHAR2('N', 'O')

Definition at line 466 of file expr_pylike_eval.cc.

Referenced by parse_not().

◆ TOKEN_NUMBER

#define TOKEN_NUMBER   MAKE_CHAR2('0', '0')

Definition at line 459 of file expr_pylike_eval.cc.

Referenced by parse_next_token(), and parse_unary().

◆ TOKEN_OR

#define TOKEN_OR   MAKE_CHAR2('O', 'R')

Definition at line 465 of file expr_pylike_eval.cc.

Referenced by parse_or().

Typedef Documentation

◆ BinaryOpFunc

using BinaryOpFunc = double (*)(double, double)

Definition at line 81 of file expr_pylike_eval.cc.

◆ TernaryOpFunc

using TernaryOpFunc = double (*)(double, double, double)

Definition at line 82 of file expr_pylike_eval.cc.

◆ UnaryOpFunc

using UnaryOpFunc = double (*)(double)

Definition at line 80 of file expr_pylike_eval.cc.

Enumeration Type Documentation

◆ eOpCode

enum eOpCode
Enumerator
OPCODE_CONST 

Double constant: (-> dval).

OPCODE_FUNC1 

1 argument function call: (a -> func1(a)).

OPCODE_FUNC2 

2 argument function call: (a b -> func2(a,b)).

OPCODE_FUNC3 

3 argument function call: (a b c -> func3(a,b,c)).

OPCODE_PARAMETER 

Parameter access: (-> params[ival]).

OPCODE_MIN 

Minimum of multiple inputs: (a b c... -> min); ival = arg count.

OPCODE_MAX 

Maximum of multiple inputs: (a b c... -> max); ival = arg count.

OPCODE_JMP 

Jump (pc += jmp_offset)

OPCODE_JMP_ELSE 

Pop and jump if zero: (a -> ); JUMP IF NOT a.

OPCODE_JMP_OR 

Jump if nonzero, or pop: (a -> a JUMP) IF a ELSE (a -> ).

OPCODE_JMP_AND 

Jump if zero, or pop: (a -> a JUMP) IF NOT a ELSE (a -> ).

OPCODE_CMP_CHAIN 

For comparison chaining: (a b -> 0 JUMP) IF NOT func2(a,b) ELSE (a b -> b).

Definition at line 53 of file expr_pylike_eval.cc.

Function Documentation

◆ BLI_expr_pylike_eval()

◆ BLI_expr_pylike_free()

void BLI_expr_pylike_free ( struct ExprPyLike_Parsed * expr)

Free the parsed data; NULL argument is ok.

Definition at line 110 of file expr_pylike_eval.cc.

Referenced by BKE_driver_invalidate_expression(), driver_compile_simple_expr(), and fcurve_free_driver().

◆ BLI_expr_pylike_is_constant()

bool BLI_expr_pylike_is_constant ( const ExprPyLike_Parsed * expr)

◆ BLI_expr_pylike_is_using_param()

bool BLI_expr_pylike_is_using_param ( const ExprPyLike_Parsed * expr,
int index )

◆ BLI_expr_pylike_is_valid()

bool BLI_expr_pylike_is_valid ( const ExprPyLike_Parsed * expr)

◆ BLI_expr_pylike_parse()

ExprPyLike_Parsed * BLI_expr_pylike_parse ( const char * expression,
const char ** param_names,
int param_names_len )

Compile the expression and return the result.

Parse the expression for evaluation later. Returns non-NULL even on failure; use is_valid to check.

Definition at line 1038 of file expr_pylike_eval.cc.

References BLI_assert, ExprPyLike_Parsed::max_stack, ExprPyLike_Parsed::ops, parse_expr(), parse_next_token(), and state.

Referenced by driver_compile_simple_expr_impl(), expr_pylike_const_test(), expr_pylike_parse_fail_test(), parse_for_eval(), TEST(), and TEST().

◆ op_add()

double op_add ( double a,
double b )
static

Definition at line 291 of file expr_pylike_eval.cc.

References b.

Referenced by parse_add().

◆ op_clamp()

double op_clamp ( double arg)
static

Definition at line 321 of file expr_pylike_eval.cc.

References CLAMP.

◆ op_clamp3()

double op_clamp3 ( double arg,
double minv,
double maxv )
static

Definition at line 327 of file expr_pylike_eval.cc.

References CLAMP.

◆ op_degrees()

double op_degrees ( double arg)
static

Definition at line 306 of file expr_pylike_eval.cc.

References M_PI.

◆ op_div()

double op_div ( double a,
double b )
static

Definition at line 286 of file expr_pylike_eval.cc.

References b.

Referenced by parse_mul().

◆ op_eq()

double op_eq ( double a,
double b )
static

Definition at line 345 of file expr_pylike_eval.cc.

References b.

Referenced by parse_get_cmp_func().

◆ op_ge()

double op_ge ( double a,
double b )
static

Definition at line 370 of file expr_pylike_eval.cc.

References b.

Referenced by parse_get_cmp_func().

◆ op_gt()

double op_gt ( double a,
double b )
static

Definition at line 365 of file expr_pylike_eval.cc.

References b.

Referenced by parse_get_cmp_func().

◆ op_le()

double op_le ( double a,
double b )
static

Definition at line 360 of file expr_pylike_eval.cc.

References b.

Referenced by parse_get_cmp_func().

◆ op_lerp()

double op_lerp ( double a,
double b,
double x )
static

Definition at line 316 of file expr_pylike_eval.cc.

References b, and x.

◆ op_log2()

double op_log2 ( double a,
double b )
static

Definition at line 311 of file expr_pylike_eval.cc.

References b, and log.

◆ op_lt()

double op_lt ( double a,
double b )
static

Definition at line 355 of file expr_pylike_eval.cc.

References b.

Referenced by parse_get_cmp_func().

◆ op_mul()

double op_mul ( double a,
double b )
static

Definition at line 281 of file expr_pylike_eval.cc.

References b.

Referenced by parse_mul().

◆ op_ne()

double op_ne ( double a,
double b )
static

Definition at line 350 of file expr_pylike_eval.cc.

References b.

Referenced by parse_get_cmp_func().

◆ op_negate()

double op_negate ( double arg)
static

Definition at line 276 of file expr_pylike_eval.cc.

Referenced by parse_unary().

◆ op_not()

double op_not ( double a)
static

Definition at line 340 of file expr_pylike_eval.cc.

Referenced by parse_not().

◆ op_radians()

double op_radians ( double arg)
static

Definition at line 301 of file expr_pylike_eval.cc.

References M_PI.

◆ op_smoothstep()

double op_smoothstep ( double a,
double b,
double x )
static

Definition at line 333 of file expr_pylike_eval.cc.

References b, CLAMP, and x.

◆ op_sub()

double op_sub ( double a,
double b )
static

◆ parse_add()

bool parse_add ( ExprParseState * state)
static

◆ parse_add_func()

◆ parse_add_jump()

int parse_add_jump ( ExprParseState * state,
eOpCode code )
static

Definition at line 524 of file expr_pylike_eval.cc.

References parse_add_op(), and state.

Referenced by parse_and(), parse_expr(), and parse_or().

◆ parse_add_op()

ExprOp * parse_add_op ( ExprParseState * state,
eOpCode code,
int stack_delta )
static

Definition at line 510 of file expr_pylike_eval.cc.

References CLAMP_MIN, and state.

Referenced by parse_add_func(), parse_add_jump(), parse_cmp_chain(), and parse_unary().

◆ parse_and()

bool parse_and ( ExprParseState * state)
static

◆ parse_cmp()

bool parse_cmp ( ExprParseState * state)
static

◆ parse_cmp_chain()

◆ parse_expr()

◆ parse_function_args()

int parse_function_args ( ExprParseState * state)
static

Definition at line 718 of file expr_pylike_eval.cc.

References parse_expr(), parse_next_token(), and state.

Referenced by parse_unary().

◆ parse_get_cmp_func()

BinaryOpFunc parse_get_cmp_func ( short token)
static

Definition at line 882 of file expr_pylike_eval.cc.

References op_eq(), op_ge(), op_gt(), op_le(), op_lt(), op_ne(), TOKEN_EQ, TOKEN_GE, TOKEN_LE, and TOKEN_NE.

Referenced by parse_cmp(), and parse_cmp_chain().

◆ parse_mul()

bool parse_mul ( ExprParseState * state)
static

Definition at line 838 of file expr_pylike_eval.cc.

References CHECK_ERROR, op_div(), op_mul(), parse_add_func(), parse_next_token(), parse_unary(), and state.

Referenced by parse_add().

◆ parse_next_token()

◆ parse_not()

bool parse_not ( ExprParseState * state)
static

◆ parse_or()

bool parse_or ( ExprParseState * state)
static

◆ parse_set_jump()

void parse_set_jump ( ExprParseState * state,
int jump )
static

Definition at line 531 of file expr_pylike_eval.cc.

References jump(), and state.

Referenced by parse_and(), parse_cmp_chain(), parse_expr(), and parse_or().

◆ parse_unary()

Variable Documentation

◆ builtin_consts

BuiltinConstDef builtin_consts[]
static
Initial value:
= {
{"pi", M_PI}, {"True", 1.0}, {"False", 0.0}, {nullptr, 0.0}}
#define M_PI

Definition at line 380 of file expr_pylike_eval.cc.

Referenced by parse_unary().

◆ builtin_ops

BuiltinOpDef builtin_ops[]
static
Initial value:
= {
{"radians", UnaryOpFunc(op_radians)},
{"degrees", UnaryOpFunc(op_degrees)},
{"abs", UnaryOpFunc(fabs)},
{"fabs", UnaryOpFunc(fabs)},
{"floor", UnaryOpFunc(floor)},
{"ceil", UnaryOpFunc(ceil)},
{"trunc", UnaryOpFunc(trunc)},
{"round", UnaryOpFunc(round)},
{"int", UnaryOpFunc(trunc)},
{"sin", UnaryOpFunc(sin)},
{"cos", UnaryOpFunc(cos)},
{"tan", UnaryOpFunc(tan)},
{"asin", UnaryOpFunc(asin)},
{"acos", UnaryOpFunc(acos)},
{"atan", UnaryOpFunc(atan)},
{"atan2", BinaryOpFunc(atan2)},
{"exp", UnaryOpFunc(exp)},
{"log", UnaryOpFunc(log)},
{"log", BinaryOpFunc(op_log2)},
{"sqrt", UnaryOpFunc(sqrt)},
{"pow", BinaryOpFunc(pow)},
{"fmod", BinaryOpFunc(fmod)},
{"lerp", TernaryOpFunc(op_lerp)},
{"clamp", UnaryOpFunc(op_clamp)},
{"clamp", TernaryOpFunc(op_clamp3)},
{"smoothstep", TernaryOpFunc(op_smoothstep)},
{nullptr},
}
double(*)(double, double, double) TernaryOpFunc
static double op_clamp3(double arg, double minv, double maxv)
static double op_smoothstep(double a, double b, double x)
static double op_lerp(double a, double b, double x)
double(*)(double, double) BinaryOpFunc
static double op_degrees(double arg)
static double op_log2(double a, double b)
static double op_clamp(double arg)
double(*)(double) UnaryOpFunc
static double op_radians(double arg)
#define atan
#define tan
#define log
#define sin
#define round
#define pow
#define exp
#define cos
#define trunc
#define floor
#define ceil
#define sqrt
#define asin
#define acos
ccl_device_inline float2 fmod(const float2 a, const float b)
ccl_device_inline float2 fabs(const float2 a)
ccl_device_inline float3 atan2(const float3 y, const float3 x)

Definition at line 412 of file expr_pylike_eval.cc.

Referenced by parse_unary().

◆ keyword_list

KeywordTokenDef keyword_list[]
static
Initial value:
= {
{"and", TOKEN_AND},
{"or", TOKEN_OR},
{"not", TOKEN_NOT},
{"if", TOKEN_IF},
{"else", TOKEN_ELSE},
{nullptr, TOKEN_ID},
}
#define TOKEN_ID
#define TOKEN_NOT
#define TOKEN_ELSE
#define TOKEN_OR
#define TOKEN_IF
#define TOKEN_AND

Definition at line 478 of file expr_pylike_eval.cc.

Referenced by denoise_func(), merge_func(), and parse_next_token().

◆ token_characters

const char* token_characters = "~`!@#$%^&*+-=/\\?:;<>(){}[]|.,\"'"
static

Definition at line 471 of file expr_pylike_eval.cc.

Referenced by parse_next_token().

◆ token_eq_characters

const char* token_eq_characters = "!=><"
static

Definition at line 470 of file expr_pylike_eval.cc.

Referenced by parse_next_token().