diff --git a/spec/inputs/try_catch.yue b/spec/inputs/try_catch.yue index 419eef4..4e05bc6 100644 --- a/spec/inputs/try_catch.yue +++ b/spec/inputs/try_catch.yue @@ -20,6 +20,8 @@ f = -> success, result = try func 1, 2, 3 + tb = {} + try tb.func try tb.func! try tb.func() @@ -57,4 +59,9 @@ f = -> try func 1, 2, 3 + do + <- x + local tb, a, b, c + f = -> try tb.f a, b, c + nil diff --git a/spec/inputs/upvalue_func.yue b/spec/inputs/upvalue_func.yue index 159be76..d4b3273 100644 --- a/spec/inputs/upvalue_func.yue +++ b/spec/inputs/upvalue_func.yue @@ -210,6 +210,8 @@ do buff_strength = (char, item) -> item.buffer.strength? char.stats.strength?::ref() + local debug_env_before, debug_env_after + exe_func = (func, env) -> ok, ... = try debug_env_before(env) diff --git a/spec/outputs/5.1/attrib.lua b/spec/outputs/5.1/attrib.lua index 9cacd97..8361b24 100644 --- a/spec/outputs/5.1/attrib.lua +++ b/spec/outputs/5.1/attrib.lua @@ -199,7 +199,9 @@ do end }) local _close_2 = assert(getmetatable(_).__close) - return _anon_func_9(_, _close_2, error, pcall(print, "third")) + return _anon_func_9(_, _close_2, error, pcall(function() + return print("third") + end)) end)) end)) end diff --git a/spec/outputs/5.1/try_catch.lua b/spec/outputs/5.1/try_catch.lua index f63cd91..d4c80c1 100644 --- a/spec/outputs/5.1/try_catch.lua +++ b/spec/outputs/5.1/try_catch.lua @@ -1,9 +1,8 @@ -local _anon_func_0 = function(func, print) - print("trying") - return func(1, 2, 3) +local _anon_func_0 = function(tb) + return tb.func end local _anon_func_1 = function(tb) - return tb.func + return tb.func() end local _anon_func_2 = function(tb) return tb.func() @@ -12,16 +11,16 @@ local _anon_func_3 = function(tb) return tb.func() end local _anon_func_4 = function(tb) - return tb.func() + return tb:func(1, 2, 3) end local _anon_func_5 = function(tb) - return tb:func(1, 2, 3) + return tb.func(1) end local _anon_func_6 = function(tb) return tb.func(1) end -local _anon_func_7 = function(tb) - return tb.func(1) +local _anon_func_7 = function(a, b, c, tb) + return tb.f(a, b, c) end local f f = function() @@ -35,22 +34,28 @@ f = function() end, function(err) return print(err) end) - pcall(_anon_func_0, func, print) + pcall(function() + print("trying") + return func(1, 2, 3) + end) do local success, result = xpcall(function() return func(1, 2, 3) end, function(err) return print(err) end) - success, result = pcall(func, 1, 2, 3) + success, result = pcall(function() + return func(1, 2, 3) + end) end + local tb = { } + pcall(_anon_func_0, tb) pcall(_anon_func_1, tb) pcall(_anon_func_2, tb) pcall(_anon_func_3, tb) pcall(_anon_func_4, tb) pcall(_anon_func_5, tb) pcall(_anon_func_6, tb) - pcall(_anon_func_7, tb) if (xpcall(function() return func(1) end, function(err) @@ -67,7 +72,9 @@ f = function() end do do - local success, result = pcall(func, "abc", 123) + local success, result = pcall(function() + return func("abc", 123) + end) if success then print(result) end @@ -87,8 +94,20 @@ f = function() end end do - pcall(func, 1, 2, 3) - pcall(func, 1, 2, 3) + pcall(function() + return func(1, 2, 3) + end) + pcall(function() + return func(1, 2, 3) + end) + end + do + x(function() + local tb, a, b, c + f = function() + return pcall(_anon_func_7, a, b, c, tb) + end + end) end return nil end diff --git a/spec/outputs/codes_from_doc.lua b/spec/outputs/codes_from_doc.lua index b2ba836..6f61569 100644 --- a/spec/outputs/codes_from_doc.lua +++ b/spec/outputs/codes_from_doc.lua @@ -608,23 +608,33 @@ end):concat(Rx.Observable.of('who do we appreciate')):map(function(value) end):subscribe(print) local str = strA .. strB .. strC func(3000, "192.168.1.1") -xpcall(func, function(err) +xpcall(function() + return func(1, 2, 3) +end, function(err) return print(yue.traceback(err)) -end, 1, 2, 3) -local success, result = xpcall(func, function(err) +end) +local success, result = xpcall(function() + return func(1, 2, 3) +end, function(err) return yue.traceback(err) -end, 1, 2, 3) -xpcall(func, function(err) +end) +xpcall(function() + return func(1, 2, 3) +end, function(err) return print(yue.traceback(err)) -end, 1, 2, 3) -success, result = pcall(func, 1, 2, 3) +end) +success, result = pcall(function() + return func(1, 2, 3) +end) pcall(function() print("trying") return func(1, 2, 3) end) -success, result = xpcall(func, function(err) +success, result = xpcall(function() + return func(1, 2, 3) +end, function(err) return print(yue.traceback(err)) -end, 1, 2, 3) +end) if success then print(result) end @@ -2595,23 +2605,33 @@ end):concat(Rx.Observable.of('who do we appreciate')):map(function(value) end):subscribe(print) local str = strA .. strB .. strC func(3000, "192.168.1.1") -xpcall(func, function(err) +xpcall(function() + return func(1, 2, 3) +end, function(err) return print(yue.traceback(err)) -end, 1, 2, 3) -local success, result = xpcall(func, function(err) +end) +local success, result = xpcall(function() + return func(1, 2, 3) +end, function(err) return yue.traceback(err) -end, 1, 2, 3) -xpcall(func, function(err) +end) +xpcall(function() + return func(1, 2, 3) +end, function(err) return print(yue.traceback(err)) -end, 1, 2, 3) -success, result = pcall(func, 1, 2, 3) +end) +success, result = pcall(function() + return func(1, 2, 3) +end) pcall(function() print("trying") return func(1, 2, 3) end) -success, result = xpcall(func, function(err) +success, result = xpcall(function() + return func(1, 2, 3) +end, function(err) return print(yue.traceback(err)) -end, 1, 2, 3) +end) if success then print(result) end diff --git a/spec/outputs/codes_from_doc_zh.lua b/spec/outputs/codes_from_doc_zh.lua index 3f9615f..aa53926 100644 --- a/spec/outputs/codes_from_doc_zh.lua +++ b/spec/outputs/codes_from_doc_zh.lua @@ -608,23 +608,33 @@ end):concat(Rx.Observable.of('who do we appreciate')):map(function(value) end):subscribe(print) local str = strA .. strB .. strC func(3000, "192.168.1.1") -xpcall(func, function(err) +xpcall(function() + return func(1, 2, 3) +end, function(err) return print(yue.traceback(err)) -end, 1, 2, 3) -local success, result = xpcall(func, function(err) +end) +local success, result = xpcall(function() + return func(1, 2, 3) +end, function(err) return yue.traceback(err) -end, 1, 2, 3) -xpcall(func, function(err) +end) +xpcall(function() + return func(1, 2, 3) +end, function(err) return print(yue.traceback(err)) -end, 1, 2, 3) -success, result = pcall(func, 1, 2, 3) +end) +success, result = pcall(function() + return func(1, 2, 3) +end) pcall(function() print("尝试中") return func(1, 2, 3) end) -success, result = xpcall(func, function(err) +success, result = xpcall(function() + return func(1, 2, 3) +end, function(err) return print(yue.traceback(err)) -end, 1, 2, 3) +end) if success then print(result) end @@ -2589,23 +2599,33 @@ end):concat(Rx.Observable.of('who do we appreciate')):map(function(value) end):subscribe(print) local str = strA .. strB .. strC func(3000, "192.168.1.1") -xpcall(func, function(err) +xpcall(function() + return func(1, 2, 3) +end, function(err) return print(yue.traceback(err)) -end, 1, 2, 3) -local success, result = xpcall(func, function(err) +end) +local success, result = xpcall(function() + return func(1, 2, 3) +end, function(err) return yue.traceback(err) -end, 1, 2, 3) -xpcall(func, function(err) +end) +xpcall(function() + return func(1, 2, 3) +end, function(err) return print(yue.traceback(err)) -end, 1, 2, 3) -success, result = pcall(func, 1, 2, 3) +end) +success, result = pcall(function() + return func(1, 2, 3) +end) pcall(function() print("尝试中") return func(1, 2, 3) end) -success, result = xpcall(func, function(err) +success, result = xpcall(function() + return func(1, 2, 3) +end, function(err) return print(yue.traceback(err)) -end, 1, 2, 3) +end) if success then print(result) end diff --git a/spec/outputs/try_catch.lua b/spec/outputs/try_catch.lua index 3c3dd3c..d4c80c1 100644 --- a/spec/outputs/try_catch.lua +++ b/spec/outputs/try_catch.lua @@ -1,9 +1,8 @@ -local _anon_func_0 = function(func, print) - print("trying") - return func(1, 2, 3) +local _anon_func_0 = function(tb) + return tb.func end local _anon_func_1 = function(tb) - return tb.func + return tb.func() end local _anon_func_2 = function(tb) return tb.func() @@ -12,69 +11,103 @@ local _anon_func_3 = function(tb) return tb.func() end local _anon_func_4 = function(tb) - return tb.func() + return tb:func(1, 2, 3) end local _anon_func_5 = function(tb) - return tb:func(1, 2, 3) + return tb.func(1) end local _anon_func_6 = function(tb) return tb.func(1) end -local _anon_func_7 = function(tb) - return tb.func(1) +local _anon_func_7 = function(a, b, c, tb) + return tb.f(a, b, c) end local f f = function() - xpcall(func, function(err) + xpcall(function() + return func(1, 2, 3) + end, function(err) return print(err) - end, 1, 2, 3) - xpcall(func, function(err) + end) + xpcall(function() + return func(1, 2, 3) + end, function(err) return print(err) - end, 1, 2, 3) - pcall(_anon_func_0, func, print) + end) + pcall(function() + print("trying") + return func(1, 2, 3) + end) do - local success, result = xpcall(func, function(err) + local success, result = xpcall(function() + return func(1, 2, 3) + end, function(err) return print(err) - end, 1, 2, 3) - success, result = pcall(func, 1, 2, 3) + end) + success, result = pcall(function() + return func(1, 2, 3) + end) end + local tb = { } + pcall(_anon_func_0, tb) pcall(_anon_func_1, tb) pcall(_anon_func_2, tb) pcall(_anon_func_3, tb) pcall(_anon_func_4, tb) pcall(_anon_func_5, tb) pcall(_anon_func_6, tb) - pcall(_anon_func_7, tb) - if (xpcall(func, function(err) + if (xpcall(function() + return func(1) + end, function(err) return print(err) - end, 1)) then + end)) then print("OK") end - if xpcall((func), function(err) + if xpcall(function() + return func(1) + end, function(err) return print(err) - end, 1) then + end) then print("OK") end do do - local success, result = pcall(func, "abc", 123) + local success, result = pcall(function() + return func("abc", 123) + end) if success then print(result) end end - local success, result = xpcall(func, function(err) + local success, result = xpcall(function() + return func("abc", 123) + end, function(err) return print(err) - end, "abc", 123) - success, result = xpcall(func, function(err) + end) + success, result = xpcall(function() + return func("abc", 123) + end, function(err) return print(err) - end, "abc", 123) + end) if success then print(result) end end do - pcall(func, 1, 2, 3) - pcall(func, 1, 2, 3) + pcall(function() + return func(1, 2, 3) + end) + pcall(function() + return func(1, 2, 3) + end) + end + do + x(function() + local tb, a, b, c + f = function() + return pcall(_anon_func_7, a, b, c, tb) + end + end) end return nil end diff --git a/spec/outputs/unicode/try_catch.lua b/spec/outputs/unicode/try_catch.lua index 7d95f9b..22f29f9 100644 --- a/spec/outputs/unicode/try_catch.lua +++ b/spec/outputs/unicode/try_catch.lua @@ -1,18 +1,26 @@ -xpcall(_u51fd_u6570, function(_u9519_u8bef) +xpcall(function() + return _u51fd_u6570(1, 2, 3) +end, function(_u9519_u8bef) return _u6253_u5370(_u9519_u8bef) -end, 1, 2, 3) -xpcall(_u51fd_u6570, function(_u9519_u8bef) +end) +xpcall(function() + return _u51fd_u6570(1, 2, 3) +end, function(_u9519_u8bef) return _u6253_u5370(_u9519_u8bef) -end, 1, 2, 3) +end) pcall(function() _u6253_u5370("正在try") return _u51fd_u6570(1, 2, 3) end) do - local _u6210_u529f, _u7ed3_u679c = xpcall(_u51fd_u6570, function(_u9519_u8bef) + local _u6210_u529f, _u7ed3_u679c = xpcall(function() + return _u51fd_u6570(1, 2, 3) + end, function(_u9519_u8bef) return _u6253_u5370(_u9519_u8bef) - end, 1, 2, 3) - _u6210_u529f, _u7ed3_u679c = pcall(_u51fd_u6570, 1, 2, 3) + end) + _u6210_u529f, _u7ed3_u679c = pcall(function() + return _u51fd_u6570(1, 2, 3) + end) end pcall(function() return _u8868["函数"] @@ -36,35 +44,49 @@ end) pcall(function() return _u8868["函数"](1) end) -if (xpcall(_u51fd_u6570, function(_u9519_u8bef) +if (xpcall(function() + return _u51fd_u6570(1) +end, function(_u9519_u8bef) return _u6253_u5370(_u9519_u8bef) -end, 1)) then +end)) then _u6253_u5370("好的") end -if xpcall((_u51fd_u6570), function(_u9519_u8bef) +if xpcall(function() + return _u51fd_u6570(1) +end, function(_u9519_u8bef) return _u6253_u5370(_u9519_u8bef) -end, 1) then +end) then _u6253_u5370("好的") end do do - local _u6210_u529f, _u7ed3_u679c = pcall(_u51fd_u6570, "abc", 123) + local _u6210_u529f, _u7ed3_u679c = pcall(function() + return _u51fd_u6570("abc", 123) + end) if _u6210_u529f then _u6253_u5370(_u7ed3_u679c) end end - local _u6210_u529f, _u7ed3_u679c = xpcall(_u51fd_u6570, function(_u9519_u8bef) + local _u6210_u529f, _u7ed3_u679c = xpcall(function() + return _u51fd_u6570("abc", 123) + end, function(_u9519_u8bef) return _u6253_u5370(_u9519_u8bef) - end, "abc", 123) - _u6210_u529f, _u7ed3_u679c = xpcall(_u51fd_u6570, function(_u9519_u8bef) + end) + _u6210_u529f, _u7ed3_u679c = xpcall(function() + return _u51fd_u6570("abc", 123) + end, function(_u9519_u8bef) return _u6253_u5370(_u9519_u8bef) - end, "abc", 123) + end) if _u6210_u529f then _u6253_u5370(_u7ed3_u679c) end end do - pcall(_u51fd_u6570, 1, 2, 3) - pcall(_u51fd_u6570, 1, 2, 3) + pcall(function() + return _u51fd_u6570(1, 2, 3) + end) + pcall(function() + return _u51fd_u6570(1, 2, 3) + end) end return nil diff --git a/spec/outputs/upvalue_func.lua b/spec/outputs/upvalue_func.lua index 5113692..e66eefa 100644 --- a/spec/outputs/upvalue_func.lua +++ b/spec/outputs/upvalue_func.lua @@ -367,12 +367,7 @@ local _anon_func_18 = function(print, select, _arg_0, ...) end end end -local _anon_func_19 = function(print) - local a = 1 - print(a + nil) - return 1, 2, 3 -end -local _anon_func_20 = function(cond, i) +local _anon_func_19 = function(cond, i) local _accum_0 = { } local _len_0 = 1 while cond do @@ -382,7 +377,7 @@ local _anon_func_20 = function(cond, i) end return _accum_0 end -local _anon_func_21 = function(value) +local _anon_func_20 = function(value) if 1 == value then return 'a' elseif 2 == value then @@ -417,27 +412,31 @@ GameEngine:onUpdate(function(deltaTime) func(_anon_func_16(pairs, tb, tostring)) func(_anon_func_17(print)) do - _anon_func_18(print, select, pcall(_anon_func_19, print)) + _anon_func_18(print, select, pcall(function() + local a = 1 + print(a + nil) + return 1, 2, 3 + end)) end i = 1 - func(_anon_func_20(cond, i)) - return func(_anon_func_21(value)) + func(_anon_func_19(cond, i)) + return func(_anon_func_20(value)) end) -local _anon_func_22 = function(cond) +local _anon_func_21 = function(cond) if cond then return 998 else return "abc" end end -local _anon_func_23 = function(valueB) +local _anon_func_22 = function(valueB) if valueB ~= nil then return valueB else return 123 end end -local _anon_func_24 = function(tb) +local _anon_func_23 = function(tb) if tb ~= nil then local _obj_0 = tb.abc if _obj_0 ~= nil then @@ -451,7 +450,7 @@ local _anon_func_24 = function(tb) end return nil end -local _anon_func_26 = function(itemA, listA) +local _anon_func_25 = function(itemA, listA) for _index_0 = 1, #listA do if listA[_index_0] == itemA then return true @@ -459,17 +458,17 @@ local _anon_func_26 = function(itemA, listA) end return false end -local _anon_func_25 = function(itemA, listA, tb) +local _anon_func_24 = function(itemA, listA, tb) do local _call_0 = tb local _call_1 = _call_0["end"](_call_0) - return _call_1["🤣"](_call_1, 123 and (#listA > 0 and _anon_func_26(itemA, listA))) + return _call_1["🤣"](_call_1, 123 and (#listA > 0 and _anon_func_25(itemA, listA))) end end GameEngine:onEvent("SomeEvent", function() - return func(value + (_anon_func_22(cond)) + (_anon_func_23(valueB)) > _anon_func_24(tb) + _anon_func_25(itemA, listA, tb)) + return func(value + (_anon_func_21(cond)) + (_anon_func_22(valueB)) > _anon_func_23(tb) + _anon_func_24(itemA, listA, tb)) end) -local _anon_func_27 = function(UpdateScoreText, tostring, value) +local _anon_func_26 = function(UpdateScoreText, tostring, value) if value > 200 then UpdateScoreText("Win: " .. tostring(value)) return "done" @@ -480,7 +479,7 @@ local _anon_func_27 = function(UpdateScoreText, tostring, value) end GameEngine:schedule(function(deltaTime) local value = 123 - return func(_anon_func_27(UpdateScoreText, tostring, value)) + return func(_anon_func_26(UpdateScoreText, tostring, value)) end) GameEngine:schedule(function(deltaTime) local value = 123 @@ -496,14 +495,14 @@ GameEngine:schedule(function(deltaTime) end end)()) end) -local _anon_func_28 = function(char) +local _anon_func_27 = function(char) local _obj_0 = char.stats.strength if _obj_0 ~= nil then return _obj_0:ref() end return nil end -local _anon_func_29 = function(os, _arg_0, ...) +local _anon_func_28 = function(os, _arg_0, ...) do local ok = _arg_0 if ok then @@ -513,7 +512,7 @@ local _anon_func_29 = function(os, _arg_0, ...) end end end -local _anon_func_30 = function(debug_env_after, debug_env_before, env, func) +local _anon_func_29 = function(debug_env_after, debug_env_before, env, func) debug_env_before(env) func(env) return debug_env_after(env) @@ -523,13 +522,14 @@ do buff_strength = function(char, item) local _obj_0 = item.buffer.strength if _obj_0 ~= nil then - return _obj_0(_anon_func_28(char)) + return _obj_0(_anon_func_27(char)) end return nil end + local debug_env_before, debug_env_after local exe_func exe_func = function(func, env) - return _anon_func_29(os, xpcall(_anon_func_30, function(ex) + return _anon_func_28(os, xpcall(_anon_func_29, function(ex) error(ex) return ex end, debug_env_after, debug_env_before, env, func)) diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index c205031..7f6a042 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.23.4"sv; +const std::string_view version = "0.23.6"sv; const std::string_view extension = "yue"sv; class CompileError : public std::logic_error { @@ -577,6 +577,273 @@ class YueCompilerImpl { } } + bool isConstTableItem(ast_node* item) { + switch (item->get_id()) { + case id(): { + auto pair = static_cast(item); + if (pair->defVal) return false; + return isConstTableItem(pair->pair); + } + case id(): { + auto pair = static_cast(item); + if (pair->defVal) return false; + return isConstTableItem(pair->pair); + } + case id(): { + auto pair = static_cast(item); + if (pair->defVal) return false; + return isConstTableItem(pair->pair); + } + case id(): { + auto pair = static_cast(item); + if (pair->defVal) return false; + return isConstTableItem(pair->pair); + } + case id(): { + auto pair = static_cast(item); + if (pair->defVal) return false; + return isConstTableItem(pair->item); + } + case id(): { + auto pair = static_cast(item); + return isConstExp(pair); + } + case id(): { + auto pair = static_cast(item); + return isLocal(variableToString(pair->name)); + } + case id(): { + auto pair = static_cast(item); + if (auto exp = pair->key.as()) { + if (!isConstExp(exp)) { + return false; + } + } + if (auto exp = pair->value.as()) { + if (!isConstExp(exp)) { + return false; + } + } else if (auto tbBlock = pair->value.as()) { + if (!isConstTable(tbBlock)) { + return false; + } + } else { + return false; + } + return true; + } + case id(): { + auto pair = static_cast(item); + return isConstTable(pair); + } + case id(): { + auto pair = static_cast(item); + return isConstTable(pair); + break; + } + case id(): { + auto pair = static_cast(item); + return isLocal(variableToString(pair->name)); + } + case id(): { + auto pair = static_cast(item); + if (auto str = pair->key.as()) { + if (!ast_is(str)) { + return false; + } + } else if (auto exp = pair->key.as()) { + if (!isConstExp(exp)) { + return false; + } + } else if (pair->key.is()) { + return true; + } else { + return false; + } + if (auto exp = pair->value.as()) { + if (!isConstExp(exp)) { + return false; + } + } else if (auto tbBlock = pair->value.as()) { + if (!isConstTable(tbBlock)) { + return false; + } + } else { + return false; + } + return true; + } + } + return false; + } + + bool isConstTable(TableLit_t* tableLit) { + for (auto value : tableLit->values.objects()) { + if (!isConstTableItem(value)) { + return false; + } + } + return true; + } + + bool isConstTable(TableBlock_t* tableBlock) { + for (auto value : tableBlock->values.objects()) { + if (!isConstTableItem(value)) { + return false; + } + } + return true; + } + + bool isConstTable(SimpleTable_t* stable) { + for (auto value : stable->pairs.objects()) { + if (!isConstTableItem(value)) { + return false; + } + } + return true; + } + + bool isConstTable(TableBlockIndent_t* table) { + for (auto value : table->values.objects()) { + if (!isConstTableItem(value)) { + return false; + } + } + return true; + } + + bool isConstChainValue(ChainValue_t* value) { + auto var = singleVariableFrom(value, AccessType::None); + return isLocal(var); + } + + bool isConstUnaryValue(UnaryValue_t* value) { + if (value->ops.size() > 1) { + return false; + } + auto unaryStr = _parser.toString(value->ops.front()); + if (unaryStr == "-"sv) { + return value->value->item->get_by_path(); + } else if (unaryStr == "#"sv) { + return false; + } else if (unaryStr == "not"sv) { + return isConstValue(value->value); + } + return false; + } + + bool isConstNum(Value_t* value) { + return value->get_by_path(); + } + + bool isConstUnaryExp(UnaryExp_t* value) { + if (value->inExp) return false; + if (value->ops.size() == 0) { + if (value->expos.size() == 1) { + return isConstValue(static_cast(value->expos.front())); + } + for (auto expo : value->expos.objects()) { + if (!isConstNum(static_cast(expo))) { + return false; + } + } + return true; + } + if (value->ops.size() > 1) { + return false; + } + auto unaryStr = _parser.toString(value->ops.front()); + if (unaryStr == "-"sv) { + for (auto expo : value->expos.objects()) { + if (!isConstNum(static_cast(expo))) { + return false; + } + } + return true; + } else if (unaryStr == "#"sv) { + return false; + } else if (unaryStr == "not"sv) { + if (value->expos.size() == 1) { + return isConstValue(static_cast(value->expos.front())); + } + for (auto expo : value->expos.objects()) { + if (!isConstNum(static_cast(expo))) { + return false; + } + } + return true; + } + return false; + } + + bool isConstValue(Value_t* value) { + if (auto strNode = value->item.as()) { + switch (strNode->str->get_id()) { + case id(): + case id(): + return true; + case id(): + return false; + default: + YUEE("AST node mismatch", strNode->str); + return false; + } + } else if (auto chainValue = value->item.as()) { + return isConstChainValue(chainValue); + } else if (auto simpleValue = value->item.as()) { + if (ast_is(simpleValue->value.get())) { + return true; + } else if (auto uValue = simpleValue->value.as()) { + return isConstUnaryValue(uValue); + } else if (auto comp = simpleValue->value.as()) { + for (auto item : comp->items.objects()) { + if (auto ndef = ast_cast(item)) { + if (ndef->defVal) { + return false; + } + if (!isConstExp(ndef->item)) { + return false; + } + } else { + return false; + } + } + return true; + } else if (auto tableLit = simpleValue->value.as()) { + return isConstTable(tableLit); + } else { + return false; + } + } else if (auto simpleTable = value->item.as()) { + return isConstTable(simpleTable); + } + return false; + } + + bool isConstUnaryExps(const ast_list& list) { + if (list.size() > 1) { + return false; + } + if (!isConstUnaryExp(static_cast(list.front()))) { + return false; + } + return true; + } + + bool isConstExp(Exp_t* exp) { + if (exp->nilCoalesed) { + return false; + } + if (!isConstUnaryExps(exp->pipeExprs)) { + return false; + } + if (exp->opValues.empty()) { + return true; + } + return false; + } + void markVarConst(const std::string& name) { auto& scope = _scopes.back(); scope.vars->insert_or_assign(name, VarType::Const); @@ -3691,7 +3958,7 @@ class YueCompilerImpl { }) != traversal::Stop; } - std::optional> getUpValueFuncFromBlock(Block_t* block, str_list* ensureArgListInTheEnd) { + std::optional> getUpValueFuncFromBlock(Block_t* block, str_list* ensureArgListInTheEnd, bool noGlobalVarPassing) { if (_funcLevel <= 1) return std::nullopt; auto result = block->traverse([&](ast_node* node) { switch (node->get_id()) { @@ -3754,6 +4021,9 @@ class YueCompilerImpl { } else if (std::find(args.begin(), args.end(), global.name) == args.end()) { args.push_back(global.name); } + if (noGlobalVarPassing && !isLocal(global.name)) { + return std::nullopt; + } } } } @@ -3809,9 +4079,9 @@ class YueCompilerImpl { } - std::optional> upValueFuncFrom(Block_t* block, str_list* ensureArgListInTheEnd = nullptr) { + std::optional> upValueFuncFrom(Block_t* block, str_list* ensureArgListInTheEnd = nullptr, bool noGlobalVarPassing = false) { if (checkUpValueFuncAvailable(block)) { - return getUpValueFuncFromBlock(block, ensureArgListInTheEnd); + return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, noGlobalVarPassing); } return std::nullopt; } @@ -3826,7 +4096,7 @@ class YueCompilerImpl { auto stmt = exp->new_ptr(); stmt->content.set(returnNode); block->statements.push_back(stmt); - return getUpValueFuncFromBlock(block, ensureArgListInTheEnd); + return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, false); } return std::nullopt; } @@ -9135,23 +9405,47 @@ class YueCompilerImpl { BREAK_IF(var.empty()); tryFunc.set(expListAssign->expList->exprs.front()); BLOCK_END - } else { - auto tryExp = tryFunc.as(); - bool needWrap = singleVariableFrom(tryExp, AccessType::None).empty(); + } + if (auto tryExp = tryFunc.as()) { + bool wrapped = true; BLOCK_START auto value = singleValueFrom(tryExp); BREAK_IF(!value); auto chainValue = value->item.as(); BREAK_IF(!chainValue); BREAK_IF(!isChainValueCall(chainValue)); - auto tmpChain = chainValue->new_ptr(); - tmpChain->items.dup(chainValue->items); - tmpChain->items.pop_back(); - auto var = singleVariableFrom(tmpChain, AccessType::None); - BREAK_IF(var.empty()); - needWrap = false; + auto chainCaller = chainValue->new_ptr(); + chainCaller->items.dup(chainValue->items); + chainCaller->items.pop_back(); + BREAK_IF(!isConstChainValue(chainCaller)); + _ast_list* args = nullptr; + if (auto invoke = ast_cast(chainValue->items.back())) { + args = &invoke->args; + } else { + args = &(ast_to(chainValue->items.back())->args); + } + wrapped = false; + for (auto arg : args->objects()) { + switch (arg->get_id()) { + case id(): + if (isConstExp(static_cast(arg))) continue; + break; + case id(): + case id(): + continue; + case id(): + break; + case id(): + if (isConstTable(static_cast(arg))) continue; + break; + case id(): + if (isConstTable(static_cast(arg))) continue; + break; + } + wrapped = true; + } BLOCK_END - if (needWrap) { + if (wrapped) { auto expList = x->new_ptr(); expList->exprs.push_back(tryFunc); auto expListAssign = x->new_ptr(); @@ -9165,7 +9459,7 @@ class YueCompilerImpl { } if (auto tryBlock = tryFunc.as()) { if (getLuaTarget(tryBlock) >= 502 || !errHandler) { - if (auto result = upValueFuncFrom(tryBlock)) { + if (auto result = upValueFuncFrom(tryBlock, nullptr, true)) { auto [funcName, args] = std::move(*result); if (errHandler) { auto xpcall = toAst("xpcall()", x);