disrupt/disruption; remove try/catch

This commit is contained in:
2026-02-06 18:40:56 -06:00
parent 8cf98d8a9e
commit e985fa5fe1
6 changed files with 94 additions and 319 deletions

View File

@@ -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 {

View File

@@ -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 ---

View File

@@ -1 +0,0 @@
try { 1 } catch(e) { 2 }

View File

@@ -1 +0,0 @@
var x = 1; try { throw 0 } catch(e) { x = 2 } finally { x = x + 1 }; x

View File

@@ -1 +0,0 @@
var x = 1; try { x = 2 } finally { x = 3 }; x

View File

@@ -1 +0,0 @@
try { throw "err" } catch(e) { e }