summaryrefslogtreecommitdiffhomepage
diff options
context:
space:
mode:
authorJo-Philipp Wich <jo@mein.io>2020-09-21 12:50:14 +0200
committerJo-Philipp Wich <jo@mein.io>2020-09-21 12:50:14 +0200
commit64d998474dc4e0c27b6f9ffa054a556d90ff7d36 (patch)
treebc779d2882db78591b9848e409a6ea93d640ba24
parentff88195a710ec58190a75a2c71e90126e52a07ca (diff)
syntax: introduce try/catch blocks
Signed-off-by: Jo-Philipp Wich <jo@mein.io>
-rw-r--r--eval.c25
-rw-r--r--lexer.c4
-rw-r--r--lexer.h2
-rw-r--r--parser.y9
4 files changed, 39 insertions, 1 deletions
diff --git a/eval.c b/eval.c
index 13e5c21..0728ba2 100644
--- a/eval.c
+++ b/eval.c
@@ -1436,6 +1436,28 @@ ut_execute_this(struct ut_state *state, uint32_t off)
}
static struct json_object *
+ut_execute_try_catch(struct ut_state *state, uint32_t off)
+{
+ struct ut_op *op = ut_get_op(state, off);
+ struct json_object *rv;
+
+ rv = ut_execute_op_sequence(state, op->tree.operand[0]);
+
+ if (ut_is_type(rv, T_EXCEPTION)) {
+ if (op->tree.operand[1])
+ ut_putval(ut_setval(ut_getscope(state, 0), ut_get_child(state, off, 1)->val,
+ json_object_new_string(json_object_get_string(rv))));
+
+ memset(&state->error, 0, sizeof(state->error));
+
+ ut_putval(rv);
+ rv = ut_execute_op_sequence(state, op->tree.operand[2]);
+ }
+
+ return rv;
+}
+
+static struct json_object *
ut_execute_op(struct ut_state *state, uint32_t off)
{
struct ut_op *op = ut_get_op(state, off);
@@ -1594,6 +1616,9 @@ ut_execute_op(struct ut_state *state, uint32_t off)
case T_CONTINUE:
return ut_execute_break_cont(state, off);
+ case T_TRY:
+ return ut_execute_try_catch(state, off);
+
default:
return ut_exception(state, off, "Runtime error: Unrecognized opcode %d", op->type);
}
diff --git a/lexer.c b/lexer.c
index 390a12e..5c1b759 100644
--- a/lexer.c
+++ b/lexer.c
@@ -132,12 +132,14 @@ static const struct token reserved_words[] = {
{ T_ENDIF, "endif", 5 },
{ T_WHILE, "while", 5 },
{ T_BREAK, "break", 5 },
+ { T_CATCH, "catch", 5 },
{ T_BOOL, "false", 5, parse_bool },
{ T_BOOL, "true", 4, parse_bool },
{ T_ELSE, "else", 4 },
{ T_THIS, "this", 4 },
{ T_NULL, "null", 4 },
{ T_NUMBER, "NaN", 3, parse_number },
+ { T_TRY, "try", 3 },
{ T_FOR, "for", 3 },
{ T_IN, "in", 2 },
};
@@ -214,6 +216,8 @@ const char *tokennames[__T_MAX] = {
[T_CONTINUE] = "'continue'",
[T_NULL] = "'null'",
[T_THIS] = "'this'",
+ [T_TRY] = "'try'",
+ [T_CATCH] = "'catch'",
//[T_LSTM] = "'{%'",
//[T_RSTM] = "'%}'"
};
diff --git a/lexer.h b/lexer.h
index cb6bca9..06a0ceb 100644
--- a/lexer.h
+++ b/lexer.h
@@ -19,7 +19,7 @@
#include "ast.h"
-#define __T_MAX 73
+#define __T_MAX 75
#define T_EXCEPTION (__T_MAX + 0)
#define T_CFUNC (__T_MAX + 1)
#define T_RESSOURCE (__T_MAX + 2)
diff --git a/parser.y b/parser.y
index a3ba991..be59abb 100644
--- a/parser.y
+++ b/parser.y
@@ -114,6 +114,7 @@ stmt(A) ::= exp_stmt(B). { A = B; }
stmt(A) ::= sel_stmt(B). { A = B; }
stmt(A) ::= iter_stmt(B). { A = B; }
stmt(A) ::= func_stmt(B). { A = B; }
+stmt(A) ::= try_stmt(B). { A = B; }
stmt(A) ::= ret_stmt(B). { A = B; }
stmt(A) ::= break_stmt(B). { A = B; }
stmt(A) ::= decl_stmt(B). { A = B; }
@@ -165,6 +166,14 @@ func_stmt(A) ::= T_FUNC(B) T_LABEL(C) T_LPAREN args(D) T_RPAREN empty_object.
func_stmt(A) ::= T_FUNC(B) T_LABEL(C) T_LPAREN args(D) T_RPAREN T_COLON chunks(E) T_ENDFUNC.
{ A = wrap_op(B, C, D, E); }
+try_stmt(A) ::= T_TRY(B) try_catch_block(C) T_CATCH T_LPAREN T_LABEL(D) T_RPAREN try_catch_block(E).
+ { A = wrap_op(B, C, D, E); }
+try_stmt(A) ::= T_TRY(B) try_catch_block(C) T_CATCH try_catch_block(D).
+ { A = wrap_op(B, C, 0, D); }
+
+try_catch_block(A) ::= cpd_stmt(B). { A = B; }
+try_catch_block(A) ::= empty_object. { A = 0; }
+
args(A) ::= args(B) T_COMMA T_LABEL(C). { A = append_op(B, C); }
args(A) ::= T_LABEL(B). { A = B; }