Blender  V3.3
expr_pylike_eval.c
Go to the documentation of this file.
1 /* SPDX-License-Identifier: GPL-2.0-or-later
2  * Copyright 2018 Blender Foundation, Alexander Gavrilov. All rights reserved. */
3 
28 #include <ctype.h>
29 #include <fenv.h>
30 #include <float.h>
31 #include <math.h>
32 #include <stddef.h>
33 #include <stdio.h>
34 #include <stdlib.h>
35 #include <string.h>
36 
37 #include "MEM_guardedalloc.h"
38 
39 #include "BLI_alloca.h"
40 #include "BLI_expr_pylike_eval.h"
41 #include "BLI_math_base.h"
42 #include "BLI_utildefines.h"
43 
44 #ifdef _MSC_VER
45 # pragma fenv_access(on)
46 #endif
47 
48 /* -------------------------------------------------------------------- */
52 typedef enum eOpCode {
53  /* Double constant: (-> dval). */
55  /* 1 argument function call: (a -> func1(a)). */
57  /* 2 argument function call: (a b -> func2(a,b)). */
59  /* 3 argument function call: (a b c -> func3(a,b,c)). */
61  /* Parameter access: (-> params[ival]) */
63  /* Minimum of multiple inputs: (a b c... -> min); ival = arg count. */
65  /* Maximum of multiple inputs: (a b c... -> max); ival = arg count. */
67  /* Jump (pc += jmp_offset) */
69  /* Pop and jump if zero: (a -> ); JUMP IF NOT a. */
71  /* Jump if nonzero, or pop: (a -> a JUMP) IF a ELSE (a -> ). */
73  /* Jump if zero, or pop: (a -> a JUMP) IF NOT a ELSE (a -> ). */
75  /* For comparison chaining: (a b -> 0 JUMP) IF NOT func2(a,b) ELSE (a b -> b). */
78 
82 
83 typedef struct ExprOp {
85 
87 
88  union {
89  int ival;
90  double dval;
91  void *ptr;
95  } arg;
97 
99  int ops_count;
101 
103 };
104 
107 /* -------------------------------------------------------------------- */
112 {
113  if (expr != NULL) {
114  MEM_freeN(expr);
115  }
116 }
117 
119 {
120  return expr != NULL && expr->ops_count > 0;
121 }
122 
124 {
125  return expr != NULL && expr->ops_count == 1 && expr->ops[0].opcode == OPCODE_CONST;
126 }
127 
129 {
130  int i;
131 
132  if (expr == NULL) {
133  return false;
134  }
135 
136  for (i = 0; i < expr->ops_count; i++) {
137  if (expr->ops[i].opcode == OPCODE_PARAMETER && expr->ops[i].arg.ival == index) {
138  return true;
139  }
140  }
141 
142  return false;
143 }
144 
147 /* -------------------------------------------------------------------- */
152  const double *param_values,
153  int param_values_len,
154  double *r_result)
155 {
156  *r_result = 0.0;
157 
158  if (!BLI_expr_pylike_is_valid(expr)) {
159  return EXPR_PYLIKE_INVALID;
160  }
161 
162 #define FAIL_IF(condition) \
163  if (condition) { \
164  return EXPR_PYLIKE_FATAL_ERROR; \
165  } \
166  ((void)0)
167 
168  /* Check the stack requirement is at least remotely sane and allocate on the actual stack. */
169  FAIL_IF(expr->max_stack <= 0 || expr->max_stack > 1000);
170 
171  double *stack = BLI_array_alloca(stack, expr->max_stack);
172 
173  /* Evaluate expression. */
174  ExprOp *ops = expr->ops;
175  int sp = 0, pc;
176 
177  feclearexcept(FE_ALL_EXCEPT);
178 
179  for (pc = 0; pc >= 0 && pc < expr->ops_count; pc++) {
180  switch (ops[pc].opcode) {
181  /* Arithmetic */
182  case OPCODE_CONST:
183  FAIL_IF(sp >= expr->max_stack);
184  stack[sp++] = ops[pc].arg.dval;
185  break;
186  case OPCODE_PARAMETER:
187  FAIL_IF(sp >= expr->max_stack || ops[pc].arg.ival >= param_values_len);
188  stack[sp++] = param_values[ops[pc].arg.ival];
189  break;
190  case OPCODE_FUNC1:
191  FAIL_IF(sp < 1);
192  stack[sp - 1] = ops[pc].arg.func1(stack[sp - 1]);
193  break;
194  case OPCODE_FUNC2:
195  FAIL_IF(sp < 2);
196  stack[sp - 2] = ops[pc].arg.func2(stack[sp - 2], stack[sp - 1]);
197  sp--;
198  break;
199  case OPCODE_FUNC3:
200  FAIL_IF(sp < 3);
201  stack[sp - 3] = ops[pc].arg.func3(stack[sp - 3], stack[sp - 2], stack[sp - 1]);
202  sp -= 2;
203  break;
204  case OPCODE_MIN:
205  FAIL_IF(sp < ops[pc].arg.ival);
206  for (int j = 1; j < ops[pc].arg.ival; j++, sp--) {
207  CLAMP_MAX(stack[sp - 2], stack[sp - 1]);
208  }
209  break;
210  case OPCODE_MAX:
211  FAIL_IF(sp < ops[pc].arg.ival);
212  for (int j = 1; j < ops[pc].arg.ival; j++, sp--) {
213  CLAMP_MIN(stack[sp - 2], stack[sp - 1]);
214  }
215  break;
216 
217  /* Jumps */
218  case OPCODE_JMP:
219  pc += ops[pc].jmp_offset;
220  break;
221  case OPCODE_JMP_ELSE:
222  FAIL_IF(sp < 1);
223  if (!stack[--sp]) {
224  pc += ops[pc].jmp_offset;
225  }
226  break;
227  case OPCODE_JMP_OR:
228  case OPCODE_JMP_AND:
229  FAIL_IF(sp < 1);
230  if (!stack[sp - 1] == !(ops[pc].opcode == OPCODE_JMP_OR)) {
231  pc += ops[pc].jmp_offset;
232  }
233  else {
234  sp--;
235  }
236  break;
237 
238  /* For chaining comparisons, i.e. "a < b < c" as "a < b and b < c" */
239  case OPCODE_CMP_CHAIN:
240  FAIL_IF(sp < 2);
241  /* If comparison fails, return 0 and jump to end. */
242  if (!ops[pc].arg.func2(stack[sp - 2], stack[sp - 1])) {
243  stack[sp - 2] = 0.0;
244  pc += ops[pc].jmp_offset;
245  }
246  /* Otherwise keep b on the stack and proceed. */
247  else {
248  stack[sp - 2] = stack[sp - 1];
249  }
250  sp--;
251  break;
252 
253  default:
255  }
256  }
257 
258  FAIL_IF(sp != 1 || pc != expr->ops_count);
259 
260 #undef FAIL_IF
261 
262  *r_result = stack[0];
263 
264  /* Detect floating point evaluation errors. */
265  int flags = fetestexcept(FE_DIVBYZERO | FE_INVALID);
266  if (flags) {
267  return (flags & FE_INVALID) ? EXPR_PYLIKE_MATH_ERROR : EXPR_PYLIKE_DIV_BY_ZERO;
268  }
269 
270  return EXPR_PYLIKE_SUCCESS;
271 }
272 
275 /* -------------------------------------------------------------------- */
279 static double op_negate(double arg)
280 {
281  return -arg;
282 }
283 
284 static double op_mul(double a, double b)
285 {
286  return a * b;
287 }
288 
289 static double op_div(double a, double b)
290 {
291  return a / b;
292 }
293 
294 static double op_add(double a, double b)
295 {
296  return a + b;
297 }
298 
299 static double op_sub(double a, double b)
300 {
301  return a - b;
302 }
303 
304 static double op_radians(double arg)
305 {
306  return arg * M_PI / 180.0;
307 }
308 
309 static double op_degrees(double arg)
310 {
311  return arg * 180.0 / M_PI;
312 }
313 
314 static double op_log2(double a, double b)
315 {
316  return log(a) / log(b);
317 }
318 
319 static double op_lerp(double a, double b, double x)
320 {
321  return a * (1.0 - x) + b * x;
322 }
323 
324 static double op_clamp(double arg)
325 {
326  CLAMP(arg, 0.0, 1.0);
327  return arg;
328 }
329 
330 static double op_clamp3(double arg, double minv, double maxv)
331 {
332  CLAMP(arg, minv, maxv);
333  return arg;
334 }
335 
336 static double op_smoothstep(double a, double b, double x)
337 {
338  double t = (x - a) / (b - a);
339  CLAMP(t, 0.0, 1.0);
340  return t * t * (3.0 - 2.0 * t);
341 }
342 
343 static double op_not(double a)
344 {
345  return a ? 0.0 : 1.0;
346 }
347 
348 static double op_eq(double a, double b)
349 {
350  return a == b ? 1.0 : 0.0;
351 }
352 
353 static double op_ne(double a, double b)
354 {
355  return a != b ? 1.0 : 0.0;
356 }
357 
358 static double op_lt(double a, double b)
359 {
360  return a < b ? 1.0 : 0.0;
361 }
362 
363 static double op_le(double a, double b)
364 {
365  return a <= b ? 1.0 : 0.0;
366 }
367 
368 static double op_gt(double a, double b)
369 {
370  return a > b ? 1.0 : 0.0;
371 }
372 
373 static double op_ge(double a, double b)
374 {
375  return a >= b ? 1.0 : 0.0;
376 }
377 
378 typedef struct BuiltinConstDef {
379  const char *name;
380  double value;
382 
384  {"pi", M_PI}, {"True", 1.0}, {"False", 0.0}, {NULL, 0.0}};
385 
386 typedef struct BuiltinOpDef {
387  const char *name;
389  void *funcptr;
391 
392 #ifdef _MSC_VER
393 /* Prevent MSVC from inlining calls to ceil/floor so the table below can get a function pointer to
394  * them. */
395 # pragma function(ceil)
396 # pragma function(floor)
397 #endif
398 
400  {"radians", OPCODE_FUNC1, op_radians},
401  {"degrees", OPCODE_FUNC1, op_degrees},
402  {"abs", OPCODE_FUNC1, fabs},
403  {"fabs", OPCODE_FUNC1, fabs},
404  {"floor", OPCODE_FUNC1, floor},
405  {"ceil", OPCODE_FUNC1, ceil},
406  {"trunc", OPCODE_FUNC1, trunc},
407  {"round", OPCODE_FUNC1, round},
408  {"int", OPCODE_FUNC1, trunc},
409  {"sin", OPCODE_FUNC1, sin},
410  {"cos", OPCODE_FUNC1, cos},
411  {"tan", OPCODE_FUNC1, tan},
412  {"asin", OPCODE_FUNC1, asin},
413  {"acos", OPCODE_FUNC1, acos},
414  {"atan", OPCODE_FUNC1, atan},
415  {"atan2", OPCODE_FUNC2, atan2},
416  {"exp", OPCODE_FUNC1, exp},
417  {"log", OPCODE_FUNC1, log},
418  {"log", OPCODE_FUNC2, op_log2},
419  {"sqrt", OPCODE_FUNC1, sqrt},
420  {"pow", OPCODE_FUNC2, pow},
421  {"fmod", OPCODE_FUNC2, fmod},
422  {"lerp", OPCODE_FUNC3, op_lerp},
423  {"clamp", OPCODE_FUNC1, op_clamp},
424  {"clamp", OPCODE_FUNC3, op_clamp3},
425  {"smoothstep", OPCODE_FUNC3, op_smoothstep},
426  {NULL, OPCODE_CONST, NULL},
427 };
428 
431 /* -------------------------------------------------------------------- */
435 #define MAKE_CHAR2(a, b) (((a) << 8) | (b))
436 
437 #define CHECK_ERROR(condition) \
438  if (!(condition)) { \
439  return false; \
440  } \
441  ((void)0)
442 
443 /* For simplicity simple token types are represented by their own character;
444  * these are special identifiers for multi-character tokens. */
445 #define TOKEN_ID MAKE_CHAR2('I', 'D')
446 #define TOKEN_NUMBER MAKE_CHAR2('0', '0')
447 #define TOKEN_GE MAKE_CHAR2('>', '=')
448 #define TOKEN_LE MAKE_CHAR2('<', '=')
449 #define TOKEN_NE MAKE_CHAR2('!', '=')
450 #define TOKEN_EQ MAKE_CHAR2('=', '=')
451 #define TOKEN_AND MAKE_CHAR2('A', 'N')
452 #define TOKEN_OR MAKE_CHAR2('O', 'R')
453 #define TOKEN_NOT MAKE_CHAR2('N', 'O')
454 #define TOKEN_IF MAKE_CHAR2('I', 'F')
455 #define TOKEN_ELSE MAKE_CHAR2('E', 'L')
456 
457 static const char *token_eq_characters = "!=><";
458 static const char *token_characters = "~`!@#$%^&*+-=/\\?:;<>(){}[]|.,\"'";
459 
460 typedef struct KeywordTokenDef {
461  const char *name;
462  short token;
464 
466  {"and", TOKEN_AND},
467  {"or", TOKEN_OR},
468  {"not", TOKEN_NOT},
469  {"if", TOKEN_IF},
470  {"else", TOKEN_ELSE},
471  {NULL, TOKEN_ID},
472 };
473 
474 typedef struct ExprParseState {
476  const char **param_names;
477 
478  /* Original expression */
479  const char *expr;
480  const char *cur;
481 
482  /* Current token */
483  short token;
484  char *tokenbuf;
485  double tokenval;
486 
487  /* Opcode buffer */
490 
491  /* Stack space requirement tracking */
494 
495 /* Reserve space for the specified number of operations in the buffer. */
497 {
498  if (state->ops_count + count > state->max_ops) {
499  state->max_ops = power_of_2_max_i(state->ops_count + count);
500  state->ops = MEM_reallocN(state->ops, state->max_ops * sizeof(ExprOp));
501  }
502 
503  ExprOp *op = &state->ops[state->ops_count];
504  state->ops_count += count;
505  return op;
506 }
507 
508 /* Add one operation and track stack usage. */
509 static ExprOp *parse_add_op(ExprParseState *state, eOpCode code, int stack_delta)
510 {
511  /* track evaluation stack depth */
512  state->stack_ptr += stack_delta;
513  CLAMP_MIN(state->stack_ptr, 0);
514  CLAMP_MIN(state->max_stack, state->stack_ptr);
515 
516  /* allocate the new instruction */
517  ExprOp *op = parse_alloc_ops(state, 1);
518  memset(op, 0, sizeof(ExprOp));
519  op->opcode = code;
520  return op;
521 }
522 
523 /* Add one jump operation and return an index for parse_set_jump. */
525 {
526  parse_add_op(state, code, -1);
527  return state->last_jmp = state->ops_count;
528 }
529 
530 /* Set the jump offset in a previously added jump operation. */
532 {
533  state->last_jmp = state->ops_count;
534  state->ops[jump - 1].jmp_offset = state->ops_count - jump;
535 }
536 
537 /* Returns the required argument count of the given function call code. */
538 static int opcode_arg_count(eOpCode code)
539 {
540  switch (code) {
541  case OPCODE_FUNC1:
542  return 1;
543  case OPCODE_FUNC2:
544  return 2;
545  case OPCODE_FUNC3:
546  return 3;
547  default:
548  BLI_assert_msg(0, "unexpected opcode");
549  return -1;
550  }
551 }
552 
553 /* Add a function call operation, applying constant folding when possible. */
554 static bool parse_add_func(ExprParseState *state, eOpCode code, int args, void *funcptr)
555 {
556  ExprOp *prev_ops = &state->ops[state->ops_count];
557  int jmp_gap = state->ops_count - state->last_jmp;
558 
559  feclearexcept(FE_ALL_EXCEPT);
560 
561  switch (code) {
562  case OPCODE_FUNC1:
563  CHECK_ERROR(args == 1);
564 
565  if (jmp_gap >= 1 && prev_ops[-1].opcode == OPCODE_CONST) {
566  UnaryOpFunc func = funcptr;
567 
568  /* volatile because some compilers overly aggressive optimize this call out.
569  * see D6012 for details. */
570  volatile double result = func(prev_ops[-1].arg.dval);
571 
572  if (fetestexcept(FE_DIVBYZERO | FE_INVALID) == 0) {
573  prev_ops[-1].arg.dval = result;
574  return true;
575  }
576  }
577  break;
578 
579  case OPCODE_FUNC2:
580  CHECK_ERROR(args == 2);
581 
582  if (jmp_gap >= 2 && prev_ops[-2].opcode == OPCODE_CONST &&
583  prev_ops[-1].opcode == OPCODE_CONST) {
584  BinaryOpFunc func = funcptr;
585 
586  /* volatile because some compilers overly aggressive optimize this call out.
587  * see D6012 for details. */
588  volatile double result = func(prev_ops[-2].arg.dval, prev_ops[-1].arg.dval);
589 
590  if (fetestexcept(FE_DIVBYZERO | FE_INVALID) == 0) {
591  prev_ops[-2].arg.dval = result;
592  state->ops_count--;
593  state->stack_ptr--;
594  return true;
595  }
596  }
597  break;
598 
599  case OPCODE_FUNC3:
600  CHECK_ERROR(args == 3);
601 
602  if (jmp_gap >= 3 && prev_ops[-3].opcode == OPCODE_CONST &&
603  prev_ops[-2].opcode == OPCODE_CONST && prev_ops[-1].opcode == OPCODE_CONST) {
604  TernaryOpFunc func = funcptr;
605 
606  /* volatile because some compilers overly aggressive optimize this call out.
607  * see D6012 for details. */
608  volatile double result = func(
609  prev_ops[-3].arg.dval, prev_ops[-2].arg.dval, prev_ops[-1].arg.dval);
610 
611  if (fetestexcept(FE_DIVBYZERO | FE_INVALID) == 0) {
612  prev_ops[-3].arg.dval = result;
613  state->ops_count -= 2;
614  state->stack_ptr -= 2;
615  return true;
616  }
617  }
618  break;
619 
620  default:
621  BLI_assert(false);
622  return false;
623  }
624 
625  parse_add_op(state, code, 1 - args)->arg.ptr = funcptr;
626  return true;
627 }
628 
629 /* Extract the next token from raw characters. */
631 {
632  /* Skip white-space. */
633  while (isspace(*state->cur)) {
634  state->cur++;
635  }
636 
637  /* End of string. */
638  if (*state->cur == 0) {
639  state->token = 0;
640  return true;
641  }
642 
643  /* Floating point numbers. */
644  if (isdigit(*state->cur) || (state->cur[0] == '.' && isdigit(state->cur[1]))) {
645  char *end, *out = state->tokenbuf;
646  bool is_float = false;
647 
648  while (isdigit(*state->cur)) {
649  *out++ = *state->cur++;
650  }
651 
652  if (*state->cur == '.') {
653  is_float = true;
654  *out++ = *state->cur++;
655 
656  while (isdigit(*state->cur)) {
657  *out++ = *state->cur++;
658  }
659  }
660 
661  if (ELEM(*state->cur, 'e', 'E')) {
662  is_float = true;
663  *out++ = *state->cur++;
664 
665  if (ELEM(*state->cur, '+', '-')) {
666  *out++ = *state->cur++;
667  }
668 
669  CHECK_ERROR(isdigit(*state->cur));
670 
671  while (isdigit(*state->cur)) {
672  *out++ = *state->cur++;
673  }
674  }
675 
676  *out = 0;
677 
678  /* Forbid C-style octal constants. */
679  if (!is_float && state->tokenbuf[0] == '0') {
680  for (char *p = state->tokenbuf + 1; *p; p++) {
681  if (*p != '0') {
682  return false;
683  }
684  }
685  }
686 
687  state->token = TOKEN_NUMBER;
688  state->tokenval = strtod(state->tokenbuf, &end);
689  return (end == out);
690  }
691 
692  /* ?= tokens */
693  if (state->cur[1] == '=' && strchr(token_eq_characters, state->cur[0])) {
694  state->token = MAKE_CHAR2(state->cur[0], state->cur[1]);
695  state->cur += 2;
696  return true;
697  }
698 
699  /* Special characters (single character tokens) */
700  if (strchr(token_characters, *state->cur)) {
701  state->token = *state->cur++;
702  return true;
703  }
704 
705  /* Identifiers */
706  if (isalpha(*state->cur) || ELEM(*state->cur, '_')) {
707  char *out = state->tokenbuf;
708 
709  while (isalnum(*state->cur) || ELEM(*state->cur, '_')) {
710  *out++ = *state->cur++;
711  }
712 
713  *out = 0;
714 
715  for (int i = 0; keyword_list[i].name; i++) {
716  if (STREQ(state->tokenbuf, keyword_list[i].name)) {
717  state->token = keyword_list[i].token;
718  return true;
719  }
720  }
721 
722  state->token = TOKEN_ID;
723  return true;
724  }
725 
726  return false;
727 }
728 
731 /* -------------------------------------------------------------------- */
735 static bool parse_expr(ExprParseState *state);
736 
738 {
739  if (!parse_next_token(state) || state->token != '(' || !parse_next_token(state)) {
740  return -1;
741  }
742 
743  int arg_count = 0;
744 
745  for (;;) {
746  if (!parse_expr(state)) {
747  return -1;
748  }
749 
750  arg_count++;
751 
752  switch (state->token) {
753  case ',':
754  if (!parse_next_token(state)) {
755  return -1;
756  }
757  break;
758 
759  case ')':
760  if (!parse_next_token(state)) {
761  return -1;
762  }
763  return arg_count;
764 
765  default:
766  return -1;
767  }
768  }
769 }
770 
772 {
773  int i;
774 
775  switch (state->token) {
776  case '+':
778 
779  case '-':
782  return true;
783 
784  case '(':
785  return parse_next_token(state) && parse_expr(state) && state->token == ')' &&
787 
788  case TOKEN_NUMBER:
789  parse_add_op(state, OPCODE_CONST, 1)->arg.dval = state->tokenval;
790  return parse_next_token(state);
791 
792  case TOKEN_ID:
793  /* Parameters: search in reverse order in case of duplicate names -
794  * the last one should win. */
795  for (i = state->param_names_len - 1; i >= 0; i--) {
796  if (STREQ(state->tokenbuf, state->param_names[i])) {
798  return parse_next_token(state);
799  }
800  }
801 
802  /* Ordinary builtin constants. */
803  for (i = 0; builtin_consts[i].name; i++) {
804  if (STREQ(state->tokenbuf, builtin_consts[i].name)) {
806  return parse_next_token(state);
807  }
808  }
809 
810  /* Ordinary builtin functions. */
811  for (i = 0; builtin_ops[i].name; i++) {
812  if (STREQ(state->tokenbuf, builtin_ops[i].name)) {
813  int args = parse_function_args(state);
814 
815  /* Search for other arg count versions if necessary. */
816  if (args != opcode_arg_count(builtin_ops[i].op)) {
817  for (int j = i + 1; builtin_ops[j].name; j++) {
818  if (opcode_arg_count(builtin_ops[j].op) == args &&
819  STREQ(builtin_ops[j].name, builtin_ops[i].name)) {
820  i = j;
821  break;
822  }
823  }
824  }
825 
826  return parse_add_func(state, builtin_ops[i].op, args, builtin_ops[i].funcptr);
827  }
828  }
829 
830  /* Specially supported functions. */
831  if (STREQ(state->tokenbuf, "min")) {
833  CHECK_ERROR(count > 0);
834 
836  return true;
837  }
838 
839  if (STREQ(state->tokenbuf, "max")) {
841  CHECK_ERROR(count > 0);
842 
844  return true;
845  }
846 
847  return false;
848 
849  default:
850  return false;
851  }
852 }
853 
855 {
857 
858  for (;;) {
859  switch (state->token) {
860  case '*':
863  break;
864 
865  case '/':
868  break;
869 
870  default:
871  return true;
872  }
873  }
874 }
875 
877 {
879 
880  for (;;) {
881  switch (state->token) {
882  case '+':
885  break;
886 
887  case '-':
890  break;
891 
892  default:
893  return true;
894  }
895  }
896 }
897 
898 static BinaryOpFunc parse_get_cmp_func(short token)
899 {
900  switch (token) {
901  case TOKEN_EQ:
902  return op_eq;
903  case TOKEN_NE:
904  return op_ne;
905  case '>':
906  return op_gt;
907  case TOKEN_GE:
908  return op_ge;
909  case '<':
910  return op_lt;
911  case TOKEN_LE:
912  return op_le;
913  default:
914  return NULL;
915  }
916 }
917 
919 {
920  BinaryOpFunc next_func = parse_get_cmp_func(state->token);
921 
922  if (next_func) {
923  parse_add_op(state, OPCODE_CMP_CHAIN, -1)->arg.func2 = cur_func;
924  int jump = state->last_jmp = state->ops_count;
925 
927  CHECK_ERROR(parse_cmp_chain(state, next_func));
928 
930  }
931  else {
932  parse_add_func(state, OPCODE_FUNC2, 2, cur_func);
933  }
934 
935  return true;
936 }
937 
939 {
941 
942  BinaryOpFunc func = parse_get_cmp_func(state->token);
943 
944  if (func) {
946 
947  return parse_cmp_chain(state, func);
948  }
949 
950  return true;
951 }
952 
954 {
955  if (state->token == TOKEN_NOT) {
958  return true;
959  }
960 
961  return parse_cmp(state);
962 }
963 
965 {
967 
968  if (state->token == TOKEN_AND) {
970 
972 
974  }
975 
976  return true;
977 }
978 
980 {
982 
983  if (state->token == TOKEN_OR) {
985 
987 
989  }
990 
991  return true;
992 }
993 
995 {
996  /* Temporarily set the constant expression evaluation barrier */
997  int prev_last_jmp = state->last_jmp;
998  int start = state->last_jmp = state->ops_count;
999 
1001 
1002  if (state->token == TOKEN_IF) {
1003  /* Ternary IF expression in python requires swapping the
1004  * main body with condition, so stash the body opcodes. */
1005  int size = state->ops_count - start;
1006  int bytes = size * sizeof(ExprOp);
1007 
1008  ExprOp *body = MEM_mallocN(bytes, "driver if body");
1009  memcpy(body, state->ops + start, bytes);
1010 
1011  state->last_jmp = state->ops_count = start;
1012  state->stack_ptr--;
1013 
1014  /* Parse condition. */
1015  if (!parse_next_token(state) || !parse_or(state) || state->token != TOKEN_ELSE ||
1016  !parse_next_token(state)) {
1017  MEM_freeN(body);
1018  return false;
1019  }
1020 
1021  int jmp_else = parse_add_jump(state, OPCODE_JMP_ELSE);
1022 
1023  /* Add body back. */
1024  memcpy(parse_alloc_ops(state, size), body, bytes);
1025  MEM_freeN(body);
1026 
1027  state->stack_ptr++;
1028 
1029  int jmp_end = parse_add_jump(state, OPCODE_JMP);
1030 
1031  /* Parse the else block. */
1032  parse_set_jump(state, jmp_else);
1033 
1035 
1036  parse_set_jump(state, jmp_end);
1037  }
1038  /* If no actual jumps happened, restore previous barrier */
1039  else if (state->last_jmp == start) {
1040  state->last_jmp = prev_last_jmp;
1041  }
1042 
1043  return true;
1044 }
1045 
1048 /* -------------------------------------------------------------------- */
1053  const char **param_names,
1054  int param_names_len)
1055 {
1056  /* Prepare the parser state. */
1058  memset(&state, 0, sizeof(state));
1059 
1060  state.cur = state.expr = expression;
1061 
1062  state.param_names_len = param_names_len;
1063  state.param_names = param_names;
1064 
1065  state.tokenbuf = MEM_mallocN(strlen(expression) + 1, __func__);
1066 
1067  state.max_ops = 16;
1068  state.ops = MEM_mallocN(state.max_ops * sizeof(ExprOp), __func__);
1069 
1070  /* Parse the expression. */
1071  ExprPyLike_Parsed *expr;
1072 
1073  if (parse_next_token(&state) && parse_expr(&state) && state.token == 0) {
1074  BLI_assert(state.stack_ptr == 1);
1075 
1076  int bytesize = sizeof(ExprPyLike_Parsed) + state.ops_count * sizeof(ExprOp);
1077 
1078  expr = MEM_mallocN(bytesize, "ExprPyLike_Parsed");
1079  expr->ops_count = state.ops_count;
1080  expr->max_stack = state.max_stack;
1081 
1082  memcpy(expr->ops, state.ops, state.ops_count * sizeof(ExprOp));
1083  }
1084  else {
1085  /* Always return a non-NULL object so that parse failure can be cached. */
1086  expr = MEM_callocN(sizeof(ExprPyLike_Parsed), "ExprPyLike_Parsed(empty)");
1087  }
1088 
1089  MEM_freeN(state.tokenbuf);
1090  MEM_freeN(state.ops);
1091  return expr;
1092 }
1093 
#define BLI_array_alloca(arr, realsize)
Definition: BLI_alloca.h:22
#define BLI_assert(a)
Definition: BLI_assert.h:46
#define BLI_assert_msg(a, msg)
Definition: BLI_assert.h:53
eExprPyLike_EvalStatus
@ EXPR_PYLIKE_FATAL_ERROR
@ EXPR_PYLIKE_SUCCESS
@ EXPR_PYLIKE_DIV_BY_ZERO
@ EXPR_PYLIKE_MATH_ERROR
@ EXPR_PYLIKE_INVALID
struct ExprPyLike_Parsed ExprPyLike_Parsed
sqrt(x)+1/max(0
MINLINE int power_of_2_max_i(int n)
#define M_PI
Definition: BLI_math_base.h:20
#define CLAMP_MAX(a, c)
#define ELEM(...)
#define STREQ(a, b)
#define CLAMP_MIN(a, b)
typedef double(DMatrix)[4][4]
_GL_VOID GLfloat value _GL_VOID_RET _GL_VOID const GLuint GLboolean *residences _GL_BOOL_RET _GL_VOID GLsizei GLfloat GLfloat GLfloat GLfloat const GLubyte *bitmap _GL_VOID_RET _GL_VOID GLenum const void *lists _GL_VOID_RET _GL_VOID const GLdouble *equation _GL_VOID_RET _GL_VOID GLdouble GLdouble blue _GL_VOID_RET _GL_VOID GLfloat GLfloat blue _GL_VOID_RET _GL_VOID GLint GLint blue _GL_VOID_RET _GL_VOID GLshort GLshort blue _GL_VOID_RET _GL_VOID GLubyte GLubyte blue _GL_VOID_RET _GL_VOID GLuint GLuint blue _GL_VOID_RET _GL_VOID GLushort GLushort blue _GL_VOID_RET _GL_VOID GLbyte GLbyte GLbyte alpha _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble alpha _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat alpha _GL_VOID_RET _GL_VOID GLint GLint GLint alpha _GL_VOID_RET _GL_VOID GLshort GLshort GLshort alpha _GL_VOID_RET _GL_VOID GLubyte GLubyte GLubyte alpha _GL_VOID_RET _GL_VOID GLuint GLuint GLuint alpha _GL_VOID_RET _GL_VOID GLushort GLushort GLushort alpha _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLint GLsizei GLsizei GLenum type _GL_VOID_RET _GL_VOID GLsizei GLenum GLenum const void *pixels _GL_VOID_RET _GL_VOID const void *pointer _GL_VOID_RET _GL_VOID GLdouble v _GL_VOID_RET _GL_VOID GLfloat v _GL_VOID_RET _GL_VOID GLint GLint i2 _GL_VOID_RET _GL_VOID GLint j _GL_VOID_RET _GL_VOID GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble GLdouble GLdouble zFar _GL_VOID_RET _GL_UINT GLdouble *equation _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLenum GLfloat *v _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLfloat *values _GL_VOID_RET _GL_VOID GLushort *values _GL_VOID_RET _GL_VOID GLenum GLfloat *params _GL_VOID_RET _GL_VOID GLenum GLdouble *params _GL_VOID_RET _GL_VOID GLenum GLint *params _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_BOOL GLfloat param _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLushort pattern _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLint GLdouble GLdouble GLint GLint const GLdouble *points _GL_VOID_RET _GL_VOID GLdouble GLdouble u2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLint GLdouble GLdouble v2 _GL_VOID_RET _GL_VOID GLenum GLfloat param _GL_VOID_RET _GL_VOID GLenum GLint param _GL_VOID_RET _GL_VOID GLenum mode _GL_VOID_RET _GL_VOID GLdouble GLdouble nz _GL_VOID_RET _GL_VOID GLfloat GLfloat nz _GL_VOID_RET _GL_VOID GLint GLint nz _GL_VOID_RET _GL_VOID GLshort GLshort nz _GL_VOID_RET _GL_VOID GLsizei const void *pointer _GL_VOID_RET _GL_VOID GLsizei const GLfloat *values _GL_VOID_RET _GL_VOID GLsizei const GLushort *values _GL_VOID_RET _GL_VOID GLint param _GL_VOID_RET _GL_VOID const GLuint const GLclampf *priorities _GL_VOID_RET _GL_VOID GLdouble y _GL_VOID_RET _GL_VOID GLfloat y _GL_VOID_RET _GL_VOID GLint y _GL_VOID_RET _GL_VOID GLshort y _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLfloat GLfloat z _GL_VOID_RET _GL_VOID GLint GLint z _GL_VOID_RET _GL_VOID GLshort GLshort z _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble w _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat w _GL_VOID_RET _GL_VOID GLint GLint GLint w _GL_VOID_RET _GL_VOID GLshort GLshort GLshort w _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble y2 _GL_VOID_RET _GL_VOID GLfloat GLfloat GLfloat y2 _GL_VOID_RET _GL_VOID GLint GLint GLint y2 _GL_VOID_RET _GL_VOID GLshort GLshort GLshort y2 _GL_VOID_RET _GL_VOID GLdouble GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLdouble GLdouble z _GL_VOID_RET _GL_VOID GLuint *buffer _GL_VOID_RET _GL_VOID GLdouble t _GL_VOID_RET _GL_VOID GLfloat t _GL_VOID_RET _GL_VOID GLint t _GL_VOID_RET _GL_VOID GLshort t _GL_VOID_RET _GL_VOID GLdouble t
Read Guarded memory(de)allocation.
#define MEM_reallocN(vmemh, len)
Group Output data from inside of a node group A color picker Mix two input colors RGB to Convert a color s luminance to a grayscale value Generate a normal vector and a dot product Bright Control the brightness and contrast of the input color Vector Map an input vectors to used to fine tune the interpolation of the input Camera Retrieve information about the camera and how it relates to the current shading point s position CLAMP
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
void jump(const btVector3 &v=btVector3(0, 0, 0))
static double op_negate(double arg)
static bool parse_next_token(ExprParseState *state)
static double op_clamp3(double arg, double minv, double maxv)
struct KeywordTokenDef KeywordTokenDef
static int parse_add_jump(ExprParseState *state, eOpCode code)
struct ExprOp ExprOp
double(* TernaryOpFunc)(double, double, double)
static double op_lt(double a, double b)
static int parse_function_args(ExprParseState *state)
static BinaryOpFunc parse_get_cmp_func(short token)
static bool parse_mul(ExprParseState *state)
static double op_smoothstep(double a, double b, double x)
static double op_mul(double a, double b)
static BuiltinOpDef builtin_ops[]
#define MAKE_CHAR2(a, b)
static bool parse_and(ExprParseState *state)
void BLI_expr_pylike_free(ExprPyLike_Parsed *expr)
static bool parse_expr(ExprParseState *state)
#define TOKEN_ID
static const char * token_characters
eExprPyLike_EvalStatus BLI_expr_pylike_eval(ExprPyLike_Parsed *expr, const double *param_values, int param_values_len, double *r_result)
static bool parse_add(ExprParseState *state)
static double op_gt(double a, double b)
#define FAIL_IF(condition)
struct ExprParseState ExprParseState
struct BuiltinOpDef BuiltinOpDef
bool BLI_expr_pylike_is_valid(ExprPyLike_Parsed *expr)
#define TOKEN_GE
static double op_ne(double a, double b)
#define TOKEN_NOT
#define CHECK_ERROR(condition)
ExprPyLike_Parsed * BLI_expr_pylike_parse(const char *expression, const char **param_names, int param_names_len)
static BuiltinConstDef builtin_consts[]
static ExprOp * parse_alloc_ops(ExprParseState *state, int count)
static double op_div(double a, double b)
static double op_eq(double a, double b)
#define TOKEN_ELSE
static void parse_set_jump(ExprParseState *state, int jump)
#define TOKEN_OR
static double op_lerp(double a, double b, double x)
eOpCode
@ OPCODE_FUNC3
@ OPCODE_FUNC2
@ OPCODE_JMP
@ OPCODE_PARAMETER
@ OPCODE_CMP_CHAIN
@ OPCODE_CONST
@ OPCODE_FUNC1
@ OPCODE_JMP_OR
@ OPCODE_JMP_ELSE
@ OPCODE_MAX
@ OPCODE_MIN
@ OPCODE_JMP_AND
static bool parse_add_func(ExprParseState *state, eOpCode code, int args, void *funcptr)
static bool parse_unary(ExprParseState *state)
static bool parse_not(ExprParseState *state)
static double op_le(double a, double b)
static const char * token_eq_characters
double(* BinaryOpFunc)(double, double)
bool BLI_expr_pylike_is_constant(ExprPyLike_Parsed *expr)
#define TOKEN_LE
double(* UnaryOpFunc)(double)
static double op_ge(double a, double b)
static double op_add(double a, double b)
static double op_not(double a)
struct BuiltinConstDef BuiltinConstDef
static double op_sub(double a, double b)
#define TOKEN_IF
static double op_degrees(double arg)
static double op_log2(double a, double b)
#define TOKEN_EQ
#define TOKEN_AND
static bool parse_cmp_chain(ExprParseState *state, BinaryOpFunc cur_func)
static KeywordTokenDef keyword_list[]
static double op_clamp(double arg)
static ExprOp * parse_add_op(ExprParseState *state, eOpCode code, int stack_delta)
static double op_radians(double arg)
static bool parse_cmp(ExprParseState *state)
static bool parse_or(ExprParseState *state)
#define TOKEN_NUMBER
#define TOKEN_NE
bool BLI_expr_pylike_is_using_param(ExprPyLike_Parsed *expr, int index)
static int opcode_arg_count(eOpCode code)
int count
const int state
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:27
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:31
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:33
ccl_device_inline float2 fabs(const float2 &a)
Definition: math_float2.h:222
ccl_device_inline float3 exp(float3 v)
Definition: math_float3.h:392
ccl_device_inline float3 ceil(const float3 &a)
Definition: math_float3.h:363
ccl_device_inline float3 pow(float3 v, float e)
Definition: math_float3.h:533
ccl_device_inline float3 log(float3 v)
Definition: math_float3.h:397
static unsigned a[3]
Definition: RandGen.cpp:78
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:319
INLINE Rall1d< T, V, S > asin(const Rall1d< T, V, S > &x)
Definition: rall1d.h:391
INLINE Rall1d< T, V, S > atan(const Rall1d< T, V, S > &x)
Definition: rall1d.h:375
INLINE Rall1d< T, V, S > acos(const Rall1d< T, V, S > &x)
Definition: rall1d.h:399
INLINE Rall1d< T, V, S > sin(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:311
INLINE Rall1d< T, V, S > tan(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:327
INLINE Rall1d< T, V, S > atan2(const Rall1d< T, V, S > &y, const Rall1d< T, V, S > &x)
Definition: rall1d.h:429
T floor(const T &a)
static const pxr::TfToken out("out", pxr::TfToken::Immortal)
static const pxr::TfToken b("b", pxr::TfToken::Immortal)
const char * name
const char * name
void * ptr
UnaryOpFunc func1
eOpCode opcode
int jmp_offset
double dval
BinaryOpFunc func2
TernaryOpFunc func3
union ExprOp::@125 arg
const char * cur
const char * expr
const char ** param_names
const char * name