]> git.kaiwu.me - njs.git/commitdiff
Parser: store statement labels as atom identifiers
authorDmitry Volyntsev <xeioex@nginx.com>
Thu, 3 Sep 2026 00:39:41 +0000 (17:39 -0700)
committerDmitry Volyntsev <xeioexception@gmail.com>
Thu, 10 Sep 2026 03:11:04 +0000 (20:11 -0700)
src/njs_generator.c
src/njs_parser.c
src/njs_parser.h
src/test/njs_unit_test.c

index dd6b7111ead37c75178bd19e247f38aa824ddd81..09cc657d6977652f790fdbba68a2708675399cbf 100644 (file)
@@ -643,6 +643,20 @@ static const njs_str_t  return_label = njs_str("@return");
 static const njs_str_t  undef_label  = { 0xffffffff, (u_char *) "" };
 
 
+njs_inline const njs_str_t *
+njs_generate_node_label(njs_vm_t *vm, njs_parser_node_t *node,
+    njs_str_t *label)
+{
+    if (node->u.label == NJS_ATOM_STRING_unknown) {
+        return &no_label;
+    }
+
+    njs_atom_string_get(vm, node->u.label, label);
+
+    return label;
+}
+
+
 njs_int_t
 njs_generator_init(njs_generator_t *generator, njs_str_t *file,
     njs_int_t depth, njs_bool_t runtime)
