Blender  V2.93
expr_pylike_eval.c
Go to the documentation of this file.
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2018 Blender Foundation, Alexander Gavrilov
17  * All rights reserved.
18  */
19 
44 #include <ctype.h>
45 #include <fenv.h>
46 #include <float.h>
47 #include <math.h>
48 #include <stddef.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 #include <string.h>
52 
53 #include "MEM_guardedalloc.h"
54 
55 #include "BLI_alloca.h"
56 #include "BLI_expr_pylike_eval.h"
57 #include "BLI_math_base.h"
58 #include "BLI_utildefines.h"
59 
60 #ifdef _MSC_VER
61 # pragma fenv_access(on)
62 #endif
63 
64 /* -------------------------------------------------------------------- */
68 typedef enum eOpCode {
69  /* Double constant: (-> dval) */
71  /* 1 argument function call: (a -> func1(a)) */
73  /* 2 argument function call: (a b -> func2(a,b)) */
75  /* 3 argument function call: (a b c -> func3(a,b,c)) */
77  /* Parameter access: (-> params[ival]) */
79  /* Minimum of multiple inputs: (a b c... -> min); ival = arg count */
81  /* Maximum of multiple inputs: (a b c... -> max); ival = arg count */
83  /* Jump (pc += jmp_offset) */
85  /* Pop and jump if zero: (a -> ); JUMP IF NOT a */
87  /* Jump if nonzero, or pop: (a -> a JUMP) IF a ELSE (a -> ) */
89  /* Jump if zero, or pop: (a -> a JUMP) IF NOT a ELSE (a -> ) */
91  /* For comparison chaining: (a b -> 0 JUMP) IF NOT func2(a,b) ELSE (a b -> b) */
94 
98 
99 typedef struct ExprOp {
101 
103 
104  union {
105  int ival;
106  double dval;
107  void *ptr;
111  } arg;
113 
117 
119 };
120 
123 /* -------------------------------------------------------------------- */
129 {
130  if (expr != NULL) {
131  MEM_freeN(expr);
132  }
133 }
134 
137 {
138  return expr != NULL && expr->ops_count > 0;
139 }
140 
143 {
144  return expr != NULL && expr->ops_count == 1 && expr->ops[0].opcode == OPCODE_CONST;
145 }
146 
149 {
150  int i;
151 
152  if (expr == NULL) {
153  return false;
154  }
155 
156  for (i = 0; i < expr->ops_count; i++) {
157  if (expr->ops[i].opcode == OPCODE_PARAMETER && expr->ops[i].arg.ival == index) {
158  return true;
159  }
160  }
161 
162  return false;
163 }
164 
167 /* -------------------------------------------------------------------- */
176  const double *param_values,
177  int param_values_len,
178  double *r_result)
179 {
180  *r_result = 0.0;
181 
182  if (!BLI_expr_pylike_is_valid(expr)) {
183  return EXPR_PYLIKE_INVALID;
184  }
185 
186 #define FAIL_IF(condition) \
187  if (condition) { \
188  return EXPR_PYLIKE_FATAL_ERROR; \
189  } \
190  ((void)0)
191 
192  /* Check the stack requirement is at least remotely sane and allocate on the actual stack. */
193  FAIL_IF(expr->max_stack <= 0 || expr->max_stack > 1000);
194 
195  double *stack = BLI_array_alloca(stack, expr->max_stack);
196 
197  /* Evaluate expression. */
198  ExprOp *ops = expr->ops;
199  int sp = 0, pc;
200 
201  feclearexcept(FE_ALL_EXCEPT);
202 
203  for (pc = 0; pc >= 0 && pc < expr->ops_count; pc++) {
204  switch (ops[pc].opcode) {
205  /* Arithmetic */
206  case OPCODE_CONST:
207  FAIL_IF(sp >= expr->max_stack);
208  stack[sp++] = ops[pc].arg.dval;
209  break;
210  case OPCODE_PARAMETER:
211  FAIL_IF(sp >= expr->max_stack || ops[pc].arg.ival >= param_values_len);
212  stack[sp++] = param_values[ops[pc].arg.ival];
213  break;
214  case OPCODE_FUNC1:
215  FAIL_IF(sp < 1);
216  stack[sp - 1] = ops[pc].arg.func1(stack[sp - 1]);
217  break;
218  case OPCODE_FUNC2:
219  FAIL_IF(sp < 2);
220  stack[sp - 2] = ops[pc].arg.func2(stack[sp - 2], stack[sp - 1]);
221  sp--;
222  break;
223  case OPCODE_FUNC3:
224  FAIL_IF(sp < 3);
225  stack[sp - 3] = ops[pc].arg.func3(stack[sp - 3], stack[sp - 2], stack[sp - 1]);
226  sp -= 2;
227  break;
228  case OPCODE_MIN:
229  FAIL_IF(sp < ops[pc].arg.ival);
230  for (int j = 1; j < ops[pc].arg.ival; j++, sp--) {
231  CLAMP_MAX(stack[sp - 2], stack[sp - 1]);
232  }
233  break;
234  case OPCODE_MAX:
235  FAIL_IF(sp < ops[pc].arg.ival);
236  for (int j = 1; j < ops[pc].arg.ival; j++, sp--) {
237  CLAMP_MIN(stack[sp - 2], stack[sp - 1]);
238  }
239  break;
240 
241  /* Jumps */
242  case OPCODE_JMP:
243  pc += ops[pc].jmp_offset;
244  break;
245  case OPCODE_JMP_ELSE:
246  FAIL_IF(sp < 1);
247  if (!stack[--sp]) {
248  pc += ops[pc].jmp_offset;
249  }
250  break;
251  case OPCODE_JMP_OR:
252  case OPCODE_JMP_AND:
253  FAIL_IF(sp < 1);
254  if (!stack[sp - 1] == !(ops[pc].opcode == OPCODE_JMP_OR)) {
255  pc += ops[pc].jmp_offset;
256  }
257  else {
258  sp--;
259  }
260  break;
261 
262  /* For chaining comparisons, i.e. "a < b < c" as "a < b and b < c" */
263  case OPCODE_CMP_CHAIN:
264  FAIL_IF(sp < 2);
265  /* If comparison fails, return 0 and jump to end. */
266  if (!ops[pc].arg.func2(stack[sp - 2], stack[sp - 1])) {
267  stack[sp - 2] = 0.0;
268  pc += ops[pc].jmp_offset;
269  }
270  /* Otherwise keep b on the stack and proceed. */
271  else {
272  stack[sp - 2] = stack[sp - 1];
273  }
274  sp--;
275  break;
276 
277  default:
279  }
280  }
281 
282  FAIL_IF(sp != 1 || pc != expr->ops_count);
283 
284 #undef FAIL_IF
285 
286  *r_result = stack[0];
287 
288  /* Detect floating point evaluation errors. */
289  int flags = fetestexcept(FE_DIVBYZERO | FE_INVALID);
290  if (flags) {
291  return (flags & FE_INVALID) ? EXPR_PYLIKE_MATH_ERROR : EXPR_PYLIKE_DIV_BY_ZERO;
292  }
293 
294  return EXPR_PYLIKE_SUCCESS;
295 }
296 
299 /* -------------------------------------------------------------------- */
303 static double op_negate(double arg)
304 {
305  return -arg;
306 }
307 
308 static double op_mul(double a, double b)
309 {
310  return a * b;
311 }
312 
313 static double op_div(double a, double b)
314 {
315  return a / b;
316 }
317 
318 static double op_add(double a, double b)
319 {
320  return a + b;
321 }
322 
323 static double op_sub(double a, double b)
324 {
325  return a - b;
326 }
327 
328 static double op_radians(double arg)
329 {
330  return arg * M_PI / 180.0;
331 }
332 
333 static double op_degrees(double arg)
334 {
335  return arg * 180.0 / M_PI;
336 }
337 
338 static double op_log2(double a, double b)
339 {
340  return log(a) / log(b);
341 }
342 
343 static double op_lerp(double a, double b, double x)
344 {
345  return a * (1.0 - x) + b * x;
346 }
347 
348 static double op_clamp(double arg)
349 {
350  CLAMP(arg, 0.0, 1.0);
351  return arg;
352 }
353 
354 static double op_clamp3(double arg, double minv, double maxv)
355 {
356  CLAMP(arg, minv, maxv);
357  return arg;
358 }
359 
360 static double op_smoothstep(double a, double b, double x)
361 {
362  double t = (x - a) / (b - a);
363  CLAMP(t, 0.0, 1.0);
364  return t * t * (3.0 - 2.0 * t);
365 }
366 
367 static double op_not(double a)
368 {
369  return a ? 0.0 : 1.0;
370 }
371 
372 static double op_eq(double a, double b)
373 {
374  return a == b ? 1.0 : 0.0;
375 }
376 
377 static double op_ne(double a, double b)
378 {
379  return a != b ? 1.0 : 0.0;
380 }
381 
382 static double op_lt(double a, double b)
383 {
384  return a < b ? 1.0 : 0.0;
385 }
386 
387 static double op_le(double a, double b)
388 {
389  return a <= b ? 1.0 : 0.0;
390 }
391 
392 static double op_gt(double a, double b)
393 {
394  return a > b ? 1.0 : 0.0;
395 }
396 
397 static double op_ge(double a, double b)
398 {
399  return a >= b ? 1.0 : 0.0;
400 }
401 
402 typedef struct BuiltinConstDef {
403  const char *name;
404  double value;
406 
408  {"pi", M_PI}, {"True", 1.0}, {"False", 0.0}, {NULL, 0.0}};
409 
410 typedef struct BuiltinOpDef {
411  const char *name;
413  void *funcptr;
415 
416 #ifdef _MSC_VER
417 /* Prevent MSVC from inlining calls to ceil/floor so the table below can get a function pointer to
418  * them. */
419 # pragma function(ceil)
420 # pragma function(floor)
421 #endif
422 
424  {"radians", OPCODE_FUNC1, op_radians},
425  {"degrees", OPCODE_FUNC1, op_degrees},
426  {"abs", OPCODE_FUNC1, fabs},
427  {"fabs", OPCODE_FUNC1, fabs},
428  {"floor", OPCODE_FUNC1, floor},
429  {"ceil", OPCODE_FUNC1, ceil},
430  {"trunc", OPCODE_FUNC1, trunc},
431  {"round", OPCODE_FUNC1, round},
432  {"int", OPCODE_FUNC1, trunc},
433  {"sin", OPCODE_FUNC1, sin},
434  {"cos", OPCODE_FUNC1, cos},
435  {"tan", OPCODE_FUNC1, tan},
436  {"asin", OPCODE_FUNC1, asin},
437  {"acos", OPCODE_FUNC1, acos},
438  {"atan", OPCODE_FUNC1, atan},
439  {"atan2", OPCODE_FUNC2, atan2},
440  {"exp", OPCODE_FUNC1, exp},
441  {"log", OPCODE_FUNC1, log},
442  {"log", OPCODE_FUNC2, op_log2},
443  {"sqrt", OPCODE_FUNC1, sqrt},
444  {"pow", OPCODE_FUNC2, pow},
445  {"fmod", OPCODE_FUNC2, fmod},
446  {"lerp", OPCODE_FUNC3, op_lerp},
447  {"clamp", OPCODE_FUNC1, op_clamp},
448  {"clamp", OPCODE_FUNC3, op_clamp3},
449  {"smoothstep", OPCODE_FUNC3, op_smoothstep},
450  {NULL, OPCODE_CONST, NULL},
451 };
452 
455 /* -------------------------------------------------------------------- */
459 #define MAKE_CHAR2(a, b) (((a) << 8) | (b))
460 
461 #define CHECK_ERROR(condition) \
462  if (!(condition)) { \
463  return false; \
464  } \
465  ((void)0)
466 
467 /* For simplicity simple token types are represented by their own character;
468  * these are special identifiers for multi-character tokens. */
469 #define TOKEN_ID MAKE_CHAR2('I', 'D')
470 #define TOKEN_NUMBER MAKE_CHAR2('0', '0')
471 #define TOKEN_GE MAKE_CHAR2('>', '=')
472 #define TOKEN_LE MAKE_CHAR2('<', '=')
473 #define TOKEN_NE MAKE_CHAR2('!', '=')
474 #define TOKEN_EQ MAKE_CHAR2('=', '=')
475 #define TOKEN_AND MAKE_CHAR2('A', 'N')
476 #define TOKEN_OR MAKE_CHAR2('O', 'R')
477 #define TOKEN_NOT MAKE_CHAR2('N', 'O')
478 #define TOKEN_IF MAKE_CHAR2('I', 'F')
479 #define TOKEN_ELSE MAKE_CHAR2('E', 'L')
480 
481 static const char *token_eq_characters = "!=><";
482 static const char *token_characters = "~`!@#$%^&*+-=/\\?:;<>(){}[]|.,\"'";
483 
484 typedef struct KeywordTokenDef {
485  const char *name;
486  short token;
488 
490  {"and", TOKEN_AND},
491  {"or", TOKEN_OR},
492  {"not", TOKEN_NOT},
493  {"if", TOKEN_IF},
494  {"else", TOKEN_ELSE},
495  {NULL, TOKEN_ID},
496 };
497 
498 typedef struct ExprParseState {
500  const char **param_names;
501 
502  /* Original expression */
503  const char *expr;
504  const char *cur;
505 
506  /* Current token */
507  short token;
508  char *tokenbuf;
509  double tokenval;
510 
511  /* Opcode buffer */
514 
515  /* Stack space requirement tracking */
518 
519 /* Reserve space for the specified number of operations in the buffer. */
521 {
522  if (state->ops_count + count > state->max_ops) {
523  state->max_ops = power_of_2_max_i(state->ops_count + count);
524  state->ops = MEM_reallocN(state->ops, state->max_ops * sizeof(ExprOp));
525  }
526 
527  ExprOp *op = &state->ops[state->ops_count];
528  state->ops_count += count;
529  return op;
530 }
531 
532 /* Add one operation and track stack usage. */
533 static ExprOp *parse_add_op(ExprParseState *state, eOpCode code, int stack_delta)
534 {
535  /* track evaluation stack depth */
536  state->stack_ptr += stack_delta;
537  CLAMP_MIN(state->stack_ptr, 0);
538  CLAMP_MIN(state->max_stack, state->stack_ptr);
539 
540  /* allocate the new instruction */
541  ExprOp *op = parse_alloc_ops(state, 1);
542  memset(op, 0, sizeof(ExprOp));
543  op->opcode = code;
544  return op;
545 }
546 
547 /* Add one jump operation and return an index for parse_set_jump. */
549 {
550  parse_add_op(state, code, -1);
551  return state->last_jmp = state->ops_count;
552 }
553 
554 /* Set the jump offset in a previously added jump operation. */
556 {
557  state->last_jmp = state->ops_count;
558  state->ops[jump - 1].jmp_offset = state->ops_count - jump;
559 }
560 
561 /* Returns the required argument count of the given function call code. */
562 static int opcode_arg_count(eOpCode code)
563 {
564  switch (code) {
565  case OPCODE_FUNC1:
566  return 1;
567  case OPCODE_FUNC2:
568  return 2;
569  case OPCODE_FUNC3:
570  return 3;
571  default:
572  BLI_assert(!"unexpected opcode");
573  return -1;
574  }
575 }
576 
577 /* Add a function call operation, applying constant folding when possible. */
578 static bool parse_add_func(ExprParseState *state, eOpCode code, int args, void *funcptr)
579 {
580  ExprOp *prev_ops = &state->ops[state->ops_count];
581  int jmp_gap = state->ops_count - state->last_jmp;
582 
583  feclearexcept(FE_ALL_EXCEPT);
584 
585  switch (code) {
586  case OPCODE_FUNC1:
587  CHECK_ERROR(args == 1);
588 
589  if (jmp_gap >= 1 && prev_ops[-1].opcode == OPCODE_CONST) {
590  UnaryOpFunc func = funcptr;
591 
592  /* volatile because some compilers overly aggressive optimize this call out.
593  * see D6012 for details. */
594  volatile double result = func(prev_ops[-1].arg.dval);
595 
596  if (fetestexcept(FE_DIVBYZERO | FE_INVALID) == 0) {
597  prev_ops[-1].arg.dval = result;
598  return true;
599  }
600  }
601  break;
602 
603  case OPCODE_FUNC2:
604  CHECK_ERROR(args == 2);
605 
606  if (jmp_gap >= 2 && prev_ops[-2].opcode == OPCODE_CONST &&
607  prev_ops[-1].opcode == OPCODE_CONST) {
608  BinaryOpFunc func = funcptr;
609 
610  /* volatile because some compilers overly aggressive optimize this call out.
611  * see D6012 for details. */
612  volatile double result = func(prev_ops[-2].arg.dval, prev_ops[-1].arg.dval);
613 
614  if (fetestexcept(FE_DIVBYZERO | FE_INVALID) == 0) {
615  prev_ops[-2].arg.dval = result;
616  state->ops_count--;
617  state->stack_ptr--;
618  return true;
619  }
620  }
621  break;
622 
623  case OPCODE_FUNC3:
624  CHECK_ERROR(args == 3);
625 
626  if (jmp_gap >= 3 && prev_ops[-3].opcode == OPCODE_CONST &&
627  prev_ops[-2].opcode == OPCODE_CONST && prev_ops[-1].opcode == OPCODE_CONST) {
628  TernaryOpFunc func = funcptr;
629 
630  /* volatile because some compilers overly aggressive optimize this call out.
631  * see D6012 for details. */
632  volatile double result = func(
633  prev_ops[-3].arg.dval, prev_ops[-2].arg.dval, prev_ops[-1].arg.dval);
634 
635  if (fetestexcept(FE_DIVBYZERO | FE_INVALID) == 0) {
636  prev_ops[-3].arg.dval = result;
637  state->ops_count -= 2;
638  state->stack_ptr -= 2;
639  return true;
640  }
641  }
642  break;
643 
644  default:
645  BLI_assert(false);
646  return false;
647  }
648 
649  parse_add_op(state, code, 1 - args)->arg.ptr = funcptr;
650  return true;
651 }
652 
653 /* Extract the next token from raw characters. */
655 {
656  /* Skip whitespace. */
657  while (isspace(*state->cur)) {
658  state->cur++;
659  }
660 
661  /* End of string. */
662  if (*state->cur == 0) {
663  state->token = 0;
664  return true;
665  }
666 
667  /* Floating point numbers. */
668  if (isdigit(*state->cur) || (state->cur[0] == '.' && isdigit(state->cur[1]))) {
669  char *end, *out = state->tokenbuf;
670  bool is_float = false;
671 
672  while (isdigit(*state->cur)) {
673  *out++ = *state->cur++;
674  }
675 
676  if (*state->cur == '.') {
677  is_float = true;
678  *out++ = *state->cur++;
679 
680  while (isdigit(*state->cur)) {
681  *out++ = *state->cur++;
682  }
683  }
684 
685  if (ELEM(*state->cur, 'e', 'E')) {
686  is_float = true;
687  *out++ = *state->cur++;
688 
689  if (ELEM(*state->cur, '+', '-')) {
690  *out++ = *state->cur++;
691  }
692 
693  CHECK_ERROR(isdigit(*state->cur));
694 
695  while (isdigit(*state->cur)) {
696  *out++ = *state->cur++;
697  }
698  }
699 
700  *out = 0;
701 
702  /* Forbid C-style octal constants. */
703  if (!is_float && state->tokenbuf[0] == '0') {
704  for (char *p = state->tokenbuf + 1; *p; p++) {
705  if (*p != '0') {
706  return false;
707  }
708  }
709  }
710 
711  state->token = TOKEN_NUMBER;
712  state->tokenval = strtod(state->tokenbuf, &end);
713  return (end == out);
714  }
715 
716  /* ?= tokens */
717  if (state->cur[1] == '=' && strchr(token_eq_characters, state->cur[0])) {
718  state->token = MAKE_CHAR2(state->cur[0], state->cur[1]);
719  state->cur += 2;
720  return true;
721  }
722 
723  /* Special characters (single character tokens) */
724  if (strchr(token_characters, *state->cur)) {
725  state->token = *state->cur++;
726  return true;
727  }
728 
729  /* Identifiers */
730  if (isalpha(*state->cur) || ELEM(*state->cur, '_')) {
731  char *out = state->tokenbuf;
732 
733  while (isalnum(*state->cur) || ELEM(*state->cur, '_')) {
734  *out++ = *state->cur++;
735  }
736 
737  *out = 0;
738 
739  for (int i = 0; keyword_list[i].name; i++) {
740  if (STREQ(state->tokenbuf, keyword_list[i].name)) {
741  state->token = keyword_list[i].token;
742  return true;
743  }
744  }
745 
746  state->token = TOKEN_ID;
747  return true;
748  }
749 
750  return false;
751 }
752 
755 /* -------------------------------------------------------------------- */
759 static bool parse_expr(ExprParseState *state);
760 
762 {
763  if (!parse_next_token(state) || state->token != '(' || !parse_next_token(state)) {
764  return -1;
765  }
766 
767  int arg_count = 0;
768 
769  for (;;) {
770  if (!parse_expr(state)) {
771  return -1;
772  }
773 
774  arg_count++;
775 
776  switch (state->token) {
777  case ',':
778  if (!parse_next_token(state)) {
779  return -1;
780  }
781  break;
782 
783  case ')':
784  if (!parse_next_token(state)) {
785  return -1;
786  }
787  return arg_count;
788 
789  default:
790  return -1;
791  }
792  }
793 }
794 
796 {
797  int i;
798 
799  switch (state->token) {
800  case '+':
802 
803  case '-':
806  return true;
807 
808  case '(':
809  return parse_next_token(state) && parse_expr(state) && state->token == ')' &&
811 
812  case TOKEN_NUMBER:
813  parse_add_op(state, OPCODE_CONST, 1)->arg.dval = state->tokenval;
814  return parse_next_token(state);
815 
816  case TOKEN_ID:
817  /* Parameters: search in reverse order in case of duplicate names -
818  * the last one should win. */
819  for (i = state->param_names_len - 1; i >= 0; i--) {
820  if (STREQ(state->tokenbuf, state->param_names[i])) {
822  return parse_next_token(state);
823  }
824  }
825 
826  /* Ordinary builtin constants. */
827  for (i = 0; builtin_consts[i].name; i++) {
828  if (STREQ(state->tokenbuf, builtin_consts[i].name)) {
830  return parse_next_token(state);
831  }
832  }
833 
834  /* Ordinary builtin functions. */
835  for (i = 0; builtin_ops[i].name; i++) {
836  if (STREQ(state->tokenbuf, builtin_ops[i].name)) {
837  int args = parse_function_args(state);
838 
839  /* Search for other arg count versions if necessary. */
840  if (args != opcode_arg_count(builtin_ops[i].op)) {
841  for (int j = i + 1; builtin_ops[j].name; j++) {
842  if (opcode_arg_count(builtin_ops[j].op) == args &&
843  STREQ(builtin_ops[j].name, builtin_ops[i].name)) {
844  i = j;
845  break;
846  }
847  }
848  }
849 
850  return parse_add_func(state, builtin_ops[i].op, args, builtin_ops[i].funcptr);
851  }
852  }
853 
854  /* Specially supported functions. */
855  if (STREQ(state->tokenbuf, "min")) {
856  int cnt = parse_function_args(state);
857  CHECK_ERROR(cnt > 0);
858 
859  parse_add_op(state, OPCODE_MIN, 1 - cnt)->arg.ival = cnt;
860  return true;
861  }
862 
863  if (STREQ(state->tokenbuf, "max")) {
864  int cnt = parse_function_args(state);
865  CHECK_ERROR(cnt > 0);
866 
867  parse_add_op(state, OPCODE_MAX, 1 - cnt)->arg.ival = cnt;
868  return true;
869  }
870 
871  return false;
872 
873  default:
874  return false;
875  }
876 }
877 
879 {
881 
882  for (;;) {
883  switch (state->token) {
884  case '*':
887  break;
888 
889  case '/':
892  break;
893 
894  default:
895  return true;
896  }
897  }
898 }
899 
901 {
903 
904  for (;;) {
905  switch (state->token) {
906  case '+':
909  break;
910 
911  case '-':
914  break;
915 
916  default:
917  return true;
918  }
919  }
920 }
921 
922 static BinaryOpFunc parse_get_cmp_func(short token)
923 {
924  switch (token) {
925  case TOKEN_EQ:
926  return op_eq;
927  case TOKEN_NE:
928  return op_ne;
929  case '>':
930  return op_gt;
931  case TOKEN_GE:
932  return op_ge;
933  case '<':
934  return op_lt;
935  case TOKEN_LE:
936  return op_le;
937  default:
938  return NULL;
939  }
940 }
941 
943 {
944  BinaryOpFunc next_func = parse_get_cmp_func(state->token);
945 
946  if (next_func) {
947  parse_add_op(state, OPCODE_CMP_CHAIN, -1)->arg.func2 = cur_func;
948  int jump = state->last_jmp = state->ops_count;
949 
951  CHECK_ERROR(parse_cmp_chain(state, next_func));
952 
954  }
955  else {
956  parse_add_func(state, OPCODE_FUNC2, 2, cur_func);
957  }
958 
959  return true;
960 }
961 
963 {
965 
966  BinaryOpFunc func = parse_get_cmp_func(state->token);
967 
968  if (func) {
970 
971  return parse_cmp_chain(state, func);
972  }
973 
974  return true;
975 }
976 
978 {
979  if (state->token == TOKEN_NOT) {
982  return true;
983  }
984 
985  return parse_cmp(state);
986 }
987 
989 {
991 
992  if (state->token == TOKEN_AND) {
994 
996 
998  }
999 
1000  return true;
1001 }
1002 
1004 {
1006 
1007  if (state->token == TOKEN_OR) {
1009 
1011 
1013  }
1014 
1015  return true;
1016 }
1017 
1019 {
1020  /* Temporarily set the constant expression evaluation barrier */
1021  int prev_last_jmp = state->last_jmp;
1022  int start = state->last_jmp = state->ops_count;
1023 
1025 
1026  if (state->token == TOKEN_IF) {
1027  /* Ternary IF expression in python requires swapping the
1028  * main body with condition, so stash the body opcodes. */
1029  int size = state->ops_count - start;
1030  int bytes = size * sizeof(ExprOp);
1031 
1032  ExprOp *body = MEM_mallocN(bytes, "driver if body");
1033  memcpy(body, state->ops + start, bytes);
1034 
1035  state->last_jmp = state->ops_count = start;
1036  state->stack_ptr--;
1037 
1038  /* Parse condition. */
1039  if (!parse_next_token(state) || !parse_or(state) || state->token != TOKEN_ELSE ||
1040  !parse_next_token(state)) {
1041  MEM_freeN(body);
1042  return false;
1043  }
1044 
1045  int jmp_else = parse_add_jump(state, OPCODE_JMP_ELSE);
1046 
1047  /* Add body back. */
1048  memcpy(parse_alloc_ops(state, size), body, bytes);
1049  MEM_freeN(body);
1050 
1051  state->stack_ptr++;
1052 
1053  int jmp_end = parse_add_jump(state, OPCODE_JMP);
1054 
1055  /* Parse the else block. */
1056  parse_set_jump(state, jmp_else);
1057 
1059 
1060  parse_set_jump(state, jmp_end);
1061  }
1062  /* If no actual jumps happened, restore previous barrier */
1063  else if (state->last_jmp == start) {
1064  state->last_jmp = prev_last_jmp;
1065  }
1066 
1067  return true;
1068 }
1069 
1072 /* -------------------------------------------------------------------- */
1083  const char **param_names,
1084  int param_names_len)
1085 {
1086  /* Prepare the parser state. */
1088  memset(&state, 0, sizeof(state));
1089 
1090  state.cur = state.expr = expression;
1091 
1092  state.param_names_len = param_names_len;
1093  state.param_names = param_names;
1094 
1095  state.tokenbuf = MEM_mallocN(strlen(expression) + 1, __func__);
1096 
1097  state.max_ops = 16;
1098  state.ops = MEM_mallocN(state.max_ops * sizeof(ExprOp), __func__);
1099 
1100  /* Parse the expression. */
1101  ExprPyLike_Parsed *expr;
1102 
1103  if (parse_next_token(&state) && parse_expr(&state) && state.token == 0) {
1104  BLI_assert(state.stack_ptr == 1);
1105 
1106  int bytesize = sizeof(ExprPyLike_Parsed) + state.ops_count * sizeof(ExprOp);
1107 
1108  expr = MEM_mallocN(bytesize, "ExprPyLike_Parsed");
1109  expr->ops_count = state.ops_count;
1110  expr->max_stack = state.max_stack;
1111 
1112  memcpy(expr->ops, state.ops, state.ops_count * sizeof(ExprOp));
1113  }
1114  else {
1115  /* Always return a non-NULL object so that parse failure can be cached. */
1116  expr = MEM_callocN(sizeof(ExprPyLike_Parsed), "ExprPyLike_Parsed(empty)");
1117  }
1118 
1119  MEM_freeN(state.tokenbuf);
1120  MEM_freeN(state.ops);
1121  return expr;
1122 }
1123 
#define BLI_array_alloca(arr, realsize)
Definition: BLI_alloca.h:36
#define BLI_assert(a)
Definition: BLI_assert.h:58
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:38
#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 RGB to Bright Vector Camera 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
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_callocN)(size_t len, const char *str)
Definition: mallocn.c:45
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
static ulong state[N]
static unsigned a[3]
Definition: RandGen.cpp:92
INLINE Rall1d< T, V, S > cos(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:319
INLINE Rall1d< T, V, S > pow(const Rall1d< T, V, S > &arg, double m)
Definition: rall1d.h:359
INLINE Rall1d< T, V, S > log(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:303
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
INLINE Rall1d< T, V, S > exp(const Rall1d< T, V, S > &arg)
Definition: rall1d.h:295
const char * name
const char * name
void * ptr
UnaryOpFunc func1
eOpCode opcode
double dval
BinaryOpFunc func2
TernaryOpFunc func3
union ExprOp::@123 arg
const char * cur
const char * expr
const char ** param_names
const char * name
ccl_device_inline float2 floor(const float2 &a)
ccl_device_inline float2 fabs(const float2 &a)
ccl_device_inline float3 ceil(const float3 &a)