mirror of
https://github.com/DoneJS-Runtime/quickjs-done-nextgen.git
synced 2025-01-09 17:43:15 +00:00
Fix break statement in presence of labels (#742)
In this snippet... for (;;) label: break ...the break statement jumped back to the start of the loop instead of *out* of the loop. Fixes: https://github.com/quickjs-ng/quickjs/issues/741
This commit is contained in:
parent
ebc1a655b4
commit
66732e78ef
2 changed files with 35 additions and 11 deletions
23
quickjs.c
23
quickjs.c
|
@ -18626,7 +18626,8 @@ typedef struct BlockEnv {
|
||||||
int drop_count; /* number of stack elements to drop */
|
int drop_count; /* number of stack elements to drop */
|
||||||
int label_finally; /* -1 if none */
|
int label_finally; /* -1 if none */
|
||||||
int scope_level;
|
int scope_level;
|
||||||
int has_iterator;
|
uint8_t has_iterator : 1;
|
||||||
|
uint8_t is_regular_stmt : 1; // i.e. not a loop statement
|
||||||
} BlockEnv;
|
} BlockEnv;
|
||||||
|
|
||||||
typedef struct JSGlobalVar {
|
typedef struct JSGlobalVar {
|
||||||
|
@ -24891,6 +24892,7 @@ static void push_break_entry(JSFunctionDef *fd, BlockEnv *be,
|
||||||
be->label_finally = -1;
|
be->label_finally = -1;
|
||||||
be->scope_level = fd->scope_level;
|
be->scope_level = fd->scope_level;
|
||||||
be->has_iterator = FALSE;
|
be->has_iterator = FALSE;
|
||||||
|
be->is_regular_stmt = FALSE;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void pop_break_entry(JSFunctionDef *fd)
|
static void pop_break_entry(JSFunctionDef *fd)
|
||||||
|
@ -24917,12 +24919,13 @@ static __exception int emit_break(JSParseState *s, JSAtom name, int is_cont)
|
||||||
emit_goto(s, OP_goto, top->label_cont);
|
emit_goto(s, OP_goto, top->label_cont);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
if (!is_cont &&
|
if (!is_cont && top->label_break != -1) {
|
||||||
top->label_break != -1 &&
|
if (top->label_name == name ||
|
||||||
(name == JS_ATOM_NULL || top->label_name == name)) {
|
(name == JS_ATOM_NULL && !top->is_regular_stmt)) {
|
||||||
emit_goto(s, OP_goto, top->label_break);
|
emit_goto(s, OP_goto, top->label_break);
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
i = 0;
|
i = 0;
|
||||||
if (top->has_iterator) {
|
if (top->has_iterator) {
|
||||||
emit_op(s, OP_iterator_close);
|
emit_op(s, OP_iterator_close);
|
||||||
|
@ -25335,7 +25338,8 @@ static __exception int js_parse_for_in_of(JSParseState *s, int label_name,
|
||||||
JS_FreeAtom(ctx, var_name);
|
JS_FreeAtom(ctx, var_name);
|
||||||
|
|
||||||
if (token_is_pseudo_keyword(s, JS_ATOM_of)) {
|
if (token_is_pseudo_keyword(s, JS_ATOM_of)) {
|
||||||
break_entry.has_iterator = is_for_of = TRUE;
|
is_for_of = TRUE;
|
||||||
|
break_entry.has_iterator = TRUE;
|
||||||
break_entry.drop_count += 2;
|
break_entry.drop_count += 2;
|
||||||
if (has_initializer)
|
if (has_initializer)
|
||||||
goto initializer_error;
|
goto initializer_error;
|
||||||
|
@ -25479,13 +25483,14 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
|
||||||
&& s->token.val != TOK_DO
|
&& s->token.val != TOK_DO
|
||||||
&& s->token.val != TOK_WHILE) {
|
&& s->token.val != TOK_WHILE) {
|
||||||
/* labelled regular statement */
|
/* labelled regular statement */
|
||||||
|
JSFunctionDef *fd = s->cur_func;
|
||||||
int label_break, mask;
|
int label_break, mask;
|
||||||
BlockEnv break_entry;
|
BlockEnv break_entry;
|
||||||
|
|
||||||
label_break = new_label(s);
|
label_break = new_label(s);
|
||||||
push_break_entry(s->cur_func, &break_entry,
|
push_break_entry(fd, &break_entry, label_name, label_break, -1, 0);
|
||||||
label_name, label_break, -1, 0);
|
fd->top_break->is_regular_stmt = 1;
|
||||||
if (!s->cur_func->is_strict_mode &&
|
if (!fd->is_strict_mode &&
|
||||||
(decl_mask & DECL_MASK_FUNC_WITH_LABEL)) {
|
(decl_mask & DECL_MASK_FUNC_WITH_LABEL)) {
|
||||||
mask = DECL_MASK_FUNC | DECL_MASK_FUNC_WITH_LABEL;
|
mask = DECL_MASK_FUNC | DECL_MASK_FUNC_WITH_LABEL;
|
||||||
} else {
|
} else {
|
||||||
|
@ -25494,7 +25499,7 @@ static __exception int js_parse_statement_or_decl(JSParseState *s,
|
||||||
if (js_parse_statement_or_decl(s, mask))
|
if (js_parse_statement_or_decl(s, mask))
|
||||||
goto fail;
|
goto fail;
|
||||||
emit_label(s, label_break);
|
emit_label(s, label_break);
|
||||||
pop_break_entry(s->cur_func);
|
pop_break_entry(fd);
|
||||||
goto done;
|
goto done;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
19
tests/bug741.js
Normal file
19
tests/bug741.js
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import {assert} from "./assert.js"
|
||||||
|
|
||||||
|
while (1) label: break
|
||||||
|
|
||||||
|
var i = 0
|
||||||
|
while (i < 3) label: {
|
||||||
|
if (i > 0)
|
||||||
|
break
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
assert(i, 1)
|
||||||
|
|
||||||
|
for (;;) label: break
|
||||||
|
|
||||||
|
for (i = 0; i < 3; i++) label: {
|
||||||
|
if (i > 0)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
assert(i, 1)
|
Loading…
Reference in a new issue