aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2022-07-12 17:41:19 +0800
committerLi Jin <dragon-fly@qq.com>2022-07-12 17:41:19 +0800
commit68e167e9f0b90968ea67b7f21fdc50a48d129173 (patch)
tree64612476c7cc5636d7a9eea68ea1e5b449bb9732
parent1a7c8e3c38fcf0af94ca799a3cd9fa7c4ef1bf08 (diff)
downloadyuescript-68e167e9f0b90968ea67b7f21fdc50a48d129173.tar.gz
yuescript-68e167e9f0b90968ea67b7f21fdc50a48d129173.tar.bz2
yuescript-68e167e9f0b90968ea67b7f21fdc50a48d129173.zip
add table pattern matching syntax and fix issue #93, remove a confusing default value syntax for destructuring.
-rw-r--r--spec/inputs/destructure.yue3
-rw-r--r--spec/inputs/switch.yue86
-rw-r--r--spec/outputs/destructure.lua121
-rw-r--r--spec/outputs/switch.lua264
-rwxr-xr-xsrc/yuescript/yue_ast.h8
-rwxr-xr-xsrc/yuescript/yue_compiler.cpp615
-rwxr-xr-xsrc/yuescript/yue_parser.cpp9
-rwxr-xr-xsrc/yuescript/yue_parser.h2
8 files changed, 790 insertions, 318 deletions
diff --git a/spec/inputs/destructure.yue b/spec/inputs/destructure.yue
index a235abd..3007adf 100644
--- a/spec/inputs/destructure.yue
+++ b/spec/inputs/destructure.yue
@@ -181,3 +181,6 @@ do
181do 181do
182 {_, a, _, b} = tb -- list placeholder 182 {_, a, _, b} = tb -- list placeholder
183 183
184do
185 {x: a.b = 1, y: a.c = 2} = x.x.x
186
diff --git a/spec/inputs/switch.yue b/spec/inputs/switch.yue
index ac3dbea..36f9be6 100644
--- a/spec/inputs/switch.yue
+++ b/spec/inputs/switch.yue
@@ -58,7 +58,91 @@ switch hi
58 58
59switch hi 59switch hi
60 when 3+1, hello!, (-> 4)! 60 when 3+1, hello!, (-> 4)!
61 yello 61 _ = yello
62 else 62 else
63 print "cool" 63 print "cool"
64 64
65do
66 dict = {
67 {}
68 {1, 2, 3}
69 a: b: c: 1
70 x: y: z: 1
71 }
72
73 switch dict
74 when {
75 first
76 {one, two, three}
77 a: b: :c
78 x: y: :z
79 }
80 print first, one, two, three, c, z
81
82do
83 items =
84 * x: 100
85 y: 200
86 * width: 300
87 height: 400
88 * false
89
90 for item in *items
91 switch item
92 when :x, :y
93 print "Vec2 #{x}, #{y}"
94 when :width, :height
95 print "Size #{width}, #{height}"
96 when false
97 print "None"
98 when __class: cls
99 switch cls
100 when ClassA
101 print "Object A"
102 when ClassB
103 print "Object B"
104 when #: mt
105 print "A table with metatable"
106 else
107 print "item not accepted!"
108
109do
110 tb = {}
111 switch tb
112 when {:a = 1, :b = 2}
113 print a, b
114
115do
116 tb = x: "abc"
117 switch tb
118 when :x, :y
119 print "x: #{x} with y: #{y}"
120 when :x
121 print "x: #{x} only"
122
123do
124 matched = switch tb
125 when 1
126 "1"
127 when :x
128 x
129 when false
130 "false"
131 else
132 nil
133
134do
135 return switch tb
136 when nil
137 "invalid"
138 when :a, :b
139 "#{a + b}"
140 when 1, 2, 3, 4, 5
141 "number 1 - 5"
142 when {:alwaysMatch = "fallback"}
143 alwaysMatch
144 else
145 "should not reach here"
146
147nil
148
diff --git a/spec/outputs/destructure.lua b/spec/outputs/destructure.lua
index 9b16181..2fe4ba9 100644
--- a/spec/outputs/destructure.lua
+++ b/spec/outputs/destructure.lua
@@ -229,12 +229,12 @@ do
229 do 229 do
230 local _obj_0 = person 230 local _obj_0 = person
231 name, job = _obj_0.name, _obj_0.job 231 name, job = _obj_0.name, _obj_0.job
232 end 232 if name == nil then
233 if name == nil then 233 name = "nameless"
234 name = "nameless" 234 end
235 end 235 if job == nil then
236 if job == nil then 236 job = "jobless"
237 job = "jobless" 237 end
238 end 238 end
239 local request 239 local request
240 request = function(url, options) 240 request = function(url, options)
@@ -261,29 +261,29 @@ do
261 do 261 do
262 local _obj_0 = tb 262 local _obj_0 = tb
263 value1, key3 = _obj_0.key1.key2, _obj_0.key3 263 value1, key3 = _obj_0.key1.key2, _obj_0.key3
264 end 264 if value1 == nil then
265 if value1 == nil then 265 value1 = 123
266 value1 = 123 266 end
267 end 267 if key3 == nil then
268 if key3 == nil then 268 key3 = "abc"
269 key3 = "abc" 269 end
270 end 270 end
271 local mt, call, add 271 local mt, call, add
272 do 272 do
273 local _obj_0 = getmetatable(tb) 273 local _obj_0 = getmetatable(tb)
274 mt, call, add = _obj_0, getmetatable(_obj_0).__call, getmetatable(_obj_0).__add 274 mt, call, add = _obj_0, getmetatable(_obj_0).__call, getmetatable(_obj_0).__add
275 end 275 if mt == nil then
276 if mt == nil then 276 mt = {
277 mt = { 277 __index = {
278 __index = { 278 abc = 123
279 abc = 123 279 }
280 } 280 }
281 } 281 end
282 end 282 if call == nil then
283 if call == nil then 283 call = (function()
284 call = (function() 284 return { }
285 return { } 285 end)
286 end) 286 end
287 end 287 end
288 local _obj_0 = tb 288 local _obj_0 = tb
289 local mtx, y, zItem = getmetatable(_obj_0.x), _obj_0.y, _obj_0.z 289 local mtx, y, zItem = getmetatable(_obj_0.x), _obj_0.y, _obj_0.z
@@ -296,27 +296,33 @@ do
296 return nil 296 return nil
297 end 297 end
298 end 298 end
299 local _obj_1 = getmetatable(tb).func 299 do
300 if _obj_1 == nil then 300 local _tmp_0
301 do 301 do
302 local _obj_2 = item 302 local _obj_1 = getmetatable(tb)
303 if _obj_2 ~= nil then 303 _tmp_0 = _obj_1.func
304 _obj_1 = _obj_2.defVal 304 end
305 if _tmp_0 == nil then
306 do
307 local _obj_1 = item
308 if _obj_1 ~= nil then
309 _tmp_0 = _obj_1.defVal
310 end
305 end 311 end
306 end 312 end
307 end 313 a.b(function()
308 a.b(function()
309 return 123 314 return 123
310 end).c = _obj_1 315 end).c = _tmp_0
316 end
311end 317end
312do 318do
313 local mt, subFunc 319 local mt, subFunc
314 do 320 do
315 local _obj_0 = getmetatable(tb.x) 321 local _obj_0 = getmetatable(tb.x)
316 mt, subFunc = _obj_0, _obj_0.__sub 322 mt, subFunc = _obj_0, _obj_0.__sub
317 end 323 if mt == nil then
318 if mt == nil then 324 mt = { }
319 mt = { } 325 end
320 end 326 end
321end 327end
322do 328do
@@ -324,27 +330,28 @@ do
324 do 330 do
325 local _obj_0 = tb 331 local _obj_0 = tb
326 mt, subFunc = getmetatable(_obj_0.x), getmetatable(_obj_0.x).__sub 332 mt, subFunc = getmetatable(_obj_0.x), getmetatable(_obj_0.x).__sub
327 end 333 if mt == nil then
328 if mt == nil then 334 mt = { }
329 mt = { } 335 end
330 end 336 end
331end 337end
332do 338do
333 local a, b, _obj_0 339 local a, b
334 do 340 do
335 local _obj_1 = tb 341 local _obj_0 = tb
336 a, b, _obj_0 = _obj_1[1], _obj_1[2], _obj_1.c[1] 342 local _tmp_0
337 end 343 a, b, _tmp_0 = _obj_0[1], _obj_0[2], _obj_0.c[1]
338 if a == nil then 344 if a == nil then
339 a = 1 345 a = 1
340 end 346 end
341 if b == nil then 347 if b == nil then
342 b = 2 348 b = 2
343 end 349 end
344 if _obj_0 == nil then 350 if _tmp_0 == nil then
345 _obj_0 = 3 351 _tmp_0 = 3
352 end
353 d.e = _tmp_0
346 end 354 end
347 d.e = _obj_0
348 local _list_0 = tuples 355 local _list_0 = tuples
349 for _index_0 = 1, #_list_0 do 356 for _index_0 = 1, #_list_0 do
350 local _des_0 = _list_0[_index_0] 357 local _des_0 = _list_0[_index_0]
@@ -365,3 +372,17 @@ do
365 a, b = _obj_0[2], _obj_0[4] 372 a, b = _obj_0[2], _obj_0[4]
366 end 373 end
367end 374end
375do
376 do
377 local _obj_0 = x.x.x
378 local _tmp_0, _tmp_1 = _obj_0.x, _obj_0.y
379 if _tmp_0 == nil then
380 _tmp_0 = 1
381 end
382 if _tmp_1 == nil then
383 _tmp_1 = 2
384 end
385 a.b = _tmp_0
386 a.c = _tmp_1
387 end
388end
diff --git a/spec/outputs/switch.lua b/spec/outputs/switch.lua
index 81f6d5a..03a0d37 100644
--- a/spec/outputs/switch.lua
+++ b/spec/outputs/switch.lua
@@ -77,11 +77,261 @@ do
77 local _ = no 77 local _ = no
78 end 78 end
79end 79end
80local _exp_0 = hi 80do
81if (3 + 1) == _exp_0 or hello() == _exp_0 or (function() 81 local _exp_0 = hi
82 return 4 82 if (3 + 1) == _exp_0 or hello() == _exp_0 or (function()
83end)() == _exp_0 then 83 return 4
84 return yello 84 end)() == _exp_0 then
85else 85 local _ = yello
86 return print("cool") 86 else
87 print("cool")
88 end
89end
90do
91 local dict = {
92 { },
93 {
94 1,
95 2,
96 3
97 },
98 a = {
99 b = {
100 c = 1
101 }
102 },
103 x = {
104 y = {
105 z = 1
106 }
107 }
108 }
109 do
110 local _tab_0 = "table" == type(dict)
111 if _tab_0 then
112 local first = dict[1]
113 local one
114 do
115 local _obj_0 = dict[2]
116 if _obj_0 ~= nil then
117 one = _obj_0[1]
118 end
119 end
120 local two
121 do
122 local _obj_0 = dict[2]
123 if _obj_0 ~= nil then
124 two = _obj_0[2]
125 end
126 end
127 local three
128 do
129 local _obj_0 = dict[2]
130 if _obj_0 ~= nil then
131 three = _obj_0[3]
132 end
133 end
134 local c
135 do
136 local _obj_0 = dict.a
137 if _obj_0 ~= nil then
138 do
139 local _obj_1 = _obj_0.b
140 if _obj_1 ~= nil then
141 c = _obj_1.c
142 end
143 end
144 end
145 end
146 local z
147 do
148 local _obj_0 = dict.x
149 if _obj_0 ~= nil then
150 do
151 local _obj_1 = _obj_0.y
152 if _obj_1 ~= nil then
153 z = _obj_1.z
154 end
155 end
156 end
157 end
158 if first ~= nil and one ~= nil and two ~= nil and three ~= nil and c ~= nil and z ~= nil then
159 print(first, one, two, three, c, z)
160 end
161 end
162 end
163end
164do
165 local items = {
166 {
167 x = 100,
168 y = 200
169 },
170 {
171 width = 300,
172 height = 400
173 },
174 false
175 }
176 for _index_0 = 1, #items do
177 local item = items[_index_0]
178 do
179 local _tab_0 = "table" == type(item)
180 local _match_0 = false
181 if _tab_0 then
182 local x = item.x
183 local y = item.y
184 if x ~= nil and y ~= nil then
185 print("Vec2 " .. tostring(x) .. ", " .. tostring(y))
186 _match_0 = true
187 end
188 end
189 if not _match_0 then
190 local _match_1 = false
191 if _tab_0 then
192 local width = item.width
193 local height = item.height
194 if width ~= nil and height ~= nil then
195 print("Size " .. tostring(width) .. ", " .. tostring(height))
196 _match_1 = true
197 end
198 end
199 if not _match_1 then
200 if false == item then
201 print("None")
202 else
203 local _match_2 = false
204 if _tab_0 then
205 local cls = item.__class
206 if cls ~= nil then
207 if ClassA == cls then
208 print("Object A")
209 elseif ClassB == cls then
210 print("Object B")
211 end
212 _match_2 = true
213 end
214 end
215 if not _match_2 then
216 if _tab_0 then
217 local mt = getmetatable(item)
218 if mt ~= nil then
219 print("A table with metatable")
220 end
221 else
222 print("item not accepted!")
223 end
224 end
225 end
226 end
227 end
228 end
229 end
230end
231do
232 local tb = { }
233 do
234 local _tab_0 = "table" == type(tb)
235 if _tab_0 then
236 local a = tb.a
237 local b = tb.b
238 if a == nil then
239 a = 1
240 end
241 if b == nil then
242 b = 2
243 end
244 if a ~= nil and b ~= nil then
245 print(a, b)
246 end
247 end
248 end
249end
250do
251 local tb = {
252 x = "abc"
253 }
254 do
255 local _tab_0 = "table" == type(tb)
256 local _match_0 = false
257 if _tab_0 then
258 local x = tb.x
259 local y = tb.y
260 if x ~= nil and y ~= nil then
261 print("x: " .. tostring(x) .. " with y: " .. tostring(y))
262 _match_0 = true
263 end
264 end
265 if not _match_0 then
266 if _tab_0 then
267 local x = tb.x
268 if x ~= nil then
269 print("x: " .. tostring(x) .. " only")
270 end
271 end
272 end
273 end
274end
275do
276 local matched
277 do
278 local _exp_0 = tb
279 if 1 == _exp_0 then
280 matched = "1"
281 else
282 local _tab_0 = "table" == type(_exp_0)
283 local _match_0 = false
284 if _tab_0 then
285 local x = _exp_0.x
286 if x ~= nil then
287 matched = x
288 _match_0 = true
289 end
290 end
291 if not _match_0 then
292 if false == _exp_0 then
293 matched = "false"
294 else
295 matched = nil
296 end
297 end
298 end
299 end
300end
301do
302 local _exp_0 = tb
303 if nil == _exp_0 then
304 return "invalid"
305 else
306 do
307 local _tab_0 = "table" == type(_exp_0)
308 local _match_0 = false
309 if _tab_0 then
310 local a = _exp_0.a
311 local b = _exp_0.b
312 if a ~= nil and b ~= nil then
313 return tostring(a + b)
314 _match_0 = true
315 end
316 end
317 if not _match_0 then
318 if 1 == _exp_0 or 2 == _exp_0 or 3 == _exp_0 or 4 == _exp_0 or 5 == _exp_0 then
319 return "number 1 - 5"
320 else
321 if _tab_0 then
322 local alwaysMatch = _exp_0.alwaysMatch
323 if alwaysMatch == nil then
324 alwaysMatch = "fallback"
325 end
326 if alwaysMatch ~= nil then
327 return alwaysMatch
328 end
329 else
330 return "should not reach here"
331 end
332 end
333 end
334 end
335 end
87end 336end
337return nil
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h
index 571c18e..05ac5ef 100755
--- a/src/yuescript/yue_ast.h
+++ b/src/yuescript/yue_ast.h
@@ -249,8 +249,14 @@ AST_NODE(With)
249 AST_MEMBER(With, &eop, &valueList, &assigns, &body) 249 AST_MEMBER(With, &eop, &valueList, &assigns, &body)
250AST_END(With, "with"sv) 250AST_END(With, "with"sv)
251 251
252AST_NODE(SwitchList)
253 ast_ptr<true, Seperator_t> sep;
254 ast_list<true, Exp_t> exprs;
255 AST_MEMBER(SwitchList, &sep, &exprs)
256AST_END(SwitchList, "switch_list"sv)
257
252AST_NODE(SwitchCase) 258AST_NODE(SwitchCase)
253 ast_ptr<true, ExpList_t> valueList; 259 ast_ptr<true, SwitchList_t> valueList;
254 ast_sel<true, Block_t, Statement_t> body; 260 ast_sel<true, Block_t, Statement_t> body;
255 AST_MEMBER(SwitchCase, &valueList, &body) 261 AST_MEMBER(SwitchCase, &valueList, &body)
256AST_END(SwitchCase, "switch_case"sv) 262AST_END(SwitchCase, "switch_case"sv)
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp
index 84cbf37..468dc23 100755
--- a/src/yuescript/yue_compiler.cpp
+++ b/src/yuescript/yue_compiler.cpp
@@ -56,7 +56,7 @@ using namespace parserlib;
56 56
57typedef std::list<std::string> str_list; 57typedef std::list<std::string> str_list;
58 58
59const std::string_view version = "0.12.0"sv; 59const std::string_view version = "0.13.0"sv;
60const std::string_view extension = "yue"sv; 60const std::string_view extension = "yue"sv;
61 61
62class YueCompilerImpl { 62class YueCompilerImpl {
@@ -283,15 +283,15 @@ private:
283 }; 283 };
284 284
285 struct DestructItem { 285 struct DestructItem {
286 bool isVariable = false; 286 ast_ptr<true, Exp_t> target;
287 std::string name; 287 std::string targetVar;
288 std::string structure; 288 std::string structure;
289 ast_ptr<true, Exp_t> defVal; 289 ast_ptr<true, Exp_t> defVal;
290 bool isMetatable = false;
291 }; 290 };
292 291
293 struct Destructure { 292 struct Destructure {
294 std::string value; 293 ast_ptr<true, ast_node> value;
294 std::string valueVar;
295 std::list<DestructItem> items; 295 std::list<DestructItem> items;
296 }; 296 };
297 297
@@ -562,6 +562,13 @@ private:
562 } 562 }
563 break; 563 break;
564 } 564 }
565 case id<SwitchList_t>(): {
566 auto expList = static_cast<SwitchList_t*>(item);
567 if (expList->exprs.size() == 1) {
568 exp = static_cast<Exp_t*>(expList->exprs.front());
569 }
570 break;
571 }
565 case id<unary_exp_t>(): { 572 case id<unary_exp_t>(): {
566 auto unary = static_cast<unary_exp_t*>(item); 573 auto unary = static_cast<unary_exp_t*>(item);
567 if (unary->expos.size() == 1) { 574 if (unary->expos.size() == 1) {
@@ -800,7 +807,7 @@ private:
800 return Empty; 807 return Empty;
801 } 808 }
802 809
803 std::string singleVariableFrom(ast_node* expList) { 810 std::string singleVariableFrom(ast_node* expList, bool accessing) {
804 if (!ast_is<Exp_t, ExpList_t>(expList)) return Empty; 811 if (!ast_is<Exp_t, ExpList_t>(expList)) return Empty;
805 BLOCK_START 812 BLOCK_START
806 auto value = singleValueFrom(expList); 813 auto value = singleValueFrom(expList);
@@ -809,9 +816,16 @@ private:
809 BREAK_IF(!chainValue); 816 BREAK_IF(!chainValue);
810 BREAK_IF(chainValue->items.size() != 1); 817 BREAK_IF(chainValue->items.size() != 1);
811 auto callable = ast_cast<Callable_t>(chainValue->items.front()); 818 auto callable = ast_cast<Callable_t>(chainValue->items.front());
812 BREAK_IF(!callable || !(callable->item.is<Variable_t>() || callable->getByPath<SelfName_t,self_t>())); 819 BREAK_IF(!callable || !(callable->item.is<Variable_t>() || callable->getByPath<SelfName_t, self_t>()));
813 str_list tmp; 820 str_list tmp;
814 transformCallable(callable, tmp); 821 if (accessing) {
822 transformCallable(callable, tmp);
823 } else {
824 bool lintGlobal = _config.lintGlobalVariable;
825 _config.lintGlobalVariable = false;
826 transformCallable(callable, tmp);
827 _config.lintGlobalVariable = lintGlobal;
828 }
815 return tmp.back(); 829 return tmp.back();
816 BLOCK_END 830 BLOCK_END
817 return Empty; 831 return Empty;
@@ -1173,7 +1187,7 @@ private:
1173 _config.lintGlobalVariable = false; 1187 _config.lintGlobalVariable = false;
1174 if (!assignment->action.is<Assign_t>()) return vars; 1188 if (!assignment->action.is<Assign_t>()) return vars;
1175 for (auto exp : assignment->expList->exprs.objects()) { 1189 for (auto exp : assignment->expList->exprs.objects()) {
1176 auto var = singleVariableFrom(exp); 1190 auto var = singleVariableFrom(exp, true);
1177 vars.push_back(var.empty() ? Empty : var); 1191 vars.push_back(var.empty() ? Empty : var);
1178 } 1192 }
1179 _config.lintGlobalVariable = lintGlobal; 1193 _config.lintGlobalVariable = lintGlobal;
@@ -1185,7 +1199,7 @@ private:
1185 bool lintGlobal = _config.lintGlobalVariable; 1199 bool lintGlobal = _config.lintGlobalVariable;
1186 _config.lintGlobalVariable = false; 1200 _config.lintGlobalVariable = false;
1187 for (auto exp : with->valueList->exprs.objects()) { 1201 for (auto exp : with->valueList->exprs.objects()) {
1188 auto var = singleVariableFrom(exp); 1202 auto var = singleVariableFrom(exp, true);
1189 vars.push_back(var.empty() ? Empty : var); 1203 vars.push_back(var.empty() ? Empty : var);
1190 } 1204 }
1191 _config.lintGlobalVariable = lintGlobal; 1205 _config.lintGlobalVariable = lintGlobal;
@@ -1241,13 +1255,15 @@ private:
1241 } 1255 }
1242 1256
1243 std::string getDestrucureDefine(ExpListAssign_t* assignment) { 1257 std::string getDestrucureDefine(ExpListAssign_t* assignment) {
1244 auto info = extractDestructureInfo(assignment, true); 1258 auto info = extractDestructureInfo(assignment, true, false);
1245 if (!info.first.empty()) { 1259 if (!info.first.empty()) {
1246 for (const auto& destruct : info.first) { 1260 for (const auto& destruct : info.first) {
1247 str_list defs; 1261 str_list defs;
1248 for (const auto& item : destruct.items) { 1262 for (const auto& item : destruct.items) {
1249 if (item.isVariable && addToScope(item.name)) { 1263 if (!item.targetVar.empty()) {
1250 defs.push_back(item.name); 1264 if (addToScope(item.targetVar)) {
1265 defs.push_back(item.targetVar);
1266 }
1251 } 1267 }
1252 } 1268 }
1253 if (!defs.empty()) _buf << indent() << "local "sv << join(defs,", "sv); 1269 if (!defs.empty()) _buf << indent() << "local "sv << join(defs,", "sv);
@@ -1282,7 +1298,18 @@ private:
1282 return nullptr; 1298 return nullptr;
1283 } 1299 }
1284 1300
1285 void transformAssignment(ExpListAssign_t* assignment, str_list& out) { 1301 ast_ptr<false, ExpListAssign_t> assignmentFrom(Exp_t* target, ast_node* value, ast_node* x) {
1302 auto assignment = x->new_ptr<ExpListAssign_t>();
1303 auto assignList = x->new_ptr<ExpList_t>();
1304 assignList->exprs.push_back(target);
1305 assignment->expList.set(assignList);
1306 auto assign = x->new_ptr<Assign_t>();
1307 assign->values.push_back(value);
1308 assignment->action.set(assign);
1309 return assignment;
1310 }
1311
1312 void transformAssignment(ExpListAssign_t* assignment, str_list& out, bool optionalDestruct = false) {
1286 checkAssignable(assignment->expList); 1313 checkAssignable(assignment->expList);
1287 BLOCK_START 1314 BLOCK_START
1288 auto assign = ast_cast<Assign_t>(assignment->action); 1315 auto assign = ast_cast<Assign_t>(assignment->action);
@@ -1516,7 +1543,7 @@ private:
1516 } 1543 }
1517 } 1544 }
1518 BLOCK_END 1545 BLOCK_END
1519 auto info = extractDestructureInfo(assignment, false); 1546 auto info = extractDestructureInfo(assignment, false, optionalDestruct);
1520 if (info.first.empty()) { 1547 if (info.first.empty()) {
1521 transformAssignmentCommon(assignment, out); 1548 transformAssignmentCommon(assignment, out);
1522 } else { 1549 } else {
@@ -1524,126 +1551,165 @@ private:
1524 if (info.second) { 1551 if (info.second) {
1525 transformAssignmentCommon(info.second, temp); 1552 transformAssignmentCommon(info.second, temp);
1526 } 1553 }
1554 auto x = assignment;
1527 for (auto& destruct : info.first) { 1555 for (auto& destruct : info.first) {
1528 std::list<std::pair<std::string, std::string>> leftPairs; 1556 std::list<std::pair<ast_ptr<true, Exp_t>, ast_ptr<true, Exp_t>>> leftPairs;
1557 bool extraScope = false;
1529 if (destruct.items.size() == 1) { 1558 if (destruct.items.size() == 1) {
1530 auto& pair = destruct.items.front(); 1559 auto& pair = destruct.items.front();
1531 if (!pair.isVariable && pair.defVal) { 1560 if (pair.targetVar.empty() && pair.defVal) {
1532 auto objVar = getUnusedName("_obj_"sv); 1561 extraScope = true;
1533 leftPairs.push_back({pair.name, objVar}); 1562 auto objVar = getUnusedName("_tmp_"sv);
1534 pair.name = objVar; 1563 auto objExp = toAst<Exp_t>(objVar, pair.target);
1535 pair.isVariable = true; 1564 leftPairs.push_back({pair.target, objExp.get()});
1536 } 1565 pair.target.set(objExp);
1537 if (pair.isMetatable) { 1566 pair.targetVar = objVar;
1538 if (pair.isVariable) { 1567 } else if (auto val = singleValueFrom(destruct.value); val->item.is<ChainValue_t>()) {
1539 checkConst(pair.name, assignment); 1568 auto chainValue = static_cast<ChainValue_t*>(val->item.get());
1540 if (addToScope(pair.name)) { 1569 int added = 0;
1541 _buf << indent() << "local "sv << pair.name << nll(assignment); 1570 if (!pair.structure.empty()) {
1571 auto appendChain = toAst<ChainValue_t>("x"s + pair.structure, x);
1572 appendChain->items.pop_front();
1573 for (auto item : appendChain->items.objects()) {
1574 chainValue->items.push_back(item);
1575 added++;
1542 } 1576 }
1543 } 1577 }
1544 bool isLocalValue = isLocal(destruct.value); 1578 auto newAssignment = assignmentFrom(pair.target, destruct.value, x);
1545 std::string objVar; 1579 transformAssignment(newAssignment, temp);
1546 if (isLocalValue) { 1580 while (added > 0) {
1547 objVar = destruct.value; 1581 chainValue->items.pop_back();
1548 } else { 1582 added--;
1549 _buf << indent() << "do"sv << nll(assignment);
1550 pushScope();
1551 objVar = getUnusedName("_obj_"sv);
1552 addToScope(objVar);
1553 _buf << indent() << "local "sv << objVar << " = "sv << destruct.value << nll(assignment);
1554 temp.push_back(clearBuf());
1555 } 1583 }
1556 auto valueExp = toAst<Exp_t>(objVar + pair.structure, assignment); 1584 if (pair.defVal) {
1557 transformExp(valueExp, temp, ExpUsage::Closure); 1585 auto stmt = toAst<Statement_t>(pair.targetVar + "=nil if "s + pair.targetVar + "==nil", pair.defVal);
1558 _buf << indent() << pair.name << " = "sv << temp.back() << nll(assignment); 1586 auto defAssign = stmt->content.as<ExpListAssign_t>();
1559 if (!isLocalValue) { 1587 auto assign = defAssign->action.as<Assign_t>();
1560 popScope(); 1588 assign->values.clear();
1561 _buf << indent() << "end"sv << nlr(assignment); 1589 assign->values.push_back(pair.defVal);
1590 transformStatement(stmt, temp);
1562 } 1591 }
1563 temp.back() = clearBuf(); 1592 continue;
1564 } else {
1565 _buf << indent();
1566 if (pair.isVariable) {
1567 checkConst(pair.name, assignment);
1568 if (addToScope(pair.name)) _buf << "local "sv;
1569 }
1570 _buf << pair.name << " = "sv << destruct.value << pair.structure << nll(assignment);
1571 temp.push_back(clearBuf());
1572 } 1593 }
1573 } else if (_parser.match<Name_t>(destruct.value) && isLocal(destruct.value)) { 1594 if (extraScope) {
1574 str_list defs, names, values; 1595 temp.push_back(indent() + "do"s + nll(x));
1575 bool isMetatable = false; 1596 pushScope();
1576 for (auto& item : destruct.items) { 1597 }
1577 if (item.isVariable) { 1598 if (!pair.targetVar.empty()) {
1578 checkConst(item.name, assignment); 1599 checkConst(pair.targetVar, x);
1579 if (addToScope(item.name)) defs.push_back(item.name); 1600 if (addToScope(pair.targetVar)) {
1580 } else if (item.defVal) { 1601 _buf << indent() << "local "sv << pair.targetVar << nll(x);
1581 auto objVar = getUnusedName("_obj_"sv); 1602 temp.push_back(clearBuf());
1582 addToScope(objVar);
1583 defs.push_back(objVar);
1584 leftPairs.push_back({item.name, objVar});
1585 item.name = objVar;
1586 } 1603 }
1587 if (item.isMetatable) isMetatable = true;
1588 names.push_back(item.name);
1589 values.push_back(item.structure);
1590 } 1604 }
1591 for (auto& v : values) v.insert(0, destruct.value); 1605 bool isLocalValue = isLocal(destruct.valueVar);
1592 if (isMetatable) { 1606 std::string objVar;
1593 auto newExpList = toAst<ExpList_t>(join(values, ","sv), assignment); 1607 if (isLocalValue) {
1594 transformExpList(newExpList, temp); 1608 objVar = destruct.valueVar;
1595 } else { 1609 } else {
1596 temp.push_back(join(values, ", "sv)); 1610 temp.push_back(indent() + "do"s + nll(x));
1611 pushScope();
1612 objVar = getUnusedName("_obj_"sv);
1613 auto newAssignment = assignmentFrom(toAst<Exp_t>(objVar, x), destruct.value, x);
1614 transformAssignment(newAssignment, temp);
1597 } 1615 }
1598 if (defs.empty()) { 1616 auto valueExp = toAst<Exp_t>(objVar + pair.structure, x);
1599 _buf << indent() << join(names, ", "sv) << " = "sv << temp.back() << nll(assignment); 1617 auto newAssignment = assignmentFrom(pair.target, valueExp, x);
1600 } else { 1618 transformAssignment(newAssignment, temp);
1601 _buf << indent() << "local "sv; 1619 if (!isLocalValue) {
1602 if (defs.size() != names.size()) { 1620 popScope();
1603 _buf << join(defs, ", "sv) << nll(assignment) << indent(); 1621 _buf << indent() << "end"sv << nlr(x);
1604 } 1622 temp.push_back(clearBuf());
1605 _buf << join(names, ", "sv) << " = "sv << temp.back() << nll(assignment);
1606 } 1623 }
1607 temp.back() = clearBuf();
1608 } else { 1624 } else {
1609 str_list defs, names, values; 1625 str_list values, defs;
1610 bool isMetatable = false; 1626 std::list<Exp_t*> names;
1627 pushScope();
1611 for (auto& item : destruct.items) { 1628 for (auto& item : destruct.items) {
1612 if (item.isVariable) { 1629 if (!item.targetVar.empty()) {
1613 checkConst(item.name, assignment); 1630 if (!isDefined(item.targetVar)) {
1614 if (addToScope(item.name)) defs.push_back(item.name); 1631 defs.push_back(item.targetVar);
1632 }
1615 } else if (item.defVal) { 1633 } else if (item.defVal) {
1616 auto objVar = getUnusedName("_obj_"sv); 1634 extraScope = true;
1635 auto objVar = getUnusedName("_tmp_"sv);
1617 addToScope(objVar); 1636 addToScope(objVar);
1618 defs.push_back(objVar); 1637 auto objExp = toAst<Exp_t>(objVar, item.target);
1619 leftPairs.push_back({item.name, objVar}); 1638 leftPairs.push_back({item.target, objExp.get()});
1620 item.name = objVar; 1639 item.target.set(objExp);
1640 item.targetVar = objVar;
1621 } 1641 }
1622 if (item.isMetatable) isMetatable = true; 1642 names.push_back(item.target);
1623 names.push_back(item.name);
1624 values.push_back(item.structure); 1643 values.push_back(item.structure);
1625 } 1644 }
1626 if (!defs.empty()) _buf << indent() << "local "sv << join(defs,", "sv) << nll(assignment); 1645 popScope();
1627 _buf << indent() << "do"sv << nll(assignment); 1646 if (_parser.match<Name_t>(destruct.valueVar) && isLocal(destruct.valueVar)) {
1628 pushScope(); 1647 for (auto& v : values) {
1629 auto objVar = getUnusedName("_obj_"sv); 1648 v.insert(0, destruct.valueVar);
1630 addToScope(objVar); 1649 }
1631 for (auto& v : values) v.insert(0, objVar); 1650 if (extraScope) {
1632 if (isMetatable) { 1651 if (!defs.empty()) {
1633 auto newExpList = toAst<ExpList_t>(join(values, ","sv), assignment); 1652 for (const auto& def : defs) {
1634 transformExpList(newExpList, temp); 1653 checkConst(def, x);
1654 addToScope(def);
1655 }
1656 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nll(x));
1657 }
1658 temp.push_back(indent() + "do"s + nll(x));
1659 pushScope();
1660 }
1635 } else { 1661 } else {
1636 temp.push_back(join(values, ", "sv)); 1662 if (!defs.empty()) {
1663 for (const auto& def : defs) {
1664 checkConst(def, x);
1665 addToScope(def);
1666 }
1667 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nll(x));
1668 }
1669 extraScope = true;
1670 temp.push_back(indent() + "do"s + nll(x));
1671 pushScope();
1672 auto valVar = getUnusedName("_obj_"sv);
1673 auto targetVar = toAst<Exp_t>(valVar, destruct.value);
1674 auto newAssignment = assignmentFrom(targetVar, destruct.value, destruct.value);
1675 transformAssignment(newAssignment, temp);
1676 for (auto& v : values) {
1677 v.insert(0, valVar);
1678 }
1679 }
1680 if (optionalDestruct) {
1681 while (!names.empty()) {
1682 auto name = names.front();
1683 names.pop_front();
1684 auto value = values.front();
1685 values.pop_front();
1686 auto valueList = toAst<ExpList_t>(value, x);
1687 auto newAssignment = x->new_ptr<ExpListAssign_t>();
1688 auto assignList = x->new_ptr<ExpList_t>();
1689 assignList->exprs.push_back(name);
1690 newAssignment->expList.set(assignList);
1691 auto assign = x->new_ptr<Assign_t>();
1692 assign->values.dup(valueList->exprs);
1693 newAssignment->action.set(assign);
1694 transformAssignment(newAssignment, temp);
1695 }
1696 } else {
1697 auto valueList = toAst<ExpList_t>(join(values, ","sv), x);
1698 auto newAssignment = x->new_ptr<ExpListAssign_t>();
1699 auto assignList = x->new_ptr<ExpList_t>();
1700 for (auto name : names) {
1701 assignList->exprs.push_back(name);
1702 }
1703 newAssignment->expList.set(assignList);
1704 auto assign = x->new_ptr<Assign_t>();
1705 assign->values.dup(valueList->exprs);
1706 newAssignment->action.set(assign);
1707 transformAssignment(newAssignment, temp);
1637 } 1708 }
1638 _buf << indent() << "local "sv << objVar << " = "sv << destruct.value << nll(assignment);
1639 _buf << indent() << join(names, ", "sv) << " = "sv << temp.back() << nll(assignment);
1640 popScope();
1641 _buf << indent() << "end"sv << nll(assignment);
1642 temp.back() = clearBuf();
1643 } 1709 }
1644 for (const auto& item : destruct.items) { 1710 for (const auto& item : destruct.items) {
1645 if (item.defVal) { 1711 if (item.defVal) {
1646 auto stmt = toAst<Statement_t>(item.name + "=nil if "s + item.name + "==nil", item.defVal); 1712 auto stmt = toAst<Statement_t>(item.targetVar + "=nil if "s + item.targetVar + "==nil", item.defVal);
1647 auto defAssign = stmt->content.as<ExpListAssign_t>(); 1713 auto defAssign = stmt->content.as<ExpListAssign_t>();
1648 auto assign = defAssign->action.as<Assign_t>(); 1714 auto assign = defAssign->action.as<Assign_t>();
1649 assign->values.clear(); 1715 assign->values.clear();
@@ -1652,9 +1718,14 @@ private:
1652 } 1718 }
1653 } 1719 }
1654 for (const auto& item : leftPairs) { 1720 for (const auto& item : leftPairs) {
1655 _buf << indent() << item.first << " = "sv << item.second << nll(assignment); 1721 auto newAssignment = assignmentFrom(item.first, item.second, x);
1722 transformAssignment(newAssignment, temp);
1723 }
1724 if (extraScope) {
1725 popScope();
1726 _buf << indent() << "end"sv << nlr(x);
1727 temp.push_back(clearBuf());
1656 } 1728 }
1657 temp.push_back(clearBuf());
1658 } 1729 }
1659 out.push_back(join(temp)); 1730 out.push_back(join(temp));
1660 } 1731 }
@@ -1671,8 +1742,9 @@ private:
1671 } 1742 }
1672 } 1743 }
1673 1744
1674 std::list<DestructItem> destructFromExp(ast_node* node) { 1745 std::list<DestructItem> destructFromExp(ast_node* node, bool optional) {
1675 const node_container* tableItems = nullptr; 1746 const node_container* tableItems = nullptr;
1747 auto sep = optional ? "?"s : Empty;
1676 switch (node->getId()) { 1748 switch (node->getId()) {
1677 case id<Exp_t>(): { 1749 case id<Exp_t>(): {
1678 auto item = singleValueFrom(node)->item.get(); 1750 auto item = singleValueFrom(node)->item.get();
@@ -1713,27 +1785,18 @@ private:
1713 auto item = value->item.get(); 1785 auto item = value->item.get();
1714 if (ast_is<simple_table_t>(item) || 1786 if (ast_is<simple_table_t>(item) ||
1715 item->getByPath<TableLit_t>()) { 1787 item->getByPath<TableLit_t>()) {
1716 auto subPairs = destructFromExp(pair); 1788 auto subPairs = destructFromExp(pair, optional);
1717 for (auto& p : subPairs) { 1789 for (auto& p : subPairs) {
1718 pairs.push_back({p.isVariable, p.name, 1790 pairs.push_back({p.target, p.targetVar,
1719 '[' + std::to_string(index) + ']' + p.structure, 1791 '[' + std::to_string(index) + ']' + sep + p.structure,
1720 p.defVal, p.isMetatable}); 1792 p.defVal});
1721 } 1793 }
1722 } else { 1794 } else {
1723 bool lintGlobal = _config.lintGlobalVariable;
1724 _config.lintGlobalVariable = false;
1725 auto exp = static_cast<Exp_t*>(pair); 1795 auto exp = static_cast<Exp_t*>(pair);
1726 auto varName = singleVariableFrom(exp); 1796 auto varName = singleVariableFrom(exp, false);
1727 if (varName == "_"sv) break; 1797 if (varName == "_"sv) break;
1728 bool isVariable = !varName.empty();
1729 if (!isVariable) {
1730 str_list temp;
1731 transformExp(exp, temp, ExpUsage::Closure);
1732 varName = std::move(temp.back());
1733 }
1734 _config.lintGlobalVariable = lintGlobal;
1735 pairs.push_back({ 1798 pairs.push_back({
1736 isVariable, 1799 exp,
1737 varName, 1800 varName,
1738 '[' + std::to_string(index) + ']', 1801 '[' + std::to_string(index) + ']',
1739 nullptr 1802 nullptr
@@ -1744,11 +1807,7 @@ private:
1744 case id<variable_pair_t>(): { 1807 case id<variable_pair_t>(): {
1745 auto vp = static_cast<variable_pair_t*>(pair); 1808 auto vp = static_cast<variable_pair_t*>(pair);
1746 auto name = _parser.toString(vp->name); 1809 auto name = _parser.toString(vp->name);
1747 if (LuaKeywords.find(name) != LuaKeywords.end()) { 1810 pairs.push_back({toAst<Exp_t>(name, vp).get(), name, '.' + name, nullptr});
1748 pairs.push_back({true, name, "[\""s + name + "\"]"s, nullptr});
1749 } else {
1750 pairs.push_back({true, name, '.' + name, nullptr});
1751 }
1752 break; 1811 break;
1753 } 1812 }
1754 case id<normal_pair_t>(): { 1813 case id<normal_pair_t>(): {
@@ -1769,29 +1828,19 @@ private:
1769 auto item = singleValueFrom(exp)->item.get(); 1828 auto item = singleValueFrom(exp)->item.get();
1770 if (ast_is<simple_table_t>(item) || 1829 if (ast_is<simple_table_t>(item) ||
1771 item->getByPath<TableLit_t>()) { 1830 item->getByPath<TableLit_t>()) {
1772 auto subPairs = destructFromExp(exp); 1831 auto subPairs = destructFromExp(exp, optional);
1773 for (auto& p : subPairs) { 1832 for (auto& p : subPairs) {
1774 pairs.push_back({ 1833 pairs.push_back({
1775 p.isVariable, 1834 p.target,
1776 p.name, 1835 p.targetVar,
1777 keyName + p.structure, 1836 keyName + sep + p.structure,
1778 p.defVal, 1837 p.defVal
1779 p.isMetatable
1780 }); 1838 });
1781 } 1839 }
1782 } else { 1840 } else {
1783 bool lintGlobal = _config.lintGlobalVariable; 1841 auto varName = singleVariableFrom(exp, false);
1784 _config.lintGlobalVariable = false;
1785 auto varName = singleVariableFrom(exp);
1786 bool isVariable = !varName.empty();
1787 if (!isVariable) {
1788 str_list temp;
1789 transformExp(exp, temp, ExpUsage::Closure);
1790 varName = std::move(temp.back());
1791 }
1792 _config.lintGlobalVariable = lintGlobal;
1793 pairs.push_back({ 1842 pairs.push_back({
1794 isVariable, 1843 exp,
1795 varName, 1844 varName,
1796 keyName, 1845 keyName,
1797 nullptr 1846 nullptr
@@ -1800,14 +1849,13 @@ private:
1800 break; 1849 break;
1801 } 1850 }
1802 if (np->value.is<TableBlock_t>()) { 1851 if (np->value.is<TableBlock_t>()) {
1803 auto subPairs = destructFromExp(np->value); 1852 auto subPairs = destructFromExp(np->value, optional);
1804 for (auto& p : subPairs) { 1853 for (auto& p : subPairs) {
1805 pairs.push_back({ 1854 pairs.push_back({
1806 p.isVariable, 1855 p.target,
1807 p.name, 1856 p.targetVar,
1808 keyName + p.structure, 1857 keyName + sep + p.structure,
1809 p.defVal, 1858 p.defVal
1810 p.isMetatable
1811 }); 1859 });
1812 } 1860 }
1813 } 1861 }
@@ -1816,14 +1864,13 @@ private:
1816 case id<TableBlockIndent_t>(): { 1864 case id<TableBlockIndent_t>(): {
1817 auto tb = static_cast<TableBlockIndent_t*>(pair); 1865 auto tb = static_cast<TableBlockIndent_t*>(pair);
1818 ++index; 1866 ++index;
1819 auto subPairs = destructFromExp(tb); 1867 auto subPairs = destructFromExp(tb, optional);
1820 for (auto& p : subPairs) { 1868 for (auto& p : subPairs) {
1821 pairs.push_back({ 1869 pairs.push_back({
1822 p.isVariable, 1870 p.target,
1823 p.name, 1871 p.targetVar,
1824 '[' + std::to_string(index) + ']' + p.structure, 1872 '[' + std::to_string(index) + ']' + sep + p.structure,
1825 p.defVal, 1873 p.defVal
1826 p.isMetatable
1827 }); 1874 });
1828 } 1875 }
1829 break; 1876 break;
@@ -1841,18 +1888,9 @@ private:
1841 item->getByPath<TableLit_t>()) { 1888 item->getByPath<TableLit_t>()) {
1842 throw std::logic_error(_info.errorMessage("invalid use of default value"sv, dp->defVal)); 1889 throw std::logic_error(_info.errorMessage("invalid use of default value"sv, dp->defVal));
1843 } else { 1890 } else {
1844 bool lintGlobal = _config.lintGlobalVariable; 1891 auto varName = singleVariableFrom(exp, false);
1845 _config.lintGlobalVariable = false;
1846 auto varName = singleVariableFrom(exp);
1847 bool isVariable = !varName.empty();
1848 if (!isVariable) {
1849 str_list temp;
1850 transformExp(exp, temp, ExpUsage::Closure);
1851 varName = std::move(temp.back());
1852 }
1853 _config.lintGlobalVariable = lintGlobal;
1854 pairs.push_back({ 1892 pairs.push_back({
1855 isVariable, 1893 exp,
1856 varName, 1894 varName,
1857 '[' + std::to_string(index) + ']', 1895 '[' + std::to_string(index) + ']',
1858 dp->defVal 1896 dp->defVal
@@ -1872,27 +1910,18 @@ private:
1872 keyName = "."s + keyName; 1910 keyName = "."s + keyName;
1873 } 1911 }
1874 } 1912 }
1875 if (auto exp = dp->value.as<Exp_t>()) { 1913 if (auto exp = dp->value.get()) {
1876 if (!isAssignable(exp)) throw std::logic_error(_info.errorMessage("can't destructure value"sv, exp)); 1914 if (!isAssignable(exp)) throw std::logic_error(_info.errorMessage("can't destructure value"sv, exp));
1877 bool lintGlobal = _config.lintGlobalVariable; 1915 auto varName = singleVariableFrom(exp, false);
1878 _config.lintGlobalVariable = false;
1879 auto varName = singleVariableFrom(exp);
1880 bool isVariable = !varName.empty();
1881 if (!isVariable) {
1882 str_list temp;
1883 transformExp(exp, temp, ExpUsage::Closure);
1884 varName = std::move(temp.back());
1885 }
1886 _config.lintGlobalVariable = lintGlobal;
1887 pairs.push_back({ 1916 pairs.push_back({
1888 isVariable, 1917 exp,
1889 varName, 1918 varName,
1890 keyName, 1919 keyName,
1891 dp->defVal 1920 dp->defVal
1892 }); 1921 });
1893 } else { 1922 } else {
1894 pairs.push_back({ 1923 pairs.push_back({
1895 true, 1924 toAst<Exp_t>(valueStr, dp).get(),
1896 valueStr, 1925 valueStr,
1897 keyName, 1926 keyName,
1898 dp->defVal 1927 dp->defVal
@@ -1910,8 +1939,7 @@ private:
1910 newPair->key.set(newKey); 1939 newPair->key.set(newKey);
1911 if (newPair->value) { 1940 if (newPair->value) {
1912 newPair->value.set(mp->value); 1941 newPair->value.set(mp->value);
1913 } 1942 } else {
1914 else {
1915 newPair->value.set(toAst<Exp_t>(key, mp->key)); 1943 newPair->value.set(toAst<Exp_t>(key, mp->key));
1916 } 1944 }
1917 } else { 1945 } else {
@@ -1959,14 +1987,13 @@ private:
1959 simpleValue->value.set(subMetaDestruct); 1987 simpleValue->value.set(subMetaDestruct);
1960 auto value = subMetaDestruct->new_ptr<Value_t>(); 1988 auto value = subMetaDestruct->new_ptr<Value_t>();
1961 value->item.set(simpleValue); 1989 value->item.set(simpleValue);
1962 auto subPairs = destructFromExp(newExp(value, subMetaDestruct)); 1990 auto subPairs = destructFromExp(newExp(value, subMetaDestruct), optional);
1963 for (const auto& p : subPairs) { 1991 for (const auto& p : subPairs) {
1964 pairs.push_back({ 1992 pairs.push_back({
1965 p.isVariable, 1993 p.target,
1966 p.name, 1994 p.targetVar,
1967 ".#"s + p.structure, 1995 ".#"s + sep + p.structure,
1968 p.defVal, 1996 p.defVal
1969 true
1970 }); 1997 });
1971 } 1998 }
1972 } 1999 }
@@ -1974,7 +2001,7 @@ private:
1974 } 2001 }
1975 2002
1976 std::pair<std::list<Destructure>, ast_ptr<false, ExpListAssign_t>> 2003 std::pair<std::list<Destructure>, ast_ptr<false, ExpListAssign_t>>
1977 extractDestructureInfo(ExpListAssign_t* assignment, bool varDefOnly) { 2004 extractDestructureInfo(ExpListAssign_t* assignment, bool varDefOnly, bool optional) {
1978 auto x = assignment; 2005 auto x = assignment;
1979 std::list<Destructure> destructs; 2006 std::list<Destructure> destructs;
1980 if (!assignment->action.is<Assign_t>()) return {destructs, nullptr}; 2007 if (!assignment->action.is<Assign_t>()) return {destructs, nullptr};
@@ -1993,10 +2020,10 @@ private:
1993 while (values.size() < size) values.emplace_back(nullNode); 2020 while (values.size() < size) values.emplace_back(nullNode);
1994 } 2021 }
1995 using iter = node_container::iterator; 2022 using iter = node_container::iterator;
1996 std::vector<std::pair<iter,iter>> destructPairs; 2023 std::vector<std::pair<iter, iter>> destructPairs;
1997 ast_list<false, ast_node> valueItems; 2024 ast_list<false, ast_node> valueItems;
1998 if (!varDefOnly) pushScope();
1999 str_list temp; 2025 str_list temp;
2026 pushScope();
2000 for (auto i = exprs.begin(), j = values.begin(); i != exprs.end(); ++i, ++j) { 2027 for (auto i = exprs.begin(), j = values.begin(); i != exprs.end(); ++i, ++j) {
2001 auto expr = *i; 2028 auto expr = *i;
2002 auto value = singleValueFrom(expr); 2029 auto value = singleValueFrom(expr);
@@ -2019,7 +2046,7 @@ private:
2019 } else { 2046 } else {
2020 throw std::logic_error(_info.errorMessage("can not destructure a nil value"sv, destructNode)); 2047 throw std::logic_error(_info.errorMessage("can not destructure a nil value"sv, destructNode));
2021 } 2048 }
2022 destructPairs.push_back({i,j}); 2049 destructPairs.push_back({i, j});
2023 auto subDestruct = destructNode->new_ptr<TableLit_t>(); 2050 auto subDestruct = destructNode->new_ptr<TableLit_t>();
2024 auto subMetaDestruct = destructNode->new_ptr<TableLit_t>(); 2051 auto subMetaDestruct = destructNode->new_ptr<TableLit_t>();
2025 const node_container* dlist = nullptr; 2052 const node_container* dlist = nullptr;
@@ -2103,15 +2130,14 @@ private:
2103 if (!tab->values.empty()) { 2130 if (!tab->values.empty()) {
2104 auto& destruct = destructs.emplace_back(); 2131 auto& destruct = destructs.emplace_back();
2105 if (!varDefOnly) { 2132 if (!varDefOnly) {
2106 transformAssignItem(valueItems.back(), temp); 2133 destruct.value = valueItems.back();
2107 destruct.value = std::move(temp.back()); 2134 destruct.valueVar = singleVariableFrom(destruct.value, false);
2108 temp.pop_back();
2109 } 2135 }
2110 auto simpleValue = tab->new_ptr<SimpleValue_t>(); 2136 auto simpleValue = tab->new_ptr<SimpleValue_t>();
2111 simpleValue->value.set(tab); 2137 simpleValue->value.set(tab);
2112 auto value = tab->new_ptr<Value_t>(); 2138 auto value = tab->new_ptr<Value_t>();
2113 value->item.set(simpleValue); 2139 value->item.set(simpleValue);
2114 auto pairs = destructFromExp(newExp(value, expr)); 2140 auto pairs = destructFromExp(newExp(value, expr), optional);
2115 if (pairs.empty()) { 2141 if (pairs.empty()) {
2116 throw std::logic_error(_info.errorMessage("expect items to be destructured"sv, tab)); 2142 throw std::logic_error(_info.errorMessage("expect items to be destructured"sv, tab));
2117 } 2143 }
@@ -2122,18 +2148,34 @@ private:
2122 item.structure.clear(); 2148 item.structure.clear();
2123 } 2149 }
2124 } else if (tab == subMetaDestruct.get()) { 2150 } else if (tab == subMetaDestruct.get()) {
2125 destruct.value.insert(0, globalVar("getmetatable"sv, tab) + '('); 2151 auto p = destruct.value.get();
2126 destruct.value.append(")"sv); 2152 auto chainValue = toAst<ChainValue_t>("getmetatable()", p);
2153 static_cast<Invoke_t*>(chainValue->items.back())->args.push_back(destruct.value);
2154 auto value = p->new_ptr<Value_t>();
2155 value->item.set(chainValue);
2156 auto exp = newExp(value, p);
2157 destruct.value.set(exp);
2158 destruct.valueVar.clear();
2127 } else if (destruct.items.size() == 1 && !singleValueFrom(*j)) { 2159 } else if (destruct.items.size() == 1 && !singleValueFrom(*j)) {
2128 destruct.value.insert(0, "("sv); 2160 auto p = destruct.value.get();
2129 destruct.value.append(")"sv); 2161 auto parens = p->new_ptr<Parens_t>();
2162 parens->expr.set(p);
2163 auto callable = p->new_ptr<Callable_t>();
2164 callable->item.set(parens);
2165 auto chainValue = p->new_ptr<ChainValue_t>();
2166 chainValue->items.push_back(callable);
2167 auto value = p->new_ptr<Value_t>();
2168 value->item.set(chainValue);
2169 auto exp = newExp(value, p);
2170 destruct.value.set(exp);
2171 destruct.valueVar.clear();
2130 } 2172 }
2131 } 2173 }
2132 } 2174 }
2133 } 2175 }
2134 } 2176 }
2135 } 2177 }
2136 if (!varDefOnly) popScope(); 2178 popScope();
2137 for (const auto& p : destructPairs) { 2179 for (const auto& p : destructPairs) {
2138 exprs.erase(p.first); 2180 exprs.erase(p.first);
2139 values.erase(p.second); 2181 values.erase(p.second);
@@ -2211,7 +2253,7 @@ private:
2211 BLOCK_START 2253 BLOCK_START
2212 auto exp = ast_cast<Exp_t>(item); 2254 auto exp = ast_cast<Exp_t>(item);
2213 BREAK_IF(!exp); 2255 BREAK_IF(!exp);
2214 auto var = singleVariableFrom(exp); 2256 auto var = singleVariableFrom(exp, true);
2215 BREAK_IF(!var.empty()); 2257 BREAK_IF(!var.empty());
2216 auto upVar = getUnusedName("_update_"sv); 2258 auto upVar = getUnusedName("_update_"sv);
2217 auto newAssignment = x->new_ptr<ExpListAssign_t>(); 2259 auto newAssignment = x->new_ptr<ExpListAssign_t>();
@@ -2373,15 +2415,12 @@ private:
2373 if (asmt) { 2415 if (asmt) {
2374 ast_ptr<false, ast_node> exp = asmt->expList->exprs.front(); 2416 ast_ptr<false, ast_node> exp = asmt->expList->exprs.front();
2375 auto x = exp; 2417 auto x = exp;
2376 bool lintGlobal = _config.lintGlobalVariable; 2418 auto var = singleVariableFrom(exp, false);
2377 _config.lintGlobalVariable = false;
2378 auto var = singleVariableFrom(exp);
2379 _config.lintGlobalVariable = lintGlobal;
2380 if (var.empty() || isGlobal(var)) { 2419 if (var.empty() || isGlobal(var)) {
2381 storingValue = true; 2420 storingValue = true;
2382 auto desVar = getUnusedName("_des_"sv); 2421 auto desVar = getUnusedName("_des_"sv);
2383 if (asmt->assign->values.objects().size() == 1) { 2422 if (asmt->assign->values.objects().size() == 1) {
2384 auto var = singleVariableFrom(asmt->assign->values.objects().front()); 2423 auto var = singleVariableFrom(asmt->assign->values.objects().front(), true);
2385 if (!var.empty() && isLocal(var)) { 2424 if (!var.empty() && isLocal(var)) {
2386 desVar = var; 2425 desVar = var;
2387 storingValue = false; 2426 storingValue = false;
@@ -2524,10 +2563,7 @@ private:
2524 } 2563 }
2525 bool findPlaceHolder = false; 2564 bool findPlaceHolder = false;
2526 for (auto a : args->objects()) { 2565 for (auto a : args->objects()) {
2527 bool lintGlobal = _config.lintGlobalVariable; 2566 auto name = singleVariableFrom(a, false);
2528 _config.lintGlobalVariable = false;
2529 auto name = singleVariableFrom(a);
2530 _config.lintGlobalVariable = lintGlobal;
2531 if (name == "_"sv) { 2567 if (name == "_"sv) {
2532 if (!findPlaceHolder) { 2568 if (!findPlaceHolder) {
2533 args->swap(a, arg); 2569 args->swap(a, arg);
@@ -2643,7 +2679,7 @@ private:
2643 funcStart = &temp.emplace_back(); 2679 funcStart = &temp.emplace_back();
2644 pushScope(); 2680 pushScope();
2645 } 2681 }
2646 auto objVar = singleVariableFrom(left); 2682 auto objVar = singleVariableFrom(left, true);
2647 auto prepareValue = [&](bool forAssignment = false) { 2683 auto prepareValue = [&](bool forAssignment = false) {
2648 if (objVar.empty() || !isLocal(objVar)) { 2684 if (objVar.empty() || !isLocal(objVar)) {
2649 if (forAssignment) { 2685 if (forAssignment) {
@@ -2953,10 +2989,7 @@ private:
2953 } 2989 }
2954 bool findPlaceHolder = false; 2990 bool findPlaceHolder = false;
2955 for (auto a : args->objects()) { 2991 for (auto a : args->objects()) {
2956 bool lintGlobal = _config.lintGlobalVariable; 2992 auto name = singleVariableFrom(a, false);
2957 _config.lintGlobalVariable = false;
2958 auto name = singleVariableFrom(a);
2959 _config.lintGlobalVariable = lintGlobal;
2960 if (name == "_"sv) { 2993 if (name == "_"sv) {
2961 if (!findPlaceHolder) { 2994 if (!findPlaceHolder) {
2962 args->swap(a, arg); 2995 args->swap(a, arg);
@@ -3040,14 +3073,14 @@ private:
3040 any->decls.push_back(var); 3073 any->decls.push_back(var);
3041 } 3074 }
3042 } 3075 }
3043 auto info = extractDestructureInfo(assignment, true); 3076 auto info = extractDestructureInfo(assignment, true, false);
3044 if (!info.first.empty()) { 3077 if (!info.first.empty()) {
3045 for (const auto& destruct : info.first) 3078 for (const auto& destruct : info.first)
3046 for (const auto& item : destruct.items) 3079 for (const auto& item : destruct.items)
3047 if (item.isVariable) { 3080 if (!item.targetVar.empty()) {
3048 if (std::isupper(item.name[0]) && capital) { capital->decls.push_back(item.name); 3081 if (std::isupper(item.targetVar[0]) && capital) { capital->decls.push_back(item.targetVar);
3049 } else if (any) { 3082 } else if (any) {
3050 any->decls.push_back(item.name); 3083 any->decls.push_back(item.targetVar);
3051 } 3084 }
3052 } 3085 }
3053 } 3086 }
@@ -4043,7 +4076,7 @@ private:
4043 auto value = x->new_ptr<Value_t>(); 4076 auto value = x->new_ptr<Value_t>();
4044 value->item.set(chainValue); 4077 value->item.set(chainValue);
4045 auto exp = newExp(value, x); 4078 auto exp = newExp(value, x);
4046 callVar = singleVariableFrom(exp); 4079 callVar = singleVariableFrom(exp, true);
4047 if (callVar.empty()) { 4080 if (callVar.empty()) {
4048 callVar = getUnusedName("_call_"s); 4081 callVar = getUnusedName("_call_"s);
4049 auto assignment = x->new_ptr<ExpListAssign_t>(); 4082 auto assignment = x->new_ptr<ExpListAssign_t>();
@@ -4672,7 +4705,7 @@ private:
4672 std::string indexVar = getUnusedName("_idx_"sv); 4705 std::string indexVar = getUnusedName("_idx_"sv);
4673 std::string keyVar = getUnusedName("_key_"sv); 4706 std::string keyVar = getUnusedName("_key_"sv);
4674 std::string valueVar = getUnusedName("_value_"sv); 4707 std::string valueVar = getUnusedName("_value_"sv);
4675 auto objVar = singleVariableFrom(spread->exp); 4708 auto objVar = singleVariableFrom(spread->exp, true);
4676 if (objVar.empty()) { 4709 if (objVar.empty()) {
4677 objVar = getUnusedName("_obj_"); 4710 objVar = getUnusedName("_obj_");
4678 auto assignment = toAst<ExpListAssign_t>(objVar + "=nil"s, item); 4711 auto assignment = toAst<ExpListAssign_t>(objVar + "=nil"s, item);
@@ -5146,7 +5179,7 @@ private:
5146 switch (loopTarget->getId()) { 5179 switch (loopTarget->getId()) {
5147 case id<star_exp_t>(): { 5180 case id<star_exp_t>(): {
5148 auto star_exp = static_cast<star_exp_t*>(loopTarget); 5181 auto star_exp = static_cast<star_exp_t*>(loopTarget);
5149 auto listVar = singleVariableFrom(star_exp->value); 5182 auto listVar = singleVariableFrom(star_exp->value, true);
5150 if (!isLocal(listVar)) listVar.clear(); 5183 if (!isLocal(listVar)) listVar.clear();
5151 auto indexVar = getUnusedName("_index_"sv); 5184 auto indexVar = getUnusedName("_index_"sv);
5152 varAfter.push_back(indexVar); 5185 varAfter.push_back(indexVar);
@@ -5816,7 +5849,7 @@ private:
5816 assignItem = std::move(temp.back()); 5849 assignItem = std::move(temp.back());
5817 temp.pop_back(); 5850 temp.pop_back();
5818 } else if (expList) { 5851 } else if (expList) {
5819 auto name = singleVariableFrom(expList); 5852 auto name = singleVariableFrom(expList, true);
5820 if (!name.empty()) { 5853 if (!name.empty()) {
5821 className = '\"' + name + '\"'; 5854 className = '\"' + name + '\"';
5822 } 5855 }
@@ -5834,12 +5867,12 @@ private:
5834 if (auto assignment = assignmentFrom(statement)) { 5867 if (auto assignment = assignmentFrom(statement)) {
5835 auto names = transformAssignDefs(assignment->expList.get(), DefOp::Mark); 5868 auto names = transformAssignDefs(assignment->expList.get(), DefOp::Mark);
5836 varDefs.insert(varDefs.end(), names.begin(), names.end()); 5869 varDefs.insert(varDefs.end(), names.begin(), names.end());
5837 auto info = extractDestructureInfo(assignment, true); 5870 auto info = extractDestructureInfo(assignment, true, false);
5838 if (!info.first.empty()) { 5871 if (!info.first.empty()) {
5839 for (const auto& destruct : info.first) 5872 for (const auto& destruct : info.first)
5840 for (const auto& item : destruct.items) 5873 for (const auto& item : destruct.items)
5841 if (item.isVariable && addToScope(item.name)) 5874 if (!item.targetVar.empty() && addToScope(item.targetVar))
5842 varDefs.push_back(item.name); 5875 varDefs.push_back(item.targetVar);
5843 } 5876 }
5844 BLOCK_START 5877 BLOCK_START
5845 auto assign = assignment->action.as<Assign_t>(); 5878 auto assign = assignment->action.as<Assign_t>();
@@ -6193,7 +6226,7 @@ private:
6193 auto vars = getAssignVars(with); 6226 auto vars = getAssignVars(with);
6194 if (vars.front().empty() || isGlobal(vars.front())) { 6227 if (vars.front().empty() || isGlobal(vars.front())) {
6195 if (with->assigns->values.objects().size() == 1) { 6228 if (with->assigns->values.objects().size() == 1) {
6196 auto var = singleVariableFrom(with->assigns->values.objects().front()); 6229 auto var = singleVariableFrom(with->assigns->values.objects().front(), true);
6197 if (!var.empty() && isLocal(var)) { 6230 if (!var.empty() && isLocal(var)) {
6198 withVar = var; 6231 withVar = var;
6199 } 6232 }
@@ -6239,7 +6272,7 @@ private:
6239 transformAssignment(assignment, temp); 6272 transformAssignment(assignment, temp);
6240 } 6273 }
6241 } else { 6274 } else {
6242 withVar = singleVariableFrom(with->valueList); 6275 withVar = singleVariableFrom(with->valueList, true);
6243 if (withVar.empty() || !isLocal(withVar)) { 6276 if (withVar.empty() || !isLocal(withVar)) {
6244 withVar = getUnusedName("_with_"sv); 6277 withVar = getUnusedName("_with_"sv);
6245 auto assignment = x->new_ptr<ExpListAssign_t>(); 6278 auto assignment = x->new_ptr<ExpListAssign_t>();
@@ -6265,11 +6298,11 @@ private:
6265 if (!names.empty()) { 6298 if (!names.empty()) {
6266 return traversal::Stop; 6299 return traversal::Stop;
6267 } 6300 }
6268 auto info = extractDestructureInfo(assignment, true); 6301 auto info = extractDestructureInfo(assignment, true, false);
6269 if (!info.first.empty()) { 6302 if (!info.first.empty()) {
6270 for (const auto& destruct : info.first) 6303 for (const auto& destruct : info.first)
6271 for (const auto& item : destruct.items) 6304 for (const auto& item : destruct.items)
6272 if (item.isVariable && !isDefined(item.name)) 6305 if (!item.targetVar.empty() && !isDefined(item.targetVar))
6273 return traversal::Stop; 6306 return traversal::Stop;
6274 } 6307 }
6275 BLOCK_START 6308 BLOCK_START
@@ -6417,12 +6450,12 @@ private:
6417 assignment->action.set(exportNode->assign); 6450 assignment->action.set(exportNode->assign);
6418 transformAssignment(assignment, out); 6451 transformAssignment(assignment, out);
6419 str_list names = transformAssignDefs(expList, DefOp::Get); 6452 str_list names = transformAssignDefs(expList, DefOp::Get);
6420 auto info = extractDestructureInfo(assignment, true); 6453 auto info = extractDestructureInfo(assignment, true, false);
6421 if (!info.first.empty()) { 6454 if (!info.first.empty()) {
6422 for (const auto& destruct : info.first) 6455 for (const auto& destruct : info.first)
6423 for (const auto& item : destruct.items) 6456 for (const auto& item : destruct.items)
6424 if (item.isVariable) 6457 if (!item.targetVar.empty())
6425 names.push_back(item.name); 6458 names.push_back(item.targetVar);
6426 } 6459 }
6427 if (_info.exportDefault) { 6460 if (_info.exportDefault) {
6428 out.back().append(indent() + _info.moduleName + " = "s + names.back() + nlr(exportNode)); 6461 out.back().append(indent() + _info.moduleName + " = "s + names.back() + nlr(exportNode));
@@ -6699,7 +6732,7 @@ private:
6699 void transformImportFrom(ImportFrom_t* import, str_list& out) { 6732 void transformImportFrom(ImportFrom_t* import, str_list& out) {
6700 str_list temp; 6733 str_list temp;
6701 auto x = import; 6734 auto x = import;
6702 auto objVar = singleVariableFrom(import->exp); 6735 auto objVar = singleVariableFrom(import->exp, true);
6703 ast_ptr<false, ExpListAssign_t> objAssign; 6736 ast_ptr<false, ExpListAssign_t> objAssign;
6704 if (objVar.empty()) { 6737 if (objVar.empty()) {
6705 objVar = getUnusedName("_obj_"sv); 6738 objVar = getUnusedName("_obj_"sv);
@@ -7065,7 +7098,7 @@ private:
7065 pushScope(); 7098 pushScope();
7066 } 7099 }
7067 bool extraScope = false; 7100 bool extraScope = false;
7068 auto objVar = singleVariableFrom(switchNode->target); 7101 auto objVar = singleVariableFrom(switchNode->target, true);
7069 if (objVar.empty() || !isLocal(objVar)) { 7102 if (objVar.empty() || !isLocal(objVar)) {
7070 if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) { 7103 if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) {
7071 extraScope = true; 7104 extraScope = true;
@@ -7082,24 +7115,89 @@ private:
7082 transformAssignment(assignment, temp); 7115 transformAssignment(assignment, temp);
7083 } 7116 }
7084 const auto& branches = switchNode->branches.objects(); 7117 const auto& branches = switchNode->branches.objects();
7118 int addScope = 0;
7119 bool firstBranch = true;
7120 std::string tabCheckVar;
7085 for (auto branch_ : branches) { 7121 for (auto branch_ : branches) {
7086 auto branch = static_cast<SwitchCase_t*>(branch_); 7122 auto branch = static_cast<SwitchCase_t*>(branch_);
7087 temp.push_back(indent() + (branches.front() == branch ? "if"s : "elseif"s)); 7123 if (auto value = singleValueFrom(branch->valueList);
7088 str_list tmp; 7124 value->item.is<simple_table_t>() ||
7089 const auto& exprs = branch->valueList->exprs.objects(); 7125 value->getByPath<SimpleValue_t, TableLit_t>()) {
7090 for (auto exp_ : exprs) { 7126 if (!firstBranch) {
7091 auto exp = static_cast<Exp_t*>(exp_); 7127 temp.push_back(indent() + "else"s + nll(branch));
7092 transformExp(exp, tmp, ExpUsage::Closure); 7128 pushScope();
7093 if (!singleValueFrom(exp)) { 7129 addScope++;
7094 tmp.back() = '(' + tmp.back() + ')'; 7130 }
7131 if (tabCheckVar.empty()) {
7132 if (!extraScope) {
7133 temp.push_back(indent() + "do"s + nll(branch));
7134 pushScope();
7135 extraScope = true;
7136 }
7137 tabCheckVar = getUnusedName("_tab_");
7138 forceAddToScope(tabCheckVar);
7139 temp.push_back(indent() + "local "s + tabCheckVar + " = \"table\" == "s + globalVar("type", branch) + '(' + objVar + ')' + nll(branch));
7140 }
7141 std::string matchVar;
7142 bool lastBranch = branches.back() == branch_;
7143 if (!lastBranch) {
7144 matchVar = getUnusedName("_match_");
7145 forceAddToScope(matchVar);
7146 temp.push_back(indent() + "local "s + matchVar + " = false"s + nll(branch));
7147 }
7148 temp.back().append(indent() + "if "s + tabCheckVar + " then"s + nll(branch));
7149 pushScope();
7150 auto assignment = assignmentFrom(static_cast<Exp_t*>(branch->valueList->exprs.front()), toAst<Exp_t>(objVar, branch), branch);
7151 auto info = extractDestructureInfo(assignment, true, false);
7152 transformAssignment(assignment, temp, true);
7153 temp.push_back(indent() + "if"s);
7154 bool firstItem = true;
7155 for (const auto& destruct : info.first) {
7156 for (const auto& item : destruct.items) {
7157 str_list tmp;
7158 transformExp(item.target, tmp, ExpUsage::Closure);
7159 temp.back().append((firstItem ? " " : " and "s) + tmp.back() + " ~= nil"s);
7160 if (firstItem) firstItem = false;
7161 }
7162 }
7163 temp.back().append(" then"s + nll(branch));
7164 pushScope();
7165 transform_plain_body(branch->body, temp, usage, assignList);
7166 if (!lastBranch) {
7167 temp.push_back(indent() + matchVar + " = true"s + nll(branch));
7168 }
7169 popScope();
7170 if (!lastBranch) {
7171 temp.push_back(indent() + "end"s + nll(branch));
7172 popScope();
7173 temp.push_back(indent() + "end"s + nll(branch));
7174 temp.push_back(indent() + "if not "s + matchVar + " then"s + nll(branch));
7175 pushScope();
7176 addScope++;
7177 } else {
7178 temp.push_back(indent() + "end"s + nll(branch));
7179 popScope();
7180 }
7181 firstBranch = true;
7182 } else {
7183 temp.push_back(indent() + (firstBranch ? "if"s : "elseif"s));
7184 firstBranch = false;
7185 str_list tmp;
7186 const auto& exprs = branch->valueList->exprs.objects();
7187 for (auto exp_ : exprs) {
7188 auto exp = static_cast<Exp_t*>(exp_);
7189 transformExp(exp, tmp, ExpUsage::Closure);
7190 if (!singleValueFrom(exp)) {
7191 tmp.back() = '(' + tmp.back() + ')';
7192 }
7193 temp.back().append(' ' + tmp.back() + " == "s +
7194 (exp == exprs.back() ? objVar : objVar + " or"s));
7095 } 7195 }
7096 temp.back().append(' ' + tmp.back() + " == "s + 7196 temp.back().append(" then"s + nll(branch));
7097 (exp == exprs.back() ? objVar : objVar + " or"s)); 7197 pushScope();
7198 transform_plain_body(branch->body, temp, usage, assignList);
7199 popScope();
7098 } 7200 }
7099 temp.back().append(" then"s + nll(branch));
7100 pushScope();
7101 transform_plain_body(branch->body, temp, usage, assignList);
7102 popScope();
7103 } 7201 }
7104 if (switchNode->lastBranch) { 7202 if (switchNode->lastBranch) {
7105 temp.push_back(indent() + "else"s + nll(switchNode->lastBranch)); 7203 temp.push_back(indent() + "else"s + nll(switchNode->lastBranch));
@@ -7107,6 +7205,11 @@ private:
7107 transform_plain_body(switchNode->lastBranch, temp, usage, assignList); 7205 transform_plain_body(switchNode->lastBranch, temp, usage, assignList);
7108 popScope(); 7206 popScope();
7109 } 7207 }
7208 while (addScope > 0) {
7209 addScope--;
7210 temp.push_back(indent() + "end"s + nlr(switchNode));
7211 popScope();
7212 }
7110 temp.push_back(indent() + "end"s + nlr(switchNode)); 7213 temp.push_back(indent() + "end"s + nlr(switchNode));
7111 if (usage == ExpUsage::Closure) { 7214 if (usage == ExpUsage::Closure) {
7112 _enableReturn.pop(); 7215 _enableReturn.pop();
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp
index 78b4713..199c0bd 100755
--- a/src/yuescript/yue_parser.cpp
+++ b/src/yuescript/yue_parser.cpp
@@ -225,7 +225,7 @@ YueParser::YueParser() {
225 WithExp = ExpList >> -Assign; 225 WithExp = ExpList >> -Assign;
226 226
227 With = Space >> key("with") >> -existential_op >> disable_do_chain_arg_table_block(WithExp) >> plain_body_with("do"); 227 With = Space >> key("with") >> -existential_op >> disable_do_chain_arg_table_block(WithExp) >> plain_body_with("do");
228 SwitchCase = Space >> key("when") >> disable_chain(disable_arg_table_block(ExpList)) >> plain_body_with("then"); 228 SwitchCase = Space >> key("when") >> disable_chain(disable_arg_table_block(SwitchList)) >> plain_body_with("then");
229 SwitchElse = Space >> key("else") >> plain_body; 229 SwitchElse = Space >> key("else") >> plain_body;
230 230
231 SwitchBlock = *EmptyLine >> 231 SwitchBlock = *EmptyLine >>
@@ -235,6 +235,9 @@ YueParser::YueParser() {
235 -(Break >> *EmptyLine >> CheckIndent >> SwitchElse) >> 235 -(Break >> *EmptyLine >> CheckIndent >> SwitchElse) >>
236 PopIndent; 236 PopIndent;
237 237
238 exp_not_tab = not_(simple_table | TableLit) >> Exp;
239
240 SwitchList = Seperator >> Exp >> *(sym(',') >> exp_not_tab);
238 Switch = Space >> key("switch") >> disable_do(Exp) >> -(Space >> key("do")) 241 Switch = Space >> key("switch") >> disable_do(Exp) >> -(Space >> key("do"))
239 >> -Space >> Break >> SwitchBlock; 242 >> -Space >> Break >> SwitchBlock;
240 243
@@ -550,14 +553,14 @@ YueParser::YueParser() {
550 symx(':') >> not_(':') >> 553 symx(':') >> not_(':') >>
551 (Exp | TableBlock | +SpaceBreak >> Exp); 554 (Exp | TableBlock | +SpaceBreak >> Exp);
552 555
553 default_pair = (sym(':') >> Variable >> not_('#') >> Seperator | KeyName >> symx(':') >> Seperator >> Exp | Exp >> Seperator) >> sym('=') >> Exp; 556 default_pair = (sym(':') >> Variable >> not_('#') >> Seperator | KeyName >> symx(':') >> Seperator >> exp_not_tab | exp_not_tab >> Seperator) >> sym('=') >> Exp;
554 557
555 meta_variable_pair = sym(':') >> Variable >> expr('#'); 558 meta_variable_pair = sym(':') >> Variable >> expr('#');
556 559
557 meta_normal_pair = Space >> -(Name | symx('[') >> not_('[') >> Exp >> sym(']')) >> expr("#:") >> 560 meta_normal_pair = Space >> -(Name | symx('[') >> not_('[') >> Exp >> sym(']')) >> expr("#:") >>
558 (Exp | TableBlock | +(SpaceBreak) >> Exp); 561 (Exp | TableBlock | +(SpaceBreak) >> Exp);
559 562
560 meta_default_pair = (sym(':') >> Variable >> expr('#') >> Seperator | Space >> -Name >> expr("#:") >> Seperator >> Exp) >> sym('=') >> Exp; 563 meta_default_pair = (sym(':') >> Variable >> expr('#') >> Seperator | Space >> -Name >> expr("#:") >> Seperator >> exp_not_tab) >> sym('=') >> Exp;
561 564
562 KeyValue = variable_pair | normal_pair | meta_variable_pair | meta_normal_pair; 565 KeyValue = variable_pair | normal_pair | meta_variable_pair | meta_normal_pair;
563 KeyValueList = KeyValue >> *(sym(',') >> KeyValue); 566 KeyValueList = KeyValue >> *(sym(',') >> KeyValue);
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h
index eea3027..b71a67c 100755
--- a/src/yuescript/yue_parser.h
+++ b/src/yuescript/yue_parser.h
@@ -188,6 +188,7 @@ private:
188 rule pipe_exp; 188 rule pipe_exp;
189 rule expo_value; 189 rule expo_value;
190 rule expo_exp; 190 rule expo_exp;
191 rule exp_not_tab;
191 rule empty_line_stop; 192 rule empty_line_stop;
192 rule Line; 193 rule Line;
193 rule Shebang; 194 rule Shebang;
@@ -230,6 +231,7 @@ private:
230 AST_RULE(ExpList) 231 AST_RULE(ExpList)
231 AST_RULE(Return) 232 AST_RULE(Return)
232 AST_RULE(With) 233 AST_RULE(With)
234 AST_RULE(SwitchList)
233 AST_RULE(SwitchCase) 235 AST_RULE(SwitchCase)
234 AST_RULE(Switch) 236 AST_RULE(Switch)
235 AST_RULE(assignment) 237 AST_RULE(assignment)