From 0503acb7e6029cb3e92bd034143821df73e4589f Mon Sep 17 00:00:00 2001 From: John Alanbrook Date: Mon, 9 Feb 2026 10:11:22 -0600 Subject: [PATCH] rm block scope --- source/mach.c | 52 +-------------- source/mcode.c | 36 ++++------ source/parse.c | 109 +++++++----------------------- source/quickjs-internal.h | 1 - syntax_suite.ce | 40 ++++------- vm_suite.ce | 137 ++++++++++++-------------------------- 6 files changed, 91 insertions(+), 284 deletions(-) diff --git a/source/mach.c b/source/mach.c index 8845d4b2..52e2cf26 100644 --- a/source/mach.c +++ b/source/mach.c @@ -93,9 +93,6 @@ typedef struct MachCompState { int loop_break; /* instruction index to patch, or -1 */ int loop_continue; /* instruction index to patch, or -1 */ - /* Scope depth for block scoping */ - int scope_depth; - /* Parent for nested function compilation */ struct MachCompState *parent; @@ -241,7 +238,6 @@ static void mach_add_var(MachCompState *cs, const char *name, int slot, int is_c v->slot = slot; v->is_const = is_const; v->is_closure = 0; - v->scope_depth = cs->scope_depth; } /* Find a variable in the current scope */ @@ -1353,17 +1349,7 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) { cJSON *right = cJSON_GetObjectItemCaseSensitive(stmt, "right"); const char *name = cJSON_GetStringValue(cJSON_GetObjectItemCaseSensitive(left, "name")); if (!name) return; - /* Check if var exists at current scope depth — if so, reuse it. - If it exists at a shallower depth, shadow it with a new slot. */ - int slot = -1; - for (int i = cs->var_count - 1; i >= 0; i--) { - if (strcmp(cs->vars[i].name, name) == 0) { - if (cs->vars[i].scope_depth == cs->scope_depth) { - slot = cs->vars[i].slot; /* same scope — reuse */ - } - break; - } - } + int slot = mach_find_var(cs, name); if (slot < 0) { slot = mach_reserve_reg(cs); mach_add_var(cs, name, slot, strcmp(kind, "def") == 0); @@ -1438,8 +1424,6 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) { /* Block */ if (strcmp(kind, "block") == 0) { - int saved_var_count = cs->var_count; - cs->scope_depth++; cJSON *stmts = cJSON_GetObjectItemCaseSensitive(stmt, "statements"); if (stmts && cJSON_IsArray(stmts)) { int count = cJSON_GetArraySize(stmts); @@ -1447,10 +1431,6 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) { mach_compile_stmt(cs, cJSON_GetArrayItem(stmts, i)); } } - cs->scope_depth--; - for (int i = saved_var_count; i < cs->var_count; i++) - sys_free(cs->vars[i].name); - cs->var_count = saved_var_count; return; } @@ -1470,8 +1450,6 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) { /* Compile then branch — "then" is a direct array of statements */ if (then_body) { - int saved_vc = cs->var_count; - cs->scope_depth++; if (cJSON_IsArray(then_body)) { int count = cJSON_GetArraySize(then_body); for (int i = 0; i < count; i++) @@ -1486,10 +1464,6 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) { mach_compile_stmt(cs, then_body); } } - cs->scope_depth--; - for (int i = saved_vc; i < cs->var_count; i++) - sys_free(cs->vars[i].name); - cs->var_count = saved_vc; } /* Check for else-if chain ("list") or plain else */ @@ -1508,8 +1482,6 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) { cs->code[jmpfalse_pc] = MACH_AsBx(MACH_JMPFALSE, cr, (int16_t)offset); /* Compile else — could be a direct array, object, or else-if stmt */ - int saved_vc = cs->var_count; - cs->scope_depth++; if (cJSON_IsArray(else_body)) { int count = cJSON_GetArraySize(else_body); for (int i = 0; i < count; i++) @@ -1524,10 +1496,6 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) { mach_compile_stmt(cs, else_body); } } - cs->scope_depth--; - for (int i = saved_vc; i < cs->var_count; i++) - sys_free(cs->vars[i].name); - cs->var_count = saved_vc; /* Patch jmpend */ offset = mach_current_pc(cs) - (jmpend_pc + 1); @@ -1560,8 +1528,6 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) { /* Compile body — "statements" on a child "block"/"body", or directly on the node */ { - int saved_vc = cs->var_count; - cs->scope_depth++; cJSON *body = cJSON_GetObjectItemCaseSensitive(stmt, "block"); if (!body) body = cJSON_GetObjectItemCaseSensitive(stmt, "body"); cJSON *stmts = body ? cJSON_GetObjectItemCaseSensitive(body, "statements") : NULL; @@ -1573,10 +1539,6 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) { } else if (body) { mach_compile_stmt(cs, body); } - cs->scope_depth--; - for (int i = saved_vc; i < cs->var_count; i++) - sys_free(cs->vars[i].name); - cs->var_count = saved_vc; } /* Patch continue chain to loop_top */ @@ -1613,8 +1575,6 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) { /* For loop */ if (strcmp(kind, "for") == 0) { - int saved_vc = cs->var_count; - cs->scope_depth++; cJSON *init = cJSON_GetObjectItemCaseSensitive(stmt, "init"); cJSON *cond = cJSON_GetObjectItemCaseSensitive(stmt, "test"); cJSON *update = cJSON_GetObjectItemCaseSensitive(stmt, "update"); @@ -1643,8 +1603,6 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) { /* Body — "statements" on a child "block"/"body", or directly on the for node */ { - int body_vc = cs->var_count; - cs->scope_depth++; cJSON *stmts = body ? cJSON_GetObjectItemCaseSensitive(body, "statements") : NULL; if (!stmts) stmts = cJSON_GetObjectItemCaseSensitive(stmt, "statements"); if (stmts && cJSON_IsArray(stmts)) { @@ -1654,10 +1612,6 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) { } else if (body) { mach_compile_stmt(cs, body); } - cs->scope_depth--; - for (int i = body_vc; i < cs->var_count; i++) - sys_free(cs->vars[i].name); - cs->var_count = body_vc; } /* Patch continue chain to update (or loop_top if no update) */ @@ -1699,10 +1653,6 @@ static void mach_compile_stmt(MachCompState *cs, cJSON *stmt) { } cs->loop_break = old_break; cs->loop_continue = old_continue; - cs->scope_depth--; - for (int i = saved_vc; i < cs->var_count; i++) - sys_free(cs->vars[i].name); - cs->var_count = saved_vc; return; } diff --git a/source/mcode.c b/source/mcode.c index ab82a984..ea957d3d 100644 --- a/source/mcode.c +++ b/source/mcode.c @@ -500,13 +500,11 @@ static int mach_gen_compound_assign (MachGenState *s, cJSON *node, const char *o if (strcmp (left_kind, "name") == 0) { const char *name = cJSON_GetStringValue (cJSON_GetObjectItemCaseSensitive (left, "name")); - const char *sn = cJSON_GetStringValue (cJSON_GetObjectItemCaseSensitive (left, "scope_name")); - const char *ln = sn ? sn : name; cJSON *level_node = cJSON_GetObjectItemCaseSensitive (left, "level"); int level = level_node ? (int)cJSON_GetNumberValue (level_node) : -1; int left_slot = mach_gen_alloc_slot (s); if (level == 0 || level == -1) { - int local = mach_gen_find_var (s, ln); + int local = mach_gen_find_var (s, name); if (local >= 0) { mach_gen_emit_2 (s, "move", left_slot, local); level = 0; /* treat as local for the store below */ @@ -515,7 +513,7 @@ static int mach_gen_compound_assign (MachGenState *s, cJSON *node, const char *o if (level > 0) { MachGenState *target = s; for (int i = 0; i < level; i++) target = target->parent; - int slot = mach_gen_find_var (target, ln); + int slot = mach_gen_find_var (target, name); mach_gen_emit_3 (s, "get", left_slot, slot, level); } else if (level == -1) { cJSON *instr = cJSON_CreateArray (); @@ -532,12 +530,12 @@ static int mach_gen_compound_assign (MachGenState *s, cJSON *node, const char *o int dest = mach_gen_alloc_slot (s); mach_gen_emit_3 (s, op, dest, left_slot, right_slot); if (level == 0) { - int local = mach_gen_find_var (s, ln); + int local = mach_gen_find_var (s, name); if (local >= 0) mach_gen_emit_2 (s, "move", local, dest); } else if (level > 0) { MachGenState *target = s; for (int i = 0; i < level; i++) target = target->parent; - int slot = mach_gen_find_var (target, ln); + int slot = mach_gen_find_var (target, name); mach_gen_emit_3 (s, "put", dest, slot, level); } else { cJSON *instr = cJSON_CreateArray (); @@ -606,12 +604,10 @@ static int mach_gen_assign (MachGenState *s, cJSON *node) { if (strcmp (left_kind, "name") == 0) { const char *name = cJSON_GetStringValue (cJSON_GetObjectItemCaseSensitive (left, "name")); - const char *sn = cJSON_GetStringValue (cJSON_GetObjectItemCaseSensitive (left, "scope_name")); - const char *ln = sn ? sn : name; cJSON *level_node = cJSON_GetObjectItemCaseSensitive (left, "level"); int level = level_node ? (int)cJSON_GetNumberValue (level_node) : -1; if (level == 0 || level == -1) { - int slot = mach_gen_find_var (s, ln); + int slot = mach_gen_find_var (s, name); if (slot >= 0) mach_gen_emit_2 (s, "move", slot, val_slot); else if (level == -1) { /* No annotation and not local — set global */ @@ -624,7 +620,7 @@ static int mach_gen_assign (MachGenState *s, cJSON *node) { } else if (level > 0) { MachGenState *target = s; for (int i = 0; i < level; i++) target = target->parent; - int slot = mach_gen_find_var (target, ln); + int slot = mach_gen_find_var (target, name); mach_gen_emit_3 (s, "put", val_slot, slot, level); } else { mach_gen_error (s, node, "cannot assign to unbound variable '%s'", name); @@ -755,18 +751,16 @@ static int mach_gen_expr (MachGenState *s, cJSON *expr, int target) { /* Variable reference — uses parser-provided level annotation */ if (strcmp (kind, "name") == 0) { const char *name = cJSON_GetStringValue (cJSON_GetObjectItemCaseSensitive (expr, "name")); - const char *scope_name = cJSON_GetStringValue (cJSON_GetObjectItemCaseSensitive (expr, "scope_name")); - const char *lookup_name = scope_name ? scope_name : name; cJSON *level_node = cJSON_GetObjectItemCaseSensitive (expr, "level"); int level = level_node ? (int)cJSON_GetNumberValue (level_node) : -1; if (level == 0 || level == -1) { /* level 0 = known local; level -1 = no annotation, try local first */ - int slot = mach_gen_find_var (s, lookup_name); + int slot = mach_gen_find_var (s, name); if (slot >= 0) return slot; } else if (level > 0) { MachGenState *target = s; for (int i = 0; i < level; i++) target = target->parent; - int parent_slot = mach_gen_find_var (target, lookup_name); + int parent_slot = mach_gen_find_var (target, name); int dest = mach_gen_alloc_slot (s); mach_gen_emit_3 (s, "get", dest, parent_slot, level); return dest; @@ -934,19 +928,17 @@ static int mach_gen_expr (MachGenState *s, cJSON *expr, int target) { if (strcmp (operand_kind, "name") == 0) { const char *name = cJSON_GetStringValue (cJSON_GetObjectItemCaseSensitive (operand, "name")); - const char *inc_sn = cJSON_GetStringValue (cJSON_GetObjectItemCaseSensitive (operand, "scope_name")); - const char *inc_ln = inc_sn ? inc_sn : name; cJSON *level_node = cJSON_GetObjectItemCaseSensitive (operand, "level"); int level = level_node ? (int)cJSON_GetNumberValue (level_node) : -1; int old_slot = mach_gen_alloc_slot (s); /* Load current value */ if (level == 0) { - int local = mach_gen_find_var (s, inc_ln); + int local = mach_gen_find_var (s, name); if (local >= 0) mach_gen_emit_2 (s, "move", old_slot, local); } else if (level > 0) { MachGenState *target = s; for (int i = 0; i < level; i++) target = target->parent; - int slot = mach_gen_find_var (target, inc_ln); + int slot = mach_gen_find_var (target, name); mach_gen_emit_3 (s, "get", old_slot, slot, level); } else { cJSON *instr = cJSON_CreateArray (); @@ -963,12 +955,12 @@ static int mach_gen_expr (MachGenState *s, cJSON *expr, int target) { mach_gen_emit_3 (s, arith_op, new_slot, old_slot, one_slot); /* Store new value */ if (level == 0) { - int local = mach_gen_find_var (s, inc_ln); + int local = mach_gen_find_var (s, name); if (local >= 0) mach_gen_emit_2 (s, "move", local, new_slot); } else if (level > 0) { MachGenState *target = s; for (int i = 0; i < level; i++) target = target->parent; - int slot = mach_gen_find_var (target, inc_ln); + int slot = mach_gen_find_var (target, name); mach_gen_emit_3 (s, "put", new_slot, slot, level); } return postfix ? old_slot : new_slot; @@ -1135,9 +1127,7 @@ static void mach_gen_statement (MachGenState *s, cJSON *stmt) { cJSON *left = cJSON_GetObjectItemCaseSensitive (stmt, "left"); cJSON *right = cJSON_GetObjectItemCaseSensitive (stmt, "right"); const char *name = cJSON_GetStringValue (cJSON_GetObjectItemCaseSensitive (left, "name")); - const char *scope_name = cJSON_GetStringValue (cJSON_GetObjectItemCaseSensitive (left, "scope_name")); - const char *lookup_name = scope_name ? scope_name : name; - int local_slot = mach_gen_find_var (s, lookup_name); + int local_slot = mach_gen_find_var (s, name); /* Pop: var val = arr[] */ cJSON *pop_flag = cJSON_GetObjectItemCaseSensitive (stmt, "pop"); if (pop_flag && cJSON_IsTrue (pop_flag) && right) { diff --git a/source/parse.c b/source/parse.c index ba48777b..e60c4ed6 100644 --- a/source/parse.c +++ b/source/parse.c @@ -966,7 +966,6 @@ cJSON *ast_parse_statement (ASTParseState *s) { case TOK_VAR: case TOK_DEF: { const char *kind_name = (s->token_val == TOK_VAR) ? "var" : "def"; - int is_def = (s->token_val == TOK_DEF); ast_next_token (s); /* Expect an identifier */ @@ -998,9 +997,9 @@ cJSON *ast_parse_statement (ASTParseState *s) { const char *right_kind = cJSON_GetStringValue (cJSON_GetObjectItemCaseSensitive (right, "kind")); if (right_kind && strcmp (right_kind, "[") == 0 && !cJSON_GetObjectItemCaseSensitive (right, "right")) cJSON_AddBoolToObject (node, "pop", 1); - } else if (is_def) { - /* def (constant) requires initializer */ - ast_error (s, var_ptr, "missing initializer for constant '%s'", var_name); + } else { + /* var and def both require initializer */ + ast_error (s, var_ptr, "missing initializer for '%s' '%s'", kind_name, var_name); } sys_free (var_name); ast_node_end (s, node, s->buf_ptr); @@ -1097,16 +1096,11 @@ cJSON *ast_parse_statement (ASTParseState *s) { if (s->token_val == '(') ast_next_token (s); else ast_error (s, s->token_ptr, "expected '(' after for"); - /* Init */ + /* Init — only expressions allowed (no var/def) */ if (s->token_val != ';') { - if (s->token_val == TOK_VAR || s->token_val == TOK_DEF) { - cJSON *init = ast_parse_statement (s); - cJSON_AddItemToObject (node, "init", init); - } else { - cJSON *init = ast_parse_expr (s); - cJSON_AddItemToObject (node, "init", init); - if (s->token_val == ';') ast_next_token (s); - } + cJSON *init = ast_parse_expr (s); + cJSON_AddItemToObject (node, "init", init); + if (s->token_val == ';') ast_next_token (s); } else { ast_next_token (s); } @@ -1271,7 +1265,6 @@ static cJSON *ast_parse_program (ASTParseState *s) { typedef struct ASTSemVar { const char *name; - const char *scope_name; /* disambiguated name for block-scope vars (NULL = use name) */ int is_const; const char *make; /* "def", "var", "function", "input" */ int function_nr; /* which function this var belongs to */ @@ -1286,7 +1279,6 @@ typedef struct ASTSemScope { int in_loop; int function_nr; /* function_nr of enclosing function */ int is_function_scope; /* 1 if this is a function's top-level scope */ - int block_depth; /* 0 = function scope, 1+ = block scope */ } ASTSemScope; typedef struct ASTSemState { @@ -1295,7 +1287,6 @@ typedef struct ASTSemState { cJSON *scopes_array; const char *intrinsics[256]; int intrinsic_count; - int block_var_counter; /* monotonically increasing counter for unique block var names */ } ASTSemState; static void ast_sem_error (ASTSemState *st, cJSON *node, const char *fmt, ...) { @@ -1324,7 +1315,6 @@ static void ast_sem_add_var (ASTSemScope *scope, const char *name, int is_const, if (scope->var_count < AST_SEM_MAX_VARS) { ASTSemVar *v = &scope->vars[scope->var_count]; v->name = name; - v->scope_name = NULL; v->is_const = is_const; v->make = make; v->function_nr = function_nr; @@ -1334,26 +1324,6 @@ static void ast_sem_add_var (ASTSemScope *scope, const char *name, int is_const, } } -/* Propagate block-scope vars to the function scope (parent) with disambiguated names */ -static void ast_sem_propagate_block_vars (ASTSemState *st, ASTSemScope *parent, - ASTSemScope *block) { - for (int i = 0; i < block->var_count; i++) { - ASTSemVar *v = &block->vars[i]; - const char *sn = v->scope_name ? v->scope_name : v->name; - if (parent->var_count < AST_SEM_MAX_VARS) { - ASTSemVar *pv = &parent->vars[parent->var_count]; - pv->name = sn; - pv->scope_name = NULL; - pv->is_const = v->is_const; - pv->make = v->make; - pv->function_nr = v->function_nr; - pv->nr_uses = v->nr_uses; - pv->closure = v->closure; - parent->var_count++; - } - } -} - typedef struct { ASTSemVar *var; int level; @@ -1486,8 +1456,6 @@ static void ast_sem_check_assign_target (ASTSemState *st, ASTSemScope *scope, cJ if (r.var) { cJSON_AddNumberToObject (left, "level", r.level); cJSON_AddNumberToObject (left, "function_nr", r.def_function_nr); - if (r.var->scope_name) - cJSON_AddStringToObject (left, "scope_name", r.var->scope_name); } else { cJSON_AddNumberToObject (left, "level", -1); } @@ -1540,13 +1508,11 @@ static void ast_sem_check_expr (ASTSemState *st, ASTSemScope *scope, cJSON *expr } else if (v->is_const) { ast_sem_error (st, expr, "cannot assign to constant '%s'", name); } - /* Annotate with level/function_nr/scope_name so compilers can emit correct set instructions */ + /* Annotate with level/function_nr so compilers can emit correct set instructions */ ASTSemLookup r = ast_sem_lookup_var (scope, name); if (r.var) { cJSON_AddNumberToObject (operand, "level", r.level); cJSON_AddNumberToObject (operand, "function_nr", r.def_function_nr); - if (r.var->scope_name) - cJSON_AddStringToObject (operand, "scope_name", r.var->scope_name); } else { cJSON_AddNumberToObject (operand, "level", -1); } @@ -1697,8 +1663,6 @@ static void ast_sem_check_expr (ASTSemState *st, ASTSemScope *scope, cJSON *expr cJSON_AddNumberToObject (expr, "function_nr", r.def_function_nr); r.var->nr_uses++; if (r.level > 0) r.var->closure = 1; - if (r.var->scope_name) - cJSON_AddStringToObject (expr, "scope_name", r.var->scope_name); } else { cJSON_AddNumberToObject (expr, "level", -1); ast_sem_add_intrinsic (st, name); @@ -1717,6 +1681,10 @@ static void ast_sem_check_stmt (ASTSemState *st, ASTSemScope *scope, cJSON *stmt if (!kind) return; if (strcmp (kind, "var_list") == 0) { + if (!scope->is_function_scope) { + ast_sem_error (st, stmt, "'var' declaration must be at function body level"); + return; + } cJSON *item; cJSON_ArrayForEach (item, cJSON_GetObjectItemCaseSensitive (stmt, "list")) { ast_sem_check_stmt (st, scope, item); @@ -1725,6 +1693,10 @@ static void ast_sem_check_stmt (ASTSemState *st, ASTSemScope *scope, cJSON *stmt } if (strcmp (kind, "var") == 0) { + if (!scope->is_function_scope) { + ast_sem_error (st, stmt, "'var' declaration must be at function body level"); + return; + } /* Register variable */ cJSON *left = cJSON_GetObjectItemCaseSensitive (stmt, "left"); const char *name = cJSON_GetStringValue (cJSON_GetObjectItemCaseSensitive (left, "name")); @@ -1733,23 +1705,18 @@ static void ast_sem_check_stmt (ASTSemState *st, ASTSemScope *scope, cJSON *stmt if (existing && existing->is_const) { ast_sem_error (st, left, "cannot redeclare constant '%s'", name); } - if (!existing || existing->function_nr != scope->function_nr - || scope->block_depth > 0) + if (!existing || existing->function_nr != scope->function_nr) ast_sem_add_var (scope, name, 0, "var", scope->function_nr); - if (scope->block_depth > 0) { - char buf[128]; - snprintf (buf, sizeof (buf), "_%s_%d", name, st->block_var_counter++); - char *sn = sys_malloc (strlen (buf) + 1); - strcpy (sn, buf); - scope->vars[scope->var_count - 1].scope_name = sn; - cJSON_AddStringToObject (left, "scope_name", sn); - } } ast_sem_check_expr (st, scope, cJSON_GetObjectItemCaseSensitive (stmt, "right")); return; } if (strcmp (kind, "def") == 0) { + if (!scope->is_function_scope) { + ast_sem_error (st, stmt, "'def' declaration must be at function body level"); + return; + } /* Register constant */ cJSON *left = cJSON_GetObjectItemCaseSensitive (stmt, "left"); const char *name = cJSON_GetStringValue (cJSON_GetObjectItemCaseSensitive (left, "name")); @@ -1763,14 +1730,6 @@ static void ast_sem_check_stmt (ASTSemState *st, ASTSemScope *scope, cJSON *stmt existing->make = "def"; } else { ast_sem_add_var (scope, name, 1, "def", scope->function_nr); - if (scope->block_depth > 0) { - char buf[128]; - snprintf (buf, sizeof (buf), "_%s_%d", name, st->block_var_counter++); - char *sn = sys_malloc (strlen (buf) + 1); - strcpy (sn, buf); - scope->vars[scope->var_count - 1].scope_name = sn; - cJSON_AddStringToObject (left, "scope_name", sn); - } } } ast_sem_check_expr (st, scope, cJSON_GetObjectItemCaseSensitive (stmt, "right")); @@ -1789,31 +1748,25 @@ static void ast_sem_check_stmt (ASTSemState *st, ASTSemScope *scope, cJSON *stmt ASTSemScope then_scope = {0}; then_scope.parent = scope; then_scope.function_nr = scope->function_nr; - then_scope.block_depth = scope->block_depth + 1; cJSON_ArrayForEach (s2, cJSON_GetObjectItemCaseSensitive (stmt, "then")) { ast_sem_check_stmt (st, &then_scope, s2); } - ast_sem_propagate_block_vars (st, scope, &then_scope); } { ASTSemScope list_scope = {0}; list_scope.parent = scope; list_scope.function_nr = scope->function_nr; - list_scope.block_depth = scope->block_depth + 1; cJSON_ArrayForEach (s2, cJSON_GetObjectItemCaseSensitive (stmt, "list")) { ast_sem_check_stmt (st, &list_scope, s2); } - ast_sem_propagate_block_vars (st, scope, &list_scope); } { ASTSemScope else_scope = {0}; else_scope.parent = scope; else_scope.function_nr = scope->function_nr; - else_scope.block_depth = scope->block_depth + 1; cJSON_ArrayForEach (s2, cJSON_GetObjectItemCaseSensitive (stmt, "else")) { ast_sem_check_stmt (st, &else_scope, s2); } - ast_sem_propagate_block_vars (st, scope, &else_scope); } return; } @@ -1824,12 +1777,10 @@ static void ast_sem_check_stmt (ASTSemState *st, ASTSemScope *scope, cJSON *stmt loop_scope.parent = scope; loop_scope.in_loop = 1; loop_scope.function_nr = scope->function_nr; - loop_scope.block_depth = scope->block_depth + 1; cJSON *s2; cJSON_ArrayForEach (s2, cJSON_GetObjectItemCaseSensitive (stmt, "statements")) { ast_sem_check_stmt (st, &loop_scope, s2); } - ast_sem_propagate_block_vars (st, scope, &loop_scope); return; } @@ -1838,12 +1789,10 @@ static void ast_sem_check_stmt (ASTSemState *st, ASTSemScope *scope, cJSON *stmt loop_scope.parent = scope; loop_scope.in_loop = 1; loop_scope.function_nr = scope->function_nr; - loop_scope.block_depth = scope->block_depth + 1; cJSON *s2; cJSON_ArrayForEach (s2, cJSON_GetObjectItemCaseSensitive (stmt, "statements")) { ast_sem_check_stmt (st, &loop_scope, s2); } - ast_sem_propagate_block_vars (st, scope, &loop_scope); ast_sem_check_expr (st, scope, cJSON_GetObjectItemCaseSensitive (stmt, "expression")); return; } @@ -1853,24 +1802,16 @@ static void ast_sem_check_stmt (ASTSemState *st, ASTSemScope *scope, cJSON *stmt loop_scope.parent = scope; loop_scope.in_loop = 1; loop_scope.function_nr = scope->function_nr; - loop_scope.block_depth = scope->block_depth + 1; - /* init may be a var/def statement or expression */ + /* init is expression only (no var/def in for init) */ cJSON *init = cJSON_GetObjectItemCaseSensitive (stmt, "init"); - if (init) { - const char *init_kind = cJSON_GetStringValue (cJSON_GetObjectItemCaseSensitive (init, "kind")); - if (init_kind && (strcmp (init_kind, "var") == 0 || strcmp (init_kind, "def") == 0)) { - ast_sem_check_stmt (st, &loop_scope, init); - } else { - ast_sem_check_expr (st, &loop_scope, init); - } - } + if (init) + ast_sem_check_expr (st, &loop_scope, init); ast_sem_check_expr (st, &loop_scope, cJSON_GetObjectItemCaseSensitive (stmt, "test")); ast_sem_check_expr (st, &loop_scope, cJSON_GetObjectItemCaseSensitive (stmt, "update")); cJSON *s2; cJSON_ArrayForEach (s2, cJSON_GetObjectItemCaseSensitive (stmt, "statements")) { ast_sem_check_stmt (st, &loop_scope, s2); } - ast_sem_propagate_block_vars (st, scope, &loop_scope); return; } @@ -1901,12 +1842,10 @@ static void ast_sem_check_stmt (ASTSemState *st, ASTSemScope *scope, cJSON *stmt ASTSemScope block_scope = {0}; block_scope.parent = scope; block_scope.function_nr = scope->function_nr; - block_scope.block_depth = scope->block_depth + 1; cJSON *s2; cJSON_ArrayForEach (s2, cJSON_GetObjectItemCaseSensitive (stmt, "statements")) { ast_sem_check_stmt (st, &block_scope, s2); } - ast_sem_propagate_block_vars (st, scope, &block_scope); return; } diff --git a/source/quickjs-internal.h b/source/quickjs-internal.h index b17464cc..9036b1e1 100644 --- a/source/quickjs-internal.h +++ b/source/quickjs-internal.h @@ -1738,7 +1738,6 @@ typedef struct MachVarInfo { int slot; int is_const; /* 1 for def, function args; 0 for var */ int is_closure; /* 1 if captured by a nested function */ - int scope_depth; /* block scope nesting level */ } MachVarInfo; /* === PPretext (parser pretext, system-malloc, used by cell_js.c parser) === */ diff --git a/syntax_suite.ce b/syntax_suite.ce index 2eefab84..51a36662 100644 --- a/syntax_suite.ce +++ b/syntax_suite.ce @@ -7,7 +7,8 @@ var error_names = [] var error_reasons = [] var fail_msg = "" -for (var _i = 0; _i < 100; _i++) { +var _i = 0 +for (_i = 0; _i < 100; _i++) { error_names[] = null error_reasons[] = null } @@ -105,11 +106,6 @@ run("var declaration", function() { assert_eq(x, 5, "var init") }) -run("var uninitialized", function() { - var x - assert_eq(x, null, "var defaults to null") -}) - run("var multiple declaration", function() { var a = 1, b = 2, c = 3 assert_eq(a + b + c, 6, "multi var") @@ -330,19 +326,21 @@ run("while break continue", function() { run("for loop", function() { var sum = 0 - for (var i = 0; i < 5; i++) sum += i + var i = 0 + for (i = 0; i < 5; i++) sum += i assert_eq(sum, 10, "for basic") }) run("for break continue", function() { var sum = 0 - for (var i = 0; i < 10; i++) { + var i = 0 + for (i = 0; i < 10; i++) { if (i == 5) break sum += i } assert_eq(sum, 10, "for break") sum = 0 - for (var i = 0; i < 5; i++) { + for (i = 0; i < 5; i++) { if (i % 2 == 0) continue sum += i } @@ -351,28 +349,13 @@ run("for break continue", function() { run("nested for", function() { var sum = 0 - for (var i = 0; i < 3; i++) - for (var j = 0; j < 3; j++) + var i = 0, j = 0 + for (i = 0; i < 3; i++) + for (j = 0; j < 3; j++) sum++ assert_eq(sum, 9, "nested for") }) -// === BLOCK SCOPING === - -run("block scoping", function() { - var x = 1 - { - var x = 2 - assert_eq(x, 2, "inner block") - } - assert_eq(x, 1, "outer preserved") -}) - -run("for iterator scope", function() { - for (var i = 0; i < 1; i++) {} - assert_eq(should_disrupt(function() { var y = i }), true, "for var does not leak") -}) - // === FUNCTIONS === run("function expression", function() { @@ -649,9 +632,10 @@ run("inequality not confused with bang ident", function() { // === SUMMARY === print(text(passed) + " passed, " + text(failed) + " failed out of " + text(passed + failed)) +var _j = 0 if (failed > 0) { print("") - for (var _j = 0; _j < failed; _j++) { + for (_j = 0; _j < failed; _j++) { print(" FAIL " + error_names[_j] + ": " + error_reasons[_j]) } } diff --git a/vm_suite.ce b/vm_suite.ce index 3becf158..5f362ff3 100644 --- a/vm_suite.ce +++ b/vm_suite.ce @@ -9,7 +9,8 @@ var error_reasons = [] var fail_msg = "" // pre-allocate 500 slots to avoid array growth during disruption handlers -for (var _i = 0; _i < 5; _i++) { +var _i = 0 +for (_i = 0; _i < 5; _i++) { error_names[] = null error_reasons[] = null } @@ -295,79 +296,9 @@ run("var reassignment", function() { if (x != 10) fail("var reassignment failed") }) -run("var block scope basic", function() { - var x = 1 - { - var x = 2 - if (x != 2) fail("var should be block scoped - inner scope failed") - } - if (x != 1) fail("var should be block scoped - outer scope affected") -}) - -run("var block scope if", function() { - var x = 1 - if (true) { - var x = 2 - if (x != 2) fail("var in if block should be scoped") - } - if (x != 1) fail("var in if block should not affect outer scope") -}) - -run("var block scope for", function() { - var x = 1 - for (var i = 0; i < 1; i = i + 1) { - var x = 2 - if (x != 2) fail("var in for block should be scoped") - } - if (x != 1) fail("var in for block should not affect outer scope") -}) - -run("var for loop iterator scope", function() { - var sum = 0 - for (var i = 0; i < 3; i = i + 1) { - sum = sum + i - } - if (sum != 3) fail("for loop should work with block scoped var") - if (!should_disrupt(function() { var y = i })) fail("for loop iterator should not leak to outer scope") -}) - -run("var nested blocks", function() { - var x = 1 - { - var x = 2 - { - var x = 3 - if (x != 3) fail("var in nested block level 2 failed") - } - if (x != 2) fail("var in nested block level 1 failed") - } - if (x != 1) fail("var in nested blocks outer scope failed") -}) - -run("var redeclaration different scope", function() { - var x = 1 - { - var x = 2 - } - if (x != 1) fail("var in different scope should not affect outer") -}) - -run("var while scope", function() { - var x = 1 - var count = 0 - while (count < 1) { - var x = 2 - if (x != 2) fail("var in while should be block scoped") - count = count + 1 - } - if (x != 1) fail("var in while should not affect outer scope") -}) - -run("var no initialization", function() { - { - var x - if (x != null) fail("uninitialized var should be null") - } +run("var null initialization", function() { + var x = null + if (x != null) fail("null-initialized var should be null") }) run("multiple var declaration", function() { @@ -717,7 +648,8 @@ run("while continue", function() { run("for loop", function() { var sum = 0 - for (var i = 0; i < 5; i = i + 1) { + var i = 0 + for (i = 0; i < 5; i = i + 1) { sum = sum + i } if (sum != 10) fail("for loop failed") @@ -725,7 +657,8 @@ run("for loop", function() { run("for loop break", function() { var sum = 0 - for (var i = 0; i < 10; i = i + 1) { + var i = 0 + for (i = 0; i < 10; i = i + 1) { if (i == 5) break sum = sum + i } @@ -734,7 +667,8 @@ run("for loop break", function() { run("for loop continue", function() { var sum = 0 - for (var i = 0; i < 10; i = i + 1) { + var i = 0 + for (i = 0; i < 10; i = i + 1) { if (i % 2 == 0) continue sum = sum + i } @@ -743,8 +677,9 @@ run("for loop continue", function() { run("nested for loops", function() { var sum = 0 - for (var i = 0; i < 3; i = i + 1) { - for (var j = 0; j < 3; j = j + 1) { + var i = 0, j = 0 + for (i = 0; i < 3; i = i + 1) { + for (j = 0; j < 3; j = j + 1) { sum = sum + 1 } } @@ -877,7 +812,7 @@ run("is_null", function() { if (is_null("")) fail("is_null empty string should be false") if (is_null({})) fail("is_null object should be false") if (is_null([])) fail("is_null array should be false") - var x + var x = null if (!is_null(x)) fail("is_null undefined variable should be true") }) @@ -1265,9 +1200,9 @@ run("function length property", function() { // NULL AND UNDEFINED BEHAVIOR // ============================================================================ -run("undefined variable is null", function() { - var x - if (x != null) fail("undefined variable should be null") +run("null initialized variable is null", function() { + var x = null + if (x != null) fail("null initialized variable should be null") }) // ============================================================================ @@ -1716,7 +1651,8 @@ run("function proxy with one arg", function() { run("function proxy with multiple args", function() { var proxy = function(name, args) { var sum = 0 - for (var i = 0; i < length(args); i++) { + var i = 0 + for (i = 0; i < length(args); i++) { sum = sum + args[i] } return `${name}:${sum}` @@ -3183,7 +3119,8 @@ run("gc cycle object self", function() { run("gc cycle array self", function() { var arr = [] - for (var i = 0; i < 10; i++) { + var i = 0 + for (i = 0; i < 10; i++) { arr[] = arr } if (arr[0] != arr) fail("array self cycle failed") @@ -3336,22 +3273,26 @@ run("fn.apply with single value", function() { run("gc reverse under pressure", function() { var arrays = [] - for (var i = 0; i < 100; i = i + 1) { + var i = 0 + var rev = null + for (i = 0; i < 100; i = i + 1) { arrays[i] = [i, i+1, i+2, i+3, i+4] } - for (var i = 0; i < 100; i = i + 1) { - var rev = reverse(arrays[i]) + for (i = 0; i < 100; i = i + 1) { + rev = reverse(arrays[i]) if (rev[0] != i+4) fail("gc reverse stress failed") } }) run("gc object select under pressure", function() { var objs = [] - for (var i = 0; i < 100; i = i + 1) { + var i = 0 + var selected = null + for (i = 0; i < 100; i = i + 1) { objs[i] = {a: i, b: i+1, c: i+2, d: i+3} } - for (var i = 0; i < 100; i = i + 1) { - var selected = object(objs[i], ["a", "c"]) + for (i = 0; i < 100; i = i + 1) { + selected = object(objs[i], ["a", "c"]) if (selected.a != i) fail("gc object select stress failed") if (selected.c != i+2) fail("gc object select stress c failed") } @@ -3359,12 +3300,15 @@ run("gc object select under pressure", function() { run("gc object from keys function under pressure", function() { var keysets = [] - for (var i = 0; i < 50; i = i + 1) { + var i = 0 + var obj = null + var expected = null + for (i = 0; i < 50; i = i + 1) { keysets[i] = [`k${i}`, `j${i}`, `m${i}`] } - for (var i = 0; i < 50; i = i + 1) { - var obj = object(keysets[i], function(k) { return k + "_value" }) - var expected = `k${i}_value` + for (i = 0; i < 50; i = i + 1) { + obj = object(keysets[i], function(k) { return k + "_value" }) + expected = `k${i}_value` if (obj[`k${i}`] != expected) fail("gc object from keys func stress failed") } }) @@ -3550,9 +3494,10 @@ run("functino >>>! unsigned shift right", function() { // ============================================================================ print(text(passed) + " passed, " + text(failed) + " failed out of " + text(passed + failed)) +var _j = 0 if (failed > 0) { print("") - for (var _j = 0; _j < failed; _j++) { + for (_j = 0; _j < failed; _j++) { print(" FAIL " + error_names[_j] + ": " + error_reasons[_j]) } }