aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2025-06-04 11:38:34 +0800
committerLi Jin <dragon-fly@qq.com>2025-06-04 11:38:34 +0800
commit548ab1d9ff5b831050f14f1355a3314a41163ad6 (patch)
treed84b6b64b4e547070c7c43db53821b83b819ab8e
parent98be64dd52df92f7fdd40bae225c279db1676cab (diff)
downloadyuescript-548ab1d9ff5b831050f14f1355a3314a41163ad6.tar.gz
yuescript-548ab1d9ff5b831050f14f1355a3314a41163ad6.tar.bz2
yuescript-548ab1d9ff5b831050f14f1355a3314a41163ad6.zip
Added new syntax.
- Slice Expression. - Reversed Indexing,. - Range Destructuring. - Table Range Matching.
-rw-r--r--spec/inputs/destructure.yue38
-rw-r--r--spec/inputs/lists.yue47
-rw-r--r--spec/inputs/switch.yue17
-rw-r--r--spec/outputs/codes_from_doc.lua8
-rw-r--r--spec/outputs/codes_from_doc_zh.lua8
-rw-r--r--spec/outputs/comprehension.lua4
-rw-r--r--spec/outputs/destructure.lua90
-rw-r--r--spec/outputs/lists.lua192
-rw-r--r--spec/outputs/switch.lua50
-rw-r--r--spec/outputs/unicode/comprehension.lua4
-rw-r--r--spec/outputs/unicode/lists.lua6
-rw-r--r--src/yuescript/yue_ast.cpp6
-rw-r--r--src/yuescript/yue_ast.h7
-rw-r--r--src/yuescript/yue_compiler.cpp248
-rw-r--r--src/yuescript/yue_parser.cpp3
-rw-r--r--src/yuescript/yue_parser.h1
16 files changed, 678 insertions, 51 deletions
diff --git a/spec/inputs/destructure.yue b/spec/inputs/destructure.yue
index 9f01a20..b6250d0 100644
--- a/spec/inputs/destructure.yue
+++ b/spec/inputs/destructure.yue
@@ -240,5 +240,43 @@ do
240 switch tb 240 switch tb
241 when {c: {<"abc">: meta_field = "def"}, <[[any string]]>: {d: abc = 123}, <'str'>: {e: def = {}}} 241 when {c: {<"abc">: meta_field = "def"}, <[[any string]]>: {d: abc = 123}, <'str'>: {e: def = {}}}
242 print meta_field, abc, def 242 print meta_field, abc, def
243
244do
245 clients = ["VIP_Alice", "User_Bob", "User_Clara", "VIP_Eva"]
246 [vipStart, ...regulars, vipEnd] = clients
247 print vipStart -- "VIP_Alice"
248 print regulars -- {"User_Bob", "User_Clara"}
249 print vipEnd -- "VIP_Eva"
250
251do
252 setupMeeting = (participants) ->
253 [chair, ..._, secretary] = participants
254 print chair, secretary
255
256 setupMeeting ["Alice", "Bob", "Charlie", "David"]
257 -- Output: Alice David
258
259do
260 getTransactions = ->
261 {
262 {id: "T1", amount: 100}
263 {id: "T2", amount: 200}
264 {id: "T3", amount: 300}
265 }
266
267 :id, :amount = getTransactions![#]
268 assert id == "T3"
269 assert amount == 300
270
271do
272 [
273 _
274 ...middle
275 _
276 ] = tb
277
278do
279 {a, :abc, b, :def, ...sub, d, e} = tb
280
243nil 281nil
244 282
diff --git a/spec/inputs/lists.yue b/spec/inputs/lists.yue
index 921cae0..c493b68 100644
--- a/spec/inputs/lists.yue
+++ b/spec/inputs/lists.yue
@@ -87,4 +87,51 @@ do
87 [a, b] = hello 87 [a, b] = hello
88 [name = "nameless", job = "jobless"] = person 88 [name = "nameless", job = "jobless"] = person
89 89
90do
91 transactions = ["T001", "T002", "T003", "T004", "T005"]
92 middleTransactions = transactions[2, -2]
93 print middleTransactions -- => {"T002", "T003", "T004"}
94
95do
96 logs =
97 - start: 0, end: 100
98 - start: 100, end: 200
99 - start: 200, end: 123
100 print logs[#].end -- => 123
101
102do
103 pendingOrders = ["O001", "O002", "O003", "O004"]
104 print pendingOrders[# - 1] -- => "O003"
105
106do
107 getOrders = ->
108 {
109 { id: "O1001", status: "pending" }
110 { id: "O1002", status: "processing" }
111 { id: "O1003", status: "done" }
112 }
113
114 lastStatus = getOrders()[#].status
115 assert lastStatus == "done"
116
117do
118 cloneList1 = (list) -> list[,]
119 cloneList2 = (list) -> [...list,]
120 cloneTable = (tb) -> {...tb}
121
122do
123 print(
124 globalTB[#]
125 a.b.c[# - 2]
126 x?\y?!.z?[# - 3]
127 )
128
129do
130 f = ->
131 print(
132 globalTB[#]\end 123
133 a.b.c[5,-5][# - 2]
134 x?\y?!.z?[# - 3]?[, -3]
135 )
136
90nil 137nil
diff --git a/spec/inputs/switch.yue b/spec/inputs/switch.yue
index 5097db3..2b0669c 100644
--- a/spec/inputs/switch.yue
+++ b/spec/inputs/switch.yue
@@ -272,4 +272,21 @@ do
272 else 272 else
273 print "not matched" 273 print "not matched"
274 274
275do
276 clientData = ["Meta", "CUST_1001", "CHK123"]
277 switch clientData
278 when [...metadata, customerId, checksum]
279 print metadata -- {"Meta"}
280 print customerId -- "CUST_1001"
281 print checksum -- "CHK123"
282
283do
284 handlePath = (segments) ->
285 switch segments
286 when [..._, resource, action]
287 print "Resource:", resource
288 print "Action:", action
289
290 handlePath ["admin", "logs", "view"]
291
275nil 292nil
diff --git a/spec/outputs/codes_from_doc.lua b/spec/outputs/codes_from_doc.lua
index cce0516..b8dd9b7 100644
--- a/spec/outputs/codes_from_doc.lua
+++ b/spec/outputs/codes_from_doc.lua
@@ -1063,7 +1063,7 @@ local _accum_0 = { }
1063local _len_0 = 1 1063local _len_0 = 1
1064local _list_0 = items 1064local _list_0 = items
1065local _max_0 = 5 1065local _max_0 = 5
1066for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do 1066for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 + 1 or _max_0 do
1067 local item = _list_0[_index_0] 1067 local item = _list_0[_index_0]
1068 _accum_0[_len_0] = item 1068 _accum_0[_len_0] = item
1069 _len_0 = _len_0 + 1 1069 _len_0 = _len_0 + 1
@@ -1100,7 +1100,7 @@ for key, value in pairs(object) do
1100end 1100end
1101local _list_0 = items 1101local _list_0 = items
1102local _max_0 = 4 1102local _max_0 = 4
1103for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do 1103for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 + 1 or _max_0 do
1104 local item = _list_0[_index_0] 1104 local item = _list_0[_index_0]
1105 print(item) 1105 print(item)
1106end 1106end
@@ -3333,7 +3333,7 @@ local _accum_0 = { }
3333local _len_0 = 1 3333local _len_0 = 1
3334local _list_0 = items 3334local _list_0 = items
3335local _max_0 = 5 3335local _max_0 = 5
3336for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do 3336for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 + 1 or _max_0 do
3337 local item = _list_0[_index_0] 3337 local item = _list_0[_index_0]
3338 _accum_0[_len_0] = item 3338 _accum_0[_len_0] = item
3339 _len_0 = _len_0 + 1 3339 _len_0 = _len_0 + 1
@@ -3370,7 +3370,7 @@ for key, value in pairs(object) do
3370end 3370end
3371local _list_0 = items 3371local _list_0 = items
3372local _max_0 = 4 3372local _max_0 = 4
3373for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do 3373for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 + 1 or _max_0 do
3374 local item = _list_0[_index_0] 3374 local item = _list_0[_index_0]
3375 print(item) 3375 print(item)
3376end 3376end
diff --git a/spec/outputs/codes_from_doc_zh.lua b/spec/outputs/codes_from_doc_zh.lua
index e267709..80644a5 100644
--- a/spec/outputs/codes_from_doc_zh.lua
+++ b/spec/outputs/codes_from_doc_zh.lua
@@ -1057,7 +1057,7 @@ local _accum_0 = { }
1057local _len_0 = 1 1057local _len_0 = 1
1058local _list_0 = items 1058local _list_0 = items
1059local _max_0 = 5 1059local _max_0 = 5
1060for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do 1060for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 + 1 or _max_0 do
1061 local item = _list_0[_index_0] 1061 local item = _list_0[_index_0]
1062 _accum_0[_len_0] = item 1062 _accum_0[_len_0] = item
1063 _len_0 = _len_0 + 1 1063 _len_0 = _len_0 + 1
@@ -1094,7 +1094,7 @@ for key, value in pairs(object) do
1094end 1094end
1095local _list_0 = items 1095local _list_0 = items
1096local _max_0 = 4 1096local _max_0 = 4
1097for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do 1097for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 + 1 or _max_0 do
1098 local item = _list_0[_index_0] 1098 local item = _list_0[_index_0]
1099 print(item) 1099 print(item)
1100end 1100end
@@ -3321,7 +3321,7 @@ local _accum_0 = { }
3321local _len_0 = 1 3321local _len_0 = 1
3322local _list_0 = items 3322local _list_0 = items
3323local _max_0 = 5 3323local _max_0 = 5
3324for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do 3324for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 + 1 or _max_0 do
3325 local item = _list_0[_index_0] 3325 local item = _list_0[_index_0]
3326 _accum_0[_len_0] = item 3326 _accum_0[_len_0] = item
3327 _len_0 = _len_0 + 1 3327 _len_0 = _len_0 + 1
@@ -3358,7 +3358,7 @@ for key, value in pairs(object) do
3358end 3358end
3359local _list_0 = items 3359local _list_0 = items
3360local _max_0 = 4 3360local _max_0 = 4
3361for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do 3361for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 + 1 or _max_0 do
3362 local item = _list_0[_index_0] 3362 local item = _list_0[_index_0]
3363 print(item) 3363 print(item)
3364end 3364end
diff --git a/spec/outputs/comprehension.lua b/spec/outputs/comprehension.lua
index 9a7c478..ac4f9d8 100644
--- a/spec/outputs/comprehension.lua
+++ b/spec/outputs/comprehension.lua
@@ -244,7 +244,7 @@ do
244 local _accum_0 = { } 244 local _accum_0 = { }
245 local _len_0 = 1 245 local _len_0 = 1
246 local _max_0 = 3 + 4 246 local _max_0 = 3 + 4
247 for _index_0 = 1 + 2, _max_0 < 0 and #items + _max_0 or _max_0 do 247 for _index_0 = 1 + 2, _max_0 < 0 and #items + _max_0 + 1 or _max_0 do
248 local item = items[_index_0] 248 local item = items[_index_0]
249 _accum_0[_len_0] = item 249 _accum_0[_len_0] = item
250 _len_0 = _len_0 + 1 250 _len_0 = _len_0 + 1
@@ -255,7 +255,7 @@ do
255 local _accum_0 = { } 255 local _accum_0 = { }
256 local _len_0 = 1 256 local _len_0 = 1
257 local _max_0 = 2 - thing[4] 257 local _max_0 = 2 - thing[4]
258 for _index_0 = hello() * 4, _max_0 < 0 and #items + _max_0 or _max_0 do 258 for _index_0 = hello() * 4, _max_0 < 0 and #items + _max_0 + 1 or _max_0 do
259 local item = items[_index_0] 259 local item = items[_index_0]
260 _accum_0[_len_0] = item 260 _accum_0[_len_0] = item
261 _len_0 = _len_0 + 1 261 _len_0 = _len_0 + 1
diff --git a/spec/outputs/destructure.lua b/spec/outputs/destructure.lua
index 44da58b..216d921 100644
--- a/spec/outputs/destructure.lua
+++ b/spec/outputs/destructure.lua
@@ -621,4 +621,94 @@ do
621 print(meta_field, abc, def) 621 print(meta_field, abc, def)
622 end 622 end
623end 623end
624do
625 local clients = {
626 "VIP_Alice",
627 "User_Bob",
628 "User_Clara",
629 "VIP_Eva"
630 }
631 local vipStart, regulars, vipEnd = clients[1], (function()
632 local _accum_0 = { }
633 local _len_0 = 1
634 local _max_0 = -2
635 for _index_0 = 2, _max_0 < 0 and #clients + _max_0 + 1 or _max_0 do
636 local _item_0 = clients[_index_0]
637 _accum_0[_len_0] = _item_0
638 _len_0 = _len_0 + 1
639 end
640 return _accum_0
641 end)(), clients[#clients]
642 print(vipStart)
643 print(regulars)
644 print(vipEnd)
645end
646do
647 local setupMeeting
648 setupMeeting = function(participants)
649 local chair, secretary = participants[1], participants[#participants]
650 return print(chair, secretary)
651 end
652 setupMeeting({
653 "Alice",
654 "Bob",
655 "Charlie",
656 "David"
657 })
658end
659do
660 local getTransactions
661 getTransactions = function()
662 return {
663 {
664 id = "T1",
665 amount = 100
666 },
667 {
668 id = "T2",
669 amount = 200
670 },
671 {
672 id = "T3",
673 amount = 300
674 }
675 }
676 end
677 local id, amount
678 do
679 local _item_0 = getTransactions()
680 local _obj_0 = _item_0[#_item_0]
681 id, amount = _obj_0.id, _obj_0.amount
682 end
683 assert(id == "T3")
684 assert(amount == 300)
685end
686do
687 local middle
688 local _accum_0 = { }
689 local _len_0 = 1
690 local _list_0 = tb
691 local _max_0 = -2
692 for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 + 1 or _max_0 do
693 local _item_0 = _list_0[_index_0]
694 _accum_0[_len_0] = _item_0
695 _len_0 = _len_0 + 1
696 end
697 middle = _accum_0
698end
699do
700 local a, abc, b, def, sub, d, e
701 local _obj_0 = tb
702 a, abc, b, def, sub, d, e = _obj_0[1], _obj_0.abc, _obj_0[2], _obj_0.def, (function()
703 local _accum_0 = { }
704 local _len_0 = 1
705 local _max_0 = -3
706 for _index_0 = 3, _max_0 < 0 and #_obj_0 + _max_0 + 1 or _max_0 do
707 local _item_0 = _obj_0[_index_0]
708 _accum_0[_len_0] = _item_0
709 _len_0 = _len_0 + 1
710 end
711 return _accum_0
712 end)(), _obj_0[#_obj_0 - 1], _obj_0[#_obj_0]
713end
624return nil 714return nil
diff --git a/spec/outputs/lists.lua b/spec/outputs/lists.lua
index 48ec9c8..1bdfa3e 100644
--- a/spec/outputs/lists.lua
+++ b/spec/outputs/lists.lua
@@ -231,12 +231,12 @@ x = {
231 7 231 7
232} 232}
233local _max_0 = -5 233local _max_0 = -5
234for _index_0 = 2, _max_0 < 0 and #x + _max_0 or _max_0, 2 do 234for _index_0 = 2, _max_0 < 0 and #x + _max_0 + 1 or _max_0, 2 do
235 local y = x[_index_0] 235 local y = x[_index_0]
236 print(y) 236 print(y)
237end 237end
238local _max_1 = 3 238local _max_1 = 3
239for _index_0 = 1, _max_1 < 0 and #x + _max_1 or _max_1 do 239for _index_0 = 1, _max_1 < 0 and #x + _max_1 + 1 or _max_1 do
240 local y = x[_index_0] 240 local y = x[_index_0]
241 print(y) 241 print(y)
242end 242end
@@ -254,7 +254,7 @@ for _index_0 = 2, #x, 2 do
254end 254end
255local a, b, c = 1, 5, 2 255local a, b, c = 1, 5, 2
256local _max_2 = b 256local _max_2 = b
257for _index_0 = a, _max_2 < 0 and #x + _max_2 or _max_2, c do 257for _index_0 = a, _max_2 < 0 and #x + _max_2 + 1 or _max_2, c do
258 local y = x[_index_0] 258 local y = x[_index_0]
259 print(y) 259 print(y)
260end 260end
@@ -327,4 +327,190 @@ do
327 job = "jobless" 327 job = "jobless"
328 end 328 end
329end 329end
330do
331 local transactions = {
332 "T001",
333 "T002",
334 "T003",
335 "T004",
336 "T005"
337 }
338 local middleTransactions
339 do
340 local _accum_0 = { }
341 local _len_0 = 1
342 local _max_3 = -2
343 for _index_0 = 2, _max_3 < 0 and #transactions + _max_3 + 1 or _max_3 do
344 local _item_0 = transactions[_index_0]
345 _accum_0[_len_0] = _item_0
346 _len_0 = _len_0 + 1
347 end
348 middleTransactions = _accum_0
349 end
350 print(middleTransactions)
351end
352do
353 local logs = {
354 {
355 start = 0,
356 ["end"] = 100
357 },
358 {
359 start = 100,
360 ["end"] = 200
361 },
362 {
363 start = 200,
364 ["end"] = 123
365 }
366 }
367 print(logs[#logs]["end"])
368end
369do
370 local pendingOrders = {
371 "O001",
372 "O002",
373 "O003",
374 "O004"
375 }
376 print(pendingOrders[#pendingOrders - 1])
377end
378do
379 local getOrders
380 getOrders = function()
381 return {
382 {
383 id = "O1001",
384 status = "pending"
385 },
386 {
387 id = "O1002",
388 status = "processing"
389 },
390 {
391 id = "O1003",
392 status = "done"
393 }
394 }
395 end
396 local lastStatus
397 do
398 local _item_0 = getOrders()
399 lastStatus = _item_0[#_item_0].status
400 end
401 assert(lastStatus == "done")
402end
403do
404 local cloneList1
405 cloneList1 = function(list)
406 local _accum_0 = { }
407 local _len_0 = 1
408 for _index_0 = 1, #list do
409 local _item_0 = list[_index_0]
410 _accum_0[_len_0] = _item_0
411 _len_0 = _len_0 + 1
412 end
413 return _accum_0
414 end
415 local cloneList2
416 cloneList2 = function(list)
417 local _tab_0 = { }
418 local _idx_0 = #_tab_0 + 1
419 for _index_0 = 1, #list do
420 local _value_0 = list[_index_0]
421 _tab_0[_idx_0] = _value_0
422 _idx_0 = _idx_0 + 1
423 end
424 return _tab_0
425 end
426 local cloneTable
427 cloneTable = function(tb)
428 local _tab_0 = { }
429 local _idx_0 = 1
430 for _key_0, _value_0 in pairs(tb) do
431 if _idx_0 == _key_0 then
432 _tab_0[#_tab_0 + 1] = _value_0
433 _idx_0 = _idx_0 + 1
434 else
435 _tab_0[_key_0] = _value_0
436 end
437 end
438 return _tab_0
439 end
440end
441do
442 print((function()
443 local _item_0 = globalTB
444 return _item_0[#_item_0]
445 end)(), (function()
446 local _item_0 = a.b.c
447 return _item_0[#_item_0 - 2]
448 end)(), (function()
449 if x ~= nil then
450 local _obj_0 = x.y
451 if _obj_0 ~= nil then
452 local _obj_1 = _obj_0(x).z
453 if _obj_1 ~= nil then
454 return _obj_1[#_obj_1 - 3]
455 end
456 return nil
457 end
458 return nil
459 end
460 return nil
461 end)())
462end
463local _anon_func_0 = function(globalTB)
464 local _item_0 = globalTB
465 local _call_0 = _item_0[#_item_0]
466 return _call_0["end"](_call_0, 123)
467end
468local _anon_func_1 = function(a)
469 local _item_0
470 do
471 local _accum_0 = { }
472 local _len_0 = 1
473 local _list_0 = a.b.c
474 local _max_3 = -5
475 for _index_0 = 5, _max_3 < 0 and #_list_0 + _max_3 + 1 or _max_3 do
476 local _item_1 = _list_0[_index_0]
477 _accum_0[_len_0] = _item_1
478 _len_0 = _len_0 + 1
479 end
480 _item_0 = _accum_0
481 end
482 return _item_0[#_item_0 - 2]
483end
484local _anon_func_2 = function(x)
485 if x ~= nil then
486 local _obj_0 = x.y
487 if _obj_0 ~= nil then
488 local _obj_1 = _obj_0(x).z
489 if _obj_1 ~= nil then
490 local _obj_2 = _obj_1[#_obj_1 - 3]
491 if _obj_2 ~= nil then
492 local _accum_0 = { }
493 local _len_0 = 1
494 local _max_3 = -3
495 for _index_0 = 1, _max_3 < 0 and #_obj_2 + _max_3 + 1 or _max_3 do
496 local _item_0 = _obj_2[_index_0]
497 _accum_0[_len_0] = _item_0
498 _len_0 = _len_0 + 1
499 end
500 return _accum_0
501 end
502 return nil
503 end
504 return nil
505 end
506 return nil
507 end
508 return nil
509end
510do
511 local f
512 f = function()
513 return print(_anon_func_0(globalTB), _anon_func_1(a), _anon_func_2(x))
514 end
515end
330return nil 516return nil
diff --git a/spec/outputs/switch.lua b/spec/outputs/switch.lua
index 204b816..7a11bac 100644
--- a/spec/outputs/switch.lua
+++ b/spec/outputs/switch.lua
@@ -727,4 +727,54 @@ do
727 print("not matched") 727 print("not matched")
728 end 728 end
729end 729end
730do
731 local clientData = {
732 "Meta",
733 "CUST_1001",
734 "CHK123"
735 }
736 local _type_0 = type(clientData)
737 local _tab_0 = "table" == _type_0 or "userdata" == _type_0
738 if _tab_0 then
739 local metadata
740 do
741 local _accum_0 = { }
742 local _len_0 = 1
743 local _max_0 = -3
744 for _index_0 = 1, _max_0 < 0 and #clientData + _max_0 + 1 or _max_0 do
745 local _item_0 = clientData[_index_0]
746 _accum_0[_len_0] = _item_0
747 _len_0 = _len_0 + 1
748 end
749 metadata = _accum_0
750 end
751 local customerId = clientData[#clientData - 1]
752 local checksum = clientData[#clientData]
753 if customerId ~= nil and checksum ~= nil then
754 print(metadata)
755 print(customerId)
756 print(checksum)
757 end
758 end
759end
760do
761 local handlePath
762 handlePath = function(segments)
763 local _type_0 = type(segments)
764 local _tab_0 = "table" == _type_0 or "userdata" == _type_0
765 if _tab_0 then
766 local resource = segments[#segments - 1]
767 local action = segments[#segments]
768 if resource ~= nil and action ~= nil then
769 print("Resource:", resource)
770 return print("Action:", action)
771 end
772 end
773 end
774 handlePath({
775 "admin",
776 "logs",
777 "view"
778 })
779end
730return nil 780return nil
diff --git a/spec/outputs/unicode/comprehension.lua b/spec/outputs/unicode/comprehension.lua
index 60e490f..894e78f 100644
--- a/spec/outputs/unicode/comprehension.lua
+++ b/spec/outputs/unicode/comprehension.lua
@@ -244,7 +244,7 @@ do
244 local _accum_0 = { } 244 local _accum_0 = { }
245 local _len_0 = 1 245 local _len_0 = 1
246 local _max_0 = 3 + 4 246 local _max_0 = 3 + 4
247 for _index_0 = 1 + 2, _max_0 < 0 and #_u5217_u8868 + _max_0 or _max_0 do 247 for _index_0 = 1 + 2, _max_0 < 0 and #_u5217_u8868 + _max_0 + 1 or _max_0 do
248 local _u9879_u76ee = _u5217_u8868[_index_0] 248 local _u9879_u76ee = _u5217_u8868[_index_0]
249 _accum_0[_len_0] = _u9879_u76ee 249 _accum_0[_len_0] = _u9879_u76ee
250 _len_0 = _len_0 + 1 250 _len_0 = _len_0 + 1
@@ -255,7 +255,7 @@ do
255 local _accum_0 = { } 255 local _accum_0 = { }
256 local _len_0 = 1 256 local _len_0 = 1
257 local _max_0 = 2 - _u4e1c_u897f[4] 257 local _max_0 = 2 - _u4e1c_u897f[4]
258 for _index_0 = _u4f60_u597d() * 4, _max_0 < 0 and #_u5217_u8868 + _max_0 or _max_0 do 258 for _index_0 = _u4f60_u597d() * 4, _max_0 < 0 and #_u5217_u8868 + _max_0 + 1 or _max_0 do
259 local _u9879_u76ee = _u5217_u8868[_index_0] 259 local _u9879_u76ee = _u5217_u8868[_index_0]
260 _accum_0[_len_0] = _u9879_u76ee 260 _accum_0[_len_0] = _u9879_u76ee
261 _len_0 = _len_0 + 1 261 _len_0 = _len_0 + 1
diff --git a/spec/outputs/unicode/lists.lua b/spec/outputs/unicode/lists.lua
index aafd516..a3c329b 100644
--- a/spec/outputs/unicode/lists.lua
+++ b/spec/outputs/unicode/lists.lua
@@ -230,12 +230,12 @@ _u53d8_u91cfx = {
230 7 230 7
231} 231}
232local _max_0 = -5 232local _max_0 = -5
233for _index_0 = 2, _max_0 < 0 and #_u53d8_u91cfx + _max_0 or _max_0, 2 do 233for _index_0 = 2, _max_0 < 0 and #_u53d8_u91cfx + _max_0 + 1 or _max_0, 2 do
234 local _u53d8_u91cfy = _u53d8_u91cfx[_index_0] 234 local _u53d8_u91cfy = _u53d8_u91cfx[_index_0]
235 _u6253_u5370(_u53d8_u91cfy) 235 _u6253_u5370(_u53d8_u91cfy)
236end 236end
237local _max_1 = 3 237local _max_1 = 3
238for _index_0 = 1, _max_1 < 0 and #_u53d8_u91cfx + _max_1 or _max_1 do 238for _index_0 = 1, _max_1 < 0 and #_u53d8_u91cfx + _max_1 + 1 or _max_1 do
239 local _u53d8_u91cfy = _u53d8_u91cfx[_index_0] 239 local _u53d8_u91cfy = _u53d8_u91cfx[_index_0]
240 _u6253_u5370(_u53d8_u91cfy) 240 _u6253_u5370(_u53d8_u91cfy)
241end 241end
@@ -253,7 +253,7 @@ for _index_0 = 2, #_u53d8_u91cfx, 2 do
253end 253end
254local _u53d8_u91cfa, _u53d8_u91cfb, _u53d8_u91cfc = 1, 5, 2 254local _u53d8_u91cfa, _u53d8_u91cfb, _u53d8_u91cfc = 1, 5, 2
255local _max_2 = _u53d8_u91cfb 255local _max_2 = _u53d8_u91cfb
256for _index_0 = _u53d8_u91cfa, _max_2 < 0 and #_u53d8_u91cfx + _max_2 or _max_2, _u53d8_u91cfc do 256for _index_0 = _u53d8_u91cfa, _max_2 < 0 and #_u53d8_u91cfx + _max_2 + 1 or _max_2, _u53d8_u91cfc do
257 local _u53d8_u91cfy = _u53d8_u91cfx[_index_0] 257 local _u53d8_u91cfy = _u53d8_u91cfx[_index_0]
258 _u6253_u5370(_u53d8_u91cfy) 258 _u6253_u5370(_u53d8_u91cfy)
259end 259end
diff --git a/src/yuescript/yue_ast.cpp b/src/yuescript/yue_ast.cpp
index c4f133b..da99d07 100644
--- a/src/yuescript/yue_ast.cpp
+++ b/src/yuescript/yue_ast.cpp
@@ -870,6 +870,12 @@ std::string Exp_t::to_string(void* ud) const {
870 } 870 }
871 return join(temp, " "sv); 871 return join(temp, " "sv);
872} 872}
873std::string ReversedIndex_t::to_string(void* ud) const {
874 if (modifier) {
875 return "[# - "s + modifier->to_string(ud) + ']';
876 }
877 return "[#]"s;
878}
873std::string Callable_t::to_string(void* ud) const { 879std::string Callable_t::to_string(void* ud) const {
874 return item->to_string(ud); 880 return item->to_string(ud);
875} 881}
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h
index 6bdc31b..d396d82 100644
--- a/src/yuescript/yue_ast.h
+++ b/src/yuescript/yue_ast.h
@@ -643,9 +643,14 @@ AST_END(TableAppendingOp)
643AST_LEAF(PlainItem) 643AST_LEAF(PlainItem)
644AST_END(PlainItem) 644AST_END(PlainItem)
645 645
646AST_NODE(ReversedIndex)
647 ast_ptr<false, Exp_t> modifier;
648 AST_MEMBER(ReversedIndex, &modifier)
649AST_END(ReversedIndex)
650
646AST_NODE(ChainValue) 651AST_NODE(ChainValue)
647 ast_ptr<true, Seperator_t> sep; 652 ast_ptr<true, Seperator_t> sep;
648 ast_sel_list<true, Callable_t, Invoke_t, DotChainItem_t, ColonChainItem_t, Slice_t, Exp_t, String_t, InvokeArgs_t, ExistentialOp_t, TableAppendingOp_t, 653 ast_sel_list<true, Callable_t, Invoke_t, DotChainItem_t, ColonChainItem_t, Slice_t, Exp_t, String_t, InvokeArgs_t, ExistentialOp_t, TableAppendingOp_t, ReversedIndex_t,
649 /*non-syntax-rule*/ PlainItem_t> items; 654 /*non-syntax-rule*/ PlainItem_t> items;
650 AST_MEMBER(ChainValue, &sep, &items) 655 AST_MEMBER(ChainValue, &sep, &items)
651AST_END(ChainValue) 656AST_END(ChainValue)
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp
index 4bac51b..cbf976f 100644
--- a/src/yuescript/yue_compiler.cpp
+++ b/src/yuescript/yue_compiler.cpp
@@ -78,7 +78,7 @@ static std::unordered_set<std::string> Metamethods = {
78 "close"s // Lua 5.4 78 "close"s // Lua 5.4
79}; 79};
80 80
81const std::string_view version = "0.28.7"sv; 81const std::string_view version = "0.29.0"sv;
82const std::string_view extension = "yue"sv; 82const std::string_view extension = "yue"sv;
83 83
84class CompileError : public std::logic_error { 84class CompileError : public std::logic_error {
@@ -1281,6 +1281,8 @@ private:
1281 Common, 1281 Common,
1282 EndWithColon, 1282 EndWithColon,
1283 EndWithEOP, 1283 EndWithEOP,
1284 EndWithSlice,
1285 HasRIndex,
1284 HasEOP, 1286 HasEOP,
1285 HasKeyword, 1287 HasKeyword,
1286 HasUnicode, 1288 HasUnicode,
@@ -1299,6 +1301,9 @@ private:
1299 if (ast_is<ExistentialOp_t>(chainValue->items.back())) { 1301 if (ast_is<ExistentialOp_t>(chainValue->items.back())) {
1300 return ChainType::EndWithEOP; 1302 return ChainType::EndWithEOP;
1301 } 1303 }
1304 if (ast_is<Slice_t>(chainValue->items.back())) {
1305 return ChainType::EndWithSlice;
1306 }
1302 if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) { 1307 if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) {
1303 if (dot->name.is<Metatable_t>()) { 1308 if (dot->name.is<Metatable_t>()) {
1304 return ChainType::Metatable; 1309 return ChainType::Metatable;
@@ -1324,6 +1329,8 @@ private:
1324 } 1329 }
1325 } else if (ast_is<ExistentialOp_t>(item)) { 1330 } else if (ast_is<ExistentialOp_t>(item)) {
1326 return ChainType::HasEOP; 1331 return ChainType::HasEOP;
1332 } else if (ast_is<ReversedIndex_t>(item)) {
1333 return ChainType::HasRIndex;
1327 } 1334 }
1328 } 1335 }
1329 return type; 1336 return type;
@@ -2471,12 +2478,14 @@ private:
2471 switch (type) { 2478 switch (type) {
2472 case ChainType::HasEOP: 2479 case ChainType::HasEOP:
2473 case ChainType::EndWithColon: 2480 case ChainType::EndWithColon:
2481 case ChainType::EndWithSlice:
2474 case ChainType::MetaFieldInvocation: { 2482 case ChainType::MetaFieldInvocation: {
2475 std::string preDefine = getPreDefineLine(assignment); 2483 std::string preDefine = getPreDefineLine(assignment);
2476 transformChainValue(chainValue, out, ExpUsage::Assignment, expList, false, optionalDestruct); 2484 transformChainValue(chainValue, out, ExpUsage::Assignment, expList, false, optionalDestruct);
2477 out.back().insert(0, preDefine); 2485 out.back().insert(0, preDefine);
2478 return false; 2486 return false;
2479 } 2487 }
2488 case ChainType::HasRIndex:
2480 case ChainType::HasKeyword: 2489 case ChainType::HasKeyword:
2481 case ChainType::HasUnicode: 2490 case ChainType::HasUnicode:
2482 case ChainType::Macro: 2491 case ChainType::Macro:
@@ -2832,17 +2841,19 @@ private:
2832 if (!tableItems) throw CompileError("invalid destructure value"sv, node); 2841 if (!tableItems) throw CompileError("invalid destructure value"sv, node);
2833 std::list<DestructItem> pairs; 2842 std::list<DestructItem> pairs;
2834 int index = 0; 2843 int index = 0;
2844 int count = 0;
2845 bool hasSpread = false;
2835 auto subMetaDestruct = node->new_ptr<TableLit_t>(); 2846 auto subMetaDestruct = node->new_ptr<TableLit_t>();
2836 for (auto pair : *tableItems) { 2847 for (auto pair : *tableItems) {
2837 switch (pair->get_id()) { 2848 switch (pair->get_id()) {
2838 case id<Exp_t>(): 2849 case id<Exp_t>():
2839 case id<NormalDef_t>(): { 2850 case id<NormalDef_t>(): {
2851 ++index;
2840 Exp_t* defVal = nullptr; 2852 Exp_t* defVal = nullptr;
2841 if (auto nd = ast_cast<NormalDef_t>(pair)) { 2853 if (auto nd = ast_cast<NormalDef_t>(pair)) {
2842 pair = nd->item.get(); 2854 pair = nd->item.get();
2843 defVal = nd->defVal.get(); 2855 defVal = nd->defVal.get();
2844 } 2856 }
2845 ++index;
2846 bool assignable = false; 2857 bool assignable = false;
2847 try { 2858 try {
2848 assignable = isAssignable(static_cast<Exp_t*>(pair)); 2859 assignable = isAssignable(static_cast<Exp_t*>(pair));
@@ -2853,13 +2864,19 @@ private:
2853 if (optional) break; 2864 if (optional) break;
2854 throw CompileError("can't destructure value"sv, pair); 2865 throw CompileError("can't destructure value"sv, pair);
2855 } 2866 }
2867 ast_ptr<true, ast_node> indexItem;
2868 if (hasSpread) {
2869 int rIndex = count - index;
2870 indexItem.set(toAst<ReversedIndex_t>('#' + (rIndex == 0 ? Empty : "-"s + std::to_string(rIndex)), pair));
2871 } else {
2872 indexItem.set(toAst<Exp_t>(std::to_string(index), pair));
2873 }
2856 if (optional && varDefOnly && !assignable) { 2874 if (optional && varDefOnly && !assignable) {
2857 if (defVal) { 2875 if (defVal) {
2858 throw CompileError("default value is not supported here"sv, defVal); 2876 throw CompileError("default value is not supported here"sv, defVal);
2859 } 2877 }
2860 auto exp = static_cast<Exp_t*>(pair); 2878 auto exp = static_cast<Exp_t*>(pair);
2861 auto chain = exp->new_ptr<ChainValue_t>(); 2879 auto chain = exp->new_ptr<ChainValue_t>();
2862 auto indexItem = toAst<Exp_t>(std::to_string(index), exp);
2863 chain->items.push_back(indexItem); 2880 chain->items.push_back(indexItem);
2864 pairs.push_back({exp, Empty, chain, nullptr}); 2881 pairs.push_back({exp, Empty, chain, nullptr});
2865 break; 2882 break;
@@ -2874,7 +2891,6 @@ private:
2874 throw CompileError("default value is not supported here"sv, defVal); 2891 throw CompileError("default value is not supported here"sv, defVal);
2875 } 2892 }
2876 } 2893 }
2877 auto indexItem = toAst<Exp_t>(std::to_string(index), value);
2878 for (auto& p : subPairs) { 2894 for (auto& p : subPairs) {
2879 if (sep) p.structure->items.push_front(sep); 2895 if (sep) p.structure->items.push_front(sep);
2880 p.structure->items.push_front(indexItem); 2896 p.structure->items.push_front(indexItem);
@@ -2885,7 +2901,6 @@ private:
2885 auto varName = singleVariableFrom(exp, AccessType::None); 2901 auto varName = singleVariableFrom(exp, AccessType::None);
2886 if (varName == "_"sv) break; 2902 if (varName == "_"sv) break;
2887 auto chain = exp->new_ptr<ChainValue_t>(); 2903 auto chain = exp->new_ptr<ChainValue_t>();
2888 auto indexItem = toAst<Exp_t>(std::to_string(index), exp);
2889 chain->items.push_back(indexItem); 2904 chain->items.push_back(indexItem);
2890 pairs.push_back({exp, 2905 pairs.push_back({exp,
2891 varName, 2906 varName,
@@ -3010,7 +3025,13 @@ private:
3010 auto tb = static_cast<TableBlockIndent_t*>(pair); 3025 auto tb = static_cast<TableBlockIndent_t*>(pair);
3011 ++index; 3026 ++index;
3012 auto subPairs = destructFromExp(tb, varDefOnly, optional); 3027 auto subPairs = destructFromExp(tb, varDefOnly, optional);
3013 auto indexItem = toAst<Exp_t>(std::to_string(index), tb); 3028 ast_ptr<true, ast_node> indexItem;
3029 if (hasSpread) {
3030 int rIndex = count - index;
3031 indexItem.set(toAst<ReversedIndex_t>('#' + (rIndex == 0 ? Empty : "-"s + std::to_string(rIndex)), tb));
3032 } else {
3033 indexItem.set(toAst<Exp_t>(std::to_string(index), tb));
3034 }
3014 for (auto& p : subPairs) { 3035 for (auto& p : subPairs) {
3015 if (sep) p.structure->items.push_front(sep); 3036 if (sep) p.structure->items.push_front(sep);
3016 p.structure->items.push_front(indexItem); 3037 p.structure->items.push_front(indexItem);
@@ -3067,6 +3088,42 @@ private:
3067 subMetaDestruct->values.push_back(newPairDef); 3088 subMetaDestruct->values.push_back(newPairDef);
3068 break; 3089 break;
3069 } 3090 }
3091 case id<SpreadListExp_t>():
3092 case id<SpreadExp_t>(): {
3093 ++index;
3094 if (hasSpread) {
3095 throw CompileError("duplicated spread expression"sv, pair);
3096 }
3097 hasSpread = true;
3098 for (auto item : *tableItems) {
3099 if (ast_is<
3100 SpreadListExp_t, SpreadExp_t,
3101 TableBlockIndent_t,
3102 Exp_t, NormalDef_t>(item)) {
3103 count++;
3104 }
3105 }
3106 Exp_t* exp = nullptr;
3107 if (auto se = ast_cast<SpreadExp_t>(pair)) {
3108 exp = se->exp.get();
3109 } else {
3110 exp = ast_to<SpreadListExp_t>(pair)->exp.get();
3111 }
3112 auto varName = singleVariableFrom(exp, AccessType::None);
3113 if (varName == "_"sv) break;
3114 int start = index;
3115 int stop = index - count - 1;
3116 auto chain = exp->new_ptr<ChainValue_t>();
3117 auto slice = toAst<Slice_t>(
3118 '[' + (start == 1 ? Empty : std::to_string(start)) + ',' + (stop == -1 ? Empty : std::to_string(stop)) + ']', exp);
3119 chain->items.push_back(slice);
3120 auto nil = toAst<Exp_t>("nil"sv, slice);
3121 pairs.push_back({exp,
3122 varName,
3123 chain,
3124 nil.get()});
3125 break;
3126 }
3070 default: YUEE("AST node mismatch", pair); break; 3127 default: YUEE("AST node mismatch", pair); break;
3071 } 3128 }
3072 } 3129 }
@@ -5706,6 +5763,45 @@ private:
5706 } 5763 }
5707 } 5764 }
5708 5765
5766 bool transformChainEndWithSlice(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) {
5767 auto x = chainList.front();
5768 if (ast_is<Slice_t>(chainList.back())) {
5769 auto comp = x->new_ptr<Comprehension_t>();
5770 {
5771 auto chainValue = x->new_ptr<ChainValue_t>();
5772 for (auto item : chainList) {
5773 chainValue->items.push_back(item);
5774 }
5775 auto itemVar = getUnusedName("_item_"sv);
5776 auto expCode = YueFormat{}.toString(chainValue);
5777 auto compCode = '[' + itemVar + " for "s + itemVar + " in *"s + expCode + ']';
5778 comp.set(toAst<Comprehension_t>(compCode, x));
5779 }
5780 switch (usage) {
5781 case ExpUsage::Assignment: {
5782 auto simpleValue = x->new_ptr<SimpleValue_t>();
5783 simpleValue->value.set(comp);
5784 auto exp = newExp(simpleValue, x);
5785 auto assignment = x->new_ptr<ExpListAssign_t>();
5786 assignment->expList.set(assignList);
5787 auto assign = x->new_ptr<Assign_t>();
5788 assign->values.push_back(exp);
5789 assignment->action.set(assign);
5790 transformAssignment(assignment, out);
5791 break;
5792 }
5793 case ExpUsage::Return:
5794 transformComprehension(comp, out, ExpUsage::Return);
5795 break;
5796 default:
5797 transformComprehension(comp, out, ExpUsage::Closure);
5798 break;
5799 }
5800 return true;
5801 }
5802 return false;
5803 }
5804
5709 bool transformChainEndWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) { 5805 bool transformChainEndWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) {
5710 auto x = chainList.front(); 5806 auto x = chainList.front();
5711 if (ast_is<ExistentialOp_t>(chainList.back())) { 5807 if (ast_is<ExistentialOp_t>(chainList.back())) {
@@ -6369,6 +6465,93 @@ private:
6369 } 6465 }
6370 return; 6466 return;
6371 } 6467 }
6468 break;
6469 }
6470 case id<ReversedIndex_t>(): {
6471 auto rIndex = static_cast<ReversedIndex_t*>(*it);
6472 auto current = it;
6473 auto prevChain = x->new_ptr<ChainValue_t>();
6474 for (auto i = chainList.begin(); i != current; ++i) {
6475 prevChain->items.push_back(*i);
6476 }
6477 auto var = singleVariableFrom(prevChain, AccessType::None);
6478 if (!var.empty() && isLocal(var)) {
6479 auto indexNode = toAst<Exp_t>('#' + var, rIndex);
6480 if (rIndex->modifier) {
6481 auto opValue = rIndex->new_ptr<ExpOpValue_t>();
6482 opValue->op.set(toAst<BinaryOperator_t>("-"sv, rIndex));
6483 opValue->pipeExprs.dup(rIndex->modifier->pipeExprs);
6484 indexNode->opValues.push_back(opValue);
6485 indexNode->opValues.dup(rIndex->modifier->opValues);
6486 indexNode->nilCoalesed.set(rIndex->modifier->nilCoalesed);
6487 }
6488 prevChain->items.push_back(indexNode);
6489 auto next = current;
6490 ++next;
6491 for (auto i = next; i != chainList.end(); ++i) {
6492 prevChain->items.push_back(*i);
6493 }
6494 if (usage == ExpUsage::Assignment) {
6495 auto assignment = x->new_ptr<ExpListAssign_t>();
6496 assignment->expList.set(assignList);
6497 auto assign = x->new_ptr<Assign_t>();
6498 assign->values.push_back(newExp(prevChain, x));
6499 assignment->action.set(assign);
6500 transformAssignment(assignment, out);
6501 return;
6502 }
6503 transformChainValue(prevChain, out, usage, assignList);
6504 return;
6505 } else {
6506 auto itemVar = getUnusedName("_item_"sv);
6507 auto asmt = assignmentFrom(toAst<Exp_t>(itemVar, x), newExp(prevChain, x), x);
6508 auto stmt1 = x->new_ptr<Statement_t>();
6509 stmt1->content.set(asmt);
6510 auto newChain = x->new_ptr<ChainValue_t>();
6511 newChain->items.push_back(toAst<Callable_t>(itemVar, x));
6512 auto indexNode = toAst<Exp_t>('#' + itemVar, rIndex);
6513 if (rIndex->modifier) {
6514 auto opValue = rIndex->new_ptr<ExpOpValue_t>();
6515 opValue->op.set(toAst<BinaryOperator_t>("-"sv, rIndex));
6516 opValue->pipeExprs.dup(rIndex->modifier->pipeExprs);
6517 indexNode->opValues.push_back(opValue);
6518 indexNode->opValues.dup(rIndex->modifier->opValues);
6519 indexNode->nilCoalesed.set(rIndex->modifier->nilCoalesed);
6520 }
6521 newChain->items.push_back(indexNode);
6522 auto next = current;
6523 ++next;
6524 for (auto i = next; i != chainList.end(); ++i) {
6525 newChain->items.push_back(*i);
6526 }
6527 auto expList = x->new_ptr<ExpList_t>();
6528 expList->exprs.push_back(newExp(newChain, x));
6529 auto expListAssign = x->new_ptr<ExpListAssign_t>();
6530 expListAssign->expList.set(expList);
6531 auto stmt2 = x->new_ptr<Statement_t>();
6532 stmt2->content.set(expListAssign);
6533 auto block = x->new_ptr<Block_t>();
6534 block->statements.push_back(stmt1);
6535 block->statements.push_back(stmt2);
6536 auto body = x->new_ptr<Body_t>();
6537 body->content.set(block);
6538 auto doNode = x->new_ptr<Do_t>();
6539 doNode->body.set(body);
6540 if (usage == ExpUsage::Assignment) {
6541 auto assignment = x->new_ptr<ExpListAssign_t>();
6542 assignment->expList.set(assignList);
6543 auto assign = x->new_ptr<Assign_t>();
6544 auto sVal = x->new_ptr<SimpleValue_t>();
6545 sVal->value.set(doNode);
6546 assign->values.push_back(newExp(sVal, x));
6547 assignment->action.set(assign);
6548 transformAssignment(assignment, out);
6549 return;
6550 }
6551 transformDo(doNode, out, usage);
6552 return;
6553 }
6554 break;
6372 } 6555 }
6373 } 6556 }
6374 } 6557 }
@@ -6887,6 +7070,9 @@ private:
6887 if (transformChainEndWithColonItem(chainList, out, usage, assignList)) { 7070 if (transformChainEndWithColonItem(chainList, out, usage, assignList)) {
6888 return; 7071 return;
6889 } 7072 }
7073 if (transformChainEndWithSlice(chainList, out, usage, assignList)) {
7074 return;
7075 }
6890 transformChainList(chainList, out, usage, assignList); 7076 transformChainList(chainList, out, usage, assignList);
6891 } 7077 }
6892 7078
@@ -8107,7 +8293,7 @@ private:
8107 if (stopValue.empty()) { 8293 if (stopValue.empty()) {
8108 _buf << "#"sv << listVar; 8294 _buf << "#"sv << listVar;
8109 } else { 8295 } else {
8110 _buf << maxVar << " < 0 and #"sv << listVar << " + "sv << maxVar << " or "sv << maxVar; 8296 _buf << maxVar << " < 0 and #"sv << listVar << " + "sv << maxVar << " + 1 or "sv << maxVar;
8111 } 8297 }
8112 if (!stepValue.empty()) { 8298 if (!stepValue.empty()) {
8113 _buf << ", "sv << stepValue; 8299 _buf << ", "sv << stepValue;
@@ -10059,24 +10245,24 @@ private:
10059 str_list rets; 10245 str_list rets;
10060 pushScope(); 10246 pushScope();
10061 auto okVar = getUnusedName("_ok_"sv); 10247 auto okVar = getUnusedName("_ok_"sv);
10062 for (size_t i = 0; i < assignList->exprs.size(); i++) { 10248 for (size_t i = 0; i < assignList->exprs.size(); i++) {
10063 auto retVar = getUnusedName("_ret_"sv); 10249 auto retVar = getUnusedName("_ret_"sv);
10064 rets.emplace_back(retVar); 10250 rets.emplace_back(retVar);
10065 addToScope(retVar); 10251 addToScope(retVar);
10066 } 10252 }
10067 popScope(); 10253 popScope();
10068 auto varList = join(rets, ","sv); 10254 auto varList = join(rets, ","sv);
10069 auto ifNode = toAst<If_t>("if "s + okVar + ',' + varList + ":=try nil then "s + varList, x); 10255 auto ifNode = toAst<If_t>("if "s + okVar + ',' + varList + ":=try nil then "s + varList, x);
10070 auto exp = ast_to<IfCond_t>(ifNode->nodes.front())->assignment->assign->values.front(); 10256 auto exp = ast_to<IfCond_t>(ifNode->nodes.front())->assignment->assign->values.front();
10071 auto sVal = simpleSingleValueFrom(exp); 10257 auto sVal = simpleSingleValueFrom(exp);
10072 auto newTry = sVal->value.to<Try_t>(); 10258 auto newTry = sVal->value.to<Try_t>();
10073 newTry->func.set(tryNode->func); 10259 newTry->func.set(tryNode->func);
10074 newTry->catchBlock.set(tryNode->catchBlock); 10260 newTry->catchBlock.set(tryNode->catchBlock);
10075 auto assignment = x->new_ptr<ExpListAssign_t>(); 10261 auto assignment = x->new_ptr<ExpListAssign_t>();
10076 assignment->expList.set(assignList); 10262 assignment->expList.set(assignList);
10077 auto assign = x->new_ptr<Assign_t>(); 10263 auto assign = x->new_ptr<Assign_t>();
10078 assign->values.push_back(ifNode); 10264 assign->values.push_back(ifNode);
10079 assignment->action.set(assign); 10265 assignment->action.set(assign);
10080 transformAssignment(assignment, out); 10266 transformAssignment(assignment, out);
10081 return; 10267 return;
10082 } 10268 }
@@ -10084,12 +10270,12 @@ private:
10084 auto okVar = getUnusedName("_ok_"sv); 10270 auto okVar = getUnusedName("_ok_"sv);
10085 auto code = "do\n\t"s + okVar + ", ... = try nil\n\t... if "s + okVar; 10271 auto code = "do\n\t"s + okVar + ", ... = try nil\n\t... if "s + okVar;
10086 auto doNode = toAst<Do_t>(code, x); 10272 auto doNode = toAst<Do_t>(code, x);
10087 auto block = doNode->body->content.to<Block_t>(); 10273 auto block = doNode->body->content.to<Block_t>();
10088 auto asmt = static_cast<Statement_t*>(block->statements.front())->content.to<ExpListAssign_t>(); 10274 auto asmt = static_cast<Statement_t*>(block->statements.front())->content.to<ExpListAssign_t>();
10089 auto assign = asmt->action.to<Assign_t>(); 10275 auto assign = asmt->action.to<Assign_t>();
10090 auto sVal = simpleSingleValueFrom(assign->values.back()); 10276 auto sVal = simpleSingleValueFrom(assign->values.back());
10091 auto newTry = sVal->value.to<Try_t>(); 10277 auto newTry = sVal->value.to<Try_t>();
10092 newTry->func.set(tryNode->func); 10278 newTry->func.set(tryNode->func);
10093 newTry->catchBlock.set(tryNode->catchBlock); 10279 newTry->catchBlock.set(tryNode->catchBlock);
10094 transformDo(doNode, out, usage); 10280 transformDo(doNode, out, usage);
10095 return; 10281 return;
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp
index e860d55..1011a49 100644
--- a/src/yuescript/yue_parser.cpp
+++ b/src/yuescript/yue_parser.cpp
@@ -709,7 +709,8 @@ YueParser::YueParser() {
709 chain_with_colon = +chain_item >> -colon_chain; 709 chain_with_colon = +chain_item >> -colon_chain;
710 chain_items = chain_with_colon | colon_chain; 710 chain_items = chain_with_colon | colon_chain;
711 711
712 index = '[' >> not_('[') >> space >> Exp >> space >> ']'; 712 index = '[' >> not_('[') >> space >> (ReversedIndex >> and_(space >> ']') | Exp) >> space >> ']';
713 ReversedIndex = '#' >> space >> -('-' >> space >> Exp);
713 chain_item = 714 chain_item =
714 Invoke >> -ExistentialOp | 715 Invoke >> -ExistentialOp |
715 DotChainItem >> -ExistentialOp | 716 DotChainItem >> -ExistentialOp |
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h
index 0d9db19..1057626 100644
--- a/src/yuescript/yue_parser.h
+++ b/src/yuescript/yue_parser.h
@@ -365,6 +365,7 @@ private:
365 AST_RULE(ExpOpValue); 365 AST_RULE(ExpOpValue);
366 AST_RULE(Exp); 366 AST_RULE(Exp);
367 AST_RULE(Callable); 367 AST_RULE(Callable);
368 AST_RULE(ReversedIndex);
368 AST_RULE(ChainValue); 369 AST_RULE(ChainValue);
369 AST_RULE(SimpleTable); 370 AST_RULE(SimpleTable);
370 AST_RULE(SimpleValue); 371 AST_RULE(SimpleValue);