diff --git a/llex.c b/llex.c index b6dc50b2..17e5a986 100644 --- a/llex.c +++ b/llex.c @@ -50,8 +50,8 @@ static const char *const luaX_tokens [] = { "//", "..", "...", "==", ">=", "<=", "~=", "<<", ">>", "::", "", "", "", "", "", - "", "", "", - "", "" + "", "", + "" }; @@ -475,8 +475,8 @@ static void read_string (LexState *ls, int del, SemInfo *seminfo) { ** Called initially when '`' is seen, and also continued via ** luaX_readcommandcont() after the parser processes an interpolated ** expression. -** Returns TK_COMMAND if the string is complete (closing ` found), -** or TK_COMMAND_INTERP if an interpolation ${...} was found. +** Returns TK_COMMAND or TK_INTERACTIVE in all cases. +** When an interpolation ${...} is found, cmd_mode remains non-zero. */ static int read_command_body (LexState *ls, SemInfo *seminfo) { int interactive = (ls->cmd_mode == 2); @@ -513,7 +513,7 @@ static int read_command_body (LexState *ls, SemInfo *seminfo) { seminfo->ts = luaX_newstring(ls, luaZ_buffer(ls->buff), luaZ_bufflen(ls->buff)); ls->saved_cmd_mode = ls->cmd_mode; /* save for readcommandcont */ - return interactive ? TK_INTERACTIVE_INTERP : TK_COMMAND_INTERP; + return interactive ? TK_INTERACTIVE : TK_COMMAND; } else { save(ls, '$'); /* not an interpolation, keep literal '$' */ diff --git a/llex.h b/llex.h index 566032b1..af853258 100644 --- a/llex.h +++ b/llex.h @@ -41,10 +41,8 @@ enum RESERVED { TK_DBCOLON, TK_EOS, TK_FLT, TK_INT, TK_NAME, TK_STRING, TK_COMMAND, - TK_COMMAND_INTERP, TK_ENVVAR, - TK_INTERACTIVE, - TK_INTERACTIVE_INTERP + TK_INTERACTIVE }; /* number of reserved words */ diff --git a/lparser.c b/lparser.c index 9cc166c7..1854a196 100644 --- a/lparser.c +++ b/lparser.c @@ -554,24 +554,34 @@ static void singlevar (LexState *ls, expdesc *var) { /* -** Compile a command expression: emit code equivalent to -** __command(cmdstring) -** where cmdstring is already built (possibly via concatenation -** from interpolation fragments). +** Helper: parse a single ${expr} interpolation fragment. +** Emits tostring(expr), reads the next command continuation fragment, +** and pushes it as a string constant. Returns with the continuation +** token already set (TK_COMMAND or TK_INTERACTIVE). */ -static void codecommand (LexState *ls, expdesc *v, expdesc *cmdstr) { +static void parseinterp (LexState *ls, TString *tsname, int *nconcat) { FuncState *fs = ls->fs; - int base, line; - expdesc func; - line = ls->linenumber; - codelushfunc(fs, LUSH_OP_COMMAND, &func); - base = func.u.info; - /* push the command string argument */ - luaK_exp2nextreg(fs, cmdstr); - /* emit OP_CALL: 1 arg, 1 result */ - init_exp(v, VCALL, luaK_codeABC(fs, OP_CALL, base, 2, 2)); - luaK_fixline(fs, line); - fs->freereg = cast_byte(base + 1); + expdesc interp, tostrfn; + int tostr_base; + luaX_next(ls); /* advance past TK_COMMAND / TK_INTERACTIVE */ + /* emit tostring(expr) */ + buildglobal(ls, tsname, &tostrfn); + luaK_exp2nextreg(fs, &tostrfn); + tostr_base = tostrfn.u.info; + expr(ls, &interp); + check(ls, '}'); + luaK_exp2nextreg(fs, &interp); + luaK_codeABC(fs, OP_CALL, tostr_base, 2, 2); + fs->freereg = cast_byte(tostr_base + 1); + (*nconcat)++; + /* read continuation fragment */ + luaX_readcommandcont(ls); + { + expdesc frag; + codestring(&frag, ls->t.seminfo.ts); + luaK_exp2nextreg(fs, &frag); + (*nconcat)++; + } } @@ -1230,83 +1240,38 @@ static void funcargs (LexState *ls, expdesc *f) { /* -** Parse a backtick command expression (TK_COMMAND or TK_COMMAND_INTERP). +** Parse a backtick command expression (TK_COMMAND). ** Compiles `cmd` as __command("cmd") and `cmd ${expr}` as ** __command("cmd " .. tostring(expr) .. ""). -** On entry, ls->t.token is TK_COMMAND or TK_COMMAND_INTERP. +** On entry, ls->t.token is TK_COMMAND. ** On exit, the token has been consumed (ls->t has the next token). */ static void commandexp (LexState *ls, expdesc *v) { - if (ls->t.token == TK_COMMAND) { - /* simple command with no interpolation */ - expdesc cmdstr; - codestring(&cmdstr, ls->t.seminfo.ts); - luaX_next(ls); - codecommand(ls, v, &cmdstr); + FuncState *fs = ls->fs; + expdesc func, cmdstr; + int base, nconcat = 0; + int line = ls->linenumber; + TString *tsname = NULL; + codelushfunc(fs, LUSH_OP_COMMAND, &func); + base = func.u.info; + /* load the first fragment */ + codestring(&cmdstr, ls->t.seminfo.ts); + luaK_exp2nextreg(fs, &cmdstr); + nconcat++; + while (ls->cmd_mode != 0) { + if (tsname == NULL) + tsname = luaX_newstring(ls, "tostring", 8); + parseinterp(ls, tsname, &nconcat); } - else { - /* command with ${expr} interpolation */ - FuncState *fs = ls->fs; - expdesc func, cmdstr; - int base, nconcat = 0; - int line = ls->linenumber; - TString *tsname = luaX_newstring(ls, "tostring", 8); - /* load __command function first so it occupies the base register */ - codelushfunc(fs, LUSH_OP_COMMAND, &func); - base = func.u.info; - /* load the first fragment */ - codestring(&cmdstr, ls->t.seminfo.ts); - luaK_exp2nextreg(fs, &cmdstr); - nconcat++; - for (;;) { - expdesc interp, tostrfn; - int tostr_base; - /* parse the interpolated expression */ - luaX_next(ls); /* advance past TK_COMMAND_INTERP */ - /* emit tostring(expr): load tostring function, then the expr, - ** then OP_CALL — result occupies one register in the concat chain */ - buildglobal(ls, tsname, &tostrfn); - luaK_exp2nextreg(fs, &tostrfn); - tostr_base = tostrfn.u.info; - expr(ls, &interp); - check(ls, '}'); - /* don't call luaX_next — luaX_readcommandcont reads directly - from ls->current, which is already past the '}' */ - luaK_exp2nextreg(fs, &interp); - luaK_codeABC(fs, OP_CALL, tostr_base, 2, 2); - fs->freereg = cast_byte(tostr_base + 1); - nconcat++; - /* continue reading the command string */ - if (luaX_readcommandcont(ls) == TK_COMMAND_INTERP) { - /* another fragment + more interpolation coming */ - expdesc frag; - codestring(&frag, ls->t.seminfo.ts); - luaK_exp2nextreg(fs, &frag); - nconcat++; - /* loop continues */ - } - else { - /* TK_COMMAND: final fragment */ - expdesc frag; - codestring(&frag, ls->t.seminfo.ts); - luaK_exp2nextreg(fs, &frag); - nconcat++; - break; - } - } - /* advance past the final TK_COMMAND token */ - luaX_next(ls); - /* emit OP_CONCAT for all fragments (result goes into base+1) */ - if (nconcat > 1) { - int first = base + 1; - luaK_codeABC(fs, OP_CONCAT, first, nconcat, 0); - fs->freereg = cast_byte(first + 1); - } - /* emit OP_CALL: 1 arg (the concatenated string), 1 result */ - init_exp(v, VCALL, luaK_codeABC(fs, OP_CALL, base, 2, 2)); - luaK_fixline(fs, line); - fs->freereg = cast_byte(base + 1); + luaX_next(ls); /* consume final TK_COMMAND */ + if (nconcat > 1) { + int first = base + 1; + luaK_codeABC(fs, OP_CONCAT, first, nconcat, 0); + fs->freereg = cast_byte(first + 1); } + init_exp(v, VCALL, luaK_codeABC(fs, OP_CALL, base, 2, 2)); + luaK_fixline(fs, line); + fs->freereg = cast_byte(base + 1); } @@ -1340,7 +1305,7 @@ static void primaryexp (LexState *ls, expdesc *v) { singlevar(ls, v); return; } - case TK_COMMAND: case TK_COMMAND_INTERP: { + case TK_COMMAND: { commandexp(ls, v); return; } @@ -2216,71 +2181,29 @@ static void envstat (LexState *ls) { */ static void interactivestat (LexState *ls) { FuncState *fs = ls->fs; - if (ls->t.token == TK_INTERACTIVE) { - /* simple interactive command, no interpolation */ - int base, line; - expdesc func, cmdstr, v; - line = ls->linenumber; - codelushfunc(fs, LUSH_OP_INTERACTIVE, &func); - base = func.u.info; - codestring(&cmdstr, ls->t.seminfo.ts); - luaK_exp2nextreg(fs, &cmdstr); - luaX_next(ls); /* consume TK_INTERACTIVE */ - init_exp(&v, VCALL, luaK_codeABC(fs, OP_CALL, base, 2, 1)); - luaK_fixline(fs, line); - fs->freereg = cast_byte(base); + expdesc func, cmdstr, v; + int base, nconcat = 0; + int line = ls->linenumber; + TString *tsname = NULL; + codelushfunc(fs, LUSH_OP_INTERACTIVE, &func); + base = func.u.info; + codestring(&cmdstr, ls->t.seminfo.ts); + luaK_exp2nextreg(fs, &cmdstr); + nconcat++; + while (ls->cmd_mode != 0) { + if (tsname == NULL) + tsname = luaX_newstring(ls, "tostring", 8); + parseinterp(ls, tsname, &nconcat); } - else { - /* interactive command with ${expr} interpolation */ - expdesc func, cmdstr, v; - int base, nconcat = 0; - int line = ls->linenumber; - TString *tsname = luaX_newstring(ls, "tostring", 8); - codelushfunc(fs, LUSH_OP_INTERACTIVE, &func); - base = func.u.info; - /* load the first fragment */ - codestring(&cmdstr, ls->t.seminfo.ts); - luaK_exp2nextreg(fs, &cmdstr); - nconcat++; - for (;;) { - expdesc interp, tostrfn; - int tostr_base; - luaX_next(ls); /* advance past TK_INTERACTIVE_INTERP */ - buildglobal(ls, tsname, &tostrfn); - luaK_exp2nextreg(fs, &tostrfn); - tostr_base = tostrfn.u.info; - expr(ls, &interp); - check(ls, '}'); - luaK_exp2nextreg(fs, &interp); - luaK_codeABC(fs, OP_CALL, tostr_base, 2, 2); - fs->freereg = cast_byte(tostr_base + 1); - nconcat++; - if (luaX_readcommandcont(ls) == TK_INTERACTIVE_INTERP) { - expdesc frag; - codestring(&frag, ls->t.seminfo.ts); - luaK_exp2nextreg(fs, &frag); - nconcat++; - } - else { - /* TK_INTERACTIVE: final fragment */ - expdesc frag; - codestring(&frag, ls->t.seminfo.ts); - luaK_exp2nextreg(fs, &frag); - nconcat++; - break; - } - } - luaX_next(ls); /* advance past final TK_INTERACTIVE */ - if (nconcat > 1) { - int first = base + 1; - luaK_codeABC(fs, OP_CONCAT, first, nconcat, 0); - fs->freereg = cast_byte(first + 1); - } - /* emit void call (C=1 means 0 return values) */ - init_exp(&v, VCALL, luaK_codeABC(fs, OP_CALL, base, 2, 1)); - luaK_fixline(fs, line); - fs->freereg = cast_byte(base); + luaX_next(ls); /* consume final TK_INTERACTIVE */ + if (nconcat > 1) { + int first = base + 1; + luaK_codeABC(fs, OP_CONCAT, first, nconcat, 0); + fs->freereg = cast_byte(first + 1); } + init_exp(&v, VCALL, luaK_codeABC(fs, OP_CALL, base, 2, 1)); + luaK_fixline(fs, line); + fs->freereg = cast_byte(base); } @@ -2353,8 +2276,7 @@ static void statement (LexState *ls) { envstat(ls); break; } - case TK_INTERACTIVE: - case TK_INTERACTIVE_INTERP: { /* stat -> !command */ + case TK_INTERACTIVE: { /* stat -> !command */ interactivestat(ls); break; }