From 0f5bdeaeba0f04e49c47f4a2be55b14185a7dfdd Mon Sep 17 00:00:00 2001 From: Li Jin Date: Tue, 26 Jul 2022 18:05:23 +0800 Subject: fix missing checks and issues related to destrucuring in if branches. --- spec/inputs/assign.yue | 50 ++++++++++- spec/inputs/cond.yue | 2 +- spec/inputs/global.yue | 4 +- spec/inputs/metatable.yue | 2 +- spec/inputs/using.yue | 7 ++ spec/outputs/assign.lua | 93 ++++++++++++++++++- spec/outputs/cond.lua | 2 +- spec/outputs/global.lua | 4 +- spec/outputs/metatable.lua | 2 +- spec/outputs/using.lua | 7 ++ src/yuescript/yue_compiler.cpp | 200 +++++++++++++++++++++++------------------ 11 files changed, 273 insertions(+), 100 deletions(-) diff --git a/spec/inputs/assign.yue b/spec/inputs/assign.yue index dac2ba3..d04bcb8 100644 --- a/spec/inputs/assign.yue +++ b/spec/inputs/assign.yue @@ -8,20 +8,20 @@ _ = -> a,b,c,d = 1,2,3,4 - hello[232], (5+5)[121], hello, x[99] = 100, 200, 300 + hello[232], (5+5)[121], hello, x[99] = 100, 200, 300, 400 joop = 12 joop = 2345 a, b = if hello - "hello" + "hello", nil else "nothing", "yeah" a, b = if hello - if yeah then "one", "two" else "mmhh" + if yeah then "one", "two" else "mmhh", nil else print "the other" "nothing", "yeah" @@ -31,3 +31,47 @@ c, d = 1, 2 if true x = (do f! 123) if f = getHandler! + +(using nil) <- _ + +a.# = do + print 123 + {} + +do + {a, b} = switch c + when "a" + tb + when "b" + f! + +a[] = if x + 1 +else + 2 + +do + a, b[] = if x + switch y + when 1 + f! + +do + a, {b} = if x + f! + else + 123, tb + +do + a, b[], c, d.add# = if x + switch y + when 1 + f! + elseif x2 + if y2 + f1! + else + print "hello" + do + print 123 + 1, f2! diff --git a/spec/inputs/cond.yue b/spec/inputs/cond.yue index 773ef91..9981e93 100644 --- a/spec/inputs/cond.yue +++ b/spec/inputs/cond.yue @@ -158,7 +158,7 @@ do ---------------- a = 12 -a,c,b = "cool" if something +a,c,b = "cool", nil, nil if something diff --git a/spec/inputs/global.yue b/spec/inputs/global.yue index 7d6cfde..59cf764 100644 --- a/spec/inputs/global.yue +++ b/spec/inputs/global.yue @@ -1,6 +1,6 @@ do - global a,b,c = 223, 343 + global a,b,c = 223, 343, nil global cool = "dad" do @@ -9,7 +9,7 @@ do do global a,b,c - a,b,c,d = "hello" + a,b,c,d = "hello", nil, nil, nil do diff --git a/spec/inputs/metatable.yue b/spec/inputs/metatable.yue index 7e9b4f2..86991c2 100644 --- a/spec/inputs/metatable.yue +++ b/spec/inputs/metatable.yue @@ -24,7 +24,7 @@ do x.abc, a.b.# = 123, {} func!.# = mt --, extra -a, b.c.#, d, e = 1, mt, "abc" +a, b.c.#, d, e = 1, mt, "abc", nil is_same = a.#.__index == a.index# diff --git a/spec/inputs/using.yue b/spec/inputs/using.yue index 9944b60..31afaab 100644 --- a/spec/inputs/using.yue +++ b/spec/inputs/using.yue @@ -20,3 +20,10 @@ _ = (a,e,f using a,b,c, hello) -> _ = (using nil) -> hello or= 2 + +do + a = {} + (using nil) <- _ + {x, y} = a + +nil diff --git a/spec/outputs/assign.lua b/spec/outputs/assign.lua index 628f763..c7f2e20 100644 --- a/spec/outputs/assign.lua +++ b/spec/outputs/assign.lua @@ -7,14 +7,14 @@ _ = function() local a, b, c a, b, c, d = 1, 2, 3, 4 local hello - hello[232], (5 + 5)[121], hello, x[99] = 100, 200, 300 + hello[232], (5 + 5)[121], hello, x[99] = 100, 200, 300, 400 joop = 12 end end local joop = 2345 local a, b if hello then - a, b = "hello" + a, b = "hello", nil else a, b = "nothing", "yeah" end @@ -22,7 +22,7 @@ if hello then if yeah then a, b = "one", "two" else - a, b = "mmhh" + a, b = "mmhh", nil end else print("the other") @@ -42,3 +42,90 @@ do end)()) end end +return _(function() + setmetatable(a, (function() + print(123) + return { } + end)()) + do + local a, b + if "a" == c then + do + local _obj_0 = tb + a, b = _obj_0[1], _obj_0[2] + end + elseif "b" == c then + do + local _obj_0 = f() + a, b = _obj_0[1], _obj_0[2] + end + end + end + if x then + a[#a + 1] = 1 + else + a[#a + 1] = 2 + end + do + local a + if x then + do + local _exp_0 = y + if 1 == _exp_0 then + do + local _obj_0, _obj_1 = f() + b[#b + 1] = _obj_1 + a = _obj_0 + end + end + end + end + end + do + local a + local b + if x then + do + local _obj_0, _obj_1 = f() + a = _obj_0 + b = _obj_1[1] + end + else + a = 123 + b = tb[1] + end + end + do + local a, c + if x then + do + local _exp_0 = y + if 1 == _exp_0 then + do + local _obj_0, _obj_1, _obj_2, _obj_3 = f() + b[#b + 1] = _obj_1 + a, c, getmetatable(d).__add = _obj_0, _obj_2, _obj_3 + end + end + end + elseif x2 then + if y2 then + do + local _obj_0, _obj_1, _obj_2, _obj_3 = f1() + b[#b + 1] = _obj_1 + a, c, getmetatable(d).__add = _obj_0, _obj_2, _obj_3 + end + end + else + print("hello") + do + print(123) + do + local _obj_0, _obj_1, _obj_2 = f2() + b[#b + 1] = _obj_0 + a, c, getmetatable(d).__add = 1, _obj_1, _obj_2 + end + end + end + end +end) diff --git a/spec/outputs/cond.lua b/spec/outputs/cond.lua index 178bf9b..7764439 100644 --- a/spec/outputs/cond.lua +++ b/spec/outputs/cond.lua @@ -251,7 +251,7 @@ end local a = 12 local c, b if something then - a, c, b = "cool" + a, c, b = "cool", nil, nil end local j if 1 then diff --git a/spec/outputs/global.lua b/spec/outputs/global.lua index ef73823..930ecf6 100644 --- a/spec/outputs/global.lua +++ b/spec/outputs/global.lua @@ -1,5 +1,5 @@ do - a, b, c = 223, 343 + a, b, c = 223, 343, nil cool = "dad" end do @@ -29,7 +29,7 @@ do end do local d - a, b, c, d = "hello" + a, b, c, d = "hello", nil, nil, nil end do local What diff --git a/spec/outputs/metatable.lua b/spec/outputs/metatable.lua index 2d72e1d..6f5ceed 100644 --- a/spec/outputs/metatable.lua +++ b/spec/outputs/metatable.lua @@ -66,7 +66,7 @@ setmetatable(a.b, { }) x.abc = 123 setmetatable(func(), mt) setmetatable(b.c, mt) -a, d, e = 1, "abc" +a, d, e = 1, "abc", nil local is_same = getmetatable(a).__index == getmetatable(a).__index setmetatable(a, { __index = tb diff --git a/spec/outputs/using.lua b/spec/outputs/using.lua index 6d0d888..ff23a30 100644 --- a/spec/outputs/using.lua +++ b/spec/outputs/using.lua @@ -21,3 +21,10 @@ end _ = function() local hello = hello or 2 end +do + local a = { }; + _(function() + local x, y = a[1], a[2] + end) +end +return nil diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 2a703d0..1a44832 100755 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp @@ -54,7 +54,7 @@ namespace yue { typedef std::list str_list; -const std::string_view version = "0.14.1"sv; +const std::string_view version = "0.14.2"sv; const std::string_view extension = "yue"sv; class YueCompilerImpl { @@ -1355,13 +1355,31 @@ private: } throw std::logic_error(_info.errorMessage(clearBuf(), values.front())); } + bool checkValuesLater = false; if (exprs.size() > values.size()) { BLOCK_START + switch (values.back()->getId()) { + case id(): + case id(): + checkValuesLater = true; + break; + } + BREAK_IF(checkValuesLater); auto value = singleValueFrom(values.back()); BREAK_IF(!value); + if (auto val = value->item.as()) { + switch (val->value->getId()) { + case id(): + case id(): + case id(): + case id(): + checkValuesLater = true; + break; + } + BREAK_IF(checkValuesLater); + } auto chainValue = value->item.as(); - BREAK_IF(!chainValue); - if (!ast_is(chainValue->items.back())) { + if (!chainValue || !ast_is(chainValue->items.back())) { _buf << exprs.size() << " right values expected, got "sv << values.size(); throw std::logic_error(_info.errorMessage(clearBuf(), values.front())); } @@ -1430,96 +1448,107 @@ private: return; BLOCK_END } - auto vit = values.begin(); - for (auto it = exprs.begin(); it != exprs.end(); ++it) { - BLOCK_START - auto value = singleValueFrom(*it); - BREAK_IF(!value); - auto chainValue = value->item.as(); - BREAK_IF(!chainValue); - str_list temp; - if (auto dot = ast_cast(chainValue->items.back())) { - BREAK_IF(!dot->name.is()); - str_list args; - chainValue->items.pop_back(); - if (chainValue->items.empty()) { - if (_withVars.empty()) { - throw std::logic_error(_info.errorMessage("short dot/colon syntax must be called within a with block"sv, x)); + if (!checkValuesLater) { + auto vit = values.begin(); + for (auto it = exprs.begin(); it != exprs.end(); ++it) { + BLOCK_START + auto value = singleValueFrom(*it); + BREAK_IF(!value); + auto chainValue = value->item.as(); + BREAK_IF(!chainValue); + str_list temp; + if (auto dot = ast_cast(chainValue->items.back())) { + BREAK_IF(!dot->name.is()); + str_list args; + auto tmpChain = chainValue->new_ptr(); + tmpChain->items.dup(chainValue->items); + tmpChain->items.pop_back(); + if (tmpChain->items.empty()) { + if (_withVars.empty()) { + throw std::logic_error(_info.errorMessage("short dot/colon syntax must be called within a with block"sv, x)); + } else { + args.push_back(_withVars.top()); + } } else { - args.push_back(_withVars.top()); + auto value = tmpChain->new_ptr(); + value->item.set(tmpChain); + transformExp(newExp(value, tmpChain), args, ExpUsage::Closure); } - } else { - transformExp(static_cast(*it), args, ExpUsage::Closure); - } - if (vit != values.end()) transformAssignItem(*vit, args); - else args.push_back("nil"s); - _buf << indent() << globalVar("setmetatable"sv, x) << '(' << join(args, ", "sv) << ')' << nll(x); - temp.push_back(clearBuf()); - } else if (ast_is(chainValue->items.back())) { - chainValue->items.pop_back(); - if (chainValue->items.empty()) { - if (_withVars.empty()) { - throw std::logic_error(_info.errorMessage("short table appending must be called within a with block"sv, x)); - } else { - chainValue->items.push_back(toAst(_withVars.top(), chainValue)); + if (vit == values.end()) { + throw std::logic_error(_info.errorMessage("right value missing"sv, values.front())); + } + transformAssignItem(*vit, args); + _buf << indent() << globalVar("setmetatable"sv, x) << '(' << join(args, ", "sv) << ')' << nll(x); + temp.push_back(clearBuf()); + } else if (ast_is(chainValue->items.back())) { + auto tmpChain = chainValue->new_ptr(); + tmpChain->items.dup(chainValue->items); + tmpChain->items.pop_back(); + if (tmpChain->items.empty()) { + if (_withVars.empty()) { + throw std::logic_error(_info.errorMessage("short table appending must be called within a with block"sv, x)); + } else { + tmpChain->items.push_back(toAst(_withVars.top(), chainValue)); + } + } + auto varName = singleVariableFrom(tmpChain); + bool isScoped = false; + if (varName.empty() || !isLocal(varName)) { + isScoped = true; + temp.push_back(indent() + "do"s + nll(x)); + pushScope(); + auto objVar = getUnusedName("_obj_"sv); + auto newAssignment = x->new_ptr(); + newAssignment->expList.set(toAst(objVar, x)); + auto assign = x->new_ptr(); + auto value = tmpChain->new_ptr(); + value->item.set(tmpChain); + assign->values.push_back(newExp(value, tmpChain)); + newAssignment->action.set(assign); + transformAssignment(newAssignment, temp); + varName = objVar; } - } - auto varName = singleVariableFrom(chainValue); - bool isScoped = false; - if (varName.empty() || !isLocal(varName)) { - isScoped = true; - temp.push_back(indent() + "do"s + nll(x)); - pushScope(); - auto objVar = getUnusedName("_obj_"sv); auto newAssignment = x->new_ptr(); - newAssignment->expList.set(toAst(objVar, x)); + newAssignment->expList.set(toAst(varName + "[#"s + varName + "+1]"s, x)); auto assign = x->new_ptr(); - assign->values.push_back(*it); + if (vit == values.end()) { + throw std::logic_error(_info.errorMessage("right value missing"sv, values.front())); + } + assign->values.push_back(*vit); newAssignment->action.set(assign); transformAssignment(newAssignment, temp); - varName = objVar; - } + if (isScoped) { + popScope(); + temp.push_back(indent() + "end"s + nlr(x)); + } + } else break; + auto newExpList = x->new_ptr(); + auto newAssign = x->new_ptr(); auto newAssignment = x->new_ptr(); - newAssignment->expList.set(toAst(varName + "[#"s + varName + "+1]"s, x)); - auto assign = x->new_ptr(); - if (vit != values.end()) { - assign->values.push_back(*vit); - } else { - assign->values.push_back(toAst("nil"sv, *vit)); + newAssignment->expList.set(newExpList); + newAssignment->action.set(newAssign); + for (auto exp : exprs) { + if (exp != *it) newExpList->exprs.push_back(exp); } - newAssignment->action.set(assign); - transformAssignment(newAssignment, temp); - if (isScoped) { - popScope(); - temp.push_back(indent() + "end"s + nlr(x)); + for (auto value : values) { + if (value != *vit) newAssign->values.push_back(value); } - } else break; - auto newExpList = x->new_ptr(); - auto newAssign = x->new_ptr(); - auto newAssignment = x->new_ptr(); - newAssignment->expList.set(newExpList); - newAssignment->action.set(newAssign); - for (auto exp : exprs) { - if (exp != *it) newExpList->exprs.push_back(exp); - } - for (auto value : values) { - if (value != *vit) newAssign->values.push_back(value); - } - if (newExpList->exprs.empty() && newAssign->values.empty()) { + if (newExpList->exprs.empty() && newAssign->values.empty()) { + out.push_back(join(temp)); + return; + } + if (newExpList->exprs.size() < newAssign->values.size()) { + auto exp = toAst("_"sv, x); + while (newExpList->exprs.size() < newAssign->values.size()) { + newExpList->exprs.push_back(exp); + } + } + transformAssignment(newAssignment, temp); out.push_back(join(temp)); return; + BLOCK_END + if (vit != values.end()) ++vit; } - if (newExpList->exprs.size() < newAssign->values.size()) { - auto exp = toAst("_"sv, x); - while (newExpList->exprs.size() < newAssign->values.size()) { - newExpList->exprs.push_back(exp); - } - } - transformAssignment(newAssignment, temp); - out.push_back(join(temp)); - return; - BLOCK_END - if (vit != values.end()) ++vit; } BREAK_IF(assign->values.objects().size() != 1); auto value = assign->values.objects().back(); @@ -1530,12 +1559,11 @@ private: } switch (value->getId()) { case id(): { - auto expList = assignment->expList.get(); - str_list temp; - auto defs = transformAssignDefs(expList, DefOp::Mark); - if (!defs.empty()) temp.push_back(toLocalDecl(defs) + nll(expList)); - transformIf(static_cast(value), temp, ExpUsage::Assignment, expList); - out.push_back(join(temp)); + auto ifNode = static_cast(value); + auto assignList = assignment->expList.get(); + std::string preDefine = getPreDefineLine(assignment); + transformIf(ifNode, out, ExpUsage::Assignment, assignList); + out.back().insert(0, preDefine); return; } case id(): { -- cgit v1.2.3-55-g6feb