From 1334c0ae67fdf4cb1377e0e7a3ef291f5cf694c0 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Sat, 19 Oct 2024 00:35:11 +0800 Subject: Fixed issue #174. --- src/3rdParty/lua/lauxlib.c | 28 +++++++++++++++++++++------- src/3rdParty/lua/lcode.c | 6 ++++-- src/3rdParty/lua/ldebug.c | 41 +++++++++++++++++++++-------------------- src/3rdParty/lua/ldo.c | 4 ++++ src/3rdParty/lua/lgc.c | 2 +- src/3rdParty/lua/liolib.c | 27 ++++++++++++++++++++------- src/3rdParty/lua/lmathlib.c | 2 +- src/3rdParty/lua/loslib.c | 2 ++ src/3rdParty/lua/lstring.c | 2 +- src/3rdParty/lua/lua.h | 34 ++++++++++++---------------------- src/3rdParty/lua/luaconf.h | 2 +- src/3rdParty/lua/lundump.h | 2 +- src/3rdParty/lua/lvm.c | 4 ++-- src/yuescript/yue_ast.cpp | 2 +- src/yuescript/yue_ast.h | 3 ++- src/yuescript/yue_compiler.cpp | 37 +++++++++++++++++++++++++++++++++---- src/yuescript/yue_parser.cpp | 2 +- 17 files changed, 128 insertions(+), 72 deletions(-) (limited to 'src') diff --git a/src/3rdParty/lua/lauxlib.c b/src/3rdParty/lua/lauxlib.c index 4ca6c65..923105e 100644 --- a/src/3rdParty/lua/lauxlib.c +++ b/src/3rdParty/lua/lauxlib.c @@ -80,6 +80,7 @@ static int pushglobalfuncname (lua_State *L, lua_Debug *ar) { int top = lua_gettop(L); lua_getinfo(L, "f", ar); /* push function */ lua_getfield(L, LUA_REGISTRYINDEX, LUA_LOADED_TABLE); + luaL_checkstack(L, 6, "not enough stack"); /* slots for 'findfield' */ if (findfield(L, top + 1, 2)) { const char *name = lua_tostring(L, -1); if (strncmp(name, LUA_GNAME ".", 3) == 0) { /* name start with '_G.'? */ @@ -249,11 +250,13 @@ LUALIB_API int luaL_fileresult (lua_State *L, int stat, const char *fname) { return 1; } else { + const char *msg; luaL_pushfail(L); + msg = (en != 0) ? strerror(en) : "(no extra info)"; if (fname) - lua_pushfstring(L, "%s: %s", fname, strerror(en)); + lua_pushfstring(L, "%s: %s", fname, msg); else - lua_pushstring(L, strerror(en)); + lua_pushstring(L, msg); lua_pushinteger(L, en); return 3; } @@ -732,9 +735,12 @@ static const char *getF (lua_State *L, void *ud, size_t *size) { static int errfile (lua_State *L, const char *what, int fnameindex) { - const char *serr = strerror(errno); + int err = errno; const char *filename = lua_tostring(L, fnameindex) + 1; - lua_pushfstring(L, "cannot %s %s: %s", what, filename, serr); + if (err != 0) + lua_pushfstring(L, "cannot %s %s: %s", what, filename, strerror(err)); + else + lua_pushfstring(L, "cannot %s %s", what, filename); lua_remove(L, fnameindex); return LUA_ERRFILE; } @@ -787,6 +793,7 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename, } else { lua_pushfstring(L, "@%s", filename); + errno = 0; lf.f = fopen(filename, "r"); if (lf.f == NULL) return errfile(L, "open", fnameindex); } @@ -796,6 +803,7 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename, if (c == LUA_SIGNATURE[0]) { /* binary file? */ lf.n = 0; /* remove possible newline */ if (filename) { /* "real" file? */ + errno = 0; lf.f = freopen(filename, "rb", lf.f); /* reopen in binary mode */ if (lf.f == NULL) return errfile(L, "reopen", fnameindex); skipcomment(lf.f, &c); /* re-read initial portion */ @@ -803,6 +811,7 @@ LUALIB_API int luaL_loadfilex (lua_State *L, const char *filename, } if (c != EOF) lf.buff[lf.n++] = c; /* 'c' is the first character of the stream */ + errno = 0; status = lua_load(L, getF, &lf, lua_tostring(L, -1), mode); readstatus = ferror(lf.f); if (filename) fclose(lf.f); /* close file (even in case of errors) */ @@ -933,7 +942,7 @@ LUALIB_API const char *luaL_tolstring (lua_State *L, int idx, size_t *len) { LUALIB_API void luaL_setfuncs (lua_State *L, const luaL_Reg *l, int nup) { luaL_checkstack(L, nup, "too many upvalues"); for (; l->name != NULL; l++) { /* fill the table with given functions */ - if (l->func == NULL) /* place holder? */ + if (l->func == NULL) /* placeholder? */ lua_pushboolean(L, 0); else { int i; @@ -1025,9 +1034,14 @@ static void *l_alloc (void *ud, void *ptr, size_t osize, size_t nsize) { } +/* +** Standard panic funcion just prints an error message. The test +** with 'lua_type' avoids possible memory errors in 'lua_tostring'. +*/ static int panic (lua_State *L) { - const char *msg = lua_tostring(L, -1); - if (msg == NULL) msg = "error object is not a string"; + const char *msg = (lua_type(L, -1) == LUA_TSTRING) + ? lua_tostring(L, -1) + : "error object is not a string"; lua_writestringerror("PANIC: unprotected error in call to Lua API (%s)\n", msg); return 0; /* return to Lua to abort */ diff --git a/src/3rdParty/lua/lcode.c b/src/3rdParty/lua/lcode.c index caac6ba..8761614 100644 --- a/src/3rdParty/lua/lcode.c +++ b/src/3rdParty/lua/lcode.c @@ -776,7 +776,8 @@ void luaK_dischargevars (FuncState *fs, expdesc *e) { break; } case VLOCAL: { /* already in a register */ - e->u.info = e->u.var.ridx; + int temp = e->u.var.ridx; + e->u.info = temp; /* (can't do a direct assignment; values overlap) */ e->k = VNONRELOC; /* becomes a non-relocatable value */ break; } @@ -1283,8 +1284,9 @@ void luaK_indexed (FuncState *fs, expdesc *t, expdesc *k) { if (t->k == VUPVAL && !isKstr(fs, k)) /* upvalue indexed by non 'Kstr'? */ luaK_exp2anyreg(fs, t); /* put it in a register */ if (t->k == VUPVAL) { + int temp = t->u.info; /* upvalue index */ lua_assert(isKstr(fs, k)); - t->u.ind.t = t->u.info; /* upvalue index */ + t->u.ind.t = temp; /* (can't do a direct assignment; values overlap) */ t->u.ind.idx = k->u.info; /* literal short string */ t->k = VINDEXUP; } diff --git a/src/3rdParty/lua/ldebug.c b/src/3rdParty/lua/ldebug.c index b1f16ac..591b352 100644 --- a/src/3rdParty/lua/ldebug.c +++ b/src/3rdParty/lua/ldebug.c @@ -31,7 +31,7 @@ -#define noLuaClosure(f) ((f) == NULL || (f)->c.tt == LUA_VCCL) +#define LuaClosure(f) ((f) != NULL && (f)->c.tt == LUA_VLCL) static const char *funcnamefromcall (lua_State *L, CallInfo *ci, @@ -254,7 +254,7 @@ LUA_API const char *lua_setlocal (lua_State *L, const lua_Debug *ar, int n) { static void funcinfo (lua_Debug *ar, Closure *cl) { - if (noLuaClosure(cl)) { + if (!LuaClosure(cl)) { ar->source = "=[C]"; ar->srclen = LL("=[C]"); ar->linedefined = -1; @@ -288,29 +288,31 @@ static int nextline (const Proto *p, int currentline, int pc) { static void collectvalidlines (lua_State *L, Closure *f) { - if (noLuaClosure(f)) { + if (!LuaClosure(f)) { setnilvalue(s2v(L->top.p)); api_incr_top(L); } else { - int i; - TValue v; const Proto *p = f->l.p; int currentline = p->linedefined; Table *t = luaH_new(L); /* new table to store active lines */ sethvalue2s(L, L->top.p, t); /* push it on stack */ api_incr_top(L); - setbtvalue(&v); /* boolean 'true' to be the value of all indices */ - if (!p->is_vararg) /* regular function? */ - i = 0; /* consider all instructions */ - else { /* vararg function */ - lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP); - currentline = nextline(p, currentline, 0); - i = 1; /* skip first instruction (OP_VARARGPREP) */ - } - for (; i < p->sizelineinfo; i++) { /* for each instruction */ - currentline = nextline(p, currentline, i); /* get its line */ - luaH_setint(L, t, currentline, &v); /* table[line] = true */ + if (p->lineinfo != NULL) { /* proto with debug information? */ + int i; + TValue v; + setbtvalue(&v); /* boolean 'true' to be the value of all indices */ + if (!p->is_vararg) /* regular function? */ + i = 0; /* consider all instructions */ + else { /* vararg function */ + lua_assert(GET_OPCODE(p->code[0]) == OP_VARARGPREP); + currentline = nextline(p, currentline, 0); + i = 1; /* skip first instruction (OP_VARARGPREP) */ + } + for (; i < p->sizelineinfo; i++) { /* for each instruction */ + currentline = nextline(p, currentline, i); /* get its line */ + luaH_setint(L, t, currentline, &v); /* table[line] = true */ + } } } } @@ -339,7 +341,7 @@ static int auxgetinfo (lua_State *L, const char *what, lua_Debug *ar, } case 'u': { ar->nups = (f == NULL) ? 0 : f->c.nupvalues; - if (noLuaClosure(f)) { + if (!LuaClosure(f)) { ar->isvararg = 1; ar->nparams = 0; } @@ -925,12 +927,12 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) { } pc++; /* reference is always next instruction */ ci->u.l.savedpc = pc; /* save 'pc' */ - counthook = (--L->hookcount == 0 && (mask & LUA_MASKCOUNT)); + counthook = (mask & LUA_MASKCOUNT) && (--L->hookcount == 0); if (counthook) resethookcount(L); /* reset count */ else if (!(mask & LUA_MASKLINE)) return 1; /* no line hook and count != 0; nothing to be done now */ - if (ci->callstatus & CIST_HOOKYIELD) { /* called hook last time? */ + if (ci->callstatus & CIST_HOOKYIELD) { /* hook yielded last time? */ ci->callstatus &= ~CIST_HOOKYIELD; /* erase mark */ return 1; /* do not call hook again (VM yielded, so it did not move) */ } @@ -952,7 +954,6 @@ int luaG_traceexec (lua_State *L, const Instruction *pc) { if (L->status == LUA_YIELD) { /* did hook yield? */ if (counthook) L->hookcount = 1; /* undo decrement to zero */ - ci->u.l.savedpc--; /* undo increment (resume will increment it again) */ ci->callstatus |= CIST_HOOKYIELD; /* mark that it yielded */ luaD_throw(L, LUA_YIELD); } diff --git a/src/3rdParty/lua/ldo.c b/src/3rdParty/lua/ldo.c index bd8d965..ea05295 100644 --- a/src/3rdParty/lua/ldo.c +++ b/src/3rdParty/lua/ldo.c @@ -792,6 +792,10 @@ static void resume (lua_State *L, void *ud) { lua_assert(L->status == LUA_YIELD); L->status = LUA_OK; /* mark that it is running (again) */ if (isLua(ci)) { /* yielded inside a hook? */ + /* undo increment made by 'luaG_traceexec': instruction was not + executed yet */ + lua_assert(ci->callstatus & CIST_HOOKYIELD); + ci->u.l.savedpc--; L->top.p = firstArg; /* discard arguments */ luaV_execute(L, ci); /* just continue running Lua code */ } diff --git a/src/3rdParty/lua/lgc.c b/src/3rdParty/lua/lgc.c index 253a289..5817f9e 100644 --- a/src/3rdParty/lua/lgc.c +++ b/src/3rdParty/lua/lgc.c @@ -1713,7 +1713,7 @@ static void fullinc (lua_State *L, global_State *g) { /* finish any pending sweep phase to start a new cycle */ luaC_runtilstate(L, bitmask(GCSpause)); luaC_runtilstate(L, bitmask(GCSpropagate)); /* start new cycle */ - g->gcstate = GCSenteratomic; /* go straight to atomic phase ??? */ + g->gcstate = GCSenteratomic; /* go straight to atomic phase */ luaC_runtilstate(L, bitmask(GCScallfin)); /* run up to finalizers */ /* estimate must be correct after a full GC cycle */ lua_assert(g->GCestimate == gettotalbytes(g)); diff --git a/src/3rdParty/lua/liolib.c b/src/3rdParty/lua/liolib.c index b08397d..c5075f3 100644 --- a/src/3rdParty/lua/liolib.c +++ b/src/3rdParty/lua/liolib.c @@ -245,8 +245,8 @@ static int f_gc (lua_State *L) { */ static int io_fclose (lua_State *L) { LStream *p = tolstream(L); - int res = fclose(p->f); - return luaL_fileresult(L, (res == 0), NULL); + errno = 0; + return luaL_fileresult(L, (fclose(p->f) == 0), NULL); } @@ -272,6 +272,7 @@ static int io_open (lua_State *L) { LStream *p = newfile(L); const char *md = mode; /* to traverse/check mode */ luaL_argcheck(L, l_checkmode(md), 2, "invalid mode"); + errno = 0; p->f = fopen(filename, mode); return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; } @@ -292,6 +293,7 @@ static int io_popen (lua_State *L) { const char *mode = luaL_optstring(L, 2, "r"); LStream *p = newprefile(L); luaL_argcheck(L, l_checkmodep(mode), 2, "invalid mode"); + errno = 0; p->f = l_popen(L, filename, mode); p->closef = &io_pclose; return (p->f == NULL) ? luaL_fileresult(L, 0, filename) : 1; @@ -300,6 +302,7 @@ static int io_popen (lua_State *L) { static int io_tmpfile (lua_State *L) { LStream *p = newfile(L); + errno = 0; p->f = tmpfile(); return (p->f == NULL) ? luaL_fileresult(L, 0, NULL) : 1; } @@ -567,6 +570,7 @@ static int g_read (lua_State *L, FILE *f, int first) { int nargs = lua_gettop(L) - 1; int n, success; clearerr(f); + errno = 0; if (nargs == 0) { /* no arguments? */ success = read_line(L, f, 1); n = first + 1; /* to return 1 result */ @@ -660,6 +664,7 @@ static int io_readline (lua_State *L) { static int g_write (lua_State *L, FILE *f, int arg) { int nargs = lua_gettop(L) - arg; int status = 1; + errno = 0; for (; nargs--; arg++) { if (lua_type(L, arg) == LUA_TNUMBER) { /* optimization: could be done exactly as for strings */ @@ -678,7 +683,8 @@ static int g_write (lua_State *L, FILE *f, int arg) { } if (l_likely(status)) return 1; /* file handle already on stack top */ - else return luaL_fileresult(L, status, NULL); + else + return luaL_fileresult(L, status, NULL); } @@ -703,6 +709,7 @@ static int f_seek (lua_State *L) { l_seeknum offset = (l_seeknum)p3; luaL_argcheck(L, (lua_Integer)offset == p3, 3, "not an integer in proper range"); + errno = 0; op = l_fseek(f, offset, mode[op]); if (l_unlikely(op)) return luaL_fileresult(L, 0, NULL); /* error */ @@ -719,19 +726,25 @@ static int f_setvbuf (lua_State *L) { FILE *f = tofile(L); int op = luaL_checkoption(L, 2, NULL, modenames); lua_Integer sz = luaL_optinteger(L, 3, LUAL_BUFFERSIZE); - int res = setvbuf(f, NULL, mode[op], (size_t)sz); + int res; + errno = 0; + res = setvbuf(f, NULL, mode[op], (size_t)sz); return luaL_fileresult(L, res == 0, NULL); } static int io_flush (lua_State *L) { - return luaL_fileresult(L, fflush(getiofile(L, IO_OUTPUT)) == 0, NULL); + FILE *f = getiofile(L, IO_OUTPUT); + errno = 0; + return luaL_fileresult(L, fflush(f) == 0, NULL); } static int f_flush (lua_State *L) { - return luaL_fileresult(L, fflush(tofile(L)) == 0, NULL); + FILE *f = tofile(L); + errno = 0; + return luaL_fileresult(L, fflush(f) == 0, NULL); } @@ -773,7 +786,7 @@ static const luaL_Reg meth[] = { ** metamethods for file handles */ static const luaL_Reg metameth[] = { - {"__index", NULL}, /* place holder */ + {"__index", NULL}, /* placeholder */ {"__gc", f_gc}, {"__close", f_gc}, {"__tostring", f_tostring}, diff --git a/src/3rdParty/lua/lmathlib.c b/src/3rdParty/lua/lmathlib.c index f140d62..4381063 100644 --- a/src/3rdParty/lua/lmathlib.c +++ b/src/3rdParty/lua/lmathlib.c @@ -352,7 +352,7 @@ static lua_Number I2d (Rand64 x) { SRand64 sx = (SRand64)(trim64(x) >> shift64_FIG); lua_Number res = (lua_Number)(sx) * scaleFIG; if (sx < 0) - res += 1.0; /* correct the two's complement if negative */ + res += l_mathop(1.0); /* correct the two's complement if negative */ lua_assert(0 <= res && res < 1); return res; } diff --git a/src/3rdParty/lua/loslib.c b/src/3rdParty/lua/loslib.c index ad5a927..ba80d72 100644 --- a/src/3rdParty/lua/loslib.c +++ b/src/3rdParty/lua/loslib.c @@ -155,6 +155,7 @@ static int os_execute (lua_State *L) { static int os_remove (lua_State *L) { const char *filename = luaL_checkstring(L, 1); + errno = 0; return luaL_fileresult(L, remove(filename) == 0, filename); } @@ -162,6 +163,7 @@ static int os_remove (lua_State *L) { static int os_rename (lua_State *L) { const char *fromname = luaL_checkstring(L, 1); const char *toname = luaL_checkstring(L, 2); + errno = 0; return luaL_fileresult(L, rename(fromname, toname) == 0, NULL); } diff --git a/src/3rdParty/lua/lstring.c b/src/3rdParty/lua/lstring.c index e921dd0..9775735 100644 --- a/src/3rdParty/lua/lstring.c +++ b/src/3rdParty/lua/lstring.c @@ -224,7 +224,7 @@ TString *luaS_newlstr (lua_State *L, const char *str, size_t l) { return internshrstr(L, str, l); else { TString *ts; - if (l_unlikely(l >= (MAX_SIZE - sizeof(TString))/sizeof(char))) + if (l_unlikely(l * sizeof(char) >= (MAX_SIZE - sizeof(TString)))) luaM_toobig(L); ts = luaS_createlngstrobj(L, l); memcpy(getlngstr(ts), str, l * sizeof(char)); diff --git a/src/3rdParty/lua/lua.h b/src/3rdParty/lua/lua.h index 040cc8e..f050dac 100644 --- a/src/3rdParty/lua/lua.h +++ b/src/3rdParty/lua/lua.h @@ -1,7 +1,7 @@ /* ** $Id: lua.h $ ** Lua - A Scripting Language -** Lua.org, PUC-Rio, Brazil (www.lua.org) +** Lua.org, PUC-Rio, Brazil (http://www.lua.org) ** See Copyright Notice at the end of this file */ @@ -13,19 +13,20 @@ #include -#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2023 Lua.org, PUC-Rio" -#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" - +#include "luaconf.h" -#define LUA_VERSION_MAJOR_N 5 -#define LUA_VERSION_MINOR_N 4 -#define LUA_VERSION_RELEASE_N 6 -#define LUA_VERSION_NUM (LUA_VERSION_MAJOR_N * 100 + LUA_VERSION_MINOR_N) -#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + LUA_VERSION_RELEASE_N) +#define LUA_VERSION_MAJOR "5" +#define LUA_VERSION_MINOR "4" +#define LUA_VERSION_RELEASE "7" +#define LUA_VERSION_NUM 504 +#define LUA_VERSION_RELEASE_NUM (LUA_VERSION_NUM * 100 + 7) -#include "luaconf.h" +#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR +#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE +#define LUA_COPYRIGHT LUA_RELEASE " Copyright (C) 1994-2024 Lua.org, PUC-Rio" +#define LUA_AUTHORS "R. Ierusalimschy, L. H. de Figueiredo, W. Celes" /* mark for precompiled code ('Lua') */ @@ -495,19 +496,8 @@ struct lua_Debug { /* }====================================================================== */ -#define LUAI_TOSTRAUX(x) #x -#define LUAI_TOSTR(x) LUAI_TOSTRAUX(x) - -#define LUA_VERSION_MAJOR LUAI_TOSTR(LUA_VERSION_MAJOR_N) -#define LUA_VERSION_MINOR LUAI_TOSTR(LUA_VERSION_MINOR_N) -#define LUA_VERSION_RELEASE LUAI_TOSTR(LUA_VERSION_RELEASE_N) - -#define LUA_VERSION "Lua " LUA_VERSION_MAJOR "." LUA_VERSION_MINOR -#define LUA_RELEASE LUA_VERSION "." LUA_VERSION_RELEASE - - /****************************************************************************** -* Copyright (C) 1994-2023 Lua.org, PUC-Rio. +* Copyright (C) 1994-2024 Lua.org, PUC-Rio. * * Permission is hereby granted, free of charge, to any person obtaining * a copy of this software and associated documentation files (the diff --git a/src/3rdParty/lua/luaconf.h b/src/3rdParty/lua/luaconf.h index acebe29..33bb580 100644 --- a/src/3rdParty/lua/luaconf.h +++ b/src/3rdParty/lua/luaconf.h @@ -261,7 +261,7 @@ /* ** LUA_IGMARK is a mark to ignore all after it when building the ** module name (e.g., used to build the luaopen_ function name). -** Typically, the sufix after the mark is the module version, +** Typically, the suffix after the mark is the module version, ** as in "mod-v1.2.so". */ #define LUA_IGMARK "-" diff --git a/src/3rdParty/lua/lundump.h b/src/3rdParty/lua/lundump.h index bc71ced..a97676c 100644 --- a/src/3rdParty/lua/lundump.h +++ b/src/3rdParty/lua/lundump.h @@ -21,7 +21,7 @@ /* ** Encode major-minor version in one byte, one nibble for each */ -#define LUAC_VERSION (LUA_VERSION_MAJOR_N*16+LUA_VERSION_MINOR_N) +#define LUAC_VERSION (((LUA_VERSION_NUM / 100) * 16) + LUA_VERSION_NUM % 100) #define LUAC_FORMAT 0 /* this is the official format */ diff --git a/src/3rdParty/lua/lvm.c b/src/3rdParty/lua/lvm.c index 4d71cff..fcd24e1 100644 --- a/src/3rdParty/lua/lvm.c +++ b/src/3rdParty/lua/lvm.c @@ -92,7 +92,7 @@ static int l_strton (const TValue *obj, TValue *result) { if (!cvt2num(obj)) /* is object not a string? */ return 0; else { - TString *st = tsvalue(obj); + TString *st = tsvalue(obj); return (luaO_str2num(getstr(st), result) == tsslen(st) + 1); } } @@ -661,7 +661,7 @@ void luaV_concat (lua_State *L, int total) { /* collect total length and number of strings */ for (n = 1; n < total && tostring(L, s2v(top - n - 1)); n++) { size_t l = tsslen(tsvalue(s2v(top - n - 1))); - if (l_unlikely(l >= (MAX_SIZE/sizeof(char)) - tl)) { + if (l_unlikely(l >= MAX_SIZE - sizeof(TString) - tl)) { L->top.p = top - total; /* pop strings to avoid wasting stack */ luaG_runerror(L, "string length overflow"); } diff --git a/src/yuescript/yue_ast.cpp b/src/yuescript/yue_ast.cpp index a454908..7f0dd07 100644 --- a/src/yuescript/yue_ast.cpp +++ b/src/yuescript/yue_ast.cpp @@ -490,7 +490,7 @@ std::string If_t::to_string(void* ud) const { std::string While_t::to_string(void* ud) const { auto info = reinterpret_cast(ud); str_list temp{ - type->to_string(ud) + ' ' + condition->to_string(ud)}; + type->to_string(ud) + ' ' + condition->to_string(ud) + (assignment ? assignment->to_string(ud) : std::string())}; if (body.is()) { temp.back() += " do "s + body->to_string(ud); } else { diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index 8063517..92d67ac 100644 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h @@ -337,8 +337,9 @@ AST_END(WhileType) AST_NODE(While) ast_ptr type; ast_ptr condition; + ast_ptr assignment; ast_sel body; - AST_MEMBER(While, &type, &condition, &body) + AST_MEMBER(While, &type, &condition, &assignment, &body) AST_END(While) AST_NODE(Repeat) diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index c29513e..77a4967 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp @@ -75,7 +75,7 @@ static std::unordered_set Metamethods = { "close"s // Lua 5.4 }; -const std::string_view version = "0.25.5"sv; +const std::string_view version = "0.25.6"sv; const std::string_view extension = "yue"sv; class CompileError : public std::logic_error { @@ -1585,7 +1585,8 @@ private: } goto metamethod53; } - case 504: { + case 504: + case 505: { if (name == "ipairs"sv) { throw CompileError("metamethod is not supported since Lua 5.4"sv, x); } @@ -5038,7 +5039,7 @@ private: #ifndef YUE_NO_MACRO return LUA_VERSION_NUM; #else - return 504; + return 505; #endif // YUE_NO_MACRO } @@ -8080,7 +8081,7 @@ private: } void addDoToLastLineReturn(ast_node* body) { - if (auto block = ast_cast(body); body && !block->statements.empty()) { + if (auto block = ast_cast(body); block && !block->statements.empty()) { auto last = static_cast(block->statements.back()); if (last->content.is()) { auto doNode = last->new_ptr(); @@ -10271,6 +10272,34 @@ private: } void transformWhile(While_t* whileNode, str_list& out) { + if (whileNode->assignment) { + auto x = whileNode; + auto repeat = x->new_ptr(); + repeat->condition.set(toAst("false"sv, x)); + auto ifNode = x->new_ptr(); + auto ifCond = x->new_ptr(); + bool isUntil = _parser.toString(whileNode->type) == "until"sv; + ifNode->type.set(toAst(isUntil ? "unless"sv : "if"sv, x)); + ifCond->condition.set(whileNode->condition); + ifCond->assignment.set(whileNode->assignment); + ifNode->nodes.push_back(ifCond); + ifNode->nodes.push_back(whileNode->body); + ifNode->nodes.push_back(toAst("break"sv, x)); + auto simpleValue = x->new_ptr(); + simpleValue->value.set(ifNode); + auto exp = newExp(simpleValue, x); + auto expList = x->new_ptr(); + expList->exprs.push_back(exp); + auto expListAssign = x->new_ptr(); + expListAssign->expList.set(expList); + auto stmt = x->new_ptr(); + stmt->content.set(expListAssign); + auto body = x->new_ptr(); + body->content.set(stmt); + repeat->body.set(body); + transformRepeat(repeat, out); + return; + } str_list temp; pushScope(); bool isUntil = _parser.toString(whileNode->type) == "until"sv; diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index d7af780..c917255 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp @@ -383,7 +383,7 @@ YueParser::YueParser() { If = IfType >> space >> IfCond >> space >> opt_body_with("then") >> *if_else_if >> -if_else; WhileType = (expr("while") | "until") >> not_alpha_num; - While = WhileType >> space >> disable_do_chain_arg_table_block_rule(Exp) >> space >> opt_body_with("do"); + While = WhileType >> space >> disable_do_chain_arg_table_block_rule(Exp >> -(space >> Assignment)) >> space >> opt_body_with("do"); Repeat = key("repeat") >> space >> Body >> line_break >> *space_break >> check_indent_match >> space >> key("until") >> space >> Exp; for_key = pl::user(key("for"), [](const item_t& item) { -- cgit v1.2.3-55-g6feb