From e985fa5fe19f63e7d7ad5361574d31b973d41a42 Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Fri, 6 Feb 2026 18:40:56 -0600 Subject: [PATCH] disrupt/disruption; remove try/catch --- source/quickjs.c | 379 ++++++++-------------------------- vm_test/syntax.txt | 30 +-- vm_test/try_catch.txt | 1 - vm_test/try_catch_finally.txt | 1 - vm_test/try_finally.txt | 1 - vm_test/try_throw.txt | 1 - 6 files changed, 94 insertions(+), 319 deletions(-) delete mode 100644 vm_test/try_catch.txt delete mode 100644 vm_test/try_catch_finally.txt delete mode 100644 vm_test/try_finally.txt delete mode 100644 vm_test/try_throw.txt diff --git a/source/quickjs.c b/source/quickjs.c index 38168bd6..185886d3 100644 --- a/source/quickjs.c +++ b/source/quickjs.c @@ -8547,10 +8547,8 @@ enum { TOK_FOR, TOK_BREAK, TOK_CONTINUE, - TOK_THROW, - TOK_TRY, - TOK_CATCH, - TOK_FINALLY, + TOK_DISRUPT, + TOK_DISRUPTION, TOK_FUNCTION, TOK_DEBUGGER, TOK_WITH, @@ -8653,10 +8651,8 @@ static const char *ast_token_kind_str(int token_val) { case TOK_FOR: return "for"; case TOK_BREAK: return "break"; case TOK_CONTINUE: return "continue"; - case TOK_THROW: return "throw"; - case TOK_TRY: return "try"; - case TOK_CATCH: return "catch"; - case TOK_FINALLY: return "finally"; + case TOK_DISRUPT: return "disrupt"; + case TOK_DISRUPTION: return "disruption"; case TOK_FUNCTION: return "function"; case TOK_DEBUGGER: return "debugger"; case TOK_WITH: return "with"; @@ -9808,10 +9804,8 @@ static const JSKeywordEntry js_keywords[] = { { "for", TOK_FOR, FALSE }, { "break", TOK_BREAK, FALSE }, { "continue", TOK_CONTINUE, FALSE }, - { "throw", TOK_THROW, FALSE }, - { "try", TOK_TRY, FALSE }, - { "catch", TOK_CATCH, FALSE }, - { "finally", TOK_FINALLY, FALSE }, + { "disrupt", TOK_DISRUPT, FALSE }, + { "disruption", TOK_DISRUPTION, FALSE }, { "function", TOK_FUNCTION, FALSE }, { "debugger", TOK_DEBUGGER, FALSE }, { "with", TOK_WITH, FALSE }, @@ -12058,7 +12052,7 @@ static __exception int js_define_var (JSParseState *s, JSValue name, int tok) { case TOK_VAR: var_def_type = JS_VAR_DEF_LET; break; - case TOK_CATCH: + case TOK_DISRUPTION: var_def_type = JS_VAR_DEF_CATCH; break; default: @@ -13378,16 +13372,9 @@ static __exception int js_parse_statement_or_decl (JSParseState *s, } if (js_parse_expect_semi (s)) goto fail; } break; - case TOK_THROW: { - const uint8_t *op_token_ptr; - op_token_ptr = s->token.ptr; + case TOK_DISRUPT: { if (next_token (s)) goto fail; - if (s->got_lf) { - js_parse_error (s, "line terminator not allowed after throw"); - goto fail; - } - if (js_parse_expr (s)) goto fail; - emit_source_pos (s, op_token_ptr); + emit_op (s, OP_null); emit_op (s, OP_throw); if (js_parse_expect_semi (s)) goto fail; } break; @@ -13604,126 +13591,6 @@ static __exception int js_parse_statement_or_decl (JSParseState *s, } if (js_parse_expect_semi (s)) goto fail; } break; - case TOK_TRY: { - int label_catch, label_catch2, label_finally, label_end; - JSValue name; - BlockEnv block_env; - - if (next_token (s)) goto fail; - label_catch = new_label (s); - label_catch2 = new_label (s); - label_finally = new_label (s); - label_end = new_label (s); - - emit_goto (s, OP_catch, label_catch); - - push_break_entry (s->cur_func, &block_env, JS_NULL, -1, -1, 1); - block_env.label_finally = label_finally; - - if (js_parse_block (s)) goto fail; - - pop_break_entry (s->cur_func); - - if (js_is_live_code (s)) { - /* drop the catch offset */ - emit_op (s, OP_drop); - /* must push dummy value to keep same stack size */ - emit_op (s, OP_null); - emit_goto (s, OP_gosub, label_finally); - emit_op (s, OP_drop); - - emit_goto (s, OP_goto, label_end); - } - - if (s->token.val == TOK_CATCH) { - if (next_token (s)) goto fail; - - push_scope (s); /* catch variable */ - emit_label (s, label_catch); - - if (s->token.val == '{') { - /* support optional-catch-binding feature */ - emit_op (s, OP_drop); /* pop the exception object */ - } else { - if (js_parse_expect (s, '(')) goto fail; - if (!(s->token.val == TOK_IDENT && !s->token.u.ident.is_reserved)) { - if (s->token.val == '[' || s->token.val == '{') { - /* catch variables behave like var (block scoped) */ - if (js_parse_destructuring_element (s, TOK_VAR, 0, TRUE, TRUE, FALSE) - < 0) - goto fail; - } else { - js_parse_error (s, "identifier expected"); - goto fail; - } - } else { - name = s->token.u.ident.str; - if (next_token (s) || js_define_var (s, name, TOK_CATCH) < 0) { - goto fail; - } - /* store the exception value in the catch variable */ - emit_op (s, OP_scope_put_var); - emit_key (s, name); - emit_u16 (s, s->cur_func->scope_level); - } - if (js_parse_expect (s, ')')) goto fail; - } - /* XXX: should keep the address to nop it out if there is no finally - * block */ - emit_goto (s, OP_catch, label_catch2); - - push_scope (s); /* catch block */ - push_break_entry (s->cur_func, &block_env, JS_NULL, -1, -1, 1); - block_env.label_finally = label_finally; - - if (js_parse_block (s)) goto fail; - - pop_break_entry (s->cur_func); - pop_scope (s); /* catch block */ - pop_scope (s); /* catch variable */ - - if (js_is_live_code (s)) { - /* drop the catch2 offset */ - emit_op (s, OP_drop); - /* XXX: should keep the address to nop it out if there is no finally - * block */ - /* must push dummy value to keep same stack size */ - emit_op (s, OP_null); - emit_goto (s, OP_gosub, label_finally); - emit_op (s, OP_drop); - emit_goto (s, OP_goto, label_end); - } - /* catch exceptions thrown in the catch block to execute the - * finally clause and rethrow the exception */ - emit_label (s, label_catch2); - /* catch value is at TOS, no need to push undefined */ - emit_goto (s, OP_gosub, label_finally); - emit_op (s, OP_throw); - - } else if (s->token.val == TOK_FINALLY) { - /* finally without catch : execute the finally clause - * and rethrow the exception */ - emit_label (s, label_catch); - /* catch value is at TOS, no need to push undefined */ - emit_goto (s, OP_gosub, label_finally); - emit_op (s, OP_throw); - } else { - js_parse_error (s, "expecting catch or finally"); - goto fail; - } - emit_label (s, label_finally); - if (s->token.val == TOK_FINALLY) { - if (next_token (s)) goto fail; - /* on the stack: ret_value gosub_ret_value */ - push_break_entry (s->cur_func, &block_env, JS_NULL, -1, -1, 2); - - if (js_parse_block (s)) goto fail; - - pop_break_entry (s->cur_func); - } - emit_op (s, OP_ret); - emit_label (s, label_end); - } break; case ';': /* empty statement */ if (next_token (s)) goto fail; @@ -16579,8 +16446,7 @@ static __exception int js_parse_directives (JSParseState *s) { case TOK_DO: case TOK_WHILE: case TOK_FOR: - case TOK_THROW: - case TOK_TRY: + case TOK_DISRUPT: case TOK_FUNCTION: case TOK_DEBUGGER: case TOK_DEF: @@ -27867,6 +27733,7 @@ typedef struct ASTParseState { int function_nr; cJSON *errors; /* array of error objects */ int has_error; + int in_disruption; union { struct { const char *str; @@ -28171,7 +28038,6 @@ redo: else if (len == 3 && !memcmp (start, "var", 3)) s->token_val = TOK_VAR; else if (len == 3 && !memcmp (start, "def", 3)) s->token_val = TOK_DEF; else if (len == 3 && !memcmp (start, "for", 3)) s->token_val = TOK_FOR; - else if (len == 3 && !memcmp (start, "try", 3)) s->token_val = TOK_TRY; else if (len == 4 && !memcmp (start, "else", 4)) s->token_val = TOK_ELSE; else if (len == 4 && !memcmp (start, "this", 4)) s->token_val = TOK_THIS; else if (len == 4 && !memcmp (start, "null", 4)) s->token_val = TOK_NULL; @@ -28179,13 +28045,12 @@ redo: else if (len == 5 && !memcmp (start, "false", 5)) s->token_val = TOK_FALSE; else if (len == 5 && !memcmp (start, "while", 5)) s->token_val = TOK_WHILE; else if (len == 5 && !memcmp (start, "break", 5)) s->token_val = TOK_BREAK; - else if (len == 5 && !memcmp (start, "throw", 5)) s->token_val = TOK_THROW; - else if (len == 5 && !memcmp (start, "catch", 5)) s->token_val = TOK_CATCH; else if (len == 6 && !memcmp (start, "return", 6)) s->token_val = TOK_RETURN; else if (len == 6 && !memcmp (start, "delete", 6)) s->token_val = TOK_DELETE; - else if (len == 7 && !memcmp (start, "finally", 7)) s->token_val = TOK_FINALLY; + else if (len == 7 && !memcmp (start, "disrupt", 7)) s->token_val = TOK_DISRUPT; else if (len == 8 && !memcmp (start, "function", 8)) s->token_val = TOK_FUNCTION; else if (len == 8 && !memcmp (start, "continue", 8)) s->token_val = TOK_CONTINUE; + else if (len == 10 && !memcmp (start, "disruption", 10)) s->token_val = TOK_DISRUPTION; } break; case '.': if (p[1] >= '0' && p[1] <= '9') { @@ -28499,7 +28364,6 @@ static int tokenize_next (ASTParseState *s) { else if (len == 3 && !memcmp (start, "var", 3)) s->token_val = TOK_VAR; else if (len == 3 && !memcmp (start, "def", 3)) s->token_val = TOK_DEF; else if (len == 3 && !memcmp (start, "for", 3)) s->token_val = TOK_FOR; - else if (len == 3 && !memcmp (start, "try", 3)) s->token_val = TOK_TRY; else if (len == 4 && !memcmp (start, "else", 4)) s->token_val = TOK_ELSE; else if (len == 4 && !memcmp (start, "this", 4)) s->token_val = TOK_THIS; else if (len == 4 && !memcmp (start, "null", 4)) s->token_val = TOK_NULL; @@ -28507,13 +28371,12 @@ static int tokenize_next (ASTParseState *s) { else if (len == 5 && !memcmp (start, "false", 5)) s->token_val = TOK_FALSE; else if (len == 5 && !memcmp (start, "while", 5)) s->token_val = TOK_WHILE; else if (len == 5 && !memcmp (start, "break", 5)) s->token_val = TOK_BREAK; - else if (len == 5 && !memcmp (start, "throw", 5)) s->token_val = TOK_THROW; - else if (len == 5 && !memcmp (start, "catch", 5)) s->token_val = TOK_CATCH; else if (len == 6 && !memcmp (start, "return", 6)) s->token_val = TOK_RETURN; else if (len == 6 && !memcmp (start, "delete", 6)) s->token_val = TOK_DELETE; - else if (len == 7 && !memcmp (start, "finally", 7)) s->token_val = TOK_FINALLY; + else if (len == 7 && !memcmp (start, "disrupt", 7)) s->token_val = TOK_DISRUPT; else if (len == 8 && !memcmp (start, "function", 8)) s->token_val = TOK_FUNCTION; else if (len == 8 && !memcmp (start, "continue", 8)) s->token_val = TOK_CONTINUE; + else if (len == 10 && !memcmp (start, "disruption", 10)) s->token_val = TOK_DISRUPTION; } break; case '.': if (p[1] >= '0' && p[1] <= '9') { @@ -29370,6 +29233,10 @@ static cJSON *ast_parse_function_inner (ASTParseState *s, BOOL is_expr) { const uint8_t *start = s->token_ptr; cJSON *node = ast_node (s, "function", start); + if (s->in_disruption) { + ast_error (s, s->token_ptr, "cannot define function inside disruption clause"); + } + ast_next_token (s); /* skip 'function' */ /* Optional function name */ @@ -29444,6 +29311,26 @@ static cJSON *ast_parse_function_inner (ASTParseState *s, BOOL is_expr) { ast_error (s, s->token_ptr, "expected '{' for function body"); } + /* Optional disruption clause */ + if (s->token_val == TOK_DISRUPTION) { + ast_next_token (s); + if (s->token_val == '{') { + ast_next_token (s); + int old_in_disruption = s->in_disruption; + s->in_disruption = 1; + cJSON *disruption_stmts = ast_parse_block_statements (s); + s->in_disruption = old_in_disruption; + cJSON_AddItemToObject (node, "disruption", disruption_stmts); + if (s->token_val == '}') { + ast_next_token (s); + } else if (s->token_val == TOK_EOF) { + ast_error (s, s->token_ptr, "unterminated disruption clause, expected '}'"); + } + } else { + ast_error (s, s->token_ptr, "expected '{' after disruption"); + } + } + cJSON_AddNumberToObject (node, "function_nr", s->function_nr++); ast_node_end (s, node, s->buf_ptr); return node; @@ -29455,6 +29342,10 @@ static cJSON *ast_parse_arrow_function (ASTParseState *s) { cJSON *node = ast_node (s, "function", start); cJSON_AddBoolToObject (node, "arrow", 1); + if (s->in_disruption) { + ast_error (s, s->token_ptr, "cannot define function inside disruption clause"); + } + /* Parameters */ cJSON *params = cJSON_AddArrayToObject (node, "list"); @@ -29558,7 +29449,7 @@ static void ast_sync_to_statement (ASTParseState *s) { case '}': return; /* don't consume - let caller handle */ case TOK_VAR: case TOK_DEF: case TOK_IF: case TOK_WHILE: - case TOK_FOR: case TOK_RETURN: case TOK_THROW: case TOK_TRY: + case TOK_FOR: case TOK_RETURN: case TOK_DISRUPT: case TOK_FUNCTION: case TOK_BREAK: case TOK_CONTINUE: case TOK_DO: return; /* statement-starting keyword found */ @@ -29774,14 +29665,9 @@ static cJSON *ast_parse_statement (ASTParseState *s) { ast_node_end (s, node, s->buf_ptr); } break; - case TOK_THROW: { - node = ast_node (s, "throw", start); + case TOK_DISRUPT: { + node = ast_node (s, "disrupt", start); ast_next_token (s); - if (s->got_lf) { - ast_error (s, s->token_ptr, "line terminator not allowed after throw"); - } - cJSON *expr = ast_parse_expr (s); - cJSON_AddItemToObject (node, "expression", expr); ast_expect_semi (s); ast_node_end (s, node, s->buf_ptr); } break; @@ -29808,57 +29694,6 @@ static cJSON *ast_parse_statement (ASTParseState *s) { ast_node_end (s, node, s->buf_ptr); } break; - case TOK_TRY: { - node = ast_node (s, "try", start); - ast_next_token (s); - - if (s->token_val == '{') { - ast_next_token (s); - cJSON *stmts = ast_parse_block_statements (s); - cJSON_AddItemToObject (node, "statements", stmts); - if (s->token_val == '}') ast_next_token (s); - } else { - ast_error (s, s->token_ptr, "expected '{' for try block"); - } - - if (s->token_val != TOK_CATCH && s->token_val != TOK_FINALLY) - ast_error (s, s->token_ptr, "expected 'catch' or 'finally' after try block"); - - if (s->token_val == TOK_CATCH) { - cJSON *catch_node = ast_node (s, "catch", s->token_ptr); - ast_next_token (s); - if (s->token_val == '(') { - ast_next_token (s); - if (s->token_val == TOK_IDENT) { - cjson_add_strn (catch_node, "name", s->token_u.ident.str, s->token_u.ident.len); - ast_next_token (s); - } - if (s->token_val == ')') ast_next_token (s); - } - if (s->token_val == '{') { - ast_next_token (s); - cJSON *catch_stmts = ast_parse_block_statements (s); - cJSON_AddItemToObject (catch_node, "statements", catch_stmts); - if (s->token_val == '}') ast_next_token (s); - } - ast_node_end (s, catch_node, s->buf_ptr); - cJSON_AddItemToObject (node, "catch", catch_node); - } - - if (s->token_val == TOK_FINALLY) { - cJSON *finally_node = ast_node (s, "finally", s->token_ptr); - ast_next_token (s); - if (s->token_val == '{') { - ast_next_token (s); - cJSON *finally_stmts = ast_parse_block_statements (s); - cJSON_AddItemToObject (finally_node, "statements", finally_stmts); - if (s->token_val == '}') ast_next_token (s); - } - ast_node_end (s, finally_node, s->buf_ptr); - cJSON_AddItemToObject (node, "finally", finally_node); - } - ast_node_end (s, node, s->buf_ptr); - } break; case TOK_FUNCTION: { node = ast_parse_function_inner (s, FALSE); @@ -30244,6 +30079,14 @@ static void ast_sem_check_expr (ASTSemState *st, ASTSemScope *scope, cJSON *expr ast_sem_check_stmt (st, &fn_scope, stmt); } + /* Check disruption clause */ + cJSON *disruption = cJSON_GetObjectItem (expr, "disruption"); + if (disruption) { + cJSON_ArrayForEach (stmt, disruption) { + ast_sem_check_stmt (st, &fn_scope, stmt); + } + } + /* Build scope record and attach to scopes array */ int nr_slots, nr_close; cJSON *rec = ast_sem_build_scope_record (&fn_scope, &nr_slots, &nr_close); @@ -30399,12 +30242,15 @@ static void ast_sem_check_stmt (ASTSemState *st, ASTSemScope *scope, cJSON *stmt return; } - if (strcmp (kind, "return") == 0 || strcmp (kind, "throw") == 0 || - strcmp (kind, "go") == 0) { + if (strcmp (kind, "return") == 0 || strcmp (kind, "go") == 0) { ast_sem_check_expr (st, scope, cJSON_GetObjectItem (stmt, "expression")); return; } + if (strcmp (kind, "disrupt") == 0) { + return; + } + if (strcmp (kind, "break") == 0) { if (!ast_sem_in_loop (scope)) { ast_sem_error (st, stmt, "'break' used outside of loop"); @@ -30419,31 +30265,6 @@ static void ast_sem_check_stmt (ASTSemState *st, ASTSemScope *scope, cJSON *stmt return; } - if (strcmp (kind, "try") == 0) { - cJSON *s2; - cJSON_ArrayForEach (s2, cJSON_GetObjectItem (stmt, "statements")) { - ast_sem_check_stmt (st, scope, s2); - } - cJSON *catch_node = cJSON_GetObjectItem (stmt, "catch"); - if (catch_node) { - ASTSemScope catch_scope = {0}; - catch_scope.parent = scope; - catch_scope.function_nr = scope->function_nr; - const char *catch_name = cJSON_GetStringValue (cJSON_GetObjectItem (catch_node, "name")); - if (catch_name) ast_sem_add_var (&catch_scope, catch_name, 0, "var", scope->function_nr); - cJSON_ArrayForEach (s2, cJSON_GetObjectItem (catch_node, "statements")) { - ast_sem_check_stmt (st, &catch_scope, s2); - } - } - cJSON *finally_node = cJSON_GetObjectItem (stmt, "finally"); - if (finally_node) { - cJSON_ArrayForEach (s2, cJSON_GetObjectItem (finally_node, "statements")) { - ast_sem_check_stmt (st, scope, s2); - } - } - return; - } - if (strcmp (kind, "block") == 0) { ASTSemScope block_scope = {0}; block_scope.parent = scope; @@ -30489,6 +30310,14 @@ static void ast_sem_check_stmt (ASTSemState *st, ASTSemScope *scope, cJSON *stmt ast_sem_check_stmt (st, &fn_scope, s2); } + /* Check disruption clause */ + cJSON *disruption = cJSON_GetObjectItem (stmt, "disruption"); + if (disruption) { + cJSON_ArrayForEach (s2, disruption) { + ast_sem_check_stmt (st, &fn_scope, s2); + } + } + /* Build scope record and attach to scopes array */ int nr_slots, nr_close; cJSON *rec = ast_sem_build_scope_record (&fn_scope, &nr_slots, &nr_close); @@ -31743,13 +31572,9 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) { return; } - /* Throw statement */ - if (strcmp(kind, "throw") == 0) { - cJSON *expr = cJSON_GetObjectItem(stmt, "expression"); - int save = cs->freereg; - int r = mach_compile_expr(cs, expr, -1); - mach_emit(cs, MACH_ABC(MACH_THROW, r, 0, 0)); - mach_free_reg_to(cs, save); + /* Disrupt statement */ + if (strcmp(kind, "disrupt") == 0) { + mach_emit(cs, MACH_ABC(MACH_THROW, 0, 0, 0)); return; } @@ -33559,10 +33384,8 @@ static void mach_gen_statement (MachGenState *s, cJSON *stmt) { return; } - if (strcmp (kind, "throw") == 0) { - cJSON *expr = cJSON_GetObjectItem (stmt, "expression"); - int slot = mach_gen_expr (s, expr, -1); - mach_gen_emit_1 (s, "throw", slot); + if (strcmp (kind, "disrupt") == 0) { + mach_gen_emit_0 (s, "disrupt"); return; } @@ -33623,44 +33446,6 @@ static void mach_gen_statement (MachGenState *s, cJSON *stmt) { return; } - if (strcmp (kind, "try") == 0) { - cJSON *try_stmts = cJSON_GetObjectItem (stmt, "statements"); - cJSON *catch_node = cJSON_GetObjectItem (stmt, "catch"); - cJSON *finally_node = cJSON_GetObjectItem (stmt, "finally"); - char *catch_label = catch_node ? mach_gen_label (s, "catch") : NULL; - char *finally_label = finally_node ? mach_gen_label (s, "finally") : NULL; - char *end_label = mach_gen_label (s, "try_end"); - cJSON *instr = cJSON_CreateArray (); - cJSON_AddItemToArray (instr, cJSON_CreateString ("try_begin")); - cJSON_AddItemToArray (instr, cJSON_CreateString (catch_label ? catch_label : end_label)); - cJSON_AddItemToArray (instr, cJSON_CreateString (finally_label ? finally_label : end_label)); - cJSON_AddItemToArray (s->instructions, instr); - cJSON *child; - cJSON_ArrayForEach (child, try_stmts) { mach_gen_statement (s, child); } - mach_gen_emit_0 (s, "try_end"); - if (catch_node) mach_gen_emit_jump (s, finally_label ? finally_label : end_label); - if (catch_node) { - mach_gen_emit_label (s, catch_label); - int err_slot = mach_gen_alloc_slot (s); - mach_gen_emit_1 (s, "catch_begin", err_slot); - cJSON *catch_stmts = cJSON_GetObjectItem (catch_node, "statements"); - cJSON_ArrayForEach (child, catch_stmts) { mach_gen_statement (s, child); } - mach_gen_emit_0 (s, "catch_end"); - sys_free (catch_label); - } - if (finally_node) { - mach_gen_emit_label (s, finally_label); - mach_gen_emit_0 (s, "finally_begin"); - cJSON *finally_stmts = cJSON_GetObjectItem (finally_node, "statements"); - cJSON_ArrayForEach (child, finally_stmts) { mach_gen_statement (s, child); } - mach_gen_emit_0 (s, "finally_end"); - sys_free (finally_label); - } - mach_gen_emit_label (s, end_label); - sys_free (end_label); - return; - } - if (strcmp (kind, "function") == 0) { cJSON *name_obj = cJSON_GetObjectItem (stmt, "name"); if (name_obj && cJSON_IsString (name_obj)) { @@ -33787,6 +33572,12 @@ static cJSON *mach_gen_function (MachGenState *parent, cJSON *func_node) { mach_gen_emit_0 (&s, "return_undef"); + /* Compile disruption clause if present */ + cJSON *disruption = cJSON_GetObjectItem (func_node, "disruption"); + if (disruption && cJSON_IsArray (disruption)) { + cJSON_ArrayForEach (stmt, disruption) { mach_gen_statement (&s, stmt); } + } + cJSON *fn_scope = mach_find_scope_record (s.scopes, s.function_nr); cJSON *fn_ncs = fn_scope ? cJSON_GetObjectItem (fn_scope, "nr_close_slots") : NULL; cJSON_AddNumberToObject (result, "nr_close_slots", fn_ncs ? (int)cJSON_GetNumberValue (fn_ncs) : 0); @@ -33874,7 +33665,7 @@ static cJSON *mach_gen_program (MachGenState *s, cJSON *ast) { if (strcmp (kind, "call") == 0) { cJSON *expr = cJSON_GetObjectItem (stmt, "expression"); last_expr_slot = mach_gen_expr (s, expr, -1); - } else if (strcmp (kind, "return") == 0 || strcmp (kind, "throw") == 0 || + } else if (strcmp (kind, "return") == 0 || strcmp (kind, "disrupt") == 0 || strcmp (kind, "break") == 0 || strcmp (kind, "continue") == 0) { mach_gen_statement (s, stmt); last_expr_slot = -1; @@ -33882,7 +33673,7 @@ static cJSON *mach_gen_program (MachGenState *s, cJSON *ast) { strcmp (kind, "function") == 0 || strcmp (kind, "block") == 0 || strcmp (kind, "if") == 0 || strcmp (kind, "while") == 0 || strcmp (kind, "do") == 0 || strcmp (kind, "for") == 0 || - strcmp (kind, "switch") == 0 || strcmp (kind, "try") == 0) { + strcmp (kind, "switch") == 0) { mach_gen_statement (s, stmt); last_expr_slot = -1; } else { @@ -34795,15 +34586,11 @@ static JSValue mcode_exec(JSContext *ctx, JSMCode *code, JSValue this_obj, } } - /* ---- Exceptions ---- */ - else if (strcmp(op, "throw") == 0) { - result = JS_Throw(ctx, frame->slots[(int)a1->valuedouble]); + /* ---- Disruption ---- */ + else if (strcmp(op, "disrupt") == 0) { + result = JS_Throw(ctx, JS_NULL); goto done; } - else if (strcmp(op, "try_begin") == 0 || strcmp(op, "try_end") == 0 || - strcmp(op, "catch_begin") == 0 || strcmp(op, "catch_end") == 0) { - /* TODO: exception handling */ - } /* ---- Unknown opcode ---- */ else { diff --git a/vm_test/syntax.txt b/vm_test/syntax.txt index 74bf51e1..3af3d06d 100644 --- a/vm_test/syntax.txt +++ b/vm_test/syntax.txt @@ -252,29 +252,21 @@ loop: for (var m = 0; m < 3; m++) { } } -// --- try/catch/finally --- -var tc -try { - throw "error" -} catch (e) { - tc = e +// --- disrupt and disruption --- +function disrupt_test() { + disrupt } -var tcf = 0 -try { - throw "err" -} catch (e) { - tcf = 1 -} finally { - tcf += 10 +function disruption_test() { + var x = 1 +} disruption { + var y = 2 } -// --- try/finally (no catch) --- -var tf = 0 -try { - tf = 1 -} finally { - tf += 1 +function disrupt_with_disruption() { + disrupt +} disruption { + var handled = true } // --- delete operator --- diff --git a/vm_test/try_catch.txt b/vm_test/try_catch.txt deleted file mode 100644 index 2058bf48..00000000 --- a/vm_test/try_catch.txt +++ /dev/null @@ -1 +0,0 @@ -try { 1 } catch(e) { 2 } diff --git a/vm_test/try_catch_finally.txt b/vm_test/try_catch_finally.txt deleted file mode 100644 index 87f944c7..00000000 --- a/vm_test/try_catch_finally.txt +++ /dev/null @@ -1 +0,0 @@ -var x = 1; try { throw 0 } catch(e) { x = 2 } finally { x = x + 1 }; x diff --git a/vm_test/try_finally.txt b/vm_test/try_finally.txt deleted file mode 100644 index 18e1abab..00000000 --- a/vm_test/try_finally.txt +++ /dev/null @@ -1 +0,0 @@ -var x = 1; try { x = 2 } finally { x = 3 }; x diff --git a/vm_test/try_throw.txt b/vm_test/try_throw.txt deleted file mode 100644 index e47f3d15..00000000 --- a/vm_test/try_throw.txt +++ /dev/null @@ -1 +0,0 @@ -try { throw "err" } catch(e) { e }