aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2024-09-03 23:23:25 +0800
committerLi Jin <dragon-fly@qq.com>2024-09-03 23:23:25 +0800
commit2f8215df7288e0aac690c8e8b1ff79865f114302 (patch)
tree2fc316ec0d6ca82123dc1fbc2012d8eeb3bc8427
parent880b7eb9a427b263091f6eef5197c0285c723fd7 (diff)
downloadyuescript-2f8215df7288e0aac690c8e8b1ff79865f114302.tar.gz
yuescript-2f8215df7288e0aac690c8e8b1ff79865f114302.tar.bz2
yuescript-2f8215df7288e0aac690c8e8b1ff79865f114302.zip
fix correct evaluation order for multi-value assignments.v0.25.0
-rw-r--r--spec/inputs/destructure.yue8
-rw-r--r--spec/outputs/assign.lua3
-rw-r--r--spec/outputs/destructure.lua49
-rw-r--r--spec/outputs/metatable.lua13
-rw-r--r--spec/outputs/unicode/assign.lua3
-rw-r--r--spec/outputs/unicode/destructure.lua24
-rw-r--r--spec/outputs/unicode/metatable.lua13
-rw-r--r--src/yuescript/parser.cpp10
-rw-r--r--src/yuescript/parser.hpp11
-rw-r--r--src/yuescript/yue_compiler.cpp247
10 files changed, 257 insertions, 124 deletions
diff --git a/spec/inputs/destructure.yue b/spec/inputs/destructure.yue
index 5017ee1..674dfe4 100644
--- a/spec/inputs/destructure.yue
+++ b/spec/inputs/destructure.yue
@@ -7,6 +7,14 @@ do
7 { :hello, :world } = value 7 { :hello, :world } = value
8 8
9do 9do
10 x, [a, b] = f!
11 print x, a, b
12
13do
14 list = [ [1, 2], [3, 4]]
15 {x, y}, list = lume.first(list), lume.slice list, 2
16
17do
10 { yes: no, thing } = world 18 { yes: no, thing } = world
11 19
12 {:a,:b,:c,:d} = yeah 20 {:a,:b,:c,:d} = yeah
diff --git a/spec/outputs/assign.lua b/spec/outputs/assign.lua
index 5552f73..1978df1 100644
--- a/spec/outputs/assign.lua
+++ b/spec/outputs/assign.lua
@@ -77,8 +77,7 @@ return _(function()
77 end 77 end
78 end 78 end
79 do 79 do
80 local a 80 local a, b
81 local b
82 if x then 81 if x then
83 local _obj_0, _obj_1 = f() 82 local _obj_0, _obj_1 = f()
84 a = _obj_0 83 a = _obj_0
diff --git a/spec/outputs/destructure.lua b/spec/outputs/destructure.lua
index 2d0d46f..d8517a0 100644
--- a/spec/outputs/destructure.lua
+++ b/spec/outputs/destructure.lua
@@ -14,6 +14,31 @@ do
14 hello, world = _obj_0.hello, _obj_0.world 14 hello, world = _obj_0.hello, _obj_0.world
15end 15end
16do 16do
17 local x, a, b
18 do
19 local _obj_0, _obj_1 = f()
20 x = _obj_0
21 a, b = _obj_1[1], _obj_1[2]
22 end
23 print(x, a, b)
24end
25do
26 local list = {
27 {
28 1,
29 2
30 },
31 {
32 3,
33 4
34 }
35 }
36 local x, y
37 local _obj_0 = lume.first(list)
38 x, y = _obj_0[1], _obj_0[2]
39 list = lume.slice(list, 2)
40end
41do
17 local no, thing 42 local no, thing
18 do 43 do
19 local _obj_0 = world 44 local _obj_0 = world
@@ -24,12 +49,12 @@ do
24 local _obj_0 = yeah 49 local _obj_0 = yeah
25 a, b, c, d = _obj_0.a, _obj_0.b, _obj_0.c, _obj_0.d 50 a, b, c, d = _obj_0.a, _obj_0.b, _obj_0.c, _obj_0.d
26 end 51 end
27 b = two
28 a = one[1] 52 a = one[1]
29 c = nil 53 b = two
30 b = one[1] 54 b = one[1]
31 local e = two 55 c = nil
32 d = one[1] 56 d = one[1]
57 local e = two
33 local x = one 58 local x = one
34 local y = two[1] 59 local y = two[1]
35 local xx, yy = 1, 2 60 local xx, yy = 1, 2
@@ -46,9 +71,9 @@ do
46 a, b, c, d, e, f, g = _obj_0[1], _obj_0.b, _obj_0[2], _obj_0.d, _obj_0[3], _obj_0.f, _obj_0[4] 71 a, b, c, d, e, f, g = _obj_0[1], _obj_0.b, _obj_0[2], _obj_0.d, _obj_0[3], _obj_0.f, _obj_0[4]
47 end 72 end
48 do 73 do
49 c = nil
50 local _obj_0 = tbl 74 local _obj_0 = tbl
51 a, b = _obj_0.a, _obj_0.b 75 a, b = _obj_0.a, _obj_0.b
76 c = nil
52 end 77 end
53 do 78 do
54 a = tbl 79 a = tbl
@@ -56,8 +81,8 @@ do
56 b, c = _obj_0.b, _obj_0.c 81 b, c = _obj_0.b, _obj_0.c
57 end 82 end
58 do 83 do
59 b = _
60 a = tbl.a 84 a = tbl.a
85 b = _
61 c = _.c 86 c = _.c
62 end 87 end
63end 88end
@@ -211,8 +236,8 @@ do
211 end 236 end
212 one, two, three = _tbl_0.one, _tbl_0.two, _tbl_0.three 237 one, two, three = _tbl_0.one, _tbl_0.two, _tbl_0.three
213 end 238 end
214 b = 123
215 a = (a["if"](a, 123) + t).a 239 a = (a["if"](a, 123) + t).a
240 b = 123
216end 241end
217do 242do
218 local name, job 243 local name, job
@@ -399,8 +424,7 @@ do
399 end 424 end
400end 425end
401do 426do
402 local x1, x2, x3, d, e 427 local x1, x2, x3, d, b, e
403 local b
404 do 428 do
405 local _obj_0, _obj_1, _obj_2, _obj_3, _obj_4 = f() 429 local _obj_0, _obj_1, _obj_2, _obj_3, _obj_4 = f()
406 do 430 do
@@ -408,14 +432,15 @@ do
408 _obj_5[#_obj_5 + 1] = _obj_0 432 _obj_5[#_obj_5 + 1] = _obj_0
409 end 433 end
410 setmetatable(c, _obj_4) 434 setmetatable(c, _obj_4)
411 x1, x2, x3, d, e = 1, 2, 3, _obj_1, _obj_3 435 x1, x2, x3, d = 1, 2, 3, _obj_1
412 b = _obj_2[1] 436 b = _obj_2[1]
437 e = _obj_3
413 end 438 end
414 local y1, y4 439 local y1, y2, y3, y4
415 local y2, y3
416 local _obj_0, _obj_1 = f2() 440 local _obj_0, _obj_1 = f2()
417 y1, y4 = f1(), _obj_1 441 y1 = f1()
418 y2, y3 = _obj_0.y2, _obj_0.y3 442 y2, y3 = _obj_0.y2, _obj_0.y3
443 y4 = _obj_1
419end 444end
420do 445do
421 local v1, v2, v3, v4 446 local v1, v2, v3, v4
diff --git a/spec/outputs/metatable.lua b/spec/outputs/metatable.lua
index 6af10e5..0715b58 100644
--- a/spec/outputs/metatable.lua
+++ b/spec/outputs/metatable.lua
@@ -48,14 +48,15 @@ do
48end 48end
49do 49do
50 local x, new, var, close, closeA, num, add, sub 50 local x, new, var, close, closeA, num, add, sub
51 local _obj_0, _obj_1 51 x = 123
52 x, _obj_0, _obj_1 = 123, a.b.c, func() 52 local _obj_0 = a.b.c
53 new, var = _obj_0.new, _obj_0.var 53 new, var = _obj_0.new, _obj_0.var
54 local _obj_2 = getmetatable(_obj_0) 54 local _obj_1 = getmetatable(_obj_0)
55 close, closeA = _obj_2.__close, _obj_2.__close 55 close, closeA = _obj_1.__close, _obj_1.__close
56 _obj_1 = func()
56 num = _obj_1.num 57 num = _obj_1.num
57 local _obj_3 = getmetatable(_obj_1) 58 local _obj_2 = getmetatable(_obj_1)
58 add, sub = _obj_3.__add, _obj_3.__sub 59 add, sub = _obj_2.__add, _obj_2.__sub
59end 60end
60setmetatable(a.b, { }) 61setmetatable(a.b, { })
61x.abc = 123 62x.abc = 123
diff --git a/spec/outputs/unicode/assign.lua b/spec/outputs/unicode/assign.lua
index cb53159..e883d68 100644
--- a/spec/outputs/unicode/assign.lua
+++ b/spec/outputs/unicode/assign.lua
@@ -81,8 +81,7 @@ return __u65e0_u6548_u53d8_u91cf(function()
81 end 81 end
82 end 82 end
83 do 83 do
84 local _u53d8_u91cfa 84 local _u53d8_u91cfa, _u5143_u7d20b
85 local _u5143_u7d20b
86 if x_u6761_u4ef6 then 85 if x_u6761_u4ef6 then
87 local _obj_0, _obj_1 = _u51fd_u6570() 86 local _obj_0, _obj_1 = _u51fd_u6570()
88 _u53d8_u91cfa = _obj_0 87 _u53d8_u91cfa = _obj_0
diff --git a/spec/outputs/unicode/destructure.lua b/spec/outputs/unicode/destructure.lua
index e1cd6ae..29697fa 100644
--- a/spec/outputs/unicode/destructure.lua
+++ b/spec/outputs/unicode/destructure.lua
@@ -24,12 +24,12 @@ do
24 local _obj_0 = _u597d 24 local _obj_0 = _u597d
25 _u5b57_u6bb5a, _u5b57_u6bb5b, _u5b57_u6bb5c, d_u5b57_u6bb5 = _obj_0["字段a"], _obj_0["字段b"], _obj_0["字段c"], _obj_0["d字段"] 25 _u5b57_u6bb5a, _u5b57_u6bb5b, _u5b57_u6bb5c, d_u5b57_u6bb5 = _obj_0["字段a"], _obj_0["字段b"], _obj_0["字段c"], _obj_0["d字段"]
26 end 26 end
27 local _u53d8_u91cfb = _u4e8c
28 local a_u5143_u7d20 = _u4e00[1] 27 local a_u5143_u7d20 = _u4e00[1]
29 local _u53d8_u91cfc = nil 28 local _u53d8_u91cfb = _u4e8c
30 local b_u5143_u7d20 = _u4e00[1] 29 local b_u5143_u7d20 = _u4e00[1]
31 local _u53d8_u91cfe = _u4e8c 30 local _u53d8_u91cfc = nil
32 local d_u5143_u7d20 = _u4e00[1] 31 local d_u5143_u7d20 = _u4e00[1]
32 local _u53d8_u91cfe = _u4e8c
33 local _u53d8_u91cfx = _u4e00 33 local _u53d8_u91cfx = _u4e00
34 local _u5143_u7d20y = _u4e8c[1] 34 local _u5143_u7d20y = _u4e8c[1]
35 local _u53d8_u91cfxx, _u53d8_u91cfyy = 1, 2 35 local _u53d8_u91cfxx, _u53d8_u91cfyy = 1, 2
@@ -47,9 +47,9 @@ do
47 _u5143_u7d20a, _u5b57_u6bb5b, _u5143_u7d20c, _u5b57_u6bb5d, _u5143_u7d20e, _u5b57_u6bb5f, _u5143_u7d20g = _obj_0[1], _obj_0["字段b"], _obj_0[2], _obj_0["字段d"], _obj_0[3], _obj_0["字段f"], _obj_0[4] 47 _u5143_u7d20a, _u5b57_u6bb5b, _u5143_u7d20c, _u5b57_u6bb5d, _u5143_u7d20e, _u5b57_u6bb5f, _u5143_u7d20g = _obj_0[1], _obj_0["字段b"], _obj_0[2], _obj_0["字段d"], _obj_0[3], _obj_0["字段f"], _obj_0[4]
48 end 48 end
49 do 49 do
50 _u53d8_u91cfc = nil
51 local _obj_0 = _u8868 50 local _obj_0 = _u8868
52 _u5b57_u6bb5a, _u5b57_u6bb5b = _obj_0["字段a"], _obj_0["字段b"] 51 _u5b57_u6bb5a, _u5b57_u6bb5b = _obj_0["字段a"], _obj_0["字段b"]
52 _u53d8_u91cfc = nil
53 end 53 end
54 do 54 do
55 local _u53d8_u91cfa = _u8868 55 local _u53d8_u91cfa = _u8868
@@ -57,8 +57,8 @@ do
57 _u5b57_u6bb5b, _u5b57_u6bb5c = _obj_0["字段b"], _obj_0["字段c"] 57 _u5b57_u6bb5b, _u5b57_u6bb5c = _obj_0["字段b"], _obj_0["字段c"]
58 end 58 end
59 do 59 do
60 _u53d8_u91cfb = __u65e0_u6548_u53d8_u91cf
61 _u5b57_u6bb5a = _u8868["字段a"] 60 _u5b57_u6bb5a = _u8868["字段a"]
61 _u53d8_u91cfb = __u65e0_u6548_u53d8_u91cf
62 _u5b57_u6bb5c = __u65e0_u6548_u53d8_u91cf["字段c"] 62 _u5b57_u6bb5c = __u65e0_u6548_u53d8_u91cf["字段c"]
63 end 63 end
64end 64end
@@ -212,11 +212,11 @@ do
212 end 212 end
213 _u4e00, _u4e8c, _u4e09 = _tbl_0["一"], _tbl_0["二"], _tbl_0["三"] 213 _u4e00, _u4e8c, _u4e09 = _tbl_0["一"], _tbl_0["二"], _tbl_0["三"]
214 end 214 end
215 local _u53d8_u91cfb = 123
216 _u5b57_u6bb5a = ((function() 215 _u5b57_u6bb5a = ((function()
217 local _call_0 = _u5bf9_u8c61a 216 local _call_0 = _u5bf9_u8c61a
218 return _call_0["如果"](_call_0, 123) 217 return _call_0["如果"](_call_0, 123)
219 end)() + _u53d8_u91cft)["字段a"] 218 end)() + _u53d8_u91cft)["字段a"]
219 local _u53d8_u91cfb = 123
220end 220end
221do 221do
222 local _u540d_u79f0, _u5de5_u4f5c 222 local _u540d_u79f0, _u5de5_u4f5c
@@ -386,8 +386,7 @@ do
386 end 386 end
387end 387end
388do 388do
389 local _u53d8_u91cf1, _u53d8_u91cf2, _u53d8_u91cf3, _u53d8_u91cfd, _u53d8_u91cfe 389 local _u53d8_u91cf1, _u53d8_u91cf2, _u53d8_u91cf3, _u53d8_u91cfd, _u5143_u7d20b, _u53d8_u91cfe
390 local _u5143_u7d20b
391 do 390 do
392 local _obj_0, _obj_1, _obj_2, _obj_3, _obj_4 = _u51fd_u6570() 391 local _obj_0, _obj_1, _obj_2, _obj_3, _obj_4 = _u51fd_u6570()
393 do 392 do
@@ -395,14 +394,15 @@ do
395 _obj_5[#_obj_5 + 1] = _obj_0 394 _obj_5[#_obj_5 + 1] = _obj_0
396 end 395 end
397 setmetatable(_u5bf9_u8c61c, _obj_4) 396 setmetatable(_u5bf9_u8c61c, _obj_4)
398 _u53d8_u91cf1, _u53d8_u91cf2, _u53d8_u91cf3, _u53d8_u91cfd, _u53d8_u91cfe = 1, 2, 3, _obj_1, _obj_3 397 _u53d8_u91cf1, _u53d8_u91cf2, _u53d8_u91cf3, _u53d8_u91cfd = 1, 2, 3, _obj_1
399 _u5143_u7d20b = _obj_2[1] 398 _u5143_u7d20b = _obj_2[1]
399 _u53d8_u91cfe = _obj_3
400 end 400 end
401 local _u53d8_u91cfy1, _u53d8_u91cfy4 401 local _u53d8_u91cfy1, _u5b57_u6bb5y2, _u5b57_u6bb5y3, _u53d8_u91cfy4
402 local _u5b57_u6bb5y2, _u5b57_u6bb5y3
403 local _obj_0, _obj_1 = _u51fd_u65702() 402 local _obj_0, _obj_1 = _u51fd_u65702()
404 _u53d8_u91cfy1, _u53d8_u91cfy4 = _u51fd_u65701(), _obj_1 403 _u53d8_u91cfy1 = _u51fd_u65701()
405 _u5b57_u6bb5y2, _u5b57_u6bb5y3 = _obj_0["字段y2"], _obj_0["字段y3"] 404 _u5b57_u6bb5y2, _u5b57_u6bb5y3 = _obj_0["字段y2"], _obj_0["字段y3"]
405 _u53d8_u91cfy4 = _obj_1
406end 406end
407do 407do
408 local _u53d8_u91cfv1, _u53d8_u91cfv2, _u53d8_u91cfv3, _u53d8_u91cfv4 408 local _u53d8_u91cfv1, _u53d8_u91cfv2, _u53d8_u91cfv3, _u53d8_u91cfv4
diff --git a/spec/outputs/unicode/metatable.lua b/spec/outputs/unicode/metatable.lua
index ca48d0d..f948d21 100644
--- a/spec/outputs/unicode/metatable.lua
+++ b/spec/outputs/unicode/metatable.lua
@@ -48,14 +48,15 @@ do
48end 48end
49do 49do
50 local _u53d8_u91cfx, _u65b0, _u53d8_u91cf, close, _u5173_u95edA, num, add, sub 50 local _u53d8_u91cfx, _u65b0, _u53d8_u91cf, close, _u5173_u95edA, num, add, sub
51 local _obj_0, _obj_1 51 _u53d8_u91cfx = 123
52 _u53d8_u91cfx, _obj_0, _obj_1 = 123, _u53d8_u91cfa["变量b"]["变量c"], _u51fd_u6570() 52 local _obj_0 = _u53d8_u91cfa["变量b"]["变量c"]
53 _u65b0, _u53d8_u91cf = _obj_0["新"], _obj_0["变量"] 53 _u65b0, _u53d8_u91cf = _obj_0["新"], _obj_0["变量"]
54 local _obj_2 = getmetatable(_obj_0) 54 local _obj_1 = getmetatable(_obj_0)
55 close, _u5173_u95edA = _obj_2.__close, _obj_2.__close 55 close, _u5173_u95edA = _obj_1.__close, _obj_1.__close
56 _obj_1 = _u51fd_u6570()
56 num = _obj_1.num 57 num = _obj_1.num
57 local _obj_3 = getmetatable(_obj_1) 58 local _obj_2 = getmetatable(_obj_1)
58 add, sub = _obj_3.__add, _obj_3.__sub 59 add, sub = _obj_2.__add, _obj_2.__sub
59end 60end
60setmetatable(_u53d8_u91cfa["变量b"], { }) 61setmetatable(_u53d8_u91cfa["变量b"], { })
61_u53d8_u91cfx.abc = 123 62_u53d8_u91cfx.abc = 123
diff --git a/src/yuescript/parser.cpp b/src/yuescript/parser.cpp
index 5e4caa2..5d0773c 100644
--- a/src/yuescript/parser.cpp
+++ b/src/yuescript/parser.cpp
@@ -15,15 +15,9 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
15#include <stdexcept> 15#include <stdexcept>
16#include <unordered_map> 16#include <unordered_map>
17#include <unordered_set> 17#include <unordered_set>
18#include <memory>
19 18
20#include "yuescript/parser.hpp" 19#include "yuescript/parser.hpp"
21 20
22#define _DEFER(code, line) std::shared_ptr<void> _defer_##line(nullptr, [&](auto) { \
23 code; \
24})
25#define DEFER(code) _DEFER(code, __LINE__)
26
27namespace parserlib { 21namespace parserlib {
28 22
29// internal private class that manages access to the public classes' internals. 23// internal private class that manages access to the public classes' internals.
@@ -914,7 +908,7 @@ bool _context::parse_non_term(rule& r) {
914 // save the state of the rule 908 // save the state of the rule
915 rule::_state old_state = r.m_state; 909 rule::_state old_state = r.m_state;
916 // restore the rule's state 910 // restore the rule's state
917 DEFER(r.m_state = old_state); 911 rule::_state_guard quard(old_state, &r.m_state);
918 912
919 // success/failure result 913 // success/failure result
920 bool ok = false; 914 bool ok = false;
@@ -1008,7 +1002,7 @@ bool _context::parse_term(rule& r) {
1008 // save the state of the rule 1002 // save the state of the rule
1009 rule::_state old_state = r.m_state; 1003 rule::_state old_state = r.m_state;
1010 // restore the rule's state 1004 // restore the rule's state
1011 DEFER(r.m_state = old_state); 1005 rule::_state_guard quard(old_state, &r.m_state);
1012 1006
1013 // success/failure result 1007 // success/failure result
1014 bool ok = false; 1008 bool ok = false;
diff --git a/src/yuescript/parser.hpp b/src/yuescript/parser.hpp
index 71bbc1a..5ab327f 100644
--- a/src/yuescript/parser.hpp
+++ b/src/yuescript/parser.hpp
@@ -294,6 +294,17 @@ private:
294 , m_mode(mode) { } 294 , m_mode(mode) { }
295 }; 295 };
296 296
297 struct _state_guard {
298 _state m_old_state;
299 _state* m_current_state;
300 _state_guard(const _state& old, _state* new_)
301 : m_old_state(old)
302 , m_current_state(new_) { }
303 ~_state_guard() {
304 *m_current_state = m_old_state;
305 }
306 };
307
297 // internal expression 308 // internal expression
298 _expr* m_expr; 309 _expr* m_expr;
299 310
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp
index 32db488..cbb5f81 100644
--- a/src/yuescript/yue_compiler.cpp
+++ b/src/yuescript/yue_compiler.cpp
@@ -75,7 +75,7 @@ static std::unordered_set<std::string> Metamethods = {
75 "close"s // Lua 5.4 75 "close"s // Lua 5.4
76}; 76};
77 77
78const std::string_view version = "0.24.1"sv; 78const std::string_view version = "0.25.0"sv;
79const std::string_view extension = "yue"sv; 79const std::string_view extension = "yue"sv;
80 80
81class CompileError : public std::logic_error { 81class CompileError : public std::logic_error {
@@ -1943,16 +1943,26 @@ private:
1943 1943
1944 std::string getDestrucureDefine(ExpListAssign_t* assignment) { 1944 std::string getDestrucureDefine(ExpListAssign_t* assignment) {
1945 auto info = extractDestructureInfo(assignment, true, false); 1945 auto info = extractDestructureInfo(assignment, true, false);
1946 if (info.assignment) {
1947 _buf << getPreDefineLine(info.assignment);
1948 }
1949 if (!info.destructures.empty()) { 1946 if (!info.destructures.empty()) {
1950 str_list defs; 1947 str_list defs;
1951 for (const auto& destruct : info.destructures) { 1948 for (const auto& des : info.destructures) {
1952 for (const auto& item : destruct.items) { 1949 if (std::holds_alternative<Destructure>(des)) {
1953 if (!item.targetVar.empty()) { 1950 const auto& destruct = std::get<Destructure>(des);
1954 if (addToScope(item.targetVar)) { 1951 for (const auto& item : destruct.items) {
1955 defs.push_back(item.targetVar); 1952 if (!item.targetVar.empty()) {
1953 if (addToScope(item.targetVar)) {
1954 defs.push_back(item.targetVar);
1955 }
1956 }
1957 }
1958 } else {
1959 const auto& assignment = std::get<AssignmentPtr>(des);
1960 if (!assignment.extraAssignment) {
1961 auto names = transformAssignDefs(assignment.ptr->expList, DefOp::Get);
1962 for (const auto& name : names) {
1963 if (addToScope(name.first)) {
1964 defs.push_back(name.first);
1965 }
1956 } 1966 }
1957 } 1967 }
1958 } 1968 }
@@ -2007,12 +2017,15 @@ private:
2007 2017
2008 void markDestructureConst(ExpListAssign_t* assignment) { 2018 void markDestructureConst(ExpListAssign_t* assignment) {
2009 auto info = extractDestructureInfo(assignment, true, false); 2019 auto info = extractDestructureInfo(assignment, true, false);
2010 for (auto& destruct : info.destructures) { 2020 for (const auto& des : info.destructures) {
2011 for (auto& item : destruct.items) { 2021 if (std::holds_alternative<Destructure>(des)) {
2012 if (item.targetVar.empty()) { 2022 const auto& destruct = std::get<Destructure>(des);
2013 throw CompileError("can only declare variable as const"sv, item.target); 2023 for (const auto& item : destruct.items) {
2024 if (item.targetVar.empty()) {
2025 throw CompileError("can only declare variable as const"sv, item.target);
2026 }
2027 markVarConst(item.targetVar);
2014 } 2028 }
2015 markVarConst(item.targetVar);
2016 } 2029 }
2017 } 2030 }
2018 } 2031 }
@@ -2079,7 +2092,7 @@ private:
2079 BLOCK_START 2092 BLOCK_START
2080 auto value = singleValueFrom(*it); 2093 auto value = singleValueFrom(*it);
2081 BREAK_IF(!value); 2094 BREAK_IF(!value);
2082 if (value->item.is<SimpleTable_t>() || value->get_by_path<SimpleValue_t, TableLit_t>()) { 2095 if (value->item.is<SimpleTable_t>() || value->get_by_path<SimpleValue_t, TableLit_t>() || value->get_by_path<SimpleValue_t, Comprehension_t>()) {
2083 holdItem = true; 2096 holdItem = true;
2084 break; 2097 break;
2085 } 2098 }
@@ -2404,11 +2417,24 @@ private:
2404 bool extraScope = false; 2417 bool extraScope = false;
2405 if (info.extraScope) { 2418 if (info.extraScope) {
2406 str_list defs; 2419 str_list defs;
2407 for (auto& destruct : info.destructures) { 2420 for (const auto& des : info.destructures) {
2408 for (auto& item : destruct.items) { 2421 if (std::holds_alternative<Destructure>(des)) {
2409 if (!item.targetVar.empty()) { 2422 const auto& destruct = std::get<Destructure>(des);
2410 if (!isDefined(item.targetVar)) { 2423 for (auto& item : destruct.items) {
2411 defs.push_back(item.targetVar); 2424 if (!item.targetVar.empty()) {
2425 if (!isDefined(item.targetVar)) {
2426 defs.push_back(item.targetVar);
2427 }
2428 }
2429 }
2430 } else {
2431 const auto& assignment = std::get<AssignmentPtr>(des);
2432 if (!assignment.extraAssignment) {
2433 auto names = transformAssignDefs(assignment.ptr->expList, DefOp::Get);
2434 for (const auto& name : names) {
2435 if (addToScope(name.first)) {
2436 defs.push_back(name.first);
2437 }
2412 } 2438 }
2413 } 2439 }
2414 } 2440 }
@@ -2426,10 +2452,13 @@ private:
2426 pushScope(); 2452 pushScope();
2427 } 2453 }
2428 } 2454 }
2429 if (info.assignment) { 2455 for (auto& des : info.destructures) {
2430 transformAssignmentCommon(info.assignment, temp); 2456 if (std::holds_alternative<AssignmentPtr>(des)) {
2431 } 2457 auto assignment = std::get<AssignmentPtr>(des).ptr.get();
2432 for (auto& destruct : info.destructures) { 2458 transformAssignment(assignment, temp);
2459 continue;
2460 }
2461 auto& destruct = std::get<Destructure>(des);
2433 std::list<std::pair<ast_ptr<true, Exp_t>, ast_ptr<true, Exp_t>>> leftPairs; 2462 std::list<std::pair<ast_ptr<true, Exp_t>, ast_ptr<true, Exp_t>>> leftPairs;
2434 bool extraScope = false; 2463 bool extraScope = false;
2435 if (!destruct.inlineAssignment && destruct.items.size() == 1) { 2464 if (!destruct.inlineAssignment && destruct.items.size() == 1) {
@@ -2931,17 +2960,21 @@ private:
2931 return pairs; 2960 return pairs;
2932 } 2961 }
2933 2962
2963 struct AssignmentPtr {
2964 ast_ptr<false, ExpListAssign_t> ptr;
2965 bool extraAssignment = false;
2966 };
2967
2934 struct DestructureInfo { 2968 struct DestructureInfo {
2935 std::list<Destructure> destructures; 2969 std::list<std::variant<Destructure, AssignmentPtr>> destructures;
2936 ast_ptr<false, ExpListAssign_t> assignment;
2937 bool extraScope = false; 2970 bool extraScope = false;
2938 }; 2971 };
2939 2972
2940 DestructureInfo extractDestructureInfo(ExpListAssign_t* assignment, bool varDefOnly, bool optional) { 2973 DestructureInfo extractDestructureInfo(ExpListAssign_t* assignment, bool varDefOnly, bool optional) {
2974 if (!assignment->action.is<Assign_t>()) return {};
2941 auto x = assignment; 2975 auto x = assignment;
2942 bool extraScope = false; 2976 bool extraScope = false;
2943 std::list<Destructure> destructs; 2977 std::list<std::variant<Destructure, AssignmentPtr>> destructs;
2944 if (!assignment->action.is<Assign_t>()) return {destructs, nullptr};
2945 auto exprs = assignment->expList->exprs.objects(); 2978 auto exprs = assignment->expList->exprs.objects();
2946 auto values = assignment->action.to<Assign_t>()->values.objects(); 2979 auto values = assignment->action.to<Assign_t>()->values.objects();
2947 size_t size = std::max(exprs.size(), values.size()); 2980 size_t size = std::max(exprs.size(), values.size());
@@ -2951,10 +2984,26 @@ private:
2951 while (values.size() < size) values.emplace_back(nil); 2984 while (values.size() < size) values.emplace_back(nil);
2952 } 2985 }
2953 using iter = node_container::iterator; 2986 using iter = node_container::iterator;
2954 std::vector<std::pair<iter, iter>> destructPairs; 2987 std::vector<std::pair<iter, iter>> assignPairs;
2955 ast_list<false, ast_node> valueItems; 2988 ast_list<false, ast_node> valueItems;
2956 str_list temp; 2989 str_list temp;
2957 pushScope(); 2990 pushScope();
2991 auto checkCommonAssignment = [&]() {
2992 if (!assignPairs.empty()) {
2993 auto expList = x->new_ptr<ExpList_t>();
2994 auto newAssign = x->new_ptr<ExpListAssign_t>();
2995 newAssign->expList.set(expList);
2996 auto assign = x->new_ptr<Assign_t>();
2997 newAssign->action.set(assign);
2998 for (const auto& pair : assignPairs) {
2999 expList->exprs.push_back(*pair.first);
3000 assign->values.push_back(*pair.second);
3001 }
3002 assignPairs.clear();
3003 destructs.push_back(AssignmentPtr{newAssign, false});
3004 }
3005 };
3006 bool hasDestructuring = false;
2958 for (auto i = exprs.begin(), j = values.begin(); i != exprs.end(); ++i, ++j) { 3007 for (auto i = exprs.begin(), j = values.begin(); i != exprs.end(); ++i, ++j) {
2959 auto expr = *i; 3008 auto expr = *i;
2960 auto value = singleValueFrom(expr); 3009 auto value = singleValueFrom(expr);
@@ -2974,6 +3023,8 @@ private:
2974 } 3023 }
2975 } 3024 }
2976 if (destructNode) { 3025 if (destructNode) {
3026 hasDestructuring = true;
3027 checkCommonAssignment();
2977 if (*j != nil) { 3028 if (*j != nil) {
2978 if (auto ssVal = simpleSingleValueFrom(*j)) { 3029 if (auto ssVal = simpleSingleValueFrom(*j)) {
2979 switch (ssVal->value->get_id()) { 3030 switch (ssVal->value->get_id()) {
@@ -2989,7 +3040,6 @@ private:
2989 } 3040 }
2990 } 3041 }
2991 } 3042 }
2992 destructPairs.push_back({i, j});
2993 auto subDestruct = destructNode->new_ptr<TableLit_t>(); 3043 auto subDestruct = destructNode->new_ptr<TableLit_t>();
2994 auto subMetaDestruct = destructNode->new_ptr<TableLit_t>(); 3044 auto subMetaDestruct = destructNode->new_ptr<TableLit_t>();
2995 const node_container* dlist = nullptr; 3045 const node_container* dlist = nullptr;
@@ -3113,19 +3163,26 @@ private:
3113 if (!varDefOnly && !subDestruct->values.empty() && !subMetaDestruct->values.empty()) { 3163 if (!varDefOnly && !subDestruct->values.empty() && !subMetaDestruct->values.empty()) {
3114 auto var = singleVariableFrom(*j, AccessType::None); 3164 auto var = singleVariableFrom(*j, AccessType::None);
3115 if (var.empty() || !isLocal(var)) { 3165 if (var.empty() || !isLocal(var)) {
3166 checkCommonAssignment();
3116 auto objVar = getUnusedName("_obj_"sv); 3167 auto objVar = getUnusedName("_obj_"sv);
3117 addToScope(objVar); 3168 addToScope(objVar);
3118 valueItems.pop_back(); 3169 valueItems.pop_back();
3119 valueItems.push_back(toAst<Exp_t>(objVar, *j)); 3170 valueItems.push_back(toAst<Exp_t>(objVar, *j));
3120 exprs.push_back(valueItems.back()); 3171 auto expList = x->new_ptr<ExpList_t>();
3121 values.push_back(*j); 3172 auto newAssign = x->new_ptr<ExpListAssign_t>();
3173 newAssign->expList.set(expList);
3174 auto assign = x->new_ptr<Assign_t>();
3175 newAssign->action.set(assign);
3176 expList->exprs.push_back(valueItems.back());
3177 assign->values.push_back(*j);
3178 destructs.push_back(AssignmentPtr{newAssign, true});
3122 extraScope = true; 3179 extraScope = true;
3123 } 3180 }
3124 } 3181 }
3125 TableLit_t* tabs[] = {subDestruct.get(), subMetaDestruct.get()}; 3182 TableLit_t* tabs[] = {subDestruct.get(), subMetaDestruct.get()};
3126 for (auto tab : tabs) { 3183 for (auto tab : tabs) {
3127 if (!tab->values.empty()) { 3184 if (!tab->values.empty()) {
3128 auto& destruct = destructs.emplace_back(); 3185 Destructure destruct;
3129 if (!varDefOnly) { 3186 if (!varDefOnly) {
3130 destruct.value = valueItems.back(); 3187 destruct.value = valueItems.back();
3131 destruct.valueVar = singleVariableFrom(destruct.value, AccessType::None); 3188 destruct.valueVar = singleVariableFrom(destruct.value, AccessType::None);
@@ -3172,29 +3229,28 @@ private:
3172 destruct.valueVar.clear(); 3229 destruct.valueVar.clear();
3173 } 3230 }
3174 } 3231 }
3232 destructs.push_back(destruct);
3175 } 3233 }
3176 } 3234 }
3235 } else {
3236 assignPairs.push_back({i, j});
3177 } 3237 }
3178 } 3238 }
3179 for (const auto& p : destructPairs) { 3239 if (!hasDestructuring) {
3180 exprs.erase(p.first); 3240 popScope();
3181 values.erase(p.second); 3241 return {};
3182 }
3183 ast_ptr<false, ExpListAssign_t> newAssignment;
3184 if (!destructPairs.empty() && !exprs.empty()) {
3185 auto x = assignment;
3186 auto expList = x->new_ptr<ExpList_t>();
3187 auto newAssign = x->new_ptr<ExpListAssign_t>();
3188 newAssign->expList.set(expList);
3189 for (auto expr : exprs) expList->exprs.push_back(expr);
3190 auto assign = x->new_ptr<Assign_t>();
3191 for (auto value : values) assign->values.push_back(value);
3192 newAssign->action.set(assign);
3193 newAssignment = newAssign;
3194 } 3242 }
3243 checkCommonAssignment();
3195 if (!varDefOnly) { 3244 if (!varDefOnly) {
3196 for (auto& des : destructs) { 3245 for (auto& d : destructs) {
3246 if (std::holds_alternative<AssignmentPtr>(d)) {
3247 continue;
3248 }
3249 auto& des = std::get<Destructure>(d);
3197 for (const auto& item : des.items) { 3250 for (const auto& item : des.items) {
3251 if (!item.structure) {
3252 continue;
3253 }
3198 for (auto node : item.structure->items.objects()) { 3254 for (auto node : item.structure->items.objects()) {
3199 if (auto exp = ast_cast<Exp_t>(node)) { 3255 if (auto exp = ast_cast<Exp_t>(node)) {
3200 if (auto value = simpleSingleValueFrom(node)) { 3256 if (auto value = simpleSingleValueFrom(node)) {
@@ -3236,7 +3292,7 @@ private:
3236 } 3292 }
3237 } 3293 }
3238 popScope(); 3294 popScope();
3239 return {std::move(destructs), newAssignment, extraScope}; 3295 return {std::move(destructs), extraScope};
3240 } 3296 }
3241 3297
3242 void transformAssignmentCommon(ExpListAssign_t* assignment, str_list& out) { 3298 void transformAssignmentCommon(ExpListAssign_t* assignment, str_list& out) {
@@ -4746,23 +4802,30 @@ private:
4746 } 4802 }
4747 auto info = extractDestructureInfo(assignment, true, false); 4803 auto info = extractDestructureInfo(assignment, true, false);
4748 if (!info.destructures.empty()) { 4804 if (!info.destructures.empty()) {
4749 for (const auto& destruct : info.destructures) 4805 for (const auto& des : info.destructures) {
4750 for (const auto& item : destruct.items) 4806 if (std::holds_alternative<Destructure>(des)) {
4751 if (!item.targetVar.empty()) { 4807 const auto& destruct = std::get<Destructure>(des);
4752 if (std::isupper(item.targetVar[0]) && capital) { 4808 for (const auto& item : destruct.items) {
4753 capital->decls.push_back(item.targetVar); 4809 if (!item.targetVar.empty()) {
4754 } else if (any) { 4810 if (std::isupper(item.targetVar[0]) && capital) {
4755 any->decls.push_back(item.targetVar); 4811 capital->decls.push_back(item.targetVar);
4812 } else if (any) {
4813 any->decls.push_back(item.targetVar);
4814 }
4815 }
4816 }
4817 } else {
4818 const auto& assignment = std::get<AssignmentPtr>(des);
4819 if (!assignment.extraAssignment) {
4820 auto defs = transformAssignDefs(assignment.ptr->expList, DefOp::Get);
4821 for (const auto& def : defs) {
4822 if (std::isupper(def.first[0]) && capital) {
4823 capital->decls.push_back(def.first);
4824 } else if (any) {
4825 any->decls.push_back(def.first);
4826 }
4756 } 4827 }
4757 } 4828 }
4758 }
4759 if (info.assignment) {
4760 auto defs = transformAssignDefs(info.assignment->expList, DefOp::Get);
4761 for (const auto& def : defs) {
4762 if (std::isupper(def.first[0]) && capital) {
4763 capital->decls.push_back(def.first);
4764 } else if (any) {
4765 any->decls.push_back(def.first);
4766 } 4829 }
4767 } 4830 }
4768 } 4831 }
@@ -8551,10 +8614,17 @@ private:
8551 } 8614 }
8552 auto info = extractDestructureInfo(assignment, true, false); 8615 auto info = extractDestructureInfo(assignment, true, false);
8553 if (!info.destructures.empty()) { 8616 if (!info.destructures.empty()) {
8554 for (const auto& destruct : info.destructures) 8617 for (const auto& des : info.destructures) {
8555 for (const auto& item : destruct.items) 8618 if (std::holds_alternative<AssignmentPtr>(des)) {
8556 if (!item.targetVar.empty() && addToScope(item.targetVar)) 8619 continue;
8620 }
8621 const auto& destruct = std::get<Destructure>(des);
8622 for (const auto& item : destruct.items) {
8623 if (!item.targetVar.empty() && addToScope(item.targetVar)) {
8557 varDefs.push_back(item.targetVar); 8624 varDefs.push_back(item.targetVar);
8625 }
8626 }
8627 }
8558 } 8628 }
8559 BLOCK_START 8629 BLOCK_START
8560 auto assign = assignment->action.as<Assign_t>(); 8630 auto assign = assignment->action.as<Assign_t>();
@@ -9006,10 +9076,17 @@ private:
9006 } 9076 }
9007 auto info = extractDestructureInfo(assignment, true, false); 9077 auto info = extractDestructureInfo(assignment, true, false);
9008 if (!info.destructures.empty()) { 9078 if (!info.destructures.empty()) {
9009 for (const auto& destruct : info.destructures) 9079 for (const auto& des : info.destructures) {
9010 for (const auto& item : destruct.items) 9080 if (std::holds_alternative<AssignmentPtr>(des)) {
9011 if (!item.targetVar.empty() && !isDefined(item.targetVar)) 9081 continue;
9082 }
9083 const auto& destruct = std::get<Destructure>(des);
9084 for (const auto& item : destruct.items) {
9085 if (!item.targetVar.empty() && !isDefined(item.targetVar)) {
9012 return traversal::Stop; 9086 return traversal::Stop;
9087 }
9088 }
9089 }
9013 } 9090 }
9014 BLOCK_START 9091 BLOCK_START
9015 auto assign = assignment->action.as<Assign_t>(); 9092 auto assign = assignment->action.as<Assign_t>();
@@ -9248,13 +9325,19 @@ private:
9248 auto names = transformAssignDefs(expList, DefOp::Get); 9325 auto names = transformAssignDefs(expList, DefOp::Get);
9249 auto info = extractDestructureInfo(assignment, true, false); 9326 auto info = extractDestructureInfo(assignment, true, false);
9250 if (!info.destructures.empty()) { 9327 if (!info.destructures.empty()) {
9251 for (const auto& destruct : info.destructures) 9328 for (const auto& des : info.destructures) {
9252 for (const auto& item : destruct.items) 9329 if (std::holds_alternative<AssignmentPtr>(des)) {
9330 continue;
9331 }
9332 const auto& destruct = std::get<Destructure>(des);
9333 for (const auto& item : destruct.items) {
9253 if (!item.targetVar.empty()) { 9334 if (!item.targetVar.empty()) {
9254 auto dot = ast_cast<DotChainItem_t>(item.structure->items.back()); 9335 auto dot = ast_cast<DotChainItem_t>(item.structure->items.back());
9255 auto uname = dot->name.as<UnicodeName_t>(); 9336 auto uname = dot->name.as<UnicodeName_t>();
9256 names.emplace_back(item.targetVar, uname ? _parser.toString(uname) : Empty); 9337 names.emplace_back(item.targetVar, uname ? _parser.toString(uname) : Empty);
9257 } 9338 }
9339 }
9340 }
9258 } 9341 }
9259 if (_info.exportDefault) { 9342 if (_info.exportDefault) {
9260 out.back().append(indent() + _info.moduleName + " = "s + names.back().first + nlr(exportNode)); 9343 out.back().append(indent() + _info.moduleName + " = "s + names.back().first + nlr(exportNode));
@@ -10213,7 +10296,11 @@ private:
10213 auto info = extractDestructureInfo(assignment, true, false); 10296 auto info = extractDestructureInfo(assignment, true, false);
10214 transformAssignment(assignment, temp, true); 10297 transformAssignment(assignment, temp, true);
10215 str_list conds; 10298 str_list conds;
10216 for (const auto& destruct : info.destructures) { 10299 for (const auto& des : info.destructures) {
10300 if (std::holds_alternative<AssignmentPtr>(des)) {
10301 continue;
10302 }
10303 const auto& destruct = std::get<Destructure>(des);
10217 for (const auto& item : destruct.items) { 10304 for (const auto& item : destruct.items) {
10218 if (!item.defVal) { 10305 if (!item.defVal) {
10219 transformExp(item.target, conds, ExpUsage::Closure); 10306 transformExp(item.target, conds, ExpUsage::Closure);
@@ -10475,7 +10562,11 @@ private:
10475 assignment->expList.set(leftList); 10562 assignment->expList.set(leftList);
10476 assignment->action.set(assign); 10563 assignment->action.set(assign);
10477 auto info = extractDestructureInfo(assignment, true, false); 10564 auto info = extractDestructureInfo(assignment, true, false);
10478 for (auto& destruct : info.destructures) { 10565 for (const auto& des : info.destructures) {
10566 if (std::holds_alternative<AssignmentPtr>(des)) {
10567 continue;
10568 }
10569 const auto& destruct = std::get<Destructure>(des);
10479 for (auto& item : destruct.items) { 10570 for (auto& item : destruct.items) {
10480 if (item.targetVar.empty()) { 10571 if (item.targetVar.empty()) {
10481 throw CompileError("can only declare variable as const"sv, item.target); 10572 throw CompileError("can only declare variable as const"sv, item.target);
@@ -10569,7 +10660,11 @@ private:
10569 assignment->action.set(assignB); 10660 assignment->action.set(assignB);
10570 auto info = extractDestructureInfo(assignment, true, false); 10661 auto info = extractDestructureInfo(assignment, true, false);
10571 str_list vars; 10662 str_list vars;
10572 for (auto& destruct : info.destructures) { 10663 for (auto& des : info.destructures) {
10664 if (std::holds_alternative<AssignmentPtr>(des)) {
10665 continue;
10666 }
10667 const auto& destruct = std::get<Destructure>(des);
10573 for (auto& item : destruct.items) { 10668 for (auto& item : destruct.items) {
10574 if (item.targetVar.empty()) { 10669 if (item.targetVar.empty()) {
10575 throw CompileError("can only declare variable as const"sv, item.target); 10670 throw CompileError("can only declare variable as const"sv, item.target);