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.
-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; |