summaryrefslogtreecommitdiffhomepage
path: root/eval.c
AgeCommit message (Collapse)Author
2020-11-19treewide: rebrand to ucodeJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-11-12ast: simplify declaration AST structureJo-Philipp Wich
Do not emit dummy T_ASSIGN nodes for plain variable declarations without initialization (`let foo` or `local foo`). This also allows simplifying `ut_check_for_in()` since we only need to deal with one common structure for both `for (... in ...)` and `for (local ... in ...)` cases. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-11-12syntax: implement key/value for-in loop iterationJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-11-05eval: rework handling of list expressionsJo-Philipp Wich
Tune the grammar and rework the VM to properly yield the last result of list expressions in various contexts. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-11-05syntax: implement ES6-like arrow function syntaxJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-11-03syntax: implement ES6-like spread operatorJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-11-03syntax: implement ES6-like rest parameters for variadic functionsJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-11-02syntax: support `elif` clauses for alternative `if` syntaxJo-Philipp Wich
In the alternative `if` syntax mode, support a specific `elif` keyword instead of requiring an `else` branch followed by a disjunct `if` statement. The advantage is that templates do not require error-prone redundant `endif` keywords in else-if ladders. After this change, the following example: {% if (...): %} One condition {% else if (...): %} Another condition {% else if (...): %} A third condition {% else %} Final condition {% endif; endif; endif %} ... can be simplified into: {% if (...): %} One condition {% elif (...): %} Another condition {% elif (...): %} A third condition {% else %} Final condition {% endif %} Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-19eval: fix memory leak in ut_execute_local()Jo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-19eval: fix leaking key value in object for-in loopsJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-19eval: record correct source contexts in call stackJo-Philipp Wich
Also handle calls to C functions. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-19eval: avoid ut_op deref after ut_execute_op() in ut_execute_local()Jo-Philipp Wich
Since we're invoking ut_execute_op() to obtain the assignment value, the operand pool might have been reallocated at a different memory address, invalidating the label opcode pointer. Obtain a reference to the underlying json label value and re-obtain the assignment opcode pointer with each iteration to avoid dereferencing stale pointers. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-18ast, eval: add recursion limitJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-18eval: fix segmentation faults with self-invoking functionsJo-Philipp Wich
Store the invocation scope and function context in the call stack frame and not in the function object to properly deal with recursive invocations. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-15eval: fix potential segfault in for() loopsJo-Philipp Wich
When a for() loop body, initializer, test or increment expression compiles further code, e.g. by invoking invoke() or require(), the opcode pool will be reallocated, potentially changing the addresses of all opcodes. This might lead to an invalid memory access when previously cached opcode pointers are accessed later on. Solve this issue by obtaining the relative offsets of the corresponding opcodes, avoiding the need for pointer dereferences. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-14eval: forward exceptions in `if` conditionsJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-14eval: expose complete exception object in catch {} blocksJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-14eval: get rid of alloca() allocationsJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-14treewide: unify error handlingJo-Philipp Wich
Get rid of the distinction between lexer/parser errors and runtime exceptions, use exceptions everywhere instead. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-14treewide: rework source file and callstack handlingJo-Philipp Wich
- Keep an open FILE* reference to processed source files in order to be able to rewind and extract error context later - Build a proper call stack when invoking utpl functions - Report call stack in exceptions Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-14eval: refactor ut_parse_op()Jo-Philipp Wich
Refactor the central ut_parse_op() function to use a jump table for invoking the proper operand handler function in order to reduce the compiled code size. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-14lexer: rewriteJo-Philipp Wich
Rewrite the lexer into a restartable state machine to support parsing from file streams without the need to read the entire source text into memory first. As a side effect, the length of labels and strings is unlimited now. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-06eval: properly break out of switch/case on return/continue/exceptionJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-06eval: restore context pointer of first evaluated dot/bracket expressionJo-Philipp Wich
When an expression such as `foo.bar(a.b, c.d)` is evaluated, the state context pointer will point to `c` while we need `foo` when invoking functions. Since the context pointer is only relevant for function calls and since for function call opcodes, the lhs expression is always the first operand, there is no need to store the context of subsequent ops. Adjust the ut_get_operands() procedure to restore state->ctx to the result of the first evaluated operand. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-06treewide: rework exception context formattingJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-06ast, eval: track current file name across function invocationsJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-05eval: restore correct scope after leaving functionJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-04treewide: rework function scopingJo-Philipp Wich
- Implement proper closure scoping for function - Avoid circular references when managing scopes pointers - Eliminate ut_putval() in favor to json_object_put() - Fix function return value handling - Change internal function structure Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-02eval: avoid null pointer access in ut_invoke()Jo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-02eval: properly forward execeptions in for-in loop value evaluationJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-02ast: store function declarations as opcode offsetsJo-Philipp Wich
We cannot use direct pointers since the opcode array might be reallocated resulting in potentially changed memory addresses. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-02eval: free previous exception when storing a new oneJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-02eval: fix potential uninitialized memory access in ut_getref()Jo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-02Revert "eval: release root scope after finishing the execution"Jo-Philipp Wich
This reverts commit 206630d7141f32594e9110081f6710446f5aebd3. Revert this commit to fix a double-free. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-02treewide: rework handling of memory allocation failuresJo-Philipp Wich
Instead of propagating failures to the caller, print a generic error message and terminate program execution through abort(). Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-10-02eval: release root scope after finishing the executionJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-09-24syntax: add regular expression supportJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-09-23eval: ensure that argument array is initialized when invoking C functionsJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-09-23eval: propagate exceptions when resolving referencesJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-09-22syntax: introduce case statement supportJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-09-21eval: fix potential null pointer access when computing operandsJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-09-21syntax: introduce try/catch blocksJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-09-21eval: don't escape slashes when outputting array or object JSONJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-09-21treewide: ensure to properly propagate exceptionsJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-09-20eval: fix leaking calculated object keysJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-09-20eval: fix double free of env valuesJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-09-20eval: implement -m option to preload modulesJo-Philipp Wich
The -m option instructs the interpreter to automatically require the named module and to register the module context as global variable. The following two commands are equivalent, with the former one serving as a shortcut for the latter: utpl -m fs -s '{{ fs.open("test.txt").read("all") }}' utpl -s '{% fs = require("fs"); print(fs.open("test.txt").read("all")) %}' Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-09-20eval: improve reference error reportingJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-09-20Revert "treewide: rework exception handling"Jo-Philipp Wich
This reverts commit 54bb15b2be3656e91386b80074f45591b20fed3f. Relying on setjmp() / longjmp() causes too many headaches trying to track and properly release intermediate values. Signed-off-by: Jo-Philipp Wich <jo@mein.io>
2020-09-17eval: sanitize variable namesJo-Philipp Wich
Signed-off-by: Jo-Philipp Wich <jo@mein.io>