@@ -1297,9 +1311,10 @@ njs_generate_if_statement(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
     njs_int_t  ret;
+    njs_str_t  label;
 
     ret = njs_generate_start_block(vm, generator, NJS_GENERATOR_BLOCK,
-                                    &node->name);
+                         njs_generate_node_label(vm, node, &label));
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
@@ -1545,6 +1560,7 @@ njs_generate_switch_expression(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *swtch)
 {
     njs_int_t                   ret;
+    njs_str_t                   label;
     njs_parser_node_t           *expr;
     njs_vmcode_move_t           *move;
     njs_generator_switch_ctx_t  *ctx;
@@ -1564,7 +1580,7 @@ njs_generate_switch_expression(njs_vm_t *vm, njs_generator_t *generator,
     }
 
     ret = njs_generate_start_block(vm, generator, NJS_GENERATOR_SWITCH,
-                                   &swtch->name);
+                         njs_generate_node_label(vm, swtch, &label));
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
@@ -1769,6 +1785,7 @@ njs_generate_while_statement(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
     njs_int_t                 ret;
+    njs_str_t                 label;
     njs_vmcode_jump_t         *jump;
     njs_generator_loop_ctx_t  ctx;
 
@@ -1782,7 +1799,7 @@ njs_generate_while_statement(njs_vm_t *vm, njs_generator_t *generator,
     ctx.jump_offset = njs_code_offset(generator, jump);
 
     ret = njs_generate_start_block(vm, generator, NJS_GENERATOR_LOOP,
-                                   &node->name);
+                         njs_generate_node_label(vm, node, &label));
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
@@ -1851,10 +1868,11 @@ njs_generate_do_while_statement(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
     njs_int_t                 ret;
+    njs_str_t                 label;
     njs_generator_loop_ctx_t  ctx;
 
     ret = njs_generate_start_block(vm, generator, NJS_GENERATOR_LOOP,
-                                   &node->name);
+                         njs_generate_node_label(vm, node, &label));
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
@@ -1918,10 +1936,11 @@ njs_generate_for_statement(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
     njs_int_t                 ret;
+    njs_str_t                 label;
     njs_generator_loop_ctx_t  ctx;
 
     ret = njs_generate_start_block(vm, generator, NJS_GENERATOR_LOOP,
-                                   &node->name);
+                         njs_generate_node_label(vm, node, &label));
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
@@ -2291,11 +2310,12 @@ njs_generate_for_in_statement(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
     njs_int_t                 ret;
+    njs_str_t                 label;
     njs_parser_node_t         *foreach, *name;
     njs_generator_loop_ctx_t  ctx;
 
     ret = njs_generate_start_block(vm, generator, NJS_GENERATOR_LOOP,
-                                   &node->name);
+                         njs_generate_node_label(vm, node, &label));
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
@@ -2851,12 +2871,13 @@ static njs_int_t
 njs_generate_continue_statement(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
+    njs_str_t              name;
     const njs_str_t        *label, *dest;
     njs_vmcode_jump_t      *jump;
     njs_generator_patch_t  *patch;
     njs_generator_block_t  *block;
 
-    label = &node->name;
+    label = njs_generate_node_label(vm, node, &name);
 
     block = njs_generate_find_block(vm, generator->block, NJS_GENERATOR_LOOP,
                                     label);
@@ -2900,12 +2921,13 @@ static njs_int_t
 njs_generate_break_statement(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
+    njs_str_t              name;
     const njs_str_t        *label, *dest;
     njs_vmcode_jump_t      *jump;
     njs_generator_patch_t  *patch;
     njs_generator_block_t  *block;
 
-    label = &node->name;
+    label = njs_generate_node_label(vm, node, &name);
 
     block = njs_generate_find_block(vm, generator->block, NJS_GENERATOR_ALL,
                                     label);
@@ -3012,10 +3034,11 @@ njs_generate_block_statement(njs_vm_t *vm, njs_generator_t *generator,
     njs_parser_node_t *node)
 {
     njs_int_t         ret;
+    njs_str_t         label;
     njs_queue_link_t  *link;
 
     ret = njs_generate_start_block(vm, generator, NJS_GENERATOR_BLOCK,
-                                   &node->name);
+                         njs_generate_node_label(vm, node, &label));
     if (njs_slow_path(ret != NJS_OK)) {
         return ret;
     }
index 0a4419a451d620c924aa48312e3b3698d303afb7..efc1d2907e3b6bf324b90fff005b9ad0210ca27c 100644 (file)
@@ -381,6 +381,8 @@ static njs_int_t njs_parser_labelled_statement(njs_parser_t *parser,
     njs_lexer_token_t *token, njs_queue_link_t *current);
 static njs_int_t njs_parser_labelled_statement_after(njs_parser_t *parser,
     njs_lexer_token_t *token, njs_queue_link_t *current);
+static void njs_parser_statement_label(njs_parser_node_t *node,
+    uintptr_t atom_id);
 
 static njs_int_t njs_parser_throw_statement(njs_parser_t *parser,
     njs_lexer_token_t *token, njs_queue_link_t *current);
@@ -6015,8 +6017,6 @@ static njs_int_t
 njs_parser_break_continue(njs_parser_t *parser, njs_lexer_token_t *token,
     njs_token_type_t type)
 {
-    njs_int_t  ret;
-
     parser->node = njs_parser_node_new(parser, type);
     if (parser->node == NULL) {
         return NJS_ERROR;
@@ -6044,10 +6044,7 @@ njs_parser_break_continue(njs_parser_t *parser, njs_lexer_token_t *token,
                 return NJS_DONE;
             }
 
-            ret = njs_name_copy(parser->vm, &parser->node->name, &token->text);
-            if (ret != NJS_OK) {
-                return NJS_ERROR;
-            }
+            parser->node->u.label = token->atom_id;
 
             break;
         }
@@ -6486,7 +6483,6 @@ njs_parser_labelled_statement_after(njs_parser_t *parser,
     njs_lexer_token_t *token, njs_queue_link_t *current)
 {
     njs_int_t          ret;
-    njs_str_t          str;
     uintptr_t          atom_id;
     njs_parser_node_t  *node;
 
@@ -6504,12 +6500,7 @@ njs_parser_labelled_statement_after(njs_parser_t *parser,
 
     atom_id = (uint32_t) (uintptr_t) parser->target;
 
-    njs_atom_string_get(parser->vm, atom_id, &str);
-
-    ret = njs_name_copy(parser->vm, &parser->node->name, &str);
-    if (ret != NJS_OK) {
-        return NJS_ERROR;
-    }
+    njs_parser_statement_label(parser->node, atom_id);
 
     ret = njs_label_remove(parser, atom_id);
     if (ret != NJS_OK) {
@@ -6520,6 +6511,26 @@ njs_parser_labelled_statement_after(njs_parser_t *parser,
 }
 
 
+static void
+njs_parser_statement_label(njs_parser_node_t *node, uintptr_t atom_id)
+{
+    switch (node->token_type) {
+    case NJS_TOKEN_BLOCK:
+    case NJS_TOKEN_IF:
+    case NJS_TOKEN_SWITCH:
+    case NJS_TOKEN_WHILE:
+    case NJS_TOKEN_DO:
+    case NJS_TOKEN_FOR:
+    case NJS_TOKEN_FOR_IN:
+        node->u.label = atom_id;
+        break;
+
+    default:
+        break;
+    }
+}
+
+
 /*
  * 13.14 throw Statement
  */
index 941a0a10fe431267d74157ff98add6ebf2257bc7..3498d48efa70d1ad4d47daed4a2d3ff14f1f63ed 100644 (file)
@@ -58,13 +58,12 @@ struct njs_parser_node_s {
         } array;
         njs_variable_reference_t    reference;
         njs_value_t                 value;
+        uintptr_t                   label;
         njs_vmcode_t                operation;
         njs_parser_node_t           *object;
         njs_mod_t                   *module;
     } u;
 
-    njs_str_t                       name;
-
     njs_index_t                     index;
 
     /*
index fd9dd150d8168526bba1132350ae59e61bea8fd6..a0b2bd16cd0ff1c3b6fb4498437ae926ea952ac1 100644 (file)
@@ -3973,6 +3973,18 @@ static njs_unit_test_t  njs_test[] =
     { njs_str("a : var n = 0; b :++n"),
       njs_str("1") },
 
+    { njs_str("var r = 0; outer: for (;;) { inner: break outer; r++ } r"),
+      njs_str("0") },
+
+    { njs_str("var r = 0; outer: for (; r < 3; r++) {"
+                  "inner: continue outer } r"),
+      njs_str("3") },
+
+    { njs_str("var x = 0, f = () => ++x;"
+                  "a: x = 1; b: x++; c: f(); d: [1,2].length;"
+                  "e: 's'; g: typeof x; x"),
+      njs_str("3") },
+
     { njs_str("a:{a:1}"),
       njs_str("SyntaxError: Label \"a\" has already been declared") },