Allow empty statements (semicolons) anywhere. v3.0 backport.

Reported by Volodymyr Chernetskyi. #1519
This commit is contained in:
Mike Pall 2026-10-13 11:49:54 +02:00
parent c6ffc141a8
commit 0218af7e36
2 changed files with 10 additions and 9 deletions

View File

@ -370,8 +370,7 @@ Other features are only enabled, if LuaJIT is built with
</p> </p>
<ul> <ul>
<li><tt>goto</tt> is a keyword and not a valid variable name anymore.</li> <li><tt>goto</tt> is a keyword and not a valid variable name anymore.</li>
<li><tt>break</tt> can be placed anywhere. Empty statements (<tt>;;</tt>) <li><tt>break</tt> can be placed anywhere.</li>
are allowed.</li>
<li><tt>__lt</tt>, <tt>__le</tt> are invoked for mixed types.</li> <li><tt>__lt</tt>, <tt>__le</tt> are invoked for mixed types.</li>
<li><tt>__len</tt> for tables. <tt>rawlen()</tt> library function.</li> <li><tt>__len</tt> for tables. <tt>rawlen()</tt> library function.</li>
<li><tt>pairs()</tt> and <tt>ipairs()</tt> check for <tt>__pairs</tt> and <li><tt>pairs()</tt> and <tt>ipairs()</tt> check for <tt>__pairs</tt> and
@ -427,6 +426,7 @@ LuaJIT 2.1 supports some
<li><tt>const</tt> Declaration</li> <li><tt>const</tt> Declaration</li>
<li>Short Function Expression</li> <li>Short Function Expression</li>
<li>Underscores in Number Literals</li> <li>Underscores in Number Literals</li>
<li>Empty statements (<tt>;;</tt>) are allowed anywhere.</li>
</ul> </ul>
<p> <p>
Not backported are: Not backported are:

View File

@ -2740,13 +2740,13 @@ static void parse_label(LexState *ls)
lj_lex_error(ls, 0, LJ_ERR_XLDUP, strdata(name)); lj_lex_error(ls, 0, LJ_ERR_XLDUP, strdata(name));
idx = gola_new(ls, name, VSTACK_LABEL, fs->pc); idx = gola_new(ls, name, VSTACK_LABEL, fs->pc);
lex_check(ls, TK_label); lex_check(ls, TK_label);
/* Recursively parse trailing statements: labels and ';' (Lua 5.2 only). */ /* Recursively parse trailing statements: labels and ';'. */
for (;;) { for (;;) {
if (ls->tok == TK_label) { if (ls->tok == TK_label) {
synlevel_begin(ls); synlevel_begin(ls);
parse_label(ls); parse_label(ls);
synlevel_end(ls); synlevel_end(ls);
} else if (LJ_52 && ls->tok == ';') { } else if (ls->tok == ';') {
lj_lex_next(ls); lj_lex_next(ls);
} else { } else {
break; break;
@ -3033,16 +3033,17 @@ static int parse_stmt(LexState *ls)
lj_lex_next(ls); lj_lex_next(ls);
parse_break(ls); parse_break(ls);
return !LJ_52; /* Must be last in Lua 5.1. */ return !LJ_52; /* Must be last in Lua 5.1. */
case TK_continue: case TK_continue: {
if (!parse_isend(lj_lex_lookahead(ls))) goto assign; /* Soft keyword. */ LexToken tokx = lj_lex_lookahead(ls);
if (!(parse_isend(tokx) || tokx == ';'))
goto assign; /* Soft keyword. */
lj_lex_next(ls); lj_lex_next(ls);
parse_continue(ls); parse_continue(ls);
return 1; /* Must be last. */ return 1; /* Must be last. */
#if LJ_52 }
case ';': case ';':
lj_lex_next(ls); lj_lex_next(ls);
break; break;
#endif
case TK_label: case TK_label:
parse_label(ls); parse_label(ls);
break; break;
@ -3068,7 +3069,7 @@ static void parse_chunk(LexState *ls)
synlevel_begin(ls); synlevel_begin(ls);
while (!islast && !parse_isend(ls->tok)) { while (!islast && !parse_isend(ls->tok)) {
islast = parse_stmt(ls); islast = parse_stmt(ls);
lex_opt(ls, ';'); while (ls->tok == ';') lj_lex_next(ls);
lj_assertLS(ls->fs->framesize >= ls->fs->freereg && lj_assertLS(ls->fs->framesize >= ls->fs->freereg &&
ls->fs->freereg >= ls->fs->nactvar, ls->fs->freereg >= ls->fs->nactvar,
"bad regalloc"); "bad regalloc");