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. --- doc/docs/doc/README.md | 16 +++++++ doc/docs/zh/doc/README.md | 90 ++++++++++++++++++++++---------------- spec/inputs/loops.yue | 17 +++++++ spec/outputs/5.1/loops.lua | 49 +++++++++++++++++++++ spec/outputs/codes_from_doc.lua | 16 +++++++ spec/outputs/codes_from_doc_zh.lua | 16 +++++++ spec/outputs/loops.lua | 37 ++++++++++++++++ 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 +- 24 files changed, 332 insertions(+), 109 deletions(-) diff --git a/doc/docs/doc/README.md b/doc/docs/doc/README.md index f6aebfc..83d351f 100755 --- a/doc/docs/doc/README.md +++ b/doc/docs/doc/README.md @@ -1313,6 +1313,22 @@ print "OK" +### While Assignment + +You can also use if assignment in a while loop to get the value as the loop condition. +```moonscript +while byte := stream\read_one! + -- do something with the byte + print byte +``` + +
+while byte := stream\read_one!
+  -- do something with the byte
+  print byte
+
+
+ ## Varargs Assignment You can assign the results returned from a function to a varargs symbol `...`. And then access its content using the Lua way. diff --git a/doc/docs/zh/doc/README.md b/doc/docs/zh/doc/README.md index 871edd2..bc53075 100755 --- a/doc/docs/zh/doc/README.md +++ b/doc/docs/zh/doc/README.md @@ -1310,6 +1310,22 @@ print "好的" +### While 赋值 + +您可以在 while 循环中同样使用赋值来获取循环条件的值。 +```moonscript +while byte := stream\read_one! + -- 对 byte 做一些操作 + print byte +``` + +
+while byte := stream\read_one!
+  -- 对 byte 做一些操作
+  print byte
+
+
+ ## 可变参数赋值 您可以将函数返回的结果赋值给一个可变参数符号 `...`。然后使用Lua的方式访问其内容。 @@ -3550,7 +3566,7 @@ print i, k -- 这些已经被更新 月之脚本版本。 **签名:** -```tl +```lua version: string ``` @@ -3563,7 +3579,7 @@ version: string 当前平台的文件分隔符。 **签名:** -```tl +```lua dirsep: string ``` @@ -3576,7 +3592,7 @@ dirsep: string 编译模块代码缓存。 **签名:** -```tl +```lua yue_compiled: {string: string} ``` @@ -3589,7 +3605,7 @@ yue_compiled: {string: string} 月之脚本的编译函数。它将 Yuescript 代码编译为 Lua 代码。 **签名:** -```tl +```lua to_lua: function(code: string, config?: Config): --[[codes]] string | nil, --[[error]] string | nil, @@ -3620,7 +3636,7 @@ to_lua: function(code: string, config?: Config): 检查源文件是否存在的函数。可以覆盖该函数以自定义行为。 **签名:** -```tl +```lua file_exist: function(filename: string): boolean ``` @@ -3645,7 +3661,7 @@ file_exist: function(filename: string): boolean 读取源文件的函数。可以覆盖该函数以自定义行为。 **签名:** -```tl +```lua read_file: function(filename: string): string ``` @@ -3670,7 +3686,7 @@ read_file: function(filename: string): string 将 Yuescript 加载器插入到 Lua 包加载器(搜索器)中。 **签名:** -```tl +```lua insert_loader: function(pos?: integer): boolean ``` @@ -3695,7 +3711,7 @@ insert_loader: function(pos?: integer): boolean 从 Lua 包加载器(搜索器)中移除 Yuescript 加载器。 **签名:** -```tl +```lua remove_loader: function(): boolean ``` @@ -3714,7 +3730,7 @@ remove_loader: function(): boolean 将 Yuescript 代码字符串加载为一个函数。 **签名:** -```tl +```lua loadstring: function(input: string, chunkname: string, env: table, config?: Config): --[[loaded function]] nil | function(...: any): (any...), --[[error]] string | nil @@ -3745,7 +3761,7 @@ loadstring: function(input: string, chunkname: string, env: table, config?: Conf 将 Yuescript 代码字符串加载为一个函数。 **签名:** -```tl +```lua loadstring: function(input: string, chunkname: string, config?: Config): --[[loaded function]] nil | function(...: any): (any...), --[[error]] string | nil @@ -3775,7 +3791,7 @@ loadstring: function(input: string, chunkname: string, config?: Config): 将 Yuescript 代码字符串加载为一个函数。 **签名:** -```tl +```lua loadstring: function(input: string, config?: Config): --[[loaded function]] nil | function(...: any): (any...), --[[error]] string | nil @@ -3804,7 +3820,7 @@ loadstring: function(input: string, config?: Config): 将 Yuescript 代码文件加载为一个函数。 **签名:** -```tl +```lua loadfile: function(filename: string, env: table, config?: Config): nil | function(...: any): (any...), string | nil @@ -3834,7 +3850,7 @@ loadfile: function(filename: string, env: table, config?: Config): 将 Yuescript 代码文件加载为一个函数。 **签名:** -```tl +```lua loadfile: function(filename: string, config?: Config): nil | function(...: any): (any...), string | nil @@ -3863,7 +3879,7 @@ loadfile: function(filename: string, config?: Config): 将 Yuescript 代码文件加载为一个函数并执行。 **签名:** -```tl +```lua dofile: function(filename: string, env: table, config?: Config): any... ``` @@ -3890,7 +3906,7 @@ dofile: function(filename: string, env: table, config?: Config): any... 将 Yuescript 代码文件加载为一个函数并执行。 **签名:** -```tl +```lua dofile: function(filename: string, config?: Config): any... ``` @@ -3916,7 +3932,7 @@ dofile: function(filename: string, config?: Config): any... 将 Yuescript 模块名解析为文件路径。 **签名:** -```tl +```lua find_modulepath: function(name: string): string ``` @@ -3943,7 +3959,7 @@ find_modulepath: function(name: string): string 当发生错误时,将错误信息中的代码行号重写为 Yuescript 代码中的原始行号。 **签名:** -```tl +```lua pcall: function(f: function, ...: any): boolean, any... ``` @@ -3970,7 +3986,7 @@ pcall: function(f: function, ...: any): boolean, any... 如果模块是 Yuescript 模块且加载失败,则将错误信息中的代码行号重写为 Yuescript 代码中的原始行号。 **签名:** -```tl +```lua require: function(name: string): any... ``` @@ -3995,7 +4011,7 @@ require: function(name: string): any... 检查传递的值的内部结构,并打印值出它的字符串表示。 **签名:** -```tl +```lua p: function(...: any) ``` @@ -4014,7 +4030,7 @@ p: function(...: any) 当前编译器选项。 **签名:** -```tl +```lua options: Config.Options ``` @@ -4027,7 +4043,7 @@ options: Config.Options 重写堆栈跟踪中的行号为 Yuescript 代码中的原始行号的 traceback 函数。 **签名:** -```tl +```lua traceback: function(message: string): string ``` @@ -4052,7 +4068,7 @@ traceback: function(message: string): string 检查代码是否匹配指定的 AST。 **签名:** -```tl +```lua is_ast: function(astName: string, code: string): boolean ``` @@ -4078,7 +4094,7 @@ is_ast: function(astName: string, code: string): boolean AST 类型定义,带有名称、行、列和子节点。 **签名:** -```tl +```lua type AST = {string, integer, integer, any} ``` @@ -4091,7 +4107,7 @@ type AST = {string, integer, integer, any} 将代码转换为 AST。 **签名:** -```tl +```lua to_ast: function(code: string, flattenLevel?: number, astName?: string): --[[AST]] AST | nil, --[[error]] nil | string @@ -4114,7 +4130,7 @@ to_ast: function(code: string, flattenLevel?: number, astName?: string): 如果发生加载失败,则将错误信息中的代码行号重写为 Yuescript 代码中的原始行号。 **签名:** -```tl +```lua metamethod __call: function(self: yue, module: string): any... ``` @@ -4145,7 +4161,7 @@ metamethod __call: function(self: yue, module: string): any... 编译器是否应该收集代码中出现的全局变量。 **签名:** -```tl +```lua lint_global: boolean ``` @@ -4158,7 +4174,7 @@ lint_global: boolean 编译器是否应该对根层级的代码块进行隐式的表达式返回。 **签名:** -```tl +```lua implicit_return_root: boolean ``` @@ -4171,7 +4187,7 @@ implicit_return_root: boolean 编译器是否应该在编译后的代码中保留原始行号。 **签名:** -```tl +```lua reserve_line_number: boolean ``` @@ -4184,7 +4200,7 @@ reserve_line_number: boolean 编译器是否应该在编译后的代码中使用空格字符而不是制表符字符。 **签名:** -```tl +```lua space_over_tab: boolean ``` @@ -4197,7 +4213,7 @@ space_over_tab: boolean 编译器是否应该将要编译的代码视为当前正在编译的模块。仅供编译器内部使用。 **签名:** -```tl +```lua same_module: boolean ``` @@ -4210,7 +4226,7 @@ same_module: boolean 编译器错误消息是否应该包含行号偏移量。仅供编译器内部使用。 **签名:** -```tl +```lua line_offset: integer ``` @@ -4223,7 +4239,7 @@ line_offset: integer 目标 Lua 版本枚举。 **签名:** -```tl +```lua enum LuaTarget "5.1" "5.2" @@ -4242,7 +4258,7 @@ end 要传递给编译函数的额外选项。 **签名:** -```tl +```lua options: Options ``` @@ -4261,7 +4277,7 @@ options: Options 编译目标 Lua 版本。 **签名:** -```tl +```lua target: LuaTarget ``` @@ -4274,7 +4290,7 @@ target: LuaTarget 额外模块搜索路径。 **签名:** -```tl +```lua path: string ``` @@ -4287,7 +4303,7 @@ path: string 是否在回溯错误消息中输出代码块的局部变量。默认为 false。 **签名:** -```tl +```lua dump_locals: boolean ``` @@ -4300,7 +4316,7 @@ dump_locals: boolean 是否简化输出的错误消息。默认为 true。 **签名:** -```tl +```lua simplified: boolean ``` diff --git a/spec/inputs/loops.yue b/spec/inputs/loops.yue index 5cadbf0..c5b28b3 100644 --- a/spec/inputs/loops.yue +++ b/spec/inputs/loops.yue @@ -196,3 +196,20 @@ do print i continue print "abc" + +do + while byte := stream::read_one! + -- do something with the byte + continue if byte == 0 + print byte + +do + local func + while success, result := try func 1, 2, 3 + catch err + print err + print result + +do + until x := func 'a', b do + print "false expected" diff --git a/spec/outputs/5.1/loops.lua b/spec/outputs/5.1/loops.lua index cc019e0..57b19be 100644 --- a/spec/outputs/5.1/loops.lua +++ b/spec/outputs/5.1/loops.lua @@ -440,3 +440,52 @@ do end end end +do + repeat + local _cond_0 = false + local _continue_0 = false + repeat + local byte = stream:read_one() + if byte then + if byte == 0 then + _cond_0 = false + _continue_0 = true + break + end + print(byte) + else + break + end + _cond_0 = false + _continue_0 = true + until true + if not _continue_0 then + break + end + until _cond_0 +end +do + local func + repeat + local success, result = xpcall(function() + return func(1, 2, 3) + end, function(err) + return print(err) + end) + if success then + print(result) + else + break + end + until false +end +do + repeat + x = func('a', b) + if not x then + print("false expected") + else + break + end + until false +end diff --git a/spec/outputs/codes_from_doc.lua b/spec/outputs/codes_from_doc.lua index 4073056..e2bba8e 100644 --- a/spec/outputs/codes_from_doc.lua +++ b/spec/outputs/codes_from_doc.lua @@ -585,6 +585,14 @@ do end end print("OK") +repeat + local byte = stream:read_one() + if byte then + print(byte) + else + break + end +until false local list = { 1, 2, @@ -2583,6 +2591,14 @@ do end end print("OK") +repeat + local byte = stream:read_one() + if byte then + print(byte) + else + break + end +until false local list = { 1, 2, diff --git a/spec/outputs/codes_from_doc_zh.lua b/spec/outputs/codes_from_doc_zh.lua index f251450..4839525 100644 --- a/spec/outputs/codes_from_doc_zh.lua +++ b/spec/outputs/codes_from_doc_zh.lua @@ -585,6 +585,14 @@ do end end print("好的") +repeat + local byte = stream:read_one() + if byte then + print(byte) + else + break + end +until false local list = { 1, 2, @@ -2577,6 +2585,14 @@ do end end print("好的") +repeat + local byte = stream:read_one() + if byte then + print(byte) + else + break + end +until false local list = { 1, 2, diff --git a/spec/outputs/loops.lua b/spec/outputs/loops.lua index 40e27b9..8624d49 100644 --- a/spec/outputs/loops.lua +++ b/spec/outputs/loops.lua @@ -333,3 +333,40 @@ do ::_continue_11:: end end +do + repeat + local byte = stream:read_one() + if byte then + if byte == 0 then + goto _continue_13 + end + print(byte) + else + break + end + ::_continue_13:: + until false +end +do + local func + repeat + local success, result = xpcall(func, function(err) + return print(err) + end, 1, 2, 3) + if success then + print(result) + else + break + end + until false +end +do + repeat + x = func('a', b) + if not x then + print("false expected") + else + break + end + until false +end 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