diff options
| author | Li Jin <dragon-fly@qq.com> | 2025-06-04 11:38:34 +0800 |
|---|---|---|
| committer | Li Jin <dragon-fly@qq.com> | 2025-06-04 11:38:34 +0800 |
| commit | 548ab1d9ff5b831050f14f1355a3314a41163ad6 (patch) | |
| tree | d84b6b64b4e547070c7c43db53821b83b819ab8e | |
| parent | 98be64dd52df92f7fdd40bae225c279db1676cab (diff) | |
| download | yuescript-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.yue | 38 | ||||
| -rw-r--r-- | spec/inputs/lists.yue | 47 | ||||
| -rw-r--r-- | spec/inputs/switch.yue | 17 | ||||
| -rw-r--r-- | spec/outputs/codes_from_doc.lua | 8 | ||||
| -rw-r--r-- | spec/outputs/codes_from_doc_zh.lua | 8 | ||||
| -rw-r--r-- | spec/outputs/comprehension.lua | 4 | ||||
| -rw-r--r-- | spec/outputs/destructure.lua | 90 | ||||
| -rw-r--r-- | spec/outputs/lists.lua | 192 | ||||
| -rw-r--r-- | spec/outputs/switch.lua | 50 | ||||
| -rw-r--r-- | spec/outputs/unicode/comprehension.lua | 4 | ||||
| -rw-r--r-- | spec/outputs/unicode/lists.lua | 6 | ||||
| -rw-r--r-- | src/yuescript/yue_ast.cpp | 6 | ||||
| -rw-r--r-- | src/yuescript/yue_ast.h | 7 | ||||
| -rw-r--r-- | src/yuescript/yue_compiler.cpp | 248 | ||||
| -rw-r--r-- | src/yuescript/yue_parser.cpp | 3 | ||||
| -rw-r--r-- | src/yuescript/yue_parser.h | 1 |
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 | |||
| 244 | do | ||
| 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 | |||
| 251 | do | ||
| 252 | setupMeeting = (participants) -> | ||
| 253 | [chair, ..._, secretary] = participants | ||
| 254 | print chair, secretary | ||
| 255 | |||
| 256 | setupMeeting ["Alice", "Bob", "Charlie", "David"] | ||
| 257 | -- Output: Alice David | ||
| 258 | |||
| 259 | do | ||
| 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 | |||
| 271 | do | ||
| 272 | [ | ||
| 273 | _ | ||
| 274 | ...middle | ||
| 275 | _ | ||
| 276 | ] = tb | ||
| 277 | |||
| 278 | do | ||
| 279 | {a, :abc, b, :def, ...sub, d, e} = tb | ||
| 280 | |||
| 243 | nil | 281 | nil |
| 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 | ||
| 90 | do | ||
| 91 | transactions = ["T001", "T002", "T003", "T004", "T005"] | ||
| 92 | middleTransactions = transactions[2, -2] | ||
| 93 | print middleTransactions -- => {"T002", "T003", "T004"} | ||
| 94 | |||
| 95 | do | ||
| 96 | logs = | ||
| 97 | - start: 0, end: 100 | ||
| 98 | - start: 100, end: 200 | ||
| 99 | - start: 200, end: 123 | ||
| 100 | print logs[#].end -- => 123 | ||
| 101 | |||
| 102 | do | ||
| 103 | pendingOrders = ["O001", "O002", "O003", "O004"] | ||
| 104 | print pendingOrders[# - 1] -- => "O003" | ||
| 105 | |||
| 106 | do | ||
| 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 | |||
| 117 | do | ||
| 118 | cloneList1 = (list) -> list[,] | ||
| 119 | cloneList2 = (list) -> [...list,] | ||
| 120 | cloneTable = (tb) -> {...tb} | ||
| 121 | |||
| 122 | do | ||
| 123 | print( | ||
| 124 | globalTB[#] | ||
| 125 | a.b.c[# - 2] | ||
| 126 | x?\y?!.z?[# - 3] | ||
| 127 | ) | ||
| 128 | |||
| 129 | do | ||
| 130 | f = -> | ||
| 131 | print( | ||
| 132 | globalTB[#]\end 123 | ||
| 133 | a.b.c[5,-5][# - 2] | ||
| 134 | x?\y?!.z?[# - 3]?[, -3] | ||
| 135 | ) | ||
| 136 | |||
| 90 | nil | 137 | nil |
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 | ||
| 275 | do | ||
| 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 | |||
| 283 | do | ||
| 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 | |||
| 275 | nil | 292 | nil |
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 = { } | |||
| 1063 | local _len_0 = 1 | 1063 | local _len_0 = 1 |
| 1064 | local _list_0 = items | 1064 | local _list_0 = items |
| 1065 | local _max_0 = 5 | 1065 | local _max_0 = 5 |
| 1066 | for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do | 1066 | for _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 | |||
| 1100 | end | 1100 | end |
| 1101 | local _list_0 = items | 1101 | local _list_0 = items |
| 1102 | local _max_0 = 4 | 1102 | local _max_0 = 4 |
| 1103 | for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do | 1103 | for _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) |
| 1106 | end | 1106 | end |
| @@ -3333,7 +3333,7 @@ local _accum_0 = { } | |||
| 3333 | local _len_0 = 1 | 3333 | local _len_0 = 1 |
| 3334 | local _list_0 = items | 3334 | local _list_0 = items |
| 3335 | local _max_0 = 5 | 3335 | local _max_0 = 5 |
| 3336 | for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do | 3336 | for _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 | |||
| 3370 | end | 3370 | end |
| 3371 | local _list_0 = items | 3371 | local _list_0 = items |
| 3372 | local _max_0 = 4 | 3372 | local _max_0 = 4 |
| 3373 | for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do | 3373 | for _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) |
| 3376 | end | 3376 | end |
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 = { } | |||
| 1057 | local _len_0 = 1 | 1057 | local _len_0 = 1 |
| 1058 | local _list_0 = items | 1058 | local _list_0 = items |
| 1059 | local _max_0 = 5 | 1059 | local _max_0 = 5 |
| 1060 | for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do | 1060 | for _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 | |||
| 1094 | end | 1094 | end |
| 1095 | local _list_0 = items | 1095 | local _list_0 = items |
| 1096 | local _max_0 = 4 | 1096 | local _max_0 = 4 |
| 1097 | for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do | 1097 | for _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) |
| 1100 | end | 1100 | end |
| @@ -3321,7 +3321,7 @@ local _accum_0 = { } | |||
| 3321 | local _len_0 = 1 | 3321 | local _len_0 = 1 |
| 3322 | local _list_0 = items | 3322 | local _list_0 = items |
| 3323 | local _max_0 = 5 | 3323 | local _max_0 = 5 |
| 3324 | for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do | 3324 | for _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 | |||
| 3358 | end | 3358 | end |
| 3359 | local _list_0 = items | 3359 | local _list_0 = items |
| 3360 | local _max_0 = 4 | 3360 | local _max_0 = 4 |
| 3361 | for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do | 3361 | for _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) |
| 3364 | end | 3364 | end |
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 |
| 623 | end | 623 | end |
| 624 | do | ||
| 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) | ||
| 645 | end | ||
| 646 | do | ||
| 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 | }) | ||
| 658 | end | ||
| 659 | do | ||
| 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) | ||
| 685 | end | ||
| 686 | do | ||
| 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 | ||
| 698 | end | ||
| 699 | do | ||
| 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] | ||
| 713 | end | ||
| 624 | return nil | 714 | return 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 | } |
| 233 | local _max_0 = -5 | 233 | local _max_0 = -5 |
| 234 | for _index_0 = 2, _max_0 < 0 and #x + _max_0 or _max_0, 2 do | 234 | for _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) |
| 237 | end | 237 | end |
| 238 | local _max_1 = 3 | 238 | local _max_1 = 3 |
| 239 | for _index_0 = 1, _max_1 < 0 and #x + _max_1 or _max_1 do | 239 | for _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) |
| 242 | end | 242 | end |
| @@ -254,7 +254,7 @@ for _index_0 = 2, #x, 2 do | |||
| 254 | end | 254 | end |
| 255 | local a, b, c = 1, 5, 2 | 255 | local a, b, c = 1, 5, 2 |
| 256 | local _max_2 = b | 256 | local _max_2 = b |
| 257 | for _index_0 = a, _max_2 < 0 and #x + _max_2 or _max_2, c do | 257 | for _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) |
| 260 | end | 260 | end |
| @@ -327,4 +327,190 @@ do | |||
| 327 | job = "jobless" | 327 | job = "jobless" |
| 328 | end | 328 | end |
| 329 | end | 329 | end |
| 330 | do | ||
| 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) | ||
| 351 | end | ||
| 352 | do | ||
| 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"]) | ||
| 368 | end | ||
| 369 | do | ||
| 370 | local pendingOrders = { | ||
| 371 | "O001", | ||
| 372 | "O002", | ||
| 373 | "O003", | ||
| 374 | "O004" | ||
| 375 | } | ||
| 376 | print(pendingOrders[#pendingOrders - 1]) | ||
| 377 | end | ||
| 378 | do | ||
| 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") | ||
| 402 | end | ||
| 403 | do | ||
| 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 | ||
| 440 | end | ||
| 441 | do | ||
| 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)()) | ||
| 462 | end | ||
| 463 | local _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) | ||
| 467 | end | ||
| 468 | local _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] | ||
| 483 | end | ||
| 484 | local _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 | ||
| 509 | end | ||
| 510 | do | ||
| 511 | local f | ||
| 512 | f = function() | ||
| 513 | return print(_anon_func_0(globalTB), _anon_func_1(a), _anon_func_2(x)) | ||
| 514 | end | ||
| 515 | end | ||
| 330 | return nil | 516 | return 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 |
| 729 | end | 729 | end |
| 730 | do | ||
| 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 | ||
| 759 | end | ||
| 760 | do | ||
| 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 | }) | ||
| 779 | end | ||
| 730 | return nil | 780 | return 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 | } |
| 232 | local _max_0 = -5 | 232 | local _max_0 = -5 |
| 233 | for _index_0 = 2, _max_0 < 0 and #_u53d8_u91cfx + _max_0 or _max_0, 2 do | 233 | for _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) |
| 236 | end | 236 | end |
| 237 | local _max_1 = 3 | 237 | local _max_1 = 3 |
| 238 | for _index_0 = 1, _max_1 < 0 and #_u53d8_u91cfx + _max_1 or _max_1 do | 238 | for _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) |
| 241 | end | 241 | end |
| @@ -253,7 +253,7 @@ for _index_0 = 2, #_u53d8_u91cfx, 2 do | |||
| 253 | end | 253 | end |
| 254 | local _u53d8_u91cfa, _u53d8_u91cfb, _u53d8_u91cfc = 1, 5, 2 | 254 | local _u53d8_u91cfa, _u53d8_u91cfb, _u53d8_u91cfc = 1, 5, 2 |
| 255 | local _max_2 = _u53d8_u91cfb | 255 | local _max_2 = _u53d8_u91cfb |
| 256 | for _index_0 = _u53d8_u91cfa, _max_2 < 0 and #_u53d8_u91cfx + _max_2 or _max_2, _u53d8_u91cfc do | 256 | for _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) |
| 259 | end | 259 | end |
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 | } |
| 873 | std::string ReversedIndex_t::to_string(void* ud) const { | ||
| 874 | if (modifier) { | ||
| 875 | return "[# - "s + modifier->to_string(ud) + ']'; | ||
| 876 | } | ||
| 877 | return "[#]"s; | ||
| 878 | } | ||
| 873 | std::string Callable_t::to_string(void* ud) const { | 879 | std::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) | |||
| 643 | AST_LEAF(PlainItem) | 643 | AST_LEAF(PlainItem) |
| 644 | AST_END(PlainItem) | 644 | AST_END(PlainItem) |
| 645 | 645 | ||
| 646 | AST_NODE(ReversedIndex) | ||
| 647 | ast_ptr<false, Exp_t> modifier; | ||
| 648 | AST_MEMBER(ReversedIndex, &modifier) | ||
| 649 | AST_END(ReversedIndex) | ||
| 650 | |||
| 646 | AST_NODE(ChainValue) | 651 | AST_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) |
| 651 | AST_END(ChainValue) | 656 | AST_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 | ||
| 81 | const std::string_view version = "0.28.7"sv; | 81 | const std::string_view version = "0.29.0"sv; |
| 82 | const std::string_view extension = "yue"sv; | 82 | const std::string_view extension = "yue"sv; |
| 83 | 83 | ||
| 84 | class CompileError : public std::logic_error { | 84 | class 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); |
