diff options
author | Li Jin <dragon-fly@qq.com> | 2022-07-12 17:41:19 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2022-07-12 17:41:19 +0800 |
commit | 68e167e9f0b90968ea67b7f21fdc50a48d129173 (patch) | |
tree | 64612476c7cc5636d7a9eea68ea1e5b449bb9732 | |
parent | 1a7c8e3c38fcf0af94ca799a3cd9fa7c4ef1bf08 (diff) | |
download | yuescript-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.yue | 3 | ||||
-rw-r--r-- | spec/inputs/switch.yue | 86 | ||||
-rw-r--r-- | spec/outputs/destructure.lua | 121 | ||||
-rw-r--r-- | spec/outputs/switch.lua | 264 | ||||
-rwxr-xr-x | src/yuescript/yue_ast.h | 8 | ||||
-rwxr-xr-x | src/yuescript/yue_compiler.cpp | 615 | ||||
-rwxr-xr-x | src/yuescript/yue_parser.cpp | 9 | ||||
-rwxr-xr-x | src/yuescript/yue_parser.h | 2 |
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 | |||
181 | do | 181 | do |
182 | {_, a, _, b} = tb -- list placeholder | 182 | {_, a, _, b} = tb -- list placeholder |
183 | 183 | ||
184 | do | ||
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 | ||
59 | switch hi | 59 | switch 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 | ||
65 | do | ||
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 | |||
82 | do | ||
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 | |||
109 | do | ||
110 | tb = {} | ||
111 | switch tb | ||
112 | when {:a = 1, :b = 2} | ||
113 | print a, b | ||
114 | |||
115 | do | ||
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 | |||
123 | do | ||
124 | matched = switch tb | ||
125 | when 1 | ||
126 | "1" | ||
127 | when :x | ||
128 | x | ||
129 | when false | ||
130 | "false" | ||
131 | else | ||
132 | nil | ||
133 | |||
134 | do | ||
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 | |||
147 | nil | ||
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 | ||
311 | end | 317 | end |
312 | do | 318 | do |
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 |
321 | end | 327 | end |
322 | do | 328 | do |
@@ -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 |
331 | end | 337 | end |
332 | do | 338 | do |
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 |
367 | end | 374 | end |
375 | do | ||
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 | ||
388 | end | ||
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 |
79 | end | 79 | end |
80 | local _exp_0 = hi | 80 | do |
81 | if (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() |
83 | end)() == _exp_0 then | 83 | return 4 |
84 | return yello | 84 | end)() == _exp_0 then |
85 | else | 85 | local _ = yello |
86 | return print("cool") | 86 | else |
87 | print("cool") | ||
88 | end | ||
89 | end | ||
90 | do | ||
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 | ||
163 | end | ||
164 | do | ||
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 | ||
230 | end | ||
231 | do | ||
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 | ||
249 | end | ||
250 | do | ||
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 | ||
274 | end | ||
275 | do | ||
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 | ||
300 | end | ||
301 | do | ||
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 | ||
87 | end | 336 | end |
337 | return 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) |
250 | AST_END(With, "with"sv) | 250 | AST_END(With, "with"sv) |
251 | 251 | ||
252 | AST_NODE(SwitchList) | ||
253 | ast_ptr<true, Seperator_t> sep; | ||
254 | ast_list<true, Exp_t> exprs; | ||
255 | AST_MEMBER(SwitchList, &sep, &exprs) | ||
256 | AST_END(SwitchList, "switch_list"sv) | ||
257 | |||
252 | AST_NODE(SwitchCase) | 258 | AST_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) |
256 | AST_END(SwitchCase, "switch_case"sv) | 262 | AST_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 | ||
57 | typedef std::list<std::string> str_list; | 57 | typedef std::list<std::string> str_list; |
58 | 58 | ||
59 | const std::string_view version = "0.12.0"sv; | 59 | const std::string_view version = "0.13.0"sv; |
60 | const std::string_view extension = "yue"sv; | 60 | const std::string_view extension = "yue"sv; |
61 | 61 | ||
62 | class YueCompilerImpl { | 62 | class 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) |