From e67dec7ef8269df2ad0b36f880b99ff8074f3437 Mon Sep 17 00:00:00 2001 From: theMackabu Date: Tue, 5 May 2026 12:29:42 -0700 Subject: [PATCH] misc annexb improvements --- examples/results.txt | 4 +-- src/silver/compiler.c | 66 +++++++++++++++++++++++++++++++++++++++++-- src/silver/lexer.c | 33 ++++++++++++++++++++++ 3 files changed, 98 insertions(+), 5 deletions(-) diff --git a/examples/results.txt b/examples/results.txt index 957b1bd..85954b3 100644 --- a/examples/results.txt +++ b/examples/results.txt @@ -719,10 +719,10 @@ compat-table/es6/annex-b.RegExp.prototype.compile.returns-this.js: OK compat-table/es6/annex-b.String.prototype.html.existence.js: OK compat-table/es6/annex-b.String.prototype.html.lowercase.js: OK compat-table/es6/annex-b.String.prototype.html.quotes-escaped.js: OK -compat-table/es6/annex-b.function.hoisted-block-level.js: ReferenceError: 'g' is not defined +compat-table/es6/annex-b.function.hoisted-block-level.js: OK compat-table/es6/annex-b.function.if-statement.js: OK compat-table/es6/annex-b.function.labeled.js: OK -compat-table/es6/annex-b.html-comments.js: SyntaxError: Unexpected token '>' +compat-table/es6/annex-b.html-comments.js: OK compat-table/es6/annex-b.regex.backreferences-octal.js: OK compat-table/es6/annex-b.regex.hyphens.js: OK compat-table/es6/annex-b.regex.incomplete-patterns.js: OK diff --git a/src/silver/compiler.c b/src/silver/compiler.c index af8a535..88fe854 100644 --- a/src/silver/compiler.c +++ b/src/silver/compiler.c @@ -591,6 +591,18 @@ static int resolve_local(sv_compiler_t *c, const char *name, uint32_t len) { return -1; } +static int resolve_local_at_depth(sv_compiler_t *c, const char *name, uint32_t len, int depth) { + for (int i = c->local_count - 1; i >= 0; i--) { + sv_local_t *loc = &c->locals[i]; + if ( + loc->depth == depth && + loc->name_len == len && + memcmp(loc->name, name, len) == 0 + ) return i; + } + return -1; +} + static int add_local( sv_compiler_t *c, const char *name, uint32_t len, bool is_const, int depth @@ -1337,6 +1349,42 @@ static void annex_b_collect_funcs(sv_ast_t *node, sv_ast_list_t *out) { } else if (node->type == N_LABEL) annex_b_collect_funcs(node->body, out); } +static void annex_b_collect_block_var_funcs(sv_ast_t *node, sv_ast_list_t *out) { + if (!node || node->type == N_FUNC || node->type == N_CLASS) return; + if (node->type == N_BLOCK) { + for (int i = 0; i < node->args.count; i++) { + sv_ast_t *stmt = node->args.items[i]; + if (!stmt) continue; + if (stmt->type == N_FUNC && stmt->str && !(stmt->flags & (FN_ARROW | FN_PAREN))) { + sv_ast_list_push(out, stmt); + continue; + } + annex_b_collect_block_var_funcs(stmt, out); + } + return; + } + if (node->type == N_IF) { + annex_b_collect_block_var_funcs(node->left, out); + annex_b_collect_block_var_funcs(node->right, out); + } else if (node->type == N_LABEL) { + annex_b_collect_block_var_funcs(node->body, out); + } else if (node->type == N_WHILE || node->type == N_DO_WHILE) { + annex_b_collect_block_var_funcs(node->body, out); + } else if (node->type == N_FOR || node->type == N_FOR_IN || node->type == N_FOR_OF || node->type == N_FOR_AWAIT_OF) { + annex_b_collect_block_var_funcs(node->body, out); + } else if (node->type == N_SWITCH) { + for (int i = 0; i < node->args.count; i++) { + sv_ast_t *cas = node->args.items[i]; + for (int j = 0; cas && j < cas->args.count; j++) + annex_b_collect_block_var_funcs(cas->args.items[j], out); + } + } else if (node->type == N_TRY) { + annex_b_collect_block_var_funcs(node->body, out); + annex_b_collect_block_var_funcs(node->catch_body, out); + annex_b_collect_block_var_funcs(node->finally_body, out); + } +} + static void hoist_lexical_decls(sv_compiler_t *c, sv_ast_list_t *stmts) { for (int i = 0; i < stmts->count; i++) { sv_ast_t *node = stmts->items[i]; @@ -1392,22 +1440,34 @@ static void hoist_lexical_decls(sv_compiler_t *c, sv_ast_list_t *stmts) { add_local(c, fn->str, fn->len, false, c->scope_depth); } } + if (!c->is_strict && decl_node->type == N_BLOCK) { + sv_ast_list_t funcs = {0}; + annex_b_collect_block_var_funcs(decl_node, &funcs); + for (int j = 0; j < funcs.count; j++) { + sv_ast_t *fn = funcs.items[j]; + if (resolve_local_at_depth(c, fn->str, fn->len, 0) == -1) + add_local(c, fn->str, fn->len, false, 0); + } + } } } -static void hoist_one_func(sv_compiler_t *c, sv_ast_t *node) { +static void hoist_one_func(sv_compiler_t *c, sv_ast_t *node, bool annex_b_update_var) { sv_func_t *fn = compile_function_body(c, node, c->mode); if (!fn) return; int idx = add_constant(c, mkval(T_NTARG, (uintptr_t)fn)); emit_op(c, OP_CLOSURE); emit_u32(c, (uint32_t)idx); emit_set_function_name(c, node->str, node->len); + int annex_var = annex_b_update_var ? resolve_local_at_depth(c, node->str, node->len, 0) : -1; + if (annex_var >= 0) emit_op(c, OP_DUP); if (is_repl_top_level(c)) { emit_atom_op(c, OP_PUT_GLOBAL, node->str, node->len); } else { int local = resolve_local(c, node->str, node->len); emit_put_local(c, local); } + if (annex_var >= 0) emit_put_local(c, annex_var); } static void hoist_func_decls(sv_compiler_t *c, sv_ast_list_t *stmts) { @@ -1417,13 +1477,13 @@ static void hoist_func_decls(sv_compiler_t *c, sv_ast_list_t *stmts) { node = node->left; if (!node) continue; if (node->type == N_FUNC && node->str && !(node->flags & (FN_ARROW | FN_PAREN))) { - hoist_one_func(c, node); + hoist_one_func(c, node, !c->is_strict && c->scope_depth > 0); } if (!c->is_strict && (node->type == N_IF || node->type == N_LABEL)) { sv_ast_list_t funcs = {0}; annex_b_collect_funcs(node, &funcs); for (int j = 0; j < funcs.count; j++) - hoist_one_func(c, funcs.items[j]); + hoist_one_func(c, funcs.items[j], false); } } } diff --git a/src/silver/lexer.c b/src/silver/lexer.c index 4ac3b3f..60f066f 100644 --- a/src/silver/lexer.c +++ b/src/silver/lexer.c @@ -133,6 +133,22 @@ static const uint8_t cc[128] = { 0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, }; +static inline bool html_close_comment_at_line_start(const char *code, const char *p) { + while (p > code) { + char c = p[-1]; + if (c == '\n' || c == '\r') return true; + if (c != ' ' && c != '\t' && c != '\f' && c != '\v') return false; + p--; + } + return true; +} + +static inline const char *skip_html_line_comment(const char *p, const char *end, bool *saw_nl) { + while (p < end && *p != '\n') p++; + if (p < end) { *saw_nl = true; p++; } + return p; +} + static ant_offset_t sv_skiptonext(const char *code, ant_offset_t len, ant_offset_t n, bool *nl) { static const void *D[] = { &&L0, &&LS, &&LN, &&LSL, &&LH }; bool saw_nl = false; @@ -196,6 +212,23 @@ LH: { } L0: + if (__builtin_expect(p + 3 < end && p[0] == '<' && p[1] == '!' && p[2] == '-' && p[3] == '-', 0)) { + p = skip_html_line_comment(p + 4, end, &saw_nl); + if (__builtin_expect(p >= end, 0)) goto L_done; + c = (unsigned char)*p; + goto *D[c & 0x80 ? C_HI : cc[c]]; + } + if (__builtin_expect( + p + 2 < end && p[0] == '-' && p[1] == '-' && p[2] == '>' && + html_close_comment_at_line_start(code, p), 0 + )) { + p = skip_html_line_comment(p + 3, end, &saw_nl); + if (__builtin_expect(p >= end, 0)) goto L_done; + c = (unsigned char)*p; + goto *D[c & 0x80 ? C_HI : cc[c]]; + } + +L_done: if (nl) *nl = saw_nl; return (ant_offset_t)(p - code); } -- 2.51.2