diff options
| author | Li Jin <dragon-fly@qq.com> | 2021-10-31 17:29:45 +0800 |
|---|---|---|
| committer | Li Jin <dragon-fly@qq.com> | 2021-10-31 17:29:45 +0800 |
| commit | aed806476fe50899c0f01750175531ac41267b9d (patch) | |
| tree | c46f212a2987a9088b03e2c0225f18cd9a5d4265 | |
| parent | 60a979e224f26117f5be82bfca757a2483cef0fd (diff) | |
| download | yuescript-aed806476fe50899c0f01750175531ac41267b9d.tar.gz yuescript-aed806476fe50899c0f01750175531ac41267b9d.tar.bz2 yuescript-aed806476fe50899c0f01750175531ac41267b9d.zip | |
partially fix issue #69, fix a few case the generated code leaks some temp variables.
Diffstat (limited to '')
| -rw-r--r-- | spec/inputs/nil_coalesing.yue | 40 | ||||
| -rw-r--r-- | spec/outputs/export.lua | 32 | ||||
| -rw-r--r-- | spec/outputs/multiline_chain.lua | 12 | ||||
| -rw-r--r-- | spec/outputs/nil_coalesing.lua | 138 | ||||
| -rw-r--r-- | spec/outputs/switch.lua | 110 | ||||
| -rwxr-xr-x | src/yuescript/yue_ast.h | 3 | ||||
| -rwxr-xr-x | src/yuescript/yue_compiler.cpp | 255 | ||||
| -rwxr-xr-x | src/yuescript/yue_parser.cpp | 7 |
8 files changed, 490 insertions, 107 deletions
diff --git a/spec/inputs/nil_coalesing.yue b/spec/inputs/nil_coalesing.yue new file mode 100644 index 0000000..45b34f4 --- /dev/null +++ b/spec/inputs/nil_coalesing.yue | |||
| @@ -0,0 +1,40 @@ | |||
| 1 | do | ||
| 2 | a = b ?? c | ||
| 3 | |||
| 4 | do | ||
| 5 | :a = b ?? c | ||
| 6 | |||
| 7 | do | ||
| 8 | a = func! | ||
| 9 | a ??= false | ||
| 10 | |||
| 11 | do | ||
| 12 | a ??= func! | ||
| 13 | |||
| 14 | do | ||
| 15 | local a, b, c, d, e | ||
| 16 | a = b ?? c ?? d ?? e | ||
| 17 | |||
| 18 | do | ||
| 19 | a = b ?? c ?? d ?? e | ||
| 20 | |||
| 21 | do | ||
| 22 | func x ?? "hello" | ||
| 23 | |||
| 24 | do | ||
| 25 | with funcA! ?? funcB! | ||
| 26 | print .field | ||
| 27 | |||
| 28 | do | ||
| 29 | a = 1 + 2 + b ?? c + 3 + 4 | ||
| 30 | |||
| 31 | do | ||
| 32 | a = 1 + 2 + (b ?? c) + 3 + 4 | ||
| 33 | |||
| 34 | do | ||
| 35 | :a, :b = func! | ||
| 36 | a or= 1 | ||
| 37 | b ??= c ?? 2 | ||
| 38 | |||
| 39 | nil | ||
| 40 | |||
diff --git a/spec/outputs/export.lua b/spec/outputs/export.lua index 02546ec..4d81cc0 100644 --- a/spec/outputs/export.lua +++ b/spec/outputs/export.lua | |||
| @@ -65,22 +65,26 @@ y = function() | |||
| 65 | local k = 100 | 65 | local k = 100 |
| 66 | end | 66 | end |
| 67 | _module_0["y"] = y | 67 | _module_0["y"] = y |
| 68 | local _exp_0 = h | 68 | do |
| 69 | if 100 == _exp_0 or 150 == _exp_0 then | 69 | local _exp_0 = h |
| 70 | _module_0[#_module_0 + 1] = 200 | 70 | if 100 == _exp_0 or 150 == _exp_0 then |
| 71 | elseif 200 == _exp_0 then | 71 | _module_0[#_module_0 + 1] = 200 |
| 72 | _module_0[#_module_0 + 1] = 300 | 72 | elseif 200 == _exp_0 then |
| 73 | else | 73 | _module_0[#_module_0 + 1] = 300 |
| 74 | _module_0[#_module_0 + 1] = 0 | 74 | else |
| 75 | _module_0[#_module_0 + 1] = 0 | ||
| 76 | end | ||
| 75 | end | 77 | end |
| 76 | local Constant | 78 | local Constant |
| 77 | local _exp_1 = value | 79 | do |
| 78 | if "good" == _exp_1 then | 80 | local _exp_0 = value |
| 79 | Constant = 1 | 81 | if "good" == _exp_0 then |
| 80 | elseif "better" == _exp_1 then | 82 | Constant = 1 |
| 81 | Constant = 2 | 83 | elseif "better" == _exp_0 then |
| 82 | elseif "best" == _exp_1 then | 84 | Constant = 2 |
| 83 | Constant = 3 | 85 | elseif "best" == _exp_0 then |
| 86 | Constant = 3 | ||
| 87 | end | ||
| 84 | end | 88 | end |
| 85 | _module_0["Constant"] = Constant | 89 | _module_0["Constant"] = Constant |
| 86 | local item = func(123) | 90 | local item = func(123) |
diff --git a/spec/outputs/multiline_chain.lua b/spec/outputs/multiline_chain.lua index fea7bc6..ecd2ca8 100644 --- a/spec/outputs/multiline_chain.lua +++ b/spec/outputs/multiline_chain.lua | |||
| @@ -56,11 +56,13 @@ do | |||
| 56 | _with_0:callMethod():chainCall() | 56 | _with_0:callMethod():chainCall() |
| 57 | _with_0:callMethod():chainCall() | 57 | _with_0:callMethod():chainCall() |
| 58 | _with_0:chainCall() | 58 | _with_0:chainCall() |
| 59 | local _exp_0 = _with_0.itemFieldB:getValue() | 59 | do |
| 60 | if "Valid" == _exp_0 or _with_0:getItemState() == _exp_0 then | 60 | local _exp_0 = _with_0.itemFieldB:getValue() |
| 61 | _with_0:itemMethodA():getValue() | 61 | if "Valid" == _exp_0 or _with_0:getItemState() == _exp_0 then |
| 62 | else | 62 | _with_0:itemMethodA():getValue() |
| 63 | _with_0:itemMethodB():getValue() | 63 | else |
| 64 | _with_0:itemMethodB():getValue() | ||
| 65 | end | ||
| 64 | end | 66 | end |
| 65 | local a | 67 | local a |
| 66 | if _with_0.itemFieldC then | 68 | if _with_0.itemFieldC then |
diff --git a/spec/outputs/nil_coalesing.lua b/spec/outputs/nil_coalesing.lua new file mode 100644 index 0000000..36a6644 --- /dev/null +++ b/spec/outputs/nil_coalesing.lua | |||
| @@ -0,0 +1,138 @@ | |||
| 1 | do | ||
| 2 | local a | ||
| 3 | do | ||
| 4 | local _exp_0 = b | ||
| 5 | if _exp_0 ~= nil then | ||
| 6 | a = _exp_0 | ||
| 7 | else | ||
| 8 | a = c | ||
| 9 | end | ||
| 10 | end | ||
| 11 | end | ||
| 12 | do | ||
| 13 | local a | ||
| 14 | do | ||
| 15 | local _exp_0 = b | ||
| 16 | if _exp_0 ~= nil then | ||
| 17 | a = _exp_0.a | ||
| 18 | else | ||
| 19 | a = c.a | ||
| 20 | end | ||
| 21 | end | ||
| 22 | end | ||
| 23 | do | ||
| 24 | local a = func() | ||
| 25 | if a == nil then | ||
| 26 | a = false | ||
| 27 | end | ||
| 28 | end | ||
| 29 | do | ||
| 30 | local a | ||
| 31 | if a == nil then | ||
| 32 | a = func() | ||
| 33 | end | ||
| 34 | end | ||
| 35 | do | ||
| 36 | local a, b, c, d, e | ||
| 37 | if b ~= nil then | ||
| 38 | a = b | ||
| 39 | else | ||
| 40 | if c ~= nil then | ||
| 41 | a = c | ||
| 42 | else | ||
| 43 | if d ~= nil then | ||
| 44 | a = d | ||
| 45 | else | ||
| 46 | a = e | ||
| 47 | end | ||
| 48 | end | ||
| 49 | end | ||
| 50 | end | ||
| 51 | do | ||
| 52 | local a | ||
| 53 | do | ||
| 54 | local _exp_0 = b | ||
| 55 | if _exp_0 ~= nil then | ||
| 56 | a = _exp_0 | ||
| 57 | else | ||
| 58 | do | ||
| 59 | local _exp_1 = c | ||
| 60 | if _exp_1 ~= nil then | ||
| 61 | a = _exp_1 | ||
| 62 | else | ||
| 63 | do | ||
| 64 | local _exp_2 = d | ||
| 65 | if _exp_2 ~= nil then | ||
| 66 | a = _exp_2 | ||
| 67 | else | ||
| 68 | a = e | ||
| 69 | end | ||
| 70 | end | ||
| 71 | end | ||
| 72 | end | ||
| 73 | end | ||
| 74 | end | ||
| 75 | end | ||
| 76 | do | ||
| 77 | func((function() | ||
| 78 | local _exp_0 = x | ||
| 79 | if _exp_0 ~= nil then | ||
| 80 | return _exp_0 | ||
| 81 | else | ||
| 82 | return "hello" | ||
| 83 | end | ||
| 84 | end)()) | ||
| 85 | end | ||
| 86 | do | ||
| 87 | do | ||
| 88 | local _with_0 | ||
| 89 | do | ||
| 90 | local _exp_0 = funcA() | ||
| 91 | if _exp_0 ~= nil then | ||
| 92 | _with_0 = _exp_0 | ||
| 93 | else | ||
| 94 | _with_0 = funcB() | ||
| 95 | end | ||
| 96 | end | ||
| 97 | print(_with_0.field) | ||
| 98 | end | ||
| 99 | end | ||
| 100 | do | ||
| 101 | local a = 1 + 2 + (function() | ||
| 102 | local _exp_0 = b | ||
| 103 | if _exp_0 ~= nil then | ||
| 104 | return _exp_0 | ||
| 105 | else | ||
| 106 | return c + 3 + 4 | ||
| 107 | end | ||
| 108 | end)() | ||
| 109 | end | ||
| 110 | do | ||
| 111 | local a = 1 + 2 + ((function() | ||
| 112 | local _exp_0 = b | ||
| 113 | if _exp_0 ~= nil then | ||
| 114 | return _exp_0 | ||
| 115 | else | ||
| 116 | return c | ||
| 117 | end | ||
| 118 | end)()) + 3 + 4 | ||
| 119 | end | ||
| 120 | do | ||
| 121 | local a, b | ||
| 122 | do | ||
| 123 | local _obj_0 = func() | ||
| 124 | a, b = _obj_0.a, _obj_0.b | ||
| 125 | end | ||
| 126 | a = a or 1 | ||
| 127 | if b == nil then | ||
| 128 | do | ||
| 129 | local _exp_0 = c | ||
| 130 | if _exp_0 ~= nil then | ||
| 131 | b = _exp_0 | ||
| 132 | else | ||
| 133 | b = 2 | ||
| 134 | end | ||
| 135 | end | ||
| 136 | end | ||
| 137 | end | ||
| 138 | return nil | ||
diff --git a/spec/outputs/switch.lua b/spec/outputs/switch.lua index 1c8839f..81f6d5a 100644 --- a/spec/outputs/switch.lua +++ b/spec/outputs/switch.lua | |||
| @@ -1,70 +1,86 @@ | |||
| 1 | local _exp_0 = value | 1 | do |
| 2 | if "cool" == _exp_0 then | 2 | local _exp_0 = value |
| 3 | print("hello world") | 3 | if "cool" == _exp_0 then |
| 4 | print("hello world") | ||
| 5 | end | ||
| 4 | end | 6 | end |
| 5 | local _exp_1 = value | 7 | do |
| 6 | if "cool" == _exp_1 then | 8 | local _exp_0 = value |
| 7 | print("hello world") | 9 | if "cool" == _exp_0 then |
| 8 | else | 10 | print("hello world") |
| 9 | print("okay rad") | 11 | else |
| 12 | print("okay rad") | ||
| 13 | end | ||
| 10 | end | 14 | end |
| 11 | local _exp_2 = value | 15 | do |
| 12 | if "cool" == _exp_2 then | 16 | local _exp_0 = value |
| 13 | print("hello world") | 17 | if "cool" == _exp_0 then |
| 14 | elseif "yeah" == _exp_2 then | 18 | print("hello world") |
| 15 | local _ = [[FFFF]] + [[MMMM]] | 19 | elseif "yeah" == _exp_0 then |
| 16 | elseif (2323 + 32434) == _exp_2 then | 20 | local _ = [[FFFF]] + [[MMMM]] |
| 17 | print("okay") | 21 | elseif (2323 + 32434) == _exp_0 then |
| 18 | else | 22 | print("okay") |
| 19 | print("okay rad") | 23 | else |
| 24 | print("okay rad") | ||
| 25 | end | ||
| 20 | end | 26 | end |
| 21 | local out | 27 | local out |
| 22 | local _exp_3 = value | 28 | do |
| 23 | if "cool" == _exp_3 then | 29 | local _exp_0 = value |
| 24 | out = print("hello world") | 30 | if "cool" == _exp_0 then |
| 25 | else | 31 | out = print("hello world") |
| 26 | out = print("okay rad") | 32 | else |
| 33 | out = print("okay rad") | ||
| 34 | end | ||
| 27 | end | 35 | end |
| 28 | local _exp_4 = value | 36 | do |
| 29 | if "cool" == _exp_4 then | 37 | local _exp_0 = value |
| 30 | out = xxxx | 38 | if "cool" == _exp_0 then |
| 31 | elseif "umm" == _exp_4 then | 39 | out = xxxx |
| 32 | out = 34340 | 40 | elseif "umm" == _exp_0 then |
| 33 | else | 41 | out = 34340 |
| 34 | out = error("this failed big time") | 42 | else |
| 43 | out = error("this failed big time") | ||
| 44 | end | ||
| 35 | end | 45 | end |
| 36 | do | 46 | do |
| 37 | local _with_0 = something | 47 | local _with_0 = something |
| 38 | local _exp_5 = _with_0:value() | 48 | do |
| 39 | if _with_0.okay == _exp_5 then | 49 | local _exp_0 = _with_0:value() |
| 40 | local _ = "world" | 50 | if _with_0.okay == _exp_0 then |
| 41 | else | 51 | local _ = "world" |
| 42 | local _ = "yesh" | 52 | else |
| 53 | local _ = "yesh" | ||
| 54 | end | ||
| 43 | end | 55 | end |
| 44 | end | 56 | end |
| 45 | fix(this) | 57 | fix(this) |
| 46 | call_func((function() | 58 | call_func((function() |
| 47 | local _exp_5 = something | 59 | local _exp_0 = something |
| 48 | if 1 == _exp_5 then | 60 | if 1 == _exp_0 then |
| 49 | return "yes" | 61 | return "yes" |
| 50 | else | 62 | else |
| 51 | return "no" | 63 | return "no" |
| 52 | end | 64 | end |
| 53 | end)()) | 65 | end)()) |
| 54 | local _exp_5 = hi | 66 | do |
| 55 | if (hello or world) == _exp_5 then | 67 | local _exp_0 = hi |
| 56 | local _ = greene | 68 | if (hello or world) == _exp_0 then |
| 69 | local _ = greene | ||
| 70 | end | ||
| 57 | end | 71 | end |
| 58 | local _exp_6 = hi | 72 | do |
| 59 | if "one" == _exp_6 or "two" == _exp_6 then | 73 | local _exp_0 = hi |
| 60 | print("cool") | 74 | if "one" == _exp_0 or "two" == _exp_0 then |
| 61 | elseif "dad" == _exp_6 then | 75 | print("cool") |
| 62 | local _ = no | 76 | elseif "dad" == _exp_0 then |
| 77 | local _ = no | ||
| 78 | end | ||
| 63 | end | 79 | end |
| 64 | local _exp_7 = hi | 80 | local _exp_0 = hi |
| 65 | if (3 + 1) == _exp_7 or hello() == _exp_7 or (function() | 81 | if (3 + 1) == _exp_0 or hello() == _exp_0 or (function() |
| 66 | return 4 | 82 | return 4 |
| 67 | end)() == _exp_7 then | 83 | end)() == _exp_0 then |
| 68 | return yello | 84 | return yello |
| 69 | else | 85 | else |
| 70 | return print("cool") | 86 | return print("cool") |
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index 38da1fa..719b1cd 100755 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h | |||
| @@ -404,7 +404,8 @@ AST_NODE(Exp) | |||
| 404 | ast_ptr<true, Seperator_t> sep; | 404 | ast_ptr<true, Seperator_t> sep; |
| 405 | ast_list<true, unary_exp_t> pipeExprs; | 405 | ast_list<true, unary_exp_t> pipeExprs; |
| 406 | ast_list<false, exp_op_value_t> opValues; | 406 | ast_list<false, exp_op_value_t> opValues; |
| 407 | AST_MEMBER(Exp, &sep, &pipeExprs, &opValues) | 407 | ast_ptr<false, Exp_t> nilCoalesed; |
| 408 | AST_MEMBER(Exp, &sep, &pipeExprs, &opValues, &nilCoalesed) | ||
| 408 | AST_END(Exp) | 409 | AST_END(Exp) |
| 409 | 410 | ||
| 410 | class Parens_t; | 411 | class Parens_t; |
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 3ff032c..415fcd3 100755 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp | |||
| @@ -856,6 +856,10 @@ private: | |||
| 856 | return exp->opValues.empty() && exp->pipeExprs.size() > 1; | 856 | return exp->opValues.empty() && exp->pipeExprs.size() > 1; |
| 857 | } | 857 | } |
| 858 | 858 | ||
| 859 | bool isPureNilCoalesed(Exp_t* exp) const { | ||
| 860 | return exp->nilCoalesed && exp->opValues.empty(); | ||
| 861 | } | ||
| 862 | |||
| 859 | bool isMacroChain(ChainValue_t* chainValue) const { | 863 | bool isMacroChain(ChainValue_t* chainValue) const { |
| 860 | const auto& chainList = chainValue->items.objects(); | 864 | const auto& chainList = chainValue->items.objects(); |
| 861 | BLOCK_START | 865 | BLOCK_START |
| @@ -1345,6 +1349,10 @@ private: | |||
| 1345 | auto expList = assignment->expList.get(); | 1349 | auto expList = assignment->expList.get(); |
| 1346 | transformExp(exp, out, ExpUsage::Assignment, expList); | 1350 | transformExp(exp, out, ExpUsage::Assignment, expList); |
| 1347 | return; | 1351 | return; |
| 1352 | } else if (isPureNilCoalesed(exp)) { | ||
| 1353 | auto expList = assignment->expList.get(); | ||
| 1354 | transformNilCoalesedExp(exp, out, ExpUsage::Assignment, expList); | ||
| 1355 | return; | ||
| 1348 | } | 1356 | } |
| 1349 | auto singleVal = singleValueFrom(exp); | 1357 | auto singleVal = singleValueFrom(exp); |
| 1350 | BREAK_IF(!singleVal); | 1358 | BREAK_IF(!singleVal); |
| @@ -2020,12 +2028,12 @@ private: | |||
| 2020 | auto var = singleVariableFrom(exp); | 2028 | auto var = singleVariableFrom(exp); |
| 2021 | BREAK_IF(!var.empty()); | 2029 | BREAK_IF(!var.empty()); |
| 2022 | auto upVar = getUnusedName("_update_"sv); | 2030 | auto upVar = getUnusedName("_update_"sv); |
| 2023 | auto assignment = x->new_ptr<ExpListAssign_t>(); | 2031 | auto newAssignment = x->new_ptr<ExpListAssign_t>(); |
| 2024 | assignment->expList.set(toAst<ExpList_t>(upVar, x)); | 2032 | newAssignment->expList.set(toAst<ExpList_t>(upVar, x)); |
| 2025 | auto assign = x->new_ptr<Assign_t>(); | 2033 | auto assign = x->new_ptr<Assign_t>(); |
| 2026 | assign->values.push_back(exp); | 2034 | assign->values.push_back(exp); |
| 2027 | assignment->action.set(assign); | 2035 | newAssignment->action.set(assign); |
| 2028 | transformAssignment(assignment, temp); | 2036 | transformAssignment(newAssignment, temp); |
| 2029 | tmpChain->items.push_back(toAst<Exp_t>(upVar, x)); | 2037 | tmpChain->items.push_back(toAst<Exp_t>(upVar, x)); |
| 2030 | itemAdded = true; | 2038 | itemAdded = true; |
| 2031 | BLOCK_END | 2039 | BLOCK_END |
| @@ -2034,6 +2042,17 @@ private: | |||
| 2034 | chain->items.clear(); | 2042 | chain->items.clear(); |
| 2035 | chain->items.dup(tmpChain->items); | 2043 | chain->items.dup(tmpChain->items); |
| 2036 | } | 2044 | } |
| 2045 | auto op = _parser.toString(update->op); | ||
| 2046 | if (op == "??"sv) { | ||
| 2047 | auto defs = getPredefine(assignment); | ||
| 2048 | auto rightExp = x->new_ptr<Exp_t>(); | ||
| 2049 | rightExp->pipeExprs.dup(leftExp->pipeExprs); | ||
| 2050 | rightExp->opValues.dup(leftExp->opValues); | ||
| 2051 | rightExp->nilCoalesed.set(update->value); | ||
| 2052 | transformNilCoalesedExp(rightExp, out, ExpUsage::Assignment, assignment->expList, true); | ||
| 2053 | if (!defs.empty()) out.back().insert(0, defs + nll(x)); | ||
| 2054 | return; | ||
| 2055 | } | ||
| 2037 | auto defs = getPredefine(assignment); | 2056 | auto defs = getPredefine(assignment); |
| 2038 | transformValue(leftValue, temp); | 2057 | transformValue(leftValue, temp); |
| 2039 | auto left = std::move(temp.back()); | 2058 | auto left = std::move(temp.back()); |
| @@ -2048,7 +2067,7 @@ private: | |||
| 2048 | if (!defs.empty()) _buf << defs; | 2067 | if (!defs.empty()) _buf << defs; |
| 2049 | else _buf << indent() << left; | 2068 | else _buf << indent() << left; |
| 2050 | _buf << " = "sv << left << | 2069 | _buf << " = "sv << left << |
| 2051 | ' ' << _parser.toString(update->op) << ' ' << right << nll(assignment); | 2070 | ' ' << op << ' ' << right << nll(assignment); |
| 2052 | out.push_back(clearBuf()); | 2071 | out.push_back(clearBuf()); |
| 2053 | break; | 2072 | break; |
| 2054 | } | 2073 | } |
| @@ -2142,10 +2161,10 @@ private: | |||
| 2142 | str_list temp; | 2161 | str_list temp; |
| 2143 | std::string* funcStart = nullptr; | 2162 | std::string* funcStart = nullptr; |
| 2144 | if (usage == ExpUsage::Closure) { | 2163 | if (usage == ExpUsage::Closure) { |
| 2164 | _enableReturn.push(true); | ||
| 2145 | pushAnonVarArg(); | 2165 | pushAnonVarArg(); |
| 2146 | funcStart = &temp.emplace_back(); | 2166 | funcStart = &temp.emplace_back(); |
| 2147 | pushScope(); | 2167 | pushScope(); |
| 2148 | _enableReturn.push(true); | ||
| 2149 | } | 2168 | } |
| 2150 | std::list<std::pair<IfCond_t*, ast_node*>> ifCondPairs; | 2169 | std::list<std::pair<IfCond_t*, ast_node*>> ifCondPairs; |
| 2151 | ifCondPairs.emplace_back(); | 2170 | ifCondPairs.emplace_back(); |
| @@ -2255,11 +2274,11 @@ private: | |||
| 2255 | temp.push_back(indent() + "end"s + nlr(nodes.front())); | 2274 | temp.push_back(indent() + "end"s + nlr(nodes.front())); |
| 2256 | } | 2275 | } |
| 2257 | if (usage == ExpUsage::Closure) { | 2276 | if (usage == ExpUsage::Closure) { |
| 2258 | _enableReturn.pop(); | ||
| 2259 | popScope(); | 2277 | popScope(); |
| 2260 | *funcStart = anonFuncStart() + nll(nodes.front()); | 2278 | *funcStart = anonFuncStart() + nll(nodes.front()); |
| 2261 | temp.push_back(indent() + anonFuncEnd()); | 2279 | temp.push_back(indent() + anonFuncEnd()); |
| 2262 | popAnonVarArg(); | 2280 | popAnonVarArg(); |
| 2281 | _enableReturn.pop(); | ||
| 2263 | } | 2282 | } |
| 2264 | out.push_back(join(temp)); | 2283 | out.push_back(join(temp)); |
| 2265 | } | 2284 | } |
| @@ -2375,15 +2394,19 @@ private: | |||
| 2375 | } | 2394 | } |
| 2376 | 2395 | ||
| 2377 | void transformExp(Exp_t* exp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { | 2396 | void transformExp(Exp_t* exp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { |
| 2378 | if (exp->opValues.empty()) { | 2397 | if (exp->opValues.empty() && !exp->nilCoalesed) { |
| 2379 | transform_pipe_exp(exp->pipeExprs.objects(), out, usage, assignList); | 2398 | transform_pipe_exp(exp->pipeExprs.objects(), out, usage, assignList); |
| 2380 | return; | 2399 | return; |
| 2381 | } | 2400 | } |
| 2382 | if (usage != ExpUsage::Closure) { | 2401 | if (usage != ExpUsage::Closure) { |
| 2383 | YUEE("invalid expression usage", exp); | 2402 | YUEE("invalid expression usage", exp); |
| 2384 | } | 2403 | } |
| 2404 | if (exp->nilCoalesed) { | ||
| 2405 | transformNilCoalesedExp(exp, out, ExpUsage::Closure); | ||
| 2406 | return; | ||
| 2407 | } | ||
| 2385 | str_list temp; | 2408 | str_list temp; |
| 2386 | transform_pipe_exp(exp->pipeExprs.objects(), temp, ExpUsage::Closure); | 2409 | transform_pipe_exp(exp->pipeExprs.objects(), temp, ExpUsage::Closure); |
| 2387 | for (auto _opValue : exp->opValues.objects()) { | 2410 | for (auto _opValue : exp->opValues.objects()) { |
| 2388 | auto opValue = static_cast<exp_op_value_t*>(_opValue); | 2411 | auto opValue = static_cast<exp_op_value_t*>(_opValue); |
| 2389 | transformBinaryOperator(opValue->op, temp); | 2412 | transformBinaryOperator(opValue->op, temp); |
| @@ -2392,6 +2415,129 @@ private: | |||
| 2392 | out.push_back(join(temp, " "sv)); | 2415 | out.push_back(join(temp, " "sv)); |
| 2393 | } | 2416 | } |
| 2394 | 2417 | ||
| 2418 | void transformNilCoalesedExp(Exp_t* exp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr, bool nilBranchOnly = false) { | ||
| 2419 | auto x = exp; | ||
| 2420 | str_list temp; | ||
| 2421 | std::string prefix; | ||
| 2422 | auto left = exp->new_ptr<Exp_t>(); | ||
| 2423 | if (exp->opValues.empty()) { | ||
| 2424 | left->pipeExprs.dup(exp->pipeExprs); | ||
| 2425 | } else { | ||
| 2426 | if (usage != ExpUsage::Closure) { | ||
| 2427 | YUEE("invalid expression usage", exp); | ||
| 2428 | } | ||
| 2429 | transform_pipe_exp(exp->pipeExprs.objects(), temp, ExpUsage::Closure); | ||
| 2430 | auto last = exp->opValues.objects().back(); | ||
| 2431 | for (auto _opValue : exp->opValues.objects()) { | ||
| 2432 | auto opValue = static_cast<exp_op_value_t*>(_opValue); | ||
| 2433 | transformBinaryOperator(opValue->op, temp); | ||
| 2434 | if (opValue == last) { | ||
| 2435 | left->pipeExprs.dup(opValue->pipeExprs); | ||
| 2436 | } else { | ||
| 2437 | transform_pipe_exp(opValue->pipeExprs.objects(), temp, ExpUsage::Closure); | ||
| 2438 | } | ||
| 2439 | } | ||
| 2440 | prefix = join(temp, " "sv) + ' '; | ||
| 2441 | temp.clear(); | ||
| 2442 | temp.push_back(prefix); | ||
| 2443 | } | ||
| 2444 | std::string* funcStart = nullptr; | ||
| 2445 | if (usage == ExpUsage::Closure) { | ||
| 2446 | _enableReturn.push(true); | ||
| 2447 | pushAnonVarArg(); | ||
| 2448 | funcStart = &temp.emplace_back(); | ||
| 2449 | pushScope(); | ||
| 2450 | } | ||
| 2451 | auto objVar = singleVariableFrom(left); | ||
| 2452 | auto prepareValue = [&](bool forAssignment = false) { | ||
| 2453 | if (objVar.empty() || !isLocal(objVar)) { | ||
| 2454 | if (forAssignment) { | ||
| 2455 | temp.push_back(indent() + "do"s + nll(x)); | ||
| 2456 | pushScope(); | ||
| 2457 | } | ||
| 2458 | objVar = getUnusedName("_exp_"sv); | ||
| 2459 | auto expList = toAst<ExpList_t>(objVar, x); | ||
| 2460 | auto assign = x->new_ptr<Assign_t>(); | ||
| 2461 | assign->values.push_back(left); | ||
| 2462 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
| 2463 | assignment->expList.set(expList); | ||
| 2464 | assignment->action.set(assign); | ||
| 2465 | transformAssignment(assignment, temp); | ||
| 2466 | return true; | ||
| 2467 | } | ||
| 2468 | return false; | ||
| 2469 | }; | ||
| 2470 | switch (usage) { | ||
| 2471 | case ExpUsage::Common: YUEE("AST node mismatch", x); return; | ||
| 2472 | case ExpUsage::Return: | ||
| 2473 | case ExpUsage::Closure: { | ||
| 2474 | prepareValue(); | ||
| 2475 | _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x); | ||
| 2476 | _buf << indent(1) << "return "s << objVar << nll(x); | ||
| 2477 | _buf << indent() << "else"s << nll(x); | ||
| 2478 | temp.push_back(clearBuf()); | ||
| 2479 | auto ret = x->new_ptr<Return_t>(); | ||
| 2480 | auto retList = x->new_ptr<ExpListLow_t>(); | ||
| 2481 | retList->exprs.push_back(exp->nilCoalesed); | ||
| 2482 | ret->valueList.set(retList); | ||
| 2483 | incIndentOffset(); | ||
| 2484 | transformReturn(ret, temp); | ||
| 2485 | decIndentOffset(); | ||
| 2486 | temp.push_back(indent() + "end"s + nll(x)); | ||
| 2487 | if (usage == ExpUsage::Closure) { | ||
| 2488 | popScope(); | ||
| 2489 | *funcStart = anonFuncStart() + nll(x); | ||
| 2490 | temp.push_back(indent() + anonFuncEnd()); | ||
| 2491 | popAnonVarArg(); | ||
| 2492 | _enableReturn.pop(); | ||
| 2493 | } | ||
| 2494 | break; | ||
| 2495 | } | ||
| 2496 | case ExpUsage::Assignment: { | ||
| 2497 | auto assign = x->new_ptr<Assign_t>(); | ||
| 2498 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
| 2499 | assignment->expList.set(assignList); | ||
| 2500 | assignment->action.set(assign); | ||
| 2501 | bool extraScope = false; | ||
| 2502 | if (!nilBranchOnly) { | ||
| 2503 | assign->values.push_back(exp); | ||
| 2504 | std::string& predefine = temp.emplace_back(); | ||
| 2505 | auto defs = getPredefine(assignment); | ||
| 2506 | if (!defs.empty()) predefine = defs + nll(x); | ||
| 2507 | extraScope = prepareValue(true); | ||
| 2508 | _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x); | ||
| 2509 | temp.push_back(clearBuf()); | ||
| 2510 | pushScope(); | ||
| 2511 | assign->values.clear(); | ||
| 2512 | assign->values.push_back(toAst<Exp_t>(objVar, x)); | ||
| 2513 | transformAssignment(assignment, temp); | ||
| 2514 | popScope(); | ||
| 2515 | temp.push_back(indent() + "else"s + nll(x)); | ||
| 2516 | assign->values.clear(); | ||
| 2517 | assign->values.push_back(exp->nilCoalesed); | ||
| 2518 | } else { | ||
| 2519 | assign->values.clear(); | ||
| 2520 | assign->values.push_back(exp->nilCoalesed); | ||
| 2521 | auto defs = getPredefine(assignment); | ||
| 2522 | if (!defs.empty()) temp.push_back(defs + nll(x)); | ||
| 2523 | prepareValue(); | ||
| 2524 | _buf << indent() << "if "sv << objVar << " == nil then"sv << nll(x); | ||
| 2525 | temp.push_back(clearBuf()); | ||
| 2526 | } | ||
| 2527 | pushScope(); | ||
| 2528 | transformAssignment(assignment, temp); | ||
| 2529 | popScope(); | ||
| 2530 | temp.push_back(indent() + "end"s + nlr(x)); | ||
| 2531 | if (extraScope) { | ||
| 2532 | popScope(); | ||
| 2533 | temp.push_back(indent() + "end"s + nlr(x)); | ||
| 2534 | } | ||
| 2535 | break; | ||
| 2536 | } | ||
| 2537 | } | ||
| 2538 | out.push_back(join(temp)); | ||
| 2539 | } | ||
| 2540 | |||
| 2395 | void transformValue(Value_t* value, str_list& out) { | 2541 | void transformValue(Value_t* value, str_list& out) { |
| 2396 | auto item = value->item.get(); | 2542 | auto item = value->item.get(); |
| 2397 | switch (item->getId()) { | 2543 | switch (item->getId()) { |
| @@ -3022,6 +3168,9 @@ private: | |||
| 3022 | if (isPureBackcall(exp)) { | 3168 | if (isPureBackcall(exp)) { |
| 3023 | transformExp(exp, out, ExpUsage::Return); | 3169 | transformExp(exp, out, ExpUsage::Return); |
| 3024 | return; | 3170 | return; |
| 3171 | } else if (isPureNilCoalesed(exp)) { | ||
| 3172 | transformNilCoalesedExp(exp, out, ExpUsage::Return); | ||
| 3173 | return; | ||
| 3025 | } | 3174 | } |
| 3026 | } | 3175 | } |
| 3027 | if (auto singleValue = singleValueFrom(valueList)) { | 3176 | if (auto singleValue = singleValueFrom(valueList)) { |
| @@ -3294,10 +3443,10 @@ private: | |||
| 3294 | str_list temp; | 3443 | str_list temp; |
| 3295 | std::string* funcStart = nullptr; | 3444 | std::string* funcStart = nullptr; |
| 3296 | if (usage == ExpUsage::Closure) { | 3445 | if (usage == ExpUsage::Closure) { |
| 3446 | _enableReturn.push(true); | ||
| 3297 | pushAnonVarArg(); | 3447 | pushAnonVarArg(); |
| 3298 | funcStart = &temp.emplace_back(); | 3448 | funcStart = &temp.emplace_back(); |
| 3299 | pushScope(); | 3449 | pushScope(); |
| 3300 | _enableReturn.push(true); | ||
| 3301 | } | 3450 | } |
| 3302 | auto partOne = x->new_ptr<ChainValue_t>(); | 3451 | auto partOne = x->new_ptr<ChainValue_t>(); |
| 3303 | for (auto it = chainList.begin();it != opIt;++it) { | 3452 | for (auto it = chainList.begin();it != opIt;++it) { |
| @@ -3428,11 +3577,11 @@ private: | |||
| 3428 | break; | 3577 | break; |
| 3429 | case ExpUsage::Closure: | 3578 | case ExpUsage::Closure: |
| 3430 | temp.push_back(indent() + "return nil"s + nlr(x)); | 3579 | temp.push_back(indent() + "return nil"s + nlr(x)); |
| 3431 | _enableReturn.pop(); | ||
| 3432 | popScope(); | 3580 | popScope(); |
| 3433 | *funcStart = anonFuncStart() + nll(x); | 3581 | *funcStart = anonFuncStart() + nll(x); |
| 3434 | temp.push_back(indent() + anonFuncEnd()); | 3582 | temp.push_back(indent() + anonFuncEnd()); |
| 3435 | popAnonVarArg(); | 3583 | popAnonVarArg(); |
| 3584 | _enableReturn.pop(); | ||
| 3436 | break; | 3585 | break; |
| 3437 | default: | 3586 | default: |
| 3438 | break; | 3587 | break; |
| @@ -3454,10 +3603,10 @@ private: | |||
| 3454 | pushScope(); | 3603 | pushScope(); |
| 3455 | break; | 3604 | break; |
| 3456 | case ExpUsage::Closure: | 3605 | case ExpUsage::Closure: |
| 3606 | _enableReturn.push(true); | ||
| 3457 | pushAnonVarArg(); | 3607 | pushAnonVarArg(); |
| 3458 | funcStart = &temp.emplace_back(); | 3608 | funcStart = &temp.emplace_back(); |
| 3459 | pushScope(); | 3609 | pushScope(); |
| 3460 | _enableReturn.push(true); | ||
| 3461 | break; | 3610 | break; |
| 3462 | default: | 3611 | default: |
| 3463 | break; | 3612 | break; |
| @@ -3529,11 +3678,11 @@ private: | |||
| 3529 | temp.push_back(indent() + "end"s + nlr(x)); | 3678 | temp.push_back(indent() + "end"s + nlr(x)); |
| 3530 | break; | 3679 | break; |
| 3531 | case ExpUsage::Closure: | 3680 | case ExpUsage::Closure: |
| 3532 | _enableReturn.pop(); | ||
| 3533 | popScope(); | 3681 | popScope(); |
| 3534 | *funcStart = anonFuncStart() + nll(x); | 3682 | *funcStart = anonFuncStart() + nll(x); |
| 3535 | temp.push_back(indent() + anonFuncEnd()); | 3683 | temp.push_back(indent() + anonFuncEnd()); |
| 3536 | popAnonVarArg(); | 3684 | popAnonVarArg(); |
| 3685 | _enableReturn.pop(); | ||
| 3537 | break; | 3686 | break; |
| 3538 | default: | 3687 | default: |
| 3539 | break; | 3688 | break; |
| @@ -4263,8 +4412,8 @@ private: | |||
| 4263 | switch (usage) { | 4412 | switch (usage) { |
| 4264 | case ExpUsage::Closure: | 4413 | case ExpUsage::Closure: |
| 4265 | _enableReturn.push(true); | 4414 | _enableReturn.push(true); |
| 4266 | pushScope(); | ||
| 4267 | pushAnonVarArg(); | 4415 | pushAnonVarArg(); |
| 4416 | pushScope(); | ||
| 4268 | break; | 4417 | break; |
| 4269 | case ExpUsage::Assignment: | 4418 | case ExpUsage::Assignment: |
| 4270 | pushScope(); | 4419 | pushScope(); |
| @@ -4320,13 +4469,13 @@ private: | |||
| 4320 | case ExpUsage::Common: | 4469 | case ExpUsage::Common: |
| 4321 | break; | 4470 | break; |
| 4322 | case ExpUsage::Closure: { | 4471 | case ExpUsage::Closure: { |
| 4323 | _enableReturn.pop(); | ||
| 4324 | out.push_back(clearBuf()); | 4472 | out.push_back(clearBuf()); |
| 4325 | out.back().append(indent() + "return "s + accumVar + nlr(comp)); | 4473 | out.back().append(indent() + "return "s + accumVar + nlr(comp)); |
| 4326 | popScope(); | 4474 | popScope(); |
| 4327 | out.back().insert(0, anonFuncStart() + nll(comp)); | 4475 | out.back().insert(0, anonFuncStart() + nll(comp)); |
| 4328 | out.back().append(indent() + anonFuncEnd()); | 4476 | out.back().append(indent() + anonFuncEnd()); |
| 4329 | popAnonVarArg(); | 4477 | popAnonVarArg(); |
| 4478 | _enableReturn.pop(); | ||
| 4330 | break; | 4479 | break; |
| 4331 | } | 4480 | } |
| 4332 | case ExpUsage::Assignment: { | 4481 | case ExpUsage::Assignment: { |
| @@ -4352,11 +4501,12 @@ private: | |||
| 4352 | } | 4501 | } |
| 4353 | } | 4502 | } |
| 4354 | 4503 | ||
| 4355 | void transformForEachHead(AssignableNameList_t* nameList, ast_node* loopTarget, str_list& out) { | 4504 | bool transformForEachHead(AssignableNameList_t* nameList, ast_node* loopTarget, str_list& out, bool isStatement = false) { |
| 4356 | auto x = nameList; | 4505 | auto x = nameList; |
| 4357 | str_list temp; | 4506 | str_list temp; |
| 4358 | str_list vars; | 4507 | str_list vars; |
| 4359 | str_list varBefore, varAfter; | 4508 | str_list varBefore, varAfter; |
| 4509 | bool extraScope = false; | ||
| 4360 | std::list<std::pair<ast_node*, ast_ptr<false, ast_node>>> destructPairs; | 4510 | std::list<std::pair<ast_node*, ast_ptr<false, ast_node>>> destructPairs; |
| 4361 | for (auto _item : nameList->items.objects()) { | 4511 | for (auto _item : nameList->items.objects()) { |
| 4362 | auto item = static_cast<NameOrDestructure_t*>(_item)->item.get(); | 4512 | auto item = static_cast<NameOrDestructure_t*>(_item)->item.get(); |
| @@ -4422,16 +4572,28 @@ private: | |||
| 4422 | temp.pop_back(); | 4572 | temp.pop_back(); |
| 4423 | } | 4573 | } |
| 4424 | if (listVar.empty()) { | 4574 | if (listVar.empty()) { |
| 4575 | std::string prefix; | ||
| 4576 | if (isStatement) { | ||
| 4577 | extraScope = true; | ||
| 4578 | prefix = indent() + "do"s + nll(x); | ||
| 4579 | pushScope(); | ||
| 4580 | } | ||
| 4425 | listVar = getUnusedName("_list_"sv); | 4581 | listVar = getUnusedName("_list_"sv); |
| 4426 | varBefore.push_back(listVar); | 4582 | varBefore.push_back(listVar); |
| 4427 | transformChainValue(chain, temp, ExpUsage::Closure); | 4583 | transformChainValue(chain, temp, ExpUsage::Closure); |
| 4428 | _buf << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList); | 4584 | _buf << prefix << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList); |
| 4429 | } | 4585 | } |
| 4430 | std::string maxVar; | 4586 | std::string maxVar; |
| 4431 | if (!stopValue.empty()) { | 4587 | if (!stopValue.empty()) { |
| 4588 | std::string prefix; | ||
| 4589 | if (isStatement && !extraScope) { | ||
| 4590 | extraScope = true; | ||
| 4591 | prefix = indent() + "do"s + nll(x); | ||
| 4592 | pushScope(); | ||
| 4593 | } | ||
| 4432 | maxVar = getUnusedName("_max_"sv); | 4594 | maxVar = getUnusedName("_max_"sv); |
| 4433 | varBefore.push_back(maxVar); | 4595 | varBefore.push_back(maxVar); |
| 4434 | _buf << indent() << "local "sv << maxVar << " = "sv << stopValue << nll(nameList); | 4596 | _buf << prefix << indent() << "local "sv << maxVar << " = "sv << stopValue << nll(nameList); |
| 4435 | } | 4597 | } |
| 4436 | _buf << indent() << "for "sv << indexVar << " = "sv; | 4598 | _buf << indent() << "for "sv << indexVar << " = "sv; |
| 4437 | _buf << startValue << ", "sv; | 4599 | _buf << startValue << ", "sv; |
| @@ -4497,6 +4659,7 @@ private: | |||
| 4497 | } | 4659 | } |
| 4498 | out.back().append(join(temp)); | 4660 | out.back().append(join(temp)); |
| 4499 | } | 4661 | } |
| 4662 | return extraScope; | ||
| 4500 | } | 4663 | } |
| 4501 | 4664 | ||
| 4502 | void transformCompForEach(CompForEach_t* comp, str_list& out) { | 4665 | void transformCompForEach(CompForEach_t* comp, str_list& out) { |
| @@ -4651,17 +4814,17 @@ private: | |||
| 4651 | 4814 | ||
| 4652 | void transformForClosure(For_t* forNode, str_list& out) { | 4815 | void transformForClosure(For_t* forNode, str_list& out) { |
| 4653 | str_list temp; | 4816 | str_list temp; |
| 4817 | _enableReturn.push(true); | ||
| 4654 | pushAnonVarArg(); | 4818 | pushAnonVarArg(); |
| 4655 | std::string& funcStart = temp.emplace_back(); | 4819 | std::string& funcStart = temp.emplace_back(); |
| 4656 | pushScope(); | 4820 | pushScope(); |
| 4657 | _enableReturn.push(true); | ||
| 4658 | auto accum = transformForInner(forNode, temp); | 4821 | auto accum = transformForInner(forNode, temp); |
| 4659 | temp.push_back(indent() + "return "s + accum + nlr(forNode)); | 4822 | temp.push_back(indent() + "return "s + accum + nlr(forNode)); |
| 4660 | _enableReturn.pop(); | ||
| 4661 | popScope(); | 4823 | popScope(); |
| 4662 | funcStart = anonFuncStart() + nll(forNode); | 4824 | funcStart = anonFuncStart() + nll(forNode); |
| 4663 | temp.push_back(indent() + anonFuncEnd()); | 4825 | temp.push_back(indent() + anonFuncEnd()); |
| 4664 | popAnonVarArg(); | 4826 | popAnonVarArg(); |
| 4827 | _enableReturn.pop(); | ||
| 4665 | out.push_back(join(temp)); | 4828 | out.push_back(join(temp)); |
| 4666 | } | 4829 | } |
| 4667 | 4830 | ||
| @@ -4697,10 +4860,14 @@ private: | |||
| 4697 | 4860 | ||
| 4698 | void transformForEach(ForEach_t* forEach, str_list& out) { | 4861 | void transformForEach(ForEach_t* forEach, str_list& out) { |
| 4699 | str_list temp; | 4862 | str_list temp; |
| 4700 | transformForEachHead(forEach->nameList, forEach->loopValue, temp); | 4863 | bool extraScope = transformForEachHead(forEach->nameList, forEach->loopValue, temp, true); |
| 4701 | transformLoopBody(forEach->body, temp, Empty, ExpUsage::Common); | 4864 | transformLoopBody(forEach->body, temp, Empty, ExpUsage::Common); |
| 4702 | popScope(); | 4865 | popScope(); |
| 4703 | out.push_back(temp.front() + temp.back() + indent() + "end"s + nlr(forEach)); | 4866 | out.push_back(temp.front() + temp.back() + indent() + "end"s + nlr(forEach)); |
| 4867 | if (extraScope) { | ||
| 4868 | popScope(); | ||
| 4869 | out.back().append(indent() + "end"s + nlr(forEach)); | ||
| 4870 | } | ||
| 4704 | } | 4871 | } |
| 4705 | 4872 | ||
| 4706 | std::string transformForEachInner(ForEach_t* forEach, str_list& out) { | 4873 | std::string transformForEachInner(ForEach_t* forEach, str_list& out) { |
| @@ -4723,17 +4890,17 @@ private: | |||
| 4723 | 4890 | ||
| 4724 | void transformForEachClosure(ForEach_t* forEach, str_list& out) { | 4891 | void transformForEachClosure(ForEach_t* forEach, str_list& out) { |
| 4725 | str_list temp; | 4892 | str_list temp; |
| 4893 | _enableReturn.push(true); | ||
| 4726 | pushAnonVarArg(); | 4894 | pushAnonVarArg(); |
| 4727 | std::string& funcStart = temp.emplace_back(); | 4895 | std::string& funcStart = temp.emplace_back(); |
| 4728 | pushScope(); | 4896 | pushScope(); |
| 4729 | _enableReturn.push(true); | ||
| 4730 | auto accum = transformForEachInner(forEach, temp); | 4897 | auto accum = transformForEachInner(forEach, temp); |
| 4731 | temp.push_back(indent() + "return "s + accum + nlr(forEach)); | 4898 | temp.push_back(indent() + "return "s + accum + nlr(forEach)); |
| 4732 | _enableReturn.pop(); | ||
| 4733 | popScope(); | 4899 | popScope(); |
| 4734 | funcStart = anonFuncStart() + nll(forEach); | 4900 | funcStart = anonFuncStart() + nll(forEach); |
| 4735 | temp.push_back(indent() + anonFuncEnd()); | 4901 | temp.push_back(indent() + anonFuncEnd()); |
| 4736 | popAnonVarArg(); | 4902 | popAnonVarArg(); |
| 4903 | _enableReturn.pop(); | ||
| 4737 | out.push_back(join(temp)); | 4904 | out.push_back(join(temp)); |
| 4738 | } | 4905 | } |
| 4739 | 4906 | ||
| @@ -4878,16 +5045,16 @@ private: | |||
| 4878 | 5045 | ||
| 4879 | void transformClassDeclClosure(ClassDecl_t* classDecl, str_list& out) { | 5046 | void transformClassDeclClosure(ClassDecl_t* classDecl, str_list& out) { |
| 4880 | str_list temp; | 5047 | str_list temp; |
| 5048 | _enableReturn.push(true); | ||
| 4881 | pushAnonVarArg(); | 5049 | pushAnonVarArg(); |
| 4882 | std::string& funcStart = temp.emplace_back(); | 5050 | std::string& funcStart = temp.emplace_back(); |
| 4883 | pushScope(); | 5051 | pushScope(); |
| 4884 | _enableReturn.push(true); | ||
| 4885 | transformClassDecl(classDecl, temp, ExpUsage::Return); | 5052 | transformClassDecl(classDecl, temp, ExpUsage::Return); |
| 4886 | _enableReturn.pop(); | ||
| 4887 | popScope(); | 5053 | popScope(); |
| 4888 | funcStart = anonFuncStart() + nll(classDecl); | 5054 | funcStart = anonFuncStart() + nll(classDecl); |
| 4889 | temp.push_back(indent() + anonFuncEnd()); | 5055 | temp.push_back(indent() + anonFuncEnd()); |
| 4890 | popAnonVarArg(); | 5056 | popAnonVarArg(); |
| 5057 | _enableReturn.pop(); | ||
| 4891 | out.push_back(join(temp)); | 5058 | out.push_back(join(temp)); |
| 4892 | } | 5059 | } |
| 4893 | 5060 | ||
| @@ -5256,16 +5423,16 @@ private: | |||
| 5256 | 5423 | ||
| 5257 | void transformWithClosure(With_t* with, str_list& out) { | 5424 | void transformWithClosure(With_t* with, str_list& out) { |
| 5258 | str_list temp; | 5425 | str_list temp; |
| 5426 | _enableReturn.push(true); | ||
| 5259 | pushAnonVarArg(); | 5427 | pushAnonVarArg(); |
| 5260 | std::string& funcStart = temp.emplace_back(); | 5428 | std::string& funcStart = temp.emplace_back(); |
| 5261 | pushScope(); | 5429 | pushScope(); |
| 5262 | _enableReturn.push(true); | ||
| 5263 | transformWith(with, temp, nullptr, true); | 5430 | transformWith(with, temp, nullptr, true); |
| 5264 | _enableReturn.pop(); | ||
| 5265 | popScope(); | 5431 | popScope(); |
| 5266 | funcStart = anonFuncStart() + nll(with); | 5432 | funcStart = anonFuncStart() + nll(with); |
| 5267 | temp.push_back(indent() + anonFuncEnd()); | 5433 | temp.push_back(indent() + anonFuncEnd()); |
| 5268 | popAnonVarArg(); | 5434 | popAnonVarArg(); |
| 5435 | _enableReturn.pop(); | ||
| 5269 | out.push_back(join(temp)); | 5436 | out.push_back(join(temp)); |
| 5270 | } | 5437 | } |
| 5271 | 5438 | ||
| @@ -5674,9 +5841,9 @@ private: | |||
| 5674 | void transformTblComprehension(TblComprehension_t* comp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { | 5841 | void transformTblComprehension(TblComprehension_t* comp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { |
| 5675 | switch (usage) { | 5842 | switch (usage) { |
| 5676 | case ExpUsage::Closure: | 5843 | case ExpUsage::Closure: |
| 5677 | pushScope(); | ||
| 5678 | _enableReturn.push(true); | 5844 | _enableReturn.push(true); |
| 5679 | pushAnonVarArg(); | 5845 | pushAnonVarArg(); |
| 5846 | pushScope(); | ||
| 5680 | break; | 5847 | break; |
| 5681 | case ExpUsage::Assignment: | 5848 | case ExpUsage::Assignment: |
| 5682 | pushScope(); | 5849 | pushScope(); |
| @@ -5733,10 +5900,10 @@ private: | |||
| 5733 | case ExpUsage::Closure: | 5900 | case ExpUsage::Closure: |
| 5734 | out.push_back(clearBuf() + indent() + "return "s + tbl + nlr(comp)); | 5901 | out.push_back(clearBuf() + indent() + "return "s + tbl + nlr(comp)); |
| 5735 | popScope(); | 5902 | popScope(); |
| 5736 | _enableReturn.pop(); | ||
| 5737 | out.back().insert(0, anonFuncStart() + nll(comp)); | 5903 | out.back().insert(0, anonFuncStart() + nll(comp)); |
| 5738 | out.back().append(indent() + anonFuncEnd()); | 5904 | out.back().append(indent() + anonFuncEnd()); |
| 5739 | popAnonVarArg(); | 5905 | popAnonVarArg(); |
| 5906 | _enableReturn.pop(); | ||
| 5740 | break; | 5907 | break; |
| 5741 | case ExpUsage::Assignment: { | 5908 | case ExpUsage::Assignment: { |
| 5742 | out.push_back(clearBuf()); | 5909 | out.push_back(clearBuf()); |
| @@ -5802,10 +5969,10 @@ private: | |||
| 5802 | transformBody(doNode->body, temp, usage, assignList); | 5969 | transformBody(doNode->body, temp, usage, assignList); |
| 5803 | popScope(); | 5970 | popScope(); |
| 5804 | if (usage == ExpUsage::Closure) { | 5971 | if (usage == ExpUsage::Closure) { |
| 5805 | _enableReturn.pop(); | ||
| 5806 | *funcStart = anonFuncStart() + nll(doNode); | 5972 | *funcStart = anonFuncStart() + nll(doNode); |
| 5807 | temp.push_back(indent() + anonFuncEnd()); | 5973 | temp.push_back(indent() + anonFuncEnd()); |
| 5808 | popAnonVarArg(); | 5974 | popAnonVarArg(); |
| 5975 | _enableReturn.pop(); | ||
| 5809 | } else { | 5976 | } else { |
| 5810 | temp.push_back(indent() + "end"s + nlr(doNode)); | 5977 | temp.push_back(indent() + "end"s + nlr(doNode)); |
| 5811 | } | 5978 | } |
| @@ -6111,10 +6278,10 @@ private: | |||
| 6111 | void transformWhileClosure(While_t* whileNode, str_list& out) { | 6278 | void transformWhileClosure(While_t* whileNode, str_list& out) { |
| 6112 | auto x = whileNode; | 6279 | auto x = whileNode; |
| 6113 | str_list temp; | 6280 | str_list temp; |
| 6281 | _enableReturn.push(true); | ||
| 6114 | pushAnonVarArg(); | 6282 | pushAnonVarArg(); |
| 6115 | std::string& funcStart = temp.emplace_back(); | 6283 | std::string& funcStart = temp.emplace_back(); |
| 6116 | pushScope(); | 6284 | pushScope(); |
| 6117 | _enableReturn.push(true); | ||
| 6118 | auto accumVar = getUnusedName("_accum_"sv); | 6285 | auto accumVar = getUnusedName("_accum_"sv); |
| 6119 | addToScope(accumVar); | 6286 | addToScope(accumVar); |
| 6120 | auto lenVar = getUnusedName("_len_"sv); | 6287 | auto lenVar = getUnusedName("_len_"sv); |
| @@ -6131,11 +6298,11 @@ private: | |||
| 6131 | popScope(); | 6298 | popScope(); |
| 6132 | temp.push_back(indent() + "end"s + nlr(whileNode)); | 6299 | temp.push_back(indent() + "end"s + nlr(whileNode)); |
| 6133 | temp.push_back(indent() + "return "s + accumVar + nlr(whileNode)); | 6300 | temp.push_back(indent() + "return "s + accumVar + nlr(whileNode)); |
| 6134 | _enableReturn.pop(); | ||
| 6135 | popScope(); | 6301 | popScope(); |
| 6136 | funcStart = anonFuncStart() + nll(whileNode); | 6302 | funcStart = anonFuncStart() + nll(whileNode); |
| 6137 | temp.push_back(indent() + anonFuncEnd()); | 6303 | temp.push_back(indent() + anonFuncEnd()); |
| 6138 | popAnonVarArg(); | 6304 | popAnonVarArg(); |
| 6305 | _enableReturn.pop(); | ||
| 6139 | out.push_back(join(temp)); | 6306 | out.push_back(join(temp)); |
| 6140 | } | 6307 | } |
| 6141 | 6308 | ||
| @@ -6165,21 +6332,31 @@ private: | |||
| 6165 | } | 6332 | } |
| 6166 | 6333 | ||
| 6167 | void transformSwitch(Switch_t* switchNode, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { | 6334 | void transformSwitch(Switch_t* switchNode, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { |
| 6335 | auto x = switchNode; | ||
| 6168 | str_list temp; | 6336 | str_list temp; |
| 6169 | std::string* funcStart = nullptr; | 6337 | std::string* funcStart = nullptr; |
| 6170 | if (usage == ExpUsage::Closure) { | 6338 | if (usage == ExpUsage::Closure) { |
| 6339 | _enableReturn.push(true); | ||
| 6171 | pushAnonVarArg(); | 6340 | pushAnonVarArg(); |
| 6172 | funcStart = &temp.emplace_back(); | 6341 | funcStart = &temp.emplace_back(); |
| 6173 | pushScope(); | 6342 | pushScope(); |
| 6174 | _enableReturn.push(true); | ||
| 6175 | } | 6343 | } |
| 6344 | bool extraScope = false; | ||
| 6176 | auto objVar = singleVariableFrom(switchNode->target); | 6345 | auto objVar = singleVariableFrom(switchNode->target); |
| 6177 | if (objVar.empty() || !isLocal(objVar)) { | 6346 | if (objVar.empty() || !isLocal(objVar)) { |
| 6347 | if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) { | ||
| 6348 | extraScope = true; | ||
| 6349 | temp.push_back(indent() + "do"s + nll(x)); | ||
| 6350 | pushScope(); | ||
| 6351 | } | ||
| 6178 | objVar = getUnusedName("_exp_"sv); | 6352 | objVar = getUnusedName("_exp_"sv); |
| 6179 | addToScope(objVar); | 6353 | auto expList = toAst<ExpList_t>(objVar, x); |
| 6180 | transformExp(switchNode->target, temp, ExpUsage::Closure); | 6354 | auto assign = x->new_ptr<Assign_t>(); |
| 6181 | _buf << indent() << "local "sv << objVar << " = "sv << temp.back() << nll(switchNode); | 6355 | assign->values.push_back(switchNode->target); |
| 6182 | temp.back() = clearBuf(); | 6356 | auto assignment = x->new_ptr<ExpListAssign_t>(); |
| 6357 | assignment->expList.set(expList); | ||
| 6358 | assignment->action.set(assign); | ||
| 6359 | transformAssignment(assignment, temp); | ||
| 6183 | } | 6360 | } |
| 6184 | const auto& branches = switchNode->branches.objects(); | 6361 | const auto& branches = switchNode->branches.objects(); |
| 6185 | for (auto branch_ : branches) { | 6362 | for (auto branch_ : branches) { |
| @@ -6215,6 +6392,10 @@ private: | |||
| 6215 | temp.push_back(indent() + anonFuncEnd()); | 6392 | temp.push_back(indent() + anonFuncEnd()); |
| 6216 | popAnonVarArg(); | 6393 | popAnonVarArg(); |
| 6217 | } | 6394 | } |
| 6395 | if (extraScope) { | ||
| 6396 | popScope(); | ||
| 6397 | temp.push_back(indent() + "end"s + nlr(switchNode)); | ||
| 6398 | } | ||
| 6218 | out.push_back(join(temp)); | 6399 | out.push_back(join(temp)); |
| 6219 | } | 6400 | } |
| 6220 | 6401 | ||
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index 6ecd369..5628062 100755 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp | |||
| @@ -323,7 +323,8 @@ YueParser::YueParser() { | |||
| 323 | expr("&") | | 323 | expr("&") | |
| 324 | expr("|") | | 324 | expr("|") | |
| 325 | expr(">>") | | 325 | expr(">>") | |
| 326 | expr("<<"); | 326 | expr("<<") | |
| 327 | expr("??"); | ||
| 327 | 328 | ||
| 328 | Update = Space >> update_op >> expr("=") >> Exp; | 329 | Update = Space >> update_op >> expr("=") >> Exp; |
| 329 | 330 | ||
| @@ -360,7 +361,7 @@ YueParser::YueParser() { | |||
| 360 | expr("//") | | 361 | expr("//") | |
| 361 | set("+-*/%><|&~"); | 362 | set("+-*/%><|&~"); |
| 362 | exp_op_value = Space >> BinaryOperator >> *SpaceBreak >> pipe_exp; | 363 | exp_op_value = Space >> BinaryOperator >> *SpaceBreak >> pipe_exp; |
| 363 | Exp = Seperator >> pipe_exp >> *exp_op_value; | 364 | Exp = Seperator >> pipe_exp >> *exp_op_value >> -(Space >> expr("??") >> Exp); |
| 364 | 365 | ||
| 365 | DisableChain = pl::user(true_(), [](const item_t& item) { | 366 | DisableChain = pl::user(true_(), [](const item_t& item) { |
| 366 | State* st = reinterpret_cast<State*>(item.user_data); | 367 | State* st = reinterpret_cast<State*>(item.user_data); |
| @@ -424,7 +425,7 @@ YueParser::YueParser() { | |||
| 424 | Metatable = expr('#'); | 425 | Metatable = expr('#'); |
| 425 | Metamethod = Name >> expr('#'); | 426 | Metamethod = Name >> expr('#'); |
| 426 | 427 | ||
| 427 | existential_op = expr('?'); | 428 | existential_op = expr('?') >> not_(expr('?')); |
| 428 | chain_call = (Callable | String) >> -existential_op >> ChainItems; | 429 | chain_call = (Callable | String) >> -existential_op >> ChainItems; |
| 429 | chain_item = and_(set(".\\")) >> ChainItems; | 430 | chain_item = and_(set(".\\")) >> ChainItems; |
| 430 | chain_dot_chain = DotChainItem >> -existential_op >> -ChainItems; | 431 | chain_dot_chain = DotChainItem >> -existential_op >> -ChainItems; |
