aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to '')
-rwxr-xr-xdoc/docs/.vuepress/components/YueCompiler.vue83
-rwxr-xr-xdoc/docs/doc/README.md657
-rwxr-xr-xdoc/docs/zh/doc/README.md685
-rw-r--r--makefile2
-rw-r--r--spec/inputs/backcall.yue4
-rw-r--r--spec/inputs/destructure.yue40
-rw-r--r--spec/inputs/funcs.yue31
-rw-r--r--spec/inputs/global.yue6
-rw-r--r--spec/inputs/import.yue10
-rw-r--r--spec/inputs/lists.yue47
-rw-r--r--spec/inputs/loops.yue52
-rw-r--r--spec/inputs/macro.yue54
-rw-r--r--spec/inputs/macro_export.yue31
-rw-r--r--spec/inputs/macro_teal.yue13
-rw-r--r--spec/inputs/macro_todo.yue7
-rw-r--r--spec/inputs/props.yue61
-rw-r--r--spec/inputs/string.yue73
-rw-r--r--spec/inputs/switch.yue125
-rw-r--r--spec/inputs/tables.yue18
-rw-r--r--spec/inputs/try_catch.yue122
-rw-r--r--spec/inputs/unicode/destructure.yue2
-rw-r--r--spec/inputs/unicode/macro_export.yue4
-rw-r--r--spec/inputs/unicode/with.yue24
-rw-r--r--spec/inputs/with.yue42
-rw-r--r--spec/outputs/5.1/literals.lua44
-rw-r--r--spec/outputs/5.1/loops.lua132
-rw-r--r--spec/outputs/5.1/try_catch.lua265
-rw-r--r--spec/outputs/assign.lua6
-rw-r--r--spec/outputs/codes_from_doc.lua928
-rw-r--r--spec/outputs/codes_from_doc_zh.lua928
-rw-r--r--spec/outputs/comprehension.lua10
-rw-r--r--spec/outputs/destructure.lua90
-rw-r--r--spec/outputs/funcs.lua153
-rw-r--r--spec/outputs/global.lua25
-rw-r--r--spec/outputs/import.lua10
-rw-r--r--spec/outputs/lists.lua215
-rw-r--r--spec/outputs/loops.lua132
-rw-r--r--spec/outputs/macro.lua15
-rw-r--r--spec/outputs/props.lua240
-rw-r--r--spec/outputs/string.lua41
-rw-r--r--spec/outputs/switch.lua362
-rw-r--r--spec/outputs/tables.lua22
-rw-r--r--spec/outputs/try_catch.lua266
-rw-r--r--spec/outputs/unicode/assign.lua6
-rw-r--r--spec/outputs/unicode/comprehension.lua10
-rw-r--r--spec/outputs/unicode/lists.lua23
-rw-r--r--spec/outputs/unicode/loops.lua4
-rw-r--r--spec/outputs/unicode/macro.lua48
-rw-r--r--spec/outputs/unicode/multiline_chain.lua6
-rw-r--r--spec/outputs/unicode/syntax.lua6
-rw-r--r--spec/outputs/unicode/vararg.lua28
-rw-r--r--spec/outputs/upvalue_func.lua48
-rw-r--r--spec/outputs/vararg.lua28
-rw-r--r--spec/outputs/with.lua62
-rw-r--r--src/3rdParty/efsw/FileWatcherGeneric.cpp2
-rw-r--r--src/yuescript/yue_ast.cpp201
-rw-r--r--src/yuescript/yue_ast.h102
-rw-r--r--src/yuescript/yue_compiler.cpp1260
-rw-r--r--src/yuescript/yue_compiler.h1
-rw-r--r--src/yuescript/yue_parser.cpp162
-rw-r--r--src/yuescript/yue_parser.h36
-rw-r--r--src/yuescript/yuescript.cpp16
-rw-r--r--win-build/Yuescript/Yuescript.vcxproj4
63 files changed, 7374 insertions, 756 deletions
diff --git a/doc/docs/.vuepress/components/YueCompiler.vue b/doc/docs/.vuepress/components/YueCompiler.vue
index 6b6042c..3a22d1c 100755
--- a/doc/docs/.vuepress/components/YueCompiler.vue
+++ b/doc/docs/.vuepress/components/YueCompiler.vue
@@ -1,21 +1,21 @@
1<template> 1<template>
2 <div style="width: 100%; height: auto;"> 2 <div style="width: 100%; height: auto;">
3 <div class="parent" style="background-color: #f5f7ff;"> 3 <div class="parent" style="background-color: #f5f7ff;">
4 <div class="childL" style="height: 2.5em;"> 4 <div class="editor-section">
5 <div class="childTitle">YueScript {{ info }}</div> 5 <div class="childTitle">YueScript {{ info }}</div>
6 <div class="editor-container" ref='yueEditor'>
7 <ClientOnly>
8 <prism-editor class="my-editor" v-model="code" :highlight="highlighterYue" @input="codeChanged($event)" line-numbers :readonly="readonly"></prism-editor>
9 </ClientOnly>
10 </div>
6 </div> 11 </div>
7 <div class="childR" style="height: 2.5em;"> 12 <div class="editor-section">
8 <div class="childTitle">Lua</div> 13 <div class="childTitle">Lua</div>
9 </div> 14 <div class="editor-container">
10 <div class="childL" ref='yueEditor' style="height: 30em;"> 15 <ClientOnly>
11 <ClientOnly> 16 <prism-editor class="my-editor" v-model="compiled" :highlight="highlighterLua" @input="codeChanged($event)" :line-numbers="isMobileLayout" readonly></prism-editor>
12 <prism-editor class="my-editor" v-model="code" :highlight="highlighterYue" @input="codeChanged($event)" line-numbers :readonly="readonly"></prism-editor> 17 </ClientOnly>
13 </ClientOnly> 18 </div>
14 </div>
15 <div class="childR" style="height: 30em;">
16 <ClientOnly>
17 <prism-editor class="my-editor" v-model="compiled" :highlight="highlighterLua" @input="codeChanged($event)" readonly></prism-editor>
18 </ClientOnly>
19 </div> 19 </div>
20 </div> 20 </div>
21 <div v-if="!compileronly"> 21 <div v-if="!compileronly">
@@ -57,9 +57,18 @@
57 code: '', 57 code: '',
58 compiled: '', 58 compiled: '',
59 result: '', 59 result: '',
60 windowWidth: 0,
60 }; 61 };
61 }, 62 },
63 computed: {
64 isMobileLayout() {
65 return this.windowWidth <= 768;
66 },
67 },
62 mounted () { 68 mounted () {
69 this.windowWidth = window.innerWidth;
70 window.addEventListener('resize', this.handleResize);
71
63 if (this.text !== '') { 72 if (this.text !== '') {
64 this.$data.code = this.text; 73 this.$data.code = this.text;
65 this.codeChanged(this.text); 74 this.codeChanged(this.text);
@@ -86,7 +95,13 @@
86 })(this); 95 })(this);
87 check(); 96 check();
88 }, 97 },
98 beforeDestroy() {
99 window.removeEventListener('resize', this.handleResize);
100 },
89 methods: { 101 methods: {
102 handleResize() {
103 this.windowWidth = window.innerWidth;
104 },
90 runCode() { 105 runCode() {
91 if (window.yue && this.$data.compiled !== '') { 106 if (window.yue && this.$data.compiled !== '') {
92 let res = ''; 107 let res = '';
@@ -136,27 +151,35 @@
136 resize: none; 151 resize: none;
137 margin-top: 5px; 152 margin-top: 5px;
138 } 153 }
139 .childL { 154
140 float: left; 155 .parent {
141 width: 50%; 156 display: flex;
142 box-sizing: border-box; 157 flex-wrap: wrap;
143 background-clip: content-box; 158 width: 100%;
144 background: #f5f7ff;
145 } 159 }
146 .childR { 160
147 float: left; 161 .editor-section {
148 width: 50%; 162 width: 50%;
149 box-sizing: border-box; 163 box-sizing: border-box;
150 background-clip: content-box;
151 background: #f5f7ff; 164 background: #f5f7ff;
152 } 165 }
166
167 .editor-container {
168 height: 55vh;
169 }
170
153 .childTitle { 171 .childTitle {
154 width: 100%; 172 width: 100%;
155 font-size: 1.2em; 173 font-size: 1.2em;
156 color: #b7ae8f; 174 color: #b7ae8f;
157 text-align: center; 175 text-align: center;
158 padding: 0.2em; 176 padding: 0.2em;
177 height: 2.5em;
178 display: flex;
179 align-items: center;
180 justify-content: center;
159 } 181 }
182
160 .button { 183 .button {
161 float: right; 184 float: right;
162 border: none; 185 border: none;
@@ -173,9 +196,11 @@
173 margin-top: 10px; 196 margin-top: 10px;
174 margin-right: 5px; 197 margin-right: 5px;
175 } 198 }
199
176 .button:hover { 200 .button:hover {
177 background-color: #beb69a; 201 background-color: #beb69a;
178 } 202 }
203
179 .button:focus, 204 .button:focus,
180 .button:active:focus, 205 .button:active:focus,
181 .button.active:focus, 206 .button.active:focus,
@@ -207,5 +232,19 @@
207 .my-editor >>> .prism-editor__textarea:focus { 232 .my-editor >>> .prism-editor__textarea:focus {
208 outline: none; 233 outline: none;
209 } 234 }
210</style>
211 235
236 /* 移动端å“应å¼å¸ƒå±€ */
237 @media screen and (max-width: 768px) {
238 .parent {
239 flex-direction: column;
240 }
241
242 .editor-section {
243 width: 100%;
244 }
245
246 .editor-container {
247 height: 30vh;
248 }
249 }
250</style>
diff --git a/doc/docs/doc/README.md b/doc/docs/doc/README.md
index c4518bf..57f27c8 100755
--- a/doc/docs/doc/README.md
+++ b/doc/docs/doc/README.md
@@ -16,19 +16,29 @@ Yue (月) is the name of moon in Chinese and it's pronounced as [jyɛ].
16### An Overview of YueScript 16### An Overview of YueScript
17```moonscript 17```moonscript
18-- import syntax 18-- import syntax
19import "yue" as :p, :to_lua 19import p, to_lua from "yue"
20 20
21-- object literals 21-- object literals
22inventory = 22inventory =
23 equipment: 23 equipment:
24 * "sword" 24 - "sword"
25 * "shield" 25 - "shield"
26 items: 26 items:
27 * name: "potion" 27 - name: "potion"
28 count: 10 28 count: 10
29 * name: "bread" 29 - name: "bread"
30 count: 3 30 count: 3
31 31
32-- list comprehension
33map = (arr, action) ->
34 [action item for item in *arr]
35
36filter = (arr, cond) ->
37 [item for item in *arr when cond item]
38
39reduce = (arr, init, action): init ->
40 init = action init, item for item in *arr
41
32-- pipe operator 42-- pipe operator
33[1, 2, 3] 43[1, 2, 3]
34 |> map (x) -> x * 2 44 |> map (x) -> x * 2
@@ -51,19 +61,29 @@ export 🌛 = "月之脚本"
51<YueDisplay> 61<YueDisplay>
52<pre> 62<pre>
53-- import syntax 63-- import syntax
54import "yue" as :p, :to_lua 64import p, to_lua from "yue"
55 65
56-- object literals 66-- object literals
57inventory = 67inventory =
58 equipment: 68 equipment:
59 * "sword" 69 - "sword"
60 * "shield" 70 - "shield"
61 items: 71 items:
62 * name: "potion" 72 - name: "potion"
63 count: 10 73 count: 10
64 * name: "bread" 74 - name: "bread"
65 count: 3 75 count: 3
66 76
77-- list comprehension
78map = (arr, action) ->
79 [action item for item in *arr]
80
81filter = (arr, cond) ->
82 [item for item in *arr when cond item]
83
84reduce = (arr, init, action): init ->
85 init = action init, item for item in *arr
86
67-- pipe operator 87-- pipe operator
68[1, 2, 3] 88[1, 2, 3]
69 |> map (x) -> x * 2 89 |> map (x) -> x * 2
@@ -132,14 +152,14 @@ export 🌛 = "月之脚本"
132 152
133&emsp;Use YueScript module in Lua: 153&emsp;Use YueScript module in Lua:
134 154
135* **Case 1** 155* **Case 1**
136Require "your_yuescript_entry.yue" in Lua. 156Require "your_yuescript_entry.yue" in Lua.
137```Lua 157```Lua
138require("yue")("your_yuescript_entry") 158require("yue")("your_yuescript_entry")
139``` 159```
140&emsp;And this code still works when you compile "your_yuescript_entry.yue" to "your_yuescript_entry.lua" in the same path. In the rest YueScript files just use the normal **require** or **import**. The code line numbers in error messages will also be handled correctly. 160&emsp;And this code still works when you compile "your_yuescript_entry.yue" to "your_yuescript_entry.lua" in the same path. In the rest YueScript files just use the normal **require** or **import**. The code line numbers in error messages will also be handled correctly.
141 161
142* **Case 2** 162* **Case 2**
143Require YueScript module and rewite message by hand. 163Require YueScript module and rewite message by hand.
144```lua 164```lua
145local yue = require("yue") 165local yue = require("yue")
@@ -151,7 +171,7 @@ end, function(err)
151end) 171end)
152``` 172```
153 173
154* **Case 3** 174* **Case 3**
155Use the YueScript compiler function in Lua. 175Use the YueScript compiler function in Lua.
156```lua 176```lua
157local yue = require("yue") 177local yue = require("yue")
@@ -203,12 +223,12 @@ Usage: yue [options|files|directories] ...
203 Execute without options to enter REPL, type symbol '$' 223 Execute without options to enter REPL, type symbol '$'
204 in a single line to start/stop multi-line mode 224 in a single line to start/stop multi-line mode
205``` 225```
206&emsp;&emsp;Use cases: 226&emsp;&emsp;Use cases:
207&emsp;&emsp;Recursively compile every YueScript file with extension **.yue** under current path: **yue .** 227&emsp;&emsp;Recursively compile every YueScript file with extension **.yue** under current path: **yue .**
208&emsp;&emsp;Compile and save results to a target path: **yue -t /target/path/ .** 228&emsp;&emsp;Compile and save results to a target path: **yue -t /target/path/ .**
209&emsp;&emsp;Compile and reserve debug info: **yue -l .** 229&emsp;&emsp;Compile and reserve debug info: **yue -l .**
210&emsp;&emsp;Compile and generate minified codes: **yue -m .** 230&emsp;&emsp;Compile and generate minified codes: **yue -m .**
211&emsp;&emsp;Execute raw codes: **yue -e 'print 123'** 231&emsp;&emsp;Execute raw codes: **yue -e 'print 123'**
212&emsp;&emsp;Execute a YueScript file: **yue -e main.yue** 232&emsp;&emsp;Execute a YueScript file: **yue -e main.yue**
213 233
214## Macro 234## Macro
@@ -424,6 +444,54 @@ print "Valid enum type:", $BodyType Static
424</pre> 444</pre>
425</YueDisplay> 445</YueDisplay>
426 446
447### Argument Validation
448
449You can declare the expected AST node types in the argument list, and check whether the incoming macro arguments meet the expectations at compile time.
450
451```moonscript
452macro printNumAndStr = (num `Num, str `String) -> |
453 print(
454 #{num}
455 #{str}
456 )
457
458$printNumAndStr 123, "hello"
459```
460<YueDisplay>
461<pre>
462macro printNumAndStr = (num `Num, str `String) -> |
463 print(
464 #{num}
465 #{str}
466 )
467
468$printNumAndStr 123, "hello"
469</pre>
470</YueDisplay>
471
472If you need more flexible argument checking, you can use the built-in `$is_ast` macro function to manually check at the appropriate place.
473
474```moonscript
475macro printNumAndStr = (num, str) ->
476 error "expected Num as first argument" unless $is_ast Num, num
477 error "expected String as second argument" unless $is_ast String, str
478 "print(#{num}, #{str})"
479
480$printNumAndStr 123, "hello"
481```
482<YueDisplay>
483<pre>
484macro printNumAndStr = (num, str) ->
485 error "expected Num as first argument" unless $is_ast Num, num
486 error "expected String as second argument" unless $is_ast String, str
487 "print(#{num}, #{str})"
488
489$printNumAndStr 123, "hello"
490</pre>
491</YueDisplay>
492
493For more details about available AST nodes, please refer to the uppercased definitions in [yue_parser.cpp](https://github.com/IppClub/YueScript/blob/main/src/yuescript/yue_parser.cpp).
494
427## Operator 495## Operator
428 496
429All of Lua's binary and unary operators are available. Additionally **!=** is as an alias for **~=**, and either **\\** or **::** can be used to write a chaining function call like `tb\func!` or `tb::func!`. And Yuescipt offers some other special operators to write more expressive codes. 497All of Lua's binary and unary operators are available. Additionally **!=** is as an alias for **~=**, and either **\\** or **::** can be used to write a chaining function call like `tb\func!` or `tb::func!`. And Yuescipt offers some other special operators to write more expressive codes.
@@ -566,11 +634,26 @@ merge = {...a, ...b}
566</pre> 634</pre>
567</YueDisplay> 635</YueDisplay>
568 636
637### Table Reversed Indexing
638
639You can use the **#** operator to get the last elements of a table.
640
641```moonscript
642last = data.items[#]
643second_last = data.items[#-1]
644```
645<YueDisplay>
646<pre>
647last = data.items[#]
648second_last = data.items[#-1]
649</pre>
650</YueDisplay>
651
569### Metatable 652### Metatable
570 653
571The **<>** operator can be used as a shortcut for metatable manipulation. 654The **<>** operator can be used as a shortcut for metatable manipulation.
572 655
573* **Metatable Creation** 656* **Metatable Creation**
574Create normal table with empty bracekets **<>** or metamethod key which is surrounded by **<>**. 657Create normal table with empty bracekets **<>** or metamethod key which is surrounded by **<>**.
575 658
576```moonscript 659```moonscript
@@ -606,7 +689,7 @@ close _ = &lt;close&gt;: -> print "out of scope"
606</pre> 689</pre>
607</YueDisplay> 690</YueDisplay>
608 691
609* **Metatable Accessing** 692* **Metatable Accessing**
610Accessing metatable with **<>** or metamethod name surrounded by **<>** or writing some expression in **<>**. 693Accessing metatable with **<>** or metamethod name surrounded by **<>** or writing some expression in **<>**.
611 694
612```moonscript 695```moonscript
@@ -630,7 +713,7 @@ print tb.item
630</pre> 713</pre>
631</YueDisplay> 714</YueDisplay>
632 715
633* **Metatable Destructure** 716* **Metatable Destructure**
634Destruct metatable with metamethod key surrounded by **<>**. 717Destruct metatable with metamethod key surrounded by **<>**.
635 718
636```moonscript 719```moonscript
@@ -732,34 +815,45 @@ a ??= false
732 815
733### Implicit Object 816### Implicit Object
734 817
735You can write a list of implicit structures that starts with the symbol **\*** inside a table block. If you are creating implicit object, the fields of the object must be with the same indent. 818You can write a list of implicit structures that starts with the symbol **\*** or **-** inside a table block. If you are creating implicit object, the fields of the object must be with the same indent.
819
736```moonscript 820```moonscript
821-- assignment with implicit object
737list = 822list =
738 * 1 823 * 1
739 * 2 824 * 2
740 * 3 825 * 3
741 826
827-- function call with implicit object
742func 828func
743 * 1 829 * 1
744 * 2 830 * 2
745 * 3 831 * 3
746 832
833-- return with implicit object
834f = ->
835 return
836 * 1
837 * 2
838 * 3
839
840-- table with implicit object
747tb = 841tb =
748 name: "abc" 842 name: "abc"
749 843
750 values: 844 values:
751 * "a" 845 - "a"
752 * "b" 846 - "b"
753 * "c" 847 - "c"
754 848
755 objects: 849 objects:
756 * name: "a" 850 - name: "a"
757 value: 1 851 value: 1
758 func: => @value + 1 852 func: => @value + 1
759 tb: 853 tb:
760 fieldA: 1 854 fieldA: 1
761 855
762 * name: "b" 856 - name: "b"
763 value: 2 857 value: 2
764 func: => @value + 2 858 func: => @value + 2
765 tb: { } 859 tb: { }
@@ -767,32 +861,42 @@ tb =
767``` 861```
768<YueDisplay> 862<YueDisplay>
769<pre> 863<pre>
864-- assignment with implicit object
770list = 865list =
771 * 1 866 * 1
772 * 2 867 * 2
773 * 3 868 * 3
774 869
870-- function call with implicit object
775func 871func
776 * 1 872 * 1
777 * 2 873 * 2
778 * 3 874 * 3
779 875
876-- return with implicit object
877f = ->
878 return
879 * 1
880 * 2
881 * 3
882
883-- table with implicit object
780tb = 884tb =
781 name: "abc" 885 name: "abc"
782 886
783 values: 887 values:
784 * "a" 888 - "a"
785 * "b" 889 - "b"
786 * "c" 890 - "c"
787 891
788 objects: 892 objects:
789 * name: "a" 893 - name: "a"
790 value: 1 894 value: 1
791 func: => @value + 1 895 func: => @value + 1
792 tb: 896 tb:
793 fieldA: 1 897 fieldA: 1
794 898
795 * name: "b" 899 - name: "b"
796 value: 2 900 value: 2
797 func: => @value + 2 901 func: => @value + 2
798 tb: { } 902 tb: { }
@@ -860,7 +964,7 @@ do
860 964
861The export statement offers a concise way to define modules. 965The export statement offers a concise way to define modules.
862 966
863* **Named Export** 967* **Named Export**
864Named export will define a local variable as well as adding a field in the exported table. 968Named export will define a local variable as well as adding a field in the exported table.
865 969
866```moonscript 970```moonscript
@@ -924,7 +1028,7 @@ export["a-b-c"] = 123
924</pre> 1028</pre>
925</YueDisplay> 1029</YueDisplay>
926 1030
927* **Unnamed Export** 1031* **Unnamed Export**
928Unnamed export will add the target item into the array part of the exported table. 1032Unnamed export will add the target item into the array part of the exported table.
929 1033
930```moonscript 1034```moonscript
@@ -954,7 +1058,7 @@ export with tmp
954</pre> 1058</pre>
955</YueDisplay> 1059</YueDisplay>
956 1060
957* **Default Export** 1061* **Default Export**
958Using the **default** keyword in export statement to replace the exported table with any thing. 1062Using the **default** keyword in export statement to replace the exported table with any thing.
959 1063
960```moonscript 1064```moonscript
@@ -1202,7 +1306,7 @@ If the destructuring statement is complicated, feel free to spread it out over a
1202</pre> 1306</pre>
1203</YueDisplay> 1307</YueDisplay>
1204 1308
1205It’s common to extract values from at table and assign them the local variables that have the same name as the key. In order to avoid repetition we can use the **:** prefix operator: 1309It's common to extract values from at table and assign them the local variables that have the same name as the key. In order to avoid repetition we can use the **:** prefix operator:
1206 1310
1207```moonscript 1311```moonscript
1208{:concat, :insert} = table 1312{:concat, :insert} = table
@@ -1246,6 +1350,52 @@ You can use `_` as placeholder when doing a list destructuring:
1246</pre> 1350</pre>
1247</YueDisplay> 1351</YueDisplay>
1248 1352
1353### Range Destructuring
1354
1355You can use the spread operator `...` in list destructuring to capture a range of values. This is useful when you want to extract specific elements from the beginning and end of a list while collecting the rest in between.
1356
1357```moonscript
1358orders = ["first", "second", "third", "fourth", "last"]
1359[first, ...bulk, last] = orders
1360print first -- prints: first
1361print bulk -- prints: {"second", "third", "fourth"}
1362print last -- prints: last
1363```
1364<YueDisplay>
1365<pre>
1366orders = ["first", "second", "third", "fourth", "last"]
1367[first, ...bulk, last] = orders
1368print first -- prints: first
1369print bulk -- prints: {"second", "third", "fourth"}
1370print last -- prints: last
1371</pre>
1372</YueDisplay>
1373
1374The spread operator can be used in different positions to capture different ranges, and you can use `_` as a placeholder for the values you don't want to capture:
1375
1376```moonscript
1377-- Capture everything after first element
1378[first, ...rest] = orders
1379
1380-- Capture everything before last element
1381[...start, last] = orders
1382
1383-- Capture things except the middle elements
1384[first, ..._, last] = orders
1385```
1386<YueDisplay>
1387<pre>
1388-- Capture everything after first element
1389[first, ...rest] = orders
1390
1391-- Capture everything before last element
1392[...start, last] = orders
1393
1394-- Capture things except the middle elements
1395[first, ..._, last] = orders
1396</pre>
1397</YueDisplay>
1398
1249### Destructuring In Other Places 1399### Destructuring In Other Places
1250 1400
1251Destructuring can also show up in places where an assignment implicitly takes place. An example of this is a for loop: 1401Destructuring can also show up in places where an assignment implicitly takes place. An example of this is a for loop:
@@ -1475,6 +1625,47 @@ catch err
1475</pre> 1625</pre>
1476</YueDisplay> 1626</YueDisplay>
1477 1627
1628### Try?
1629
1630`try?` is a simplified use for error handling syntax that omit the boolean status from the `try` statement, and it will return the result from the try block when success, return nil instead of error object otherwise.
1631
1632```moonscript
1633a, b, c = try? func!
1634
1635-- with nil coalescing operator
1636a = (try? func!) ?? "default"
1637
1638-- as function argument
1639f try? func!
1640
1641-- with catch block
1642f try?
1643 print 123
1644 func!
1645catch e
1646 print e
1647 e
1648```
1649<YueDisplay>
1650<pre>
1651a, b, c = try? func!
1652
1653-- with nil coalescing operator
1654a = (try? func!) ?? "default"
1655
1656-- as function argument
1657f try? func!
1658
1659-- with catch block
1660f try?
1661 print 123
1662 func!
1663catch e
1664 print e
1665 e
1666</pre>
1667</YueDisplay>
1668
1478## Attributes 1669## Attributes
1479 1670
1480Syntax support for Lua 5.4 attributes. And you can still use both the `const` and `close` declaration and get constant check and scoped callback working when targeting Lua versions below 5.4. 1671Syntax support for Lua 5.4 attributes. And you can still use both the `const` and `close` declaration and get constant check and scoped callback working when targeting Lua versions below 5.4.
@@ -1503,6 +1694,19 @@ const {:a, :b, c, d} = tb
1503</pre> 1694</pre>
1504</YueDisplay> 1695</YueDisplay>
1505 1696
1697You can also declare a global variable to be `const`.
1698
1699```moonscript
1700global const Constant = 123
1701-- Constant = 1
1702```
1703<YueDisplay>
1704<pre>
1705global const Constant = 123
1706-- Constant = 1
1707</pre>
1708</YueDisplay>
1709
1506## Literals 1710## Literals
1507 1711
1508All of the primitive literals in Lua can be used. This applies to numbers, strings, booleans, and **nil**. 1712All of the primitive literals in Lua can be used. This applies to numbers, strings, booleans, and **nil**.
@@ -1535,12 +1739,73 @@ You can use underscores in a number literal to increase readability.
1535```moonscript 1739```moonscript
1536integer = 1_000_000 1740integer = 1_000_000
1537hex = 0xEF_BB_BF 1741hex = 0xEF_BB_BF
1742binary = 0B10011
1538``` 1743```
1539<YueDisplay> 1744<YueDisplay>
1540 1745
1541<pre> 1746<pre>
1542integer = 1_000_000 1747integer = 1_000_000
1543hex = 0xEF_BB_BF 1748hex = 0xEF_BB_BF
1749binary = 0B10011
1750</pre>
1751</YueDisplay>
1752
1753### YAML Multiline String
1754
1755The `|` prefix introduces a YAML-style multiline string literal:
1756
1757```moonscript
1758str = |
1759 key: value
1760 list:
1761 - item1
1762 - #{expr}
1763```
1764<YueDisplay>
1765<pre>
1766str = |
1767 key: value
1768 list:
1769 - item1
1770 - #{expr}
1771</pre>
1772</YueDisplay>
1773
1774This allows writing structured multiline text conveniently. All line breaks and indentation are preserved relative to the first non-empty line, and expressions inside `#{...}` are interpolated automatically as `tostring(expr)`.
1775
1776YAML Multiline String automatically detects the common leading whitespace prefix (minimum indentation across all non-empty lines) and removes it from all lines. This makes it easy to indent your code visually without affecting the resulting string content.
1777
1778```moonscript
1779fn = ->
1780 str = |
1781 foo:
1782 bar: baz
1783 return str
1784```
1785<YueDisplay>
1786<pre>
1787fn = ->
1788 str = |
1789 foo:
1790 bar: baz
1791 return str
1792</pre>
1793</YueDisplay>
1794
1795Internal indentation is preserved relative to the removed common prefix, allowing clean nested structures.
1796
1797All special characters like quotes (`"`) and backslashes (`\`) in the YAMLMultiline block are automatically escaped so that the generated Lua string is syntactically valid and behaves as expected.
1798
1799```moonscript
1800str = |
1801 path: "C:\Program Files\App"
1802 note: 'He said: "#{Hello}!"'
1803```
1804<YueDisplay>
1805<pre>
1806str = |
1807 path: "C:\Program Files\App"
1808 note: 'He said: "#{Hello}!"'
1544</pre> 1809</pre>
1545</YueDisplay> 1810</YueDisplay>
1546 1811
@@ -1861,6 +2126,89 @@ if func 1, 2, 3,
1861</pre> 2126</pre>
1862</YueDisplay> 2127</YueDisplay>
1863 2128
2129### Parameter Destructuring
2130
2131YueScript now supports destructuring function parameters when the argument is an object. Two forms of destructuring table literals are available:
2132
2133* **Curly-brace wrapped literals/object parameters**, allowing optional default values when fields are missing (e.g., `{:a, :b}`, `{a: a1 = 123}`).
2134
2135* **Unwrapped simple table syntax**, starting with a sequence of key-value or shorthand bindings and continuing until another expression terminates it (e.g., `:a, b: b1, :c`). This form extracts multiple fields from the same object.
2136
2137```moonscript
2138f1 = (:a, :b, :c) ->
2139 print a, b, c
2140
2141f1 a: 1, b: "2", c: {}
2142
2143f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) ->
2144 print a1, b, c
2145
2146arg1 = {a: 0}
2147f2 arg1, arg2
2148```
2149<YueDisplay>
2150<pre>
2151f1 = (:a, :b, :c) ->
2152 print a, b, c
2153
2154f1 a: 1, b: "2", c: {}
2155
2156f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) ->
2157print a1, b, c
2158
2159arg1 = {a: 0}
2160f2 arg1, arg2
2161</pre>
2162</YueDisplay>
2163
2164### Prefixed Return Expression
2165
2166When working with deeply nested function bodies, it can be tedious to maintain readability and consistency of the return value. To address this, YueScript introduces the **Prefixed Return Expression** syntax. Its form is as follows:
2167
2168```moon
2169findFirstEven = (list): nil ->
2170 for item in *list
2171 if type(item) == "table"
2172 for sub in *item
2173 if sub % 2 == 0
2174 return sub
2175```
2176<YueDisplay>
2177<pre>
2178findFirstEven = (list): nil ->
2179 for item in *list
2180 if type(item) == "table"
2181 for sub in *item
2182 if sub % 2 == 0
2183 return sub
2184</pre>
2185</YueDisplay>
2186
2187This is equivalent to:
2188
2189```moon
2190findFirstEven = (list) ->
2191 for item in *list
2192 if type(item) == "table"
2193 for sub in *item
2194 if sub % 2 == 0
2195 return sub
2196 nil
2197```
2198<YueDisplay>
2199<pre>
2200findFirstEven = (list) ->
2201 for item in *list
2202 if type(item) == "table"
2203 for sub in *item
2204 if sub % 2 == 0
2205 return sub
2206 nil
2207</pre>
2208</YueDisplay>
2209
2210The only difference is that you can move the final return expression before the `->` or `=>` token to indicate the function’s implicit return value as the last statement. This way, even in functions with multiple nested loops or conditional branches, you no longer need to write a trailing return expression at the end of the function body, making the logic structure more straightforward and easier to follow.
2211
1864## Backcalls 2212## Backcalls
1865 2213
1866Backcalls are used for unnesting callbacks. They are defined using arrows pointed to the left as the last parameter by default filling in a function call. All the syntax is mostly the same as regular arrow functions except that it is just pointing the other way and the function body does not require indent. 2214Backcalls are used for unnesting callbacks. They are defined using arrows pointed to the left as the last parameter by default filling in a function call. All the syntax is mostly the same as regular arrow functions except that it is just pointing the other way and the function body does not require indent.
@@ -1902,22 +2250,22 @@ x * 2
1902</pre> 2250</pre>
1903</YueDisplay> 2251</YueDisplay>
1904 2252
1905If you wish to have further code after your backcalls, you can set them aside with a do statement. 2253If you wish to have further code after your backcalls, you can set them aside with a do statement. And the parentheses can be omitted with non-fat arrow functions.
1906 2254
1907```moonscript 2255```moonscript
1908result, msg = do 2256result, msg = do
1909 (data) <- readAsync "filename.txt" 2257 data <- readAsync "filename.txt"
1910 print data 2258 print data
1911 (info) <- processAsync data 2259 info <- processAsync data
1912 check info 2260 check info
1913print result, msg 2261print result, msg
1914``` 2262```
1915<YueDisplay> 2263<YueDisplay>
1916<pre> 2264<pre>
1917result, msg = do 2265result, msg = do
1918 (data) <- readAsync "filename.txt" 2266 data <- readAsync "filename.txt"
1919 print data 2267 print data
1920 (info) <- processAsync data 2268 info <- processAsync data
1921 check info 2269 check info
1922print result, msg 2270print result, msg
1923</pre> 2271</pre>
@@ -2248,6 +2596,45 @@ slice = [item for item in *items[,,2]]
2248</pre> 2596</pre>
2249</YueDisplay> 2597</YueDisplay>
2250 2598
2599Both the minimum and maximum bounds can be negative, which means that the bounds are counted from the end of the table.
2600
2601```moonscript
2602-- take the last 4 items
2603slice = [item for item in *items[-4,-1]]
2604```
2605<YueDisplay>
2606<pre>
2607-- take the last 4 items
2608slice = [item for item in *items[-4,-1]]
2609</pre>
2610</YueDisplay>
2611
2612The step size can also be negative, which means that the items are taken in reverse order.
2613
2614```moonscript
2615reverse_slice = [item for item in *items[-1,1,-1]]
2616```
2617<YueDisplay>
2618<pre>
2619reverse_slice = [item for item in *items[-1,1,-1]]
2620</pre>
2621</YueDisplay>
2622
2623#### Slicing Expression
2624
2625Slicing can also be used as an expression. This is useful for getting a sub-list of a table.
2626
2627```moonscript
2628-- take the 2nd and 4th items as a new list
2629sub_list = items[2, 4]
2630```
2631<YueDisplay>
2632<pre>
2633-- take the 2nd and 4th items as a new list
2634sub_list = items[2, 4]
2635</pre>
2636</YueDisplay>
2637
2251## For Loop 2638## For Loop
2252 2639
2253There are two for loop forms, just like in Lua. A numeric one and a generic one: 2640There are two for loop forms, just like in Lua. A numeric one and a generic one:
@@ -2324,6 +2711,23 @@ doubled_evens = for i = 1, 20
2324</pre> 2711</pre>
2325</YueDisplay> 2712</YueDisplay>
2326 2713
2714In addition, for loops support break with a return value, allowing the loop itself to be used as an expression that exits early with a meaningful result.
2715
2716For example, to find the first number greater than 10:
2717
2718```moonscript
2719first_large = for n in *numbers
2720 break n if n > 10
2721```
2722<YueDisplay>
2723<pre>
2724first_large = for n in *numbers
2725 break n if n > 10
2726</pre>
2727</YueDisplay>
2728
2729This break-with-value syntax enables concise and expressive search or early-exit patterns directly within loop expressions.
2730
2327You can also filter values by combining the for loop expression with the continue statement. 2731You can also filter values by combining the for loop expression with the continue statement.
2328 2732
2329For loops at the end of a function body are not accumulated into a table for a return value (Instead the function will return nil). Either an explicit return statement can be used, or the loop can be converted into a list comprehension. 2733For loops at the end of a function body are not accumulated into a table for a return value (Instead the function will return nil). Either an explicit return statement can be used, or the loop can be converted into a list comprehension.
@@ -2345,7 +2749,7 @@ print func_b! -- prints table object
2345</pre> 2749</pre>
2346</YueDisplay> 2750</YueDisplay>
2347 2751
2348This is done to avoid the needless creation of tables for functions that don’t need to return the results of the loop. 2752This is done to avoid the needless creation of tables for functions that don't need to return the results of the loop.
2349 2753
2350## Repeat Loop 2754## Repeat Loop
2351 2755
@@ -2624,28 +3028,26 @@ reader\parse_line! until reader\eof!
2624 3028
2625## Switch 3029## Switch
2626 3030
2627The switch statement is shorthand for writing a series of if statements that check against the same value. Note that the value is only evaluated once. Like if statements, switches can have an else block to handle no matches. Comparison is done with the == operator. 3031The switch statement is shorthand for writing a series of if statements that check against the same value. Note that the value is only evaluated once. Like if statements, switches can have an else block to handle no matches. Comparison is done with the == operator. In switch statement, you can also use assignment expression to store temporary variable value.
2628 3032
2629```moonscript 3033```moonscript
2630name = "Dan" 3034switch name := "Dan"
2631switch name
2632 when "Robert" 3035 when "Robert"
2633 print "You are Robert" 3036 print "You are Robert"
2634 when "Dan", "Daniel" 3037 when "Dan", "Daniel"
2635 print "Your name, it's Dan" 3038 print "Your name, it's Dan"
2636 else 3039 else
2637 print "I don't know about your name" 3040 print "I don't know about you with name #{name}"
2638``` 3041```
2639<YueDisplay> 3042<YueDisplay>
2640<pre> 3043<pre>
2641name = "Dan" 3044switch name := "Dan"
2642switch name
2643 when "Robert" 3045 when "Robert"
2644 print "You are Robert" 3046 print "You are Robert"
2645 when "Dan", "Daniel" 3047 when "Dan", "Daniel"
2646 print "Your name, it's Dan" 3048 print "Your name, it's Dan"
2647 else 3049 else
2648 print "I don't know about your name" 3050 print "I don't know about you with name #{name}"
2649</pre> 3051</pre>
2650</YueDisplay> 3052</YueDisplay>
2651 3053
@@ -2676,7 +3078,7 @@ next_number = switch b
2676</pre> 3078</pre>
2677</YueDisplay> 3079</YueDisplay>
2678 3080
2679We can use the then keyword to write a switch’s when block on a single line. No extra keyword is needed to write the else block on a single line. 3081We can use the then keyword to write a switch's when block on a single line. No extra keyword is needed to write the else block on a single line.
2680 3082
2681```moonscript 3083```moonscript
2682msg = switch math.random(1, 5) 3084msg = switch math.random(1, 5)
@@ -2722,7 +3124,7 @@ else
2722</pre> 3124</pre>
2723</YueDisplay> 3125</YueDisplay>
2724 3126
2725It is worth noting the order of the case comparison expression. The case’s expression is on the left hand side. This can be useful if the case’s expression wants to overwrite how the comparison is done by defining an eq metamethod. 3127It is worth noting the order of the case comparison expression. The case's expression is on the left hand side. This can be useful if the case's expression wants to overwrite how the comparison is done by defining an eq metamethod.
2726 3128
2727### Table Matching 3129### Table Matching
2728 3130
@@ -2782,6 +3184,123 @@ switch item
2782</pre> 3184</pre>
2783</YueDisplay> 3185</YueDisplay>
2784 3186
3187You can also match against array elements, table fields, and even nested structures with array or table literals.
3188
3189Match against array elements.
3190
3191```moonscript
3192switch tb
3193 when [1, 2, 3]
3194 print "1, 2, 3"
3195 when [1, b, 3]
3196 print "1, #{b}, 3"
3197 when [1, 2, b = 3] -- b has a default value
3198 print "1, 2, #{b}"
3199```
3200<YueDisplay>
3201<pre>
3202switch tb
3203 when [1, 2, 3]
3204 print "1, 2, 3"
3205 when [1, b, 3]
3206 print "1, #{b}, 3"
3207 when [1, 2, b = 3] -- b has a default value
3208 print "1, 2, #{b}"
3209</pre>
3210</YueDisplay>
3211
3212Match against table fields with destructuring.
3213
3214```moonscript
3215switch tb
3216 when success: true, :result
3217 print "success", result
3218 when success: false
3219 print "failed", result
3220 else
3221 print "invalid"
3222```
3223<YueDisplay>
3224<pre>
3225switch tb
3226 when success: true, :result
3227 print "success", result
3228 when success: false
3229 print "failed", result
3230 else
3231 print "invalid"
3232</pre>
3233</YueDisplay>
3234
3235Match against nested table structures.
3236
3237```moonscript
3238switch tb
3239 when data: {type: "success", :content}
3240 print "success", content
3241 when data: {type: "error", :content}
3242 print "failed", content
3243 else
3244 print "invalid"
3245```
3246<YueDisplay>
3247<pre>
3248switch tb
3249 when data: {type: "success", :content}
3250 print "success", content
3251 when data: {type: "error", :content}
3252 print "failed", content
3253 else
3254 print "invalid"
3255</pre>
3256</YueDisplay>
3257
3258Match against array of tables.
3259
3260```moonscript
3261switch tb
3262 when [
3263 {a: 1, b: 2}
3264 {a: 3, b: 4}
3265 {a: 5, b: 6}
3266 fourth
3267 ]
3268 print "matched", fourth
3269```
3270<YueDisplay>
3271<pre>
3272switch tb
3273 when [
3274 {a: 1, b: 2}
3275 {a: 3, b: 4}
3276 {a: 5, b: 6}
3277 fourth
3278 ]
3279 print "matched", fourth
3280</pre>
3281</YueDisplay>
3282
3283Match against a list and capture a range of elements.
3284
3285```moonscript
3286segments = ["admin", "users", "logs", "view"]
3287switch segments
3288 when [...groups, resource, action]
3289 print "Group:", groups -- prints: {"admin", "users"}
3290 print "Resource:", resource -- prints: "logs"
3291 print "Action:", action -- prints: "view"
3292```
3293<YueDisplay>
3294<pre>
3295segments = ["admin", "users", "logs", "view"]
3296switch segments
3297 when [...groups, resource, action]
3298 print "Group:", groups -- prints: {"admin", "users"}
3299 print "Resource:", resource -- prints: "logs"
3300 print "Action:", action -- prints: "view"
3301</pre>
3302</YueDisplay>
3303
2785## Object Oriented Programming 3304## Object Oriented Programming
2786 3305
2787In these examples, the generated Lua code may appear overwhelming. It is best to focus on the meaning of the YueScript code at first, then look into the Lua code if you wish to know the implementation details. 3306In these examples, the generated Lua code may appear overwhelming. It is best to focus on the meaning of the YueScript code at first, then look into the Lua code if you wish to know the implementation details.
@@ -2913,7 +3432,7 @@ class BackPack extends Inventory
2913 3432
2914Here we extend our Inventory class, and limit the amount of items it can carry. 3433Here we extend our Inventory class, and limit the amount of items it can carry.
2915 3434
2916In this example, we don’t define a constructor on the subclass, so the parent class' constructor is called when we make a new instance. If we did define a constructor then we can use the super method to call the parent constructor. 3435In this example, we don't define a constructor on the subclass, so the parent class' constructor is called when we make a new instance. If we did define a constructor then we can use the super method to call the parent constructor.
2917 3436
2918Whenever a class inherits from another, it sends a message to the parent class by calling the method __inherited on the parent class if it exists. The function receives two arguments, the class that is being inherited and the child class. 3437Whenever a class inherits from another, it sends a message to the parent class by calling the method __inherited on the parent class if it exists. The function receives two arguments, the class that is being inherited and the child class.
2919 3438
@@ -3000,13 +3519,13 @@ print BackPack.size -- prints 10
3000 3519
3001The class object is what we create when we use a class statement. The class object is stored in a variable of the same name of the class. 3520The class object is what we create when we use a class statement. The class object is stored in a variable of the same name of the class.
3002 3521
3003The class object can be called like a function in order to create new instances. That’s how we created instances of classes in the examples above. 3522The class object can be called like a function in order to create new instances. That's how we created instances of classes in the examples above.
3004 3523
3005A class is made up of two tables. The class table itself, and the base table. The base is used as the metatable for all the instances. All properties listed in the class declaration are placed in the base. 3524A class is made up of two tables. The class table itself, and the base table. The base is used as the metatable for all the instances. All properties listed in the class declaration are placed in the base.
3006 3525
3007The class object’s metatable reads properties from the base if they don’t exist in the class object. This means we can access functions and properties directly from the class. 3526The class object's metatable reads properties from the base if they don't exist in the class object. This means we can access functions and properties directly from the class.
3008 3527
3009It is important to note that assigning to the class object does not assign into the base, so it’s not a valid way to add new methods to instances. Instead the base must explicitly be changed. See the __base field below. 3528It is important to note that assigning to the class object does not assign into the base, so it's not a valid way to add new methods to instances. Instead the base must explicitly be changed. See the __base field below.
3010 3529
3011The class object has a couple special properties: 3530The class object has a couple special properties:
3012 3531
@@ -3079,7 +3598,7 @@ print Counter.count -- prints 2
3079</pre> 3598</pre>
3080</YueDisplay> 3599</YueDisplay>
3081 3600
3082The calling semantics of @@ are similar to @. Calling a @@ name will pass the class in as the first argument using Lua’s colon syntax. 3601The calling semantics of @@ are similar to @. Calling a @@ name will pass the class in as the first argument using Lua's colon syntax.
3083 3602
3084```moonscript 3603```moonscript
3085@@hello 1,2,3,4 3604@@hello 1,2,3,4
@@ -3094,7 +3613,7 @@ The calling semantics of @@ are similar to @. Calling a @@ name will pass the cl
3094 3613
3095In the body of a class declaration, we can have normal expressions in addition to key/value pairs. In this context, self is equal to the class object. 3614In the body of a class declaration, we can have normal expressions in addition to key/value pairs. In this context, self is equal to the class object.
3096 3615
3097Here is an alternative way to create a class variable compared to what’s described above: 3616Here is an alternative way to create a class variable compared to what's described above:
3098 3617
3099```moonscript 3618```moonscript
3100class Things 3619class Things
@@ -3360,19 +3879,19 @@ In this usage, with can be seen as a special form of the K combinator.
3360The expression in the with statement can also be an assignment, if you want to give a name to the expression. 3879The expression in the with statement can also be an assignment, if you want to give a name to the expression.
3361 3880
3362```moonscript 3881```moonscript
3363with str = "Hello" 3882with str := "Hello"
3364 print "original:", str 3883 print "original:", str
3365 print "upper:", \upper! 3884 print "upper:", \upper!
3366``` 3885```
3367<YueDisplay> 3886<YueDisplay>
3368<pre> 3887<pre>
3369with str = "Hello" 3888with str := "Hello"
3370 print "original:", str 3889 print "original:", str
3371 print "upper:", \upper! 3890 print "upper:", \upper!
3372</pre> 3891</pre>
3373</YueDisplay> 3892</YueDisplay>
3374 3893
3375Accessing special keys with `[]` in a `with` statement. 3894You can access special keys with `[]` in a `with` statement.
3376 3895
3377```moonscript 3896```moonscript
3378with tb 3897with tb
@@ -3395,6 +3914,18 @@ with tb
3395</pre> 3914</pre>
3396</YueDisplay> 3915</YueDisplay>
3397 3916
3917`with?` is an enhanced version of `with` syntax, which introduces an existential check to safely access objects that may be nil without explicit null checks.
3918
3919```moonscript
3920with? obj
3921 print obj.name
3922```
3923<YueDisplay>
3924<pre>
3925with? obj
3926 print obj.name
3927</pre>
3928</YueDisplay>
3398 3929
3399## Do 3930## Do
3400 3931
@@ -3415,7 +3946,7 @@ print var -- nil here
3415</pre> 3946</pre>
3416</YueDisplay> 3947</YueDisplay>
3417 3948
3418YueScript’s **do** can also be used an expression . Allowing you to combine multiple lines into one. The result of the do expression is the last statement in its body. 3949YueScript's **do** can also be used an expression . Allowing you to combine multiple lines into one. The result of the do expression is the last statement in its body.
3419 3950
3420```moonscript 3951```moonscript
3421counter = do 3952counter = do
@@ -3541,7 +4072,7 @@ print i -- will print 0
3541</pre> 4072</pre>
3542</YueDisplay> 4073</YueDisplay>
3543 4074
3544In my_func, we've overwritten the value of i mistakenly. In this example it is quite obvious, but consider a large, or foreign code base where it isn’t clear what names have already been declared. 4075In my_func, we've overwritten the value of i mistakenly. In this example it is quite obvious, but consider a large, or foreign code base where it isn't clear what names have already been declared.
3545 4076
3546It would be helpful to say which variables from the enclosing scope we intend on change, in order to prevent us from changing others by accident. 4077It would be helpful to say which variables from the enclosing scope we intend on change, in order to prevent us from changing others by accident.
3547 4078
diff --git a/doc/docs/zh/doc/README.md b/doc/docs/zh/doc/README.md
index 754566c..5cfe4e6 100755
--- a/doc/docs/zh/doc/README.md
+++ b/doc/docs/zh/doc/README.md
@@ -16,19 +16,29 @@ Yue(月)是中文中“月亮â€çš„å称。
16### 月之脚本概览 16### 月之脚本概览
17```moonscript 17```moonscript
18-- 导入语法 18-- 导入语法
19import "yue" as :p, :to_lua 19import p, to_lua from "yue"
20 20
21-- éšå¼å¯¹è±¡ 21-- éšå¼å¯¹è±¡
22inventory = 22inventory =
23 equipment: 23 equipment:
24 * "sword" 24 - "sword"
25 * "shield" 25 - "shield"
26 items: 26 items:
27 * name: "potion" 27 - name: "potion"
28 count: 10 28 count: 10
29 * name: "bread" 29 - name: "bread"
30 count: 3 30 count: 3
31 31
32-- 列表推导
33map = (arr, action) ->
34 [action item for item in *arr]
35
36filter = (arr, cond) ->
37 [item for item in *arr when cond item]
38
39reduce = (arr, init, action): init ->
40 init = action init, item for item in *arr
41
32-- ç®¡é“æ“作符 42-- ç®¡é“æ“作符
33[1, 2, 3] 43[1, 2, 3]
34 |> map (x) -> x * 2 44 |> map (x) -> x * 2
@@ -51,19 +61,29 @@ export 🌛 = "月之脚本"
51<YueDisplay> 61<YueDisplay>
52<pre> 62<pre>
53-- 导入语法 63-- 导入语法
54import "yue" as :p, :to_lua 64import p, to_lua from "yue"
55 65
56-- éšå¼å¯¹è±¡ 66-- éšå¼å¯¹è±¡
57inventory = 67inventory =
58 equipment: 68 equipment:
59 * "sword" 69 - "sword"
60 * "shield" 70 - "shield"
61 items: 71 items:
62 * name: "potion" 72 - name: "potion"
63 count: 10 73 count: 10
64 * name: "bread" 74 - name: "bread"
65 count: 3 75 count: 3
66 76
77-- 列表推导
78map = (arr, action) ->
79 [action item for item in *arr]
80
81filter = (arr, cond) ->
82 [item for item in *arr when cond item]
83
84reduce = (arr, init, action): init ->
85 init = action init, item for item in *arr
86
67-- ç®¡é“æ“作符 87-- ç®¡é“æ“作符
68[1, 2, 3] 88[1, 2, 3]
69 |> map (x) -> x * 2 89 |> map (x) -> x * 2
@@ -122,7 +142,7 @@ export 🌛 = "月之脚本"
122 142
123* **下载预编译的二进制程åº** 143* **下载预编译的二进制程åº**
124 144
125&emsp;您å¯ä»¥ä¸‹è½½é¢„编译的二进制程åºï¼ŒåŒ…括兼容ä¸åŒ Lua ç‰ˆæœ¬çš„äºŒè¿›åˆ¶å¯æ‰§è¡Œæ–‡ä»¶å’Œåº“文件。 145&emsp;ä½ å¯ä»¥ä¸‹è½½é¢„编译的二进制程åºï¼ŒåŒ…括兼容ä¸åŒ Lua ç‰ˆæœ¬çš„äºŒè¿›åˆ¶å¯æ‰§è¡Œæ–‡ä»¶å’Œåº“文件。
126 146
127&emsp;在[这里](https://github.com/IppClub/YueScript/releases)下载预编译的二进制程åºã€‚ 147&emsp;在[这里](https://github.com/IppClub/YueScript/releases)下载预编译的二进制程åºã€‚
128 148
@@ -132,14 +152,14 @@ export 🌛 = "月之脚本"
132 152
133在Lua中使用月之脚本模å—: 153在Lua中使用月之脚本模å—:
134 154
135* **用法 1** 155* **用法 1**
136在Lua中引入 "ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶.yue"。 156在Lua中引入 "ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶.yue"。
137```Lua 157```Lua
138require("yue")("ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶") 158require("yue")("ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶")
139``` 159```
140当你在åŒä¸€è·¯å¾„下把 "ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶.yue" 编译æˆäº† "ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶.lua" 时,ä»ç„¶å¯ä»¥ä½¿ç”¨è¿™ä¸ªä»£ç åŠ è½½ .lua ä»£ç æ–‡ä»¶ã€‚在其余的月之脚本文件中,åªéœ€æ­£å¸¸ä½¿ç”¨ **require** 或 **import**进行脚本引用å³å¯ã€‚错误消æ¯ä¸­çš„代ç è¡Œå·ä¹Ÿä¼šè¢«æ­£ç¡®å¤„ç†ã€‚ 160当你在åŒä¸€è·¯å¾„下把 "ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶.yue" 编译æˆäº† "ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶.lua" 时,ä»ç„¶å¯ä»¥ä½¿ç”¨è¿™ä¸ªä»£ç åŠ è½½ .lua ä»£ç æ–‡ä»¶ã€‚在其余的月之脚本文件中,åªéœ€æ­£å¸¸ä½¿ç”¨ **require** 或 **import**进行脚本引用å³å¯ã€‚错误消æ¯ä¸­çš„代ç è¡Œå·ä¹Ÿä¼šè¢«æ­£ç¡®å¤„ç†ã€‚
141 161
142* **用法 2** 162* **用法 2**
143手动引入月之脚本模å—å¹¶é‡å†™é”™è¯¯æ¶ˆæ¯æ¥å¸®åŠ©è°ƒè¯•ã€‚ 163手动引入月之脚本模å—å¹¶é‡å†™é”™è¯¯æ¶ˆæ¯æ¥å¸®åŠ©è°ƒè¯•ã€‚
144```lua 164```lua
145local yue = require("yue") 165local yue = require("yue")
@@ -151,7 +171,7 @@ end, function(err)
151end) 171end)
152``` 172```
153 173
154* **用法 3** 174* **用法 3**
155在Lua中使用月之脚本编译器功能。 175在Lua中使用月之脚本编译器功能。
156```lua 176```lua
157local yue = require("yue") 177local yue = require("yue")
@@ -202,12 +222,12 @@ f!
202 䏿·»åŠ ä»»ä½•é€‰é¡¹æ‰§è¡Œå‘½ä»¤å¯ä»¥è¿›å…¥REPL模å¼ï¼Œ 222 䏿·»åŠ ä»»ä½•é€‰é¡¹æ‰§è¡Œå‘½ä»¤å¯ä»¥è¿›å…¥REPL模å¼ï¼Œ
203 在å•è¡Œè¾“å…¥ç¬¦å· '$' å¹¶æ¢è¡ŒåŽï¼Œå¯ä»¥å¼€å§‹æˆ–æ˜¯åœæ­¢å¤šè¡Œè¾“å…¥æ¨¡å¼ 223 在å•è¡Œè¾“å…¥ç¬¦å· '$' å¹¶æ¢è¡ŒåŽï¼Œå¯ä»¥å¼€å§‹æˆ–æ˜¯åœæ­¢å¤šè¡Œè¾“入模å¼
204``` 224```
205&emsp;&emsp;使用案例: 225&emsp;&emsp;使用案例:
206&emsp;&emsp;递归编译当å‰è·¯å¾„下扩展å为 **.yue** çš„æ¯ä¸ªæœˆä¹‹è„šæœ¬æ–‡ä»¶ï¼š **yue .** 226&emsp;&emsp;递归编译当å‰è·¯å¾„下扩展å为 **.yue** çš„æ¯ä¸ªæœˆä¹‹è„šæœ¬æ–‡ä»¶ï¼š **yue .**
207&emsp;&emsp;编译并将结果ä¿å­˜åˆ°ç›®æ ‡è·¯å¾„: **yue -t /target/path/ .** 227&emsp;&emsp;编译并将结果ä¿å­˜åˆ°ç›®æ ‡è·¯å¾„: **yue -t /target/path/ .**
208&emsp;&emsp;编译并ä¿ç•™è°ƒè¯•ä¿¡æ¯ï¼š **yue -l .** 228&emsp;&emsp;编译并ä¿ç•™è°ƒè¯•ä¿¡æ¯ï¼š **yue -l .**
209&emsp;&emsp;编译并生æˆåŽ‹ç¼©ä»£ç ï¼š **yue -m .** 229&emsp;&emsp;编译并生æˆåŽ‹ç¼©ä»£ç ï¼š **yue -m .**
210&emsp;&emsp;直接执行代ç ï¼š **yue -e 'print 123'** 230&emsp;&emsp;直接执行代ç ï¼š **yue -e 'print 123'**
211&emsp;&emsp;执行一个月之脚本文件: **yue -e main.yue** 231&emsp;&emsp;执行一个月之脚本文件: **yue -e main.yue**
212 232
213## å® 233## å®
@@ -333,7 +353,7 @@ end
333 353
334### å¯¼å‡ºå® 354### 导出å®
335 355
336å®å‡½æ•°å¯ä»¥ä»Žä¸€ä¸ªæ¨¡å—中导出,并在å¦ä¸€ä¸ªæ¨¡å—中导入。您必须将导出的å®å‡½æ•°æ”¾åœ¨ä¸€ä¸ªå•ç‹¬çš„æ–‡ä»¶ä¸­ä½¿ç”¨ï¼Œè€Œä¸”åªæœ‰å®å®šä¹‰ã€å®å¯¼å…¥å’Œå®å±•å¼€å¯ä»¥æ”¾å…¥è¿™ä¸ªå®å¯¼å‡ºæ¨¡å—中。 356å®å‡½æ•°å¯ä»¥ä»Žä¸€ä¸ªæ¨¡å—中导出,并在å¦ä¸€ä¸ªæ¨¡å—中导入。你必须将导出的å®å‡½æ•°æ”¾åœ¨ä¸€ä¸ªå•ç‹¬çš„æ–‡ä»¶ä¸­ä½¿ç”¨ï¼Œè€Œä¸”åªæœ‰å®å®šä¹‰ã€å®å¯¼å…¥å’Œå®å±•å¼€å¯ä»¥æ”¾å…¥è¿™ä¸ªå®å¯¼å‡ºæ¨¡å—中。
337```moonscript 357```moonscript
338-- 文件: utils.yue 358-- 文件: utils.yue
339export macro map = (items, action) -> "[#{action} for _ in *#{items}]" 359export macro map = (items, action) -> "[#{action} for _ in *#{items}]"
@@ -422,6 +442,54 @@ print "有效的枚举类型:", $BodyType Static
422</pre> 442</pre>
423</YueDisplay> 443</YueDisplay>
424 444
445### å®å‚数检查
446
447å¯ä»¥ç›´æŽ¥åœ¨å‚数列表中声明期望的 AST 节点类型,并在编译时检查传入的å®å‚数是å¦ç¬¦åˆé¢„期。
448
449```moonscript
450macro printNumAndStr = (num `Num, str `String) -> |
451 print(
452 #{num}
453 #{str}
454 )
455
456$printNumAndStr 123, "hello"
457```
458<YueDisplay>
459<pre>
460macro printNumAndStr = (num `Num, str `String) -> |
461 print(
462 #{num}
463 #{str}
464 )
465
466$printNumAndStr 123, "hello"
467</pre>
468</YueDisplay>
469
470如果需è¦åšæ›´åŠ çµæ´»çš„傿•°æ£€æŸ¥æ“作,å¯ä»¥ä½¿ç”¨å†…置的 `$is_ast` å®å‡½æ•°åœ¨åˆé€‚çš„ä½ç½®è¿›è¡Œæ‰‹åŠ¨æ£€æŸ¥ã€‚
471
472```moonscript
473macro printNumAndStr = (num, str) ->
474 error "expected Num as first argument" unless $is_ast Num, num
475 error "expected String as second argument" unless $is_ast String, str
476 "print(#{num}, #{str})"
477
478$printNumAndStr 123, "hello"
479```
480<YueDisplay>
481<pre>
482macro printNumAndStr = (num, str) ->
483 error "expected Num as first argument" unless $is_ast Num, num
484 error "expected String as second argument" unless $is_ast String, str
485 "print(#{num}, #{str})"
486
487$printNumAndStr 123, "hello"
488</pre>
489</YueDisplay>
490
491更多关于å¯ç”¨ AST 节点的详细信æ¯ï¼Œè¯·å‚考 [yue_parser.cpp](https://github.com/IppClub/YueScript/blob/main/src/yuescript/yue_parser.cpp) 中大写的规则定义。
492
425## æ“作符 493## æ“作符
426 494
427Lua的所有二元和一元æ“作符在月之脚本中都是å¯ç”¨çš„。此外,**!=** ç¬¦å·æ˜¯ **~=** 的别å,而 **\\** 或 **::** å‡å¯ç”¨äºŽç¼–写链å¼å‡½æ•°è°ƒç”¨ï¼Œå¦‚写作 `tb\func!` 或 `tb::func!`。此外月之脚本还æä¾›äº†ä¸€äº›å…¶ä»–特殊的æ“作符,以编写更具表达力的代ç ã€‚ 495Lua的所有二元和一元æ“作符在月之脚本中都是å¯ç”¨çš„。此外,**!=** ç¬¦å·æ˜¯ **~=** 的别å,而 **\\** 或 **::** å‡å¯ç”¨äºŽç¼–写链å¼å‡½æ•°è°ƒç”¨ï¼Œå¦‚写作 `tb\func!` 或 `tb::func!`。此外月之脚本还æä¾›äº†ä¸€äº›å…¶ä»–特殊的æ“作符,以编写更具表达力的代ç ã€‚
@@ -439,7 +507,7 @@ tb::func! if tb != nil
439 507
440### 链弿¯”较 508### 链弿¯”较
441 509
442您å¯ä»¥åœ¨æœˆä¹‹è„šæœ¬ä¸­è¿›è¡Œæ¯”è¾ƒè¡¨è¾¾å¼çš„链å¼ä¹¦å†™ï¼š 510ä½ å¯ä»¥åœ¨æœˆä¹‹è„šæœ¬ä¸­è¿›è¡Œæ¯”è¾ƒè¡¨è¾¾å¼çš„链å¼ä¹¦å†™ï¼š
443 511
444```moonscript 512```moonscript
445print 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5 513print 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5
@@ -528,7 +596,7 @@ tab[] = "Value"
528 596
529### 表扩展 597### 表扩展
530 598
531您å¯ä»¥ä½¿ç”¨å‰ç½® `...` æ“作符在Lua表中æ’入数组表或哈希表。 599ä½ å¯ä»¥ä½¿ç”¨å‰ç½® `...` æ“作符在Lua表中æ’入数组表或哈希表。
532 600
533```moonscript 601```moonscript
534parts = 602parts =
@@ -565,11 +633,26 @@ merge = {...a, ...b}
565</pre> 633</pre>
566</YueDisplay> 634</YueDisplay>
567 635
636### 表åå‘索引
637
638ä½ å¯ä»¥ä½¿ç”¨ **#** æ“作符æ¥åå‘索引表中的元素。
639
640```moonscript
641last = data.items[#]
642second_last = data.items[#-1]
643```
644<YueDisplay>
645<pre>
646last = data.items[#]
647second_last = data.items[#-1]
648</pre>
649</YueDisplay>
650
568### 元表 651### 元表
569 652
570**<>** æ“ä½œç¬¦å¯æä¾›å…ƒè¡¨æ“ä½œçš„å¿«æ·æ–¹å¼ã€‚ 653**<>** æ“ä½œç¬¦å¯æä¾›å…ƒè¡¨æ“ä½œçš„å¿«æ·æ–¹å¼ã€‚
571 654
572* **元表创建** 655* **元表创建**
573ä½¿ç”¨ç©ºæ‹¬å· **<>** 或被 **<>** 包围的元方法键创建普通的Lua表。 656ä½¿ç”¨ç©ºæ‹¬å· **<>** 或被 **<>** 包围的元方法键创建普通的Lua表。
574 657
575```moonscript 658```moonscript
@@ -605,7 +688,7 @@ close _ = &lt;close&gt;: -> print "超出范围"
605</pre> 688</pre>
606</YueDisplay> 689</YueDisplay>
607 690
608* **元表访问** 691* **元表访问**
609使用 **<>** 或被 **<>** åŒ…å›´çš„å…ƒæ–¹æ³•åæˆ–在 **<>** 中编写æŸäº›è¡¨è¾¾å¼æ¥è®¿é—®å…ƒè¡¨ã€‚ 692使用 **<>** 或被 **<>** åŒ…å›´çš„å…ƒæ–¹æ³•åæˆ–在 **<>** 中编写æŸäº›è¡¨è¾¾å¼æ¥è®¿é—®å…ƒè¡¨ã€‚
610 693
611```moonscript 694```moonscript
@@ -629,7 +712,7 @@ print tb.item
629</pre> 712</pre>
630</YueDisplay> 713</YueDisplay>
631 714
632* **元表解构** 715* **元表解构**
633使用被 **<>** 包围的元方法键解构元表。 716使用被 **<>** 包围的元方法键解构元表。
634 717
635```moonscript 718```moonscript
@@ -680,7 +763,7 @@ with? io.open "test.txt", "w"
680 763
681### ç®¡é“ 764### 管é“
682 765
683与其使用一系列嵌套的函数调用,您还å¯ä»¥è€ƒè™‘使用è¿ç®—符 **|>** æ¥ä¼ é€’值。 766与其使用一系列嵌套的函数调用,你还å¯ä»¥è€ƒè™‘使用è¿ç®—符 **|>** æ¥ä¼ é€’值。
684 767
685```moonscript 768```moonscript
686"你好" |> print 769"你好" |> print
@@ -731,67 +814,87 @@ a ??= false
731 814
732### éšå¼å¯¹è±¡ 815### éšå¼å¯¹è±¡
733 816
734您å¯ä»¥åœ¨è¡¨æ ¼å—å†…ä½¿ç”¨ç¬¦å· **\*** 开始编写一系列éšå¼ç»“构。如果您正在创建éšå¼å¯¹è±¡ï¼Œå¯¹è±¡çš„字段必须具有相åŒçš„缩进。 817ä½ å¯ä»¥åœ¨è¡¨æ ¼å—å†…ä½¿ç”¨ç¬¦å· **\*** 或是 **-** 开始编写一系列éšå¼ç»“构。如果你正在创建éšå¼å¯¹è±¡ï¼Œå¯¹è±¡çš„字段必须具有相åŒçš„缩进。
818
735```moonscript 819```moonscript
820-- 赋值时使用éšå¼å¯¹è±¡
736list = 821list =
737 * 1 822 * 1
738 * 2 823 * 2
739 * 3 824 * 3
740 825
826-- 函数调用时使用éšå¼å¯¹è±¡
741func 827func
742 * 1 828 * 1
743 * 2 829 * 2
744 * 3 830 * 3
745 831
832-- 返回时使用éšå¼å¯¹è±¡
833f = ->
834 return
835 * 1
836 * 2
837 * 3
838
839-- 表格时使用éšå¼å¯¹è±¡
746tb = 840tb =
747 name: "abc" 841 name: "abc"
748 842
749 values: 843 values:
750 * "a" 844 - "a"
751 * "b" 845 - "b"
752 * "c" 846 - "c"
753 847
754 objects: 848 objects:
755 * name: "a" 849 - name: "a"
756 value: 1 850 value: 1
757 func: => @value + 1 851 func: => @value + 1
758 tb: 852 tb:
759 fieldA: 1 853 fieldA: 1
760 854
761 * name: "b" 855 - name: "b"
762 value: 2 856 value: 2
763 func: => @value + 2 857 func: => @value + 2
764 tb: { } 858 tb: { }
765
766``` 859```
767<YueDisplay> 860<YueDisplay>
768<pre> 861<pre>
862-- 赋值时使用éšå¼å¯¹è±¡
769list = 863list =
770 * 1 864 * 1
771 * 2 865 * 2
772 * 3 866 * 3
773 867
868-- 函数调用时使用éšå¼å¯¹è±¡
774func 869func
775 * 1 870 * 1
776 * 2 871 * 2
777 * 3 872 * 3
778 873
874-- 返回时使用éšå¼å¯¹è±¡
875f = ->
876 return
877 * 1
878 * 2
879 * 3
880
881-- 表格时使用éšå¼å¯¹è±¡
779tb = 882tb =
780 name: "abc" 883 name: "abc"
781 884
782 values: 885 values:
783 * "a" 886 - "a"
784 * "b" 887 - "b"
785 * "c" 888 - "c"
786 889
787 objects: 890 objects:
788 * name: "a" 891 - name: "a"
789 value: 1 892 value: 1
790 func: => @value + 1 893 func: => @value + 1
791 tb: 894 tb:
792 fieldA: 1 895 fieldA: 1
793 896
794 * name: "b" 897 - name: "b"
795 value: 2 898 value: 2
796 func: => @value + 2 899 func: => @value + 2
797 tb: { } 900 tb: { }
@@ -859,7 +962,7 @@ do
859 962
860å¯¼å‡ºè¯­å¥æä¾›äº†ä¸€ç§ç®€æ´çš„æ–¹å¼æ¥å®šä¹‰å½“å‰çš„æ¨¡å—。 963å¯¼å‡ºè¯­å¥æä¾›äº†ä¸€ç§ç®€æ´çš„æ–¹å¼æ¥å®šä¹‰å½“å‰çš„æ¨¡å—。
861 964
862* **命å导出** 965* **命å导出**
863带命å的导出将定义一个局部å˜é‡ï¼Œå¹¶åœ¨å¯¼å‡ºçš„表中添加一个åŒå的字段。 966带命å的导出将定义一个局部å˜é‡ï¼Œå¹¶åœ¨å¯¼å‡ºçš„表中添加一个åŒå的字段。
864 967
865```moonscript 968```moonscript
@@ -923,7 +1026,7 @@ export["a-b-c"] = 123
923</pre> 1026</pre>
924</YueDisplay> 1027</YueDisplay>
925 1028
926* **未命å导出** 1029* **未命å导出**
927未命å导出会将è¦å¯¼å‡ºçš„目标项目添加到导出表的数组部分。 1030未命å导出会将è¦å¯¼å‡ºçš„目标项目添加到导出表的数组部分。
928 1031
929```moonscript 1032```moonscript
@@ -953,7 +1056,7 @@ export with tmp
953</pre> 1056</pre>
954</YueDisplay> 1057</YueDisplay>
955 1058
956* **默认导出** 1059* **默认导出**
957在导出语å¥ä¸­ä½¿ç”¨ **default** å…³é”®å­—ï¼Œæ¥æ›¿æ¢å¯¼å‡ºçš„表为一个目标的对象。 1060在导出语å¥ä¸­ä½¿ç”¨ **default** å…³é”®å­—ï¼Œæ¥æ›¿æ¢å¯¼å‡ºçš„表为一个目标的对象。
958 1061
959```moonscript 1062```moonscript
@@ -1223,7 +1326,7 @@ print first, second, color
1223</pre> 1326</pre>
1224</YueDisplay> 1327</YueDisplay>
1225 1328
1226在进行解构时,您å¯ä»¥æŒ‡å®šé»˜è®¤å€¼ï¼Œå¦‚: 1329在进行解构时,你å¯ä»¥æŒ‡å®šé»˜è®¤å€¼ï¼Œå¦‚:
1227 1330
1228```moonscript 1331```moonscript
1229{:name = "nameless", :job = "jobless"} = person 1332{:name = "nameless", :job = "jobless"} = person
@@ -1234,7 +1337,7 @@ print first, second, color
1234</pre> 1337</pre>
1235</YueDisplay> 1338</YueDisplay>
1236 1339
1237在进行列表解构时,您å¯ä»¥ä½¿ç”¨`_`作为å ä½ç¬¦ï¼š 1340在进行列表解构时,你å¯ä»¥ä½¿ç”¨`_`作为å ä½ç¬¦ï¼š
1238 1341
1239```moonscript 1342```moonscript
1240[_, two, _, four] = items 1343[_, two, _, four] = items
@@ -1245,9 +1348,55 @@ print first, second, color
1245</pre> 1348</pre>
1246</YueDisplay> 1349</YueDisplay>
1247 1350
1248### 在其它地方的解构 1351### 范围解构
1352
1353ä½ å¯ä»¥ä½¿ç”¨å±•å¼€è¿ç®—符 `...` åœ¨åˆ—è¡¨è§£æž„ä¸­æ¥æ•获一个范围的值到å­åˆ—表中。这在当你想è¦ä»Žåˆ—表的开头和结尾æå–ç‰¹å®šå…ƒç´ ï¼ŒåŒæ—¶æ”¶é›†ä¸­é—´çš„元素时éžå¸¸æœ‰ç”¨ã€‚
1354
1355```moonscript
1356orders = ["first", "second", "third", "fourth", "last"]
1357[first, ...bulk, last] = orders
1358print first -- 打å°: first
1359print bulk -- 打å°: {"second", "third", "fourth"}
1360print last -- 打å°: last
1361```
1362<YueDisplay>
1363<pre>
1364orders = ["first", "second", "third", "fourth", "last"]
1365[first, ...bulk, last] = orders
1366print first -- 打å°: first
1367print bulk -- 打å°: {"second", "third", "fourth"}
1368print last -- 打å°: last
1369</pre>
1370</YueDisplay>
1371
1372展开è¿ç®—符å¯ä»¥ç”¨åœ¨ä¸åŒçš„ä½ç½®æ¥æ•获ä¸åŒçš„范围,并且你å¯ä»¥ä½¿ç”¨ `_` 作为å ä½ç¬¦æ¥è¡¨ç¤ºä½ æƒ³è·³è¿‡å¯¹åº”范围的æ•获:
1373
1374```moonscript
1375-- æ•获第一个元素之åŽçš„æ‰€æœ‰å…ƒç´ 
1376[first, ...rest] = orders
1377
1378-- æ•获最åŽä¸€ä¸ªå…ƒç´ ä¹‹å‰çš„æ‰€æœ‰å…ƒç´ 
1379[...start, last] = orders
1380
1381-- è·³è¿‡ä¸­é—´çš„å…ƒç´ ï¼Œåªæ•获第一个和最åŽä¸€ä¸ªå…ƒç´ 
1382[first, ..._, last] = orders
1383```
1384<YueDisplay>
1385<pre>
1386-- æ•获第一个元素之åŽçš„æ‰€æœ‰å…ƒç´ 
1387[first, ...rest] = orders
1388
1389-- æ•获最åŽä¸€ä¸ªå…ƒç´ ä¹‹å‰çš„æ‰€æœ‰å…ƒç´ 
1390[...start, last] = orders
1391
1392-- è·³è¿‡ä¸­é—´çš„å…ƒç´ ï¼Œåªæ•获第一个和最åŽä¸€ä¸ªå…ƒç´ 
1393[first, ..._, last] = orders
1394</pre>
1395</YueDisplay>
1396
1397### 在其它地方的解构赋值
1249 1398
1250解构也å¯ä»¥å‡ºçŽ°åœ¨å…¶å®ƒéšå¼è¿›è¡Œèµ‹å€¼çš„åœ°æ–¹ã€‚ä¸€ä¸ªä¾‹å­æ˜¯ç”¨åœ¨for循环: 1399解构赋值也å¯ä»¥å‡ºçŽ°åœ¨å…¶å®ƒéšå¼è¿›è¡Œèµ‹å€¼çš„åœ°æ–¹ã€‚ä¸€ä¸ªä¾‹å­æ˜¯ç”¨åœ¨for循环中:
1251 1400
1252```moonscript 1401```moonscript
1253tuples = [ 1402tuples = [
@@ -1322,7 +1471,7 @@ print "好的"
1322 1471
1323### While 赋值 1472### While 赋值
1324 1473
1325您å¯ä»¥åœ¨ while å¾ªçŽ¯ä¸­åŒæ ·ä½¿ç”¨èµ‹å€¼æ¥èŽ·å–循环æ¡ä»¶çš„值。 1474ä½ å¯ä»¥åœ¨ while å¾ªçŽ¯ä¸­åŒæ ·ä½¿ç”¨èµ‹å€¼æ¥èŽ·å–循环æ¡ä»¶çš„值。
1326```moonscript 1475```moonscript
1327while byte := stream\read_one! 1476while byte := stream\read_one!
1328 -- 对 byte åšä¸€äº›æ“作 1477 -- 对 byte åšä¸€äº›æ“作
@@ -1338,7 +1487,7 @@ while byte := stream\read_one!
1338 1487
1339## å¯å˜å‚数赋值 1488## å¯å˜å‚数赋值
1340 1489
1341您å¯ä»¥å°†å‡½æ•°è¿”回的结果赋值给一个å¯å˜å‚æ•°ç¬¦å· `...`。然åŽä½¿ç”¨Lua的方å¼è®¿é—®å…¶å†…容。 1490ä½ å¯ä»¥å°†å‡½æ•°è¿”回的结果赋值给一个å¯å˜å‚æ•°ç¬¦å· `...`。然åŽä½¿ç”¨Lua的方å¼è®¿é—®å…¶å†…容。
1342```moonscript 1491```moonscript
1343list = [1, 2, 3, 4, 5] 1492list = [1, 2, 3, 4, 5]
1344fn = (ok) -> ok, table.unpack list 1493fn = (ok) -> ok, table.unpack list
@@ -1360,7 +1509,7 @@ print ok, count, first
1360 1509
1361## 空白 1510## 空白
1362 1511
1363æœˆä¹‹è„šæœ¬æ˜¯ä¸€ä¸ªå¯¹ç©ºç™½æ•æ„Ÿçš„语言。您必须在相åŒçš„缩进中使用空格 **' '** 或制表符 **'\t'** æ¥ç¼–写一些代ç å—,如函数体ã€å€¼åˆ—表和一些控制å—。包å«ä¸åŒç©ºç™½çš„表达å¼å¯èƒ½æ„味ç€ä¸åŒçš„事情。制表符被视为4个空格,但最好ä¸è¦æ··åˆä½¿ç”¨ç©ºæ ¼å’Œåˆ¶è¡¨ç¬¦ã€‚ 1512æœˆä¹‹è„šæœ¬æ˜¯ä¸€ä¸ªå¯¹ç©ºç™½æ•æ„Ÿçš„语言。你必须在相åŒçš„缩进中使用空格 **' '** 或制表符 **'\t'** æ¥ç¼–写一些代ç å—,如函数体ã€å€¼åˆ—表和一些控制å—。包å«ä¸åŒç©ºç™½çš„表达å¼å¯èƒ½æ„味ç€ä¸åŒçš„事情。制表符被视为4个空格,但最好ä¸è¦æ··åˆä½¿ç”¨ç©ºæ ¼å’Œåˆ¶è¡¨ç¬¦ã€‚
1364 1513
1365### 多行链å¼è°ƒç”¨ 1514### 多行链å¼è°ƒç”¨
1366 1515
@@ -1474,6 +1623,47 @@ catch err
1474</pre> 1623</pre>
1475</YueDisplay> 1624</YueDisplay>
1476 1625
1626### 错误处ç†ç®€åŒ–
1627
1628`try?` 是 `try` 的功能简化语法,它ä¸å†è¿”回 `try` 语å¥çš„布尔状æ€ï¼Œå¹¶åœ¨æˆåŠŸæ—¶ç›´æŽ¥è¿”å›ž `try` 代ç å—的结果,失败时返回 `nil` 值而éžé”™è¯¯å¯¹è±¡ã€‚
1629
1630```moonscript
1631a, b, c = try? func!
1632
1633-- 与空值åˆå¹¶è¿ç®—符一起使用
1634a = (try? func!) ?? "default"
1635
1636-- ä½œä¸ºå‡½æ•°å‚æ•°
1637f try? func!
1638
1639-- 带 catch å—çš„ try!
1640f try?
1641 print 123
1642 func!
1643catch e
1644 print e
1645 e
1646```
1647<YueDisplay>
1648<pre>
1649a, b, c = try? func!
1650
1651-- 与空值åˆå¹¶è¿ç®—符一起使用
1652a = (try? func!) ?? "default"
1653
1654-- ä½œä¸ºå‡½æ•°å‚æ•°
1655f try? func!
1656
1657-- 带 catch å—çš„ try!
1658f try?
1659 print 123
1660 func!
1661catch e
1662 print e
1663 e
1664</pre>
1665</YueDisplay>
1666
1477## 属性 1667## 属性
1478 1668
1479月之脚本现在æä¾›äº†Lua 5.4新增的å«åšå±žæ€§çš„语法支æŒã€‚在月之脚本编译到的Lua目标版本低于5.4时,你ä»ç„¶å¯ä»¥åŒæ—¶ä½¿ç”¨`const`å’Œ`close`çš„å±žæ€§å£°æ˜Žè¯­æ³•ï¼Œå¹¶èŽ·å¾—å¸¸é‡æ£€æŸ¥å’Œä½œç”¨åŸŸå›žè°ƒçš„功能。 1669月之脚本现在æä¾›äº†Lua 5.4新增的å«åšå±žæ€§çš„语法支æŒã€‚在月之脚本编译到的Lua目标版本低于5.4时,你ä»ç„¶å¯ä»¥åŒæ—¶ä½¿ç”¨`const`å’Œ`close`çš„å±žæ€§å£°æ˜Žè¯­æ³•ï¼Œå¹¶èŽ·å¾—å¸¸é‡æ£€æŸ¥å’Œä½œç”¨åŸŸå›žè°ƒçš„功能。
@@ -1502,6 +1692,19 @@ const {:a, :b, c, d} = tb
1502</pre> 1692</pre>
1503</YueDisplay> 1693</YueDisplay>
1504 1694
1695你也å¯ä»¥å£°æ˜Žå…¨å±€å˜é‡ä¸ºå¸¸é‡ã€‚
1696
1697```moonscript
1698global const Constant = 123
1699-- Constant = 1
1700```
1701<YueDisplay>
1702<pre>
1703global const Constant = 123
1704-- Constant = 1
1705</pre>
1706</YueDisplay>
1707
1505## å­—é¢é‡ 1708## å­—é¢é‡
1506 1709
1507Lua中的所有基本字é¢é‡éƒ½å¯ä»¥åœ¨æœˆä¹‹è„šæœ¬ä¸­ä½¿ç”¨ã€‚åŒ…æ‹¬æ•°å­—ã€å­—符串ã€å¸ƒå°”值和**nil**。 1710Lua中的所有基本字é¢é‡éƒ½å¯ä»¥åœ¨æœˆä¹‹è„šæœ¬ä¸­ä½¿ç”¨ã€‚åŒ…æ‹¬æ•°å­—ã€å­—符串ã€å¸ƒå°”值和**nil**。
@@ -1529,17 +1732,78 @@ print "我有#{math.random! * 100}%的把æ¡ã€‚"
1529 1732
1530### æ•°å­—å­—é¢é‡ 1733### æ•°å­—å­—é¢é‡
1531 1734
1532您å¯ä»¥åœ¨æ•°å­—å­—é¢é‡ä¸­ä½¿ç”¨ä¸‹åˆ’线æ¥å¢žåŠ å¯è¯»æ€§ã€‚ 1735ä½ å¯ä»¥åœ¨æ•°å­—å­—é¢é‡ä¸­ä½¿ç”¨ä¸‹åˆ’线æ¥å¢žåŠ å¯è¯»æ€§ã€‚
1533 1736
1534```moonscript 1737```moonscript
1535integer = 1_000_000 1738integer = 1_000_000
1536hex = 0xEF_BB_BF 1739hex = 0xEF_BB_BF
1740binary = 0B10011
1537``` 1741```
1538<YueDisplay> 1742<YueDisplay>
1539 1743
1540<pre> 1744<pre>
1541integer = 1_000_000 1745integer = 1_000_000
1542hex = 0xEF_BB_BF 1746hex = 0xEF_BB_BF
1747binary = 0B10011
1748</pre>
1749</YueDisplay>
1750
1751### YAML 风格字符串
1752
1753使用 `|` å‰ç¼€æ ‡è®°ä¸€ä¸ªå¤šè¡Œ YAML 风格字符串:
1754
1755```moonscript
1756str = |
1757 key: value
1758 list:
1759 - item1
1760 - #{expr}
1761```
1762<YueDisplay>
1763<pre>
1764str = |
1765 key: value
1766 list:
1767 - item1
1768 - #{expr}
1769</pre>
1770</YueDisplay>
1771
1772其效果类似于原生 Lua çš„å¤šè¡Œæ‹¼æŽ¥ï¼Œæ‰€æœ‰æ–‡æœ¬ï¼ˆå«æ¢è¡Œï¼‰å°†è¢«ä¿ç•™ä¸‹æ¥ï¼Œå¹¶æ”¯æŒ `#{...}` 语法,通过 `tostring(expr)` æ’入表达å¼ç»“果。
1773
1774YAML é£Žæ ¼çš„å¤šè¡Œå­—ç¬¦ä¸²ä¼šè‡ªåŠ¨æ£€æµ‹é¦–è¡ŒåŽæœ€å°çš„公共缩进,并从所有行中删除该å‰ç¼€ç©ºç™½å­—符。这让你å¯ä»¥åœ¨ä»£ç ä¸­å¯¹é½æ–‡æœ¬ï¼Œä½†è¾“出字符串ä¸ä¼šå¸¦å¤šä½™ç¼©è¿›ã€‚
1775
1776```moonscript
1777fn = ->
1778 str = |
1779 foo:
1780 bar: baz
1781 return str
1782```
1783<YueDisplay>
1784<pre>
1785fn = ->
1786 str = |
1787 foo:
1788 bar: baz
1789 return str
1790</pre>
1791</YueDisplay>
1792
1793输出字符串中的 foo: 对é½åˆ°è¡Œé¦–,ä¸ä¼šå¸¦æœ‰å‡½æ•°ç¼©è¿›ç©ºæ ¼ã€‚ä¿ç•™å†…部缩进的相对结构,适åˆä¹¦å†™ç»“构化嵌套样å¼çš„内容。
1794
1795支æŒè‡ªåЍ处ç†å­—符中的引å·ã€åæ–œæ ç­‰ç‰¹æ®Šç¬¦å·ï¼Œæ— éœ€æ‰‹åŠ¨è½¬ä¹‰ï¼š
1796
1797```moonscript
1798str = |
1799 path: "C:\Program Files\App"
1800 note: 'He said: "#{Hello}!"'
1801```
1802<YueDisplay>
1803<pre>
1804str = |
1805 path: "C:\Program Files\App"
1806 note: 'He said: "#{Hello}!"'
1543</pre> 1807</pre>
1544</YueDisplay> 1808</YueDisplay>
1545 1809
@@ -1644,7 +1908,7 @@ print "数字的和是", sum 10, 20
1644</pre> 1908</pre>
1645</YueDisplay> 1909</YueDisplay>
1646 1910
1647如果您需è¦åšæ˜¾å¼è¿”回,å¯ä»¥ä½¿ç”¨return关键字: 1911如果你需è¦åšæ˜¾å¼è¿”回,å¯ä»¥ä½¿ç”¨return关键字:
1648 1912
1649```moonscript 1913```moonscript
1650sum = (x, y) -> return x + y 1914sum = (x, y) -> return x + y
@@ -1822,6 +2086,89 @@ if func 1, 2, 3,
1822</pre> 2086</pre>
1823</YueDisplay> 2087</YueDisplay>
1824 2088
2089### 傿•°è§£æž„
2090
2091月之脚本支æŒåœ¨å‡½æ•°å½¢å‚ä½ç½®å¯¹ä¼ å…¥å¯¹è±¡è¿›è¡Œè§£æž„。适用两类解构表å­é¢é‡ï¼š
2092
2093- 使用 {} 包裹的字é¢é‡/对象形å‚ï¼Œæ”¯æŒæä¾›èŽ·å¾—ç©ºå­—æ®µæ—¶çš„é»˜è®¤å€¼ï¼ˆä¾‹å¦‚ {:a, :b}ã€{a: a1 = 123})。
2094
2095- æ—  {} 包裹ã€ä»¥é”®å€¼/简写键åºåˆ—开头,直至é‡åˆ°å…¶å®ƒè¡¨è¾¾å¼ç»ˆæ­¢ï¼ˆä¾‹å¦‚ :a, b: b1, :c),表示从åŒä¸€ä¸ªå¯¹è±¡ä¸­è§£æž„多个字段。
2096
2097```moonscript
2098f1 = (:a, :b, :c) ->
2099 print a, b, c
2100
2101f1 a: 1, b: "2", c: {}
2102
2103f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) ->
2104 print a1, b, c
2105
2106arg1 = {a: 0}
2107f2 arg1, arg2
2108```
2109<YueDisplay>
2110<pre>
2111f1 = (:a, :b, :c) ->
2112 print a, b, c
2113
2114f1 a: 1, b: "2", c: {}
2115
2116f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) ->
2117 print a1, b, c
2118
2119arg1 = {a: 0}
2120f2 arg1, arg2
2121</pre>
2122</YueDisplay>
2123
2124### å‰ç½®è¿”回表达å¼
2125
2126在深度嵌套的函数体中,为了æå‡è¿”回值的å¯è¯»æ€§åŠç¼–写便利性,我们新增了 “å‰ç½®è¿”回表达å¼â€ 语法。其形å¼å¦‚下:
2127
2128```moon
2129findFirstEven = (list): nil ->
2130 for item in *list
2131 if type(item) == "table"
2132 for sub in *item
2133 if sub % 2 == 0
2134 return sub
2135```
2136<YueDisplay>
2137<pre>
2138findFirstEven = (list): nil ->
2139 for item in *list
2140 if type(item) == "table"
2141 for sub in *item
2142 if sub % 2 == 0
2143 return sub
2144</pre>
2145</YueDisplay>
2146
2147这个写法等价于:
2148
2149```moon
2150findFirstEven = (list) ->
2151 for item in *list
2152 if type(item) == "table"
2153 for sub in *item
2154 if sub % 2 == 0
2155 return sub
2156 nil
2157```
2158<YueDisplay>
2159<pre>
2160findFirstEven = (list) ->
2161 for item in *list
2162 if type(item) == "table"
2163 for sub in *item
2164 if sub % 2 == 0
2165 return sub
2166 nil
2167</pre>
2168</YueDisplay>
2169
2170唯一的区别在于:你å¯ä»¥å°†å‡½æ•°çš„è¿”å›žå€¼è¡¨è¾¾å¼æå‰å†™åœ¨ `->` 或 `=>` å‰ï¼Œç”¨ä»¥æŒ‡ç¤ºè¯¥å‡½æ•°åº”éšå¼è¿”回该表达å¼çš„值。这样å³ä½¿åœ¨å¤šå±‚循环或æ¡ä»¶åˆ¤æ–­çš„场景下,也无需编写尾行悬挂的返回表达å¼ï¼Œé€»è¾‘结构会更加直观清晰。
2171
1825## åå‘回调 2172## åå‘回调
1826 2173
1827åå‘回调用于å‡å°‘函数回调的嵌套。它们使用指å‘左侧的箭头,并且默认会被定义为传入åŽç»­å‡½æ•°è°ƒç”¨çš„æœ€åŽä¸€ä¸ªå‚数。它的语法大部分与常规箭头函数相åŒï¼Œåªæ˜¯å®ƒæŒ‡å‘å¦ä¸€æ–¹å‘,并且åŽç»­çš„函数体ä¸éœ€è¦è¿›è¡Œç¼©è¿›ã€‚ 2174åå‘回调用于å‡å°‘函数回调的嵌套。它们使用指å‘左侧的箭头,并且默认会被定义为传入åŽç»­å‡½æ•°è°ƒç”¨çš„æœ€åŽä¸€ä¸ªå‚数。它的语法大部分与常规箭头函数相åŒï¼Œåªæ˜¯å®ƒæŒ‡å‘å¦ä¸€æ–¹å‘,并且åŽç»­çš„函数体ä¸éœ€è¦è¿›è¡Œç¼©è¿›ã€‚
@@ -1850,7 +2197,7 @@ print @value
1850</pre> 2197</pre>
1851</YueDisplay> 2198</YueDisplay>
1852 2199
1853您å¯ä»¥é€šè¿‡ä¸€ä¸ªå ä½ç¬¦æŒ‡å®šå›žè°ƒå‡½æ•°çš„ä¼ å‚ä½ç½®ã€‚ 2200ä½ å¯ä»¥é€šè¿‡ä¸€ä¸ªå ä½ç¬¦æŒ‡å®šå›žè°ƒå‡½æ•°çš„ä¼ å‚ä½ç½®ã€‚
1854 2201
1855```moonscript 2202```moonscript
1856(x) <- map _, [1, 2, 3] 2203(x) <- map _, [1, 2, 3]
@@ -1863,22 +2210,22 @@ x * 2
1863</pre> 2210</pre>
1864</YueDisplay> 2211</YueDisplay>
1865 2212
1866如果您希望在åå‘回调处ç†åŽç»§ç»­ç¼–写更多其它的代ç ï¼Œæ‚¨å¯ä»¥ä½¿ç”¨do语å¥å°†ä¸å½’属åå‘回调的代ç åˆ†å¼€ã€‚ 2213如果你希望在åå‘回调处ç†åŽç»§ç»­ç¼–写更多其它的代ç ï¼Œå¯ä»¥ä½¿ç”¨ do 语å¥å°†ä¸å±žäºŽåå‘回调的代ç åˆ†éš”开。对于éžç²—箭头函数的åå‘回调,回调返回值的括å·ä¹Ÿæ˜¯å¯ä»¥çœç•¥çš„。
1867 2214
1868```moonscript 2215```moonscript
1869result, msg = do 2216result, msg = do
1870 (data) <- readAsync "文件å.txt" 2217 data <- readAsync "文件å.txt"
1871 print data 2218 print data
1872 (info) <- processAsync data 2219 info <- processAsync data
1873 check info 2220 check info
1874print result, msg 2221print result, msg
1875``` 2222```
1876<YueDisplay> 2223<YueDisplay>
1877<pre> 2224<pre>
1878result, msg = do 2225result, msg = do
1879 (data) <- readAsync "文件å.txt" 2226 data <- readAsync "文件å.txt"
1880 print data 2227 print data
1881 (info) <- processAsync data 2228 info <- processAsync data
1882 check info 2229 check info
1883print result, msg 2230print result, msg
1884</pre> 2231</pre>
@@ -2037,7 +2384,7 @@ list_with_one_element = [ 1, ]
2037 2384
2038## æŽ¨å¯¼å¼ 2385## 推导å¼
2039 2386
2040推导å¼ä¸ºæˆ‘们æä¾›äº†ä¸€ç§ä¾¿æ·çš„语法,通过éåŽ†çŽ°æœ‰å¯¹è±¡å¹¶å¯¹å…¶å€¼åº”ç”¨è¡¨è¾¾å¼æ¥æž„é€ å‡ºæ–°çš„è¡¨æ ¼ã€‚æœˆä¹‹è„šæœ¬æœ‰ä¸¤ç§æŽ¨å¯¼å¼ï¼šåˆ—表推导å¼å’Œè¡¨æ ¼æŽ¨å¯¼å¼ã€‚它们最终都是产生Lua表格;列表推导å¼å°†å€¼ç´¯ç§¯åˆ°ç±»ä¼¼æ•°ç»„的表格中,而表格推导å¼å…è®¸æ‚¨åœ¨æ¯æ¬¡é历时设置新表格的键和值。 2387推导å¼ä¸ºæˆ‘们æä¾›äº†ä¸€ç§ä¾¿æ·çš„语法,通过éåŽ†çŽ°æœ‰å¯¹è±¡å¹¶å¯¹å…¶å€¼åº”ç”¨è¡¨è¾¾å¼æ¥æž„é€ å‡ºæ–°çš„è¡¨æ ¼ã€‚æœˆä¹‹è„šæœ¬æœ‰ä¸¤ç§æŽ¨å¯¼å¼ï¼šåˆ—表推导å¼å’Œè¡¨æ ¼æŽ¨å¯¼å¼ã€‚它们最终都是产生Lua表格;列表推导å¼å°†å€¼ç´¯ç§¯åˆ°ç±»ä¼¼æ•°ç»„的表格中,而表格推导å¼å…è®¸ä½ åœ¨æ¯æ¬¡é历时设置新表格的键和值。
2041 2388
2042### åˆ—è¡¨æŽ¨å¯¼å¼ 2389### 列表推导å¼
2043 2390
@@ -2210,6 +2557,45 @@ slice = [item for item in *items[,,2]]
2210</pre> 2557</pre>
2211</YueDisplay> 2558</YueDisplay>
2212 2559
2560最å°å’Œæœ€å¤§è¾¹ç•Œéƒ½å¯ä»¥æ˜¯è´Ÿæ•°ï¼Œä½¿ç”¨è´Ÿæ•°æ„味ç€è¾¹ç•Œæ˜¯ä»Žè¡¨çš„æœ«å°¾å¼€å§‹è®¡ç®—的。
2561
2562```moonscript
2563-- å–æœ€åŽ4个元素
2564slice = [item for item in *items[-4,-1]]
2565```
2566<YueDisplay>
2567<pre>
2568-- å–æœ€åŽ4个元素
2569slice = [item for item in *items[-4,-1]]
2570</pre>
2571</YueDisplay>
2572
2573切片的步长也å¯ä»¥æ˜¯è´Ÿæ•°ï¼Œè¿™æ„味ç€å…ƒç´ ä¼šä»¥ç›¸å的顺åºè¢«å–出。
2574
2575```moonscript
2576reverse_slice = [item for item in *items[-1,1,-1]]
2577```
2578<YueDisplay>
2579<pre>
2580reverse_slice = [item for item in *items[-1,1,-1]]
2581</pre>
2582</YueDisplay>
2583
2584#### 切片表达å¼
2585
2586切片也å¯ä»¥ä½œä¸ºè¡¨è¾¾å¼æ¥ä½¿ç”¨ã€‚å¯ä»¥ç”¨äºŽèŽ·å–一个表包å«çš„å­åˆ—表。
2587
2588```moonscript
2589-- å–第2和第4个元素作为新的列表
2590sub_list = items[2, 4]
2591```
2592<YueDisplay>
2593<pre>
2594-- å–第2和第4个元素作为新的列表
2595sub_list = items[2, 4]
2596</pre>
2597</YueDisplay>
2598
2213## for 循环 2599## for 循环
2214 2600
2215Lua中有两ç§for循环形å¼ï¼Œæ•°å­—型和通用型: 2601Lua中有两ç§for循环形å¼ï¼Œæ•°å­—型和通用型:
@@ -2286,9 +2672,24 @@ doubled_evens = for i = 1, 20
2286</pre> 2672</pre>
2287</YueDisplay> 2673</YueDisplay>
2288 2674
2289您还å¯ä»¥ç»“åˆfor循环表达å¼ä¸Žcontinueè¯­å¥æ¥è¿‡æ»¤å€¼ã€‚ 2675此外,for循环还支æŒå¸¦è¿”回值的break语å¥ï¼Œè¿™æ ·å¾ªçŽ¯æœ¬èº«å°±å¯ä»¥ä½œä¸ºä¸€ä¸ªè¡¨è¾¾å¼ï¼Œåœ¨æ»¡è¶³æ¡ä»¶æ—¶æå‰é€€å‡ºå¹¶è¿”回有æ„义的结果。
2676
2677例如,查找第一个大于10的数字:
2678
2679```moonscript
2680first_large = for n in *numbers
2681 break n if n > 10
2682```
2683<YueDisplay>
2684<pre>
2685first_large = for n in *numbers
2686 break n if n > 10
2687</pre>
2688</YueDisplay>
2689
2690你还å¯ä»¥ç»“åˆfor循环表达å¼ä¸Žcontinueè¯­å¥æ¥è¿‡æ»¤å€¼ã€‚
2290 2691
2291注æ„出现在函数体末尾的for循环,ä¸ä¼šè¢«å½“作是一个表达å¼ï¼Œå¹¶å°†å¾ªçŽ¯ç»“æžœç´¯ç§¯åˆ°ä¸€ä¸ªåˆ—è¡¨ä¸­ä½œä¸ºè¿”å›žå€¼ï¼ˆç›¸å,函数将返回nil)。如果è¦å‡½æ•°æœ«å°¾çš„循环转æ¢ä¸ºåˆ—表表达å¼ï¼Œå¯ä»¥ä½¿ç”¨è¿”回语å¥åŠ for循环表达å¼ã€‚ 2692注æ„出现在函数体末尾的for循环,ä¸ä¼šè¢«å½“作是一个表达å¼å¹¶å°†å¾ªçŽ¯ç»“æžœç´¯ç§¯åˆ°ä¸€ä¸ªåˆ—è¡¨ä¸­ä½œä¸ºè¿”å›žå€¼ï¼ˆç›¸å,函数将返回nil)。如果è¦å‡½æ•°æœ«å°¾çš„循环转æ¢ä¸ºåˆ—表表达å¼ï¼Œå¯ä»¥æ˜¾å¼åœ°ä½¿ç”¨è¿”回语å¥åŠ for循环表达å¼ã€‚
2292 2693
2293```moonscript 2694```moonscript
2294func_a = -> for i = 1, 10 do print i 2695func_a = -> for i = 1, 10 do print i
@@ -2513,7 +2914,7 @@ print "你真幸è¿ï¼" unless math.random! > 0.1
2513 2914
2514### èŒƒå›´è¡¨è¾¾å¼ 2915### 范围表达å¼
2515 2916
2516您å¯ä»¥ä½¿ç”¨èŒƒå›´è¡¨è¾¾å¼æ¥ç¼–写进行范围检查的代ç ã€‚ 2917ä½ å¯ä»¥ä½¿ç”¨èŒƒå›´è¡¨è¾¾å¼æ¥ç¼–写进行范围检查的代ç ã€‚
2517 2918
2518```moonscript 2919```moonscript
2519a = 5 2920a = 5
@@ -2586,28 +2987,26 @@ reader\parse_line! until reader\eof!
2586 2987
2587## switch è¯­å¥ 2988## switch 语å¥
2588 2989
2589switchè¯­å¥æ˜¯ä¸ºäº†ç®€åŒ–检查一系列相åŒå€¼çš„if语å¥è€Œæä¾›çš„ç®€å†™è¯­æ³•ã€‚è¦æ³¨æ„用于比较检查的目标值åªä¼šè®¡ç®—一次。和if语å¥ä¸€æ ·ï¼Œswitch语å¥åœ¨æœ€åŽå¯ä»¥æŽ¥ä¸€ä¸ªelse代ç å—æ¥å¤„ç†æ²¡æœ‰åŒ¹é…的情况。在生æˆçš„Lua代ç ä¸­ï¼Œè¿›è¡Œæ¯”较是使用==æ“作符完æˆçš„。 2990switchè¯­å¥æ˜¯ä¸ºäº†ç®€åŒ–检查一系列相åŒå€¼çš„if语å¥è€Œæä¾›çš„ç®€å†™è¯­æ³•ã€‚è¦æ³¨æ„用于比较检查的目标值åªä¼šè®¡ç®—一次。和if语å¥ä¸€æ ·ï¼Œswitch语å¥åœ¨æœ€åŽå¯ä»¥æŽ¥ä¸€ä¸ªelse代ç å—æ¥å¤„ç†æ²¡æœ‰åŒ¹é…的情况。在生æˆçš„Lua代ç ä¸­ï¼Œè¿›è¡Œæ¯”较是使用==æ“作符完æˆçš„。switch语å¥ä¸­ä¹Ÿå¯ä»¥ä½¿ç”¨èµ‹å€¼è¡¨è¾¾å¼æ¥å‚¨å­˜ä¸´æ—¶å˜é‡å€¼ã€‚
2590 2991
2591```moonscript 2992```moonscript
2592name = "Dan" 2993switch name := "Dan"
2593switch name
2594 when "Robert" 2994 when "Robert"
2595 print "你是Robert" 2995 print "你是Robert"
2596 when "Dan", "Daniel" 2996 when "Dan", "Daniel"
2597 print "ä½ çš„å字是Dan" 2997 print "ä½ çš„å字是Dan"
2598 else 2998 else
2599 print "我ä¸çŸ¥é“ä½ çš„åå­—" 2999 print "我ä¸è®¤è¯†ä½ ï¼Œä½ çš„å字是#{name}"
2600``` 3000```
2601<YueDisplay> 3001<YueDisplay>
2602<pre> 3002<pre>
2603name = "Dan" 3003switch name := "Dan"
2604switch name
2605 when "Robert" 3004 when "Robert"
2606 print "你是Robert" 3005 print "你是Robert"
2607 when "Dan", "Daniel" 3006 when "Dan", "Daniel"
2608 print "ä½ çš„å字是Dan" 3007 print "ä½ çš„å字是Dan"
2609 else 3008 else
2610 print "我ä¸çŸ¥é“ä½ çš„åå­—" 3009 print "我ä¸è®¤è¯†ä½ ï¼Œä½ çš„å字是#{name}"
2611</pre> 3010</pre>
2612</YueDisplay> 3011</YueDisplay>
2613 3012
@@ -2684,7 +3083,7 @@ else
2684</pre> 3083</pre>
2685</YueDisplay> 3084</YueDisplay>
2686 3085
2687值得注æ„的是,在生æˆLuaä»£ç æ—¶ï¼Œæˆ‘们è¦åšæ£€æŸ¥çš„ç›®æ ‡å˜é‡ä¼šæ”¾åœ¨==表达å¼çš„å³ä¾§ã€‚当您希望给whenå­å¥çš„æ¯”较对象定义一个\_\_eq元方法æ¥é‡è½½åˆ¤æ–­é€»è¾‘时,å¯èƒ½ä¼šæœ‰ç”¨ã€‚ 3086值得注æ„的是,在生æˆLuaä»£ç æ—¶ï¼Œæˆ‘们è¦åšæ£€æŸ¥çš„ç›®æ ‡å˜é‡ä¼šæ”¾åœ¨==表达å¼çš„å³ä¾§ã€‚当你希望给whenå­å¥çš„æ¯”较对象定义一个\_\_eq元方法æ¥é‡è½½åˆ¤æ–­é€»è¾‘时,å¯èƒ½ä¼šæœ‰ç”¨ã€‚
2688 3087
2689### è¡¨æ ¼åŒ¹é… 3088### 表格匹é…
2690 3089
@@ -2744,9 +3143,126 @@ switch item
2744</pre> 3143</pre>
2745</YueDisplay> 3144</YueDisplay>
2746 3145
3146你也å¯ä»¥åŒ¹é…数组元素ã€è¡¨æ ¼å­—段,甚至使用数组或表格字é¢é‡æ¥åŒ¹é…嵌套的结构。
3147
3148åŒ¹é…æ•°ç»„元素。
3149
3150```moonscript
3151switch tb
3152 when [1, 2, 3]
3153 print "1, 2, 3"
3154 when [1, b, 3]
3155 print "1, #{b}, 3"
3156 when [1, 2, b = 3] -- å˜é‡b有默认值
3157 print "1, 2, #{b}"
3158```
3159<YueDisplay>
3160<pre>
3161switch tb
3162 when [1, 2, 3]
3163 print "1, 2, 3"
3164 when [1, b, 3]
3165 print "1, #{b}, 3"
3166 when [1, 2, b = 3] -- å˜é‡b有默认值
3167 print "1, 2, #{b}"
3168</pre>
3169</YueDisplay>
3170
3171匹é…表格字段。
3172
3173```moonscript
3174switch tb
3175 when success: true, :result
3176 print "æˆåŠŸ", result
3177 when success: false
3178 print "失败", result
3179 else
3180 print "无效值"
3181```
3182<YueDisplay>
3183<pre>
3184switch tb
3185 when success: true, :result
3186 print "æˆåŠŸ", result
3187 when success: false
3188 print "失败", result
3189 else
3190 print "无效值"
3191</pre>
3192</YueDisplay>
3193
3194匹é…嵌套的表格结构。
3195
3196```moonscript
3197switch tb
3198 when data: {type: "success", :content}
3199 print "æˆåŠŸ", content
3200 when data: {type: "error", :content}
3201 print "失败", content
3202 else
3203 print "无效值"
3204```
3205<YueDisplay>
3206<pre>
3207switch tb
3208 when data: {type: "success", :content}
3209 print "æˆåŠŸ", content
3210 when data: {type: "error", :content}
3211 print "失败", content
3212 else
3213 print "无效值"
3214</pre>
3215</YueDisplay>
3216
3217匹é…表格数组。
3218
3219```moonscript
3220switch tb
3221 when [
3222 {a: 1, b: 2}
3223 {a: 3, b: 4}
3224 {a: 5, b: 6}
3225 fourth
3226 ]
3227 print "åŒ¹é…æˆåŠŸ", fourth
3228```
3229<YueDisplay>
3230<pre>
3231switch tb
3232 when [
3233 {a: 1, b: 2}
3234 {a: 3, b: 4}
3235 {a: 5, b: 6}
3236 fourth
3237 ]
3238 print "åŒ¹é…æˆåŠŸ", fourth
3239</pre>
3240</YueDisplay>
3241
3242匹é…一个列表并æ•获特定范围内的元素。
3243
3244```moonscript
3245segments = ["admin", "users", "logs", "view"]
3246switch segments
3247 when [...groups, resource, action]
3248 print "Group:", groups -- 打å°: {"admin", "users"}
3249 print "Resource:", resource -- 打å°: "logs"
3250 print "Action:", action -- 打å°: "view"
3251```
3252<YueDisplay>
3253<pre>
3254segments = ["admin", "users", "logs", "view"]
3255switch segments
3256 when [...groups, resource, action]
3257 print "Group:", groups -- 打å°: {"admin", "users"}
3258 print "Resource:", resource -- 打å°: "logs"
3259 print "Action:", action -- 打å°: "view"
3260</pre>
3261</YueDisplay>
3262
2747## é¢å‘对象编程 3263## é¢å‘对象编程
2748 3264
2749在以下的示例中,月之脚本生æˆçš„Lua代ç å¯èƒ½çœ‹èµ·æ¥ä¼šå¾ˆå¤æ‚。所以最好主è¦å…³æ³¨æœˆä¹‹è„šæœ¬ä»£ç å±‚é¢çš„æ„ä¹‰ï¼Œç„¶åŽå¦‚果您想知é“关于é¢å‘å¯¹è±¡åŠŸèƒ½çš„å®žçŽ°ç»†èŠ‚ï¼Œå†æŸ¥çœ‹Lua代ç ã€‚ 3265在以下的示例中,月之脚本生æˆçš„Lua代ç å¯èƒ½çœ‹èµ·æ¥ä¼šå¾ˆå¤æ‚。所以最好主è¦å…³æ³¨æœˆä¹‹è„šæœ¬ä»£ç å±‚é¢çš„æ„ä¹‰ï¼Œç„¶åŽå¦‚果你想知é“关于é¢å‘å¯¹è±¡åŠŸèƒ½çš„å®žçŽ°ç»†èŠ‚ï¼Œå†æŸ¥çœ‹Lua代ç ã€‚
2750 3266
2751一个简å•的类: 3267一个简å•的类:
2752 3268
@@ -3214,7 +3730,7 @@ x = class
3214 3730
3215### ç±»æ··åˆ 3731### 类混åˆ
3216 3732
3217您å¯ä»¥é€šè¿‡ä½¿ç”¨ `using` 关键字æ¥å®žçŽ°ç±»æ··åˆã€‚è¿™æ„å‘³ç€æ‚¨å¯ä»¥ä»Žä¸€ä¸ªæ™®é€š Lua 表格或已定义的类对象中,å¤åˆ¶å‡½æ•°åˆ°æ‚¨åˆ›å»ºçš„æ–°ç±»ä¸­ã€‚当您使用普通 Lua è¡¨æ ¼è¿›è¡Œç±»æ··åˆæ—¶ï¼Œæ‚¨æœ‰æœºä¼šç”¨è‡ªå·±çš„实现æ¥é‡å†™ç±»çš„索引方法(例如元方法 `__index`ï¼‰ã€‚ç„¶è€Œï¼Œå½“æ‚¨ä»Žä¸€ä¸ªç±»å¯¹è±¡åšæ··åˆæ—¶ï¼Œéœ€è¦æ³¨æ„的是该类对象的元方法将ä¸ä¼šè¢«å¤åˆ¶åˆ°æ–°ç±»ã€‚ 3733ä½ å¯ä»¥é€šè¿‡ä½¿ç”¨ `using` 关键字æ¥å®žçŽ°ç±»æ··åˆã€‚è¿™æ„味ç€ä½ å¯ä»¥ä»Žä¸€ä¸ªæ™®é€š Lua 表格或已定义的类对象中,å¤åˆ¶å‡½æ•°åˆ°ä½ åˆ›å»ºçš„æ–°ç±»ä¸­ã€‚当你使用普通 Lua è¡¨æ ¼è¿›è¡Œç±»æ··åˆæ—¶ï¼Œä½ æœ‰æœºä¼šç”¨è‡ªå·±çš„实现æ¥é‡å†™ç±»çš„索引方法(例如元方法 `__index`ï¼‰ã€‚ç„¶è€Œï¼Œå½“ä½ ä»Žä¸€ä¸ªç±»å¯¹è±¡åšæ··åˆæ—¶ï¼Œéœ€è¦æ³¨æ„的是该类对象的元方法将ä¸ä¼šè¢«å¤åˆ¶åˆ°æ–°ç±»ã€‚
3218 3734
3219```moonscript 3735```moonscript
3220MyIndex = __index: var: 1 3736MyIndex = __index: var: 1
@@ -3316,22 +3832,22 @@ me = create_person "Leaf", [dad, mother, sister]
3316 3832
3317在此用法中,withå¯ä»¥è¢«è§†ä¸ºK组åˆå­ï¼ˆk-combinator)的一ç§ç‰¹æ®Šå½¢å¼ã€‚ 3833在此用法中,withå¯ä»¥è¢«è§†ä¸ºK组åˆå­ï¼ˆk-combinator)的一ç§ç‰¹æ®Šå½¢å¼ã€‚
3318 3834
3319如果您想给表达å¼å¦å¤–起一个åç§°çš„è¯ï¼Œwith语å¥ä¸­çš„表达å¼ä¹Ÿå¯ä»¥æ˜¯ä¸€ä¸ªèµ‹å€¼è¯­å¥ã€‚ 3835如果你想给表达å¼å¦å¤–起一个åç§°çš„è¯ï¼Œwith语å¥ä¸­çš„表达å¼ä¹Ÿå¯ä»¥æ˜¯ä¸€ä¸ªèµ‹å€¼è¯­å¥ã€‚
3320 3836
3321```moonscript 3837```moonscript
3322with str = "你好" 3838with str := "你好"
3323 print "原始:", str 3839 print "原始:", str
3324 print "大写:", \upper! 3840 print "大写:", \upper!
3325``` 3841```
3326<YueDisplay> 3842<YueDisplay>
3327<pre> 3843<pre>
3328with str = "你好" 3844with str := "你好"
3329 print "原始:", str 3845 print "原始:", str
3330 print "大写:", \upper! 3846 print "大写:", \upper!
3331</pre> 3847</pre>
3332</YueDisplay> 3848</YueDisplay>
3333 3849
3334在with语å¥ä¸­å¯ä»¥ä½¿ç”¨`[]`访问特殊键。 3850ä½ å¯ä»¥åœ¨ `with` 语å¥ä¸­ä½¿ç”¨ `[]` 访问特殊键。
3335 3851
3336```moonscript 3852```moonscript
3337with tb 3853with tb
@@ -3354,6 +3870,19 @@ with tb
3354</pre> 3870</pre>
3355</YueDisplay> 3871</YueDisplay>
3356 3872
3873`with?` 是 `with` è¯­æ³•çš„ä¸€ä¸ªå¢žå¼ºç‰ˆæœ¬ï¼Œå¼•å…¥äº†å­˜åœ¨æ€§æ£€æŸ¥ï¼Œç”¨äºŽåœ¨ä¸æ˜¾å¼åˆ¤ç©ºçš„æƒ…况下安全访问å¯èƒ½ä¸º nil 的对象。
3874
3875```moonscript
3876with? obj
3877 print obj.name
3878```
3879<YueDisplay>
3880<pre>
3881with? obj
3882 print obj.name
3883</pre>
3884</YueDisplay>
3885
3357## do è¯­å¥ 3886## do 语å¥
3358 3887
3359å½“ç”¨ä½œè¯­å¥æ—¶ï¼Œdo语å¥çš„作用就åƒåœ¨Lua中差ä¸å¤šã€‚ 3888å½“ç”¨ä½œè¯­å¥æ—¶ï¼Œdo语å¥çš„作用就åƒåœ¨Lua中差ä¸å¤šã€‚
@@ -3373,7 +3902,7 @@ print var -- 这里是nil
3373</pre> 3902</pre>
3374</YueDisplay> 3903</YueDisplay>
3375 3904
3376月之脚本的 **do** 也å¯ä»¥ç”¨ä½œè¡¨è¾¾å¼ã€‚å…许您将多行代ç çš„处ç†åˆå¹¶ä¸ºä¸€ä¸ªè¡¨è¾¾å¼ï¼Œå¹¶å°†do语å¥ä»£ç å—的最åŽä¸€ä¸ªè¯­å¥ä½œä¸ºè¡¨è¾¾å¼è¿”回的结果。 3905月之脚本的 **do** 也å¯ä»¥ç”¨ä½œè¡¨è¾¾å¼ã€‚å…许你将多行代ç çš„处ç†åˆå¹¶ä¸ºä¸€ä¸ªè¡¨è¾¾å¼ï¼Œå¹¶å°†do语å¥ä»£ç å—的最åŽä¸€ä¸ªè¯­å¥ä½œä¸ºè¡¨è¾¾å¼è¿”回的结果。
3377 3906
3378```moonscript 3907```moonscript
3379counter = do 3908counter = do
@@ -4332,8 +4861,8 @@ simplified: boolean
4332 4861
4333ç‰ˆæƒ (c) 2017-2025 æŽç‘¾ \<dragon-fly@qq.com\> 4862ç‰ˆæƒ (c) 2017-2025 æŽç‘¾ \<dragon-fly@qq.com\>
4334 4863
4335特此å…费授予任何获得本软件副本和相关文档文件(下称“软件â€ï¼‰çš„人ä¸å—é™åˆ¶åœ°å¤„置该软件的æƒåˆ©ï¼ŒåŒ…括ä¸å—é™åˆ¶åœ°ä½¿ç”¨ã€å¤åˆ¶ã€ä¿®æ”¹ã€åˆå¹¶ã€å‘布ã€åˆ†å‘ã€è½¬æŽˆè®¸å¯å’Œ/或出售该软件副本,以åŠå†æŽˆæƒè¢«é…å‘了本软件的人如上的æƒåˆ©ï¼Œé¡»åœ¨ä¸‹åˆ—æ¡ä»¶ä¸‹ï¼š 4864特此å…费授予任何获得本软件副本和相关文档文件(下称“软件â€ï¼‰çš„人ä¸å—é™åˆ¶åœ°å¤„置该软件的æƒåˆ©ï¼ŒåŒ…括ä¸å—é™åˆ¶åœ°ä½¿ç”¨ã€å¤åˆ¶ã€ä¿®æ”¹ã€åˆå¹¶ã€å‘布ã€åˆ†å‘ã€è½¬æŽˆè®¸å¯å’Œ/或出售该软件副本,以åŠå†æŽˆæƒè¢«é…å‘了本软件的人如上的æƒåˆ©ï¼Œé¡»åœ¨ä¸‹åˆ—æ¡ä»¶ä¸‹ï¼š
4336上述版æƒå£°æ˜Žå’Œæœ¬è®¸å¯å£°æ˜Žåº”包å«åœ¨è¯¥è½¯ä»¶çš„æ‰€æœ‰å‰¯æœ¬æˆ–实质æˆåˆ†ä¸­ã€‚ 4865上述版æƒå£°æ˜Žå’Œæœ¬è®¸å¯å£°æ˜Žåº”包å«åœ¨è¯¥è½¯ä»¶çš„æ‰€æœ‰å‰¯æœ¬æˆ–实质æˆåˆ†ä¸­ã€‚
4337æœ¬è½¯ä»¶æ˜¯â€œå¦‚æ­¤â€æä¾›çš„ï¼Œæ²¡æœ‰ä»»ä½•å½¢å¼çš„æ˜Žç¤ºæˆ–暗示的ä¿è¯ï¼ŒåŒ…括但ä¸é™äºŽå¯¹é€‚销性ã€ç‰¹å®šç”¨é€”的适用性和ä¸ä¾µæƒçš„ä¿è¯ã€‚åœ¨ä»»ä½•æƒ…å†µä¸‹ï¼Œä½œè€…æˆ–ç‰ˆæƒæŒæœ‰äººéƒ½ä¸å¯¹ä»»ä½•ç´¢èµ”ã€æŸå®³æˆ–其他责任负责,无论这些追责æ¥è‡ªåˆåŒã€ä¾µæƒæˆ–å…¶å®ƒè¡Œä¸ºä¸­ï¼Œè¿˜æ˜¯äº§ç”ŸäºŽã€æºäºŽæˆ–æœ‰å…³äºŽæœ¬è½¯ä»¶ä»¥åŠæœ¬è½¯ä»¶çš„使用或其它处置。 4866æœ¬è½¯ä»¶æ˜¯â€œå¦‚æ­¤â€æä¾›çš„ï¼Œæ²¡æœ‰ä»»ä½•å½¢å¼çš„æ˜Žç¤ºæˆ–暗示的ä¿è¯ï¼ŒåŒ…括但ä¸é™äºŽå¯¹é€‚销性ã€ç‰¹å®šç”¨é€”的适用性和ä¸ä¾µæƒçš„ä¿è¯ã€‚åœ¨ä»»ä½•æƒ…å†µä¸‹ï¼Œä½œè€…æˆ–ç‰ˆæƒæŒæœ‰äººéƒ½ä¸å¯¹ä»»ä½•ç´¢èµ”ã€æŸå®³æˆ–其他责任负责,无论这些追责æ¥è‡ªåˆåŒã€ä¾µæƒæˆ–å…¶å®ƒè¡Œä¸ºä¸­ï¼Œè¿˜æ˜¯äº§ç”ŸäºŽã€æºäºŽæˆ–æœ‰å…³äºŽæœ¬è½¯ä»¶ä»¥åŠæœ¬è½¯ä»¶çš„使用或其它处置。
4338 4867
4339<CompilerModal /> 4868<CompilerModal />
diff --git a/makefile b/makefile
index d1b074a..d7e85d3 100644
--- a/makefile
+++ b/makefile
@@ -391,7 +391,6 @@ test: debug
391 @./$(BIN_NAME) $(TEST_INPUT)/try_catch.yue -o $(TEST_OUTPUT)/5.1/try_catch.lua --target=5.1 391 @./$(BIN_NAME) $(TEST_INPUT)/try_catch.yue -o $(TEST_OUTPUT)/5.1/try_catch.lua --target=5.1
392 @./$(BIN_NAME) $(TEST_INPUT)/attrib.yue -o $(TEST_OUTPUT)/5.1/attrib.lua --target=5.1 392 @./$(BIN_NAME) $(TEST_INPUT)/attrib.yue -o $(TEST_OUTPUT)/5.1/attrib.lua --target=5.1
393 @./$(BIN_NAME) $(TEST_INPUT)/test/loops_spec.yue -o $(TEST_OUTPUT)/5.1/test/loops_spec.lua --target=5.1 393 @./$(BIN_NAME) $(TEST_INPUT)/test/loops_spec.yue -o $(TEST_OUTPUT)/5.1/test/loops_spec.lua --target=5.1
394 @./$(BIN_NAME) $(TEST_INPUT)/literals.yue -o $(TEST_OUTPUT)/5.1/literals.lua --target=5.1
395 @./$(BIN_NAME) -e spec/inputs/compile_doc.yue $(TEST_OUTPUT) 394 @./$(BIN_NAME) -e spec/inputs/compile_doc.yue $(TEST_OUTPUT)
396 @echo -en "Compile time: " 395 @echo -en "Compile time: "
397 @$(END_TIME) 396 @$(END_TIME)
@@ -410,7 +409,6 @@ gen: release
410 @./$(BIN_NAME) $(TEST_INPUT)/loops.yue -o $(GEN_OUTPUT)/5.1/loops.lua --target=5.1 409 @./$(BIN_NAME) $(TEST_INPUT)/loops.yue -o $(GEN_OUTPUT)/5.1/loops.lua --target=5.1
411 @./$(BIN_NAME) $(TEST_INPUT)/try_catch.yue -o $(GEN_OUTPUT)/5.1/try_catch.lua --target=5.1 410 @./$(BIN_NAME) $(TEST_INPUT)/try_catch.yue -o $(GEN_OUTPUT)/5.1/try_catch.lua --target=5.1
412 @./$(BIN_NAME) $(TEST_INPUT)/attrib.yue -o $(GEN_OUTPUT)/5.1/attrib.lua --target=5.1 411 @./$(BIN_NAME) $(TEST_INPUT)/attrib.yue -o $(GEN_OUTPUT)/5.1/attrib.lua --target=5.1
413 @./$(BIN_NAME) $(TEST_INPUT)/literals.yue -o $(GEN_OUTPUT)/5.1/literals.lua --target=5.1
414 @./$(BIN_NAME) $(TEST_INPUT)/test/loops_spec.yue -o $(GEN_OUTPUT)/5.1/test/loops_spec.lua --target=5.1 412 @./$(BIN_NAME) $(TEST_INPUT)/test/loops_spec.yue -o $(GEN_OUTPUT)/5.1/test/loops_spec.lua --target=5.1
415 @./$(BIN_NAME) -e spec/inputs/compile_doc.yue $(GEN_OUTPUT) 413 @./$(BIN_NAME) -e spec/inputs/compile_doc.yue $(GEN_OUTPUT)
416 @echo -en "Compile time: " 414 @echo -en "Compile time: "
diff --git a/spec/inputs/backcall.yue b/spec/inputs/backcall.yue
index 8aadc71..e6b8c21 100644
--- a/spec/inputs/backcall.yue
+++ b/spec/inputs/backcall.yue
@@ -13,9 +13,9 @@ do
13 x > 2 13 x > 2
14 14
15do 15do
16 (data) <- http?.get "ajaxtest" 16 data <- http?.get "ajaxtest"
17 body[".result"]\html data 17 body[".result"]\html data
18 (processed) <- http.post "ajaxprocess", data 18 processed <- http.post "ajaxprocess", data
19 body[".result"]\append processed 19 body[".result"]\append processed
20 <- setTimeout 1000 20 <- setTimeout 1000
21 print "done" 21 print "done"
diff --git a/spec/inputs/destructure.yue b/spec/inputs/destructure.yue
index 674dfe4..b6250d0 100644
--- a/spec/inputs/destructure.yue
+++ b/spec/inputs/destructure.yue
@@ -94,7 +94,7 @@ do
94-- 94--
95 95
96do 96do
97 with {a,b} = thing 97 with {a,b} := thing
98 print a, b 98 print a, b
99 99
100 100
@@ -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/funcs.yue b/spec/inputs/funcs.yue
index e647edc..6b1669b 100644
--- a/spec/inputs/funcs.yue
+++ b/spec/inputs/funcs.yue
@@ -193,4 +193,35 @@ do
193 func = (): -> check 123 193 func = (): -> check 123
194 print func! -- get nil 194 print func! -- get nil
195 195
196do
197 f = ({:a, :b, :c}) -> print a, b, c
198 f = (:a, :b, :c) -> print a, b, c
199 g = (x, :y) -> print x, y
200 i = ({a: ax = 0, b: by = 0}) -> print ax, by
201 j = (name, {id: uid = "n/a", :role = "guest"}) -> print name, uid, role
202 m = ({user: {:name, :age}, meta: {:ver = 1}}) -> print name, age, ver
203 m1 = ({user: {:name, :age}, :meta = {}}) -> print name, age, meta and meta.ver or "nil"
204 new = ({:name = "anon", :age = 0}) =>
205 @name = name
206 @age = age
207 set = ({:name = @name, :age = @age}) =>
208 @name = name
209 @age = age
210 logKV = ({:k, :v}, ...) ->
211 print "kv:", k, v
212 print "rest count:", select "#", ...
213 macro gen = (fname) -> |
214 #{fname} = ({:a, :b = 0}) -> print a, b
215 $gen foo
216 t1 = (:a, x) -> print a, x
217 t2 = (:a) -> print a
218 w = (
219 id
220 {:x = 0, :y = 0}
221 :flag
222 ) ->
223 print id, x, y, flag
224 g1 = ({:a, a: ax}) -> print a, ax
225 g4 = ({:a, :b, ...rest}) -> print a, b
226
196nil 227nil
diff --git a/spec/inputs/global.yue b/spec/inputs/global.yue
index ce1cc15..4e3b8aa 100644
--- a/spec/inputs/global.yue
+++ b/spec/inputs/global.yue
@@ -82,3 +82,9 @@ do
82 FooBar = "pascal case" 82 FooBar = "pascal case"
83 FOOBAR = "all uppercase" 83 FOOBAR = "all uppercase"
84 84
85do
86 global const class A
87 global const Flag = 1
88 global const const, x, y = "const", 1, 2
89 global const math, table
90
diff --git a/spec/inputs/import.yue b/spec/inputs/import.yue
index b8ffc24..8982e6c 100644
--- a/spec/inputs/import.yue
+++ b/spec/inputs/import.yue
@@ -139,3 +139,13 @@ do
139 import "m" as {c: d} 139 import "m" as {c: d}
140 import "m" as {g, {<close>: i}} 140 import "m" as {g, {<close>: i}}
141 141
142do
143 import require
144 import string as stringlib
145 import string.format
146 import io.read as io_read
147
148 type = ->
149 import type as tp
150 import 月 as yue
151
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/loops.yue b/spec/inputs/loops.yue
index c5b28b3..5df10ca 100644
--- a/spec/inputs/loops.yue
+++ b/spec/inputs/loops.yue
@@ -213,3 +213,55 @@ do
213do 213do
214 until x := func 'a', b do 214 until x := func 'a', b do
215 print "false expected" 215 print "false expected"
216
217do
218 index = for i = 1, #tb
219 break i if tb[i]
220
221 f for i = 1, #tb
222 break i if tb[i]
223
224 f for i = 1, #tb
225 i if tb[i]
226
227 i = 1
228 ids = while tb[i]
229 i += 1
230 i - 1
231
232 i = 1
233 idx = while tb[i]
234 i += 1
235 break i - 1
236
237 f1 = ->
238 i = 1
239 f while tb[i]
240 i += 1
241 i - 1
242
243 i = 1
244 f while tb[i]
245 i += 1
246 break i - 1
247
248 list = for item in *items
249 switch item
250 when type: "A", :value
251 if value > 5
252 item
253
254do
255 repeat print 1 until true
256
257 x = repeat
258 a = func!
259 break a.x
260 until a.v
261
262 items = repeat
263 item = getItem!
264 break unless item
265 item if item.value > 0
266 until false
267
diff --git a/spec/inputs/macro.yue b/spec/inputs/macro.yue
index 5d5f1a9..191f09f 100644
--- a/spec/inputs/macro.yue
+++ b/spec/inputs/macro.yue
@@ -60,6 +60,11 @@ macro NumAndStr = (num, str) ->
60 60
61print $NumAndStr 123, 'xyz' 61print $NumAndStr 123, 'xyz'
62 62
63macro NumAndStr2 = (num`Num, str`SingleString) -> |
64 [#{num}, #{str}]
65
66print $NumAndStr2 456, 'abc'
67
63$asserts item == nil 68$asserts item == nil
64 69
65$myconfig false 70$myconfig false
@@ -100,13 +105,14 @@ macro filter = (items, action)->
100 $showMacro "filter", "[_ for _ in *#{items} when #{action}]" 105 $showMacro "filter", "[_ for _ in *#{items} when #{action}]"
101 106
102macro reduce = (items, def, action)-> 107macro reduce = (items, def, action)->
103 $showMacro "reduce", "if ##{items} == 0 108 $showMacro "reduce", |
104 #{def} 109 if ##{items} == 0
105else 110 #{def}
106 _1 = #{def} 111 else
107 for _2 in *#{items} 112 _1 = #{def}
108 _1 = #{action} 113 for _2 in *#{items}
109 _1" 114 _1 = #{action}
115 _1
110 116
111macro foreach = (items, action)-> 117macro foreach = (items, action)->
112 $showMacro "foreach", "for _ in *#{items} 118 $showMacro "foreach", "for _ in *#{items}
@@ -154,13 +160,15 @@ macro curry = (...)->
154f = $curry x,y,z,do 160f = $curry x,y,z,do
155 print x,y,z 161 print x,y,z
156 162
157macro get_inner = (var)-> "do 163macro get_inner = (var)-> |
158 a = 1 164 do
159 a + 1" 165 a = 1
166 a + 1
160 167
161macro get_inner_hygienic = (var)-> "(-> 168macro get_inner_hygienic = (var)-> |
162 local a = 1 169 (->
163 a + 1)!" 170 local a = 1
171 a + 1)!
164 172
165do 173do
166 a = 8 174 a = 8
@@ -196,6 +204,18 @@ end
196 204
197print x 205print x
198 206
207import "yue"
208macro lua = (code`YAMLMultiline) -> {
209 code: yue.loadstring(code)!
210 type: "lua"
211}
212
213$lua |
214 local function f2(a)
215 return a + 1
216 end
217 x = x + f2(3)
218
199macro def = (fname, ...)-> 219macro def = (fname, ...)->
200 args = {...} 220 args = {...}
201 last = table.remove args 221 last = table.remove args
@@ -317,7 +337,13 @@ $chainC(
317 Destroy! 337 Destroy!
318) 338)
319 339
320macro tb = -> "{'abc', a:123, <call>:=> 998}" 340macro tb = -> |
341 {
342 'abc'
343 a: 123
344 <call>: => 998
345 }
346
321print $tb[1], $tb.a, ($tb)!, $tb! 347print $tb[1], $tb.a, ($tb)!, $tb!
322 348
323print "current line: #{ $LINE }" 349print "current line: #{ $LINE }"
diff --git a/spec/inputs/macro_export.yue b/spec/inputs/macro_export.yue
index cc7d459..22905b5 100644
--- a/spec/inputs/macro_export.yue
+++ b/spec/inputs/macro_export.yue
@@ -8,13 +8,12 @@ export macro config = (debugging = true)->
8 "" 8 ""
9 9
10export macro showMacro = (name, res)-> 10export macro showMacro = (name, res)->
11 if debugMacro then " 11 if debugMacro then |
12do 12 do
13 txt = #{res} 13 txt = #{res}
14 print '[macro ' .. #{name} .. ']' 14 print '[macro #{name}]'
15 print txt 15 print txt
16 txt 16 txt
17"
18 else 17 else
19 res 18 res
20 19
@@ -35,14 +34,16 @@ export macro copy = (src, dst, ...)->
35 src != "_src_" and src != "_dst_" and dst != "_src_" and dst != "_dst_" 34 src != "_src_" and src != "_dst_" and dst != "_src_" and dst != "_dst_"
36 "copy targets can not be _src_ or _dst_" 35 "copy targets can not be _src_ or _dst_"
37 ) 36 )
38 " 37 copyFields = table.concat(
39do 38 ["_dst_.#{field} = _src_.#{field}" for field in *{...}]
40 local _src_, _dst_ 39 "\n\t\t\t"
41 with _dst_ = #{dst} 40 )
42 with _src_ = #{src} 41 |
43#{table.concat for field in *{...} do " 42 do
44 _dst_.#{field} = _src_.#{field} 43 local _src_, _dst_
45"}" 44 with _dst_ := #{dst}
45 with _src_ := #{src}
46 #{copyFields}
46 47
47export macro enum = (...) -> 48export macro enum = (...) ->
48 items = {...} 49 items = {...}
diff --git a/spec/inputs/macro_teal.yue b/spec/inputs/macro_teal.yue
index 0cfd862..e51bcd7 100644
--- a/spec/inputs/macro_teal.yue
+++ b/spec/inputs/macro_teal.yue
@@ -4,11 +4,16 @@ $ ->
4 options.target_extension = "tl" 4 options.target_extension = "tl"
5 package.path ..= ";./spec/lib/?.lua" 5 package.path ..= ";./spec/lib/?.lua"
6 6
7macro to_lua = (code)-> 7macro to_lua = (code)-> |
8 "require('yue').to_lua(#{code}, reserve_line_number:false, same_module:true)" 8 require('yue').to_lua #{code},
9 reserve_line_number: false
10 same_module: true
9 11
10macro trim = (name)-> 12macro trim = (name)-> |
11 "if result := #{name}\\match '[\\'\"](.*)[\\'\"]' then result else #{name}" 13 if result := #{name}\match '[\'"](.*)[\'"]'
14 result
15 else
16 #{name}
12 17
13export macro local = (decl, value = nil)-> 18export macro local = (decl, value = nil)->
14 import "yue" as {options:{:tl_enabled}} 19 import "yue" as {options:{:tl_enabled}}
diff --git a/spec/inputs/macro_todo.yue b/spec/inputs/macro_todo.yue
index 752c9cb..c9c8f77 100644
--- a/spec/inputs/macro_todo.yue
+++ b/spec/inputs/macro_todo.yue
@@ -5,9 +5,6 @@ export macro todoInner = (module, line, msg)->
5 type: "lua" 5 type: "lua"
6 } 6 }
7 7
8export macro todo = (msg)-> 8export macro todo = (msg)-> |
9 if msg 9 $todoInner $FILE, $LINE#{msg and ", #{msg}" or ""}
10 "$todoInner $FILE, $LINE, #{msg}"
11 else
12 "$todoInner $FILE, $LINE"
13 10
diff --git a/spec/inputs/props.yue b/spec/inputs/props.yue
new file mode 100644
index 0000000..bbb7aae
--- /dev/null
+++ b/spec/inputs/props.yue
@@ -0,0 +1,61 @@
1class Props
2 __index: (name): nil =>
3 cls = @.<>
4 if item := cls.__getter?[name] -- access properties
5 return item @
6 elseif item := rawget cls, name -- access member functions
7 return item
8 else
9 c = cls
10 while c := c.<> -- recursive to access base classes
11 if item := c.__getter?[name]
12 cls.__getter ??= {}
13 cls.__getter[name] = item -- cache base properties to class
14 return item @
15 elseif item := rawget c, name
16 rawset cls, name, item -- cache base member to class
17 return item
18
19 __newindex: (name, value) =>
20 cls = @.<>
21 if item := cls.__setter?[name] -- access properties
22 item @, value
23 else
24 c = cls
25 while c := c.<> -- recursive to access base classes
26 if item := c.__setter?[name]
27 cls.__setter ??= {}
28 cls.__setter[name] = item -- cache base property to class
29 item @, value
30 return
31 rawset @, name, value -- assign field to self
32
33 assignReadOnly = -> error "assigning a readonly property"
34
35 prop: (name, props) =>
36 {
37 :get
38 :set = assignReadOnly
39 } = props
40 if getter := rawget @__base, "__getter"
41 getter[name] = get
42 else
43 rawset @__base, "__getter", [name]: get
44 if setter := rawget @__base, "__setter"
45 setter[name] = set
46 else
47 rawset @__base, "__setter", [name]: set
48
49class A extends Props
50 @prop 'x'
51 get: => @_x + 1000
52 set: (v) => @_x = v
53 new: =>
54 @_x = 0
55
56class B extends A
57 @prop 'abc', get: => "hello"
58
59b = B!
60b.x = 999
61print b.x, b.abc
diff --git a/spec/inputs/string.yue b/spec/inputs/string.yue
index f91383e..1f0fba8 100644
--- a/spec/inputs/string.yue
+++ b/spec/inputs/string.yue
@@ -74,3 +74,76 @@ _ = "hello"
74something"hello"\world! 74something"hello"\world!
75something "hello"\world! 75something "hello"\world!
76 76
77do
78 str = |
79 key: value
80 str = |
81 config:
82 enabled: true
83 level: 5
84 str = |
85 header: start
86
87 footer: end
88 str = |
89 name: #{username}
90 str = |
91 count: #{total} items
92 str = |
93 user: #{name}
94 id: #{id}
95 str = |
96 path: "C:\\Program Files\\App"
97 desc: 'single "quote" test'
98 str = |
99 key: value
100 next: 123
101 str = |
102 list:
103 - "one"
104 - "two"
105 str = |
106 -- comment
107 content text
108 -- comment
109 str = |
110 #{1 + 2}
111 #{2 + 3}
112 #{"a" .. "b"}
113 obj =
114 settings: |
115 mode: #{mode}
116 flags:
117 - #{flag1}
118 - default
119 fn = -> |
120 Hello
121 name: #{userName}
122 str = |
123 result:
124 status: #{if ok then "pass" else "fail"}
125 code: #{code}
126 summary = |
127 date: #{os.date()}
128 values:
129 -
130 a: #{aVal}
131 b: #{bVal or defaultB}
132 msg = send |
133 Hello, #{user}!
134 Today is #{os.date("%A")}.
135 desc = do
136 prefix = "Result"
137 |
138 #{prefix}:
139 value: #{compute!}
140 (|
141 1
142 2
143 3
144 ) |> print
145
146export yaml = |
147 version: #{ver}
148 ok: true
149
diff --git a/spec/inputs/switch.yue b/spec/inputs/switch.yue
index 49d47f3..2b0669c 100644
--- a/spec/inputs/switch.yue
+++ b/spec/inputs/switch.yue
@@ -165,5 +165,128 @@ do
165 print item 165 print item
166 when [a = 1, b = "abc"] 166 when [a = 1, b = "abc"]
167 print a, b 167 print a, b
168nil
169 168
169do
170 switch tb
171 when [1, 2, 3]
172 print "1, 2, 3"
173 when [1, b, 3]
174 print "1, #{b}, 3"
175 when [1, 2, b = 3]
176 print "1, 2, #{b}"
177
178do
179 switch tb
180 when success: true, :result
181 print "success", result
182 when success: false
183 print "failed", result
184 else
185 print "invalid"
186
187do
188 switch tb
189 when {type: "success", :content}
190 print "success", content
191 when {type: "error", :content}
192 print "failed", content
193 else
194 print "invalid"
195
196do
197 switch tb
198 when [
199 {a: 1, b: 2}
200 {a: 3, b: 4}
201 {a: 5, b: 6}
202 fourth
203 ]
204 print "matched", fourth
205
206 switch tb
207 when [
208 {c: 1, d: 2}
209 {c: 3, d: 4}
210 {c: 5, d: 6}
211 ]
212 print "OK"
213 when [
214 _
215 _
216 {a: 1, b: 2}
217 {a: 3, b: 4}
218 {a: 5, b: 6}
219 sixth
220 ]
221 print "matched", sixth
222
223do
224 switch v := "hello"
225 when "hello"
226 print "matched hello"
227 else
228 print "not matched"
229 -- output: matched hello
230
231do
232 f = -> "ok"
233 switch val := f!
234 when "ok"
235 print "it's ok"
236 -- output: it's ok
237
238
239do
240 g = -> 42
241 switch result := g!
242 when 1, 2
243 print "small"
244 when 42
245 print "life universe everything"
246 else
247 print "other #{result}"
248 -- output: life universe everything
249
250do
251 check = ->
252 if true
253 "yes"
254 else
255 "no"
256
257 switch x := check!
258 when "yes"
259 print "affirmative"
260 else
261 print "negative"
262 -- output: affirmative
263
264do
265 t = (): tb ->
266 tb = {a: 1}
267 tb.a = 2
268
269 switch data := t!
270 when {a: 2}
271 print "matched"
272 else
273 print "not matched"
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
292nil
diff --git a/spec/inputs/tables.yue b/spec/inputs/tables.yue
index 0de8a8c..702e04a 100644
--- a/spec/inputs/tables.yue
+++ b/spec/inputs/tables.yue
@@ -245,6 +245,24 @@ menus =
245 click: -> 245 click: ->
246 } 246 }
247 247
248_ =
249 boolean:
250 - true
251 - false
252 float:
253 - 3.14
254 - -6.8523015e+5
255 int:
256 - 123
257 - -0b1010_0111_0100_1010_1110
258 null:
259 nodeName: 'node'
260 parent: nil
261 string:
262 - 'Hello world'
263 - "newline
264newline2"
265
248tb = {...other} 266tb = {...other}
249 267
250tbMix = { 268tbMix = {
diff --git a/spec/inputs/try_catch.yue b/spec/inputs/try_catch.yue
index 4e05bc6..6c29a52 100644
--- a/spec/inputs/try_catch.yue
+++ b/spec/inputs/try_catch.yue
@@ -62,6 +62,126 @@ f = ->
62 do 62 do
63 <- x 63 <- x
64 local tb, a, b, c 64 local tb, a, b, c
65 f = -> try tb.f a, b, c 65 f1 = -> try tb.f a, b, c
66
67 do
68 f1 = -> do
69 ok, ... = try func!
70 ...
71
72 do
73 local func
74 a, b, c = try? func!
75
76 do
77 a, b, c = try? func!
78
79 do
80 a = (try? func!) ?? "default"
81
82 do
83 f try? func!
84
85 do
86 f try?
87 print 123
88 func!
89 catch e
90 print e
91 e
66 92
67 nil 93 nil
94
95do
96 try
97 func 1, 2, 3
98 catch err
99 print err
100
101 try func 1, 2, 3
102 catch err
103 print err
104
105 try
106 print "trying"
107 func 1, 2, 3
108
109 do
110 success, result = try
111 func 1, 2, 3
112 catch err
113 print err
114
115 success, result = try func 1, 2, 3
116
117 tb = {}
118
119 try tb.func
120 try tb.func!
121 try tb.func()
122 try (tb.func!)
123 try (tb\func(1, 2, 3))
124
125 try tb.func 1
126 try tb.func(1)
127
128 if (try func 1
129 catch err
130 print err)
131 print "OK"
132
133 if try (func 1)
134 catch err
135 print err
136 print "OK"
137
138 do
139 if success, result := try func "abc", 123
140 print result
141
142 success, result = try func "abc", 123
143 catch err
144 print err
145
146 print result if success, result := try func "abc", 123
147 catch err
148 print err
149
150 do
151 try
152 func 1, 2, 3
153
154 try func 1, 2, 3
155
156 do
157 <- x
158 local tb, a, b, c
159 f1 = -> try tb.f a, b, c
160
161 do
162 f1 = -> do
163 ok, ... = try func!
164 ...
165
166 do
167 local func
168 a, b, c = try? func!
169
170 do
171 a, b, c = try? func!
172
173 do
174 a = (try? func!) ?? "default"
175
176 do
177 f try? func!
178
179 do
180 f try?
181 print 123
182 func!
183 catch e
184 print e
185 e
186
187nil
diff --git a/spec/inputs/unicode/destructure.yue b/spec/inputs/unicode/destructure.yue
index 3c3a369..a5ffd5d 100644
--- a/spec/inputs/unicode/destructure.yue
+++ b/spec/inputs/unicode/destructure.yue
@@ -84,7 +84,7 @@ do
84-- 84--
85 85
86do 86do
87 with {元素a,元素b} = 东西 87 with {元素a,元素b} := 东西
88 æ‰“å° å…ƒç´ a, 元素b 88 æ‰“å° å…ƒç´ a, 元素b
89 89
90 90
diff --git a/spec/inputs/unicode/macro_export.yue b/spec/inputs/unicode/macro_export.yue
index 3c9a942..56571cd 100644
--- a/spec/inputs/unicode/macro_export.yue
+++ b/spec/inputs/unicode/macro_export.yue
@@ -37,8 +37,8 @@ export macro å¤åˆ¶ = (æº, 目标, ...)->
37 " 37 "
38do 38do
39 local _æº_, _目标_ 39 local _æº_, _目标_
40 with _目标_ = #{目标} 40 with _目标_ := #{目标}
41 with _æº_ = #{æº} 41 with _æº_ := #{æº}
42#{table.concat for 字段 in *{...} do " 42#{table.concat for 字段 in *{...} do "
43 _目标_.#{字段} = _æº_.#{字段} 43 _目标_.#{字段} = _æº_.#{字段}
44"}" 44"}"
diff --git a/spec/inputs/unicode/with.yue b/spec/inputs/unicode/with.yue
index ecbfdab..3c15add 100644
--- a/spec/inputs/unicode/with.yue
+++ b/spec/inputs/unicode/with.yue
@@ -45,19 +45,19 @@ do
45 with å˜é‡a 45 with å˜é‡a
46 æ‰“å° .世界 46 æ‰“å° .世界
47 47
48 æ¨¡å— = with _æ¨¡å— = {} 48 æ¨¡å— = with _æ¨¡å— := {}
49 .事物 = "你好" 49 .事物 = "你好"
50 50
51 with å˜é‡a, å˜é‡b = 东西, 布 51 with å˜é‡a, å˜é‡b := 东西, 布
52 æ‰“å° .世界 52 æ‰“å° .世界
53 53
54 å˜é‡x = with å˜é‡a, å˜é‡b = 1, 2 54 å˜é‡x = with å˜é‡a, å˜é‡b := 1, 2
55 æ‰“å° å˜é‡a + å˜é‡b 55 æ‰“å° å˜é‡a + å˜é‡b
56 56
57 æ‰“å° with å˜é‡a, å˜é‡b = 1, 2 57 æ‰“å° with å˜é‡a, å˜é‡b := 1, 2
58 æ‰“å° å˜é‡a + å˜é‡b 58 æ‰“å° å˜é‡a + å˜é‡b
59 59
60 p = with 你好!.字段x, 世界!.字段y = 1, 2 60 p = with 你好!.字段x, 世界!.字段y := 1, 2
61 æ‰“å° å˜é‡a + å˜é‡b 61 æ‰“å° å˜é‡a + å˜é‡b
62 62
63-- 63--
@@ -68,16 +68,16 @@ do
68 å˜é‡x\大写! 68 å˜é‡x\大写!
69 69
70do 70do
71 with å˜é‡k = "ä¹”" 71 with å˜é‡k := "ä¹”"
72 æ‰“å° \大写! 72 æ‰“å° \大写!
73 73
74do 74do
75 with å˜é‡a,å˜é‡b,å˜é‡c = "", "", "" 75 with å˜é‡a,å˜é‡b,å˜é‡c := "", "", ""
76 æ‰“å° \大写! 76 æ‰“å° \大写!
77 77
78do 78do
79 å˜é‡a = "床铺" 79 å˜é‡a = "床铺"
80 with å˜é‡a,å˜é‡b,å˜é‡c = "", "", "" 80 with å˜é‡a,å˜é‡b,å˜é‡c := "", "", ""
81 æ‰“å° \大写! 81 æ‰“å° \大写!
82 82
83do 83do
@@ -85,7 +85,7 @@ do
85 æ‰“å° \大写! 85 æ‰“å° \大写!
86 86
87do 87do
88 with å˜é‡k.å˜é‡j = "ä¹”" 88 with å˜é‡k.å˜é‡j := "ä¹”"
89 æ‰“å° \大写! 89 æ‰“å° \大写!
90 90
91do 91do
@@ -96,7 +96,7 @@ do
96 96
97do 97do
98 with å˜é‡a 98 with å˜é‡a
99 with .b = 2 99 with .b := 2
100 æ‰“å° .c 100 æ‰“å° .c
101 101
102do 102do
@@ -131,12 +131,12 @@ do
131 131
132do 132do
133 global æŽ©ç  133 global 掩ç 
134 with? æŽ©ç  = 实心矩形 宽: w, 高: h, 颜色: 0x66000000 134 with? æŽ©ç  := 实心矩形 宽: w, 高: h, 颜色: 0x66000000
135 .触摸å¯ç”¨ = true 135 .触摸å¯ç”¨ = true
136 .åžå™¬è§¦æ‘¸ = true 136 .åžå™¬è§¦æ‘¸ = true
137 137
138do 138do
139 with? æŽ©ç  = 实心矩形 宽: w, 高: h, 颜色: 0x66000000 139 with? æŽ©ç  := 实心矩形 宽: w, 高: h, 颜色: 0x66000000
140 .触摸å¯ç”¨ = true 140 .触摸å¯ç”¨ = true
141 .åžå™¬è§¦æ‘¸ = true 141 .åžå™¬è§¦æ‘¸ = true
142 142
diff --git a/spec/inputs/with.yue b/spec/inputs/with.yue
index 19b7be1..2256833 100644
--- a/spec/inputs/with.yue
+++ b/spec/inputs/with.yue
@@ -48,21 +48,21 @@ do
48 with a -- only one value allowed 48 with a -- only one value allowed
49 print .world 49 print .world
50 50
51 mod = with _M = {} 51 mod = with _M := {}
52 .Thing = "hi" 52 .Thing = "hi"
53 53
54 -- operate on a only 54 -- operate on a only
55 with a, b = something, pooh 55 with a, b := something, pooh
56 print .world 56 print .world
57 57
58 x = with a, b = 1, 2 58 x = with a, b := 1, 2
59 print a + b 59 print a + b
60 60
61 print with a, b = 1, 2 61 print with a, b := 1, 2
62 print a + b 62 print a + b
63 63
64 -- assignment lhs must be evaluated in the order they appear 64 -- assignment lhs must be evaluated in the order they appear
65 p = with hello!.x, world!.y = 1, 2 65 p = with hello!.x, world!.y := 1, 2
66 print a + b 66 print a + b
67 67
68-- 68--
@@ -73,16 +73,16 @@ do
73 x\upper! 73 x\upper!
74 74
75do 75do
76 with k = "jo" 76 with k := "jo"
77 print \upper! 77 print \upper!
78 78
79do 79do
80 with a,b,c = "", "", "" 80 with a,b,c := "", "", ""
81 print \upper! 81 print \upper!
82 82
83do 83do
84 a = "bunk" 84 a = "bunk"
85 with a,b,c = "", "", "" 85 with a,b,c := "", "", ""
86 print \upper! 86 print \upper!
87 87
88do 88do
@@ -90,7 +90,7 @@ do
90 print \upper! 90 print \upper!
91 91
92do 92do
93 with k.j = "jo" 93 with k.j := "jo"
94 print \upper! 94 print \upper!
95 95
96do 96do
@@ -103,7 +103,7 @@ do
103do 103do
104 with a 104 with a
105 -- nested `with`s with assignments should change the scope correctly 105 -- nested `with`s with assignments should change the scope correctly
106 with .b = 2 106 with .b := 2
107 print .c 107 print .c
108 108
109do 109do
@@ -138,12 +138,12 @@ do
138 138
139do 139do
140 global mask 140 global mask
141 with? mask = SolidRect width: w, height: h, color: 0x66000000 141 with? mask := SolidRect width: w, height: h, color: 0x66000000
142 .touchEnabled = true 142 .touchEnabled = true
143 .swallowTouches = true 143 .swallowTouches = true
144 144
145do 145do
146 with? mask = SolidRect width: w, height: h, color: 0x66000000 146 with? mask := SolidRect width: w, height: h, color: 0x66000000
147 .touchEnabled = true 147 .touchEnabled = true
148 .swallowTouches = true 148 .swallowTouches = true
149 149
@@ -152,4 +152,22 @@ do
152 return with {} 152 return with {}
153 return [123] 153 return [123]
154 154
155do
156 f with item
157 if .id > 0
158 break .content
159
160 a = with tb
161 if .v
162 break .a
163
164 a = while true
165 break with? tb
166 break 1
167
168do
169 a = for i = 1, 100
170 with? x := tb[i]
171 break x if .id := 1
172
155nil 173nil
diff --git a/spec/outputs/5.1/literals.lua b/spec/outputs/5.1/literals.lua
deleted file mode 100644
index 36c705a..0000000
--- a/spec/outputs/5.1/literals.lua
+++ /dev/null
@@ -1,44 +0,0 @@
1local _ = {
2 121,
3 121.2323,
4 121.2323e-1,
5 121.2323e13434,
6 2323E34,
7 0x12323,
8 0xfF2323,
9 0xabcdef,
10 0xABCDEF,
11 0XFBC400,
12 2.7365508487142853e-35,
13 0xABCP321,
14 2.4074124304840448e-35,
15 6.4326233113470805e-94,
16 0.1171875,
17 162.1875,
18 3.1415926535897931,
19 1,
20 8,
21 15,
22 201,
23 .2323,
24 .2323e-1,
25 .2323e13434,
26 1LL,
27 1ULL,
28 9332LL,
29 9332,
30 0x2aLL,
31 0x2aULL,
32 1000000.0000001,
33 1234e5678,
34 1234E-5678,
35 0xDEADBEEF,
36 [[ hello world ]],
37 [=[ hello world ]=],
38 [====[ hello world ]====],
39 "another world",
40 'what world',
41 "\n hello world\n ",
42 'yeah\n what is going on\n here is something cool'
43}
44return nil
diff --git a/spec/outputs/5.1/loops.lua b/spec/outputs/5.1/loops.lua
index 57b19be..e4f2871 100644
--- a/spec/outputs/5.1/loops.lua
+++ b/spec/outputs/5.1/loops.lua
@@ -60,8 +60,8 @@ do
60 local y = hello[_index_0] 60 local y = hello[_index_0]
61 if y % 2 == 0 then 61 if y % 2 == 0 then
62 _accum_0[_len_0] = y 62 _accum_0[_len_0] = y
63 _len_0 = _len_0 + 1
63 end 64 end
64 _len_0 = _len_0 + 1
65 end 65 end
66 x = _accum_0 66 x = _accum_0
67end 67end
@@ -132,13 +132,11 @@ do
132end 132end
133do 133do
134 local _accum_0 = { } 134 local _accum_0 = { }
135 local _len_0 = 1
136 local _list_2 = 3 135 local _list_2 = 3
137 for _index_0 = 1, #_list_2 do 136 for _index_0 = 1, #_list_2 do
138 local thing = _list_2[_index_0] 137 local thing = _list_2[_index_0]
139 y = "hello" 138 y = "hello"
140 break 139 break
141 _len_0 = _len_0 + 1
142 end 140 end
143 x = _accum_0 141 x = _accum_0
144end 142end
@@ -489,3 +487,131 @@ do
489 end 487 end
490 until false 488 until false
491end 489end
490local _anon_func_0 = function(i, tb)
491 local _accum_0 = { }
492 local _len_0 = 1
493 while tb[i] do
494 i = i + 1
495 _accum_0[_len_0] = i - 1
496 _len_0 = _len_0 + 1
497 end
498 return _accum_0
499end
500do
501 local index
502 do
503 local _accum_0
504 for i = 1, #tb do
505 if tb[i] then
506 _accum_0 = i
507 break
508 end
509 end
510 index = _accum_0
511 end
512 f((function()
513 local _accum_0
514 for i = 1, #tb do
515 if tb[i] then
516 _accum_0 = i
517 break
518 end
519 end
520 return _accum_0
521 end)())
522 f((function()
523 local _accum_0 = { }
524 local _len_0 = 1
525 for i = 1, #tb do
526 if tb[i] then
527 _accum_0[_len_0] = i
528 _len_0 = _len_0 + 1
529 end
530 end
531 return _accum_0
532 end)())
533 i = 1
534 local ids
535 do
536 local _accum_0 = { }
537 local _len_0 = 1
538 while tb[i] do
539 i = i + 1
540 _accum_0[_len_0] = i - 1
541 _len_0 = _len_0 + 1
542 end
543 ids = _accum_0
544 end
545 i = 1
546 local idx
547 do
548 local _accum_0
549 while tb[i] do
550 i = i + 1
551 _accum_0 = i - 1
552 break
553 end
554 idx = _accum_0
555 end
556 local f1
557 f1 = function()
558 i = 1
559 return f(_anon_func_0(i, tb))
560 end
561 i = 1
562 f((function()
563 local _accum_0
564 while tb[i] do
565 i = i + 1
566 _accum_0 = i - 1
567 break
568 end
569 return _accum_0
570 end)())
571 local _accum_0 = { }
572 local _len_0 = 1
573 local _list_3 = items
574 for _index_0 = 1, #_list_3 do
575 local item = _list_3[_index_0]
576 local _type_0 = type(item)
577 local _tab_0 = "table" == _type_0 or "userdata" == _type_0
578 if _tab_0 then
579 local value = item.value
580 if "A" == item.type and value ~= nil then
581 if value > 5 then
582 _accum_0[_len_0] = item
583 _len_0 = _len_0 + 1
584 end
585 end
586 end
587 end
588 list = _accum_0
589end
590do
591 repeat
592 print(1)
593 until true
594 do
595 local _accum_0
596 repeat
597 a = func()
598 _accum_0 = a.x
599 break
600 until a.v
601 x = _accum_0
602 end
603 local items
604 local _accum_0 = { }
605 local _len_0 = 1
606 repeat
607 local item = getItem()
608 if not item then
609 break
610 end
611 if item.value > 0 then
612 _accum_0[_len_0] = item
613 _len_0 = _len_0 + 1
614 end
615 until false
616 items = _accum_0
617end
diff --git a/spec/outputs/5.1/try_catch.lua b/spec/outputs/5.1/try_catch.lua
index efd92c6..d2b58bc 100644
--- a/spec/outputs/5.1/try_catch.lua
+++ b/spec/outputs/5.1/try_catch.lua
@@ -22,6 +22,43 @@ end
22local _anon_func_7 = function(a, b, c, tb) 22local _anon_func_7 = function(a, b, c, tb)
23 return tb.f(a, b, c) 23 return tb.f(a, b, c)
24end 24end
25local _anon_func_8 = function(_arg_0, ...)
26 local ok = _arg_0
27 return ...
28end
29local _anon_func_10 = function(_arg_0, ...)
30 local _ok_0 = _arg_0
31 if _ok_0 then
32 return ...
33 end
34end
35local _anon_func_9 = function(func, pcall)
36 return _anon_func_10(pcall(func))
37end
38local _anon_func_12 = function(_arg_0, ...)
39 local _ok_0 = _arg_0
40 if _ok_0 then
41 return ...
42 end
43end
44local _anon_func_11 = function(func, pcall)
45 return _anon_func_12(pcall(func))
46end
47local _anon_func_14 = function(_arg_0, ...)
48 local _ok_0 = _arg_0
49 if _ok_0 then
50 return ...
51 end
52end
53local _anon_func_13 = function(func, print, xpcall)
54 return _anon_func_14(xpcall(function()
55 print(123)
56 return func()
57 end, function(e)
58 print(e)
59 return e
60 end))
61end
25local f 62local f
26f = function() 63f = function()
27 xpcall(function() 64 xpcall(function()
@@ -104,10 +141,236 @@ f = function()
104 do 141 do
105 x(function() 142 x(function()
106 local tb, a, b, c 143 local tb, a, b, c
107 f = function() 144 local f1
145 f1 = function()
108 return pcall(_anon_func_7, a, b, c, tb) 146 return pcall(_anon_func_7, a, b, c, tb)
109 end 147 end
110 end) 148 end)
111 end 149 end
150 do
151 local f1
152 f1 = function()
153 do
154 return _anon_func_8(pcall(function()
155 return func()
156 end))
157 end
158 end
159 end
160 do
161 local func
162 local a, b, c
163 local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(func)
164 if _ok_0 then
165 a, b, c = _ret_0, _ret_1, _ret_2
166 end
167 end
168 do
169 local a, b, c
170 local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function()
171 return func()
172 end)
173 if _ok_0 then
174 a, b, c = _ret_0, _ret_1, _ret_2
175 end
176 end
177 do
178 local a
179 local _exp_0 = (_anon_func_9(func, pcall))
180 if _exp_0 ~= nil then
181 a = _exp_0
182 else
183 a = "default"
184 end
185 end
186 do
187 f(_anon_func_11(func, pcall))
188 end
189 do
190 f(_anon_func_13(func, print, xpcall))
191 end
112 return nil 192 return nil
113end 193end
194local _anon_func_15 = function(a, b, c, tb)
195 return tb.f(a, b, c)
196end
197local _anon_func_16 = function(_arg_0, ...)
198 local ok = _arg_0
199 return ...
200end
201do
202 xpcall(function()
203 return func(1, 2, 3)
204 end, function(err)
205 return print(err)
206 end)
207 xpcall(function()
208 return func(1, 2, 3)
209 end, function(err)
210 return print(err)
211 end)
212 pcall(function()
213 print("trying")
214 return func(1, 2, 3)
215 end)
216 do
217 local success, result = xpcall(function()
218 return func(1, 2, 3)
219 end, function(err)
220 return print(err)
221 end)
222 success, result = pcall(function()
223 return func(1, 2, 3)
224 end)
225 end
226 local tb = { }
227 pcall(function()
228 return tb.func
229 end)
230 pcall(function()
231 return tb.func()
232 end)
233 pcall(function()
234 return tb.func()
235 end)
236 pcall(function()
237 return (tb.func())
238 end)
239 pcall(function()
240 return (tb:func(1, 2, 3))
241 end)
242 pcall(function()
243 return tb.func(1)
244 end)
245 pcall(function()
246 return tb.func(1)
247 end)
248 if (xpcall(function()
249 return func(1)
250 end, function(err)
251 return print(err)
252 end)) then
253 print("OK")
254 end
255 if xpcall(function()
256 return (func(1))
257 end, function(err)
258 return print(err)
259 end) then
260 print("OK")
261 end
262 do
263 do
264 local success, result = pcall(function()
265 return func("abc", 123)
266 end)
267 if success then
268 print(result)
269 end
270 end
271 local success, result = xpcall(function()
272 return func("abc", 123)
273 end, function(err)
274 return print(err)
275 end)
276 success, result = xpcall(function()
277 return func("abc", 123)
278 end, function(err)
279 return print(err)
280 end)
281 if success then
282 print(result)
283 end
284 end
285 do
286 pcall(function()
287 return func(1, 2, 3)
288 end)
289 pcall(function()
290 return func(1, 2, 3)
291 end)
292 end
293 do
294 x(function()
295 local tb, a, b, c
296 local f1
297 f1 = function()
298 return pcall(_anon_func_15, a, b, c, tb)
299 end
300 end)
301 end
302 do
303 local f1
304 f1 = function()
305 do
306 return _anon_func_16(pcall(function()
307 return func()
308 end))
309 end
310 end
311 end
312 do
313 local func
314 local a, b, c
315 local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(func)
316 if _ok_0 then
317 a, b, c = _ret_0, _ret_1, _ret_2
318 end
319 end
320 do
321 local a, b, c
322 local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function()
323 return func()
324 end)
325 if _ok_0 then
326 a, b, c = _ret_0, _ret_1, _ret_2
327 end
328 end
329 do
330 local a
331 local _exp_0 = ((function()
332 return (function(_arg_0, ...)
333 local _ok_0 = _arg_0
334 if _ok_0 then
335 return ...
336 end
337 end)(pcall(function()
338 return func()
339 end))
340 end)())
341 if _exp_0 ~= nil then
342 a = _exp_0
343 else
344 a = "default"
345 end
346 end
347 do
348 f((function()
349 return (function(_arg_0, ...)
350 local _ok_0 = _arg_0
351 if _ok_0 then
352 return ...
353 end
354 end)(pcall(function()
355 return func()
356 end))
357 end)())
358 end
359 do
360 f((function()
361 return (function(_arg_0, ...)
362 local _ok_0 = _arg_0
363 if _ok_0 then
364 return ...
365 end
366 end)(xpcall(function()
367 print(123)
368 return func()
369 end, function(e)
370 print(e)
371 return e
372 end))
373 end)())
374 end
375end
376return nil
diff --git a/spec/outputs/assign.lua b/spec/outputs/assign.lua
index 162c5a8..89c5f8a 100644
--- a/spec/outputs/assign.lua
+++ b/spec/outputs/assign.lua
@@ -43,10 +43,8 @@ do
43 end 43 end
44end 44end
45local _anon_func_0 = function(print) 45local _anon_func_0 = function(print)
46 do 46 print(123)
47 print(123) 47 return { }
48 return { }
49 end
50end 48end
51return _(function() 49return _(function()
52 setmetatable(a, _anon_func_0(print)) 50 setmetatable(a, _anon_func_0(print))
diff --git a/spec/outputs/codes_from_doc.lua b/spec/outputs/codes_from_doc.lua
index f6d5d61..055e79b 100644
--- a/spec/outputs/codes_from_doc.lua
+++ b/spec/outputs/codes_from_doc.lua
@@ -20,6 +20,38 @@ local inventory = {
20 } 20 }
21 } 21 }
22} 22}
23local map
24map = function(arr, action)
25 local _accum_0 = { }
26 local _len_0 = 1
27 for _index_0 = 1, #arr do
28 local item = arr[_index_0]
29 _accum_0[_len_0] = action(item)
30 _len_0 = _len_0 + 1
31 end
32 return _accum_0
33end
34local filter
35filter = function(arr, cond)
36 local _accum_0 = { }
37 local _len_0 = 1
38 for _index_0 = 1, #arr do
39 local item = arr[_index_0]
40 if cond(item) then
41 _accum_0[_len_0] = item
42 _len_0 = _len_0 + 1
43 end
44 end
45 return _accum_0
46end
47local reduce
48reduce = function(arr, init, action)
49 for _index_0 = 1, #arr do
50 local item = arr[_index_0]
51 init = action(init, item)
52 end
53 return init
54end
23print(reduce(filter(map({ 55print(reduce(filter(map({
24 1, 56 1,
25 2, 57 2,
@@ -77,6 +109,12 @@ end
77print("yuescript") 109print("yuescript")
78print(3) 110print(3)
79print("Valid enum type:", "Static") 111print("Valid enum type:", "Static")
112do
113 print(123, "hello")
114end
115do
116 print(123, "hello")
117end
80if tb ~= nil then 118if tb ~= nil then
81 tb:func() 119 tb:func()
82end 120end
@@ -177,6 +215,16 @@ for _key_0, _value_0 in pairs(b) do
177 end 215 end
178end 216end
179merge = _tab_0 217merge = _tab_0
218local last
219do
220 local _item_0 = data.items
221 last = _item_0[#_item_0]
222end
223local second_last
224do
225 local _item_0 = data.items
226 second_last = _item_0[#_item_0 - 1]
227end
180local mt = { } 228local mt = { }
181local add 229local add
182add = function(self, right) 230add = function(self, right)
@@ -307,6 +355,14 @@ func({
307 2, 355 2,
308 3 356 3
309}) 357})
358local f
359f = function()
360 return {
361 1,
362 2,
363 3
364 }
365end
310local tb = { 366local tb = {
311 name = "abc", 367 name = "abc",
312 values = { 368 values = {
@@ -547,6 +603,59 @@ end
547local two, four 603local two, four
548local _obj_0 = items 604local _obj_0 = items
549two, four = _obj_0[2], _obj_0[4] 605two, four = _obj_0[2], _obj_0[4]
606local orders = {
607 "first",
608 "second",
609 "third",
610 "fourth",
611 "last"
612}
613local first, bulk, last = orders[1], (function()
614 local _accum_0 = { }
615 local _len_0 = 1
616 local _max_0 = #orders + -2 + 1
617 for _index_0 = 2, _max_0 do
618 local _item_0 = orders[_index_0]
619 _accum_0[_len_0] = _item_0
620 _len_0 = _len_0 + 1
621 end
622 return _accum_0
623end)(), orders[#orders]
624print(first)
625print(bulk)
626print(last)
627local first, rest
628do
629 local _obj_0 = orders
630 first, rest = _obj_0[1], (function()
631 local _accum_0 = { }
632 local _len_0 = 1
633 local _max_0 = #_obj_0
634 for _index_0 = 2, _max_0 do
635 local _item_0 = _obj_0[_index_0]
636 _accum_0[_len_0] = _item_0
637 _len_0 = _len_0 + 1
638 end
639 return _accum_0
640 end)()
641end
642local start, last
643do
644 local _obj_0 = orders
645 start, last = (function()
646 local _accum_0 = { }
647 local _len_0 = 1
648 local _max_0 = #_obj_0 + -2 + 1
649 for _index_0 = 1, _max_0 do
650 local _item_0 = _obj_0[_index_0]
651 _accum_0[_len_0] = _item_0
652 _len_0 = _len_0 + 1
653 end
654 return _accum_0
655 end)(), _obj_0[#_obj_0]
656end
657local _obj_0 = orders
658first, last = _obj_0[1], _obj_0[#_obj_0]
550local tuples = { 659local tuples = {
551 { 660 {
552 "hello", 661 "hello",
@@ -648,6 +757,56 @@ end)
648if success then 757if success then
649 print(result) 758 print(result)
650end 759end
760local a, b, c
761do
762 local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function()
763 return func()
764 end)
765 if _ok_0 then
766 a, b, c = _ret_0, _ret_1, _ret_2
767 end
768end
769do
770 local _exp_0 = ((function()
771 return (function(_arg_0, ...)
772 local _ok_0 = _arg_0
773 if _ok_0 then
774 return ...
775 end
776 end)(pcall(function()
777 return func()
778 end))
779 end)())
780 if _exp_0 ~= nil then
781 a = _exp_0
782 else
783 a = "default"
784 end
785end
786f((function()
787 return (function(_arg_0, ...)
788 local _ok_0 = _arg_0
789 if _ok_0 then
790 return ...
791 end
792 end)(pcall(function()
793 return func()
794 end))
795end)())
796f((function()
797 return (function(_arg_0, ...)
798 local _ok_0 = _arg_0
799 if _ok_0 then
800 return ...
801 end
802 end)(xpcall(function()
803 print(123)
804 return func()
805 end, function(e)
806 print(e)
807 return e
808 end))
809end)())
651local a <const> = 123 810local a <const> = 123
652local _ <close> = setmetatable({ }, { 811local _ <close> = setmetatable({ }, {
653 __close = function() 812 __close = function()
@@ -657,10 +816,19 @@ local _ <close> = setmetatable({ }, {
657local a, b, c, d 816local a, b, c, d
658local _obj_0 = tb 817local _obj_0 = tb
659a, b, c, d = _obj_0.a, _obj_0.b, _obj_0[1], _obj_0[2] 818a, b, c, d = _obj_0.a, _obj_0.b, _obj_0[1], _obj_0[2]
819Constant = 123
660local some_string = "Here is a string\n that has a line break in it." 820local some_string = "Here is a string\n that has a line break in it."
661print("I am " .. tostring(math.random() * 100) .. "% sure.") 821print("I am " .. tostring(math.random() * 100) .. "% sure.")
662local integer = 1000000 822local integer = 1000000
663local hex = 0xEFBBBF 823local hex = 0xEFBBBF
824local binary = 19
825local str = "key: value\nlist:\n - item1\n - " .. tostring(expr)
826local fn
827fn = function()
828 local str = "foo:\n bar: baz"
829 return str
830end
831local str = "path: \"C:\\Program Files\\App\"\nnote: 'He said: \"" .. tostring(Hello) .. "!\"'"
664local my_function 832local my_function
665my_function = function() end 833my_function = function() end
666my_function() 834my_function()
@@ -755,6 +923,36 @@ if func(1, 2, 3, "hello", "world") then
755 print("hello") 923 print("hello")
756 print("I am inside if") 924 print("I am inside if")
757end 925end
926local f1
927f1 = function(_arg_0)
928 local a, b, c
929 a, b, c = _arg_0.a, _arg_0.b, _arg_0.c
930 return print(a, b, c)
931end
932f1({
933 a = 1,
934 b = "2",
935 c = { }
936})
937local f2
938f2 = function(_arg_0, c)
939 local a1, b
940 a1, b = _arg_0.a, _arg_0.b
941 if a1 == nil then
942 a1 = 123
943 end
944 if b == nil then
945 b = 'abc'
946 end
947 if c == nil then
948 c = { }
949 end
950 return print(a1, b, c)
951end
952local arg1 = {
953 a = 0
954}
955f2(arg1, arg2)
758f(function() 956f(function()
759 return print("hello") 957 return print("hello")
760end) 958end)
@@ -970,8 +1168,7 @@ local slice
970local _accum_0 = { } 1168local _accum_0 = { }
971local _len_0 = 1 1169local _len_0 = 1
972local _list_0 = items 1170local _list_0 = items
973local _max_0 = 5 1171for _index_0 = 1, 5 do
974for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do
975 local item = _list_0[_index_0] 1172 local item = _list_0[_index_0]
976 _accum_0[_len_0] = item 1173 _accum_0[_len_0] = item
977 _len_0 = _len_0 + 1 1174 _len_0 = _len_0 + 1
@@ -981,7 +1178,8 @@ local slice
981local _accum_0 = { } 1178local _accum_0 = { }
982local _len_0 = 1 1179local _len_0 = 1
983local _list_0 = items 1180local _list_0 = items
984for _index_0 = 2, #_list_0 do 1181local _max_0 = #_list_0
1182for _index_0 = 2, _max_0 do
985 local item = _list_0[_index_0] 1183 local item = _list_0[_index_0]
986 _accum_0[_len_0] = item 1184 _accum_0[_len_0] = item
987 _len_0 = _len_0 + 1 1185 _len_0 = _len_0 + 1
@@ -991,12 +1189,46 @@ local slice
991local _accum_0 = { } 1189local _accum_0 = { }
992local _len_0 = 1 1190local _len_0 = 1
993local _list_0 = items 1191local _list_0 = items
994for _index_0 = 1, #_list_0, 2 do 1192local _max_0 = #_list_0
1193for _index_0 = 1, _max_0, 2 do
995 local item = _list_0[_index_0] 1194 local item = _list_0[_index_0]
996 _accum_0[_len_0] = item 1195 _accum_0[_len_0] = item
997 _len_0 = _len_0 + 1 1196 _len_0 = _len_0 + 1
998end 1197end
999slice = _accum_0 1198slice = _accum_0
1199local slice
1200local _accum_0 = { }
1201local _len_0 = 1
1202local _list_0 = items
1203local _min_0 = #_list_0 + -4 + 1
1204local _max_0 = #_list_0 + -1 + 1
1205for _index_0 = _min_0, _max_0 do
1206 local item = _list_0[_index_0]
1207 _accum_0[_len_0] = item
1208 _len_0 = _len_0 + 1
1209end
1210slice = _accum_0
1211local reverse_slice
1212local _accum_0 = { }
1213local _len_0 = 1
1214local _list_0 = items
1215local _min_0 = #_list_0 + -1 + 1
1216for _index_0 = _min_0, 1, -1 do
1217 local item = _list_0[_index_0]
1218 _accum_0[_len_0] = item
1219 _len_0 = _len_0 + 1
1220end
1221reverse_slice = _accum_0
1222local sub_list
1223local _accum_0 = { }
1224local _len_0 = 1
1225local _list_0 = items
1226for _index_0 = 2, 4 do
1227 local _item_0 = _list_0[_index_0]
1228 _accum_0[_len_0] = _item_0
1229 _len_0 = _len_0 + 1
1230end
1231sub_list = _accum_0
1000for i = 10, 20 do 1232for i = 10, 20 do
1001 print(i) 1233 print(i)
1002end 1234end
@@ -1007,8 +1239,7 @@ for key, value in pairs(object) do
1007 print(key, value) 1239 print(key, value)
1008end 1240end
1009local _list_0 = items 1241local _list_0 = items
1010local _max_0 = 4 1242for _index_0 = 2, 4 do
1011for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do
1012 local item = _list_0[_index_0] 1243 local item = _list_0[_index_0]
1013 print(item) 1244 print(item)
1014end 1245end
@@ -1026,12 +1257,24 @@ local _len_0 = 1
1026for i = 1, 20 do 1257for i = 1, 20 do
1027 if i % 2 == 0 then 1258 if i % 2 == 0 then
1028 _accum_0[_len_0] = i * 2 1259 _accum_0[_len_0] = i * 2
1260 _len_0 = _len_0 + 1
1029 else 1261 else
1030 _accum_0[_len_0] = i 1262 _accum_0[_len_0] = i
1263 _len_0 = _len_0 + 1
1031 end 1264 end
1032 _len_0 = _len_0 + 1
1033end 1265end
1034doubled_evens = _accum_0 1266doubled_evens = _accum_0
1267local first_large
1268local _accum_0
1269local _list_0 = numbers
1270for _index_0 = 1, #_list_0 do
1271 local n = _list_0[_index_0]
1272 if n > 10 then
1273 _accum_0 = n
1274 break
1275 end
1276end
1277first_large = _accum_0
1035local func_a 1278local func_a
1036func_a = function() 1279func_a = function()
1037 for i = 1, 10 do 1280 for i = 1, 10 do
@@ -1180,7 +1423,7 @@ if "Robert" == name then
1180elseif "Dan" == name or "Daniel" == name then 1423elseif "Dan" == name or "Daniel" == name then
1181 print("Your name, it's Dan") 1424 print("Your name, it's Dan")
1182else 1425else
1183 print("I don't know about your name") 1426 print("I don't know about you with name " .. tostring(name))
1184end 1427end
1185local b = 1 1428local b = 1
1186local next_number 1429local next_number
@@ -1280,6 +1523,192 @@ if _tab_0 then
1280 end 1523 end
1281 print("Vec2 " .. tostring(x) .. ", " .. tostring(y)) 1524 print("Vec2 " .. tostring(x) .. ", " .. tostring(y))
1282end 1525end
1526local _exp_0 = tb
1527local _type_0 = type(_exp_0)
1528local _tab_0 = "table" == _type_0 or "userdata" == _type_0
1529local _match_0 = false
1530if _tab_0 then
1531 if 1 == _exp_0[1] and 2 == _exp_0[2] and 3 == _exp_0[3] then
1532 _match_0 = true
1533 print("1, 2, 3")
1534 end
1535end
1536if not _match_0 then
1537 local _match_1 = false
1538 if _tab_0 then
1539 local b = _exp_0[2]
1540 if 1 == _exp_0[1] and b ~= nil and 3 == _exp_0[3] then
1541 _match_1 = true
1542 print("1, " .. tostring(b) .. ", 3")
1543 end
1544 end
1545 if not _match_1 then
1546 if _tab_0 then
1547 local b = _exp_0[3]
1548 if b == nil then
1549 b = 3
1550 end
1551 if 1 == _exp_0[1] and 2 == _exp_0[2] then
1552 print("1, 2, " .. tostring(b))
1553 end
1554 end
1555 end
1556end
1557local _exp_0 = tb
1558local _type_0 = type(_exp_0)
1559local _tab_0 = "table" == _type_0 or "userdata" == _type_0
1560local _match_0 = false
1561if _tab_0 then
1562 local result = _exp_0.result
1563 if true == _exp_0.success and result ~= nil then
1564 _match_0 = true
1565 print("success", result)
1566 end
1567end
1568if not _match_0 then
1569 local _match_1 = false
1570 if _tab_0 then
1571 if false == _exp_0.success then
1572 _match_1 = true
1573 print("failed", result)
1574 end
1575 end
1576 if not _match_1 then
1577 print("invalid")
1578 end
1579end
1580local _exp_0 = tb
1581local _type_0 = type(_exp_0)
1582local _tab_0 = "table" == _type_0 or "userdata" == _type_0
1583local _match_0 = false
1584if _tab_0 then
1585 local content
1586 do
1587 local _obj_0 = _exp_0.data
1588 local _type_1 = type(_obj_0)
1589 if "table" == _type_1 or "userdata" == _type_1 then
1590 content = _obj_0.content
1591 end
1592 end
1593 local _val_0
1594 do
1595 local _obj_0 = _exp_0.data
1596 if _obj_0 ~= nil then
1597 _val_0 = _obj_0.type
1598 end
1599 end
1600 if "success" == _val_0 and content ~= nil then
1601 _match_0 = true
1602 print("success", content)
1603 end
1604end
1605if not _match_0 then
1606 local _match_1 = false
1607 if _tab_0 then
1608 local content
1609 do
1610 local _obj_0 = _exp_0.data
1611 local _type_1 = type(_obj_0)
1612 if "table" == _type_1 or "userdata" == _type_1 then
1613 content = _obj_0.content
1614 end
1615 end
1616 local _val_0
1617 do
1618 local _obj_0 = _exp_0.data
1619 if _obj_0 ~= nil then
1620 _val_0 = _obj_0.type
1621 end
1622 end
1623 if "error" == _val_0 and content ~= nil then
1624 _match_1 = true
1625 print("failed", content)
1626 end
1627 end
1628 if not _match_1 then
1629 print("invalid")
1630 end
1631end
1632local _exp_0 = tb
1633local _type_0 = type(_exp_0)
1634local _tab_0 = "table" == _type_0 or "userdata" == _type_0
1635if _tab_0 then
1636 local fourth = _exp_0[4]
1637 local _val_0
1638 do
1639 local _obj_0 = _exp_0[1]
1640 if _obj_0 ~= nil then
1641 _val_0 = _obj_0.a
1642 end
1643 end
1644 local _val_1
1645 do
1646 local _obj_0 = _exp_0[1]
1647 if _obj_0 ~= nil then
1648 _val_1 = _obj_0.b
1649 end
1650 end
1651 local _val_2
1652 do
1653 local _obj_0 = _exp_0[2]
1654 if _obj_0 ~= nil then
1655 _val_2 = _obj_0.a
1656 end
1657 end
1658 local _val_3
1659 do
1660 local _obj_0 = _exp_0[2]
1661 if _obj_0 ~= nil then
1662 _val_3 = _obj_0.b
1663 end
1664 end
1665 local _val_4
1666 do
1667 local _obj_0 = _exp_0[3]
1668 if _obj_0 ~= nil then
1669 _val_4 = _obj_0.a
1670 end
1671 end
1672 local _val_5
1673 do
1674 local _obj_0 = _exp_0[3]
1675 if _obj_0 ~= nil then
1676 _val_5 = _obj_0.b
1677 end
1678 end
1679 if 1 == _val_0 and 2 == _val_1 and 3 == _val_2 and 4 == _val_3 and 5 == _val_4 and 6 == _val_5 and fourth ~= nil then
1680 print("matched", fourth)
1681 end
1682end
1683local segments = {
1684 "admin",
1685 "users",
1686 "logs",
1687 "view"
1688}
1689local _type_0 = type(segments)
1690local _tab_0 = "table" == _type_0 or "userdata" == _type_0
1691if _tab_0 then
1692 local groups
1693 do
1694 local _accum_0 = { }
1695 local _len_0 = 1
1696 local _max_0 = #segments + -3 + 1
1697 for _index_0 = 1, _max_0 do
1698 local _item_0 = segments[_index_0]
1699 _accum_0[_len_0] = _item_0
1700 _len_0 = _len_0 + 1
1701 end
1702 groups = _accum_0
1703 end
1704 local resource = segments[#segments - 1]
1705 local action = segments[#segments]
1706 if resource ~= nil and action ~= nil then
1707 print("Group:", groups)
1708 print("Resource:", resource)
1709 print("Action:", action)
1710 end
1711end
1283local Inventory 1712local Inventory
1284local _class_0 1713local _class_0
1285local _base_0 = { 1714local _base_0 = {
@@ -1936,6 +2365,10 @@ do
1936 _with_1["key-name"] = value 2365 _with_1["key-name"] = value
1937end 2366end
1938_with_0[#_with_0 + 1] = "abc" 2367_with_0[#_with_0 + 1] = "abc"
2368local _with_0 = obj
2369if _with_0 ~= nil then
2370 print(obj.name)
2371end
1939do 2372do
1940 local var = "hello" 2373 local var = "hello"
1941 print(var) 2374 print(var)
@@ -2026,6 +2459,38 @@ local inventory = {
2026 } 2459 }
2027 } 2460 }
2028} 2461}
2462local map
2463map = function(arr, action)
2464 local _accum_0 = { }
2465 local _len_0 = 1
2466 for _index_0 = 1, #arr do
2467 local item = arr[_index_0]
2468 _accum_0[_len_0] = action(item)
2469 _len_0 = _len_0 + 1
2470 end
2471 return _accum_0
2472end
2473local filter
2474filter = function(arr, cond)
2475 local _accum_0 = { }
2476 local _len_0 = 1
2477 for _index_0 = 1, #arr do
2478 local item = arr[_index_0]
2479 if cond(item) then
2480 _accum_0[_len_0] = item
2481 _len_0 = _len_0 + 1
2482 end
2483 end
2484 return _accum_0
2485end
2486local reduce
2487reduce = function(arr, init, action)
2488 for _index_0 = 1, #arr do
2489 local item = arr[_index_0]
2490 init = action(init, item)
2491 end
2492 return init
2493end
2029print(reduce(filter(map({ 2494print(reduce(filter(map({
2030 1, 2495 1,
2031 2, 2496 2,
@@ -2083,6 +2548,12 @@ end
2083print("yuescript") 2548print("yuescript")
2084print(3) 2549print(3)
2085print("Valid enum type:", "Static") 2550print("Valid enum type:", "Static")
2551do
2552 print(123, "hello")
2553end
2554do
2555 print(123, "hello")
2556end
2086if tb ~= nil then 2557if tb ~= nil then
2087 tb:func() 2558 tb:func()
2088end 2559end
@@ -2183,6 +2654,16 @@ for _key_0, _value_0 in pairs(b) do
2183 end 2654 end
2184end 2655end
2185merge = _tab_0 2656merge = _tab_0
2657local last
2658do
2659 local _item_0 = data.items
2660 last = _item_0[#_item_0]
2661end
2662local second_last
2663do
2664 local _item_0 = data.items
2665 second_last = _item_0[#_item_0 - 1]
2666end
2186local mt = { } 2667local mt = { }
2187local add 2668local add
2188add = function(self, right) 2669add = function(self, right)
@@ -2313,6 +2794,14 @@ func({
2313 2, 2794 2,
2314 3 2795 3
2315}) 2796})
2797local f
2798f = function()
2799 return {
2800 1,
2801 2,
2802 3
2803 }
2804end
2316local tb = { 2805local tb = {
2317 name = "abc", 2806 name = "abc",
2318 values = { 2807 values = {
@@ -2553,6 +3042,59 @@ end
2553local two, four 3042local two, four
2554local _obj_0 = items 3043local _obj_0 = items
2555two, four = _obj_0[2], _obj_0[4] 3044two, four = _obj_0[2], _obj_0[4]
3045local orders = {
3046 "first",
3047 "second",
3048 "third",
3049 "fourth",
3050 "last"
3051}
3052local first, bulk, last = orders[1], (function()
3053 local _accum_0 = { }
3054 local _len_0 = 1
3055 local _max_0 = #orders + -2 + 1
3056 for _index_0 = 2, _max_0 do
3057 local _item_0 = orders[_index_0]
3058 _accum_0[_len_0] = _item_0
3059 _len_0 = _len_0 + 1
3060 end
3061 return _accum_0
3062end)(), orders[#orders]
3063print(first)
3064print(bulk)
3065print(last)
3066local first, rest
3067do
3068 local _obj_0 = orders
3069 first, rest = _obj_0[1], (function()
3070 local _accum_0 = { }
3071 local _len_0 = 1
3072 local _max_0 = #_obj_0
3073 for _index_0 = 2, _max_0 do
3074 local _item_0 = _obj_0[_index_0]
3075 _accum_0[_len_0] = _item_0
3076 _len_0 = _len_0 + 1
3077 end
3078 return _accum_0
3079 end)()
3080end
3081local start, last
3082do
3083 local _obj_0 = orders
3084 start, last = (function()
3085 local _accum_0 = { }
3086 local _len_0 = 1
3087 local _max_0 = #_obj_0 + -2 + 1
3088 for _index_0 = 1, _max_0 do
3089 local _item_0 = _obj_0[_index_0]
3090 _accum_0[_len_0] = _item_0
3091 _len_0 = _len_0 + 1
3092 end
3093 return _accum_0
3094 end)(), _obj_0[#_obj_0]
3095end
3096local _obj_0 = orders
3097first, last = _obj_0[1], _obj_0[#_obj_0]
2556local tuples = { 3098local tuples = {
2557 { 3099 {
2558 "hello", 3100 "hello",
@@ -2654,6 +3196,56 @@ end)
2654if success then 3196if success then
2655 print(result) 3197 print(result)
2656end 3198end
3199local a, b, c
3200do
3201 local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function()
3202 return func()
3203 end)
3204 if _ok_0 then
3205 a, b, c = _ret_0, _ret_1, _ret_2
3206 end
3207end
3208do
3209 local _exp_0 = ((function()
3210 return (function(_arg_0, ...)
3211 local _ok_0 = _arg_0
3212 if _ok_0 then
3213 return ...
3214 end
3215 end)(pcall(function()
3216 return func()
3217 end))
3218 end)())
3219 if _exp_0 ~= nil then
3220 a = _exp_0
3221 else
3222 a = "default"
3223 end
3224end
3225f((function()
3226 return (function(_arg_0, ...)
3227 local _ok_0 = _arg_0
3228 if _ok_0 then
3229 return ...
3230 end
3231 end)(pcall(function()
3232 return func()
3233 end))
3234end)())
3235f((function()
3236 return (function(_arg_0, ...)
3237 local _ok_0 = _arg_0
3238 if _ok_0 then
3239 return ...
3240 end
3241 end)(xpcall(function()
3242 print(123)
3243 return func()
3244 end, function(e)
3245 print(e)
3246 return e
3247 end))
3248end)())
2657local a <const> = 123 3249local a <const> = 123
2658local _ <close> = setmetatable({ }, { 3250local _ <close> = setmetatable({ }, {
2659 __close = function() 3251 __close = function()
@@ -2663,10 +3255,19 @@ local _ <close> = setmetatable({ }, {
2663local a, b, c, d 3255local a, b, c, d
2664local _obj_0 = tb 3256local _obj_0 = tb
2665a, b, c, d = _obj_0.a, _obj_0.b, _obj_0[1], _obj_0[2] 3257a, b, c, d = _obj_0.a, _obj_0.b, _obj_0[1], _obj_0[2]
3258Constant = 123
2666local some_string = "Here is a string\n that has a line break in it." 3259local some_string = "Here is a string\n that has a line break in it."
2667print("I am " .. tostring(math.random() * 100) .. "% sure.") 3260print("I am " .. tostring(math.random() * 100) .. "% sure.")
2668local integer = 1000000 3261local integer = 1000000
2669local hex = 0xEFBBBF 3262local hex = 0xEFBBBF
3263local binary = 19
3264local str = "key: value\nlist:\n - item1\n - " .. tostring(expr)
3265local fn
3266fn = function()
3267 local str = "foo:\n bar: baz"
3268 return str
3269end
3270local str = "path: \"C:\\Program Files\\App\"\nnote: 'He said: \"" .. tostring(Hello) .. "!\"'"
2670local my_function 3271local my_function
2671my_function = function() end 3272my_function = function() end
2672my_function() 3273my_function()
@@ -2761,6 +3362,66 @@ if func(1, 2, 3, "hello", "world") then
2761 print("hello") 3362 print("hello")
2762 print("I am inside if") 3363 print("I am inside if")
2763end 3364end
3365local f1
3366f1 = function(_arg_0)
3367 local a, b, c
3368 a, b, c = _arg_0.a, _arg_0.b, _arg_0.c
3369 return print(a, b, c)
3370end
3371f1({
3372 a = 1,
3373 b = "2",
3374 c = { }
3375})
3376local f2
3377f2 = function(_arg_0, c)
3378 local a1, b
3379 a1, b = _arg_0.a, _arg_0.b
3380 if a1 == nil then
3381 a1 = 123
3382 end
3383 if b == nil then
3384 b = 'abc'
3385 end
3386 if c == nil then
3387 c = { }
3388 end
3389end
3390print(a1, b, c)
3391local arg1 = {
3392 a = 0
3393}
3394f2(arg1, arg2)
3395local findFirstEven
3396findFirstEven = function(list)
3397 for _index_0 = 1, #list do
3398 local item = list[_index_0]
3399 if type(item) == "table" then
3400 for _index_1 = 1, #item do
3401 local sub = item[_index_1]
3402 if sub % 2 == 0 then
3403 return sub
3404 end
3405 end
3406 end
3407 end
3408 return nil
3409end
3410local findFirstEven
3411findFirstEven = function(list)
3412 for _index_0 = 1, #list do
3413 local item = list[_index_0]
3414 if type(item) == "table" then
3415 for _index_1 = 1, #item do
3416 local sub = item[_index_1]
3417 if sub % 2 == 0 then
3418 return sub
3419 end
3420 end
3421 end
3422 end
3423 return nil
3424end
2764f(function() 3425f(function()
2765 return print("hello") 3426 return print("hello")
2766end) 3427end)
@@ -2976,8 +3637,7 @@ local slice
2976local _accum_0 = { } 3637local _accum_0 = { }
2977local _len_0 = 1 3638local _len_0 = 1
2978local _list_0 = items 3639local _list_0 = items
2979local _max_0 = 5 3640for _index_0 = 1, 5 do
2980for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do
2981 local item = _list_0[_index_0] 3641 local item = _list_0[_index_0]
2982 _accum_0[_len_0] = item 3642 _accum_0[_len_0] = item
2983 _len_0 = _len_0 + 1 3643 _len_0 = _len_0 + 1
@@ -2987,7 +3647,8 @@ local slice
2987local _accum_0 = { } 3647local _accum_0 = { }
2988local _len_0 = 1 3648local _len_0 = 1
2989local _list_0 = items 3649local _list_0 = items
2990for _index_0 = 2, #_list_0 do 3650local _max_0 = #_list_0
3651for _index_0 = 2, _max_0 do
2991 local item = _list_0[_index_0] 3652 local item = _list_0[_index_0]
2992 _accum_0[_len_0] = item 3653 _accum_0[_len_0] = item
2993 _len_0 = _len_0 + 1 3654 _len_0 = _len_0 + 1
@@ -2997,12 +3658,46 @@ local slice
2997local _accum_0 = { } 3658local _accum_0 = { }
2998local _len_0 = 1 3659local _len_0 = 1
2999local _list_0 = items 3660local _list_0 = items
3000for _index_0 = 1, #_list_0, 2 do 3661local _max_0 = #_list_0
3662for _index_0 = 1, _max_0, 2 do
3001 local item = _list_0[_index_0] 3663 local item = _list_0[_index_0]
3002 _accum_0[_len_0] = item 3664 _accum_0[_len_0] = item
3003 _len_0 = _len_0 + 1 3665 _len_0 = _len_0 + 1
3004end 3666end
3005slice = _accum_0 3667slice = _accum_0
3668local slice
3669local _accum_0 = { }
3670local _len_0 = 1
3671local _list_0 = items
3672local _min_0 = #_list_0 + -4 + 1
3673local _max_0 = #_list_0 + -1 + 1
3674for _index_0 = _min_0, _max_0 do
3675 local item = _list_0[_index_0]
3676 _accum_0[_len_0] = item
3677 _len_0 = _len_0 + 1
3678end
3679slice = _accum_0
3680local reverse_slice
3681local _accum_0 = { }
3682local _len_0 = 1
3683local _list_0 = items
3684local _min_0 = #_list_0 + -1 + 1
3685for _index_0 = _min_0, 1, -1 do
3686 local item = _list_0[_index_0]
3687 _accum_0[_len_0] = item
3688 _len_0 = _len_0 + 1
3689end
3690reverse_slice = _accum_0
3691local sub_list
3692local _accum_0 = { }
3693local _len_0 = 1
3694local _list_0 = items
3695for _index_0 = 2, 4 do
3696 local _item_0 = _list_0[_index_0]
3697 _accum_0[_len_0] = _item_0
3698 _len_0 = _len_0 + 1
3699end
3700sub_list = _accum_0
3006for i = 10, 20 do 3701for i = 10, 20 do
3007 print(i) 3702 print(i)
3008end 3703end
@@ -3013,8 +3708,7 @@ for key, value in pairs(object) do
3013 print(key, value) 3708 print(key, value)
3014end 3709end
3015local _list_0 = items 3710local _list_0 = items
3016local _max_0 = 4 3711for _index_0 = 2, 4 do
3017for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do
3018 local item = _list_0[_index_0] 3712 local item = _list_0[_index_0]
3019 print(item) 3713 print(item)
3020end 3714end
@@ -3032,12 +3726,24 @@ local _len_0 = 1
3032for i = 1, 20 do 3726for i = 1, 20 do
3033 if i % 2 == 0 then 3727 if i % 2 == 0 then
3034 _accum_0[_len_0] = i * 2 3728 _accum_0[_len_0] = i * 2
3729 _len_0 = _len_0 + 1
3035 else 3730 else
3036 _accum_0[_len_0] = i 3731 _accum_0[_len_0] = i
3732 _len_0 = _len_0 + 1
3037 end 3733 end
3038 _len_0 = _len_0 + 1
3039end 3734end
3040doubled_evens = _accum_0 3735doubled_evens = _accum_0
3736local first_large
3737local _accum_0
3738local _list_0 = numbers
3739for _index_0 = 1, #_list_0 do
3740 local n = _list_0[_index_0]
3741 if n > 10 then
3742 _accum_0 = n
3743 break
3744 end
3745end
3746first_large = _accum_0
3041local func_a 3747local func_a
3042func_a = function() 3748func_a = function()
3043 for i = 1, 10 do 3749 for i = 1, 10 do
@@ -3186,7 +3892,7 @@ if "Robert" == name then
3186elseif "Dan" == name or "Daniel" == name then 3892elseif "Dan" == name or "Daniel" == name then
3187 print("Your name, it's Dan") 3893 print("Your name, it's Dan")
3188else 3894else
3189 print("I don't know about your name") 3895 print("I don't know about you with name " .. tostring(name))
3190end 3896end
3191local b = 1 3897local b = 1
3192local next_number 3898local next_number
@@ -3286,6 +3992,192 @@ if _tab_0 then
3286 end 3992 end
3287 print("Vec2 " .. tostring(x) .. ", " .. tostring(y)) 3993 print("Vec2 " .. tostring(x) .. ", " .. tostring(y))
3288end 3994end
3995local _exp_0 = tb
3996local _type_0 = type(_exp_0)
3997local _tab_0 = "table" == _type_0 or "userdata" == _type_0
3998local _match_0 = false
3999if _tab_0 then
4000 if 1 == _exp_0[1] and 2 == _exp_0[2] and 3 == _exp_0[3] then
4001 _match_0 = true
4002 print("1, 2, 3")
4003 end
4004end
4005if not _match_0 then
4006 local _match_1 = false
4007 if _tab_0 then
4008 local b = _exp_0[2]
4009 if 1 == _exp_0[1] and b ~= nil and 3 == _exp_0[3] then
4010 _match_1 = true
4011 print("1, " .. tostring(b) .. ", 3")
4012 end
4013 end
4014 if not _match_1 then
4015 if _tab_0 then
4016 local b = _exp_0[3]
4017 if b == nil then
4018 b = 3
4019 end
4020 if 1 == _exp_0[1] and 2 == _exp_0[2] then
4021 print("1, 2, " .. tostring(b))
4022 end
4023 end
4024 end
4025end
4026local _exp_0 = tb
4027local _type_0 = type(_exp_0)
4028local _tab_0 = "table" == _type_0 or "userdata" == _type_0
4029local _match_0 = false
4030if _tab_0 then
4031 local result = _exp_0.result
4032 if true == _exp_0.success and result ~= nil then
4033 _match_0 = true
4034 print("success", result)
4035 end
4036end
4037if not _match_0 then
4038 local _match_1 = false
4039 if _tab_0 then
4040 if false == _exp_0.success then
4041 _match_1 = true
4042 print("failed", result)
4043 end
4044 end
4045 if not _match_1 then
4046 print("invalid")
4047 end
4048end
4049local _exp_0 = tb
4050local _type_0 = type(_exp_0)
4051local _tab_0 = "table" == _type_0 or "userdata" == _type_0
4052local _match_0 = false
4053if _tab_0 then
4054 local content
4055 do
4056 local _obj_0 = _exp_0.data
4057 local _type_1 = type(_obj_0)
4058 if "table" == _type_1 or "userdata" == _type_1 then
4059 content = _obj_0.content
4060 end
4061 end
4062 local _val_0
4063 do
4064 local _obj_0 = _exp_0.data
4065 if _obj_0 ~= nil then
4066 _val_0 = _obj_0.type
4067 end
4068 end
4069 if "success" == _val_0 and content ~= nil then
4070 _match_0 = true
4071 print("success", content)
4072 end
4073end
4074if not _match_0 then
4075 local _match_1 = false
4076 if _tab_0 then
4077 local content
4078 do
4079 local _obj_0 = _exp_0.data
4080 local _type_1 = type(_obj_0)
4081 if "table" == _type_1 or "userdata" == _type_1 then
4082 content = _obj_0.content
4083 end
4084 end
4085 local _val_0
4086 do
4087 local _obj_0 = _exp_0.data
4088 if _obj_0 ~= nil then
4089 _val_0 = _obj_0.type
4090 end
4091 end
4092 if "error" == _val_0 and content ~= nil then
4093 _match_1 = true
4094 print("failed", content)
4095 end
4096 end
4097 if not _match_1 then
4098 print("invalid")
4099 end
4100end
4101local _exp_0 = tb
4102local _type_0 = type(_exp_0)
4103local _tab_0 = "table" == _type_0 or "userdata" == _type_0
4104if _tab_0 then
4105 local fourth = _exp_0[4]
4106 local _val_0
4107 do
4108 local _obj_0 = _exp_0[1]
4109 if _obj_0 ~= nil then
4110 _val_0 = _obj_0.a
4111 end
4112 end
4113 local _val_1
4114 do
4115 local _obj_0 = _exp_0[1]
4116 if _obj_0 ~= nil then
4117 _val_1 = _obj_0.b
4118 end
4119 end
4120 local _val_2
4121 do
4122 local _obj_0 = _exp_0[2]
4123 if _obj_0 ~= nil then
4124 _val_2 = _obj_0.a
4125 end
4126 end
4127 local _val_3
4128 do
4129 local _obj_0 = _exp_0[2]
4130 if _obj_0 ~= nil then
4131 _val_3 = _obj_0.b
4132 end
4133 end
4134 local _val_4
4135 do
4136 local _obj_0 = _exp_0[3]
4137 if _obj_0 ~= nil then
4138 _val_4 = _obj_0.a
4139 end
4140 end
4141 local _val_5
4142 do
4143 local _obj_0 = _exp_0[3]
4144 if _obj_0 ~= nil then
4145 _val_5 = _obj_0.b
4146 end
4147 end
4148 if 1 == _val_0 and 2 == _val_1 and 3 == _val_2 and 4 == _val_3 and 5 == _val_4 and 6 == _val_5 and fourth ~= nil then
4149 print("matched", fourth)
4150 end
4151end
4152local segments = {
4153 "admin",
4154 "users",
4155 "logs",
4156 "view"
4157}
4158local _type_0 = type(segments)
4159local _tab_0 = "table" == _type_0 or "userdata" == _type_0
4160if _tab_0 then
4161 local groups
4162 do
4163 local _accum_0 = { }
4164 local _len_0 = 1
4165 local _max_0 = #segments + -3 + 1
4166 for _index_0 = 1, _max_0 do
4167 local _item_0 = segments[_index_0]
4168 _accum_0[_len_0] = _item_0
4169 _len_0 = _len_0 + 1
4170 end
4171 groups = _accum_0
4172 end
4173 local resource = segments[#segments - 1]
4174 local action = segments[#segments]
4175 if resource ~= nil and action ~= nil then
4176 print("Group:", groups)
4177 print("Resource:", resource)
4178 print("Action:", action)
4179 end
4180end
3289local Inventory 4181local Inventory
3290local _class_0 4182local _class_0
3291local _base_0 = { 4183local _base_0 = {
@@ -3942,6 +4834,10 @@ do
3942 _with_1["key-name"] = value 4834 _with_1["key-name"] = value
3943end 4835end
3944_with_0[#_with_0 + 1] = "abc" 4836_with_0[#_with_0 + 1] = "abc"
4837local _with_0 = obj
4838if _with_0 ~= nil then
4839 print(obj.name)
4840end
3945do 4841do
3946 local var = "hello" 4842 local var = "hello"
3947 print(var) 4843 print(var)
diff --git a/spec/outputs/codes_from_doc_zh.lua b/spec/outputs/codes_from_doc_zh.lua
index acd41a0..de76829 100644
--- a/spec/outputs/codes_from_doc_zh.lua
+++ b/spec/outputs/codes_from_doc_zh.lua
@@ -20,6 +20,38 @@ local inventory = {
20 } 20 }
21 } 21 }
22} 22}
23local map
24map = function(arr, action)
25 local _accum_0 = { }
26 local _len_0 = 1
27 for _index_0 = 1, #arr do
28 local item = arr[_index_0]
29 _accum_0[_len_0] = action(item)
30 _len_0 = _len_0 + 1
31 end
32 return _accum_0
33end
34local filter
35filter = function(arr, cond)
36 local _accum_0 = { }
37 local _len_0 = 1
38 for _index_0 = 1, #arr do
39 local item = arr[_index_0]
40 if cond(item) then
41 _accum_0[_len_0] = item
42 _len_0 = _len_0 + 1
43 end
44 end
45 return _accum_0
46end
47local reduce
48reduce = function(arr, init, action)
49 for _index_0 = 1, #arr do
50 local item = arr[_index_0]
51 init = action(init, item)
52 end
53 return init
54end
23print(reduce(filter(map({ 55print(reduce(filter(map({
24 1, 56 1,
25 2, 57 2,
@@ -77,6 +109,12 @@ end
77print("yuescript") 109print("yuescript")
78print(3) 110print(3)
79print("有效的枚举类型:", "Static") 111print("有效的枚举类型:", "Static")
112do
113 print(123, "hello")
114end
115do
116 print(123, "hello")
117end
80if tb ~= nil then 118if tb ~= nil then
81 tb:func() 119 tb:func()
82end 120end
@@ -177,6 +215,16 @@ for _key_0, _value_0 in pairs(b) do
177 end 215 end
178end 216end
179merge = _tab_0 217merge = _tab_0
218local last
219do
220 local _item_0 = data.items
221 last = _item_0[#_item_0]
222end
223local second_last
224do
225 local _item_0 = data.items
226 second_last = _item_0[#_item_0 - 1]
227end
180local mt = { } 228local mt = { }
181local add 229local add
182add = function(self, right) 230add = function(self, right)
@@ -307,6 +355,14 @@ func({
307 2, 355 2,
308 3 356 3
309}) 357})
358local f
359f = function()
360 return {
361 1,
362 2,
363 3
364 }
365end
310local tb = { 366local tb = {
311 name = "abc", 367 name = "abc",
312 values = { 368 values = {
@@ -547,6 +603,59 @@ end
547local two, four 603local two, four
548local _obj_0 = items 604local _obj_0 = items
549two, four = _obj_0[2], _obj_0[4] 605two, four = _obj_0[2], _obj_0[4]
606local orders = {
607 "first",
608 "second",
609 "third",
610 "fourth",
611 "last"
612}
613local first, bulk, last = orders[1], (function()
614 local _accum_0 = { }
615 local _len_0 = 1
616 local _max_0 = #orders + -2 + 1
617 for _index_0 = 2, _max_0 do
618 local _item_0 = orders[_index_0]
619 _accum_0[_len_0] = _item_0
620 _len_0 = _len_0 + 1
621 end
622 return _accum_0
623end)(), orders[#orders]
624print(first)
625print(bulk)
626print(last)
627local first, rest
628do
629 local _obj_0 = orders
630 first, rest = _obj_0[1], (function()
631 local _accum_0 = { }
632 local _len_0 = 1
633 local _max_0 = #_obj_0
634 for _index_0 = 2, _max_0 do
635 local _item_0 = _obj_0[_index_0]
636 _accum_0[_len_0] = _item_0
637 _len_0 = _len_0 + 1
638 end
639 return _accum_0
640 end)()
641end
642local start, last
643do
644 local _obj_0 = orders
645 start, last = (function()
646 local _accum_0 = { }
647 local _len_0 = 1
648 local _max_0 = #_obj_0 + -2 + 1
649 for _index_0 = 1, _max_0 do
650 local _item_0 = _obj_0[_index_0]
651 _accum_0[_len_0] = _item_0
652 _len_0 = _len_0 + 1
653 end
654 return _accum_0
655 end)(), _obj_0[#_obj_0]
656end
657local _obj_0 = orders
658first, last = _obj_0[1], _obj_0[#_obj_0]
550local tuples = { 659local tuples = {
551 { 660 {
552 "hello", 661 "hello",
@@ -648,6 +757,56 @@ end)
648if success then 757if success then
649 print(result) 758 print(result)
650end 759end
760local a, b, c
761do
762 local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function()
763 return func()
764 end)
765 if _ok_0 then
766 a, b, c = _ret_0, _ret_1, _ret_2
767 end
768end
769do
770 local _exp_0 = ((function()
771 return (function(_arg_0, ...)
772 local _ok_0 = _arg_0
773 if _ok_0 then
774 return ...
775 end
776 end)(pcall(function()
777 return func()
778 end))
779 end)())
780 if _exp_0 ~= nil then
781 a = _exp_0
782 else
783 a = "default"
784 end
785end
786f((function()
787 return (function(_arg_0, ...)
788 local _ok_0 = _arg_0
789 if _ok_0 then
790 return ...
791 end
792 end)(pcall(function()
793 return func()
794 end))
795end)())
796f((function()
797 return (function(_arg_0, ...)
798 local _ok_0 = _arg_0
799 if _ok_0 then
800 return ...
801 end
802 end)(xpcall(function()
803 print(123)
804 return func()
805 end, function(e)
806 print(e)
807 return e
808 end))
809end)())
651local a <const> = 123 810local a <const> = 123
652local _ <close> = setmetatable({ }, { 811local _ <close> = setmetatable({ }, {
653 __close = function() 812 __close = function()
@@ -657,10 +816,19 @@ local _ <close> = setmetatable({ }, {
657local a, b, c, d 816local a, b, c, d
658local _obj_0 = tb 817local _obj_0 = tb
659a, b, c, d = _obj_0.a, _obj_0.b, _obj_0[1], _obj_0[2] 818a, b, c, d = _obj_0.a, _obj_0.b, _obj_0[1], _obj_0[2]
819Constant = 123
660local some_string = "这是一个字符串\n 并包括一个æ¢è¡Œã€‚" 820local some_string = "这是一个字符串\n 并包括一个æ¢è¡Œã€‚"
661print("我有" .. tostring(math.random() * 100) .. "%的把æ¡ã€‚") 821print("我有" .. tostring(math.random() * 100) .. "%的把æ¡ã€‚")
662local integer = 1000000 822local integer = 1000000
663local hex = 0xEFBBBF 823local hex = 0xEFBBBF
824local binary = 19
825local str = "key: value\nlist:\n - item1\n - " .. tostring(expr)
826local fn
827fn = function()
828 local str = "foo:\n bar: baz"
829 return str
830end
831local str = "path: \"C:\\Program Files\\App\"\nnote: 'He said: \"" .. tostring(Hello) .. "!\"'"
664local my_function 832local my_function
665my_function = function() end 833my_function = function() end
666my_function() 834my_function()
@@ -749,6 +917,36 @@ if func(1, 2, 3, "你好", "世界") then
749 print("hello") 917 print("hello")
750 print("我在if内部") 918 print("我在if内部")
751end 919end
920local f1
921f1 = function(_arg_0)
922 local a, b, c
923 a, b, c = _arg_0.a, _arg_0.b, _arg_0.c
924 return print(a, b, c)
925end
926f1({
927 a = 1,
928 b = "2",
929 c = { }
930})
931local f2
932f2 = function(_arg_0, c)
933 local a1, b
934 a1, b = _arg_0.a, _arg_0.b
935 if a1 == nil then
936 a1 = 123
937 end
938 if b == nil then
939 b = 'abc'
940 end
941 if c == nil then
942 c = { }
943 end
944 return print(a1, b, c)
945end
946local arg1 = {
947 a = 0
948}
949f2(arg1, arg2)
752f(function() 950f(function()
753 return print("hello") 951 return print("hello")
754end) 952end)
@@ -964,8 +1162,7 @@ local slice
964local _accum_0 = { } 1162local _accum_0 = { }
965local _len_0 = 1 1163local _len_0 = 1
966local _list_0 = items 1164local _list_0 = items
967local _max_0 = 5 1165for _index_0 = 1, 5 do
968for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do
969 local item = _list_0[_index_0] 1166 local item = _list_0[_index_0]
970 _accum_0[_len_0] = item 1167 _accum_0[_len_0] = item
971 _len_0 = _len_0 + 1 1168 _len_0 = _len_0 + 1
@@ -975,7 +1172,8 @@ local slice
975local _accum_0 = { } 1172local _accum_0 = { }
976local _len_0 = 1 1173local _len_0 = 1
977local _list_0 = items 1174local _list_0 = items
978for _index_0 = 2, #_list_0 do 1175local _max_0 = #_list_0
1176for _index_0 = 2, _max_0 do
979 local item = _list_0[_index_0] 1177 local item = _list_0[_index_0]
980 _accum_0[_len_0] = item 1178 _accum_0[_len_0] = item
981 _len_0 = _len_0 + 1 1179 _len_0 = _len_0 + 1
@@ -985,12 +1183,46 @@ local slice
985local _accum_0 = { } 1183local _accum_0 = { }
986local _len_0 = 1 1184local _len_0 = 1
987local _list_0 = items 1185local _list_0 = items
988for _index_0 = 1, #_list_0, 2 do 1186local _max_0 = #_list_0
1187for _index_0 = 1, _max_0, 2 do
989 local item = _list_0[_index_0] 1188 local item = _list_0[_index_0]
990 _accum_0[_len_0] = item 1189 _accum_0[_len_0] = item
991 _len_0 = _len_0 + 1 1190 _len_0 = _len_0 + 1
992end 1191end
993slice = _accum_0 1192slice = _accum_0
1193local slice
1194local _accum_0 = { }
1195local _len_0 = 1
1196local _list_0 = items
1197local _min_0 = #_list_0 + -4 + 1
1198local _max_0 = #_list_0 + -1 + 1
1199for _index_0 = _min_0, _max_0 do
1200 local item = _list_0[_index_0]
1201 _accum_0[_len_0] = item
1202 _len_0 = _len_0 + 1
1203end
1204slice = _accum_0
1205local reverse_slice
1206local _accum_0 = { }
1207local _len_0 = 1
1208local _list_0 = items
1209local _min_0 = #_list_0 + -1 + 1
1210for _index_0 = _min_0, 1, -1 do
1211 local item = _list_0[_index_0]
1212 _accum_0[_len_0] = item
1213 _len_0 = _len_0 + 1
1214end
1215reverse_slice = _accum_0
1216local sub_list
1217local _accum_0 = { }
1218local _len_0 = 1
1219local _list_0 = items
1220for _index_0 = 2, 4 do
1221 local _item_0 = _list_0[_index_0]
1222 _accum_0[_len_0] = _item_0
1223 _len_0 = _len_0 + 1
1224end
1225sub_list = _accum_0
994for i = 10, 20 do 1226for i = 10, 20 do
995 print(i) 1227 print(i)
996end 1228end
@@ -1001,8 +1233,7 @@ for key, value in pairs(object) do
1001 print(key, value) 1233 print(key, value)
1002end 1234end
1003local _list_0 = items 1235local _list_0 = items
1004local _max_0 = 4 1236for _index_0 = 2, 4 do
1005for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do
1006 local item = _list_0[_index_0] 1237 local item = _list_0[_index_0]
1007 print(item) 1238 print(item)
1008end 1239end
@@ -1020,12 +1251,24 @@ local _len_0 = 1
1020for i = 1, 20 do 1251for i = 1, 20 do
1021 if i % 2 == 0 then 1252 if i % 2 == 0 then
1022 _accum_0[_len_0] = i * 2 1253 _accum_0[_len_0] = i * 2
1254 _len_0 = _len_0 + 1
1023 else 1255 else
1024 _accum_0[_len_0] = i 1256 _accum_0[_len_0] = i
1257 _len_0 = _len_0 + 1
1025 end 1258 end
1026 _len_0 = _len_0 + 1
1027end 1259end
1028doubled_evens = _accum_0 1260doubled_evens = _accum_0
1261local first_large
1262local _accum_0
1263local _list_0 = numbers
1264for _index_0 = 1, #_list_0 do
1265 local n = _list_0[_index_0]
1266 if n > 10 then
1267 _accum_0 = n
1268 break
1269 end
1270end
1271first_large = _accum_0
1029local func_a 1272local func_a
1030func_a = function() 1273func_a = function()
1031 for i = 1, 10 do 1274 for i = 1, 10 do
@@ -1174,7 +1417,7 @@ if "Robert" == name then
1174elseif "Dan" == name or "Daniel" == name then 1417elseif "Dan" == name or "Daniel" == name then
1175 print("ä½ çš„å字是Dan") 1418 print("ä½ çš„å字是Dan")
1176else 1419else
1177 print("我ä¸çŸ¥é“ä½ çš„åå­—") 1420 print("我ä¸è®¤è¯†ä½ ï¼Œä½ çš„å字是" .. tostring(name))
1178end 1421end
1179local b = 1 1422local b = 1
1180local next_number 1423local next_number
@@ -1274,6 +1517,192 @@ if _tab_0 then
1274 end 1517 end
1275 print("Vec2 " .. tostring(x) .. ", " .. tostring(y)) 1518 print("Vec2 " .. tostring(x) .. ", " .. tostring(y))
1276end 1519end
1520local _exp_0 = tb
1521local _type_0 = type(_exp_0)
1522local _tab_0 = "table" == _type_0 or "userdata" == _type_0
1523local _match_0 = false
1524if _tab_0 then
1525 if 1 == _exp_0[1] and 2 == _exp_0[2] and 3 == _exp_0[3] then
1526 _match_0 = true
1527 print("1, 2, 3")
1528 end
1529end
1530if not _match_0 then
1531 local _match_1 = false
1532 if _tab_0 then
1533 local b = _exp_0[2]
1534 if 1 == _exp_0[1] and b ~= nil and 3 == _exp_0[3] then
1535 _match_1 = true
1536 print("1, " .. tostring(b) .. ", 3")
1537 end
1538 end
1539 if not _match_1 then
1540 if _tab_0 then
1541 local b = _exp_0[3]
1542 if b == nil then
1543 b = 3
1544 end
1545 if 1 == _exp_0[1] and 2 == _exp_0[2] then
1546 print("1, 2, " .. tostring(b))
1547 end
1548 end
1549 end
1550end
1551local _exp_0 = tb
1552local _type_0 = type(_exp_0)
1553local _tab_0 = "table" == _type_0 or "userdata" == _type_0
1554local _match_0 = false
1555if _tab_0 then
1556 local result = _exp_0.result
1557 if true == _exp_0.success and result ~= nil then
1558 _match_0 = true
1559 print("æˆåŠŸ", result)
1560 end
1561end
1562if not _match_0 then
1563 local _match_1 = false
1564 if _tab_0 then
1565 if false == _exp_0.success then
1566 _match_1 = true
1567 print("失败", result)
1568 end
1569 end
1570 if not _match_1 then
1571 print("无效值")
1572 end
1573end
1574local _exp_0 = tb
1575local _type_0 = type(_exp_0)
1576local _tab_0 = "table" == _type_0 or "userdata" == _type_0
1577local _match_0 = false
1578if _tab_0 then
1579 local content
1580 do
1581 local _obj_0 = _exp_0.data
1582 local _type_1 = type(_obj_0)
1583 if "table" == _type_1 or "userdata" == _type_1 then
1584 content = _obj_0.content
1585 end
1586 end
1587 local _val_0
1588 do
1589 local _obj_0 = _exp_0.data
1590 if _obj_0 ~= nil then
1591 _val_0 = _obj_0.type
1592 end
1593 end
1594 if "success" == _val_0 and content ~= nil then
1595 _match_0 = true
1596 print("æˆåŠŸ", content)
1597 end
1598end
1599if not _match_0 then
1600 local _match_1 = false
1601 if _tab_0 then
1602 local content
1603 do
1604 local _obj_0 = _exp_0.data
1605 local _type_1 = type(_obj_0)
1606 if "table" == _type_1 or "userdata" == _type_1 then
1607 content = _obj_0.content
1608 end
1609 end
1610 local _val_0
1611 do
1612 local _obj_0 = _exp_0.data
1613 if _obj_0 ~= nil then
1614 _val_0 = _obj_0.type
1615 end
1616 end
1617 if "error" == _val_0 and content ~= nil then
1618 _match_1 = true
1619 print("失败", content)
1620 end
1621 end
1622 if not _match_1 then
1623 print("无效值")
1624 end
1625end
1626local _exp_0 = tb
1627local _type_0 = type(_exp_0)
1628local _tab_0 = "table" == _type_0 or "userdata" == _type_0
1629if _tab_0 then
1630 local fourth = _exp_0[4]
1631 local _val_0
1632 do
1633 local _obj_0 = _exp_0[1]
1634 if _obj_0 ~= nil then
1635 _val_0 = _obj_0.a
1636 end
1637 end
1638 local _val_1
1639 do
1640 local _obj_0 = _exp_0[1]
1641 if _obj_0 ~= nil then
1642 _val_1 = _obj_0.b
1643 end
1644 end
1645 local _val_2
1646 do
1647 local _obj_0 = _exp_0[2]
1648 if _obj_0 ~= nil then
1649 _val_2 = _obj_0.a
1650 end
1651 end
1652 local _val_3
1653 do
1654 local _obj_0 = _exp_0[2]
1655 if _obj_0 ~= nil then
1656 _val_3 = _obj_0.b
1657 end
1658 end
1659 local _val_4
1660 do
1661 local _obj_0 = _exp_0[3]
1662 if _obj_0 ~= nil then
1663 _val_4 = _obj_0.a
1664 end
1665 end
1666 local _val_5
1667 do
1668 local _obj_0 = _exp_0[3]
1669 if _obj_0 ~= nil then
1670 _val_5 = _obj_0.b
1671 end
1672 end
1673 if 1 == _val_0 and 2 == _val_1 and 3 == _val_2 and 4 == _val_3 and 5 == _val_4 and 6 == _val_5 and fourth ~= nil then
1674 print("åŒ¹é…æˆåŠŸ", fourth)
1675 end
1676end
1677local segments = {
1678 "admin",
1679 "users",
1680 "logs",
1681 "view"
1682}
1683local _type_0 = type(segments)
1684local _tab_0 = "table" == _type_0 or "userdata" == _type_0
1685if _tab_0 then
1686 local groups
1687 do
1688 local _accum_0 = { }
1689 local _len_0 = 1
1690 local _max_0 = #segments + -3 + 1
1691 for _index_0 = 1, _max_0 do
1692 local _item_0 = segments[_index_0]
1693 _accum_0[_len_0] = _item_0
1694 _len_0 = _len_0 + 1
1695 end
1696 groups = _accum_0
1697 end
1698 local resource = segments[#segments - 1]
1699 local action = segments[#segments]
1700 if resource ~= nil and action ~= nil then
1701 print("Group:", groups)
1702 print("Resource:", resource)
1703 print("Action:", action)
1704 end
1705end
1277local Inventory 1706local Inventory
1278local _class_0 1707local _class_0
1279local _base_0 = { 1708local _base_0 = {
@@ -1930,6 +2359,10 @@ do
1930 _with_1["key-name"] = value 2359 _with_1["key-name"] = value
1931end 2360end
1932_with_0[#_with_0 + 1] = "abc" 2361_with_0[#_with_0 + 1] = "abc"
2362local _with_0 = obj
2363if _with_0 ~= nil then
2364 print(obj.name)
2365end
1933do 2366do
1934 local var = "hello" 2367 local var = "hello"
1935 print(var) 2368 print(var)
@@ -2020,6 +2453,38 @@ local inventory = {
2020 } 2453 }
2021 } 2454 }
2022} 2455}
2456local map
2457map = function(arr, action)
2458 local _accum_0 = { }
2459 local _len_0 = 1
2460 for _index_0 = 1, #arr do
2461 local item = arr[_index_0]
2462 _accum_0[_len_0] = action(item)
2463 _len_0 = _len_0 + 1
2464 end
2465 return _accum_0
2466end
2467local filter
2468filter = function(arr, cond)
2469 local _accum_0 = { }
2470 local _len_0 = 1
2471 for _index_0 = 1, #arr do
2472 local item = arr[_index_0]
2473 if cond(item) then
2474 _accum_0[_len_0] = item
2475 _len_0 = _len_0 + 1
2476 end
2477 end
2478 return _accum_0
2479end
2480local reduce
2481reduce = function(arr, init, action)
2482 for _index_0 = 1, #arr do
2483 local item = arr[_index_0]
2484 init = action(init, item)
2485 end
2486 return init
2487end
2023print(reduce(filter(map({ 2488print(reduce(filter(map({
2024 1, 2489 1,
2025 2, 2490 2,
@@ -2077,6 +2542,12 @@ end
2077print("yuescript") 2542print("yuescript")
2078print(3) 2543print(3)
2079print("有效的枚举类型:", "Static") 2544print("有效的枚举类型:", "Static")
2545do
2546 print(123, "hello")
2547end
2548do
2549 print(123, "hello")
2550end
2080if tb ~= nil then 2551if tb ~= nil then
2081 tb:func() 2552 tb:func()
2082end 2553end
@@ -2177,6 +2648,16 @@ for _key_0, _value_0 in pairs(b) do
2177 end 2648 end
2178end 2649end
2179merge = _tab_0 2650merge = _tab_0
2651local last
2652do
2653 local _item_0 = data.items
2654 last = _item_0[#_item_0]
2655end
2656local second_last
2657do
2658 local _item_0 = data.items
2659 second_last = _item_0[#_item_0 - 1]
2660end
2180local mt = { } 2661local mt = { }
2181local add 2662local add
2182add = function(self, right) 2663add = function(self, right)
@@ -2307,6 +2788,14 @@ func({
2307 2, 2788 2,
2308 3 2789 3
2309}) 2790})
2791local f
2792f = function()
2793 return {
2794 1,
2795 2,
2796 3
2797 }
2798end
2310local tb = { 2799local tb = {
2311 name = "abc", 2800 name = "abc",
2312 values = { 2801 values = {
@@ -2547,6 +3036,59 @@ end
2547local two, four 3036local two, four
2548local _obj_0 = items 3037local _obj_0 = items
2549two, four = _obj_0[2], _obj_0[4] 3038two, four = _obj_0[2], _obj_0[4]
3039local orders = {
3040 "first",
3041 "second",
3042 "third",
3043 "fourth",
3044 "last"
3045}
3046local first, bulk, last = orders[1], (function()
3047 local _accum_0 = { }
3048 local _len_0 = 1
3049 local _max_0 = #orders + -2 + 1
3050 for _index_0 = 2, _max_0 do
3051 local _item_0 = orders[_index_0]
3052 _accum_0[_len_0] = _item_0
3053 _len_0 = _len_0 + 1
3054 end
3055 return _accum_0
3056end)(), orders[#orders]
3057print(first)
3058print(bulk)
3059print(last)
3060local first, rest
3061do
3062 local _obj_0 = orders
3063 first, rest = _obj_0[1], (function()
3064 local _accum_0 = { }
3065 local _len_0 = 1
3066 local _max_0 = #_obj_0
3067 for _index_0 = 2, _max_0 do
3068 local _item_0 = _obj_0[_index_0]
3069 _accum_0[_len_0] = _item_0
3070 _len_0 = _len_0 + 1
3071 end
3072 return _accum_0
3073 end)()
3074end
3075local start, last
3076do
3077 local _obj_0 = orders
3078 start, last = (function()
3079 local _accum_0 = { }
3080 local _len_0 = 1
3081 local _max_0 = #_obj_0 + -2 + 1
3082 for _index_0 = 1, _max_0 do
3083 local _item_0 = _obj_0[_index_0]
3084 _accum_0[_len_0] = _item_0
3085 _len_0 = _len_0 + 1
3086 end
3087 return _accum_0
3088 end)(), _obj_0[#_obj_0]
3089end
3090local _obj_0 = orders
3091first, last = _obj_0[1], _obj_0[#_obj_0]
2550local tuples = { 3092local tuples = {
2551 { 3093 {
2552 "hello", 3094 "hello",
@@ -2648,6 +3190,56 @@ end)
2648if success then 3190if success then
2649 print(result) 3191 print(result)
2650end 3192end
3193local a, b, c
3194do
3195 local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function()
3196 return func()
3197 end)
3198 if _ok_0 then
3199 a, b, c = _ret_0, _ret_1, _ret_2
3200 end
3201end
3202do
3203 local _exp_0 = ((function()
3204 return (function(_arg_0, ...)
3205 local _ok_0 = _arg_0
3206 if _ok_0 then
3207 return ...
3208 end
3209 end)(pcall(function()
3210 return func()
3211 end))
3212 end)())
3213 if _exp_0 ~= nil then
3214 a = _exp_0
3215 else
3216 a = "default"
3217 end
3218end
3219f((function()
3220 return (function(_arg_0, ...)
3221 local _ok_0 = _arg_0
3222 if _ok_0 then
3223 return ...
3224 end
3225 end)(pcall(function()
3226 return func()
3227 end))
3228end)())
3229f((function()
3230 return (function(_arg_0, ...)
3231 local _ok_0 = _arg_0
3232 if _ok_0 then
3233 return ...
3234 end
3235 end)(xpcall(function()
3236 print(123)
3237 return func()
3238 end, function(e)
3239 print(e)
3240 return e
3241 end))
3242end)())
2651local a <const> = 123 3243local a <const> = 123
2652local _ <close> = setmetatable({ }, { 3244local _ <close> = setmetatable({ }, {
2653 __close = function() 3245 __close = function()
@@ -2657,10 +3249,19 @@ local _ <close> = setmetatable({ }, {
2657local a, b, c, d 3249local a, b, c, d
2658local _obj_0 = tb 3250local _obj_0 = tb
2659a, b, c, d = _obj_0.a, _obj_0.b, _obj_0[1], _obj_0[2] 3251a, b, c, d = _obj_0.a, _obj_0.b, _obj_0[1], _obj_0[2]
3252Constant = 123
2660local some_string = "这是一个字符串\n 并包括一个æ¢è¡Œã€‚" 3253local some_string = "这是一个字符串\n 并包括一个æ¢è¡Œã€‚"
2661print("我有" .. tostring(math.random() * 100) .. "%的把æ¡ã€‚") 3254print("我有" .. tostring(math.random() * 100) .. "%的把æ¡ã€‚")
2662local integer = 1000000 3255local integer = 1000000
2663local hex = 0xEFBBBF 3256local hex = 0xEFBBBF
3257local binary = 19
3258local str = "key: value\nlist:\n - item1\n - " .. tostring(expr)
3259local fn
3260fn = function()
3261 local str = "foo:\n bar: baz"
3262 return str
3263end
3264local str = "path: \"C:\\Program Files\\App\"\nnote: 'He said: \"" .. tostring(Hello) .. "!\"'"
2664local my_function 3265local my_function
2665my_function = function() end 3266my_function = function() end
2666my_function() 3267my_function()
@@ -2749,6 +3350,66 @@ if func(1, 2, 3, "你好", "世界") then
2749 print("你好") 3350 print("你好")
2750 print("我在if内部") 3351 print("我在if内部")
2751end 3352end
3353local f1
3354f1 = function(_arg_0)
3355 local a, b, c
3356 a, b, c = _arg_0.a, _arg_0.b, _arg_0.c
3357 return print(a, b, c)
3358end
3359f1({
3360 a = 1,
3361 b = "2",
3362 c = { }
3363})
3364local f2
3365f2 = function(_arg_0, c)
3366 local a1, b
3367 a1, b = _arg_0.a, _arg_0.b
3368 if a1 == nil then
3369 a1 = 123
3370 end
3371 if b == nil then
3372 b = 'abc'
3373 end
3374 if c == nil then
3375 c = { }
3376 end
3377 return print(a1, b, c)
3378end
3379local arg1 = {
3380 a = 0
3381}
3382f2(arg1, arg2)
3383local findFirstEven
3384findFirstEven = function(list)
3385 for _index_0 = 1, #list do
3386 local item = list[_index_0]
3387 if type(item) == "table" then
3388 for _index_1 = 1, #item do
3389 local sub = item[_index_1]
3390 if sub % 2 == 0 then
3391 return sub
3392 end
3393 end
3394 end
3395 end
3396 return nil
3397end
3398local findFirstEven
3399findFirstEven = function(list)
3400 for _index_0 = 1, #list do
3401 local item = list[_index_0]
3402 if type(item) == "table" then
3403 for _index_1 = 1, #item do
3404 local sub = item[_index_1]
3405 if sub % 2 == 0 then
3406 return sub
3407 end
3408 end
3409 end
3410 end
3411 return nil
3412end
2752f(function() 3413f(function()
2753 return print("hello") 3414 return print("hello")
2754end) 3415end)
@@ -2964,8 +3625,7 @@ local slice
2964local _accum_0 = { } 3625local _accum_0 = { }
2965local _len_0 = 1 3626local _len_0 = 1
2966local _list_0 = items 3627local _list_0 = items
2967local _max_0 = 5 3628for _index_0 = 1, 5 do
2968for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do
2969 local item = _list_0[_index_0] 3629 local item = _list_0[_index_0]
2970 _accum_0[_len_0] = item 3630 _accum_0[_len_0] = item
2971 _len_0 = _len_0 + 1 3631 _len_0 = _len_0 + 1
@@ -2975,7 +3635,8 @@ local slice
2975local _accum_0 = { } 3635local _accum_0 = { }
2976local _len_0 = 1 3636local _len_0 = 1
2977local _list_0 = items 3637local _list_0 = items
2978for _index_0 = 2, #_list_0 do 3638local _max_0 = #_list_0
3639for _index_0 = 2, _max_0 do
2979 local item = _list_0[_index_0] 3640 local item = _list_0[_index_0]
2980 _accum_0[_len_0] = item 3641 _accum_0[_len_0] = item
2981 _len_0 = _len_0 + 1 3642 _len_0 = _len_0 + 1
@@ -2985,12 +3646,46 @@ local slice
2985local _accum_0 = { } 3646local _accum_0 = { }
2986local _len_0 = 1 3647local _len_0 = 1
2987local _list_0 = items 3648local _list_0 = items
2988for _index_0 = 1, #_list_0, 2 do 3649local _max_0 = #_list_0
3650for _index_0 = 1, _max_0, 2 do
2989 local item = _list_0[_index_0] 3651 local item = _list_0[_index_0]
2990 _accum_0[_len_0] = item 3652 _accum_0[_len_0] = item
2991 _len_0 = _len_0 + 1 3653 _len_0 = _len_0 + 1
2992end 3654end
2993slice = _accum_0 3655slice = _accum_0
3656local slice
3657local _accum_0 = { }
3658local _len_0 = 1
3659local _list_0 = items
3660local _min_0 = #_list_0 + -4 + 1
3661local _max_0 = #_list_0 + -1 + 1
3662for _index_0 = _min_0, _max_0 do
3663 local item = _list_0[_index_0]
3664 _accum_0[_len_0] = item
3665 _len_0 = _len_0 + 1
3666end
3667slice = _accum_0
3668local reverse_slice
3669local _accum_0 = { }
3670local _len_0 = 1
3671local _list_0 = items
3672local _min_0 = #_list_0 + -1 + 1
3673for _index_0 = _min_0, 1, -1 do
3674 local item = _list_0[_index_0]
3675 _accum_0[_len_0] = item
3676 _len_0 = _len_0 + 1
3677end
3678reverse_slice = _accum_0
3679local sub_list
3680local _accum_0 = { }
3681local _len_0 = 1
3682local _list_0 = items
3683for _index_0 = 2, 4 do
3684 local _item_0 = _list_0[_index_0]
3685 _accum_0[_len_0] = _item_0
3686 _len_0 = _len_0 + 1
3687end
3688sub_list = _accum_0
2994for i = 10, 20 do 3689for i = 10, 20 do
2995 print(i) 3690 print(i)
2996end 3691end
@@ -3001,8 +3696,7 @@ for key, value in pairs(object) do
3001 print(key, value) 3696 print(key, value)
3002end 3697end
3003local _list_0 = items 3698local _list_0 = items
3004local _max_0 = 4 3699for _index_0 = 2, 4 do
3005for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do
3006 local item = _list_0[_index_0] 3700 local item = _list_0[_index_0]
3007 print(item) 3701 print(item)
3008end 3702end
@@ -3020,12 +3714,24 @@ local _len_0 = 1
3020for i = 1, 20 do 3714for i = 1, 20 do
3021 if i % 2 == 0 then 3715 if i % 2 == 0 then
3022 _accum_0[_len_0] = i * 2 3716 _accum_0[_len_0] = i * 2
3717 _len_0 = _len_0 + 1
3023 else 3718 else
3024 _accum_0[_len_0] = i 3719 _accum_0[_len_0] = i
3720 _len_0 = _len_0 + 1
3025 end 3721 end
3026 _len_0 = _len_0 + 1
3027end 3722end
3028doubled_evens = _accum_0 3723doubled_evens = _accum_0
3724local first_large
3725local _accum_0
3726local _list_0 = numbers
3727for _index_0 = 1, #_list_0 do
3728 local n = _list_0[_index_0]
3729 if n > 10 then
3730 _accum_0 = n
3731 break
3732 end
3733end
3734first_large = _accum_0
3029local func_a 3735local func_a
3030func_a = function() 3736func_a = function()
3031 for i = 1, 10 do 3737 for i = 1, 10 do
@@ -3174,7 +3880,7 @@ if "Robert" == name then
3174elseif "Dan" == name or "Daniel" == name then 3880elseif "Dan" == name or "Daniel" == name then
3175 print("ä½ çš„å字是Dan") 3881 print("ä½ çš„å字是Dan")
3176else 3882else
3177 print("我ä¸çŸ¥é“ä½ çš„åå­—") 3883 print("我ä¸è®¤è¯†ä½ ï¼Œä½ çš„å字是" .. tostring(name))
3178end 3884end
3179local b = 1 3885local b = 1
3180local next_number 3886local next_number
@@ -3274,6 +3980,192 @@ if _tab_0 then
3274 end 3980 end
3275 print("Vec2 " .. tostring(x) .. ", " .. tostring(y)) 3981 print("Vec2 " .. tostring(x) .. ", " .. tostring(y))
3276end 3982end
3983local _exp_0 = tb
3984local _type_0 = type(_exp_0)
3985local _tab_0 = "table" == _type_0 or "userdata" == _type_0
3986local _match_0 = false
3987if _tab_0 then
3988 if 1 == _exp_0[1] and 2 == _exp_0[2] and 3 == _exp_0[3] then
3989 _match_0 = true
3990 print("1, 2, 3")
3991 end
3992end
3993if not _match_0 then
3994 local _match_1 = false
3995 if _tab_0 then
3996 local b = _exp_0[2]
3997 if 1 == _exp_0[1] and b ~= nil and 3 == _exp_0[3] then
3998 _match_1 = true
3999 print("1, " .. tostring(b) .. ", 3")
4000 end
4001 end
4002 if not _match_1 then
4003 if _tab_0 then
4004 local b = _exp_0[3]
4005 if b == nil then
4006 b = 3
4007 end
4008 if 1 == _exp_0[1] and 2 == _exp_0[2] then
4009 print("1, 2, " .. tostring(b))
4010 end
4011 end
4012 end
4013end
4014local _exp_0 = tb
4015local _type_0 = type(_exp_0)
4016local _tab_0 = "table" == _type_0 or "userdata" == _type_0
4017local _match_0 = false
4018if _tab_0 then
4019 local result = _exp_0.result
4020 if true == _exp_0.success and result ~= nil then
4021 _match_0 = true
4022 print("æˆåŠŸ", result)
4023 end
4024end
4025if not _match_0 then
4026 local _match_1 = false
4027 if _tab_0 then
4028 if false == _exp_0.success then
4029 _match_1 = true
4030 print("失败", result)
4031 end
4032 end
4033 if not _match_1 then
4034 print("无效值")
4035 end
4036end
4037local _exp_0 = tb
4038local _type_0 = type(_exp_0)
4039local _tab_0 = "table" == _type_0 or "userdata" == _type_0
4040local _match_0 = false
4041if _tab_0 then
4042 local content
4043 do
4044 local _obj_0 = _exp_0.data
4045 local _type_1 = type(_obj_0)
4046 if "table" == _type_1 or "userdata" == _type_1 then
4047 content = _obj_0.content
4048 end
4049 end
4050 local _val_0
4051 do
4052 local _obj_0 = _exp_0.data
4053 if _obj_0 ~= nil then
4054 _val_0 = _obj_0.type
4055 end
4056 end
4057 if "success" == _val_0 and content ~= nil then
4058 _match_0 = true
4059 print("æˆåŠŸ", content)
4060 end
4061end
4062if not _match_0 then
4063 local _match_1 = false
4064 if _tab_0 then
4065 local content
4066 do
4067 local _obj_0 = _exp_0.data
4068 local _type_1 = type(_obj_0)
4069 if "table" == _type_1 or "userdata" == _type_1 then
4070 content = _obj_0.content
4071 end
4072 end
4073 local _val_0
4074 do
4075 local _obj_0 = _exp_0.data
4076 if _obj_0 ~= nil then
4077 _val_0 = _obj_0.type
4078 end
4079 end
4080 if "error" == _val_0 and content ~= nil then
4081 _match_1 = true
4082 print("失败", content)
4083 end
4084 end
4085 if not _match_1 then
4086 print("无效值")
4087 end
4088end
4089local _exp_0 = tb
4090local _type_0 = type(_exp_0)
4091local _tab_0 = "table" == _type_0 or "userdata" == _type_0
4092if _tab_0 then
4093 local fourth = _exp_0[4]
4094 local _val_0
4095 do
4096 local _obj_0 = _exp_0[1]
4097 if _obj_0 ~= nil then
4098 _val_0 = _obj_0.a
4099 end
4100 end
4101 local _val_1
4102 do
4103 local _obj_0 = _exp_0[1]
4104 if _obj_0 ~= nil then
4105 _val_1 = _obj_0.b
4106 end
4107 end
4108 local _val_2
4109 do
4110 local _obj_0 = _exp_0[2]
4111 if _obj_0 ~= nil then
4112 _val_2 = _obj_0.a
4113 end
4114 end
4115 local _val_3
4116 do
4117 local _obj_0 = _exp_0[2]
4118 if _obj_0 ~= nil then
4119 _val_3 = _obj_0.b
4120 end
4121 end
4122 local _val_4
4123 do
4124 local _obj_0 = _exp_0[3]
4125 if _obj_0 ~= nil then
4126 _val_4 = _obj_0.a
4127 end
4128 end
4129 local _val_5
4130 do
4131 local _obj_0 = _exp_0[3]
4132 if _obj_0 ~= nil then
4133 _val_5 = _obj_0.b
4134 end
4135 end
4136 if 1 == _val_0 and 2 == _val_1 and 3 == _val_2 and 4 == _val_3 and 5 == _val_4 and 6 == _val_5 and fourth ~= nil then
4137 print("åŒ¹é…æˆåŠŸ", fourth)
4138 end
4139end
4140local segments = {
4141 "admin",
4142 "users",
4143 "logs",
4144 "view"
4145}
4146local _type_0 = type(segments)
4147local _tab_0 = "table" == _type_0 or "userdata" == _type_0
4148if _tab_0 then
4149 local groups
4150 do
4151 local _accum_0 = { }
4152 local _len_0 = 1
4153 local _max_0 = #segments + -3 + 1
4154 for _index_0 = 1, _max_0 do
4155 local _item_0 = segments[_index_0]
4156 _accum_0[_len_0] = _item_0
4157 _len_0 = _len_0 + 1
4158 end
4159 groups = _accum_0
4160 end
4161 local resource = segments[#segments - 1]
4162 local action = segments[#segments]
4163 if resource ~= nil and action ~= nil then
4164 print("Group:", groups)
4165 print("Resource:", resource)
4166 print("Action:", action)
4167 end
4168end
3277local Inventory 4169local Inventory
3278local _class_0 4170local _class_0
3279local _base_0 = { 4171local _base_0 = {
@@ -3930,6 +4822,10 @@ do
3930 _with_1["key-name"] = value 4822 _with_1["key-name"] = value
3931end 4823end
3932_with_0[#_with_0 + 1] = "abc" 4824_with_0[#_with_0 + 1] = "abc"
4825local _with_0 = obj
4826if _with_0 ~= nil then
4827 print(obj.name)
4828end
3933do 4829do
3934 local var = "hello" 4830 local var = "hello"
3935 print(var) 4831 print(var)
diff --git a/spec/outputs/comprehension.lua b/spec/outputs/comprehension.lua
index 9a7c478..663bd44 100644
--- a/spec/outputs/comprehension.lua
+++ b/spec/outputs/comprehension.lua
@@ -243,8 +243,11 @@ end
243do 243do
244 local _accum_0 = { } 244 local _accum_0 = { }
245 local _len_0 = 1 245 local _len_0 = 1
246 local _min_0 = 1 + 2
246 local _max_0 = 3 + 4 247 local _max_0 = 3 + 4
247 for _index_0 = 1 + 2, _max_0 < 0 and #items + _max_0 or _max_0 do 248 _min_0 = _min_0 < 0 and #items + _min_0 + 1 or _min_0
249 _max_0 = _max_0 < 0 and #items + _max_0 + 1 or _max_0
250 for _index_0 = _min_0, _max_0 do
248 local item = items[_index_0] 251 local item = items[_index_0]
249 _accum_0[_len_0] = item 252 _accum_0[_len_0] = item
250 _len_0 = _len_0 + 1 253 _len_0 = _len_0 + 1
@@ -254,8 +257,11 @@ end
254do 257do
255 local _accum_0 = { } 258 local _accum_0 = { }
256 local _len_0 = 1 259 local _len_0 = 1
260 local _min_0 = hello() * 4
257 local _max_0 = 2 - thing[4] 261 local _max_0 = 2 - thing[4]
258 for _index_0 = hello() * 4, _max_0 < 0 and #items + _max_0 or _max_0 do 262 _min_0 = _min_0 < 0 and #items + _min_0 + 1 or _min_0
263 _max_0 = _max_0 < 0 and #items + _max_0 + 1 or _max_0
264 for _index_0 = _min_0, _max_0 do
259 local item = items[_index_0] 265 local item = items[_index_0]
260 _accum_0[_len_0] = item 266 _accum_0[_len_0] = item
261 _len_0 = _len_0 + 1 267 _len_0 = _len_0 + 1
diff --git a/spec/outputs/destructure.lua b/spec/outputs/destructure.lua
index 44da58b..ba216b5 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 = #clients + -2 + 1
635 for _index_0 = 2, _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 = #_list_0 + -2 + 1
692 for _index_0 = 2, _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 = #_obj_0 + -3 + 1
706 for _index_0 = 3, _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/funcs.lua b/spec/outputs/funcs.lua
index c1735c4..db7ed67 100644
--- a/spec/outputs/funcs.lua
+++ b/spec/outputs/funcs.lua
@@ -283,4 +283,157 @@ do
283 end 283 end
284 print(func()) 284 print(func())
285end 285end
286local _anon_func_0 = function(_arg_0)
287 local _accum_0 = { }
288 local _len_0 = 1
289 local _max_0 = #_arg_0
290 for _index_0 = 1, _max_0 do
291 local _item_0 = _arg_0[_index_0]
292 _accum_0[_len_0] = _item_0
293 _len_0 = _len_0 + 1
294 end
295 return _accum_0
296end
297do
298 local f
299 f = function(_arg_0)
300 local a, b, c
301 a, b, c = _arg_0.a, _arg_0.b, _arg_0.c
302 return print(a, b, c)
303 end
304 f = function(_arg_0)
305 local a, b, c
306 a, b, c = _arg_0.a, _arg_0.b, _arg_0.c
307 return print(a, b, c)
308 end
309 local g
310 g = function(x, _arg_0)
311 local y
312 y = _arg_0.y
313 return print(x, y)
314 end
315 local i
316 i = function(_arg_0)
317 local ax, by
318 ax, by = _arg_0.a, _arg_0.b
319 if ax == nil then
320 ax = 0
321 end
322 if by == nil then
323 by = 0
324 end
325 return print(ax, by)
326 end
327 j = function(name, _arg_0)
328 local uid, role
329 uid, role = _arg_0.id, _arg_0.role
330 if uid == nil then
331 uid = "n/a"
332 end
333 if role == nil then
334 role = "guest"
335 end
336 return print(name, uid, role)
337 end
338 local m
339 m = function(_arg_0)
340 local name, age, ver
341 name, age, ver = _arg_0.user.name, _arg_0.user.age, _arg_0.meta.ver
342 if ver == nil then
343 ver = 1
344 end
345 return print(name, age, ver)
346 end
347 local m1
348 m1 = function(_arg_0)
349 local name, age, meta
350 name, age, meta = _arg_0.user.name, _arg_0.user.age, _arg_0.meta
351 if meta == nil then
352 meta = { }
353 end
354 return print(name, age, meta and meta.ver or "nil")
355 end
356 local new
357 new = function(self, _arg_0)
358 local name, age
359 name, age = _arg_0.name, _arg_0.age
360 if name == nil then
361 name = "anon"
362 end
363 if age == nil then
364 age = 0
365 end
366 self.name = name
367 self.age = age
368 end
369 local set
370 set = function(self, _arg_0)
371 local name, age
372 name, age = _arg_0.name, _arg_0.age
373 if name == nil then
374 name = self.name
375 end
376 if age == nil then
377 age = self.age
378 end
379 self.name = name
380 self.age = age
381 end
382 local logKV
383 logKV = function(_arg_0, ...)
384 local k, v
385 k, v = _arg_0.k, _arg_0.v
386 print("kv:", k, v)
387 return print("rest count:", select("#", ...))
388 end
389 do
390 local foo
391 foo = function(_arg_0)
392 local a, b
393 a, b = _arg_0.a, _arg_0.b
394 if b == nil then
395 b = 0
396 end
397 return print(a, b)
398 end
399 end
400 local t1
401 t1 = function(_arg_0, x)
402 local a
403 a = _arg_0.a
404 return print(a, x)
405 end
406 local t2
407 t2 = function(_arg_0)
408 local a
409 a = _arg_0.a
410 return print(a)
411 end
412 local w
413 w = function(id, _arg_0, _arg_1)
414 local x, y
415 x, y = _arg_0.x, _arg_0.y
416 if x == nil then
417 x = 0
418 end
419 if y == nil then
420 y = 0
421 end
422 local flag
423 flag = _arg_1.flag
424 return print(id, x, y, flag)
425 end
426 local g1
427 g1 = function(_arg_0)
428 local a, ax
429 a, ax = _arg_0.a, _arg_0.a
430 return print(a, ax)
431 end
432 local g4
433 g4 = function(_arg_0)
434 local a, b, rest
435 a, b, rest = _arg_0.a, _arg_0.b, _anon_func_0(_arg_0)
436 return print(a, b)
437 end
438end
286return nil 439return nil
diff --git a/spec/outputs/global.lua b/spec/outputs/global.lua
index 54a21a9..3918f85 100644
--- a/spec/outputs/global.lua
+++ b/spec/outputs/global.lua
@@ -93,3 +93,28 @@ do
93 FooBar = "pascal case" 93 FooBar = "pascal case"
94 FOOBAR = "all uppercase" 94 FOOBAR = "all uppercase"
95end 95end
96do
97 do
98 local _class_0
99 local _base_0 = { }
100 if _base_0.__index == nil then
101 _base_0.__index = _base_0
102 end
103 _class_0 = setmetatable({
104 __init = function() end,
105 __base = _base_0,
106 __name = "A"
107 }, {
108 __index = _base_0,
109 __call = function(cls, ...)
110 local _self_0 = setmetatable({ }, _base_0)
111 cls.__init(_self_0, ...)
112 return _self_0
113 end
114 })
115 _base_0.__class = _class_0
116 A = _class_0
117 end
118 Flag = 1
119 const, x, y = "const", 1, 2
120end
diff --git a/spec/outputs/import.lua b/spec/outputs/import.lua
index 83c99e2..7aa130f 100644
--- a/spec/outputs/import.lua
+++ b/spec/outputs/import.lua
@@ -166,3 +166,13 @@ do
166 local _obj_1 = require("m") 166 local _obj_1 = require("m")
167 g, i = _obj_1[1], getmetatable(_obj_1[2]).__close 167 g, i = _obj_1[1], getmetatable(_obj_1[2]).__close
168end 168end
169do
170 local require <const> = require
171 local stringlib <const> = string
172 local format <const> = string.format
173 local io_read <const> = io.read
174 local type
175 type = function() end
176 local tp <const> = _G.type
177 local yue <const> = _G["月"]
178end
diff --git a/spec/outputs/lists.lua b/spec/outputs/lists.lua
index 48ec9c8..2ed7b95 100644
--- a/spec/outputs/lists.lua
+++ b/spec/outputs/lists.lua
@@ -230,31 +230,36 @@ x = {
230 6, 230 6,
231 7 231 7
232} 232}
233local _max_0 = -5 233local _max_0 = #x + -5 + 1
234for _index_0 = 2, _max_0 < 0 and #x + _max_0 or _max_0, 2 do 234for _index_0 = 2, _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 238for _index_0 = 1, 3 do
239for _index_0 = 1, _max_1 < 0 and #x + _max_1 or _max_1 do
240 local y = x[_index_0] 239 local y = x[_index_0]
241 print(y) 240 print(y)
242end 241end
243for _index_0 = 2, #x do 242local _max_1 = #x
243for _index_0 = 2, _max_1 do
244 local y = x[_index_0] 244 local y = x[_index_0]
245 print(y) 245 print(y)
246end 246end
247for _index_0 = 1, #x, 2 do 247local _max_2 = #x
248for _index_0 = 1, _max_2, 2 do
248 local y = x[_index_0] 249 local y = x[_index_0]
249 print(y) 250 print(y)
250end 251end
251for _index_0 = 2, #x, 2 do 252local _max_3 = #x
253for _index_0 = 2, _max_3, 2 do
252 local y = x[_index_0] 254 local y = x[_index_0]
253 print(y) 255 print(y)
254end 256end
255local a, b, c = 1, 5, 2 257local a, b, c = 1, 5, 2
256local _max_2 = b 258local _min_0 = a
257for _index_0 = a, _max_2 < 0 and #x + _max_2 or _max_2, c do 259local _max_4 = b
260_min_0 = _min_0 < 0 and #x + _min_0 + 1 or _min_0
261_max_4 = _max_4 < 0 and #x + _max_4 + 1 or _max_4
262for _index_0 = _min_0, _max_4, c do
258 local y = x[_index_0] 263 local y = x[_index_0]
259 print(y) 264 print(y)
260end 265end
@@ -287,7 +292,10 @@ do
287 a 292 a
288 }) 293 })
289 local _list_0 = f 294 local _list_0 = f
290 for _index_0 = a, #_list_0 do 295 local _min_1 = a
296 local _max_5 = #_list_0
297 _min_1 = _min_1 < 0 and #_list_0 + _min_1 + 1 or _min_1
298 for _index_0 = _min_1, _max_5 do
291 local v = _list_0[_index_0] 299 local v = _list_0[_index_0]
292 print(v) 300 print(v)
293 end 301 end
@@ -327,4 +335,191 @@ do
327 job = "jobless" 335 job = "jobless"
328 end 336 end
329end 337end
338do
339 local transactions = {
340 "T001",
341 "T002",
342 "T003",
343 "T004",
344 "T005"
345 }
346 local middleTransactions
347 do
348 local _accum_0 = { }
349 local _len_0 = 1
350 local _max_5 = #transactions + -2 + 1
351 for _index_0 = 2, _max_5 do
352 local _item_0 = transactions[_index_0]
353 _accum_0[_len_0] = _item_0
354 _len_0 = _len_0 + 1
355 end
356 middleTransactions = _accum_0
357 end
358 print(middleTransactions)
359end
360do
361 local logs = {
362 {
363 start = 0,
364 ["end"] = 100
365 },
366 {
367 start = 100,
368 ["end"] = 200
369 },
370 {
371 start = 200,
372 ["end"] = 123
373 }
374 }
375 print(logs[#logs]["end"])
376end
377do
378 local pendingOrders = {
379 "O001",
380 "O002",
381 "O003",
382 "O004"
383 }
384 print(pendingOrders[#pendingOrders - 1])
385end
386do
387 local getOrders
388 getOrders = function()
389 return {
390 {
391 id = "O1001",
392 status = "pending"
393 },
394 {
395 id = "O1002",
396 status = "processing"
397 },
398 {
399 id = "O1003",
400 status = "done"
401 }
402 }
403 end
404 local lastStatus
405 do
406 local _item_0 = getOrders()
407 lastStatus = _item_0[#_item_0].status
408 end
409 assert(lastStatus == "done")
410end
411do
412 local cloneList1
413 cloneList1 = function(list)
414 local _accum_0 = { }
415 local _len_0 = 1
416 local _max_5 = #list
417 for _index_0 = 1, _max_5 do
418 local _item_0 = list[_index_0]
419 _accum_0[_len_0] = _item_0
420 _len_0 = _len_0 + 1
421 end
422 return _accum_0
423 end
424 local cloneList2
425 cloneList2 = function(list)
426 local _tab_0 = { }
427 local _idx_0 = #_tab_0 + 1
428 for _index_0 = 1, #list do
429 local _value_0 = list[_index_0]
430 _tab_0[_idx_0] = _value_0
431 _idx_0 = _idx_0 + 1
432 end
433 return _tab_0
434 end
435 local cloneTable
436 cloneTable = function(tb)
437 local _tab_0 = { }
438 local _idx_0 = 1
439 for _key_0, _value_0 in pairs(tb) do
440 if _idx_0 == _key_0 then
441 _tab_0[#_tab_0 + 1] = _value_0
442 _idx_0 = _idx_0 + 1
443 else
444 _tab_0[_key_0] = _value_0
445 end
446 end
447 return _tab_0
448 end
449end
450do
451 print((function()
452 local _item_0 = globalTB
453 return _item_0[#_item_0]
454 end)(), (function()
455 local _item_0 = a.b.c
456 return _item_0[#_item_0 - 2]
457 end)(), (function()
458 if x ~= nil then
459 local _obj_0 = x.y
460 if _obj_0 ~= nil then
461 local _obj_1 = _obj_0(x).z
462 if _obj_1 ~= nil then
463 return _obj_1[#_obj_1 - 3]
464 end
465 return nil
466 end
467 return nil
468 end
469 return nil
470 end)())
471end
472local _anon_func_0 = function(globalTB)
473 local _item_0 = globalTB
474 local _call_0 = _item_0[#_item_0]
475 return _call_0["end"](_call_0, 123)
476end
477local _anon_func_1 = function(a)
478 local _item_0
479 do
480 local _accum_0 = { }
481 local _len_0 = 1
482 local _list_0 = a.b.c
483 local _max_5 = #_list_0 + -5 + 1
484 for _index_0 = 5, _max_5 do
485 local _item_1 = _list_0[_index_0]
486 _accum_0[_len_0] = _item_1
487 _len_0 = _len_0 + 1
488 end
489 _item_0 = _accum_0
490 end
491 return _item_0[#_item_0 - 2]
492end
493local _anon_func_2 = function(x)
494 if x ~= nil then
495 local _obj_0 = x.y
496 if _obj_0 ~= nil then
497 local _obj_1 = _obj_0(x).z
498 if _obj_1 ~= nil then
499 local _obj_2 = _obj_1[#_obj_1 - 3]
500 if _obj_2 ~= nil then
501 local _accum_0 = { }
502 local _len_0 = 1
503 local _max_5 = #_obj_2 + -3 + 1
504 for _index_0 = 1, _max_5 do
505 local _item_0 = _obj_2[_index_0]
506 _accum_0[_len_0] = _item_0
507 _len_0 = _len_0 + 1
508 end
509 return _accum_0
510 end
511 return nil
512 end
513 return nil
514 end
515 return nil
516 end
517 return nil
518end
519do
520 local f
521 f = function()
522 return print(_anon_func_0(globalTB), _anon_func_1(a), _anon_func_2(x))
523 end
524end
330return nil 525return nil
diff --git a/spec/outputs/loops.lua b/spec/outputs/loops.lua
index 8624d49..6ab4bbb 100644
--- a/spec/outputs/loops.lua
+++ b/spec/outputs/loops.lua
@@ -60,8 +60,8 @@ do
60 local y = hello[_index_0] 60 local y = hello[_index_0]
61 if y % 2 == 0 then 61 if y % 2 == 0 then
62 _accum_0[_len_0] = y 62 _accum_0[_len_0] = y
63 _len_0 = _len_0 + 1
63 end 64 end
64 _len_0 = _len_0 + 1
65 end 65 end
66 x = _accum_0 66 x = _accum_0
67end 67end
@@ -132,13 +132,11 @@ do
132end 132end
133do 133do
134 local _accum_0 = { } 134 local _accum_0 = { }
135 local _len_0 = 1
136 local _list_2 = 3 135 local _list_2 = 3
137 for _index_0 = 1, #_list_2 do 136 for _index_0 = 1, #_list_2 do
138 local thing = _list_2[_index_0] 137 local thing = _list_2[_index_0]
139 y = "hello" 138 y = "hello"
140 break 139 break
141 _len_0 = _len_0 + 1
142 end 140 end
143 x = _accum_0 141 x = _accum_0
144end 142end
@@ -370,3 +368,131 @@ do
370 end 368 end
371 until false 369 until false
372end 370end
371local _anon_func_0 = function(i, tb)
372 local _accum_0 = { }
373 local _len_0 = 1
374 while tb[i] do
375 i = i + 1
376 _accum_0[_len_0] = i - 1
377 _len_0 = _len_0 + 1
378 end
379 return _accum_0
380end
381do
382 local index
383 do
384 local _accum_0
385 for i = 1, #tb do
386 if tb[i] then
387 _accum_0 = i
388 break
389 end
390 end
391 index = _accum_0
392 end
393 f((function()
394 local _accum_0
395 for i = 1, #tb do
396 if tb[i] then
397 _accum_0 = i
398 break
399 end
400 end
401 return _accum_0
402 end)())
403 f((function()
404 local _accum_0 = { }
405 local _len_0 = 1
406 for i = 1, #tb do
407 if tb[i] then
408 _accum_0[_len_0] = i
409 _len_0 = _len_0 + 1
410 end
411 end
412 return _accum_0
413 end)())
414 i = 1
415 local ids
416 do
417 local _accum_0 = { }
418 local _len_0 = 1
419 while tb[i] do
420 i = i + 1
421 _accum_0[_len_0] = i - 1
422 _len_0 = _len_0 + 1
423 end
424 ids = _accum_0
425 end
426 i = 1
427 local idx
428 do
429 local _accum_0
430 while tb[i] do
431 i = i + 1
432 _accum_0 = i - 1
433 break
434 end
435 idx = _accum_0
436 end
437 local f1
438 f1 = function()
439 i = 1
440 return f(_anon_func_0(i, tb))
441 end
442 i = 1
443 f((function()
444 local _accum_0
445 while tb[i] do
446 i = i + 1
447 _accum_0 = i - 1
448 break
449 end
450 return _accum_0
451 end)())
452 local _accum_0 = { }
453 local _len_0 = 1
454 local _list_3 = items
455 for _index_0 = 1, #_list_3 do
456 local item = _list_3[_index_0]
457 local _type_0 = type(item)
458 local _tab_0 = "table" == _type_0 or "userdata" == _type_0
459 if _tab_0 then
460 local value = item.value
461 if "A" == item.type and value ~= nil then
462 if value > 5 then
463 _accum_0[_len_0] = item
464 _len_0 = _len_0 + 1
465 end
466 end
467 end
468 end
469 list = _accum_0
470end
471do
472 repeat
473 print(1)
474 until true
475 do
476 local _accum_0
477 repeat
478 a = func()
479 _accum_0 = a.x
480 break
481 until a.v
482 x = _accum_0
483 end
484 local items
485 local _accum_0 = { }
486 local _len_0 = 1
487 repeat
488 local item = getItem()
489 if not item then
490 break
491 end
492 if item.value > 0 then
493 _accum_0[_len_0] = item
494 _len_0 = _len_0 + 1
495 end
496 until false
497 items = _accum_0
498end
diff --git a/spec/outputs/macro.lua b/spec/outputs/macro.lua
index 4d31574..89c6e63 100644
--- a/spec/outputs/macro.lua
+++ b/spec/outputs/macro.lua
@@ -26,6 +26,10 @@ print({
26 123, 26 123,
27 'xyz' 27 'xyz'
28}) 28})
29print({
30 456,
31 'abc'
32})
29do 33do
30 assert(item == nil) 34 assert(item == nil)
31end 35end
@@ -213,6 +217,13 @@ function tb:func()
213end 217end
214end 218end
215print(x) 219print(x)
220local yue = require("yue")
221do
222local function f2(a)
223 return a + 1
224end
225x = x + f2(3)
226end
216local sel 227local sel
217sel = function(a, b, c) 228sel = function(a, b, c)
218 if a then 229 if a then
@@ -317,7 +328,7 @@ print((setmetatable({
317 return 998 328 return 998
318 end 329 end
319})) 330}))
320print("current line: " .. tostring(323)) 331print("current line: " .. tostring(349))
321do 332do
322 do 333 do
323-- TODO 334-- TODO
@@ -330,10 +341,8 @@ local _1
330_1 = function() 341_1 = function()
331 print(1) 342 print(1)
332 local _accum_0 = { } 343 local _accum_0 = { }
333 local _len_0 = 1
334 while false do 344 while false do
335 break 345 break
336 _len_0 = _len_0 + 1
337 end 346 end
338 return _accum_0 347 return _accum_0
339end 348end
diff --git a/spec/outputs/props.lua b/spec/outputs/props.lua
new file mode 100644
index 0000000..2c282e0
--- /dev/null
+++ b/spec/outputs/props.lua
@@ -0,0 +1,240 @@
1local Props
2do
3 local _class_0
4 local assignReadOnly
5 local _base_0 = {
6 __index = function(self, name)
7 local cls = getmetatable(self)
8 do
9 local item
10 do
11 local _obj_0 = cls.__getter
12 if _obj_0 ~= nil then
13 item = _obj_0[name]
14 end
15 end
16 if item then
17 return item(self)
18 else
19 item = rawget(cls, name)
20 if item then
21 return item
22 else
23 local c = cls
24 repeat
25 c = getmetatable(c)
26 if c then
27 local _obj_0 = c.__getter
28 if _obj_0 ~= nil then
29 item = _obj_0[name]
30 end
31 if item then
32 if cls.__getter == nil then
33 cls.__getter = { }
34 end
35 cls.__getter[name] = item
36 return item(self)
37 else
38 item = rawget(c, name)
39 if item then
40 rawset(cls, name, item)
41 return item
42 end
43 end
44 else
45 break
46 end
47 until false
48 end
49 end
50 end
51 return nil
52 end,
53 __newindex = function(self, name, value)
54 local cls = getmetatable(self)
55 local item
56 local _obj_0 = cls.__setter
57 if _obj_0 ~= nil then
58 item = _obj_0[name]
59 end
60 if item then
61 return item(self, value)
62 else
63 local c = cls
64 repeat
65 c = getmetatable(c)
66 if c then
67 local _obj_1 = c.__setter
68 if _obj_1 ~= nil then
69 item = _obj_1[name]
70 end
71 if item then
72 if cls.__setter == nil then
73 cls.__setter = { }
74 end
75 cls.__setter[name] = item
76 item(self, value)
77 return
78 end
79 else
80 break
81 end
82 until false
83 return rawset(self, name, value)
84 end
85 end,
86 prop = function(self, name, props)
87 local get, set = props.get, props.set
88 if set == nil then
89 set = assignReadOnly
90 end
91 do
92 local getter = rawget(self.__base, "__getter")
93 if getter then
94 getter[name] = get
95 else
96 rawset(self.__base, "__getter", {
97 [name] = get
98 })
99 end
100 end
101 local setter = rawget(self.__base, "__setter")
102 if setter then
103 setter[name] = set
104 else
105 return rawset(self.__base, "__setter", {
106 [name] = set
107 })
108 end
109 end
110 }
111 if _base_0.__index == nil then
112 _base_0.__index = _base_0
113 end
114 _class_0 = setmetatable({
115 __init = function() end,
116 __base = _base_0,
117 __name = "Props"
118 }, {
119 __index = _base_0,
120 __call = function(cls, ...)
121 local _self_0 = setmetatable({ }, _base_0)
122 cls.__init(_self_0, ...)
123 return _self_0
124 end
125 })
126 _base_0.__class = _class_0
127 local self = _class_0;
128 assignReadOnly = function()
129 return error("assigning a readonly property")
130 end
131 Props = _class_0
132end
133local A
134do
135 local _class_0
136 local _parent_0 = Props
137 local _base_0 = { }
138 for _key_0, _val_0 in pairs(_parent_0.__base) do
139 if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then
140 _base_0[_key_0] = _val_0
141 end
142 end
143 if _base_0.__index == nil then
144 _base_0.__index = _base_0
145 end
146 setmetatable(_base_0, _parent_0.__base)
147 _class_0 = setmetatable({
148 __init = function(self)
149 self._x = 0
150 end,
151 __base = _base_0,
152 __name = "A",
153 __parent = _parent_0
154 }, {
155 __index = function(cls, name)
156 local val = rawget(_base_0, name)
157 if val == nil then
158 local parent = rawget(cls, "__parent")
159 if parent then
160 return parent[name]
161 end
162 else
163 return val
164 end
165 end,
166 __call = function(cls, ...)
167 local _self_0 = setmetatable({ }, _base_0)
168 cls.__init(_self_0, ...)
169 return _self_0
170 end
171 })
172 _base_0.__class = _class_0
173 local self = _class_0;
174 self:prop('x', {
175 get = function(self)
176 return self._x + 1000
177 end,
178 set = function(self, v)
179 self._x = v
180 end
181 })
182 if _parent_0.__inherited then
183 _parent_0.__inherited(_parent_0, _class_0)
184 end
185 A = _class_0
186end
187local B
188do
189 local _class_0
190 local _parent_0 = A
191 local _base_0 = { }
192 for _key_0, _val_0 in pairs(_parent_0.__base) do
193 if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then
194 _base_0[_key_0] = _val_0
195 end
196 end
197 if _base_0.__index == nil then
198 _base_0.__index = _base_0
199 end
200 setmetatable(_base_0, _parent_0.__base)
201 _class_0 = setmetatable({
202 __init = function(self, ...)
203 return _class_0.__parent.__init(self, ...)
204 end,
205 __base = _base_0,
206 __name = "B",
207 __parent = _parent_0
208 }, {
209 __index = function(cls, name)
210 local val = rawget(_base_0, name)
211 if val == nil then
212 local parent = rawget(cls, "__parent")
213 if parent then
214 return parent[name]
215 end
216 else
217 return val
218 end
219 end,
220 __call = function(cls, ...)
221 local _self_0 = setmetatable({ }, _base_0)
222 cls.__init(_self_0, ...)
223 return _self_0
224 end
225 })
226 _base_0.__class = _class_0
227 local self = _class_0;
228 self:prop('abc', {
229 get = function(self)
230 return "hello"
231 end
232 })
233 if _parent_0.__inherited then
234 _parent_0.__inherited(_parent_0, _class_0)
235 end
236 B = _class_0
237end
238local b = B()
239b.x = 999
240return print(b.x, b.abc)
diff --git a/spec/outputs/string.lua b/spec/outputs/string.lua
index febea62..b536e6d 100644
--- a/spec/outputs/string.lua
+++ b/spec/outputs/string.lua
@@ -1,3 +1,4 @@
1local _module_0 = { }
1local hi = "hello" 2local hi = "hello"
2local hello = "what the heckyes" 3local hello = "what the heckyes"
3print(hi) 4print(hi)
@@ -41,4 +42,42 @@ local _ = "hello";
41("hello"):format().hello(1, 2, 3); 42("hello"):format().hello(1, 2, 3);
42("hello"):format(1, 2, 3) 43("hello"):format(1, 2, 3)
43something("hello"):world() 44something("hello"):world()
44return something(("hello"):world()) 45something(("hello"):world())
46do
47 local str = "key: value"
48 str = "config:\n\tenabled: true\n\tlevel: 5"
49 str = "header: start\nfooter: end"
50 str = "name: " .. tostring(username)
51 str = "count: " .. tostring(total) .. " items"
52 str = "user: " .. tostring(name) .. "\nid: " .. tostring(id)
53 str = "path: \"C:\\\\Program Files\\\\App\"\ndesc: 'single \"quote\" test'"
54 str = "key: value \nnext: 123 "
55 str = "list:\n - \"one\"\n - \"two\""
56 str = "-- comment\ncontent text\n-- comment"
57 str = tostring(1 + 2) .. '\n' .. tostring(2 + 3) .. '\n' .. tostring("a" .. "b")
58 local obj = {
59 settings = "mode: " .. tostring(mode) .. "\nflags:\n\t- " .. tostring(flag1) .. "\n\t- default"
60 }
61 local fn
62 fn = function()
63 return "Hello\nname: " .. tostring(userName)
64 end
65 str = "result:\n\tstatus: " .. tostring((function()
66 if ok then
67 return "pass"
68 else
69 return "fail"
70 end
71 end)()) .. "\n\tcode: " .. tostring(code)
72 local summary = "date: " .. tostring(os.date()) .. "\nvalues:\n\t-\n\t\ta: " .. tostring(aVal) .. "\n\t\tb: " .. tostring(bVal or defaultB)
73 local msg = send("Hello, " .. tostring(user) .. "!\nToday is " .. tostring(os.date("%A")) .. ".")
74 local desc
75 do
76 local prefix = "Result"
77 desc = tostring(prefix) .. ":\nvalue: " .. tostring(compute())
78 end
79 print(("1\n2\n3"))
80end
81local yaml = "version: " .. tostring(ver) .. "\nok: true"
82_module_0["yaml"] = yaml
83return _module_0
diff --git a/spec/outputs/switch.lua b/spec/outputs/switch.lua
index e4dedc9..7c1004b 100644
--- a/spec/outputs/switch.lua
+++ b/spec/outputs/switch.lua
@@ -415,4 +415,366 @@ do
415 end 415 end
416 end 416 end
417end 417end
418do
419 local _exp_0 = tb
420 local _type_0 = type(_exp_0)
421 local _tab_0 = "table" == _type_0 or "userdata" == _type_0
422 local _match_0 = false
423 if _tab_0 then
424 if 1 == _exp_0[1] and 2 == _exp_0[2] and 3 == _exp_0[3] then
425 _match_0 = true
426 print("1, 2, 3")
427 end
428 end
429 if not _match_0 then
430 local _match_1 = false
431 if _tab_0 then
432 local b = _exp_0[2]
433 if 1 == _exp_0[1] and b ~= nil and 3 == _exp_0[3] then
434 _match_1 = true
435 print("1, " .. tostring(b) .. ", 3")
436 end
437 end
438 if not _match_1 then
439 if _tab_0 then
440 local b = _exp_0[3]
441 if b == nil then
442 b = 3
443 end
444 if 1 == _exp_0[1] and 2 == _exp_0[2] then
445 print("1, 2, " .. tostring(b))
446 end
447 end
448 end
449 end
450end
451do
452 local _exp_0 = tb
453 local _type_0 = type(_exp_0)
454 local _tab_0 = "table" == _type_0 or "userdata" == _type_0
455 local _match_0 = false
456 if _tab_0 then
457 local result = _exp_0.result
458 if true == _exp_0.success and result ~= nil then
459 _match_0 = true
460 print("success", result)
461 end
462 end
463 if not _match_0 then
464 local _match_1 = false
465 if _tab_0 then
466 if false == _exp_0.success then
467 _match_1 = true
468 print("failed", result)
469 end
470 end
471 if not _match_1 then
472 print("invalid")
473 end
474 end
475end
476do
477 local _exp_0 = tb
478 local _type_0 = type(_exp_0)
479 local _tab_0 = "table" == _type_0 or "userdata" == _type_0
480 local _match_0 = false
481 if _tab_0 then
482 local content = _exp_0.content
483 if "success" == _exp_0.type and content ~= nil then
484 _match_0 = true
485 print("success", content)
486 end
487 end
488 if not _match_0 then
489 local _match_1 = false
490 if _tab_0 then
491 local content = _exp_0.content
492 if "error" == _exp_0.type and content ~= nil then
493 _match_1 = true
494 print("failed", content)
495 end
496 end
497 if not _match_1 then
498 print("invalid")
499 end
500 end
501end
502do
503 do
504 local _exp_0 = tb
505 local _type_0 = type(_exp_0)
506 local _tab_0 = "table" == _type_0 or "userdata" == _type_0
507 if _tab_0 then
508 local fourth = _exp_0[4]
509 local _val_0
510 do
511 local _obj_0 = _exp_0[1]
512 if _obj_0 ~= nil then
513 _val_0 = _obj_0.a
514 end
515 end
516 local _val_1
517 do
518 local _obj_0 = _exp_0[1]
519 if _obj_0 ~= nil then
520 _val_1 = _obj_0.b
521 end
522 end
523 local _val_2
524 do
525 local _obj_0 = _exp_0[2]
526 if _obj_0 ~= nil then
527 _val_2 = _obj_0.a
528 end
529 end
530 local _val_3
531 do
532 local _obj_0 = _exp_0[2]
533 if _obj_0 ~= nil then
534 _val_3 = _obj_0.b
535 end
536 end
537 local _val_4
538 do
539 local _obj_0 = _exp_0[3]
540 if _obj_0 ~= nil then
541 _val_4 = _obj_0.a
542 end
543 end
544 local _val_5
545 do
546 local _obj_0 = _exp_0[3]
547 if _obj_0 ~= nil then
548 _val_5 = _obj_0.b
549 end
550 end
551 if 1 == _val_0 and 2 == _val_1 and 3 == _val_2 and 4 == _val_3 and 5 == _val_4 and 6 == _val_5 and fourth ~= nil then
552 print("matched", fourth)
553 end
554 end
555 end
556 local _exp_0 = tb
557 local _type_0 = type(_exp_0)
558 local _tab_0 = "table" == _type_0 or "userdata" == _type_0
559 local _match_0 = false
560 if _tab_0 then
561 local _val_0
562 do
563 local _obj_0 = _exp_0[1]
564 if _obj_0 ~= nil then
565 _val_0 = _obj_0.c
566 end
567 end
568 local _val_1
569 do
570 local _obj_0 = _exp_0[1]
571 if _obj_0 ~= nil then
572 _val_1 = _obj_0.d
573 end
574 end
575 local _val_2
576 do
577 local _obj_0 = _exp_0[2]
578 if _obj_0 ~= nil then
579 _val_2 = _obj_0.c
580 end
581 end
582 local _val_3
583 do
584 local _obj_0 = _exp_0[2]
585 if _obj_0 ~= nil then
586 _val_3 = _obj_0.d
587 end
588 end
589 local _val_4
590 do
591 local _obj_0 = _exp_0[3]
592 if _obj_0 ~= nil then
593 _val_4 = _obj_0.c
594 end
595 end
596 local _val_5
597 do
598 local _obj_0 = _exp_0[3]
599 if _obj_0 ~= nil then
600 _val_5 = _obj_0.d
601 end
602 end
603 if 1 == _val_0 and 2 == _val_1 and 3 == _val_2 and 4 == _val_3 and 5 == _val_4 and 6 == _val_5 then
604 _match_0 = true
605 print("OK")
606 end
607 end
608 if not _match_0 then
609 if _tab_0 then
610 local sixth = _exp_0[6]
611 local _val_0
612 do
613 local _obj_0 = _exp_0[3]
614 if _obj_0 ~= nil then
615 _val_0 = _obj_0.a
616 end
617 end
618 local _val_1
619 do
620 local _obj_0 = _exp_0[3]
621 if _obj_0 ~= nil then
622 _val_1 = _obj_0.b
623 end
624 end
625 local _val_2
626 do
627 local _obj_0 = _exp_0[4]
628 if _obj_0 ~= nil then
629 _val_2 = _obj_0.a
630 end
631 end
632 local _val_3
633 do
634 local _obj_0 = _exp_0[4]
635 if _obj_0 ~= nil then
636 _val_3 = _obj_0.b
637 end
638 end
639 local _val_4
640 do
641 local _obj_0 = _exp_0[5]
642 if _obj_0 ~= nil then
643 _val_4 = _obj_0.a
644 end
645 end
646 local _val_5
647 do
648 local _obj_0 = _exp_0[5]
649 if _obj_0 ~= nil then
650 _val_5 = _obj_0.b
651 end
652 end
653 if 1 == _val_0 and 2 == _val_1 and 3 == _val_2 and 4 == _val_3 and 5 == _val_4 and 6 == _val_5 and sixth ~= nil then
654 print("matched", sixth)
655 end
656 end
657 end
658end
659do
660 local v = "hello"
661 if "hello" == v then
662 print("matched hello")
663 else
664 print("not matched")
665 end
666end
667do
668 local f
669 f = function()
670 return "ok"
671 end
672 local val = f()
673 if "ok" == val then
674 print("it's ok")
675 end
676end
677do
678 local g
679 g = function()
680 return 42
681 end
682 local result = g()
683 if 1 == result or 2 == result then
684 print("small")
685 elseif 42 == result then
686 print("life universe everything")
687 else
688 print("other " .. tostring(result))
689 end
690end
691do
692 local check
693 check = function()
694 if true then
695 return "yes"
696 else
697 return "no"
698 end
699 end
700 local x = check()
701 if "yes" == x then
702 print("affirmative")
703 else
704 print("negative")
705 end
706end
707do
708 local t
709 t = function()
710 local tb = {
711 a = 1
712 }
713 tb.a = 2
714 return tb
715 end
716 local data = t()
717 local _type_0 = type(data)
718 local _tab_0 = "table" == _type_0 or "userdata" == _type_0
719 local _match_0 = false
720 if _tab_0 then
721 if 2 == data.a then
722 _match_0 = true
723 print("matched")
724 end
725 end
726 if not _match_0 then
727 print("not matched")
728 end
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 = #clientData + -3 + 1
744 for _index_0 = 1, _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
418return nil 780return nil
diff --git a/spec/outputs/tables.lua b/spec/outputs/tables.lua
index f358811..3f851de 100644
--- a/spec/outputs/tables.lua
+++ b/spec/outputs/tables.lua
@@ -366,6 +366,28 @@ local menus = {
366 } 366 }
367 } 367 }
368} 368}
369_ = {
370 boolean = {
371 true,
372 false
373 },
374 float = {
375 3.14,
376 -6.8523015e+5
377 },
378 int = {
379 123,
380 -685230
381 },
382 null = {
383 nodeName = 'node',
384 parent = nil
385 },
386 string = {
387 'Hello world',
388 "newline\nnewline2"
389 }
390}
369local tb 391local tb
370do 392do
371 local _tab_0 = { } 393 local _tab_0 = { }
diff --git a/spec/outputs/try_catch.lua b/spec/outputs/try_catch.lua
index efd92c6..edb2341 100644
--- a/spec/outputs/try_catch.lua
+++ b/spec/outputs/try_catch.lua
@@ -22,6 +22,44 @@ end
22local _anon_func_7 = function(a, b, c, tb) 22local _anon_func_7 = function(a, b, c, tb)
23 return tb.f(a, b, c) 23 return tb.f(a, b, c)
24end 24end
25local _anon_func_8 = function(_arg_0, ...)
26 local ok = _arg_0
27 return ...
28end
29local _anon_func_10 = function(_arg_0, ...)
30 local _ok_0 = _arg_0
31 if _ok_0 then
32 return ...
33 end
34end
35local _anon_func_9 = function(func, pcall)
36 return _anon_func_10(pcall(func))
37end
38local _anon_func_12 = function(_arg_0, ...)
39 local _ok_0 = _arg_0
40 if _ok_0 then
41 return ...
42 end
43end
44local _anon_func_11 = function(func, pcall)
45 return _anon_func_12(pcall(func))
46end
47local _anon_func_14 = function(_arg_0, ...)
48 local _ok_0 = _arg_0
49 if _ok_0 then
50 return ...
51 end
52end
53local _anon_func_15 = function(func, print)
54 print(123)
55 return func()
56end
57local _anon_func_13 = function(func, print, xpcall)
58 return _anon_func_14(xpcall(_anon_func_15, function(e)
59 print(e)
60 return e
61 end, func, print))
62end
25local f 63local f
26f = function() 64f = function()
27 xpcall(function() 65 xpcall(function()
@@ -104,10 +142,236 @@ f = function()
104 do 142 do
105 x(function() 143 x(function()
106 local tb, a, b, c 144 local tb, a, b, c
107 f = function() 145 local f1
146 f1 = function()
108 return pcall(_anon_func_7, a, b, c, tb) 147 return pcall(_anon_func_7, a, b, c, tb)
109 end 148 end
110 end) 149 end)
111 end 150 end
151 do
152 local f1
153 f1 = function()
154 do
155 return _anon_func_8(pcall(function()
156 return func()
157 end))
158 end
159 end
160 end
161 do
162 local func
163 local a, b, c
164 local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(func)
165 if _ok_0 then
166 a, b, c = _ret_0, _ret_1, _ret_2
167 end
168 end
169 do
170 local a, b, c
171 local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function()
172 return func()
173 end)
174 if _ok_0 then
175 a, b, c = _ret_0, _ret_1, _ret_2
176 end
177 end
178 do
179 local a
180 local _exp_0 = (_anon_func_9(func, pcall))
181 if _exp_0 ~= nil then
182 a = _exp_0
183 else
184 a = "default"
185 end
186 end
187 do
188 f(_anon_func_11(func, pcall))
189 end
190 do
191 f(_anon_func_13(func, print, xpcall))
192 end
112 return nil 193 return nil
113end 194end
195local _anon_func_16 = function(a, b, c, tb)
196 return tb.f(a, b, c)
197end
198local _anon_func_17 = function(_arg_0, ...)
199 local ok = _arg_0
200 return ...
201end
202do
203 xpcall(function()
204 return func(1, 2, 3)
205 end, function(err)
206 return print(err)
207 end)
208 xpcall(function()
209 return func(1, 2, 3)
210 end, function(err)
211 return print(err)
212 end)
213 pcall(function()
214 print("trying")
215 return func(1, 2, 3)
216 end)
217 do
218 local success, result = xpcall(function()
219 return func(1, 2, 3)
220 end, function(err)
221 return print(err)
222 end)
223 success, result = pcall(function()
224 return func(1, 2, 3)
225 end)
226 end
227 local tb = { }
228 pcall(function()
229 return tb.func
230 end)
231 pcall(function()
232 return tb.func()
233 end)
234 pcall(function()
235 return tb.func()
236 end)
237 pcall(function()
238 return (tb.func())
239 end)
240 pcall(function()
241 return (tb:func(1, 2, 3))
242 end)
243 pcall(function()
244 return tb.func(1)
245 end)
246 pcall(function()
247 return tb.func(1)
248 end)
249 if (xpcall(function()
250 return func(1)
251 end, function(err)
252 return print(err)
253 end)) then
254 print("OK")
255 end
256 if xpcall(function()
257 return (func(1))
258 end, function(err)
259 return print(err)
260 end) then
261 print("OK")
262 end
263 do
264 do
265 local success, result = pcall(function()
266 return func("abc", 123)
267 end)
268 if success then
269 print(result)
270 end
271 end
272 local success, result = xpcall(function()
273 return func("abc", 123)
274 end, function(err)
275 return print(err)
276 end)
277 success, result = xpcall(function()
278 return func("abc", 123)
279 end, function(err)
280 return print(err)
281 end)
282 if success then
283 print(result)
284 end
285 end
286 do
287 pcall(function()
288 return func(1, 2, 3)
289 end)
290 pcall(function()
291 return func(1, 2, 3)
292 end)
293 end
294 do
295 x(function()
296 local tb, a, b, c
297 local f1
298 f1 = function()
299 return pcall(_anon_func_16, a, b, c, tb)
300 end
301 end)
302 end
303 do
304 local f1
305 f1 = function()
306 do
307 return _anon_func_17(pcall(function()
308 return func()
309 end))
310 end
311 end
312 end
313 do
314 local func
315 local a, b, c
316 local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(func)
317 if _ok_0 then
318 a, b, c = _ret_0, _ret_1, _ret_2
319 end
320 end
321 do
322 local a, b, c
323 local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function()
324 return func()
325 end)
326 if _ok_0 then
327 a, b, c = _ret_0, _ret_1, _ret_2
328 end
329 end
330 do
331 local a
332 local _exp_0 = ((function()
333 return (function(_arg_0, ...)
334 local _ok_0 = _arg_0
335 if _ok_0 then
336 return ...
337 end
338 end)(pcall(function()
339 return func()
340 end))
341 end)())
342 if _exp_0 ~= nil then
343 a = _exp_0
344 else
345 a = "default"
346 end
347 end
348 do
349 f((function()
350 return (function(_arg_0, ...)
351 local _ok_0 = _arg_0
352 if _ok_0 then
353 return ...
354 end
355 end)(pcall(function()
356 return func()
357 end))
358 end)())
359 end
360 do
361 f((function()
362 return (function(_arg_0, ...)
363 local _ok_0 = _arg_0
364 if _ok_0 then
365 return ...
366 end
367 end)(xpcall(function()
368 print(123)
369 return func()
370 end, function(e)
371 print(e)
372 return e
373 end))
374 end)())
375 end
376end
377return nil
diff --git a/spec/outputs/unicode/assign.lua b/spec/outputs/unicode/assign.lua
index d4ad56a..e00d016 100644
--- a/spec/outputs/unicode/assign.lua
+++ b/spec/outputs/unicode/assign.lua
@@ -43,10 +43,8 @@ do
43 end 43 end
44end 44end
45local _anon_func_0 = function(_u6253_u5370) 45local _anon_func_0 = function(_u6253_u5370)
46 do 46 _u6253_u5370(123)
47 _u6253_u5370(123) 47 return { }
48 return { }
49 end
50end 48end
51return __u65e0_u6548_u53d8_u91cf(function() 49return __u65e0_u6548_u53d8_u91cf(function()
52 setmetatable(a_u53d8_u91cf, _anon_func_0(_u6253_u5370)) 50 setmetatable(a_u53d8_u91cf, _anon_func_0(_u6253_u5370))
diff --git a/spec/outputs/unicode/comprehension.lua b/spec/outputs/unicode/comprehension.lua
index 60e490f..92bce69 100644
--- a/spec/outputs/unicode/comprehension.lua
+++ b/spec/outputs/unicode/comprehension.lua
@@ -243,8 +243,11 @@ end
243do 243do
244 local _accum_0 = { } 244 local _accum_0 = { }
245 local _len_0 = 1 245 local _len_0 = 1
246 local _min_0 = 1 + 2
246 local _max_0 = 3 + 4 247 local _max_0 = 3 + 4
247 for _index_0 = 1 + 2, _max_0 < 0 and #_u5217_u8868 + _max_0 or _max_0 do 248 _min_0 = _min_0 < 0 and #_u5217_u8868 + _min_0 + 1 or _min_0
249 _max_0 = _max_0 < 0 and #_u5217_u8868 + _max_0 + 1 or _max_0
250 for _index_0 = _min_0, _max_0 do
248 local _u9879_u76ee = _u5217_u8868[_index_0] 251 local _u9879_u76ee = _u5217_u8868[_index_0]
249 _accum_0[_len_0] = _u9879_u76ee 252 _accum_0[_len_0] = _u9879_u76ee
250 _len_0 = _len_0 + 1 253 _len_0 = _len_0 + 1
@@ -254,8 +257,11 @@ end
254do 257do
255 local _accum_0 = { } 258 local _accum_0 = { }
256 local _len_0 = 1 259 local _len_0 = 1
260 local _min_0 = _u4f60_u597d() * 4
257 local _max_0 = 2 - _u4e1c_u897f[4] 261 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 262 _min_0 = _min_0 < 0 and #_u5217_u8868 + _min_0 + 1 or _min_0
263 _max_0 = _max_0 < 0 and #_u5217_u8868 + _max_0 + 1 or _max_0
264 for _index_0 = _min_0, _max_0 do
259 local _u9879_u76ee = _u5217_u8868[_index_0] 265 local _u9879_u76ee = _u5217_u8868[_index_0]
260 _accum_0[_len_0] = _u9879_u76ee 266 _accum_0[_len_0] = _u9879_u76ee
261 _len_0 = _len_0 + 1 267 _len_0 = _len_0 + 1
diff --git a/spec/outputs/unicode/lists.lua b/spec/outputs/unicode/lists.lua
index aafd516..3bf6f50 100644
--- a/spec/outputs/unicode/lists.lua
+++ b/spec/outputs/unicode/lists.lua
@@ -229,31 +229,36 @@ _u53d8_u91cfx = {
229 6, 229 6,
230 7 230 7
231} 231}
232local _max_0 = -5 232local _max_0 = #_u53d8_u91cfx + -5 + 1
233for _index_0 = 2, _max_0 < 0 and #_u53d8_u91cfx + _max_0 or _max_0, 2 do 233for _index_0 = 2, _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 237for _index_0 = 1, 3 do
238for _index_0 = 1, _max_1 < 0 and #_u53d8_u91cfx + _max_1 or _max_1 do
239 local _u53d8_u91cfy = _u53d8_u91cfx[_index_0] 238 local _u53d8_u91cfy = _u53d8_u91cfx[_index_0]
240 _u6253_u5370(_u53d8_u91cfy) 239 _u6253_u5370(_u53d8_u91cfy)
241end 240end
242for _index_0 = 2, #_u53d8_u91cfx do 241local _max_1 = #_u53d8_u91cfx
242for _index_0 = 2, _max_1 do
243 local _u53d8_u91cfy = _u53d8_u91cfx[_index_0] 243 local _u53d8_u91cfy = _u53d8_u91cfx[_index_0]
244 _u6253_u5370(_u53d8_u91cfy) 244 _u6253_u5370(_u53d8_u91cfy)
245end 245end
246for _index_0 = 1, #_u53d8_u91cfx, 2 do 246local _max_2 = #_u53d8_u91cfx
247for _index_0 = 1, _max_2, 2 do
247 local _u53d8_u91cfy = _u53d8_u91cfx[_index_0] 248 local _u53d8_u91cfy = _u53d8_u91cfx[_index_0]
248 _u6253_u5370(_u53d8_u91cfy) 249 _u6253_u5370(_u53d8_u91cfy)
249end 250end
250for _index_0 = 2, #_u53d8_u91cfx, 2 do 251local _max_3 = #_u53d8_u91cfx
252for _index_0 = 2, _max_3, 2 do
251 local _u53d8_u91cfy = _u53d8_u91cfx[_index_0] 253 local _u53d8_u91cfy = _u53d8_u91cfx[_index_0]
252 _u6253_u5370(_u53d8_u91cfy) 254 _u6253_u5370(_u53d8_u91cfy)
253end 255end
254local _u53d8_u91cfa, _u53d8_u91cfb, _u53d8_u91cfc = 1, 5, 2 256local _u53d8_u91cfa, _u53d8_u91cfb, _u53d8_u91cfc = 1, 5, 2
255local _max_2 = _u53d8_u91cfb 257local _min_0 = _u53d8_u91cfa
256for _index_0 = _u53d8_u91cfa, _max_2 < 0 and #_u53d8_u91cfx + _max_2 or _max_2, _u53d8_u91cfc do 258local _max_4 = _u53d8_u91cfb
259_min_0 = _min_0 < 0 and #_u53d8_u91cfx + _min_0 + 1 or _min_0
260_max_4 = _max_4 < 0 and #_u53d8_u91cfx + _max_4 + 1 or _max_4
261for _index_0 = _min_0, _max_4, _u53d8_u91cfc do
257 local _u53d8_u91cfy = _u53d8_u91cfx[_index_0] 262 local _u53d8_u91cfy = _u53d8_u91cfx[_index_0]
258 _u6253_u5370(_u53d8_u91cfy) 263 _u6253_u5370(_u53d8_u91cfy)
259end 264end
diff --git a/spec/outputs/unicode/loops.lua b/spec/outputs/unicode/loops.lua
index 8379993..27bbe2e 100644
--- a/spec/outputs/unicode/loops.lua
+++ b/spec/outputs/unicode/loops.lua
@@ -60,8 +60,8 @@ do
60 local _u53d8_u91cfy = _u4f60_u597d[_index_0] 60 local _u53d8_u91cfy = _u4f60_u597d[_index_0]
61 if _u53d8_u91cfy % 2 == 0 then 61 if _u53d8_u91cfy % 2 == 0 then
62 _accum_0[_len_0] = _u53d8_u91cfy 62 _accum_0[_len_0] = _u53d8_u91cfy
63 _len_0 = _len_0 + 1
63 end 64 end
64 _len_0 = _len_0 + 1
65 end 65 end
66 _u53d8_u91cfx = _accum_0 66 _u53d8_u91cfx = _accum_0
67end 67end
@@ -132,13 +132,11 @@ do
132end 132end
133do 133do
134 local _accum_0 = { } 134 local _accum_0 = { }
135 local _len_0 = 1
136 local _list_2 = 3 135 local _list_2 = 3
137 for _index_0 = 1, #_list_2 do 136 for _index_0 = 1, #_list_2 do
138 local _u4e1c_u897f = _list_2[_index_0] 137 local _u4e1c_u897f = _list_2[_index_0]
139 _u53d8_u91cfy = "你好" 138 _u53d8_u91cfy = "你好"
140 break 139 break
141 _len_0 = _len_0 + 1
142 end 140 end
143 _u53d8_u91cfx = _accum_0 141 _u53d8_u91cfx = _accum_0
144end 142end
diff --git a/spec/outputs/unicode/macro.lua b/spec/outputs/unicode/macro.lua
index b14f571..b4e78cd 100644
--- a/spec/outputs/unicode/macro.lua
+++ b/spec/outputs/unicode/macro.lua
@@ -216,17 +216,15 @@ do
216end 216end
217local _ = require('下划线') 217local _ = require('下划线')
218local _anon_func_0 = function(_) 218local _anon_func_0 = function(_)
219 do 219 local _call_0 = (_({
220 local _call_0 = (_({ 220 1,
221 1, 221 2,
222 2, 222 3,
223 3, 223 4,
224 4, 224 -2,
225 -2, 225 3
226 3 226 }))
227 })) 227 return _call_0["链"](_call_0)
228 return _call_0["链"](_call_0)
229 end
230end 228end
231local _call_0 = ((function() 229local _call_0 = ((function()
232 local _call_0 = ((function() 230 local _call_0 = ((function()
@@ -241,17 +239,15 @@ local _call_0 = ((function()
241end)()) 239end)())
242local _u7ed3_u679ca = _call_0["å–值"](_call_0) 240local _u7ed3_u679ca = _call_0["å–值"](_call_0)
243local _anon_func_1 = function(_) 241local _anon_func_1 = function(_)
244 do 242 local _call_1 = (_({
245 local _call_1 = (_({ 243 1,
246 1, 244 2,
247 2, 245 3,
248 3, 246 4,
249 4, 247 -2,
250 -2, 248 3
251 3 249 }))
252 })) 250 return _call_1["链"](_call_1)
253 return _call_1["链"](_call_1)
254 end
255end 251end
256do 252do
257 local _call_1 = ((function() 253 local _call_1 = ((function()
@@ -270,10 +266,8 @@ do
270 end) 266 end)
271end 267end
272local _anon_func_2 = function(_u539f_u70b9) 268local _anon_func_2 = function(_u539f_u70b9)
273 do 269 local _call_1 = _u539f_u70b9["å˜æ¢"]["根节点"]["游æˆå¯¹è±¡"]
274 local _call_1 = _u539f_u70b9["å˜æ¢"]["根节点"]["游æˆå¯¹è±¡"] 270 return _call_1["父节点"](_call_1)
275 return _call_1["父节点"](_call_1)
276 end
277end 271end
278local _call_1 = ((function() 272local _call_1 = ((function()
279 local _call_1 = ((function() 273 local _call_1 = ((function()
@@ -365,10 +359,8 @@ local _1
365_1 = function() 359_1 = function()
366 _u6253_u5370(1) 360 _u6253_u5370(1)
367 local _accum_0 = { } 361 local _accum_0 = { }
368 local _len_0 = 1
369 while false do 362 while false do
370 break 363 break
371 _len_0 = _len_0 + 1
372 end 364 end
373 return _accum_0 365 return _accum_0
374end 366end
diff --git a/spec/outputs/unicode/multiline_chain.lua b/spec/outputs/unicode/multiline_chain.lua
index c1da13f..61e7057 100644
--- a/spec/outputs/unicode/multiline_chain.lua
+++ b/spec/outputs/unicode/multiline_chain.lua
@@ -59,10 +59,8 @@ _u51fd_u6570 = function()
59 return _accum_0 59 return _accum_0
60end 60end
61local _anon_func_0 = function(_u53d8_u91cfa) 61local _anon_func_0 = function(_u53d8_u91cfa)
62 do 62 local _call_1 = _u53d8_u91cfa
63 local _call_1 = _u53d8_u91cfa 63 return (_call_1["å˜é‡b"](_call_1, 123))["å˜é‡c"]("abc")
64 return (_call_1["å˜é‡b"](_call_1, 123))["å˜é‡c"]("abc")
65 end
66end 64end
67local _u51fd_u65701 65local _u51fd_u65701
68_u51fd_u65701 = function() 66_u51fd_u65701 = function()
diff --git a/spec/outputs/unicode/syntax.lua b/spec/outputs/unicode/syntax.lua
index 1984f40..a13302b 100644
--- a/spec/outputs/unicode/syntax.lua
+++ b/spec/outputs/unicode/syntax.lua
@@ -286,10 +286,8 @@ _ = 5 - _u4ec0_u4e48(_u65e0_u804a)
286_u4ec0_u4e48(_u65e0_u804a - 5) 286_u4ec0_u4e48(_u65e0_u804a - 5)
287_u53d8_u91cfx = _u4f60_u597d - _u4e16_u754c - _u67d0_u7269 287_u53d8_u91cfx = _u4f60_u597d - _u4e16_u754c - _u67d0_u7269
288local _anon_func_0 = function(_u4ec0_u4e48) 288local _anon_func_0 = function(_u4ec0_u4e48)
289 do 289 local _call_8 = _u4ec0_u4e48
290 local _call_8 = _u4ec0_u4e48 290 return _call_8["é…·"](_call_8, 100)
291 return _call_8["é…·"](_call_8, 100)
292 end
293end 291end
294(function(_u67d0_u7269) 292(function(_u67d0_u7269)
295 if _u67d0_u7269 == nil then 293 if _u67d0_u7269 == nil then
diff --git a/spec/outputs/unicode/vararg.lua b/spec/outputs/unicode/vararg.lua
index b837006..fc894ff 100644
--- a/spec/outputs/unicode/vararg.lua
+++ b/spec/outputs/unicode/vararg.lua
@@ -125,14 +125,10 @@ local _anon_func_11 = function(_u9879_u76ee, ...)
125 return _tbl_0 125 return _tbl_0
126end 126end
127local _anon_func_12 = function(_u51fd_u6570) 127local _anon_func_12 = function(_u51fd_u6570)
128 do 128 return _u51fd_u6570()
129 return _u51fd_u6570()
130 end
131end 129end
132local _anon_func_13 = function(_u51fd_u6570, ...) 130local _anon_func_13 = function(_u51fd_u6570, ...)
133 do 131 return _u51fd_u6570(...)
134 return _u51fd_u6570(...)
135 end
136end 132end
137local _anon_func_14 = function(_u51fd_u6570) 133local _anon_func_14 = function(_u51fd_u6570)
138 local _accum_0 = { } 134 local _accum_0 = { }
@@ -195,15 +191,11 @@ local _anon_func_23 = function(_u51fd_u6570, ...)
195 return nil 191 return nil
196end 192end
197local _anon_func_24 = function(_u6253_u5370, select, ...) 193local _anon_func_24 = function(_u6253_u5370, select, ...)
198 do 194 _u6253_u5370(select("#", ...))
199 _u6253_u5370(select("#", ...)) 195 return _u6253_u5370(...)
200 return _u6253_u5370(...)
201 end
202end 196end
203local _anon_func_25 = function(_u6253_u5370, ...) 197local _anon_func_25 = function(_u6253_u5370, ...)
204 do 198 return _u6253_u5370(...)
205 return _u6253_u5370(...)
206 end
207end 199end
208local _anon_func_26 = function(_u53d8_u91cfx, _u8868, _u88682) 200local _anon_func_26 = function(_u53d8_u91cfx, _u8868, _u88682)
209 if 1 == _u53d8_u91cfx then 201 if 1 == _u53d8_u91cfx then
@@ -214,9 +206,7 @@ local _anon_func_26 = function(_u53d8_u91cfx, _u8868, _u88682)
214 end 206 end
215end 207end
216local _anon_func_27 = function(_u6253_u5370, ...) 208local _anon_func_27 = function(_u6253_u5370, ...)
217 do 209 return _u6253_u5370(...)
218 return _u6253_u5370(...)
219 end
220end 210end
221local _anon_func_28 = function(_u6761_u4ef6) 211local _anon_func_28 = function(_u6761_u4ef6)
222 if _u6761_u4ef6 then 212 if _u6761_u4ef6 then
@@ -224,10 +214,8 @@ local _anon_func_28 = function(_u6761_u4ef6)
224 end 214 end
225end 215end
226local _anon_func_29 = function(_u6253_u5370, _arg_0, ...) 216local _anon_func_29 = function(_u6253_u5370, _arg_0, ...)
227 do 217 local _u8868 = _arg_0
228 local _u8868 = _arg_0 218 return _u6253_u5370(...)
229 return _u6253_u5370(...)
230 end
231end 219end
232local _u8fde_u63a5 220local _u8fde_u63a5
233_u8fde_u63a5 = function(...) 221_u8fde_u63a5 = function(...)
diff --git a/spec/outputs/upvalue_func.lua b/spec/outputs/upvalue_func.lua
index 3181adf..3e088be 100644
--- a/spec/outputs/upvalue_func.lua
+++ b/spec/outputs/upvalue_func.lua
@@ -214,10 +214,8 @@ local _anon_func_1 = function(valueB)
214 end 214 end
215end 215end
216local _anon_func_2 = function(print, select, _arg_0, ...) 216local _anon_func_2 = function(print, select, _arg_0, ...)
217 do 217 local ok = _arg_0
218 local ok = _arg_0 218 return print(select(3, ...))
219 return print(select(3, ...))
220 end
221end 219end
222local _anon_func_3 = function(tb) 220local _anon_func_3 = function(tb)
223 if tb ~= nil then 221 if tb ~= nil then
@@ -242,11 +240,9 @@ local _anon_func_5 = function(getmetatable, tb)
242 return _obj_0[1 + 1](_obj_0, "abc") 240 return _obj_0[1 + 1](_obj_0, "abc")
243end 241end
244local _anon_func_6 = function(tb) 242local _anon_func_6 = function(tb)
245 do 243 local _call_0 = tb
246 local _call_0 = tb 244 local _call_1 = _call_0["end"](_call_0)
247 local _call_1 = _call_0["end"](_call_0) 245 return _call_1["🤣"](_call_1, 123)
248 return _call_1["🤣"](_call_1, 123)
249 end
250end 246end
251local _anon_func_7 = function(itemA, listA) 247local _anon_func_7 = function(itemA, listA)
252 for _index_0 = 1, #listA do 248 for _index_0 = 1, #listA do
@@ -354,17 +350,13 @@ local _anon_func_16 = function(pairs, tb, tostring)
354 return _tbl_0 350 return _tbl_0
355end 351end
356local _anon_func_17 = function(print) 352local _anon_func_17 = function(print)
357 do 353 print(123)
358 print(123) 354 return "abc"
359 return "abc"
360 end
361end 355end
362local _anon_func_18 = function(print, select, _arg_0, ...) 356local _anon_func_18 = function(print, select, _arg_0, ...)
363 do 357 local success = _arg_0
364 local success = _arg_0 358 if success then
365 if success then 359 return print(select('#', ...))
366 return print(select('#', ...))
367 end
368 end 360 end
369end 361end
370local _anon_func_19 = function(cond, i) 362local _anon_func_19 = function(cond, i)
@@ -459,11 +451,9 @@ local _anon_func_25 = function(itemA, listA)
459 return false 451 return false
460end 452end
461local _anon_func_24 = function(itemA, listA, tb) 453local _anon_func_24 = function(itemA, listA, tb)
462 do 454 local _call_0 = tb
463 local _call_0 = tb 455 local _call_1 = _call_0["end"](_call_0)
464 local _call_1 = _call_0["end"](_call_0) 456 return _call_1["🤣"](_call_1, 123 and (#listA > 0 and _anon_func_25(itemA, listA)))
465 return _call_1["🤣"](_call_1, 123 and (#listA > 0 and _anon_func_25(itemA, listA)))
466 end
467end 457end
468GameEngine:onEvent("SomeEvent", function() 458GameEngine:onEvent("SomeEvent", function()
469 return func(value + (_anon_func_21(cond)) + (_anon_func_22(valueB)) > _anon_func_23(tb) + _anon_func_24(itemA, listA, tb)) 459 return func(value + (_anon_func_21(cond)) + (_anon_func_22(valueB)) > _anon_func_23(tb) + _anon_func_24(itemA, listA, tb))
@@ -503,13 +493,11 @@ local _anon_func_27 = function(char)
503 return nil 493 return nil
504end 494end
505local _anon_func_28 = function(os, _arg_0, ...) 495local _anon_func_28 = function(os, _arg_0, ...)
506 do 496 local ok = _arg_0
507 local ok = _arg_0 497 if ok then
508 if ok then 498 return ...
509 return ... 499 else
510 else 500 return os.exit(1)
511 return os.exit(1)
512 end
513 end 501 end
514end 502end
515local _anon_func_29 = function(debug_env_after, debug_env_before, env, func) 503local _anon_func_29 = function(debug_env_after, debug_env_before, env, func)
diff --git a/spec/outputs/vararg.lua b/spec/outputs/vararg.lua
index dabba44..254aa6a 100644
--- a/spec/outputs/vararg.lua
+++ b/spec/outputs/vararg.lua
@@ -125,14 +125,10 @@ local _anon_func_11 = function(items, ...)
125 return _tbl_0 125 return _tbl_0
126end 126end
127local _anon_func_12 = function(func) 127local _anon_func_12 = function(func)
128 do 128 return func()
129 return func()
130 end
131end 129end
132local _anon_func_13 = function(func, ...) 130local _anon_func_13 = function(func, ...)
133 do 131 return func(...)
134 return func(...)
135 end
136end 132end
137local _anon_func_14 = function(func) 133local _anon_func_14 = function(func)
138 local _accum_0 = { } 134 local _accum_0 = { }
@@ -195,15 +191,11 @@ local _anon_func_23 = function(func, ...)
195 return nil 191 return nil
196end 192end
197local _anon_func_24 = function(print, select, ...) 193local _anon_func_24 = function(print, select, ...)
198 do 194 print(select("#", ...))
199 print(select("#", ...)) 195 return print(...)
200 return print(...)
201 end
202end 196end
203local _anon_func_25 = function(print, ...) 197local _anon_func_25 = function(print, ...)
204 do 198 return print(...)
205 return print(...)
206 end
207end 199end
208local _anon_func_26 = function(tb, tb2, x) 200local _anon_func_26 = function(tb, tb2, x)
209 if 1 == x then 201 if 1 == x then
@@ -214,9 +206,7 @@ local _anon_func_26 = function(tb, tb2, x)
214 end 206 end
215end 207end
216local _anon_func_27 = function(print, ...) 208local _anon_func_27 = function(print, ...)
217 do 209 return print(...)
218 return print(...)
219 end
220end 210end
221local _anon_func_28 = function(cond) 211local _anon_func_28 = function(cond)
222 if cond then 212 if cond then
@@ -224,10 +214,8 @@ local _anon_func_28 = function(cond)
224 end 214 end
225end 215end
226local _anon_func_29 = function(print, _arg_0, ...) 216local _anon_func_29 = function(print, _arg_0, ...)
227 do 217 local tb = _arg_0
228 local tb = _arg_0 218 return print(...)
229 return print(...)
230 end
231end 219end
232local join 220local join
233join = function(...) 221join = function(...)
diff --git a/spec/outputs/with.lua b/spec/outputs/with.lua
index 1a795c1..530915e 100644
--- a/spec/outputs/with.lua
+++ b/spec/outputs/with.lua
@@ -187,4 +187,66 @@ do
187 return _with_0[123] 187 return _with_0[123]
188 end 188 end
189end 189end
190do
191 f((function()
192 local _with_0 = item
193 do
194 local _accum_0
195 repeat
196 if _with_0.id > 0 then
197 _accum_0 = _with_0.content
198 break
199 end
200 until true
201 _with_0 = _accum_0
202 end
203 return _with_0
204 end)())
205 local a
206 do
207 local _with_0 = tb
208 do
209 local _accum_0
210 repeat
211 if _with_0.v then
212 _accum_0 = _with_0.a
213 break
214 end
215 until true
216 _with_0 = _accum_0
217 end
218 a = _with_0
219 end
220 local _accum_0
221 while true do
222 local _with_0 = tb
223 local _accum_1
224 repeat
225 if _with_0 ~= nil then
226 _accum_1 = 1
227 break
228 end
229 until true
230 _with_0 = _accum_1
231 _accum_0 = _with_0
232 break
233 end
234 a = _accum_0
235end
236do
237 local a
238 local _accum_0
239 for i = 1, 100 do
240 local x = tb[i]
241 if x ~= nil then
242 local _des_0 = 1
243 if _des_0 then
244 x.id = _des_0
245 _accum_0 = x
246 break
247 end
248 end
249 end
250 a = _accum_0
251end
190return nil 252return nil
diff --git a/src/3rdParty/efsw/FileWatcherGeneric.cpp b/src/3rdParty/efsw/FileWatcherGeneric.cpp
index 3f3c52e..468d27c 100644
--- a/src/3rdParty/efsw/FileWatcherGeneric.cpp
+++ b/src/3rdParty/efsw/FileWatcherGeneric.cpp
@@ -25,7 +25,7 @@ FileWatcherGeneric::~FileWatcherGeneric() {
25} 25}
26 26
27WatchID FileWatcherGeneric::addWatch( const std::string& directory, FileWatchListener* watcher, 27WatchID FileWatcherGeneric::addWatch( const std::string& directory, FileWatchListener* watcher,
28 bool recursive, const std::vector<WatcherOption>& options ) { 28 bool recursive, const std::vector<WatcherOption>& /*options*/ ) {
29 std::string dir( directory ); 29 std::string dir( directory );
30 30
31 FileSystem::dirAddSlashAtEnd( dir ); 31 FileSystem::dirAddSlashAtEnd( dir );
diff --git a/src/yuescript/yue_ast.cpp b/src/yuescript/yue_ast.cpp
index fe6e726..945e1d7 100644
--- a/src/yuescript/yue_ast.cpp
+++ b/src/yuescript/yue_ast.cpp
@@ -167,12 +167,11 @@ std::string ExistentialOp_t::to_string(void*) const {
167std::string TableAppendingOp_t::to_string(void*) const { 167std::string TableAppendingOp_t::to_string(void*) const {
168 return "[]"s; 168 return "[]"s;
169} 169}
170std::string PlainItem_t::to_string(void *) const { 170std::string PlainItem_t::to_string(void*) const {
171 return {}; 171 return {};
172} 172}
173std::string GlobalOp_t::to_string(void* ud) const { 173std::string GlobalOp_t::to_string(void*) const {
174 auto info = reinterpret_cast<YueFormat*>(ud); 174 return "*"s;
175 return info->convert(this);
176} 175}
177std::string ExportDefault_t::to_string(void*) const { 176std::string ExportDefault_t::to_string(void*) const {
178 return "default"s; 177 return "default"s;
@@ -188,9 +187,17 @@ std::string ConstValue_t::to_string(void* ud) const {
188std::string NotIn_t::to_string(void*) const { 187std::string NotIn_t::to_string(void*) const {
189 return {}; 188 return {};
190} 189}
190std::string Break_t::to_string(void*) const {
191 return "break"s;
192}
193std::string Continue_t::to_string(void*) const {
194 return "continue"s;
195}
191std::string BreakLoop_t::to_string(void* ud) const { 196std::string BreakLoop_t::to_string(void* ud) const {
192 auto info = reinterpret_cast<YueFormat*>(ud); 197 if (value) {
193 return info->convert(this); 198 return type->to_string(ud) + ' ' + value->to_string(ud);
199 }
200 return type->to_string(ud);
194} 201}
195std::string YueLineComment_t::to_string(void* ud) const { 202std::string YueLineComment_t::to_string(void* ud) const {
196 auto info = reinterpret_cast<YueFormat*>(ud); 203 auto info = reinterpret_cast<YueFormat*>(ud);
@@ -297,6 +304,17 @@ std::string ImportAs_t::to_string(void* ud) const {
297 } 304 }
298 return join(temp, " "s); 305 return join(temp, " "s);
299} 306}
307std::string ImportGlobal_t::to_string(void* ud) const {
308 str_list temp;
309 for (auto seg : segs.objects()) {
310 temp.emplace_back(seg->to_string(ud));
311 }
312 auto item = join(temp, "."s);
313 if (target) {
314 return item + " as "s + target->to_string(ud);
315 }
316 return item;
317}
300std::string Import_t::to_string(void* ud) const { 318std::string Import_t::to_string(void* ud) const {
301 if (ast_is<FromImport_t>(content)) { 319 if (ast_is<FromImport_t>(content)) {
302 return content->to_string(ud); 320 return content->to_string(ud);
@@ -324,6 +342,12 @@ std::string Backcall_t::to_string(void* ud) const {
324 temp.emplace_back(value->to_string(ud)); 342 temp.emplace_back(value->to_string(ud));
325 return join(temp, " "sv); 343 return join(temp, " "sv);
326} 344}
345std::string SubBackcall_t::to_string(void* ud) const {
346 str_list temp;
347 temp.emplace_back(arrow->to_string(ud));
348 temp.emplace_back(value->to_string(ud));
349 return join(temp, " "sv);
350}
327std::string PipeBody_t::to_string(void* ud) const { 351std::string PipeBody_t::to_string(void* ud) const {
328 auto info = reinterpret_cast<YueFormat*>(ud); 352 auto info = reinterpret_cast<YueFormat*>(ud);
329 str_list temp; 353 str_list temp;
@@ -359,8 +383,8 @@ std::string With_t::to_string(void* ud) const {
359 str_list temp{ 383 str_list temp{
360 eop ? "with?"s : "with"s, 384 eop ? "with?"s : "with"s,
361 valueList->to_string(ud)}; 385 valueList->to_string(ud)};
362 if (assigns) { 386 if (assign) {
363 temp.push_back(assigns->to_string(ud)); 387 temp.push_back(':' + assign->to_string(ud));
364 } 388 }
365 if (body.is<Statement_t>()) { 389 if (body.is<Statement_t>()) {
366 return join(temp, " "sv) + " do "s + body->to_string(ud); 390 return join(temp, " "sv) + " do "s + body->to_string(ud);
@@ -406,6 +430,9 @@ std::string SwitchCase_t::to_string(void* ud) const {
406std::string Switch_t::to_string(void* ud) const { 430std::string Switch_t::to_string(void* ud) const {
407 auto info = reinterpret_cast<YueFormat*>(ud); 431 auto info = reinterpret_cast<YueFormat*>(ud);
408 str_list temp{"switch "s + target->to_string(ud)}; 432 str_list temp{"switch "s + target->to_string(ud)};
433 if (assignment) {
434 temp.back().append(assignment->to_string(ud));
435 }
409 info->pushScope(); 436 info->pushScope();
410 for (auto branch : branches.objects()) { 437 for (auto branch : branches.objects()) {
411 temp.emplace_back(info->ind() + branch->to_string(ud)); 438 temp.emplace_back(info->ind() + branch->to_string(ud));
@@ -449,41 +476,75 @@ std::string If_t::to_string(void* ud) const {
449 temp.back() += " then"s; 476 temp.back() += " then"s;
450 } 477 }
451 ++it; 478 ++it;
452 bool condition = true; 479 enum class NType {
480 Cond,
481 Stat,
482 Block
483 };
484 NType lastType = NType::Cond;
453 for (; it != nodes.objects().end(); ++it) { 485 for (; it != nodes.objects().end(); ++it) {
454 auto node = *it; 486 auto node = *it;
455 switch (node->get_id()) { 487 switch (node->get_id()) {
456 case id<IfCond_t>(): 488 case id<IfCond_t>():
457 temp.emplace_back(info->ind() + "elseif "s + node->to_string(ud)); 489 temp.emplace_back(info->ind() + "elseif "s + node->to_string(ud));
458 condition = true; 490 lastType = NType::Cond;
459 break; 491 break;
460 case id<Statement_t>(): { 492 case id<Statement_t>(): {
461 if (condition) { 493 switch (lastType) {
462 temp.back() += " then "s + node->to_string(ud); 494 case NType::Cond:
463 } else { 495 temp.back() += " then "s + node->to_string(ud);
464 temp.emplace_back(info->ind() + "else "s + node->to_string(ud)); 496 break;
497 case NType::Stat:
498 if (temp.back().back() == '\n') {
499 temp.emplace_back(info->ind() + "else "s + node->to_string(ud));
500 } else {
501 temp.back() += " else "s + node->to_string(ud);
502 }
503 break;
504 case NType::Block:
505 temp.emplace_back(info->ind() + "else "s + node->to_string(ud));
506 break;
465 } 507 }
466 condition = false; 508 lastType = NType::Stat;
467 break; 509 break;
468 } 510 }
469 case id<Block_t>(): { 511 case id<Block_t>(): {
470 if (condition) { 512 switch (lastType) {
471 info->pushScope(); 513 case NType::Cond: {
472 temp.emplace_back(node->to_string(ud)); 514 info->pushScope();
473 if (temp.back().empty()) { 515 temp.emplace_back(node->to_string(ud));
474 temp.back() = info->ind() + "--"s; 516 if (temp.back().empty()) {
517 temp.back() = info->ind() + "--"s;
518 }
519 info->popScope();
520 break;
521 }
522 case NType::Stat: {
523 if (temp.back().back() == '\n') {
524 temp.emplace_back(info->ind() + "else"s);
525 } else {
526 temp.back() += " else"s;
527 }
528 info->pushScope();
529 temp.emplace_back(node->to_string(ud));
530 if (temp.back().empty()) {
531 temp.back() = info->ind() + "--"s;
532 }
533 info->popScope();
534 break;
475 } 535 }
476 info->popScope(); 536 case NType::Block: {
477 } else { 537 temp.emplace_back(info->ind() + "else"s);
478 temp.emplace_back(info->ind() + "else"s); 538 info->pushScope();
479 info->pushScope(); 539 temp.emplace_back(node->to_string(ud));
480 temp.emplace_back(node->to_string(ud)); 540 if (temp.back().empty()) {
481 if (temp.back().empty()) { 541 temp.back() = info->ind() + "--"s;
482 temp.back() = info->ind() + "--"s; 542 }
543 info->popScope();
544 break;
483 } 545 }
484 info->popScope();
485 } 546 }
486 condition = false; 547 lastType = NType::Block;
487 break; 548 break;
488 } 549 }
489 } 550 }
@@ -511,10 +572,10 @@ std::string While_t::to_string(void* ud) const {
511} 572}
512std::string Repeat_t::to_string(void* ud) const { 573std::string Repeat_t::to_string(void* ud) const {
513 auto info = reinterpret_cast<YueFormat*>(ud); 574 auto info = reinterpret_cast<YueFormat*>(ud);
514 str_list temp; 575 if (body.is<Statement_t>()) {
515 if (body->content.is<Statement_t>()) { 576 return "repeat "s + body->to_string(ud) + " until "s + condition->to_string(ud);
516 temp.emplace_back("repeat "s + body->to_string(ud));
517 } else { 577 } else {
578 str_list temp;
518 temp.emplace_back("repeat"s); 579 temp.emplace_back("repeat"s);
519 info->pushScope(); 580 info->pushScope();
520 temp.emplace_back(body->to_string(ud)); 581 temp.emplace_back(body->to_string(ud));
@@ -522,9 +583,9 @@ std::string Repeat_t::to_string(void* ud) const {
522 temp.back() = info->ind() + "--"s; 583 temp.back() = info->ind() + "--"s;
523 } 584 }
524 info->popScope(); 585 info->popScope();
586 temp.emplace_back(info->ind() + "until "s + condition->to_string(ud));
587 return join(temp, "\n"sv);
525 } 588 }
526 temp.emplace_back(info->ind() + "until "s + condition->to_string(ud));
527 return join(temp, "\n"sv);
528} 589}
529std::string ForStepValue_t::to_string(void* ud) const { 590std::string ForStepValue_t::to_string(void* ud) const {
530 return value->to_string(ud); 591 return value->to_string(ud);
@@ -596,10 +657,13 @@ std::string CatchBlock_t::to_string(void* ud) const {
596std::string Try_t::to_string(void* ud) const { 657std::string Try_t::to_string(void* ud) const {
597 auto info = reinterpret_cast<YueFormat*>(ud); 658 auto info = reinterpret_cast<YueFormat*>(ud);
598 str_list temp; 659 str_list temp;
660 temp.emplace_back("try"s);
661 if (eop) {
662 temp.back() += eop->to_string(ud);
663 }
599 if (func.is<Exp_t>()) { 664 if (func.is<Exp_t>()) {
600 temp.emplace_back("try "s + func->to_string(ud)); 665 temp.back() += (" "s + func->to_string(ud));
601 } else { 666 } else {
602 temp.emplace_back("try"s);
603 info->pushScope(); 667 info->pushScope();
604 temp.emplace_back(func->to_string(ud)); 668 temp.emplace_back(func->to_string(ud));
605 if (temp.back().empty()) { 669 if (temp.back().empty()) {
@@ -851,6 +915,12 @@ std::string Exp_t::to_string(void* ud) const {
851 } 915 }
852 return join(temp, " "sv); 916 return join(temp, " "sv);
853} 917}
918std::string ReversedIndex_t::to_string(void* ud) const {
919 if (modifier) {
920 return "[# - "s + modifier->to_string(ud) + ']';
921 }
922 return "[#]"s;
923}
854std::string Callable_t::to_string(void* ud) const { 924std::string Callable_t::to_string(void* ud) const {
855 return item->to_string(ud); 925 return item->to_string(ud);
856} 926}
@@ -937,6 +1007,51 @@ std::string DoubleString_t::to_string(void* ud) const {
937 } 1007 }
938 return '"' + join(temp) + '"'; 1008 return '"' + join(temp) + '"';
939} 1009}
1010std::string YAMLIndent_t::to_string(void* ud) const {
1011 auto info = reinterpret_cast<YueFormat*>(ud);
1012 return info->convert(this);
1013}
1014std::string YAMLLineInner_t::to_string(void* ud) const {
1015 auto info = reinterpret_cast<YueFormat*>(ud);
1016 return info->convert(this);
1017}
1018std::string YAMLLineContent_t::to_string(void* ud) const {
1019 if (content.is<Exp_t>()) {
1020 return "#{"s + content->to_string(ud) + '}';
1021 }
1022 return content->to_string(ud);
1023}
1024std::string YAMLLine_t::to_string(void* ud) const {
1025 str_list temp;
1026 for (auto seg : segments.objects()) {
1027 temp.emplace_back(seg->to_string(ud));
1028 }
1029 return join(temp);
1030}
1031std::string YAMLMultiline_t::to_string(void* ud) const {
1032 auto info = reinterpret_cast<YueFormat*>(ud);
1033 int currentIndent = info->indent;
1034 str_list temp;
1035 int lastIndent = -1;
1036 for (auto line_ : lines.objects()) {
1037 auto line = static_cast<YAMLLine_t*>(line_);
1038 auto indent = line->indent->to_string(ud);
1039 int ind = 0;
1040 for (auto c : indent) {
1041 if (c == ' ') ind++;
1042 if (c == '\t') ind += 4;
1043 }
1044 if (lastIndent < ind) {
1045 info->pushScope();
1046 } else if (lastIndent > ind) {
1047 info->popScope();
1048 }
1049 lastIndent = ind;
1050 temp.emplace_back(indent + line->to_string(ud));
1051 }
1052 info->indent = currentIndent;
1053 return "|\n" + join(temp, "\n"sv) + '\n';
1054}
940std::string String_t::to_string(void* ud) const { 1055std::string String_t::to_string(void* ud) const {
941 return str->to_string(ud); 1056 return str->to_string(ud);
942} 1057}
@@ -1125,7 +1240,7 @@ std::string ClassDecl_t::to_string(void* ud) const {
1125 return line; 1240 return line;
1126} 1241}
1127std::string GlobalValues_t::to_string(void* ud) const { 1242std::string GlobalValues_t::to_string(void* ud) const {
1128 auto line = nameList->to_string(ud); 1243 std::string line = nameList->to_string(ud);
1129 if (valueList) { 1244 if (valueList) {
1130 if (valueList.is<TableBlock_t>()) { 1245 if (valueList.is<TableBlock_t>()) {
1131 line += " =\n"s + valueList->to_string(ud); 1246 line += " =\n"s + valueList->to_string(ud);
@@ -1136,7 +1251,7 @@ std::string GlobalValues_t::to_string(void* ud) const {
1136 return line; 1251 return line;
1137} 1252}
1138std::string Global_t::to_string(void* ud) const { 1253std::string Global_t::to_string(void* ud) const {
1139 return "global "s + item->to_string(ud); 1254 return "global "s + (constAttrib ? "const "s : ""s) + item->to_string(ud);
1140} 1255}
1141std::string Export_t::to_string(void* ud) const { 1256std::string Export_t::to_string(void* ud) const {
1142 auto line = "export"s; 1257 auto line = "export"s;
@@ -1235,6 +1350,9 @@ std::string FnArgDef_t::to_string(void* ud) const {
1235 if (op) { 1350 if (op) {
1236 line += op->to_string(ud); 1351 line += op->to_string(ud);
1237 } 1352 }
1353 if (label) {
1354 line += '`' + label->to_string(ud);
1355 }
1238 if (defaultValue) { 1356 if (defaultValue) {
1239 line += " = "s + defaultValue->to_string(ud); 1357 line += " = "s + defaultValue->to_string(ud);
1240 } 1358 }
@@ -1257,6 +1375,9 @@ std::string FnArgDefList_t::to_string(void* ud) const {
1257 } 1375 }
1258 if (varArg) { 1376 if (varArg) {
1259 temp.emplace_back(info->ind() + varArg->to_string(ud)); 1377 temp.emplace_back(info->ind() + varArg->to_string(ud));
1378 if (label) {
1379 temp.back().append('`' + label->to_string(ud));
1380 }
1260 } 1381 }
1261 return join(temp, "\n"sv); 1382 return join(temp, "\n"sv);
1262 } else { 1383 } else {
@@ -1265,6 +1386,9 @@ std::string FnArgDefList_t::to_string(void* ud) const {
1265 } 1386 }
1266 if (varArg) { 1387 if (varArg) {
1267 temp.emplace_back(varArg->to_string(ud)); 1388 temp.emplace_back(varArg->to_string(ud));
1389 if (label) {
1390 temp.back().append('`' + label->to_string(ud));
1391 }
1268 } 1392 }
1269 return join(temp, ", "sv); 1393 return join(temp, ", "sv);
1270 } 1394 }
@@ -1546,3 +1670,4 @@ std::string File_t::to_string(void* ud) const {
1546} // namespace yue 1670} // namespace yue
1547 1671
1548} // namespace parserlib 1672} // namespace parserlib
1673
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h
index 5e70645..6e1bb88 100644
--- a/src/yuescript/yue_ast.h
+++ b/src/yuescript/yue_ast.h
@@ -233,8 +233,15 @@ AST_NODE(ImportAs)
233 AST_MEMBER(ImportAs, &literal, &target) 233 AST_MEMBER(ImportAs, &literal, &target)
234AST_END(ImportAs) 234AST_END(ImportAs)
235 235
236AST_NODE(ImportGlobal)
237 ast_ptr<true, Seperator_t> sep;
238 ast_list<true, UnicodeName_t> segs;
239 ast_ptr<false, Variable_t> target;
240 AST_MEMBER(ImportGlobal, &sep, &segs, &target)
241AST_END(ImportGlobal)
242
236AST_NODE(Import) 243AST_NODE(Import)
237 ast_sel<true, ImportAs_t, ImportFrom_t, FromImport_t> content; 244 ast_sel<true, ImportAs_t, ImportFrom_t, FromImport_t, ImportGlobal_t> content;
238 AST_MEMBER(Import, &content) 245 AST_MEMBER(Import, &content)
239AST_END(Import) 246AST_END(Import)
240 247
@@ -273,6 +280,8 @@ AST_NODE(ExpList)
273 ast_ptr<true, Seperator_t> sep; 280 ast_ptr<true, Seperator_t> sep;
274 ast_list<true, Exp_t> exprs; 281 ast_list<true, Exp_t> exprs;
275 AST_MEMBER(ExpList, &sep, &exprs) 282 AST_MEMBER(ExpList, &sep, &exprs)
283 bool followStmtProcessed = false;
284 Statement_t* followStmt = nullptr;
276AST_END(ExpList) 285AST_END(ExpList)
277 286
278AST_NODE(Return) 287AST_NODE(Return)
@@ -285,9 +294,9 @@ AST_END(Return)
285AST_NODE(With) 294AST_NODE(With)
286 ast_ptr<false, ExistentialOp_t> eop; 295 ast_ptr<false, ExistentialOp_t> eop;
287 ast_ptr<true, ExpList_t> valueList; 296 ast_ptr<true, ExpList_t> valueList;
288 ast_ptr<false, Assign_t> assigns; 297 ast_ptr<false, Assign_t> assign;
289 ast_sel<true, Block_t, Statement_t> body; 298 ast_sel<true, Block_t, Statement_t> body;
290 AST_MEMBER(With, &eop, &valueList, &assigns, &body) 299 AST_MEMBER(With, &eop, &valueList, &assign, &body)
291AST_END(With) 300AST_END(With)
292 301
293AST_NODE(SwitchList) 302AST_NODE(SwitchList)
@@ -302,20 +311,21 @@ AST_NODE(SwitchCase)
302 AST_MEMBER(SwitchCase, &condition, &body) 311 AST_MEMBER(SwitchCase, &condition, &body)
303AST_END(SwitchCase) 312AST_END(SwitchCase)
304 313
314AST_NODE(Assignment)
315 ast_ptr<false, ExpList_t> expList;
316 ast_ptr<true, Assign_t> assign;
317 AST_MEMBER(Assignment, &expList, &assign)
318AST_END(Assignment)
319
305AST_NODE(Switch) 320AST_NODE(Switch)
306 ast_ptr<true, Exp_t> target; 321 ast_ptr<true, Exp_t> target;
322 ast_ptr<false, Assignment_t> assignment;
307 ast_ptr<true, Seperator_t> sep; 323 ast_ptr<true, Seperator_t> sep;
308 ast_list<true, SwitchCase_t> branches; 324 ast_list<true, SwitchCase_t> branches;
309 ast_sel<false, Block_t, Statement_t> lastBranch; 325 ast_sel<false, Block_t, Statement_t> lastBranch;
310 AST_MEMBER(Switch, &target, &sep, &branches, &lastBranch) 326 AST_MEMBER(Switch, &target, &assignment, &sep, &branches, &lastBranch)
311AST_END(Switch) 327AST_END(Switch)
312 328
313AST_NODE(Assignment)
314 ast_ptr<false, ExpList_t> expList;
315 ast_ptr<true, Assign_t> assign;
316 AST_MEMBER(Assignment, &expList, &assign)
317AST_END(Assignment)
318
319AST_NODE(IfCond) 329AST_NODE(IfCond)
320 ast_ptr<true, Exp_t> condition; 330 ast_ptr<true, Exp_t> condition;
321 ast_ptr<false, Assignment_t> assignment; 331 ast_ptr<false, Assignment_t> assignment;
@@ -343,7 +353,7 @@ AST_NODE(While)
343AST_END(While) 353AST_END(While)
344 354
345AST_NODE(Repeat) 355AST_NODE(Repeat)
346 ast_ptr<true, Body_t> body; 356 ast_sel<true, Block_t, Statement_t> body;
347 ast_ptr<true, Exp_t> condition; 357 ast_ptr<true, Exp_t> condition;
348 AST_MEMBER(Repeat, &body, &condition) 358 AST_MEMBER(Repeat, &body, &condition)
349AST_END(Repeat) 359AST_END(Repeat)
@@ -381,9 +391,10 @@ AST_NODE(CatchBlock)
381AST_END(CatchBlock) 391AST_END(CatchBlock)
382 392
383AST_NODE(Try) 393AST_NODE(Try)
394 ast_ptr<false, ExistentialOp_t> eop;
384 ast_sel<true, Block_t, Exp_t> func; 395 ast_sel<true, Block_t, Exp_t> func;
385 ast_ptr<false, CatchBlock_t> catchBlock; 396 ast_ptr<false, CatchBlock_t> catchBlock;
386 AST_MEMBER(Try, &func, &catchBlock) 397 AST_MEMBER(Try, &eop, &func, &catchBlock)
387AST_END(Try) 398AST_END(Try)
388 399
389AST_NODE(Comprehension) 400AST_NODE(Comprehension)
@@ -547,8 +558,8 @@ AST_NODE(SimpleValue)
547 ast_sel<true, 558 ast_sel<true,
548 TableLit_t, ConstValue_t, 559 TableLit_t, ConstValue_t,
549 If_t, Switch_t, With_t, ClassDecl_t, 560 If_t, Switch_t, With_t, ClassDecl_t,
550 ForEach_t, For_t, While_t, Do_t, Try_t, 561 ForEach_t, For_t, While_t, Repeat_t,
551 UnaryValue_t, 562 Do_t, Try_t, UnaryValue_t,
552 TblComprehension_t, Comprehension_t, 563 TblComprehension_t, Comprehension_t,
553 FunLit_t, Num_t, VarArg_t> value; 564 FunLit_t, Num_t, VarArg_t> value;
554 AST_MEMBER(SimpleValue, &value) 565 AST_MEMBER(SimpleValue, &value)
@@ -587,8 +598,31 @@ AST_NODE(DoubleString)
587 AST_MEMBER(DoubleString, &sep, &segments) 598 AST_MEMBER(DoubleString, &sep, &segments)
588AST_END(DoubleString) 599AST_END(DoubleString)
589 600
601AST_LEAF(YAMLIndent)
602AST_END(YAMLIndent)
603
604AST_LEAF(YAMLLineInner)
605AST_END(YAMLLineInner)
606
607AST_NODE(YAMLLineContent)
608 ast_sel<true, YAMLLineInner_t, Exp_t> content;
609 AST_MEMBER(YAMLLineContent, &content)
610AST_END(YAMLLineContent)
611
612AST_NODE(YAMLLine)
613 ast_ptr<true, YAMLIndent_t> indent;
614 ast_list<true, YAMLLineContent_t> segments;
615 AST_MEMBER(YAMLLine, &indent, &segments)
616AST_END(YAMLLine)
617
618AST_NODE(YAMLMultiline)
619 ast_ptr<true, Seperator_t> sep;
620 ast_list<true, YAMLLine_t> lines;
621 AST_MEMBER(YAMLMultiline, &sep, &lines)
622AST_END(YAMLMultiline)
623
590AST_NODE(String) 624AST_NODE(String)
591 ast_sel<true, DoubleString_t, SingleString_t, LuaString_t> str; 625 ast_sel<true, DoubleString_t, SingleString_t, LuaString_t, YAMLMultiline_t> str;
592 AST_MEMBER(String, &str) 626 AST_MEMBER(String, &str)
593AST_END(String) 627AST_END(String)
594 628
@@ -639,9 +673,14 @@ AST_END(TableAppendingOp)
639AST_LEAF(PlainItem) 673AST_LEAF(PlainItem)
640AST_END(PlainItem) 674AST_END(PlainItem)
641 675
676AST_NODE(ReversedIndex)
677 ast_ptr<false, Exp_t> modifier;
678 AST_MEMBER(ReversedIndex, &modifier)
679AST_END(ReversedIndex)
680
642AST_NODE(ChainValue) 681AST_NODE(ChainValue)
643 ast_ptr<true, Seperator_t> sep; 682 ast_ptr<true, Seperator_t> sep;
644 ast_sel_list<true, Callable_t, Invoke_t, DotChainItem_t, ColonChainItem_t, Slice_t, Exp_t, String_t, InvokeArgs_t, ExistentialOp_t, TableAppendingOp_t, 683 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,
645 /*non-syntax-rule*/ PlainItem_t> items; 684 /*non-syntax-rule*/ PlainItem_t> items;
646 AST_MEMBER(ChainValue, &sep, &items) 685 AST_MEMBER(ChainValue, &sep, &items)
647AST_END(ChainValue) 686AST_END(ChainValue)
@@ -725,8 +764,9 @@ AST_LEAF(GlobalOp)
725AST_END(GlobalOp) 764AST_END(GlobalOp)
726 765
727AST_NODE(Global) 766AST_NODE(Global)
767 ast_ptr<false, ConstAttrib_t> constAttrib;
728 ast_sel<true, ClassDecl_t, GlobalOp_t, GlobalValues_t> item; 768 ast_sel<true, ClassDecl_t, GlobalOp_t, GlobalValues_t> item;
729 AST_MEMBER(Global, &item) 769 AST_MEMBER(Global, &constAttrib, &item)
730AST_END(Global) 770AST_END(Global)
731 771
732AST_LEAF(ExportDefault) 772AST_LEAF(ExportDefault)
@@ -740,17 +780,19 @@ AST_NODE(Export)
740AST_END(Export) 780AST_END(Export)
741 781
742AST_NODE(FnArgDef) 782AST_NODE(FnArgDef)
743 ast_sel<true, Variable_t, SelfItem_t> name; 783 ast_sel<true, Variable_t, SelfItem_t, SimpleTable_t, TableLit_t> name;
744 ast_ptr<false, ExistentialOp_t> op; 784 ast_ptr<false, ExistentialOp_t> op;
785 ast_ptr<false, Name_t> label;
745 ast_ptr<false, Exp_t> defaultValue; 786 ast_ptr<false, Exp_t> defaultValue;
746 AST_MEMBER(FnArgDef, &name, &op, &defaultValue) 787 AST_MEMBER(FnArgDef, &name, &op, &label, &defaultValue)
747AST_END(FnArgDef) 788AST_END(FnArgDef)
748 789
749AST_NODE(FnArgDefList) 790AST_NODE(FnArgDefList)
750 ast_ptr<true, Seperator_t> sep; 791 ast_ptr<true, Seperator_t> sep;
751 ast_list<false, FnArgDef_t> definitions; 792 ast_list<false, FnArgDef_t> definitions;
752 ast_ptr<false, VarArg_t> varArg; 793 ast_ptr<false, VarArg_t> varArg;
753 AST_MEMBER(FnArgDefList, &sep, &definitions, &varArg) 794 ast_ptr<false, Name_t> label;
795 AST_MEMBER(FnArgDefList, &sep, &definitions, &varArg, &label)
754AST_END(FnArgDefList) 796AST_END(FnArgDefList)
755 797
756AST_NODE(OuterVarShadow) 798AST_NODE(OuterVarShadow)
@@ -838,9 +880,15 @@ AST_NODE(UnaryExp)
838 AST_MEMBER(UnaryExp, &ops, &expos, &inExp) 880 AST_MEMBER(UnaryExp, &ops, &expos, &inExp)
839AST_END(UnaryExp) 881AST_END(UnaryExp)
840 882
883AST_NODE(SubBackcall)
884 ast_ptr<true, FnArrowBack_t> arrow;
885 ast_ptr<true, ChainValue_t> value;
886 AST_MEMBER(SubBackcall, &arrow, &value)
887AST_END(SubBackcall)
888
841AST_NODE(ExpListAssign) 889AST_NODE(ExpListAssign)
842 ast_ptr<true, ExpList_t> expList; 890 ast_ptr<true, ExpList_t> expList;
843 ast_sel<false, Update_t, Assign_t> action; 891 ast_sel<false, Update_t, Assign_t, SubBackcall_t> action;
844 AST_MEMBER(ExpListAssign, &expList, &action) 892 AST_MEMBER(ExpListAssign, &expList, &action)
845AST_END(ExpListAssign) 893AST_END(ExpListAssign)
846 894
@@ -856,7 +904,17 @@ AST_NODE(WhileLine)
856 AST_MEMBER(WhileLine, &type, &condition) 904 AST_MEMBER(WhileLine, &type, &condition)
857AST_END(WhileLine) 905AST_END(WhileLine)
858 906
859AST_LEAF(BreakLoop) 907AST_LEAF(Break)
908AST_END(Break)
909
910AST_LEAF(Continue)
911AST_END(Continue)
912
913AST_NODE(BreakLoop)
914 ast_sel<true, Break_t, Continue_t> type;
915 ast_ptr<false, Exp_t> value;
916 AST_MEMBER(BreakLoop, &type, &value)
917 std::string varBWV;
860AST_END(BreakLoop) 918AST_END(BreakLoop)
861 919
862AST_NODE(PipeBody) 920AST_NODE(PipeBody)
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp
index 590c502..33161a7 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.27.5"sv; 81const std::string_view version = "0.29.4"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 {
@@ -165,12 +165,12 @@ public:
165 double compileTime = 0.0; 165 double compileTime = 0.0;
166 if (config.profiling) { 166 if (config.profiling) {
167 auto start = std::chrono::high_resolution_clock::now(); 167 auto start = std::chrono::high_resolution_clock::now();
168 _info = _parser.parse<File_t>(codes); 168 _info = _parser.parse<File_t>(codes, config.lax);
169 auto stop = std::chrono::high_resolution_clock::now(); 169 auto stop = std::chrono::high_resolution_clock::now();
170 std::chrono::duration<double> diff = stop - start; 170 std::chrono::duration<double> diff = stop - start;
171 parseTime = diff.count(); 171 parseTime = diff.count();
172 } else { 172 } else {
173 _info = _parser.parse<File_t>(codes); 173 _info = _parser.parse<File_t>(codes, config.lax);
174 } 174 }
175 std::unique_ptr<GlobalVars> globals; 175 std::unique_ptr<GlobalVars> globals;
176 std::unique_ptr<Options> options; 176 std::unique_ptr<Options> options;
@@ -429,8 +429,9 @@ private:
429 }; 429 };
430 enum class VarType { 430 enum class VarType {
431 Local = 0, 431 Local = 0,
432 Const = 1, 432 LocalConst = 1,
433 Global = 2 433 Global = 2,
434 GlobalConst = 3
434 }; 435 };
435 struct Scope { 436 struct Scope {
436 GlobalMode mode = GlobalMode::None; 437 GlobalMode mode = GlobalMode::None;
@@ -558,7 +559,7 @@ private:
558 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) { 559 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) {
559 auto vars = it->vars.get(); 560 auto vars = it->vars.get();
560 auto vit = vars->find(name); 561 auto vit = vars->find(name);
561 if (vit != vars->end() && vit->second != VarType::Global) { 562 if (vit != vars->end() && (vit->second == VarType::Local || vit->second == VarType::LocalConst)) {
562 local = true; 563 local = true;
563 break; 564 break;
564 } 565 }
@@ -571,7 +572,7 @@ private:
571 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) { 572 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) {
572 auto vars = it->vars.get(); 573 auto vars = it->vars.get();
573 auto vit = vars->find(name); 574 auto vit = vars->find(name);
574 if (vit != vars->end() && vit->second == VarType::Global) { 575 if (vit != vars->end() && (vit->second == VarType::Global || vit->second == VarType::GlobalConst)) {
575 global = true; 576 global = true;
576 break; 577 break;
577 } 578 }
@@ -593,7 +594,7 @@ private:
593 auto vars = it->vars.get(); 594 auto vars = it->vars.get();
594 auto vit = vars->find(name); 595 auto vit = vars->find(name);
595 if (vit != vars->end()) { 596 if (vit != vars->end()) {
596 isConst = (vit->second == VarType::Const); 597 isConst = (vit->second == VarType::LocalConst || vit->second == VarType::GlobalConst);
597 break; 598 break;
598 } 599 }
599 if (checkShadowScopeOnly && it->allows) break; 600 if (checkShadowScopeOnly && it->allows) break;
@@ -874,9 +875,9 @@ private:
874 return false; 875 return false;
875 } 876 }
876 877
877 void markVarConst(const std::string& name) { 878 void markVarLocalConst(const std::string& name) {
878 auto& scope = _scopes.back(); 879 auto& scope = _scopes.back();
879 scope.vars->insert_or_assign(name, VarType::Const); 880 scope.vars->insert_or_assign(name, VarType::LocalConst);
880 } 881 }
881 882
882 void markVarShadowed() { 883 void markVarShadowed() {
@@ -895,6 +896,11 @@ private:
895 scope.vars->insert_or_assign(name, VarType::Global); 896 scope.vars->insert_or_assign(name, VarType::Global);
896 } 897 }
897 898
899 void markVarGlobalConst(const std::string& name) {
900 auto& scope = _scopes.back();
901 scope.vars->insert_or_assign(name, VarType::GlobalConst);
902 }
903
898 void addToAllowList(const std::string& name) { 904 void addToAllowList(const std::string& name) {
899 auto& scope = _scopes.back(); 905 auto& scope = _scopes.back();
900 scope.allows->insert(name); 906 scope.allows->insert(name);
@@ -1252,7 +1258,7 @@ private:
1252 1258
1253 template <class T> 1259 template <class T>
1254 ast_ptr<false, T> toAst(std::string_view codes, ast_node* parent) { 1260 ast_ptr<false, T> toAst(std::string_view codes, ast_node* parent) {
1255 auto res = _parser.parse<T>(std::string(codes)); 1261 auto res = _parser.parse<T>(std::string(codes), false);
1256 if (res.error) { 1262 if (res.error) {
1257 throw CompileError(res.error.value().msg, parent); 1263 throw CompileError(res.error.value().msg, parent);
1258 } 1264 }
@@ -1275,6 +1281,8 @@ private:
1275 Common, 1281 Common,
1276 EndWithColon, 1282 EndWithColon,
1277 EndWithEOP, 1283 EndWithEOP,
1284 EndWithSlice,
1285 HasRIndex,
1278 HasEOP, 1286 HasEOP,
1279 HasKeyword, 1287 HasKeyword,
1280 HasUnicode, 1288 HasUnicode,
@@ -1293,6 +1301,9 @@ private:
1293 if (ast_is<ExistentialOp_t>(chainValue->items.back())) { 1301 if (ast_is<ExistentialOp_t>(chainValue->items.back())) {
1294 return ChainType::EndWithEOP; 1302 return ChainType::EndWithEOP;
1295 } 1303 }
1304 if (ast_is<Slice_t>(chainValue->items.back())) {
1305 return ChainType::EndWithSlice;
1306 }
1296 if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) { 1307 if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) {
1297 if (dot->name.is<Metatable_t>()) { 1308 if (dot->name.is<Metatable_t>()) {
1298 return ChainType::Metatable; 1309 return ChainType::Metatable;
@@ -1318,6 +1329,8 @@ private:
1318 } 1329 }
1319 } else if (ast_is<ExistentialOp_t>(item)) { 1330 } else if (ast_is<ExistentialOp_t>(item)) {
1320 return ChainType::HasEOP; 1331 return ChainType::HasEOP;
1332 } else if (ast_is<ReversedIndex_t>(item)) {
1333 return ChainType::HasRIndex;
1321 } 1334 }
1322 } 1335 }
1323 return type; 1336 return type;
@@ -1840,6 +1853,7 @@ private:
1840 case id<ForEach_t>(): transformForEach(static_cast<ForEach_t*>(value), out); break; 1853 case id<ForEach_t>(): transformForEach(static_cast<ForEach_t*>(value), out); break;
1841 case id<For_t>(): transformFor(static_cast<For_t*>(value), out); break; 1854 case id<For_t>(): transformFor(static_cast<For_t*>(value), out); break;
1842 case id<While_t>(): transformWhile(static_cast<While_t*>(value), out); break; 1855 case id<While_t>(): transformWhile(static_cast<While_t*>(value), out); break;
1856 case id<Repeat_t>(): transformRepeat(static_cast<Repeat_t*>(value), out); break;
1843 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Common); break; 1857 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Common); break;
1844 case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Common); break; 1858 case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Common); break;
1845 case id<Comprehension_t>(): { 1859 case id<Comprehension_t>(): {
@@ -1968,7 +1982,7 @@ private:
1968 return indent() + "local "s + join(defs, ", "sv); 1982 return indent() + "local "s + join(defs, ", "sv);
1969 } 1983 }
1970 1984
1971 std::string getDestrucureDefine(ExpListAssign_t* assignment) { 1985 std::string getDestructureDefine(ExpListAssign_t* assignment) {
1972 auto info = extractDestructureInfo(assignment, true, false); 1986 auto info = extractDestructureInfo(assignment, true, false);
1973 if (!info.destructures.empty()) { 1987 if (!info.destructures.empty()) {
1974 str_list defs; 1988 str_list defs;
@@ -1999,8 +2013,31 @@ private:
1999 return clearBuf(); 2013 return clearBuf();
2000 } 2014 }
2001 2015
2016 str_list getArgDestructureList(ExpListAssign_t* assignment) {
2017 str_list defs;
2018 auto info = extractDestructureInfo(assignment, true, false);
2019 if (!info.destructures.empty()) {
2020 for (const auto& des : info.destructures) {
2021 if (std::holds_alternative<Destructure>(des)) {
2022 const auto& destruct = std::get<Destructure>(des);
2023 for (const auto& item : destruct.items) {
2024 if (item.targetVar.empty()) {
2025 throw CompileError("can only destruct argument to variable"sv, item.target);
2026 } else {
2027 defs.push_back(item.targetVar);
2028 }
2029 }
2030 } else {
2031 const auto& assignment = std::get<AssignmentPtr>(des);
2032 YUEE("AST node mismatch", assignment.ptr);
2033 }
2034 }
2035 }
2036 return defs;
2037 }
2038
2002 std::string getPreDefine(ExpListAssign_t* assignment) { 2039 std::string getPreDefine(ExpListAssign_t* assignment) {
2003 auto preDefine = getDestrucureDefine(assignment); 2040 auto preDefine = getDestructureDefine(assignment);
2004 if (preDefine.empty()) { 2041 if (preDefine.empty()) {
2005 preDefine = toLocalDecl(transformAssignDefs(assignment->expList, DefOp::Mark)); 2042 preDefine = toLocalDecl(transformAssignDefs(assignment->expList, DefOp::Mark));
2006 } 2043 }
@@ -2051,13 +2088,16 @@ private:
2051 if (item.targetVar.empty()) { 2088 if (item.targetVar.empty()) {
2052 throw CompileError("can only declare variable as const"sv, item.target); 2089 throw CompileError("can only declare variable as const"sv, item.target);
2053 } 2090 }
2054 markVarConst(item.targetVar); 2091 markVarLocalConst(item.targetVar);
2055 } 2092 }
2056 } 2093 }
2057 } 2094 }
2058 } 2095 }
2059 2096
2060 bool transformAssignment(ExpListAssign_t* assignment, str_list& out, bool optionalDestruct = false) { 2097 bool transformAssignment(ExpListAssign_t* assignment, str_list& out, bool optionalDestruct = false) {
2098 if (assignment->action.is<SubBackcall_t>()) {
2099 YUEE("AST node mismatch", assignment->action);
2100 }
2061 checkAssignable(assignment->expList); 2101 checkAssignable(assignment->expList);
2062 BLOCK_START 2102 BLOCK_START
2063 auto assign = ast_cast<Assign_t>(assignment->action); 2103 auto assign = ast_cast<Assign_t>(assignment->action);
@@ -2320,6 +2360,17 @@ private:
2320 out.back().insert(0, preDefine); 2360 out.back().insert(0, preDefine);
2321 return false; 2361 return false;
2322 } 2362 }
2363 case id<Try_t>(): {
2364 auto tryNode = static_cast<Try_t*>(value);
2365 if (tryNode->eop) {
2366 auto assignList = assignment->expList.get();
2367 std::string preDefine = getPreDefineLine(assignment);
2368 transformTry(tryNode, out, ExpUsage::Assignment, assignList);
2369 out.back().insert(0, preDefine);
2370 return false;
2371 }
2372 break;
2373 }
2323 case id<Switch_t>(): { 2374 case id<Switch_t>(): {
2324 auto switchNode = static_cast<Switch_t*>(value); 2375 auto switchNode = static_cast<Switch_t*>(value);
2325 auto assignList = assignment->expList.get(); 2376 auto assignList = assignment->expList.get();
@@ -2391,6 +2442,13 @@ private:
2391 out.back().insert(0, preDefine); 2442 out.back().insert(0, preDefine);
2392 return false; 2443 return false;
2393 } 2444 }
2445 case id<Repeat_t>(): {
2446 auto expList = assignment->expList.get();
2447 std::string preDefine = getPreDefineLine(assignment);
2448 transformRepeatInPlace(static_cast<Repeat_t*>(value), out, expList);
2449 out.back().insert(0, preDefine);
2450 return false;
2451 }
2394 case id<TableLit_t>(): { 2452 case id<TableLit_t>(): {
2395 auto tableLit = static_cast<TableLit_t*>(value); 2453 auto tableLit = static_cast<TableLit_t*>(value);
2396 if (hasSpreadExp(tableLit->values.objects())) { 2454 if (hasSpreadExp(tableLit->values.objects())) {
@@ -2443,12 +2501,14 @@ private:
2443 switch (type) { 2501 switch (type) {
2444 case ChainType::HasEOP: 2502 case ChainType::HasEOP:
2445 case ChainType::EndWithColon: 2503 case ChainType::EndWithColon:
2504 case ChainType::EndWithSlice:
2446 case ChainType::MetaFieldInvocation: { 2505 case ChainType::MetaFieldInvocation: {
2447 std::string preDefine = getPreDefineLine(assignment); 2506 std::string preDefine = getPreDefineLine(assignment);
2448 transformChainValue(chainValue, out, ExpUsage::Assignment, expList, false, optionalDestruct); 2507 transformChainValue(chainValue, out, ExpUsage::Assignment, expList, false, optionalDestruct);
2449 out.back().insert(0, preDefine); 2508 out.back().insert(0, preDefine);
2450 return false; 2509 return false;
2451 } 2510 }
2511 case ChainType::HasRIndex:
2452 case ChainType::HasKeyword: 2512 case ChainType::HasKeyword:
2453 case ChainType::HasUnicode: 2513 case ChainType::HasUnicode:
2454 case ChainType::Macro: 2514 case ChainType::Macro:
@@ -2464,6 +2524,10 @@ private:
2464 auto info = extractDestructureInfo(assignment, false, optionalDestruct); 2524 auto info = extractDestructureInfo(assignment, false, optionalDestruct);
2465 if (info.destructures.empty()) { 2525 if (info.destructures.empty()) {
2466 transformAssignmentCommon(assignment, out); 2526 transformAssignmentCommon(assignment, out);
2527 if (assignment->expList->followStmt) {
2528 transformStatement(assignment->expList->followStmt, out);
2529 assignment->expList->followStmtProcessed = true;
2530 }
2467 return true; 2531 return true;
2468 } else { 2532 } else {
2469 auto x = assignment; 2533 auto x = assignment;
@@ -2729,8 +2793,12 @@ private:
2729 temp.push_back(indent() + "end"s + nlr(x)); 2793 temp.push_back(indent() + "end"s + nlr(x));
2730 } 2794 }
2731 out.push_back(join(temp)); 2795 out.push_back(join(temp));
2796 if (assignment->expList->followStmt) {
2797 transformStatement(assignment->expList->followStmt, out);
2798 assignment->expList->followStmtProcessed = true;
2799 }
2800 return false;
2732 } 2801 }
2733 return false;
2734 } 2802 }
2735 2803
2736 void transformAssignItem(ast_node* value, str_list& out) { 2804 void transformAssignItem(ast_node* value, str_list& out) {
@@ -2796,20 +2864,46 @@ private:
2796 if (!tableItems) throw CompileError("invalid destructure value"sv, node); 2864 if (!tableItems) throw CompileError("invalid destructure value"sv, node);
2797 std::list<DestructItem> pairs; 2865 std::list<DestructItem> pairs;
2798 int index = 0; 2866 int index = 0;
2867 int count = 0;
2868 bool hasSpread = false;
2799 auto subMetaDestruct = node->new_ptr<TableLit_t>(); 2869 auto subMetaDestruct = node->new_ptr<TableLit_t>();
2800 for (auto pair : *tableItems) { 2870 for (auto pair : *tableItems) {
2801 switch (pair->get_id()) { 2871 switch (pair->get_id()) {
2802 case id<Exp_t>(): 2872 case id<Exp_t>():
2803 case id<NormalDef_t>(): { 2873 case id<NormalDef_t>(): {
2874 ++index;
2804 Exp_t* defVal = nullptr; 2875 Exp_t* defVal = nullptr;
2805 if (auto nd = ast_cast<NormalDef_t>(pair)) { 2876 if (auto nd = ast_cast<NormalDef_t>(pair)) {
2806 pair = nd->item.get(); 2877 pair = nd->item.get();
2807 defVal = nd->defVal.get(); 2878 defVal = nd->defVal.get();
2808 } 2879 }
2809 ++index; 2880 bool assignable = false;
2810 if (!varDefOnly && !isAssignable(static_cast<Exp_t*>(pair))) { 2881 try {
2882 assignable = isAssignable(static_cast<Exp_t*>(pair));
2883 } catch (const CompileError& e) {
2884 if (!varDefOnly) throw e;
2885 }
2886 if (!assignable && !varDefOnly) {
2887 if (optional) break;
2811 throw CompileError("can't destructure value"sv, pair); 2888 throw CompileError("can't destructure value"sv, pair);
2812 } 2889 }
2890 ast_ptr<true, ast_node> indexItem;
2891 if (hasSpread) {
2892 int rIndex = count - index;
2893 indexItem.set(toAst<ReversedIndex_t>('#' + (rIndex == 0 ? Empty : "-"s + std::to_string(rIndex)), pair));
2894 } else {
2895 indexItem.set(toAst<Exp_t>(std::to_string(index), pair));
2896 }
2897 if (optional && varDefOnly && !assignable) {
2898 if (defVal) {
2899 throw CompileError("default value is not supported here"sv, defVal);
2900 }
2901 auto exp = static_cast<Exp_t*>(pair);
2902 auto chain = exp->new_ptr<ChainValue_t>();
2903 chain->items.push_back(indexItem);
2904 pairs.push_back({exp, Empty, chain, nullptr});
2905 break;
2906 }
2813 auto value = singleValueFrom(pair); 2907 auto value = singleValueFrom(pair);
2814 auto item = value->item.get(); 2908 auto item = value->item.get();
2815 ast_node* subExp = ast_cast<SimpleTable_t>(item); 2909 ast_node* subExp = ast_cast<SimpleTable_t>(item);
@@ -2820,7 +2914,6 @@ private:
2820 throw CompileError("default value is not supported here"sv, defVal); 2914 throw CompileError("default value is not supported here"sv, defVal);
2821 } 2915 }
2822 } 2916 }
2823 auto indexItem = toAst<Exp_t>(std::to_string(index), value);
2824 for (auto& p : subPairs) { 2917 for (auto& p : subPairs) {
2825 if (sep) p.structure->items.push_front(sep); 2918 if (sep) p.structure->items.push_front(sep);
2826 p.structure->items.push_front(indexItem); 2919 p.structure->items.push_front(indexItem);
@@ -2831,7 +2924,6 @@ private:
2831 auto varName = singleVariableFrom(exp, AccessType::None); 2924 auto varName = singleVariableFrom(exp, AccessType::None);
2832 if (varName == "_"sv) break; 2925 if (varName == "_"sv) break;
2833 auto chain = exp->new_ptr<ChainValue_t>(); 2926 auto chain = exp->new_ptr<ChainValue_t>();
2834 auto indexItem = toAst<Exp_t>(std::to_string(index), exp);
2835 chain->items.push_back(indexItem); 2927 chain->items.push_back(indexItem);
2836 pairs.push_back({exp, 2928 pairs.push_back({exp,
2837 varName, 2929 varName,
@@ -2889,7 +2981,25 @@ private:
2889 } 2981 }
2890 } 2982 }
2891 if (auto exp = np->value.as<Exp_t>()) { 2983 if (auto exp = np->value.as<Exp_t>()) {
2892 if (!varDefOnly && !isAssignable(exp)) throw CompileError("can't do destructure value"sv, exp); 2984 bool assignable = false;
2985 try {
2986 assignable = isAssignable(exp);
2987 } catch (const CompileError& e) {
2988 if (!varDefOnly) throw e;
2989 }
2990 if (!assignable && !varDefOnly) {
2991 if (optional) break;
2992 throw CompileError("can't destructure value"sv, pair);
2993 }
2994 if (optional && varDefOnly && !assignable) {
2995 if (defVal) {
2996 throw CompileError("default value is not supported here"sv, defVal);
2997 }
2998 auto chain = exp->new_ptr<ChainValue_t>();
2999 if (keyIndex) chain->items.push_back(keyIndex);
3000 pairs.push_back({exp, Empty, chain, nullptr});
3001 break;
3002 }
2893 auto item = singleValueFrom(exp)->item.get(); 3003 auto item = singleValueFrom(exp)->item.get();
2894 ast_node* subExp = ast_cast<SimpleTable_t>(item); 3004 ast_node* subExp = ast_cast<SimpleTable_t>(item);
2895 if (subExp || (subExp = item->get_by_path<TableLit_t>()) || (subExp = item->get_by_path<Comprehension_t>())) { 3005 if (subExp || (subExp = item->get_by_path<TableLit_t>()) || (subExp = item->get_by_path<Comprehension_t>())) {
@@ -2938,7 +3048,13 @@ private:
2938 auto tb = static_cast<TableBlockIndent_t*>(pair); 3048 auto tb = static_cast<TableBlockIndent_t*>(pair);
2939 ++index; 3049 ++index;
2940 auto subPairs = destructFromExp(tb, varDefOnly, optional); 3050 auto subPairs = destructFromExp(tb, varDefOnly, optional);
2941 auto indexItem = toAst<Exp_t>(std::to_string(index), tb); 3051 ast_ptr<true, ast_node> indexItem;
3052 if (hasSpread) {
3053 int rIndex = count - index;
3054 indexItem.set(toAst<ReversedIndex_t>('#' + (rIndex == 0 ? Empty : "-"s + std::to_string(rIndex)), tb));
3055 } else {
3056 indexItem.set(toAst<Exp_t>(std::to_string(index), tb));
3057 }
2942 for (auto& p : subPairs) { 3058 for (auto& p : subPairs) {
2943 if (sep) p.structure->items.push_front(sep); 3059 if (sep) p.structure->items.push_front(sep);
2944 p.structure->items.push_front(indexItem); 3060 p.structure->items.push_front(indexItem);
@@ -2995,6 +3111,42 @@ private:
2995 subMetaDestruct->values.push_back(newPairDef); 3111 subMetaDestruct->values.push_back(newPairDef);
2996 break; 3112 break;
2997 } 3113 }
3114 case id<SpreadListExp_t>():
3115 case id<SpreadExp_t>(): {
3116 ++index;
3117 if (hasSpread) {
3118 throw CompileError("duplicated spread expression"sv, pair);
3119 }
3120 hasSpread = true;
3121 for (auto item : *tableItems) {
3122 if (ast_is<
3123 SpreadListExp_t, SpreadExp_t,
3124 TableBlockIndent_t,
3125 Exp_t, NormalDef_t>(item)) {
3126 count++;
3127 }
3128 }
3129 Exp_t* exp = nullptr;
3130 if (auto se = ast_cast<SpreadExp_t>(pair)) {
3131 exp = se->exp.get();
3132 } else {
3133 exp = ast_to<SpreadListExp_t>(pair)->exp.get();
3134 }
3135 auto varName = singleVariableFrom(exp, AccessType::None);
3136 if (varName == "_"sv) break;
3137 int start = index;
3138 int stop = index - count - 1;
3139 auto chain = exp->new_ptr<ChainValue_t>();
3140 auto slice = toAst<Slice_t>(
3141 '[' + (start == 1 ? Empty : std::to_string(start)) + ',' + (stop == -1 ? Empty : std::to_string(stop)) + ']', exp);
3142 chain->items.push_back(slice);
3143 auto nil = toAst<Exp_t>("nil"sv, slice);
3144 pairs.push_back({exp,
3145 varName,
3146 chain,
3147 nil.get()});
3148 break;
3149 }
2998 default: YUEE("AST node mismatch", pair); break; 3150 default: YUEE("AST node mismatch", pair); break;
2999 } 3151 }
3000 } 3152 }
@@ -3111,7 +3263,11 @@ private:
3111 break; 3263 break;
3112 default: YUEE("AST node mismatch", destructNode); break; 3264 default: YUEE("AST node mismatch", destructNode); break;
3113 } 3265 }
3114 if (dlist->empty()) throw CompileError("expect items to be destructured"sv, destructNode); 3266 if (dlist->empty()) {
3267 if (!optional) {
3268 throw CompileError("expect items to be destructured"sv, destructNode);
3269 }
3270 }
3115 for (auto item : *dlist) { 3271 for (auto item : *dlist) {
3116 switch (item->get_id()) { 3272 switch (item->get_id()) {
3117 case id<MetaVariablePairDef_t>(): { 3273 case id<MetaVariablePairDef_t>(): {
@@ -3247,7 +3403,9 @@ private:
3247 simpleValue->value.set(tab); 3403 simpleValue->value.set(tab);
3248 auto pairs = destructFromExp(newExp(simpleValue, expr), varDefOnly, optional); 3404 auto pairs = destructFromExp(newExp(simpleValue, expr), varDefOnly, optional);
3249 if (pairs.empty()) { 3405 if (pairs.empty()) {
3250 throw CompileError("expect items to be destructured"sv, tab); 3406 if (!optional) {
3407 throw CompileError("expect items to be destructured"sv, tab);
3408 }
3251 } 3409 }
3252 destruct.items = std::move(pairs); 3410 destruct.items = std::move(pairs);
3253 if (!varDefOnly) { 3411 if (!varDefOnly) {
@@ -3286,7 +3444,7 @@ private:
3286 destruct.valueVar.clear(); 3444 destruct.valueVar.clear();
3287 } 3445 }
3288 } 3446 }
3289 destructs.push_back(destruct); 3447 destructs.push_back(std::move(destruct));
3290 } 3448 }
3291 } 3449 }
3292 } else { 3450 } else {
@@ -4205,12 +4363,22 @@ private:
4205 4363
4206 std::optional<std::pair<std::string, str_list>> upValueFuncFromExp(Exp_t* exp, str_list* ensureArgListInTheEnd, bool blockRewrite) { 4364 std::optional<std::pair<std::string, str_list>> upValueFuncFromExp(Exp_t* exp, str_list* ensureArgListInTheEnd, bool blockRewrite) {
4207 if (checkUpValueFuncAvailable(exp)) { 4365 if (checkUpValueFuncAvailable(exp)) {
4366 auto block = exp->new_ptr<Block_t>();
4367 if (auto sVal = simpleSingleValueFrom(exp)) {
4368 if (auto doNode = sVal->value.as<Do_t>()) {
4369 if (auto blk = doNode->body->content.as<Block_t>()) {
4370 block->statements.dup(blk->statements);
4371 } else {
4372 block->statements.push_back(doNode->body->content.to<Statement_t>());
4373 }
4374 return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, false, blockRewrite);
4375 }
4376 }
4208 auto returnNode = exp->new_ptr<Return_t>(); 4377 auto returnNode = exp->new_ptr<Return_t>();
4209 returnNode->explicitReturn = false; 4378 returnNode->explicitReturn = false;
4210 auto returnList = exp->new_ptr<ExpListLow_t>(); 4379 auto returnList = exp->new_ptr<ExpListLow_t>();
4211 returnList->exprs.push_back(exp); 4380 returnList->exprs.push_back(exp);
4212 returnNode->valueList.set(returnList); 4381 returnNode->valueList.set(returnList);
4213 auto block = exp->new_ptr<Block_t>();
4214 auto stmt = exp->new_ptr<Statement_t>(); 4382 auto stmt = exp->new_ptr<Statement_t>();
4215 stmt->content.set(returnNode); 4383 stmt->content.set(returnNode);
4216 block->statements.push_back(stmt); 4384 block->statements.push_back(stmt);
@@ -4287,7 +4455,9 @@ private:
4287 return false; 4455 return false;
4288 }; 4456 };
4289 switch (usage) { 4457 switch (usage) {
4290 case ExpUsage::Common: YUEE("AST node mismatch", x); return; 4458 case ExpUsage::Common:
4459 YUEE("AST node mismatch", x);
4460 return;
4291 case ExpUsage::Return: 4461 case ExpUsage::Return:
4292 case ExpUsage::Closure: { 4462 case ExpUsage::Closure: {
4293 prepareValue(); 4463 prepareValue();
@@ -4410,6 +4580,7 @@ private:
4410 case id<ForEach_t>(): transformForEachClosure(static_cast<ForEach_t*>(value), out); break; 4580 case id<ForEach_t>(): transformForEachClosure(static_cast<ForEach_t*>(value), out); break;
4411 case id<For_t>(): transformForClosure(static_cast<For_t*>(value), out); break; 4581 case id<For_t>(): transformForClosure(static_cast<For_t*>(value), out); break;
4412 case id<While_t>(): transformWhileClosure(static_cast<While_t*>(value), out); break; 4582 case id<While_t>(): transformWhileClosure(static_cast<While_t*>(value), out); break;
4583 case id<Repeat_t>(): transformRepeatClosure(static_cast<Repeat_t*>(value), out); break;
4413 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Closure); break; 4584 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Closure); break;
4414 case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Closure); break; 4585 case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Closure); break;
4415 case id<UnaryValue_t>(): transformUnaryValue(static_cast<UnaryValue_t*>(value), out); break; 4586 case id<UnaryValue_t>(): transformUnaryValue(static_cast<UnaryValue_t*>(value), out); break;
@@ -4729,11 +4900,7 @@ private:
4729 auto newBody = x->new_ptr<Body_t>(); 4900 auto newBody = x->new_ptr<Body_t>();
4730 newBody->content.set(followingBlock); 4901 newBody->content.set(followingBlock);
4731 { 4902 {
4732 auto doNode = x->new_ptr<Do_t>(); 4903 if (auto result = upValueFuncFromBlock(followingBlock.get(), &argNames, false, true)) {
4733 doNode->body.set(newBody);
4734 auto simpleValue = x->new_ptr<SimpleValue_t>();
4735 simpleValue->value.set(doNode);
4736 if (auto result = upValueFuncFromExp(newExp(simpleValue, x), &argNames, true)) {
4737 auto [funcName, args] = std::move(*result); 4904 auto [funcName, args] = std::move(*result);
4738 str_list finalArgs; 4905 str_list finalArgs;
4739 for (const auto& arg : args) { 4906 for (const auto& arg : args) {
@@ -4741,9 +4908,13 @@ private:
4741 finalArgs.push_back(arg); 4908 finalArgs.push_back(arg);
4742 } 4909 }
4743 } 4910 }
4744 newBlock->statements.push_back(toAst<Statement_t>(funcName + ' ' + join(finalArgs, ","sv), x)); 4911 newBlock->statements.push_back(toAst<Statement_t>(funcName + ' ' + (finalArgs.empty() ? "nil"s : join(finalArgs, ","sv)), x));
4745 auto sVal = singleValueFrom(static_cast<Statement_t*>(newBlock->statements.back())->content.to<ExpListAssign_t>()->expList); 4912 auto sVal = singleValueFrom(static_cast<Statement_t*>(newBlock->statements.back())->content.to<ExpListAssign_t>()->expList);
4746 ast_to<InvokeArgs_t>(sVal->item.to<ChainValue_t>()->items.back())->args.dup(newInvoke->args); 4913 auto invokArgs = ast_to<InvokeArgs_t>(sVal->item.to<ChainValue_t>()->items.back());
4914 if (finalArgs.empty()) {
4915 invokArgs->args.clear();
4916 }
4917 invokArgs->args.dup(newInvoke->args);
4747 transformBlock(newBlock, out, usage, assignList, isRoot); 4918 transformBlock(newBlock, out, usage, assignList, isRoot);
4748 return; 4919 return;
4749 } 4920 }
@@ -4820,6 +4991,38 @@ private:
4820 newBlock->statements.push_back(toAst<Statement_t>("if "s + okVar + " then return ... else error ..."s, x)); 4991 newBlock->statements.push_back(toAst<Statement_t>("if "s + okVar + " then return ... else error ..."s, x));
4821 transformBlock(newBlock, out, usage, assignList, isRoot); 4992 transformBlock(newBlock, out, usage, assignList, isRoot);
4822 return; 4993 return;
4994 } else if (auto expListAssign = stmt->content.as<ExpListAssign_t>();
4995 expListAssign && expListAssign->action && expListAssign->action.is<SubBackcall_t>()) {
4996 auto x = *nodes.begin();
4997 auto newBlock = x->new_ptr<Block_t>();
4998 if (it != nodes.begin()) {
4999 for (auto i = nodes.begin(); i != it; ++i) {
5000 newBlock->statements.push_back(*i);
5001 }
5002 }
5003 auto doBackcall = static_cast<SubBackcall_t*>(expListAssign->action.get());
5004 auto backcall = expListAssign->new_ptr<Backcall_t>();
5005 auto argsDef = backcall->new_ptr<FnArgsDef_t>();
5006 try {
5007 auto defList = toAst<FnArgDefList_t>(YueFormat{}.toString(expListAssign->expList), expListAssign->expList);
5008 argsDef->defList.set(defList);
5009 } catch (const std::exception&) {
5010 throw CompileError("backcall syntax error", backcall);
5011 }
5012 backcall->argsDef.set(argsDef);
5013 backcall->arrow.set(doBackcall->arrow);
5014 backcall->value.set(doBackcall->value);
5015 auto newStmt = backcall->new_ptr<Statement_t>();
5016 newStmt->content.set(backcall);
5017 newStmt->comments.dup(stmt->comments);
5018 newStmt->appendix.set(stmt->appendix);
5019 newBlock->statements.push_back(newStmt);
5020 auto ait = it;
5021 for (auto i = ++ait; i != nodes.end(); ++i) {
5022 newBlock->statements.push_back(*i);
5023 }
5024 transformBlock(newBlock, out, usage, assignList, isRoot);
5025 return;
4823 } 5026 }
4824 if (auto local = stmt->content.as<Local_t>()) { 5027 if (auto local = stmt->content.as<Local_t>()) {
4825 if (!local->collected) { 5028 if (!local->collected) {
@@ -4991,36 +5194,45 @@ private:
4991 if (!nodes.empty()) { 5194 if (!nodes.empty()) {
4992 str_list temp; 5195 str_list temp;
4993 for (auto node : nodes) { 5196 for (auto node : nodes) {
4994 currentScope().lastStatement = (node == nodes.back()) && currentScope().mode == GlobalMode::None; 5197 auto transformNode = [&]() {
4995 transformStatement(static_cast<Statement_t*>(node), temp); 5198 currentScope().lastStatement = (node == nodes.back()) && currentScope().mode == GlobalMode::None;
4996 if (isRoot && !_rootDefs.empty()) { 5199 transformStatement(static_cast<Statement_t*>(node), temp);
4997 auto last = std::move(temp.back()); 5200 if (isRoot && !_rootDefs.empty()) {
4998 temp.pop_back(); 5201 auto last = std::move(temp.back());
4999 temp.insert(temp.end(), _rootDefs.begin(), _rootDefs.end()); 5202 temp.pop_back();
5000 _rootDefs.clear(); 5203 temp.insert(temp.end(), _rootDefs.begin(), _rootDefs.end());
5001 temp.push_back(std::move(last)); 5204 _rootDefs.clear();
5002 } 5205 temp.push_back(std::move(last));
5003 if (!temp.empty() && _parser.startWith<StatementSep_t>(temp.back())) { 5206 }
5004 auto rit = ++temp.rbegin(); 5207 if (!temp.empty() && _parser.startWith<StatementSep_t>(temp.back())) {
5005 if (rit != temp.rend() && !rit->empty()) { 5208 auto rit = ++temp.rbegin();
5006 auto index = std::string::npos; 5209 if (rit != temp.rend() && !rit->empty()) {
5007 if (_config.reserveLineNumber) { 5210 auto index = std::string::npos;
5008 index = rit->rfind(" -- "sv); 5211 if (_config.reserveLineNumber) {
5009 } else { 5212 index = rit->rfind(" -- "sv);
5010 index = rit->find_last_not_of('\n'); 5213 } else {
5011 if (index != std::string::npos) index++; 5214 index = rit->find_last_not_of('\n');
5012 } 5215 if (index != std::string::npos) index++;
5013 if (index != std::string::npos) {
5014 auto ending = rit->substr(0, index);
5015 auto ind = ending.find_last_of(" \t\n"sv);
5016 if (ind != std::string::npos) {
5017 ending = ending.substr(ind + 1);
5018 } 5216 }
5019 if (LuaKeywords.find(ending) == LuaKeywords.end()) { 5217 if (index != std::string::npos) {
5020 rit->insert(index, ";"sv); 5218 auto ending = rit->substr(0, index);
5219 auto ind = ending.find_last_of(" \t\n"sv);
5220 if (ind != std::string::npos) {
5221 ending = ending.substr(ind + 1);
5222 }
5223 if (LuaKeywords.find(ending) == LuaKeywords.end()) {
5224 rit->insert(index, ";"sv);
5225 }
5021 } 5226 }
5022 } 5227 }
5023 } 5228 }
5229 };
5230 if (_config.lax) {
5231 try {
5232 transformNode();
5233 } catch (const CompileError&) { }
5234 } else {
5235 transformNode();
5024 } 5236 }
5025 } 5237 }
5026 out.push_back(join(temp)); 5238 out.push_back(join(temp));
@@ -5229,18 +5441,29 @@ private:
5229 auto macroLit = macro->decl.to<MacroLit_t>(); 5441 auto macroLit = macro->decl.to<MacroLit_t>();
5230 auto argsDef = macroLit->argsDef.get(); 5442 auto argsDef = macroLit->argsDef.get();
5231 str_list newArgs; 5443 str_list newArgs;
5444 str_list argChecks;
5445 bool hasCheck = false;
5232 if (argsDef) { 5446 if (argsDef) {
5233 for (auto def_ : argsDef->definitions.objects()) { 5447 for (auto def_ : argsDef->definitions.objects()) {
5234 auto def = static_cast<FnArgDef_t*>(def_); 5448 auto def = static_cast<FnArgDef_t*>(def_);
5235 if (def->name.is<SelfItem_t>()) { 5449 if (def->name.is<SelfItem_t>()) {
5236 throw CompileError("self name is not supported for macro function argument"sv, def->name); 5450 throw CompileError("self name is not supported for macro function argument"sv, def->name);
5237 } else { 5451 } else {
5452 if (def->op) throw CompileError("invalid existence checking"sv, def->op);
5453 if (def->label) {
5454 hasCheck = true;
5455 const auto& astName = argChecks.emplace_back(_parser.toString(def->label));
5456 if (!_parser.hasAST(astName)) {
5457 throw CompileError("invalid AST name"sv, def->label);
5458 }
5459 } else {
5460 argChecks.emplace_back();
5461 }
5238 std::string defVal; 5462 std::string defVal;
5239 if (def->defaultValue) { 5463 if (def->defaultValue) {
5240 defVal = _parser.toString(def->defaultValue); 5464 defVal = _parser.toString(def->defaultValue);
5241 Utils::trim(defVal); 5465 Utils::trim(defVal);
5242 defVal.insert(0, "=[==========["sv); 5466 defVal = '=' + Utils::toLuaDoubleString(defVal);
5243 defVal.append("]==========]"sv);
5244 } 5467 }
5245 newArgs.emplace_back(_parser.toString(def->name) + defVal); 5468 newArgs.emplace_back(_parser.toString(def->name) + defVal);
5246 } 5469 }
@@ -5248,6 +5471,14 @@ private:
5248 if (argsDef->varArg) { 5471 if (argsDef->varArg) {
5249 newArgs.emplace_back(_parser.toString(argsDef->varArg)); 5472 newArgs.emplace_back(_parser.toString(argsDef->varArg));
5250 } 5473 }
5474 if (argsDef->label) {
5475 hasCheck = true;
5476 const auto& astName = _parser.toString(argsDef->label);
5477 if (!_parser.hasAST(astName)) {
5478 throw CompileError("invalid AST name"sv, argsDef->label);
5479 }
5480 argChecks.emplace_back("..."s + astName);
5481 }
5251 } 5482 }
5252 std::string macroCodes = "_ENV=require('yue').macro_env\n("s + join(newArgs, ","sv) + ")->"s + _parser.toString(macroLit->body); 5483 std::string macroCodes = "_ENV=require('yue').macro_env\n("s + join(newArgs, ","sv) + ")->"s + _parser.toString(macroLit->body);
5253 auto chunkName = "=(macro "s + macroName + ')'; 5484 auto chunkName = "=(macro "s + macroName + ')';
@@ -5278,6 +5509,24 @@ private:
5278 throw CompileError("failed to generate macro function\n"s + err, macroLit); 5509 throw CompileError("failed to generate macro function\n"s + err, macroLit);
5279 } // cur true macro 5510 } // cur true macro
5280 lua_remove(L, -2); // cur macro 5511 lua_remove(L, -2); // cur macro
5512 if (hasCheck) {
5513 lua_createtable(L, 0, 0); // cur macro checks
5514 int i = 1;
5515 for (const auto& check : argChecks) {
5516 if (check.empty()) {
5517 lua_pushboolean(L, 0);
5518 lua_rawseti(L, -2, i);
5519 } else {
5520 lua_pushlstring(L, check.c_str(), check.size());
5521 lua_rawseti(L, -2, i);
5522 }
5523 i++;
5524 }
5525 lua_createtable(L, 2, 0); // cur macro checks macrotab
5526 lua_insert(L, -3); // cur macrotab macro checks
5527 lua_rawseti(L, -3, 1); // macrotab[1] = checks, cur macrotab macro
5528 lua_rawseti(L, -2, 2); // macrotab[2] = macro, cur macrotab
5529 } // cur macro
5281 if (exporting && _config.exporting && !_config.module.empty()) { 5530 if (exporting && _config.exporting && !_config.module.empty()) {
5282 pushModuleTable(_config.module); // cur macro module 5531 pushModuleTable(_config.module); // cur macro module
5283 lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro module name 5532 lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro module name
@@ -5352,6 +5601,9 @@ private:
5352 case id<While_t>(): 5601 case id<While_t>():
5353 transformWhileInPlace(static_cast<While_t*>(value), out); 5602 transformWhileInPlace(static_cast<While_t*>(value), out);
5354 return; 5603 return;
5604 case id<Repeat_t>():
5605 transformRepeatInPlace(static_cast<Repeat_t*>(value), out);
5606 return;
5355 case id<For_t>(): 5607 case id<For_t>():
5356 transformForInPlace(static_cast<For_t*>(value), out); 5608 transformForInPlace(static_cast<For_t*>(value), out);
5357 return; 5609 return;
@@ -5423,6 +5675,7 @@ private:
5423 bool checkExistence = false; 5675 bool checkExistence = false;
5424 std::string name; 5676 std::string name;
5425 std::string assignSelf; 5677 std::string assignSelf;
5678 ast_ptr<false, ExpListAssign_t> assignment;
5426 }; 5679 };
5427 std::list<ArgItem> argItems; 5680 std::list<ArgItem> argItems;
5428 str_list temp; 5681 str_list temp;
@@ -5432,7 +5685,11 @@ private:
5432 auto def = static_cast<FnArgDef_t*>(_def); 5685 auto def = static_cast<FnArgDef_t*>(_def);
5433 auto& arg = argItems.emplace_back(); 5686 auto& arg = argItems.emplace_back();
5434 switch (def->name->get_id()) { 5687 switch (def->name->get_id()) {
5435 case id<Variable_t>(): arg.name = variableToString(static_cast<Variable_t*>(def->name.get())); break; 5688 case id<Variable_t>(): {
5689 if (def->op) throw CompileError("invalid existence checking"sv, def->op);
5690 arg.name = variableToString(static_cast<Variable_t*>(def->name.get()));
5691 break;
5692 }
5436 case id<SelfItem_t>(): { 5693 case id<SelfItem_t>(): {
5437 assignSelf = true; 5694 assignSelf = true;
5438 if (def->op) { 5695 if (def->op) {
@@ -5473,6 +5730,22 @@ private:
5473 } 5730 }
5474 break; 5731 break;
5475 } 5732 }
5733 case id<TableLit_t>(): {
5734 arg.name = getUnusedName("_arg_"sv);
5735 auto simpleValue = def->new_ptr<SimpleValue_t>();
5736 simpleValue->value.set(def->name);
5737 auto asmt = assignmentFrom(newExp(simpleValue, def), toAst<Exp_t>(arg.name, def), def);
5738 arg.assignment = asmt;
5739 break;
5740 }
5741 case id<SimpleTable_t>(): {
5742 arg.name = getUnusedName("_arg_"sv);
5743 auto value = def->new_ptr<Value_t>();
5744 value->item.set(def->name);
5745 auto asmt = assignmentFrom(newExp(value, def), toAst<Exp_t>(arg.name, def), def);
5746 arg.assignment = asmt;
5747 break;
5748 }
5476 default: YUEE("AST node mismatch", def->name.get()); break; 5749 default: YUEE("AST node mismatch", def->name.get()); break;
5477 } 5750 }
5478 forceAddToScope(arg.name); 5751 forceAddToScope(arg.name);
@@ -5491,6 +5764,14 @@ private:
5491 _buf << indent() << "end"sv << nll(def); 5764 _buf << indent() << "end"sv << nll(def);
5492 temp.back() = clearBuf(); 5765 temp.back() = clearBuf();
5493 } 5766 }
5767 if (arg.assignment) {
5768 auto names = getArgDestructureList(arg.assignment);
5769 for (const auto& name : names) {
5770 forceAddToScope(name);
5771 }
5772 temp.emplace_back(indent() + "local "s + join(names, ", "sv) + nll(def));
5773 transformAssignment(arg.assignment, temp);
5774 }
5494 if (varNames.empty()) 5775 if (varNames.empty())
5495 varNames = arg.name; 5776 varNames = arg.name;
5496 else 5777 else
@@ -5571,6 +5852,45 @@ private:
5571 } 5852 }
5572 } 5853 }
5573 5854
5855 bool transformChainEndWithSlice(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) {
5856 auto x = chainList.front();
5857 if (ast_is<Slice_t>(chainList.back())) {
5858 auto comp = x->new_ptr<Comprehension_t>();
5859 {
5860 auto chainValue = x->new_ptr<ChainValue_t>();
5861 for (auto item : chainList) {
5862 chainValue->items.push_back(item);
5863 }
5864 auto itemVar = getUnusedName("_item_"sv);
5865 auto expCode = YueFormat{}.toString(chainValue);
5866 auto compCode = '[' + itemVar + " for "s + itemVar + " in *"s + expCode + ']';
5867 comp.set(toAst<Comprehension_t>(compCode, x));
5868 }
5869 switch (usage) {
5870 case ExpUsage::Assignment: {
5871 auto simpleValue = x->new_ptr<SimpleValue_t>();
5872 simpleValue->value.set(comp);
5873 auto exp = newExp(simpleValue, x);
5874 auto assignment = x->new_ptr<ExpListAssign_t>();
5875 assignment->expList.set(assignList);
5876 auto assign = x->new_ptr<Assign_t>();
5877 assign->values.push_back(exp);
5878 assignment->action.set(assign);
5879 transformAssignment(assignment, out);
5880 break;
5881 }
5882 case ExpUsage::Return:
5883 transformComprehension(comp, out, ExpUsage::Return);
5884 break;
5885 default:
5886 transformComprehension(comp, out, ExpUsage::Closure);
5887 break;
5888 }
5889 return true;
5890 }
5891 return false;
5892 }
5893
5574 bool transformChainEndWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) { 5894 bool transformChainEndWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) {
5575 auto x = chainList.front(); 5895 auto x = chainList.front();
5576 if (ast_is<ExistentialOp_t>(chainList.back())) { 5896 if (ast_is<ExistentialOp_t>(chainList.back())) {
@@ -6088,7 +6408,7 @@ private:
6088 case id<ColonChainItem_t>(): 6408 case id<ColonChainItem_t>():
6089 case id<Exp_t>(): 6409 case id<Exp_t>():
6090 if (_withVars.empty()) { 6410 if (_withVars.empty()) {
6091 throw CompileError("short dot/colon and indexing syntax must be called within a with block"sv, x); 6411 throw CompileError("short dot/colon/indexing syntax must be called within a with block"sv, x);
6092 } else { 6412 } else {
6093 temp.push_back(_withVars.top()); 6413 temp.push_back(_withVars.top());
6094 } 6414 }
@@ -6234,6 +6554,93 @@ private:
6234 } 6554 }
6235 return; 6555 return;
6236 } 6556 }
6557 break;
6558 }
6559 case id<ReversedIndex_t>(): {
6560 auto rIndex = static_cast<ReversedIndex_t*>(*it);
6561 auto current = it;
6562 auto prevChain = x->new_ptr<ChainValue_t>();
6563 for (auto i = chainList.begin(); i != current; ++i) {
6564 prevChain->items.push_back(*i);
6565 }
6566 auto var = singleVariableFrom(prevChain, AccessType::None);
6567 if (!var.empty() && isLocal(var)) {
6568 auto indexNode = toAst<Exp_t>('#' + var, rIndex);
6569 if (rIndex->modifier) {
6570 auto opValue = rIndex->new_ptr<ExpOpValue_t>();
6571 opValue->op.set(toAst<BinaryOperator_t>("-"sv, rIndex));
6572 opValue->pipeExprs.dup(rIndex->modifier->pipeExprs);
6573 indexNode->opValues.push_back(opValue);
6574 indexNode->opValues.dup(rIndex->modifier->opValues);
6575 indexNode->nilCoalesed.set(rIndex->modifier->nilCoalesed);
6576 }
6577 prevChain->items.push_back(indexNode);
6578 auto next = current;
6579 ++next;
6580 for (auto i = next; i != chainList.end(); ++i) {
6581 prevChain->items.push_back(*i);
6582 }
6583 if (usage == ExpUsage::Assignment) {
6584 auto assignment = x->new_ptr<ExpListAssign_t>();
6585 assignment->expList.set(assignList);
6586 auto assign = x->new_ptr<Assign_t>();
6587 assign->values.push_back(newExp(prevChain, x));
6588 assignment->action.set(assign);
6589 transformAssignment(assignment, out);
6590 return;
6591 }
6592 transformChainValue(prevChain, out, usage, assignList);
6593 return;
6594 } else {
6595 auto itemVar = getUnusedName("_item_"sv);
6596 auto asmt = assignmentFrom(toAst<Exp_t>(itemVar, x), newExp(prevChain, x), x);
6597 auto stmt1 = x->new_ptr<Statement_t>();
6598 stmt1->content.set(asmt);
6599 auto newChain = x->new_ptr<ChainValue_t>();
6600 newChain->items.push_back(toAst<Callable_t>(itemVar, x));
6601 auto indexNode = toAst<Exp_t>('#' + itemVar, rIndex);
6602 if (rIndex->modifier) {
6603 auto opValue = rIndex->new_ptr<ExpOpValue_t>();
6604 opValue->op.set(toAst<BinaryOperator_t>("-"sv, rIndex));
6605 opValue->pipeExprs.dup(rIndex->modifier->pipeExprs);
6606 indexNode->opValues.push_back(opValue);
6607 indexNode->opValues.dup(rIndex->modifier->opValues);
6608 indexNode->nilCoalesed.set(rIndex->modifier->nilCoalesed);
6609 }
6610 newChain->items.push_back(indexNode);
6611 auto next = current;
6612 ++next;
6613 for (auto i = next; i != chainList.end(); ++i) {
6614 newChain->items.push_back(*i);
6615 }
6616 auto expList = x->new_ptr<ExpList_t>();
6617 expList->exprs.push_back(newExp(newChain, x));
6618 auto expListAssign = x->new_ptr<ExpListAssign_t>();
6619 expListAssign->expList.set(expList);
6620 auto stmt2 = x->new_ptr<Statement_t>();
6621 stmt2->content.set(expListAssign);
6622 auto block = x->new_ptr<Block_t>();
6623 block->statements.push_back(stmt1);
6624 block->statements.push_back(stmt2);
6625 auto body = x->new_ptr<Body_t>();
6626 body->content.set(block);
6627 auto doNode = x->new_ptr<Do_t>();
6628 doNode->body.set(body);
6629 if (usage == ExpUsage::Assignment) {
6630 auto assignment = x->new_ptr<ExpListAssign_t>();
6631 assignment->expList.set(assignList);
6632 auto assign = x->new_ptr<Assign_t>();
6633 auto sVal = x->new_ptr<SimpleValue_t>();
6634 sVal->value.set(doNode);
6635 assign->values.push_back(newExp(sVal, x));
6636 assignment->action.set(assign);
6637 transformAssignment(assignment, out);
6638 return;
6639 }
6640 transformDo(doNode, out, usage);
6641 return;
6642 }
6643 break;
6237 } 6644 }
6238 } 6645 }
6239 } 6646 }
@@ -6418,7 +6825,7 @@ private:
6418 } 6825 }
6419 } 6826 }
6420 } 6827 }
6421 int len = lua_objlen(L, -1); 6828 int len = static_cast<int>(lua_objlen(L, -1));
6422 lua_pushnil(L); // cur nil 6829 lua_pushnil(L); // cur nil
6423 for (int i = len; i >= 1; i--) { 6830 for (int i = len; i >= 1; i--) {
6424 lua_pop(L, 1); // cur 6831 lua_pop(L, 1); // cur
@@ -6430,7 +6837,25 @@ private:
6430 break; 6837 break;
6431 } 6838 }
6432 } 6839 }
6433 if (!lua_isfunction(L, -1)) { 6840 str_list checks;
6841 if (lua_istable(L, -1)) {
6842 lua_rawgeti(L, -1, 1); // cur macrotab checks
6843 int len = static_cast<int>(lua_objlen(L, -1));
6844 for (int i = 1; i <= len; i++) {
6845 lua_rawgeti(L, -1, i);
6846 if (lua_toboolean(L, -1) == 0) {
6847 checks.emplace_back();
6848 } else {
6849 size_t str_len = 0;
6850 auto str = lua_tolstring(L, -1, &str_len);
6851 checks.emplace_back(std::string{str, str_len});
6852 }
6853 lua_pop(L, 1);
6854 }
6855 lua_pop(L, 1);
6856 lua_rawgeti(L, -1, 2); // cur macrotab macroFunc
6857 lua_remove(L, -2); // cur macroFunc
6858 } else if (!lua_isfunction(L, -1)) {
6434 auto code = expandBuiltinMacro(macroName, x); 6859 auto code = expandBuiltinMacro(macroName, x);
6435 if (!code.empty()) return code; 6860 if (!code.empty()) return code;
6436 if (macroName == "is_ast"sv) { 6861 if (macroName == "is_ast"sv) {
@@ -6475,11 +6900,34 @@ private:
6475 } // cur macroFunc 6900 } // cur macroFunc
6476 pushYue("pcall"sv); // cur macroFunc pcall 6901 pushYue("pcall"sv); // cur macroFunc pcall
6477 lua_insert(L, -2); // cur pcall macroFunc 6902 lua_insert(L, -2); // cur pcall macroFunc
6478 if (!lua_checkstack(L, argStrs.size())) { 6903 if (!lua_checkstack(L, static_cast<int>(argStrs.size()))) {
6479 throw CompileError("too much macro params"s, x); 6904 throw CompileError("too much macro params"s, x);
6480 } 6905 }
6906 auto checkIt = checks.begin();
6907 node_container::const_iterator argIt;
6908 if (args) {
6909 argIt = args->begin();
6910 }
6481 for (const auto& arg : argStrs) { 6911 for (const auto& arg : argStrs) {
6912 if (checkIt != checks.end()) {
6913 if (checkIt->empty()) {
6914 ++checkIt;
6915 } else {
6916 if ((*checkIt)[0] == '.') {
6917 auto astName = checkIt->substr(3);
6918 if (!_parser.match(astName, arg)) {
6919 throw CompileError("expecting \""s + astName + "\", AST mismatch"s, *argIt);
6920 }
6921 } else {
6922 if (!_parser.match(*checkIt, arg)) {
6923 throw CompileError("expecting \""s + *checkIt + "\", AST mismatch"s, *argIt);
6924 }
6925 ++checkIt;
6926 }
6927 }
6928 }
6482 lua_pushlstring(L, arg.c_str(), arg.size()); 6929 lua_pushlstring(L, arg.c_str(), arg.size());
6930 ++argIt;
6483 } // cur pcall macroFunc args... 6931 } // cur pcall macroFunc args...
6484 bool success = lua_pcall(L, static_cast<int>(argStrs.size()), 1, 0) == 0; 6932 bool success = lua_pcall(L, static_cast<int>(argStrs.size()), 1, 0) == 0;
6485 if (!success) { // cur err 6933 if (!success) { // cur err
@@ -6609,14 +7057,14 @@ private:
6609 } else { 7057 } else {
6610 if (!codes.empty()) { 7058 if (!codes.empty()) {
6611 if (isBlock) { 7059 if (isBlock) {
6612 info = _parser.parse<BlockEnd_t>(codes); 7060 info = _parser.parse<BlockEnd_t>(codes, false);
6613 if (info.error) { 7061 if (info.error) {
6614 throw CompileError("failed to expand macro as block: "s + info.error.value().msg, x); 7062 throw CompileError("failed to expand macro as block: "s + info.error.value().msg, x);
6615 } 7063 }
6616 } else { 7064 } else {
6617 info = _parser.parse<Exp_t>(codes); 7065 info = _parser.parse<Exp_t>(codes, false);
6618 if (!info.node && allowBlockMacroReturn) { 7066 if (!info.node && allowBlockMacroReturn) {
6619 info = _parser.parse<BlockEnd_t>(codes); 7067 info = _parser.parse<BlockEnd_t>(codes, false);
6620 if (info.error) { 7068 if (info.error) {
6621 throw CompileError("failed to expand macro as expr or block: "s + info.error.value().msg, x); 7069 throw CompileError("failed to expand macro as expr or block: "s + info.error.value().msg, x);
6622 } 7070 }
@@ -6752,6 +7200,9 @@ private:
6752 if (transformChainEndWithColonItem(chainList, out, usage, assignList)) { 7200 if (transformChainEndWithColonItem(chainList, out, usage, assignList)) {
6753 return; 7201 return;
6754 } 7202 }
7203 if (transformChainEndWithSlice(chainList, out, usage, assignList)) {
7204 return;
7205 }
6755 transformChainList(chainList, out, usage, assignList); 7206 transformChainList(chainList, out, usage, assignList);
6756 } 7207 }
6757 7208
@@ -7153,7 +7604,7 @@ private:
7153 try { 7604 try {
7154 unsigned long long value = std::stoull(binaryPart, nullptr, 2); 7605 unsigned long long value = std::stoull(binaryPart, nullptr, 2);
7155 numStr = std::to_string(value); 7606 numStr = std::to_string(value);
7156 } catch (const std::exception& e) { 7607 } catch (const std::exception&) {
7157 throw CompileError("invalid binary literal"sv, num); 7608 throw CompileError("invalid binary literal"sv, num);
7158 } 7609 }
7159 } else if (getLuaTarget(num) < 502) { 7610 } else if (getLuaTarget(num) < 502) {
@@ -7859,6 +8310,11 @@ private:
7859 } 8310 }
7860 8311
7861 bool transformForEachHead(AssignableNameList_t* nameList, ast_node* loopTarget, str_list& out, bool inClosure) { 8312 bool transformForEachHead(AssignableNameList_t* nameList, ast_node* loopTarget, str_list& out, bool inClosure) {
8313 enum class NumState {
8314 Unknown,
8315 Positive,
8316 Negtive
8317 };
7862 auto x = nameList; 8318 auto x = nameList;
7863 str_list temp; 8319 str_list temp;
7864 str_list vars; 8320 str_list vars;
@@ -7925,15 +8381,35 @@ private:
7925 for (auto item : chainList) { 8381 for (auto item : chainList) {
7926 chain->items.push_back(item); 8382 chain->items.push_back(item);
7927 } 8383 }
7928 std::string startValue("1"sv); 8384 std::string startValue;
8385 NumState startStatus = NumState::Unknown;
7929 if (auto exp = slice->startValue.as<Exp_t>()) { 8386 if (auto exp = slice->startValue.as<Exp_t>()) {
7930 transformExp(exp, temp, ExpUsage::Closure); 8387 transformExp(exp, temp, ExpUsage::Closure);
8388 if (temp.back().at(0) == '-') {
8389 if (_parser.match<Num_t>(temp.back().substr(1))) {
8390 startStatus = NumState::Negtive;
8391 }
8392 } else {
8393 if (_parser.match<Num_t>(temp.back())) {
8394 startStatus = NumState::Positive;
8395 }
8396 }
7931 startValue = std::move(temp.back()); 8397 startValue = std::move(temp.back());
7932 temp.pop_back(); 8398 temp.pop_back();
7933 } 8399 }
7934 std::string stopValue; 8400 std::string stopValue;
8401 NumState stopStatus = NumState::Unknown;
7935 if (auto exp = slice->stopValue.as<Exp_t>()) { 8402 if (auto exp = slice->stopValue.as<Exp_t>()) {
7936 transformExp(exp, temp, ExpUsage::Closure); 8403 transformExp(exp, temp, ExpUsage::Closure);
8404 if (temp.back().at(0) == '-') {
8405 if (_parser.match<Num_t>(temp.back().substr(1))) {
8406 stopStatus = NumState::Negtive;
8407 }
8408 } else {
8409 if (_parser.match<Num_t>(temp.back())) {
8410 stopStatus = NumState::Positive;
8411 }
8412 }
7937 stopValue = std::move(temp.back()); 8413 stopValue = std::move(temp.back());
7938 temp.pop_back(); 8414 temp.pop_back();
7939 } 8415 }
@@ -7955,8 +8431,33 @@ private:
7955 transformChainValue(chain, temp, ExpUsage::Closure); 8431 transformChainValue(chain, temp, ExpUsage::Closure);
7956 _buf << prefix << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList); 8432 _buf << prefix << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList);
7957 } 8433 }
8434 if (startValue.empty()) {
8435 startValue = "1"s;
8436 startStatus = NumState::Positive;
8437 }
8438 std::string minVar;
8439 if (startStatus != NumState::Positive) {
8440 std::string prefix;
8441 if (!extraScope && !inClosure && needScope) {
8442 extraScope = true;
8443 prefix = indent() + "do"s + nll(x);
8444 pushScope();
8445 }
8446 minVar = getUnusedName("_min_"sv);
8447 varBefore.push_back(minVar);
8448 if (startStatus == NumState::Negtive) {
8449 _buf << prefix << indent() << "local "sv << minVar << " = "sv << "#"sv << listVar << " + "sv << startValue << " + 1"sv << nll(nameList);
8450 } else {
8451 _buf << prefix << indent() << "local "sv << minVar << " = "sv << startValue << nll(nameList);
8452 }
8453 }
8454 bool defaultStop = false;
8455 if (stopValue.empty()) {
8456 stopValue = "#"s + listVar;
8457 defaultStop = true;
8458 }
7958 std::string maxVar; 8459 std::string maxVar;
7959 if (!stopValue.empty()) { 8460 if (stopStatus != NumState::Positive) {
7960 std::string prefix; 8461 std::string prefix;
7961 if (!extraScope && !inClosure && needScope) { 8462 if (!extraScope && !inClosure && needScope) {
7962 extraScope = true; 8463 extraScope = true;
@@ -7965,14 +8466,45 @@ private:
7965 } 8466 }
7966 maxVar = getUnusedName("_max_"sv); 8467 maxVar = getUnusedName("_max_"sv);
7967 varBefore.push_back(maxVar); 8468 varBefore.push_back(maxVar);
7968 _buf << prefix << indent() << "local "sv << maxVar << " = "sv << stopValue << nll(nameList); 8469 if (stopStatus == NumState::Negtive) {
8470 _buf << indent() << "local "sv << maxVar << " = "sv << "#"sv << listVar << " + "sv << stopValue << " + 1"sv << nll(nameList);
8471 } else {
8472 _buf << prefix << indent() << "local "sv << maxVar << " = "sv << stopValue << nll(nameList);
8473 }
8474 }
8475 if (startStatus == NumState::Unknown) {
8476 _buf << indent() << minVar << " = "sv << minVar << " < 0 and #"sv << listVar << " + "sv << minVar << " + 1 or "sv << minVar << nll(nameList);
8477 }
8478 if (!defaultStop && stopStatus == NumState::Unknown) {
8479 _buf << indent() << maxVar << " = "sv << maxVar << " < 0 and #"sv << listVar << " + "sv << maxVar << " + 1 or "sv << maxVar << nll(nameList);
7969 } 8480 }
7970 _buf << indent() << "for "sv << indexVar << " = "sv; 8481 _buf << indent() << "for "sv << indexVar << " = "sv;
7971 _buf << startValue << ", "sv; 8482 if (startValue.empty()) {
8483 _buf << "1"sv;
8484 } else {
8485 switch (startStatus) {
8486 case NumState::Unknown:
8487 case NumState::Negtive:
8488 _buf << minVar;
8489 break;
8490 case NumState::Positive:
8491 _buf << startValue;
8492 break;
8493 }
8494 }
8495 _buf << ", "sv;
7972 if (stopValue.empty()) { 8496 if (stopValue.empty()) {
7973 _buf << "#"sv << listVar; 8497 _buf << "#"sv << listVar;
7974 } else { 8498 } else {
7975 _buf << maxVar << " < 0 and #"sv << listVar << " + "sv << maxVar << " or "sv << maxVar; 8499 switch (stopStatus) {
8500 case NumState::Unknown:
8501 case NumState::Negtive:
8502 _buf << maxVar;
8503 break;
8504 case NumState::Positive:
8505 _buf << stopValue;
8506 break;
8507 }
7976 } 8508 }
7977 if (!stepValue.empty()) { 8509 if (!stepValue.empty()) {
7978 _buf << ", "sv << stepValue; 8510 _buf << ", "sv << stepValue;
@@ -8012,7 +8544,7 @@ private:
8012 pushScope(); 8544 pushScope();
8013 for (const auto& var : vars) forceAddToScope(var); 8545 for (const auto& var : vars) forceAddToScope(var);
8014 for (const auto& var : varAfter) addToScope(var); 8546 for (const auto& var : varAfter) addToScope(var);
8015 if (!varConstAfter.empty()) markVarConst(varConstAfter); 8547 if (!varConstAfter.empty()) markVarLocalConst(varConstAfter);
8016 if (!destructPairs.empty()) { 8548 if (!destructPairs.empty()) {
8017 temp.clear(); 8549 temp.clear();
8018 for (auto& pair : destructPairs) { 8550 for (auto& pair : destructPairs) {
@@ -8097,7 +8629,7 @@ private:
8097 _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : ", "s + step) << " do"sv << nll(var); 8629 _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : ", "s + step) << " do"sv << nll(var);
8098 pushScope(); 8630 pushScope();
8099 forceAddToScope(varName); 8631 forceAddToScope(varName);
8100 markVarConst(varName); 8632 markVarLocalConst(varName);
8101 out.push_back(clearBuf()); 8633 out.push_back(clearBuf());
8102 } 8634 }
8103 8635
@@ -8105,26 +8637,59 @@ private:
8105 transformForHead(forNode->varName, forNode->startValue, forNode->stopValue, forNode->stepValue, out); 8637 transformForHead(forNode->varName, forNode->startValue, forNode->stopValue, forNode->stepValue, out);
8106 } 8638 }
8107 8639
8108 void transform_plain_body(ast_node* body, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { 8640 void transform_plain_body(ast_node* bodyOrStmt, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
8109 switch (body->get_id()) { 8641 switch (bodyOrStmt->get_id()) {
8110 case id<Block_t>(): 8642 case id<Block_t>():
8111 transformBlock(static_cast<Block_t*>(body), out, usage, assignList); 8643 transformBlock(static_cast<Block_t*>(bodyOrStmt), out, usage, assignList);
8112 break; 8644 break;
8113 case id<Statement_t>(): { 8645 case id<Statement_t>(): {
8114 auto newBlock = body->new_ptr<Block_t>(); 8646 auto newBlock = bodyOrStmt->new_ptr<Block_t>();
8115 newBlock->statements.push_back(body); 8647 newBlock->statements.push_back(bodyOrStmt);
8116 transformBlock(newBlock, out, usage, assignList); 8648 transformBlock(newBlock, out, usage, assignList);
8117 break; 8649 break;
8118 } 8650 }
8119 default: YUEE("AST node mismatch", body); break; 8651 default: YUEE("AST node mismatch", bodyOrStmt); break;
8120 } 8652 }
8121 } 8653 }
8122 8654
8123 bool hasContinueStatement(ast_node* body) { 8655 enum class BreakLoopType {
8124 return traversal::Stop == body->traverse([&](ast_node* node) { 8656 None = 0,
8657 Break = 1,
8658 BreakWithValue = 1 << 1,
8659 Continue = 1 << 2
8660 };
8661
8662 bool hasBreak(uint32_t breakLoopType) const {
8663 return (breakLoopType & int(BreakLoopType::Break)) != 0;
8664 }
8665
8666 bool hasBreakWithValue(uint32_t breakLoopType) const {
8667 return (breakLoopType & int(BreakLoopType::BreakWithValue)) != 0;
8668 }
8669
8670 bool hasContinue(uint32_t breakLoopType) const {
8671 return (breakLoopType & int(BreakLoopType::Continue)) != 0;
8672 }
8673
8674 uint32_t getBreakLoopType(ast_node* body, const std::string& varBWV) {
8675 uint32_t type = 0;
8676 body->traverse([&](ast_node* node) {
8125 if (auto stmt = ast_cast<Statement_t>(node)) { 8677 if (auto stmt = ast_cast<Statement_t>(node)) {
8126 if (stmt->content.is<BreakLoop_t>()) { 8678 if (auto breakLoop = stmt->content.as<BreakLoop_t>()) {
8127 return _parser.toString(stmt->content) == "continue"sv ? traversal::Stop : traversal::Return; 8679 if (breakLoop->type.is<Continue_t>()) {
8680 type |= int(BreakLoopType::Continue);
8681 return traversal::Return;
8682 } else {
8683 if (breakLoop->value) {
8684 if (varBWV.empty()) {
8685 throw CompileError("break with a value is not allowed here"sv, breakLoop->value);
8686 }
8687 type |= int(BreakLoopType::BreakWithValue);
8688 breakLoop->varBWV = varBWV;
8689 } else {
8690 type |= int(BreakLoopType::Break);
8691 }
8692 }
8128 } else if (auto expList = expListFrom(stmt)) { 8693 } else if (auto expList = expListFrom(stmt)) {
8129 BLOCK_START 8694 BLOCK_START
8130 auto value = singleValueFrom(expList); 8695 auto value = singleValueFrom(expList);
@@ -8135,40 +8700,30 @@ private:
8135 switch (sVal->get_id()) { 8700 switch (sVal->get_id()) {
8136 case id<With_t>(): { 8701 case id<With_t>(): {
8137 auto withNode = static_cast<With_t*>(sVal); 8702 auto withNode = static_cast<With_t*>(sVal);
8138 if (hasContinueStatement(withNode->body)) { 8703 type |= getBreakLoopType(withNode->body, varBWV);
8139 return traversal::Stop; 8704 return traversal::Return;
8140 }
8141 break;
8142 } 8705 }
8143 case id<Do_t>(): { 8706 case id<Do_t>(): {
8144 auto doNode = static_cast<Do_t*>(sVal); 8707 auto doNode = static_cast<Do_t*>(sVal);
8145 if (hasContinueStatement(doNode->body)) { 8708 type |= getBreakLoopType(doNode->body, varBWV);
8146 return traversal::Stop; 8709 return traversal::Return;
8147 }
8148 break;
8149 } 8710 }
8150 case id<If_t>(): { 8711 case id<If_t>(): {
8151 auto ifNode = static_cast<If_t*>(sVal); 8712 auto ifNode = static_cast<If_t*>(sVal);
8152 for (auto n : ifNode->nodes.objects()) { 8713 for (auto n : ifNode->nodes.objects()) {
8153 if (hasContinueStatement(n)) { 8714 type |= getBreakLoopType(n, varBWV);
8154 return traversal::Stop;
8155 }
8156 } 8715 }
8157 break; 8716 return traversal::Return;
8158 } 8717 }
8159 case id<Switch_t>(): { 8718 case id<Switch_t>(): {
8160 auto switchNode = static_cast<Switch_t*>(sVal); 8719 auto switchNode = static_cast<Switch_t*>(sVal);
8161 for (auto branch : switchNode->branches.objects()) { 8720 for (auto branch : switchNode->branches.objects()) {
8162 if (hasContinueStatement(static_cast<SwitchCase_t*>(branch)->body)) { 8721 type |= getBreakLoopType(static_cast<SwitchCase_t*>(branch)->body, varBWV);
8163 return traversal::Stop;
8164 }
8165 } 8722 }
8166 if (switchNode->lastBranch) { 8723 if (switchNode->lastBranch) {
8167 if (hasContinueStatement(switchNode->lastBranch)) { 8724 type |= getBreakLoopType(switchNode->lastBranch, varBWV);
8168 return traversal::Stop;
8169 }
8170 } 8725 }
8171 break; 8726 return traversal::Return;
8172 } 8727 }
8173 } 8728 }
8174 BLOCK_END 8729 BLOCK_END
@@ -8182,6 +8737,7 @@ private:
8182 } 8737 }
8183 return traversal::Return; 8738 return traversal::Return;
8184 }); 8739 });
8740 return type;
8185 } 8741 }
8186 8742
8187 void addDoToLastLineReturn(ast_node* body) { 8743 void addDoToLastLineReturn(ast_node* body) {
@@ -8205,10 +8761,10 @@ private:
8205 } 8761 }
8206 } 8762 }
8207 8763
8208 void transformLoopBody(ast_node* body, str_list& out, const std::string& appendContent, ExpUsage usage, ExpList_t* assignList = nullptr) { 8764 void transformLoopBody(ast_node* body, str_list& out, uint32_t breakLoopType, ExpUsage usage, ExpList_t* assignList = nullptr) {
8209 str_list temp; 8765 str_list temp;
8210 bool extraDo = false; 8766 bool extraDo = false;
8211 bool withContinue = hasContinueStatement(body); 8767 bool withContinue = hasContinue(breakLoopType);
8212 int target = getLuaTarget(body); 8768 int target = getLuaTarget(body);
8213 std::string extraLabel; 8769 std::string extraLabel;
8214 if (withContinue) { 8770 if (withContinue) {
@@ -8217,7 +8773,7 @@ private:
8217 if (!block->statements.empty()) { 8773 if (!block->statements.empty()) {
8218 auto stmt = static_cast<Statement_t*>(block->statements.back()); 8774 auto stmt = static_cast<Statement_t*>(block->statements.back());
8219 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { 8775 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) {
8220 extraDo = _parser.toString(breakLoop) == "break"sv; 8776 extraDo = breakLoop->type.is<Break_t>();
8221 } 8777 }
8222 } 8778 }
8223 } 8779 }
@@ -8250,9 +8806,6 @@ private:
8250 popScope(); 8806 popScope();
8251 _buf << indent() << "end"sv << nll(body); 8807 _buf << indent() << "end"sv << nll(body);
8252 } 8808 }
8253 if (!appendContent.empty()) {
8254 _buf << indent() << appendContent;
8255 }
8256 _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); 8809 _buf << indent() << _continueVars.top().var << " = true"sv << nll(body);
8257 popScope(); 8810 popScope();
8258 _buf << indent() << "until true"sv << nlr(body); 8811 _buf << indent() << "until true"sv << nlr(body);
@@ -8262,14 +8815,9 @@ private:
8262 temp.push_back(clearBuf()); 8815 temp.push_back(clearBuf());
8263 _continueVars.pop(); 8816 _continueVars.pop();
8264 } else { 8817 } else {
8265 if (!appendContent.empty()) {
8266 temp.push_back(indent() + appendContent);
8267 }
8268 temp.push_back(extraLabel); 8818 temp.push_back(extraLabel);
8269 _continueVars.pop(); 8819 _continueVars.pop();
8270 } 8820 }
8271 } else if (!appendContent.empty()) {
8272 temp.back().append(indent() + appendContent);
8273 } 8821 }
8274 out.push_back(join(temp)); 8822 out.push_back(join(temp));
8275 } 8823 }
@@ -8277,8 +8825,9 @@ private:
8277 std::string transformRepeatBody(Repeat_t* repeatNode, str_list& out) { 8825 std::string transformRepeatBody(Repeat_t* repeatNode, str_list& out) {
8278 str_list temp; 8826 str_list temp;
8279 bool extraDo = false; 8827 bool extraDo = false;
8280 auto body = repeatNode->body->content.get(); 8828 auto body = repeatNode->body.get();
8281 bool withContinue = hasContinueStatement(body); 8829 auto breakLoopType = getBreakLoopType(body, Empty);
8830 bool withContinue = hasContinue(breakLoopType);
8282 std::string conditionVar; 8831 std::string conditionVar;
8283 std::string extraLabel; 8832 std::string extraLabel;
8284 ast_ptr<false, ExpListAssign_t> condAssign; 8833 ast_ptr<false, ExpListAssign_t> condAssign;
@@ -8289,7 +8838,7 @@ private:
8289 if (!block->statements.empty()) { 8838 if (!block->statements.empty()) {
8290 auto stmt = static_cast<Statement_t*>(block->statements.back()); 8839 auto stmt = static_cast<Statement_t*>(block->statements.back());
8291 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { 8840 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) {
8292 extraDo = _parser.toString(breakLoop) == "break"sv; 8841 extraDo = breakLoop->type.is<Break_t>();
8293 } 8842 }
8294 } 8843 }
8295 } 8844 }
@@ -8352,7 +8901,8 @@ private:
8352 void transformFor(For_t* forNode, str_list& out) { 8901 void transformFor(For_t* forNode, str_list& out) {
8353 str_list temp; 8902 str_list temp;
8354 transformForHead(forNode, temp); 8903 transformForHead(forNode, temp);
8355 transformLoopBody(forNode->body, temp, Empty, ExpUsage::Common); 8904 auto breakLoopType = getBreakLoopType(forNode->body, Empty);
8905 transformLoopBody(forNode->body, temp, breakLoopType, ExpUsage::Common);
8356 popScope(); 8906 popScope();
8357 out.push_back(join(temp) + indent() + "end"s + nlr(forNode)); 8907 out.push_back(join(temp) + indent() + "end"s + nlr(forNode));
8358 } 8908 }
@@ -8363,13 +8913,24 @@ private:
8363 addToScope(accum); 8913 addToScope(accum);
8364 std::string len = getUnusedName("_len_"sv); 8914 std::string len = getUnusedName("_len_"sv);
8365 addToScope(len); 8915 addToScope(len);
8366 _buf << indent() << "local "sv << accum << " = { }"sv << nll(forNode); 8916 auto breakLoopType = getBreakLoopType(forNode->body, accum);
8917 _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(forNode);
8918 out.emplace_back(clearBuf());
8367 _buf << indent() << "local "sv << len << " = 1"sv << nll(forNode); 8919 _buf << indent() << "local "sv << len << " = 1"sv << nll(forNode);
8368 out.push_back(clearBuf()); 8920 auto& lenAssign = out.emplace_back(clearBuf());
8369 transformForHead(forNode, out); 8921 transformForHead(forNode, out);
8370 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); 8922 if (hasBreakWithValue(breakLoopType)) {
8371 auto lenLine = len + " = "s + len + " + 1"s + nlr(forNode->body); 8923 lenAssign.clear();
8372 transformLoopBody(forNode->body, out, lenLine, ExpUsage::Assignment, expList); 8924 transformLoopBody(forNode->body, out, breakLoopType, ExpUsage::Common);
8925 } else {
8926 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x);
8927 auto followStmt = toAst<Statement_t>(len + "+=1"s, forNode->body);
8928 expList->followStmt = followStmt.get();
8929 transformLoopBody(forNode->body, out, breakLoopType, ExpUsage::Assignment, expList);
8930 if (!expList->followStmtProcessed) {
8931 lenAssign.clear();
8932 }
8933 }
8373 popScope(); 8934 popScope();
8374 out.push_back(indent() + "end"s + nlr(forNode)); 8935 out.push_back(indent() + "end"s + nlr(forNode));
8375 return accum; 8936 return accum;
@@ -8448,7 +9009,8 @@ private:
8448 void transformForEach(ForEach_t* forEach, str_list& out) { 9009 void transformForEach(ForEach_t* forEach, str_list& out) {
8449 str_list temp; 9010 str_list temp;
8450 bool extraScoped = transformForEachHead(forEach->nameList, forEach->loopValue, temp, false); 9011 bool extraScoped = transformForEachHead(forEach->nameList, forEach->loopValue, temp, false);
8451 transformLoopBody(forEach->body, temp, Empty, ExpUsage::Common); 9012 auto breakLoopType = getBreakLoopType(forEach->body, Empty);
9013 transformLoopBody(forEach->body, temp, breakLoopType, ExpUsage::Common);
8452 popScope(); 9014 popScope();
8453 out.push_back(temp.front() + temp.back() + indent() + "end"s + nlr(forEach)); 9015 out.push_back(temp.front() + temp.back() + indent() + "end"s + nlr(forEach));
8454 if (extraScoped) { 9016 if (extraScoped) {
@@ -8463,13 +9025,24 @@ private:
8463 addToScope(accum); 9025 addToScope(accum);
8464 std::string len = getUnusedName("_len_"sv); 9026 std::string len = getUnusedName("_len_"sv);
8465 addToScope(len); 9027 addToScope(len);
8466 _buf << indent() << "local "sv << accum << " = { }"sv << nll(forEach); 9028 auto breakLoopType = getBreakLoopType(forEach->body, accum);
9029 _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(forEach);
9030 out.emplace_back(clearBuf());
8467 _buf << indent() << "local "sv << len << " = 1"sv << nll(forEach); 9031 _buf << indent() << "local "sv << len << " = 1"sv << nll(forEach);
8468 out.push_back(clearBuf()); 9032 auto& lenAssign = out.emplace_back(clearBuf());
8469 transformForEachHead(forEach->nameList, forEach->loopValue, out, true); 9033 transformForEachHead(forEach->nameList, forEach->loopValue, out, true);
8470 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); 9034 if (hasBreakWithValue(breakLoopType)) {
8471 auto lenLine = len + " = "s + len + " + 1"s + nlr(forEach->body); 9035 lenAssign.clear();
8472 transformLoopBody(forEach->body, out, lenLine, ExpUsage::Assignment, expList); 9036 transformLoopBody(forEach->body, out, breakLoopType, ExpUsage::Common);
9037 } else {
9038 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x);
9039 auto followStmt = toAst<Statement_t>(len + "+=1"s, forEach->body);
9040 expList->followStmt = followStmt.get();
9041 transformLoopBody(forEach->body, out, breakLoopType, ExpUsage::Assignment, expList);
9042 if (!expList->followStmtProcessed) {
9043 lenAssign.clear();
9044 }
9045 }
8473 popScope(); 9046 popScope();
8474 out.push_back(indent() + "end"s + nlr(forEach)); 9047 out.push_back(indent() + "end"s + nlr(forEach));
8475 return accum; 9048 return accum;
@@ -8653,12 +9226,64 @@ private:
8653 out.push_back(temp.empty() ? "\"\""s : join(temp, " .. "sv)); 9226 out.push_back(temp.empty() ? "\"\""s : join(temp, " .. "sv));
8654 } 9227 }
8655 9228
9229 void transformYAMLMultiline(YAMLMultiline_t* multiline, str_list& out) {
9230 std::optional<std::string> indent;
9231 str_list temp;
9232 for (auto line_ : multiline->lines.objects()) {
9233 auto line = static_cast<YAMLLine_t*>(line_);
9234 auto indentStr = _parser.toString(line->indent);
9235 if (!indent) {
9236 indent = indentStr;
9237 }
9238 if (std::string_view{indentStr.c_str(), indent.value().size()} != indent.value()) {
9239 throw CompileError("inconsistent indent"sv, line);
9240 }
9241 indentStr = indentStr.substr(indent.value().size());
9242 str_list segs;
9243 bool firstSeg = true;
9244 for (auto seg_ : line->segments.objects()) {
9245 auto content = static_cast<YAMLLineContent_t*>(seg_)->content.get();
9246 switch (content->get_id()) {
9247 case id<YAMLLineInner_t>(): {
9248 auto seqStr = _parser.toString(content);
9249 Utils::replace(seqStr, "\\#"sv, "#"sv);
9250 if (firstSeg) {
9251 firstSeg = false;
9252 seqStr.insert(0, indentStr);
9253 }
9254 segs.push_back(Utils::toLuaDoubleString(seqStr));
9255 break;
9256 }
9257 case id<Exp_t>(): {
9258 if (firstSeg) {
9259 firstSeg = false;
9260 if (!indentStr.empty()) {
9261 segs.push_back(Utils::toLuaDoubleString(indentStr));
9262 }
9263 }
9264 transformExp(static_cast<Exp_t*>(content), segs, ExpUsage::Closure);
9265 segs.back() = globalVar("tostring"sv, content, AccessType::Read) + '(' + segs.back() + ')';
9266 break;
9267 }
9268 default: YUEE("AST node mismatch", content); break;
9269 }
9270 }
9271 temp.push_back(join(segs, " .. "sv));
9272 }
9273 auto str = join(temp, " .. '\\n' .. "sv);
9274 Utils::replace(str, "\" .. '\\n' .. \""sv, "\\n"sv);
9275 Utils::replace(str, "\" .. '\\n'"sv, "\\n\""sv);
9276 Utils::replace(str, "'\\n' .. \""sv, "\"\\n"sv);
9277 out.push_back(str);
9278 }
9279
8656 void transformString(String_t* string, str_list& out) { 9280 void transformString(String_t* string, str_list& out) {
8657 auto str = string->str.get(); 9281 auto str = string->str.get();
8658 switch (str->get_id()) { 9282 switch (str->get_id()) {
8659 case id<SingleString_t>(): transformSingleString(static_cast<SingleString_t*>(str), out); break; 9283 case id<SingleString_t>(): transformSingleString(static_cast<SingleString_t*>(str), out); break;
8660 case id<DoubleString_t>(): transformDoubleString(static_cast<DoubleString_t*>(str), out); break; 9284 case id<DoubleString_t>(): transformDoubleString(static_cast<DoubleString_t*>(str), out); break;
8661 case id<LuaString_t>(): transformLuaString(static_cast<LuaString_t*>(str), out); break; 9285 case id<LuaString_t>(): transformLuaString(static_cast<LuaString_t*>(str), out); break;
9286 case id<YAMLMultiline_t>(): transformYAMLMultiline(static_cast<YAMLMultiline_t*>(str), out); break;
8662 default: YUEE("AST node mismatch", str); break; 9287 default: YUEE("AST node mismatch", str); break;
8663 } 9288 }
8664 } 9289 }
@@ -8840,7 +9465,7 @@ private:
8840 auto names = transformAssignDefs(assignment->expList.get(), DefOp::Get); 9465 auto names = transformAssignDefs(assignment->expList.get(), DefOp::Get);
8841 for (const auto& name : names) { 9466 for (const auto& name : names) {
8842 forceAddToScope(name.first); 9467 forceAddToScope(name.first);
8843 markVarConst(name.first); 9468 markVarLocalConst(name.first);
8844 varDefs.push_back(name.first); 9469 varDefs.push_back(name.first);
8845 classConstVars.push_back(name.first); 9470 classConstVars.push_back(name.first);
8846 } 9471 }
@@ -8854,7 +9479,7 @@ private:
8854 for (const auto& item : destruct.items) { 9479 for (const auto& item : destruct.items) {
8855 if (!item.targetVar.empty()) { 9480 if (!item.targetVar.empty()) {
8856 forceAddToScope(item.targetVar); 9481 forceAddToScope(item.targetVar);
8857 markVarConst(item.targetVar); 9482 markVarLocalConst(item.targetVar);
8858 varDefs.push_back(item.targetVar); 9483 varDefs.push_back(item.targetVar);
8859 classConstVars.push_back(item.targetVar); 9484 classConstVars.push_back(item.targetVar);
8860 } 9485 }
@@ -9236,11 +9861,11 @@ private:
9236 std::string withVar; 9861 std::string withVar;
9237 bool needScope = !currentScope().lastStatement && !returnValue; 9862 bool needScope = !currentScope().lastStatement && !returnValue;
9238 bool extraScope = false; 9863 bool extraScope = false;
9239 if (with->assigns) { 9864 if (with->assign) {
9240 auto vars = getAssignVars(with); 9865 auto vars = getAssignVars(with);
9241 if (vars.front().empty() || isDeclaredAsGlobal(vars.front())) { 9866 if (vars.front().empty() || isDeclaredAsGlobal(vars.front())) {
9242 if (with->assigns->values.objects().size() == 1) { 9867 if (with->assign->values.objects().size() == 1) {
9243 auto var = singleVariableFrom(with->assigns->values.objects().front(), AccessType::Read); 9868 auto var = singleVariableFrom(with->assign->values.objects().front(), AccessType::Read);
9244 if (!var.empty() && isLocal(var)) { 9869 if (!var.empty() && isLocal(var)) {
9245 withVar = var; 9870 withVar = var;
9246 } 9871 }
@@ -9250,7 +9875,7 @@ private:
9250 auto assignment = x->new_ptr<ExpListAssign_t>(); 9875 auto assignment = x->new_ptr<ExpListAssign_t>();
9251 assignment->expList.set(toAst<ExpList_t>(withVar, x)); 9876 assignment->expList.set(toAst<ExpList_t>(withVar, x));
9252 auto assign = x->new_ptr<Assign_t>(); 9877 auto assign = x->new_ptr<Assign_t>();
9253 assign->values.push_back(with->assigns->values.objects().front()); 9878 assign->values.push_back(with->assign->values.objects().front());
9254 assignment->action.set(assign); 9879 assignment->action.set(assign);
9255 if (needScope) { 9880 if (needScope) {
9256 extraScope = true; 9881 extraScope = true;
@@ -9264,7 +9889,7 @@ private:
9264 auto assign = x->new_ptr<Assign_t>(); 9889 auto assign = x->new_ptr<Assign_t>();
9265 assign->values.push_back(toAst<Exp_t>(withVar, x)); 9890 assign->values.push_back(toAst<Exp_t>(withVar, x));
9266 bool skipFirst = true; 9891 bool skipFirst = true;
9267 for (auto value : with->assigns->values.objects()) { 9892 for (auto value : with->assign->values.objects()) {
9268 if (skipFirst) { 9893 if (skipFirst) {
9269 skipFirst = false; 9894 skipFirst = false;
9270 continue; 9895 continue;
@@ -9277,7 +9902,7 @@ private:
9277 withVar = vars.front(); 9902 withVar = vars.front();
9278 auto assignment = x->new_ptr<ExpListAssign_t>(); 9903 auto assignment = x->new_ptr<ExpListAssign_t>();
9279 assignment->expList.set(with->valueList); 9904 assignment->expList.set(with->valueList);
9280 assignment->action.set(with->assigns); 9905 assignment->action.set(with->assign);
9281 if (needScope) { 9906 if (needScope) {
9282 extraScope = true; 9907 extraScope = true;
9283 temp.push_back(indent() + "do"s + nll(with)); 9908 temp.push_back(indent() + "do"s + nll(with));
@@ -9355,15 +9980,57 @@ private:
9355 } 9980 }
9356 } 9981 }
9357 _withVars.push(withVar); 9982 _withVars.push(withVar);
9983 std::string breakWithVar;
9984 if (assignList || returnValue) {
9985 auto breakLoopType = getBreakLoopType(with->body, withVar);
9986 if (hasBreakWithValue(breakLoopType)) {
9987 breakWithVar = withVar;
9988 }
9989 }
9358 if (with->eop) { 9990 if (with->eop) {
9359 auto ifNode = x->new_ptr<If_t>(); 9991 auto ifNode = x->new_ptr<If_t>();
9360 ifNode->type.set(toAst<IfType_t>("if"sv, x)); 9992 ifNode->type.set(toAst<IfType_t>("if"sv, x));
9361 ifNode->nodes.push_back(toAst<IfCond_t>(withVar + "~=nil"s, x)); 9993 ifNode->nodes.push_back(toAst<IfCond_t>(withVar + "~=nil"s, x));
9362 ifNode->nodes.push_back(with->body); 9994 ifNode->nodes.push_back(with->body);
9363 transformIf(ifNode, temp, ExpUsage::Common); 9995 if (breakWithVar.empty()) {
9996 transformIf(ifNode, temp, ExpUsage::Common);
9997 } else {
9998 auto simpleValue = x->new_ptr<SimpleValue_t>();
9999 simpleValue->value.set(ifNode);
10000 auto exp = newExp(simpleValue, x);
10001 auto expList = x->new_ptr<ExpList_t>();
10002 expList->exprs.push_back(exp);
10003 auto expListAssign = x->new_ptr<ExpListAssign_t>();
10004 expListAssign->expList.set(expList);
10005 auto stmt = x->new_ptr<Statement_t>();
10006 stmt->content.set(expListAssign);
10007 auto repeatNode = toAst<Repeat_t>("repeat\n\t--\nuntil true"s, x);
10008 auto block = x->new_ptr<Block_t>();
10009 block->statements.push_back(stmt);
10010 repeatNode->body.set(block);
10011 auto sVal = x->new_ptr<SimpleValue_t>();
10012 sVal->value.set(repeatNode);
10013 auto asmt = assignmentFrom(toAst<Exp_t>(breakWithVar, x), newExp(sVal, x), x);
10014 transformAssignment(asmt, temp);
10015 }
9364 } else { 10016 } else {
9365 bool transformed = false; 10017 bool transformed = false;
9366 if (!extraScope && assignList) { 10018 if (!breakWithVar.empty()) {
10019 auto repeatNode = toAst<Repeat_t>("repeat\n\t--\nuntil true"s, x);
10020 auto block = x->new_ptr<Block_t>();
10021 if (auto blk = with->body.as<Block_t>()) {
10022 block->statements.dup(blk->statements);
10023 } else {
10024 auto stmt = with->body.to<Statement_t>();
10025 block->statements.push_back(stmt);
10026 }
10027 repeatNode->body.set(block);
10028 auto sVal = x->new_ptr<SimpleValue_t>();
10029 sVal->value.set(repeatNode);
10030 auto asmt = assignmentFrom(toAst<Exp_t>(breakWithVar, x), newExp(sVal, x), x);
10031 transformAssignment(asmt, temp);
10032 transformed = true;
10033 } else if (!extraScope && assignList) {
9367 if (auto block = with->body.as<Block_t>()) { 10034 if (auto block = with->body.as<Block_t>()) {
9368 if (!block->statements.empty()) { 10035 if (!block->statements.empty()) {
9369 Statement_t* stmt = static_cast<Statement_t*>(block->statements.back()); 10036 Statement_t* stmt = static_cast<Statement_t*>(block->statements.back());
@@ -9428,12 +10095,18 @@ private:
9428 switch (item->get_id()) { 10095 switch (item->get_id()) {
9429 case id<ClassDecl_t>(): { 10096 case id<ClassDecl_t>(): {
9430 auto classDecl = static_cast<ClassDecl_t*>(item); 10097 auto classDecl = static_cast<ClassDecl_t*>(item);
10098 std::string varName;
9431 if (classDecl->name) { 10099 if (classDecl->name) {
9432 if (auto var = classDecl->name->item.as<Variable_t>()) { 10100 if (auto var = classDecl->name->item.as<Variable_t>()) {
9433 addGlobalVar(variableToString(var), classDecl->name->item); 10101 varName = variableToString(var);
10102 addGlobalVar(varName, var);
9434 } 10103 }
9435 } 10104 }
10105 if (varName.empty()) {
10106 throw CompileError("missing name for class", classDecl);
10107 }
9436 transformClassDecl(classDecl, out, ExpUsage::Common); 10108 transformClassDecl(classDecl, out, ExpUsage::Common);
10109 markVarGlobalConst(varName);
9437 break; 10110 break;
9438 } 10111 }
9439 case id<GlobalOp_t>(): 10112 case id<GlobalOp_t>():
@@ -9447,9 +10120,11 @@ private:
9447 auto values = global->item.to<GlobalValues_t>(); 10120 auto values = global->item.to<GlobalValues_t>();
9448 if (values->valueList) { 10121 if (values->valueList) {
9449 auto expList = x->new_ptr<ExpList_t>(); 10122 auto expList = x->new_ptr<ExpList_t>();
10123 str_list varNames;
9450 for (auto name : values->nameList->names.objects()) { 10124 for (auto name : values->nameList->names.objects()) {
9451 auto var = static_cast<Variable_t*>(name); 10125 auto var = static_cast<Variable_t*>(name);
9452 addGlobalVar(variableToString(var), var); 10126 varNames.emplace_back(variableToString(var));
10127 addGlobalVar(varNames.back(), var);
9453 auto callable = x->new_ptr<Callable_t>(); 10128 auto callable = x->new_ptr<Callable_t>();
9454 callable->item.set(name); 10129 callable->item.set(name);
9455 auto chainValue = x->new_ptr<ChainValue_t>(); 10130 auto chainValue = x->new_ptr<ChainValue_t>();
@@ -9468,10 +10143,17 @@ private:
9468 } 10143 }
9469 assignment->action.set(assign); 10144 assignment->action.set(assign);
9470 transformAssignment(assignment, out); 10145 transformAssignment(assignment, out);
10146 for (const auto& name : varNames) {
10147 markVarGlobalConst(name);
10148 }
9471 } else { 10149 } else {
9472 for (auto name : values->nameList->names.objects()) { 10150 for (auto name : values->nameList->names.objects()) {
9473 auto var = static_cast<Variable_t*>(name); 10151 auto var = static_cast<Variable_t*>(name);
9474 addGlobalVar(variableToString(var), var); 10152 auto varName = variableToString(var);
10153 addGlobalVar(varName, var);
10154 if (global->constAttrib) {
10155 markVarGlobalConst(varName);
10156 }
9475 } 10157 }
9476 } 10158 }
9477 break; 10159 break;
@@ -9820,8 +10502,47 @@ private:
9820 out.push_back(join(temp)); 10502 out.push_back(join(temp));
9821 } 10503 }
9822 10504
9823 void transformTry(Try_t* tryNode, str_list& out, ExpUsage usage) { 10505 void transformTry(Try_t* tryNode, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
9824 auto x = tryNode; 10506 auto x = tryNode;
10507 if (tryNode->eop && usage == ExpUsage::Assignment) {
10508 str_list rets;
10509 pushScope();
10510 auto okVar = getUnusedName("_ok_"sv);
10511 for (size_t i = 0; i < assignList->exprs.size(); i++) {
10512 auto retVar = getUnusedName("_ret_"sv);
10513 rets.emplace_back(retVar);
10514 addToScope(retVar);
10515 }
10516 popScope();
10517 auto varList = join(rets, ","sv);
10518 auto ifNode = toAst<If_t>("if "s + okVar + ',' + varList + ":=try nil then "s + varList, x);
10519 auto exp = ast_to<IfCond_t>(ifNode->nodes.front())->assignment->assign->values.front();
10520 auto sVal = simpleSingleValueFrom(exp);
10521 auto newTry = sVal->value.to<Try_t>();
10522 newTry->func.set(tryNode->func);
10523 newTry->catchBlock.set(tryNode->catchBlock);
10524 auto assignment = x->new_ptr<ExpListAssign_t>();
10525 assignment->expList.set(assignList);
10526 auto assign = x->new_ptr<Assign_t>();
10527 assign->values.push_back(ifNode);
10528 assignment->action.set(assign);
10529 transformAssignment(assignment, out);
10530 return;
10531 }
10532 if (tryNode->eop && usage != ExpUsage::Common) {
10533 auto okVar = getUnusedName("_ok_"sv);
10534 auto code = "do\n\t"s + okVar + ", ... = try nil\n\t... if "s + okVar;
10535 auto doNode = toAst<Do_t>(code, x);
10536 auto block = doNode->body->content.to<Block_t>();
10537 auto asmt = static_cast<Statement_t*>(block->statements.front())->content.to<ExpListAssign_t>();
10538 auto assign = asmt->action.to<Assign_t>();
10539 auto sVal = simpleSingleValueFrom(assign->values.back());
10540 auto newTry = sVal->value.to<Try_t>();
10541 newTry->func.set(tryNode->func);
10542 newTry->catchBlock.set(tryNode->catchBlock);
10543 transformDo(doNode, out, usage);
10544 return;
10545 }
9825 ast_ptr<true, Exp_t> errHandler; 10546 ast_ptr<true, Exp_t> errHandler;
9826 if (tryNode->catchBlock) { 10547 if (tryNode->catchBlock) {
9827 auto catchBlock = tryNode->catchBlock.get(); 10548 auto catchBlock = tryNode->catchBlock.get();
@@ -10133,7 +10854,7 @@ private:
10133 out.push_back(join(temp)); 10854 out.push_back(join(temp));
10134 auto vars = getAssignVars(assignment); 10855 auto vars = getAssignVars(assignment);
10135 for (const auto& var : vars) { 10856 for (const auto& var : vars) {
10136 markVarConst(var); 10857 markVarLocalConst(var);
10137 } 10858 }
10138 } 10859 }
10139 10860
@@ -10361,12 +11082,36 @@ private:
10361 transformAssignment(assignment, out); 11082 transformAssignment(assignment, out);
10362 if (auto var = ast_cast<Variable_t>(target)) { 11083 if (auto var = ast_cast<Variable_t>(target)) {
10363 auto moduleName = variableToString(var); 11084 auto moduleName = variableToString(var);
10364 markVarConst(moduleName); 11085 markVarLocalConst(moduleName);
10365 } else { 11086 } else {
10366 markDestructureConst(assignment); 11087 markDestructureConst(assignment);
10367 } 11088 }
10368 } 11089 }
10369 11090
11091 void transformImportGlobal(ImportGlobal_t* importNode, str_list& out) {
11092 auto uname = static_cast<UnicodeName_t*>(importNode->segs.front());
11093 auto var = _parser.toString(uname);
11094 auto isNormal = _parser.match<Name_t>(var) && _parser.match<Variable_t>(var);
11095 auto varName = unicodeVariableFrom(uname);
11096 str_list temp;
11097 auto it = ++importNode->segs.objects().begin();
11098 for (; it != importNode->segs.objects().end(); ++it) {
11099 temp.emplace_back(_parser.toString(*it));
11100 }
11101 temp.emplace_front(var);
11102 if (isLocal(varName) || !isNormal) {
11103 temp.emplace_front("_G"s);
11104 }
11105 std::string stmt;
11106 if (importNode->target) {
11107 stmt = "const "s + _parser.toString(importNode->target) + '=' + join(temp, "."sv);
11108 } else {
11109 stmt = "const "s + temp.back() + '=' + join(temp, "."sv);
11110 }
11111 auto localAttrib = toAst<LocalAttrib_t>(stmt, importNode);
11112 transformLocalAttrib(localAttrib, out);
11113 }
11114
10370 void transformImport(Import_t* import, str_list& out) { 11115 void transformImport(Import_t* import, str_list& out) {
10371 auto content = import->content.get(); 11116 auto content = import->content.get();
10372 switch (content->get_id()) { 11117 switch (content->get_id()) {
@@ -10379,6 +11124,9 @@ private:
10379 case id<FromImport_t>(): 11124 case id<FromImport_t>():
10380 transformFromImport(static_cast<FromImport_t*>(content), out); 11125 transformFromImport(static_cast<FromImport_t*>(content), out);
10381 break; 11126 break;
11127 case id<ImportGlobal_t>():
11128 transformImportGlobal(static_cast<ImportGlobal_t*>(content), out);
11129 break;
10382 default: YUEE("AST node mismatch", content); break; 11130 default: YUEE("AST node mismatch", content); break;
10383 } 11131 }
10384 } 11132 }
@@ -10398,15 +11146,27 @@ private:
10398 addToScope(accumVar); 11146 addToScope(accumVar);
10399 auto lenVar = getUnusedName("_len_"sv); 11147 auto lenVar = getUnusedName("_len_"sv);
10400 addToScope(lenVar); 11148 addToScope(lenVar);
10401 temp.push_back(indent() + "local "s + accumVar + " = { }"s + nll(whileNode)); 11149 auto breakLoopType = getBreakLoopType(whileNode->body, accumVar);
10402 temp.push_back(indent() + "local "s + lenVar + " = 1"s + nll(whileNode)); 11150 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(whileNode);
11151 temp.emplace_back(clearBuf());
11152 _buf << indent() << "local "s << lenVar << " = 1"s << nll(whileNode);
11153 auto& lenAssign = temp.emplace_back(clearBuf());
10403 bool isUntil = _parser.toString(whileNode->type) == "until"sv; 11154 bool isUntil = _parser.toString(whileNode->type) == "until"sv;
10404 auto condStr = transformCondExp(whileNode->condition, isUntil); 11155 auto condStr = transformCondExp(whileNode->condition, isUntil);
10405 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); 11156 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode));
10406 pushScope(); 11157 pushScope();
10407 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); 11158 if (hasBreakWithValue(breakLoopType)) {
10408 auto lenLine = lenVar + " = "s + lenVar + " + 1"s + nlr(whileNode); 11159 lenAssign.clear();
10409 transformLoopBody(whileNode->body, temp, lenLine, ExpUsage::Assignment, assignLeft); 11160 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common);
11161 } else {
11162 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x);
11163 auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, whileNode);
11164 assignLeft->followStmt = followStmt.get();
11165 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft);
11166 if (!assignLeft->followStmtProcessed) {
11167 lenAssign.clear();
11168 }
11169 }
10410 popScope(); 11170 popScope();
10411 temp.push_back(indent() + "end"s + nlr(whileNode)); 11171 temp.push_back(indent() + "end"s + nlr(whileNode));
10412 if (expList) { 11172 if (expList) {
@@ -10442,15 +11202,26 @@ private:
10442 addToScope(accumVar); 11202 addToScope(accumVar);
10443 auto lenVar = getUnusedName("_len_"sv); 11203 auto lenVar = getUnusedName("_len_"sv);
10444 addToScope(lenVar); 11204 addToScope(lenVar);
10445 temp.push_back(indent() + "local "s + accumVar + " = { }"s + nll(whileNode)); 11205 auto breakLoopType = getBreakLoopType(whileNode->body, accumVar);
10446 temp.push_back(indent() + "local "s + lenVar + " = 1"s + nll(whileNode)); 11206 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(whileNode);
11207 temp.emplace_back(clearBuf());
11208 auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nll(whileNode));
10447 bool isUntil = _parser.toString(whileNode->type) == "until"sv; 11209 bool isUntil = _parser.toString(whileNode->type) == "until"sv;
10448 auto condStr = transformCondExp(whileNode->condition, isUntil); 11210 auto condStr = transformCondExp(whileNode->condition, isUntil);
10449 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); 11211 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode));
10450 pushScope(); 11212 pushScope();
10451 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); 11213 if (hasBreakWithValue(breakLoopType)) {
10452 auto lenLine = lenVar + " = "s + lenVar + " + 1"s + nlr(whileNode); 11214 lenAssign.clear();
10453 transformLoopBody(whileNode->body, temp, lenLine, ExpUsage::Assignment, assignLeft); 11215 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common);
11216 } else {
11217 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x);
11218 auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, whileNode);
11219 assignLeft->followStmt = followStmt.get();
11220 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft);
11221 if (!assignLeft->followStmtProcessed) {
11222 lenAssign.clear();
11223 }
11224 }
10454 popScope(); 11225 popScope();
10455 temp.push_back(indent() + "end"s + nlr(whileNode)); 11226 temp.push_back(indent() + "end"s + nlr(whileNode));
10456 temp.push_back(indent() + "return "s + accumVar + nlr(whileNode)); 11227 temp.push_back(indent() + "return "s + accumVar + nlr(whileNode));
@@ -10485,9 +11256,7 @@ private:
10485 expListAssign->expList.set(expList); 11256 expListAssign->expList.set(expList);
10486 auto stmt = x->new_ptr<Statement_t>(); 11257 auto stmt = x->new_ptr<Statement_t>();
10487 stmt->content.set(expListAssign); 11258 stmt->content.set(expListAssign);
10488 auto body = x->new_ptr<Body_t>(); 11259 repeat->body.set(stmt);
10489 body->content.set(stmt);
10490 repeat->body.set(body);
10491 transformRepeat(repeat, out); 11260 transformRepeat(repeat, out);
10492 return; 11261 return;
10493 } 11262 }
@@ -10495,7 +11264,8 @@ private:
10495 pushScope(); 11264 pushScope();
10496 bool isUntil = _parser.toString(whileNode->type) == "until"sv; 11265 bool isUntil = _parser.toString(whileNode->type) == "until"sv;
10497 auto condStr = transformCondExp(whileNode->condition, isUntil); 11266 auto condStr = transformCondExp(whileNode->condition, isUntil);
10498 transformLoopBody(whileNode->body, temp, Empty, ExpUsage::Common); 11267 auto breakLoopType = getBreakLoopType(whileNode->body, Empty);
11268 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common);
10499 popScope(); 11269 popScope();
10500 _buf << indent() << "while "sv << condStr << " do"sv << nll(whileNode); 11270 _buf << indent() << "while "sv << condStr << " do"sv << nll(whileNode);
10501 _buf << temp.back(); 11271 _buf << temp.back();
@@ -10503,6 +11273,106 @@ private:
10503 out.push_back(clearBuf()); 11273 out.push_back(clearBuf());
10504 } 11274 }
10505 11275
11276 void transformRepeatInPlace(Repeat_t* repeatNode, str_list& out, ExpList_t* expList = nullptr) {
11277 auto x = repeatNode;
11278 str_list temp;
11279 bool extraScope = false;
11280 if (expList) {
11281 if (!currentScope().lastStatement) {
11282 extraScope = true;
11283 temp.push_back(indent() + "do"s + nll(repeatNode));
11284 pushScope();
11285 }
11286 }
11287 auto accumVar = getUnusedName("_accum_"sv);
11288 addToScope(accumVar);
11289 auto lenVar = getUnusedName("_len_"sv);
11290 addToScope(lenVar);
11291 auto breakLoopType = getBreakLoopType(repeatNode->body, accumVar);
11292 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(repeatNode);
11293 temp.emplace_back(clearBuf());
11294 _buf << indent() << "local "s << lenVar << " = 1"s << nll(repeatNode);
11295 auto& lenAssign = temp.emplace_back(clearBuf());
11296 auto condStr = transformCondExp(repeatNode->condition, false);
11297 temp.push_back(indent() + "repeat"s + nll(repeatNode));
11298 pushScope();
11299 if (hasBreakWithValue(breakLoopType)) {
11300 lenAssign.clear();
11301 transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Common);
11302 } else {
11303 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x);
11304 auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, repeatNode);
11305 assignLeft->followStmt = followStmt.get();
11306 transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft);
11307 if (!assignLeft->followStmtProcessed) {
11308 lenAssign.clear();
11309 }
11310 }
11311 popScope();
11312 temp.push_back(indent() + "until "s + condStr + nlr(repeatNode));
11313 if (expList) {
11314 auto assign = x->new_ptr<Assign_t>();
11315 assign->values.push_back(toAst<Exp_t>(accumVar, x));
11316 auto assignment = x->new_ptr<ExpListAssign_t>();
11317 assignment->expList.set(expList);
11318 assignment->action.set(assign);
11319 transformAssignment(assignment, temp);
11320 if (extraScope) popScope();
11321 } else {
11322 temp.push_back(indent() + "return "s + accumVar + nlr(repeatNode));
11323 }
11324 if (expList && extraScope) {
11325 temp.push_back(indent() + "end"s + nlr(repeatNode));
11326 }
11327 out.push_back(join(temp));
11328 }
11329
11330 void transformRepeatClosure(Repeat_t* repeatNode, str_list& out) {
11331 auto x = repeatNode;
11332 auto simpleValue = x->new_ptr<SimpleValue_t>();
11333 simpleValue->value.set(repeatNode);
11334 if (transformAsUpValueFunc(newExp(simpleValue, x), out)) {
11335 return;
11336 }
11337 str_list temp;
11338 pushAnonFunctionScope();
11339 pushAnonVarArg();
11340 std::string& funcStart = temp.emplace_back();
11341 pushScope();
11342 auto accumVar = getUnusedName("_accum_"sv);
11343 addToScope(accumVar);
11344 auto lenVar = getUnusedName("_len_"sv);
11345 addToScope(lenVar);
11346 auto breakLoopType = getBreakLoopType(repeatNode->body, accumVar);
11347 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(repeatNode);
11348 temp.emplace_back(clearBuf());
11349 auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nll(repeatNode));
11350 auto condStr = transformCondExp(repeatNode->condition, false);
11351 temp.push_back(indent() + "repeat"s + nll(repeatNode));
11352 pushScope();
11353 if (hasBreakWithValue(breakLoopType)) {
11354 lenAssign.clear();
11355 transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Common);
11356 } else {
11357 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x);
11358 auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, repeatNode);
11359 assignLeft->followStmt = followStmt.get();
11360 transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft);
11361 if (!assignLeft->followStmtProcessed) {
11362 lenAssign.clear();
11363 }
11364 }
11365 popScope();
11366 temp.push_back(indent() + "until "s + condStr + nlr(repeatNode));
11367 temp.push_back(indent() + "return "s + accumVar + nlr(repeatNode));
11368 popScope();
11369 funcStart = anonFuncStart() + nll(repeatNode);
11370 temp.push_back(indent() + anonFuncEnd());
11371 popAnonVarArg();
11372 popFunctionScope();
11373 out.push_back(join(temp));
11374 }
11375
10506 void transformRepeat(Repeat_t* repeat, str_list& out) { 11376 void transformRepeat(Repeat_t* repeat, str_list& out) {
10507 str_list temp; 11377 str_list temp;
10508 pushScope(); 11378 pushScope();
@@ -10536,10 +11406,26 @@ private:
10536 pushScope(); 11406 pushScope();
10537 } 11407 }
10538 bool extraScope = false; 11408 bool extraScope = false;
11409 if (switchNode->assignment) {
11410 if (needScope) {
11411 extraScope = true;
11412 temp.push_back(indent() + "do"s + nll(x));
11413 pushScope();
11414 }
11415 auto asmt = x->new_ptr<ExpListAssign_t>();
11416 auto expList = x->new_ptr<ExpList_t>();
11417 expList->exprs.push_back(switchNode->target);
11418 if (switchNode->assignment->expList) {
11419 expList->exprs.dup(switchNode->assignment->expList->exprs);
11420 }
11421 asmt->expList.set(expList);
11422 asmt->action.set(switchNode->assignment->assign);
11423 transformAssignment(asmt, temp);
11424 }
10539 auto objVar = singleVariableFrom(switchNode->target, AccessType::Read); 11425 auto objVar = singleVariableFrom(switchNode->target, AccessType::Read);
10540 if (objVar.empty() || !isLocal(objVar)) { 11426 if (objVar.empty() || !isLocal(objVar)) {
10541 if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) { 11427 if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) {
10542 if (needScope) { 11428 if (needScope && !extraScope) {
10543 extraScope = true; 11429 extraScope = true;
10544 temp.push_back(indent() + "do"s + nll(x)); 11430 temp.push_back(indent() + "do"s + nll(x));
10545 pushScope(); 11431 pushScope();
@@ -10597,8 +11483,9 @@ private:
10597 } 11483 }
10598 temp.back().append(indent() + "if "s + tabCheckVar + " then"s + nll(branch)); 11484 temp.back().append(indent() + "if "s + tabCheckVar + " then"s + nll(branch));
10599 pushScope(); 11485 pushScope();
10600 auto assignment = assignmentFrom(static_cast<Exp_t*>(valueList->exprs.front()), toAst<Exp_t>(objVar, branch), branch); 11486 auto chainValue = toAst<ChainValue_t>(objVar, branch);
10601 auto info = extractDestructureInfo(assignment, true, false); 11487 auto assignment = assignmentFrom(static_cast<Exp_t*>(valueList->exprs.front()), newExp(chainValue, branch), branch);
11488 auto info = extractDestructureInfo(assignment, true, true);
10602 transformAssignment(assignment, temp, true); 11489 transformAssignment(assignment, temp, true);
10603 str_list conds; 11490 str_list conds;
10604 for (const auto& des : info.destructures) { 11491 for (const auto& des : info.destructures) {
@@ -10608,8 +11495,31 @@ private:
10608 const auto& destruct = std::get<Destructure>(des); 11495 const auto& destruct = std::get<Destructure>(des);
10609 for (const auto& item : destruct.items) { 11496 for (const auto& item : destruct.items) {
10610 if (!item.defVal) { 11497 if (!item.defVal) {
10611 transformExp(item.target, conds, ExpUsage::Closure); 11498 if (!isAssignable(item.target)) {
10612 conds.back().append(" ~= nil"s); 11499 auto callable = chainValue->items.front();
11500 auto chain = callable->new_ptr<ChainValue_t>();
11501 chain->items.push_back(callable);
11502 chain->items.dup(item.structure->items);
11503 if (specialChainValue(chain) == ChainType::Common) {
11504 transformChainValue(chain, conds, ExpUsage::Closure);
11505 auto vStr = conds.back();
11506 conds.pop_back();
11507 transformExp(item.target, conds, ExpUsage::Closure);
11508 conds.back().append(" == "s);
11509 conds.back().append(vStr);
11510 } else {
11511 auto varName = getUnusedName("_val_"sv);
11512 auto vExp = toAst<Exp_t>(varName, chain);
11513 auto asmt = assignmentFrom(vExp, newExp(chain, chain), chain);
11514 transformAssignment(asmt, temp);
11515 transformExp(item.target, conds, ExpUsage::Closure);
11516 conds.back().append(" == "s);
11517 conds.back().append(varName);
11518 }
11519 } else {
11520 transformExp(item.target, conds, ExpUsage::Closure);
11521 conds.back().append(" ~= nil"s);
11522 }
10613 } 11523 }
10614 } 11524 }
10615 } 11525 }
@@ -10907,7 +11817,7 @@ private:
10907 } 11817 }
10908 transformAssignment(assignment, temp); 11818 transformAssignment(assignment, temp);
10909 for (const auto& name : vars) { 11819 for (const auto& name : vars) {
10910 markVarConst(name); 11820 markVarLocalConst(name);
10911 } 11821 }
10912 if (localAttrib->attrib.is<CloseAttrib_t>()) { 11822 if (localAttrib->attrib.is<CloseAttrib_t>()) {
10913 str_list leftVars, rightVars; 11823 str_list leftVars, rightVars;
@@ -10979,7 +11889,7 @@ private:
10979 temp.push_back(indent() + "local "s + join(leftVars, ", "sv) + " = "s + join(items, ", "sv) + nll(x)); 11889 temp.push_back(indent() + "local "s + join(leftVars, ", "sv) + " = "s + join(items, ", "sv) + nll(x));
10980 } 11890 }
10981 for (const auto& var : vars) { 11891 for (const auto& var : vars) {
10982 markVarConst(var); 11892 markVarLocalConst(var);
10983 } 11893 }
10984 } 11894 }
10985 if (!listB->exprs.empty()) { 11895 if (!listB->exprs.empty()) {
@@ -11004,18 +11914,24 @@ private:
11004 temp.push_back(indent() + "local "s + join(vars, ", "sv) + nll(x)); 11914 temp.push_back(indent() + "local "s + join(vars, ", "sv) + nll(x));
11005 transformAssignment(assignment, temp); 11915 transformAssignment(assignment, temp);
11006 for (const auto& name : vars) { 11916 for (const auto& name : vars) {
11007 markVarConst(name); 11917 markVarLocalConst(name);
11008 } 11918 }
11009 } 11919 }
11010 out.push_back(join(temp)); 11920 out.push_back(join(temp));
11011 } 11921 }
11012 11922
11013 void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) { 11923 void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) {
11014 auto keyword = _parser.toString(breakLoop); 11924 auto isBreak = breakLoop->type.is<Break_t>();
11925 auto keyword = isBreak ? "break"s : "continue"s;
11015 if (_enableBreakLoop.empty() || !_enableBreakLoop.top()) { 11926 if (_enableBreakLoop.empty() || !_enableBreakLoop.top()) {
11016 throw CompileError(keyword + " is not inside a loop"s, breakLoop); 11927 throw CompileError(keyword + " is not inside a loop"s, breakLoop);
11017 } 11928 }
11018 if (keyword == "break"sv) { 11929 if (isBreak) {
11930 if (breakLoop->value) {
11931 auto exp = toAst<Exp_t>(breakLoop->varBWV, breakLoop->value);
11932 auto assignment = assignmentFrom(exp, breakLoop->value, breakLoop);
11933 transformAssignment(assignment, out);
11934 }
11019 out.push_back(indent() + keyword + nll(breakLoop)); 11935 out.push_back(indent() + keyword + nll(breakLoop));
11020 return; 11936 return;
11021 } 11937 }
diff --git a/src/yuescript/yue_compiler.h b/src/yuescript/yue_compiler.h
index d352636..aff5978 100644
--- a/src/yuescript/yue_compiler.h
+++ b/src/yuescript/yue_compiler.h
@@ -31,6 +31,7 @@ struct YueConfig {
31 bool reserveLineNumber = true; 31 bool reserveLineNumber = true;
32 bool useSpaceOverTab = false; 32 bool useSpaceOverTab = false;
33 bool reserveComment = false; 33 bool reserveComment = false;
34 bool lax = false;
34 // internal options 35 // internal options
35 bool exporting = false; 36 bool exporting = false;
36 bool profiling = false; 37 bool profiling = false;
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp
index 77c5901..01ca083 100644
--- a/src/yuescript/yue_parser.cpp
+++ b/src/yuescript/yue_parser.cpp
@@ -118,8 +118,8 @@ YueParser::YueParser() {
118 return false; 118 return false;
119 }); 119 });
120 120
121 if_assignment_syntax_error = pl::user(true_(), [](const item_t& item) { 121 assignment_expression_syntax_error = pl::user(true_(), [](const item_t& item) {
122 throw ParserError("use := for if-assignment expression"sv, item.begin); 122 throw ParserError("use := for assignment expression"sv, item.begin);
123 return false; 123 return false;
124 }); 124 });
125 125
@@ -162,6 +162,13 @@ YueParser::YueParser() {
162 ) \ 162 ) \
163 ) 163 )
164 164
165 #define disable_until_rule(patt) ( \
166 disable_until >> ( \
167 (patt) >> enable_until | \
168 enable_until >> cut \
169 ) \
170 )
171
165 #define body_with(str) ( \ 172 #define body_with(str) ( \
166 key(str) >> space >> (in_block | Statement) | \ 173 key(str) >> space >> (in_block | Statement) | \
167 in_block | \ 174 in_block | \
@@ -325,7 +332,7 @@ YueParser::YueParser() {
325 Exp; 332 Exp;
326 import_tab_list = import_tab_item >> *(space >> ',' >> space >> import_tab_item); 333 import_tab_list = import_tab_item >> *(space >> ',' >> space >> import_tab_item);
327 import_tab_line = ( 334 import_tab_line = (
328 push_indent_match >> (space >> import_tab_list >> pop_indent | pop_indent) 335 push_indent_match >> ensure(space >> import_tab_list, pop_indent)
329 ) | space; 336 ) | space;
330 import_tab_lines = space_break >> import_tab_line >> *(-(space >> ',') >> space_break >> import_tab_line) >> -(space >> ','); 337 import_tab_lines = space_break >> import_tab_line >> *(-(space >> ',') >> space_break >> import_tab_line) >> -(space >> ',');
331 import_tab_key_value = key_value | ':' >> MacroName | MacroNamePair | ImportAllMacro; 338 import_tab_key_value = key_value | ':' >> MacroName | MacroNamePair | ImportAllMacro;
@@ -342,7 +349,9 @@ YueParser::YueParser() {
342 349
343 ImportAs = ImportLiteral >> -(space >> key("as") >> space >> (ImportTabLit | Variable | ImportAllMacro)); 350 ImportAs = ImportLiteral >> -(space >> key("as") >> space >> (ImportTabLit | Variable | ImportAllMacro));
344 351
345 Import = key("import") >> space >> (ImportAs | ImportFrom) | FromImport; 352 ImportGlobal = Seperator >> UnicodeName >> *('.' >> UnicodeName) >> -(space >> key("as") >> space >> Variable);
353
354 Import = key("import") >> space >> (ImportAs | ImportFrom | ImportGlobal) | FromImport;
346 355
347 Label = "::" >> LabelName >> "::"; 356 Label = "::" >> LabelName >> "::";
348 357
@@ -350,11 +359,13 @@ YueParser::YueParser() {
350 359
351 ShortTabAppending = "[]" >> space >> Assign; 360 ShortTabAppending = "[]" >> space >> Assign;
352 361
353 BreakLoop = (expr("break") | "continue") >> not_alpha_num; 362 Break = key("break");
363 Continue = key("continue");
364 BreakLoop = (Break >> -(space >> Exp) | Continue) >> not_alpha_num;
354 365
355 Return = key("return") >> -(space >> (TableBlock | ExpListLow)); 366 Return = key("return") >> -(space >> (TableBlock | ExpListLow));
356 367
357 with_exp = ExpList >> -(space >> Assign); 368 with_exp = ExpList >> -(space >> (':' >> Assign | and_('=') >> assignment_expression_syntax_error));
358 369
359 With = key("with") >> -ExistentialOp >> space >> disable_do_chain_arg_table_block_rule(with_exp) >> space >> body_with("do"); 370 With = key("with") >> -ExistentialOp >> space >> disable_do_chain_arg_table_block_rule(with_exp) >> space >> body_with("do");
360 SwitchCase = key("when") >> space >> disable_chain_rule(disable_arg_table_block_rule(SwitchList)) >> space >> body_with("then"); 371 SwitchCase = key("when") >> space >> disable_chain_rule(disable_arg_table_block_rule(SwitchList)) >> space >> body_with("then");
@@ -370,7 +381,8 @@ YueParser::YueParser() {
370 and_(SimpleTable | TableLit) >> Exp | 381 and_(SimpleTable | TableLit) >> Exp |
371 exp_not_tab >> *(space >> ',' >> space >> exp_not_tab) 382 exp_not_tab >> *(space >> ',' >> space >> exp_not_tab)
372 ); 383 );
373 Switch = key("switch") >> space >> Exp >> 384 Switch = key("switch") >> space >>
385 Exp >> -(space >> Assignment) >>
374 space >> Seperator >> ( 386 space >> Seperator >> (
375 SwitchCase >> space >> ( 387 SwitchCase >> space >> (
376 switch_block | 388 switch_block |
@@ -379,20 +391,26 @@ YueParser::YueParser() {
379 +space_break >> advance_match >> space >> SwitchCase >> switch_block >> pop_indent 391 +space_break >> advance_match >> space >> SwitchCase >> switch_block >> pop_indent
380 ); 392 );
381 393
382 Assignment = -(',' >> space >> ExpList >> space) >> (':' >> Assign | and_('=') >> if_assignment_syntax_error); 394 Assignment = -(',' >> space >> ExpList >> space) >> (':' >> Assign | and_('=') >> assignment_expression_syntax_error);
383 IfCond = disable_chain_rule(disable_arg_table_block_rule(Exp >> -(space >> Assignment))); 395 IfCond = disable_chain_rule(disable_arg_table_block_rule(Exp >> -(space >> Assignment)));
384 if_else_if = -(line_break >> *space_break >> check_indent_match) >> space >> key("elseif") >> space >> IfCond >> space >> body_with("then"); 396 if_else_if = -(line_break >> *space_break >> check_indent_match) >> space >> key("elseif") >> space >> IfCond >> space >> body_with("then");
385 if_else = -(line_break >> *space_break >> check_indent_match) >> space >> key("else") >> space >> body; 397 if_else = -(line_break >> *space_break >> check_indent_match) >> space >> key("else") >> space >> body;
386 IfType = (expr("if") | "unless") >> not_alpha_num; 398 IfType = (expr("if") | "unless") >> not_alpha_num;
387 If = IfType >> space >> IfCond >> space >> opt_body_with("then") >> *if_else_if >> -if_else; 399 If = IfType >> space >> IfCond >> space >> opt_body_with("then") >> *if_else_if >> -if_else;
388 400
389 WhileType = (expr("while") | "until") >> not_alpha_num; 401 WhileType = (expr("while") | pl::user("until", [](const item_t& item) {
390 While = WhileType >> space >> disable_do_chain_arg_table_block_rule(Exp >> -(space >> Assignment)) >> space >> opt_body_with("do"); 402 State* st = reinterpret_cast<State*>(item.user_data);
391 Repeat = key("repeat") >> space >> Body >> line_break >> *space_break >> check_indent_match >> space >> key("until") >> space >> Exp; 403 return st->noUntilStack.empty() || !st->noUntilStack.back();
404 })) >> not_alpha_num;
405 While = key(WhileType) >> space >> disable_do_chain_arg_table_block_rule(Exp >> -(space >> Assignment)) >> space >> opt_body_with("do");
406 Repeat = key("repeat") >> space >> (
407 in_block >> line_break >> *space_break >> check_indent_match |
408 disable_until_rule(Statement)
409 ) >> space >> key("until") >> space >> Exp;
392 410
393 for_key = pl::user(key("for"), [](const item_t& item) { 411 for_key = pl::user(key("for"), [](const item_t& item) {
394 State* st = reinterpret_cast<State*>(item.user_data); 412 State* st = reinterpret_cast<State*>(item.user_data);
395 return st->noForStack.empty() || !st->noForStack.top(); 413 return st->noForStack.empty() || !st->noForStack.back();
396 }); 414 });
397 ForStepValue = ',' >> space >> Exp; 415 ForStepValue = ',' >> space >> Exp;
398 for_args = Variable >> space >> '=' >> space >> Exp >> space >> ',' >> space >> Exp >> space >> -ForStepValue; 416 for_args = Variable >> space >> '=' >> space >> Exp >> space >> ',' >> space >> Exp >> space >> -ForStepValue;
@@ -406,18 +424,18 @@ YueParser::YueParser() {
406 424
407 Do = pl::user(key("do"), [](const item_t& item) { 425 Do = pl::user(key("do"), [](const item_t& item) {
408 State* st = reinterpret_cast<State*>(item.user_data); 426 State* st = reinterpret_cast<State*>(item.user_data);
409 return st->noDoStack.empty() || !st->noDoStack.top(); 427 return st->noDoStack.empty() || !st->noDoStack.back();
410 }) >> space >> Body; 428 }) >> space >> Body;
411 429
412 disable_do = pl::user(true_(), [](const item_t& item) { 430 disable_do = pl::user(true_(), [](const item_t& item) {
413 State* st = reinterpret_cast<State*>(item.user_data); 431 State* st = reinterpret_cast<State*>(item.user_data);
414 st->noDoStack.push(true); 432 st->noDoStack.push_back(true);
415 return true; 433 return true;
416 }); 434 });
417 435
418 enable_do = pl::user(true_(), [](const item_t& item) { 436 enable_do = pl::user(true_(), [](const item_t& item) {
419 State* st = reinterpret_cast<State*>(item.user_data); 437 State* st = reinterpret_cast<State*>(item.user_data);
420 st->noDoStack.pop(); 438 st->noDoStack.pop_back();
421 return true; 439 return true;
422 }); 440 });
423 441
@@ -435,46 +453,58 @@ YueParser::YueParser() {
435 453
436 disable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) { 454 disable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) {
437 State* st = reinterpret_cast<State*>(item.user_data); 455 State* st = reinterpret_cast<State*>(item.user_data);
438 st->noDoStack.push(true); 456 st->noDoStack.push_back(true);
439 st->noChainBlockStack.push(true); 457 st->noChainBlockStack.push_back(true);
440 st->noTableBlockStack.push(true); 458 st->noTableBlockStack.push_back(true);
441 return true; 459 return true;
442 }); 460 });
443 461
444 enable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) { 462 enable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) {
445 State* st = reinterpret_cast<State*>(item.user_data); 463 State* st = reinterpret_cast<State*>(item.user_data);
446 st->noDoStack.pop(); 464 st->noDoStack.pop_back();
447 st->noChainBlockStack.pop(); 465 st->noChainBlockStack.pop_back();
448 st->noTableBlockStack.pop(); 466 st->noTableBlockStack.pop_back();
449 return true; 467 return true;
450 }); 468 });
451 469
452 disable_arg_table_block = pl::user(true_(), [](const item_t& item) { 470 disable_arg_table_block = pl::user(true_(), [](const item_t& item) {
453 State* st = reinterpret_cast<State*>(item.user_data); 471 State* st = reinterpret_cast<State*>(item.user_data);
454 st->noTableBlockStack.push(true); 472 st->noTableBlockStack.push_back(true);
455 return true; 473 return true;
456 }); 474 });
457 475
458 enable_arg_table_block = pl::user(true_(), [](const item_t& item) { 476 enable_arg_table_block = pl::user(true_(), [](const item_t& item) {
459 State* st = reinterpret_cast<State*>(item.user_data); 477 State* st = reinterpret_cast<State*>(item.user_data);
460 st->noTableBlockStack.pop(); 478 st->noTableBlockStack.pop_back();
461 return true; 479 return true;
462 }); 480 });
463 481
464 disable_for = pl::user(true_(), [](const item_t& item) { 482 disable_for = pl::user(true_(), [](const item_t& item) {
465 State* st = reinterpret_cast<State*>(item.user_data); 483 State* st = reinterpret_cast<State*>(item.user_data);
466 st->noForStack.push(true); 484 st->noForStack.push_back(true);
467 return true; 485 return true;
468 }); 486 });
469 487
470 enable_for = pl::user(true_(), [](const item_t& item) { 488 enable_for = pl::user(true_(), [](const item_t& item) {
471 State* st = reinterpret_cast<State*>(item.user_data); 489 State* st = reinterpret_cast<State*>(item.user_data);
472 st->noForStack.pop(); 490 st->noForStack.pop_back();
491 return true;
492 });
493
494 disable_until = pl::user(true_(), [](const item_t& item) {
495 State* st = reinterpret_cast<State*>(item.user_data);
496 st->noUntilStack.push_back(true);
497 return true;
498 });
499
500 enable_until = pl::user(true_(), [](const item_t& item) {
501 State* st = reinterpret_cast<State*>(item.user_data);
502 st->noUntilStack.pop_back();
473 return true; 503 return true;
474 }); 504 });
475 505
476 CatchBlock = line_break >> *space_break >> check_indent_match >> space >> key("catch") >> space >> Variable >> space >> in_block; 506 CatchBlock = line_break >> *space_break >> check_indent_match >> space >> key("catch") >> space >> Variable >> space >> in_block;
477 Try = key("try") >> space >> (in_block | Exp) >> -CatchBlock; 507 Try = key("try") >> -ExistentialOp >> space >> (in_block | Exp) >> -CatchBlock;
478 508
479 list_value = 509 list_value =
480 and_( 510 and_(
@@ -561,20 +591,20 @@ YueParser::YueParser() {
561 591
562 disable_chain = pl::user(true_(), [](const item_t& item) { 592 disable_chain = pl::user(true_(), [](const item_t& item) {
563 State* st = reinterpret_cast<State*>(item.user_data); 593 State* st = reinterpret_cast<State*>(item.user_data);
564 st->noChainBlockStack.push(true); 594 st->noChainBlockStack.push_back(true);
565 return true; 595 return true;
566 }); 596 });
567 597
568 enable_chain = pl::user(true_(), [](const item_t& item) { 598 enable_chain = pl::user(true_(), [](const item_t& item) {
569 State* st = reinterpret_cast<State*>(item.user_data); 599 State* st = reinterpret_cast<State*>(item.user_data);
570 st->noChainBlockStack.pop(); 600 st->noChainBlockStack.pop_back();
571 return true; 601 return true;
572 }); 602 });
573 603
574 chain_line = check_indent_match >> space >> (chain_dot_chain | colon_chain) >> -InvokeArgs; 604 chain_line = check_indent_match >> space >> (chain_dot_chain | colon_chain) >> -InvokeArgs;
575 chain_block = pl::user(true_(), [](const item_t& item) { 605 chain_block = pl::user(true_(), [](const item_t& item) {
576 State* st = reinterpret_cast<State*>(item.user_data); 606 State* st = reinterpret_cast<State*>(item.user_data);
577 return st->noChainBlockStack.empty() || !st->noChainBlockStack.top(); 607 return st->noChainBlockStack.empty() || !st->noChainBlockStack.back();
578 }) >> +space_break >> advance_match >> ensure( 608 }) >> +space_break >> advance_match >> ensure(
579 chain_line >> *(+space_break >> chain_line), pop_indent); 609 chain_line >> *(+space_break >> chain_line), pop_indent);
580 ChainValue = 610 ChainValue =
@@ -611,7 +641,15 @@ YueParser::YueParser() {
611 DoubleStringInner = +(not_("#{") >> double_string_plain); 641 DoubleStringInner = +(not_("#{") >> double_string_plain);
612 DoubleStringContent = DoubleStringInner | interp; 642 DoubleStringContent = DoubleStringInner | interp;
613 DoubleString = '"' >> Seperator >> *DoubleStringContent >> '"'; 643 DoubleString = '"' >> Seperator >> *DoubleStringContent >> '"';
614 String = DoubleString | SingleString | LuaString; 644
645 YAMLIndent = +set(" \t");
646 YAMLLineInner = +('\\' >> set("\"\\#") | not_("#{" | stop) >> any_char);
647 YAMLLineContent = YAMLLineInner | interp;
648 YAMLLine = check_indent_match >> YAMLIndent >> +(YAMLLineContent) |
649 advance_match >> YAMLIndent >> ensure(+YAMLLineContent, pop_indent);
650 YAMLMultiline = '|' >> space >> Seperator >> +(*set(" \t") >> line_break) >> advance_match >> ensure(YAMLLine >> *(+(*set(" \t") >> line_break) >> YAMLLine), pop_indent);
651
652 String = DoubleString | SingleString | LuaString | YAMLMultiline;
615 653
616 lua_string_open = '[' >> *expr('=') >> '['; 654 lua_string_open = '[' >> *expr('=') >> '[';
617 lua_string_close = ']' >> *expr('=') >> ']'; 655 lua_string_close = ']' >> *expr('=') >> ']';
@@ -639,7 +677,7 @@ YueParser::YueParser() {
639 fn_args_value_list = Exp >> *(space >> ',' >> space >> Exp); 677 fn_args_value_list = Exp >> *(space >> ',' >> space >> Exp);
640 678
641 fn_args_lit_line = ( 679 fn_args_lit_line = (
642 push_indent_match >> (space >> fn_args_value_list >> pop_indent | pop_indent) 680 push_indent_match >> ensure(space >> fn_args_value_list, pop_indent)
643 ) | ( 681 ) | (
644 space 682 space
645 ); 683 );
@@ -681,7 +719,8 @@ YueParser::YueParser() {
681 chain_with_colon = +chain_item >> -colon_chain; 719 chain_with_colon = +chain_item >> -colon_chain;
682 chain_items = chain_with_colon | colon_chain; 720 chain_items = chain_with_colon | colon_chain;
683 721
684 index = '[' >> not_('[') >> space >> Exp >> space >> ']'; 722 index = '[' >> not_('[') >> space >> (ReversedIndex >> and_(space >> ']') | Exp) >> space >> ']';
723 ReversedIndex = '#' >> space >> -('-' >> space >> Exp);
685 chain_item = 724 chain_item =
686 Invoke >> -ExistentialOp | 725 Invoke >> -ExistentialOp |
687 DotChainItem >> -ExistentialOp | 726 DotChainItem >> -ExistentialOp |
@@ -738,7 +777,7 @@ YueParser::YueParser() {
738 777
739 table_block_inner = Seperator >> key_value_line >> *(+space_break >> key_value_line); 778 table_block_inner = Seperator >> key_value_line >> *(+space_break >> key_value_line);
740 TableBlock = +space_break >> advance_match >> ensure(table_block_inner, pop_indent); 779 TableBlock = +space_break >> advance_match >> ensure(table_block_inner, pop_indent);
741 TableBlockIndent = '*' >> Seperator >> disable_arg_table_block_rule( 780 TableBlockIndent = ('*' | '-' >> space_one) >> Seperator >> disable_arg_table_block_rule(
742 space >> key_value_list >> -(space >> ',') >> 781 space >> key_value_list >> -(space >> ',') >>
743 -(+space_break >> advance_match >> space >> ensure(key_value_list >> -(space >> ',') >> *(+space_break >> key_value_line), pop_indent))); 782 -(+space_break >> advance_match >> space >> ensure(key_value_list >> -(space >> ',') >> *(+space_break >> key_value_line), pop_indent)));
744 783
@@ -759,7 +798,7 @@ YueParser::YueParser() {
759 798
760 GlobalValues = NameList >> -(space >> '=' >> space >> (TableBlock | ExpListLow)); 799 GlobalValues = NameList >> -(space >> '=' >> space >> (TableBlock | ExpListLow));
761 GlobalOp = expr('*') | '^'; 800 GlobalOp = expr('*') | '^';
762 Global = key("global") >> space >> (ClassDecl | GlobalOp | GlobalValues); 801 Global = key("global") >> space >> (-(ConstAttrib >> space) >> ClassDecl | GlobalOp | -(ConstAttrib >> space) >> GlobalValues);
763 802
764 ExportDefault = key("default"); 803 ExportDefault = key("default");
765 804
@@ -841,24 +880,24 @@ YueParser::YueParser() {
841 key_value_line = check_indent_match >> space >> ( 880 key_value_line = check_indent_match >> space >> (
842 key_value_list >> -(space >> ',') | 881 key_value_list >> -(space >> ',') |
843 TableBlockIndent | 882 TableBlockIndent |
844 '*' >> space >> (SpreadExp | Exp | TableBlock) 883 ('*' | '-' >> space_one) >> space >> (SpreadExp | Exp | TableBlock)
845 ); 884 );
846 885
847 fn_arg_def_list = FnArgDef >> *(space >> ',' >> space >> FnArgDef); 886 fn_arg_def_list = FnArgDef >> *(space >> ',' >> space >> FnArgDef);
848 887
849 fn_arg_def_lit_line = ( 888 fn_arg_def_lit_line = (
850 push_indent_match >> (space >> fn_arg_def_list >> pop_indent | pop_indent) 889 push_indent_match >> ensure(space >> fn_arg_def_list, pop_indent)
851 ) | ( 890 ) | (
852 space 891 space
853 ); 892 );
854 893
855 fn_arg_def_lit_lines = fn_arg_def_lit_line >> *(-(space >> ',') >> space_break >> fn_arg_def_lit_line); 894 fn_arg_def_lit_lines = fn_arg_def_lit_line >> *(-(space >> ',') >> space_break >> fn_arg_def_lit_line);
856 895
857 FnArgDef = (Variable | SelfItem >> -ExistentialOp) >> -(space >> '=' >> space >> Exp); 896 FnArgDef = (Variable | SelfItem >> -ExistentialOp) >> -(space >> '`' >> space >> Name) >> -(space >> '=' >> space >> Exp) | TableLit | SimpleTable;
858 897
859 FnArgDefList = Seperator >> ( 898 FnArgDefList = Seperator >> (
860 fn_arg_def_lit_lines >> -(-(space >> ',') >> white >> VarArg) | 899 fn_arg_def_lit_lines >> -(-(space >> ',') >> white >> VarArg >> -(space >> '`' >> space >> Name)) |
861 white >> VarArg 900 white >> VarArg >> -(space >> '`' >> space >> Name)
862 ); 901 );
863 902
864 OuterVarShadow = key("using") >> space >> (NameList | key("nil")); 903 OuterVarShadow = key("using") >> space >> (NameList | key("nil"));
@@ -887,6 +926,7 @@ YueParser::YueParser() {
887 926
888 FnArrowBack = '<' >> set("-="); 927 FnArrowBack = '<' >> set("-=");
889 Backcall = -(FnArgsDef >> space) >> FnArrowBack >> space >> ChainValue; 928 Backcall = -(FnArgsDef >> space) >> FnArrowBack >> space >> ChainValue;
929 SubBackcall = FnArrowBack >> space >> ChainValue;
890 930
891 PipeBody = Seperator >> 931 PipeBody = Seperator >>
892 pipe_operator >> space >> UnaryExp >> 932 pipe_operator >> space >> UnaryExp >>
@@ -900,7 +940,7 @@ YueParser::YueParser() {
900 940
901 arg_table_block = pl::user(true_(), [](const item_t& item) { 941 arg_table_block = pl::user(true_(), [](const item_t& item) {
902 State* st = reinterpret_cast<State*>(item.user_data); 942 State* st = reinterpret_cast<State*>(item.user_data);
903 return st->noTableBlockStack.empty() || !st->noTableBlockStack.top(); 943 return st->noTableBlockStack.empty() || !st->noTableBlockStack.back();
904 }) >> TableBlock; 944 }) >> TableBlock;
905 945
906 invoke_args_with_table = 946 invoke_args_with_table =
@@ -940,11 +980,11 @@ YueParser::YueParser() {
940 980
941 SimpleValue = 981 SimpleValue =
942 TableLit | ConstValue | If | Switch | Try | With | 982 TableLit | ConstValue | If | Switch | Try | With |
943 ClassDecl | ForEach | For | While | Do | 983 ClassDecl | ForEach | For | While | Repeat | Do |
944 UnaryValue | TblComprehension | Comprehension | 984 UnaryValue | TblComprehension | Comprehension |
945 FunLit | Num | VarArg; 985 FunLit | Num | VarArg;
946 986
947 ExpListAssign = ExpList >> -(space >> (Update | Assign)) >> not_(space >> '='); 987 ExpListAssign = ExpList >> -(space >> (Update | Assign | SubBackcall)) >> not_(space >> '=');
948 988
949 IfLine = IfType >> space >> IfCond; 989 IfLine = IfType >> space >> IfCond;
950 WhileLine = WhileType >> space >> Exp; 990 WhileLine = WhileType >> space >> Exp;
@@ -1001,11 +1041,16 @@ YueParser::YueParser() {
1001 empty_line_break | 1041 empty_line_break |
1002 advance_match >> ensure(space >> (indentation_error | Statement), pop_indent) 1042 advance_match >> ensure(space >> (indentation_error | Statement), pop_indent)
1003 ); 1043 );
1004 Block = Seperator >> line >> *(+line_break >> line); 1044 Block = Seperator >> (pl::user(true_(), [](const item_t& item) {
1045 State* st = reinterpret_cast<State*>(item.user_data);
1046 return st->lax;
1047 }) >> lax_line >> *(+line_break >> lax_line) | line >> *(+line_break >> line));
1005 1048
1006 shebang = "#!" >> *(not_(stop) >> any_char); 1049 shebang = "#!" >> *(not_(stop) >> any_char);
1007 BlockEnd = Block >> white >> stop; 1050 BlockEnd = Block >> white >> stop;
1008 File = -shebang >> -Block >> white >> stop; 1051 File = -shebang >> -Block >> white >> stop;
1052
1053 lax_line = advance_match >> ensure(*(not_(stop) >> any()), pop_indent) | line >> and_(stop) | check_indent_match >> *(not_(stop) >> any());
1009} 1054}
1010// clang-format on 1055// clang-format on
1011 1056
@@ -1035,7 +1080,7 @@ bool YueParser::startWith(std::string_view codes, rule& r) {
1035 return true; 1080 return true;
1036} 1081}
1037 1082
1038ParseInfo YueParser::parse(std::string_view codes, rule& r) { 1083ParseInfo YueParser::parse(std::string_view codes, rule& r, bool lax) {
1039 ParseInfo res; 1084 ParseInfo res;
1040 if (codes.substr(0, 3) == "\xEF\xBB\xBF"sv) { 1085 if (codes.substr(0, 3) == "\xEF\xBB\xBF"sv) {
1041 codes = codes.substr(3); 1086 codes = codes.substr(3);
@@ -1053,6 +1098,7 @@ ParseInfo YueParser::parse(std::string_view codes, rule& r) {
1053 error_list errors; 1098 error_list errors;
1054 try { 1099 try {
1055 State state; 1100 State state;
1101 state.lax = lax;
1056 res.node.set(::yue::parse(*(res.codes), r, errors, &state)); 1102 res.node.set(::yue::parse(*(res.codes), r, errors, &state));
1057 if (state.exportCount > 0) { 1103 if (state.exportCount > 0) {
1058 int index = 0; 1104 int index = 0;
@@ -1090,19 +1136,21 @@ ParseInfo YueParser::parse(std::string_view codes, rule& r) {
1090 return res; 1136 return res;
1091} 1137}
1092 1138
1093ParseInfo YueParser::parse(std::string_view astName, std::string_view codes) { 1139ParseInfo YueParser::parse(std::string_view astName, std::string_view codes, bool lax) {
1094 auto it = _rules.find(astName); 1140 auto it = _rules.find(astName);
1095 if (it != _rules.end()) { 1141 if (it != _rules.end()) {
1096 return parse(codes, *it->second); 1142 return parse(codes, *it->second, lax);
1097 } 1143 }
1098 return {}; 1144 ParseInfo info{};
1145 info.error = ParseInfo::Error{"invalid rule: "s + std::string{astName}, 1, 1};
1146 return info;
1099} 1147}
1100 1148
1101bool YueParser::match(std::string_view astName, std::string_view codes) { 1149bool YueParser::match(std::string_view astName, std::string_view codes) {
1102 auto it = _rules.find(astName); 1150 auto it = _rules.find(astName);
1103 if (it != _rules.end()) { 1151 if (it != _rules.end()) {
1104 auto rEnd = rule(*it->second >> eof()); 1152 auto rEnd = rule(*it->second >> eof());
1105 return parse(codes, rEnd).node; 1153 return parse(codes, rEnd, false).node;
1106 } 1154 }
1107 return false; 1155 return false;
1108} 1156}
@@ -1138,6 +1186,24 @@ void trim(std::string& str) {
1138 str.erase(0, str.find_first_not_of(" \t\r\n")); 1186 str.erase(0, str.find_first_not_of(" \t\r\n"));
1139 str.erase(str.find_last_not_of(" \t\r\n") + 1); 1187 str.erase(str.find_last_not_of(" \t\r\n") + 1);
1140} 1188}
1189
1190std::string toLuaDoubleString(const std::string& input) {
1191 std::string luaStr = "\"";
1192 for (char c : input) {
1193 switch (c) {
1194 case '\"': luaStr += "\\\""; break;
1195 case '\\': luaStr += "\\\\"; break;
1196 case '\n': luaStr += "\\n"; break;
1197 case '\r': luaStr += "\\r"; break;
1198 case '\t': luaStr += "\\t"; break;
1199 default:
1200 luaStr += c;
1201 break;
1202 }
1203 }
1204 luaStr += "\"";
1205 return luaStr;
1206}
1141} // namespace Utils 1207} // namespace Utils
1142 1208
1143std::string ParseInfo::errorMessage(std::string_view msg, int errLine, int errCol, int lineOffset) const { 1209std::string ParseInfo::errorMessage(std::string_view msg, int errLine, int errCol, int lineOffset) const {
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h
index 7281ec3..c91e530 100644
--- a/src/yuescript/yue_parser.h
+++ b/src/yuescript/yue_parser.h
@@ -74,16 +74,16 @@ extern std::unordered_set<std::string> Keywords;
74class YueParser { 74class YueParser {
75public: 75public:
76 template <class AST> 76 template <class AST>
77 ParseInfo parse(std::string_view codes) { 77 ParseInfo parse(std::string_view codes, bool lax) {
78 return parse(codes, getRule<AST>()); 78 return parse(codes, getRule<AST>(), lax);
79 } 79 }
80 80
81 ParseInfo parse(std::string_view astName, std::string_view codes); 81 ParseInfo parse(std::string_view astName, std::string_view codes, bool lax);
82 82
83 template <class AST> 83 template <class AST>
84 bool match(std::string_view codes) { 84 bool match(std::string_view codes) {
85 auto rEnd = rule(getRule<AST>() >> eof()); 85 auto rEnd = rule(getRule<AST>() >> eof());
86 return parse(codes, rEnd).node; 86 return parse(codes, rEnd, false).node;
87 } 87 }
88 88
89 bool match(std::string_view astName, std::string_view codes); 89 bool match(std::string_view astName, std::string_view codes);
@@ -102,13 +102,14 @@ public:
102 102
103protected: 103protected:
104 YueParser(); 104 YueParser();
105 ParseInfo parse(std::string_view codes, rule& r); 105 ParseInfo parse(std::string_view codes, rule& r, bool lax);
106 bool startWith(std::string_view codes, rule& r); 106 bool startWith(std::string_view codes, rule& r);
107 107
108 struct State { 108 struct State {
109 State() { 109 State() {
110 indents.push(0); 110 indents.push(0);
111 } 111 }
112 bool lax = false;
112 bool exportDefault = false; 113 bool exportDefault = false;
113 bool exportMacro = false; 114 bool exportMacro = false;
114 bool exportMetatable = false; 115 bool exportMetatable = false;
@@ -119,10 +120,11 @@ protected:
119 size_t stringOpen = 0; 120 size_t stringOpen = 0;
120 std::string buffer; 121 std::string buffer;
121 std::stack<int> indents; 122 std::stack<int> indents;
122 std::stack<bool> noDoStack; 123 std::vector<bool> noDoStack;
123 std::stack<bool> noChainBlockStack; 124 std::vector<bool> noChainBlockStack;
124 std::stack<bool> noTableBlockStack; 125 std::vector<bool> noTableBlockStack;
125 std::stack<bool> noForStack; 126 std::vector<bool> noForStack;
127 std::vector<bool> noUntilStack;
126 std::unordered_set<std::string> usedNames; 128 std::unordered_set<std::string> usedNames;
127 }; 129 };
128 130
@@ -156,7 +158,7 @@ private:
156 NONE_AST_RULE(invalid_interpolation_error); 158 NONE_AST_RULE(invalid_interpolation_error);
157 NONE_AST_RULE(confusing_unary_not_error); 159 NONE_AST_RULE(confusing_unary_not_error);
158 NONE_AST_RULE(table_key_pair_error); 160 NONE_AST_RULE(table_key_pair_error);
159 NONE_AST_RULE(if_assignment_syntax_error); 161 NONE_AST_RULE(assignment_expression_syntax_error);
160 162
161 NONE_AST_RULE(inc_exp_level); 163 NONE_AST_RULE(inc_exp_level);
162 NONE_AST_RULE(dec_exp_level); 164 NONE_AST_RULE(dec_exp_level);
@@ -217,6 +219,8 @@ private:
217 NONE_AST_RULE(enable_for); 219 NONE_AST_RULE(enable_for);
218 NONE_AST_RULE(enable_fun_lit); 220 NONE_AST_RULE(enable_fun_lit);
219 NONE_AST_RULE(disable_fun_lit); 221 NONE_AST_RULE(disable_fun_lit);
222 NONE_AST_RULE(disable_until);
223 NONE_AST_RULE(enable_until);
220 NONE_AST_RULE(switch_else); 224 NONE_AST_RULE(switch_else);
221 NONE_AST_RULE(switch_block); 225 NONE_AST_RULE(switch_block);
222 NONE_AST_RULE(if_else_if); 226 NONE_AST_RULE(if_else_if);
@@ -284,6 +288,7 @@ private:
284 NONE_AST_RULE(yue_line_comment); 288 NONE_AST_RULE(yue_line_comment);
285 NONE_AST_RULE(line); 289 NONE_AST_RULE(line);
286 NONE_AST_RULE(shebang); 290 NONE_AST_RULE(shebang);
291 NONE_AST_RULE(lax_line);
287 292
288 AST_RULE(Num); 293 AST_RULE(Num);
289 AST_RULE(Name); 294 AST_RULE(Name);
@@ -315,12 +320,14 @@ private:
315 AST_RULE(ImportAllMacro); 320 AST_RULE(ImportAllMacro);
316 AST_RULE(ImportTabLit); 321 AST_RULE(ImportTabLit);
317 AST_RULE(ImportAs); 322 AST_RULE(ImportAs);
323 AST_RULE(ImportGlobal);
318 AST_RULE(Import); 324 AST_RULE(Import);
319 AST_RULE(Label); 325 AST_RULE(Label);
320 AST_RULE(Goto); 326 AST_RULE(Goto);
321 AST_RULE(ShortTabAppending); 327 AST_RULE(ShortTabAppending);
322 AST_RULE(FnArrowBack); 328 AST_RULE(FnArrowBack);
323 AST_RULE(Backcall); 329 AST_RULE(Backcall);
330 AST_RULE(SubBackcall);
324 AST_RULE(PipeBody); 331 AST_RULE(PipeBody);
325 AST_RULE(ExpListLow); 332 AST_RULE(ExpListLow);
326 AST_RULE(ExpList); 333 AST_RULE(ExpList);
@@ -359,6 +366,7 @@ private:
359 AST_RULE(ExpOpValue); 366 AST_RULE(ExpOpValue);
360 AST_RULE(Exp); 367 AST_RULE(Exp);
361 AST_RULE(Callable); 368 AST_RULE(Callable);
369 AST_RULE(ReversedIndex);
362 AST_RULE(ChainValue); 370 AST_RULE(ChainValue);
363 AST_RULE(SimpleTable); 371 AST_RULE(SimpleTable);
364 AST_RULE(SimpleValue); 372 AST_RULE(SimpleValue);
@@ -371,6 +379,11 @@ private:
371 AST_RULE(DoubleStringInner); 379 AST_RULE(DoubleStringInner);
372 AST_RULE(DoubleStringContent); 380 AST_RULE(DoubleStringContent);
373 AST_RULE(DoubleString); 381 AST_RULE(DoubleString);
382 AST_RULE(YAMLIndent);
383 AST_RULE(YAMLLineInner);
384 AST_RULE(YAMLLineContent);
385 AST_RULE(YAMLLine);
386 AST_RULE(YAMLMultiline);
374 AST_RULE(String); 387 AST_RULE(String);
375 AST_RULE(Parens); 388 AST_RULE(Parens);
376 AST_RULE(DotChainItem); 389 AST_RULE(DotChainItem);
@@ -427,6 +440,8 @@ private:
427 AST_RULE(ExpListAssign); 440 AST_RULE(ExpListAssign);
428 AST_RULE(IfLine); 441 AST_RULE(IfLine);
429 AST_RULE(WhileLine); 442 AST_RULE(WhileLine);
443 AST_RULE(Break);
444 AST_RULE(Continue);
430 AST_RULE(BreakLoop); 445 AST_RULE(BreakLoop);
431 AST_RULE(StatementAppendix); 446 AST_RULE(StatementAppendix);
432 AST_RULE(Statement); 447 AST_RULE(Statement);
@@ -444,6 +459,7 @@ private:
444namespace Utils { 459namespace Utils {
445void replace(std::string& str, std::string_view from, std::string_view to); 460void replace(std::string& str, std::string_view from, std::string_view to);
446void trim(std::string& str); 461void trim(std::string& str);
462std::string toLuaDoubleString(const std::string& input);
447} // namespace Utils 463} // namespace Utils
448 464
449} // namespace yue 465} // namespace yue
diff --git a/src/yuescript/yuescript.cpp b/src/yuescript/yuescript.cpp
index 7e8e8b7..61e3949 100644
--- a/src/yuescript/yuescript.cpp
+++ b/src/yuescript/yuescript.cpp
@@ -93,6 +93,12 @@ static void get_config(lua_State* L, yue::YueConfig& config) {
93 config.useSpaceOverTab = lua_toboolean(L, -1) != 0; 93 config.useSpaceOverTab = lua_toboolean(L, -1) != 0;
94 } 94 }
95 lua_pop(L, 1); 95 lua_pop(L, 1);
96 lua_pushliteral(L, "lax");
97 lua_gettable(L, -2);
98 if (lua_isboolean(L, -1) != 0) {
99 config.lax = lua_toboolean(L, -1) != 0;
100 }
101 lua_pop(L, 1);
96 lua_pushliteral(L, "options"); 102 lua_pushliteral(L, "options");
97 lua_gettable(L, -2); 103 lua_gettable(L, -2);
98 if (lua_istable(L, -1) != 0) { 104 if (lua_istable(L, -1) != 0) {
@@ -180,7 +186,7 @@ static int yueformat(lua_State* L) {
180 tabSize = static_cast<int>(luaL_checkinteger(L, 2)); 186 tabSize = static_cast<int>(luaL_checkinteger(L, 2));
181 } 187 }
182 std::string_view codes(input, len); 188 std::string_view codes(input, len);
183 auto info = yue::YueParser::shared().parse<yue::File_t>(codes); 189 auto info = yue::YueParser::shared().parse<yue::File_t>(codes, false);
184 if (info.error) { 190 if (info.error) {
185 const auto& error = info.error.value(); 191 const auto& error = info.error.value();
186 if (!info.codes) { 192 if (!info.codes) {
@@ -201,6 +207,7 @@ static int yueformat(lua_State* L) {
201 formatter.spaceOverTab = false; 207 formatter.spaceOverTab = false;
202 } 208 }
203 auto result = formatter.toString(info.node.get()); 209 auto result = formatter.toString(info.node.get());
210 yue::Utils::replace(result, "\n\n", "\n");
204 lua_pushlstring(L, result.c_str(), result.size()); 211 lua_pushlstring(L, result.c_str(), result.size());
205 return 1; 212 return 1;
206} 213}
@@ -282,8 +289,13 @@ static int yuetoast(lua_State* L) {
282 ruleName = {name, nameSize}; 289 ruleName = {name, nameSize};
283 } 290 }
284 } 291 }
292 bool lax = false;
293 if (!lua_isnoneornil(L, 4)) {
294 luaL_checktype(L, 4, LUA_TBOOLEAN);
295 lax = lua_toboolean(L, 4) != 0;
296 }
285 auto& yueParser = yue::YueParser::shared(); 297 auto& yueParser = yue::YueParser::shared();
286 auto info = ruleName.empty() ? yueParser.parse<yue::File_t>({input, size}) : yueParser.parse(ruleName, {input, size}); 298 auto info = ruleName.empty() ? yueParser.parse<yue::File_t>({input, size}, lax) : yueParser.parse(ruleName, {input, size}, lax);
287 if (!info.error) { 299 if (!info.error) {
288 lua_createtable(L, 0, 0); 300 lua_createtable(L, 0, 0);
289 int tableIndex = lua_gettop(L); 301 int tableIndex = lua_gettop(L);
diff --git a/win-build/Yuescript/Yuescript.vcxproj b/win-build/Yuescript/Yuescript.vcxproj
index d073e70..87e13ce 100644
--- a/win-build/Yuescript/Yuescript.vcxproj
+++ b/win-build/Yuescript/Yuescript.vcxproj
@@ -215,6 +215,7 @@
215 <Link> 215 <Link>
216 <SubSystem>Console</SubSystem> 216 <SubSystem>Console</SubSystem>
217 <GenerateDebugInformation>true</GenerateDebugInformation> 217 <GenerateDebugInformation>true</GenerateDebugInformation>
218 <AdditionalOptions>/STACK:2097152 %(AdditionalOptions)</AdditionalOptions>
218 </Link> 219 </Link>
219 </ItemDefinitionGroup> 220 </ItemDefinitionGroup>
220 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug53|x64'"> 221 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Debug53|x64'">
@@ -230,6 +231,7 @@
230 <Link> 231 <Link>
231 <SubSystem>Console</SubSystem> 232 <SubSystem>Console</SubSystem>
232 <GenerateDebugInformation>true</GenerateDebugInformation> 233 <GenerateDebugInformation>true</GenerateDebugInformation>
234 <AdditionalOptions>/STACK:2097152 %(AdditionalOptions)</AdditionalOptions>
233 </Link> 235 </Link>
234 </ItemDefinitionGroup> 236 </ItemDefinitionGroup>
235 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'"> 237 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release|Win32'">
@@ -287,6 +289,7 @@
287 <EnableCOMDATFolding>true</EnableCOMDATFolding> 289 <EnableCOMDATFolding>true</EnableCOMDATFolding>
288 <OptimizeReferences>true</OptimizeReferences> 290 <OptimizeReferences>true</OptimizeReferences>
289 <GenerateDebugInformation>true</GenerateDebugInformation> 291 <GenerateDebugInformation>true</GenerateDebugInformation>
292 <AdditionalOptions>/STACK:2097152 %(AdditionalOptions)</AdditionalOptions>
290 </Link> 293 </Link>
291 </ItemDefinitionGroup> 294 </ItemDefinitionGroup>
292 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release53|x64'"> 295 <ItemDefinitionGroup Condition="'$(Configuration)|$(Platform)'=='Release53|x64'">
@@ -306,6 +309,7 @@
306 <EnableCOMDATFolding>true</EnableCOMDATFolding> 309 <EnableCOMDATFolding>true</EnableCOMDATFolding>
307 <OptimizeReferences>true</OptimizeReferences> 310 <OptimizeReferences>true</OptimizeReferences>
308 <GenerateDebugInformation>true</GenerateDebugInformation> 311 <GenerateDebugInformation>true</GenerateDebugInformation>
312 <AdditionalOptions>/STACK:2097152 %(AdditionalOptions)</AdditionalOptions>
309 </Link> 313 </Link>
310 </ItemDefinitionGroup> 314 </ItemDefinitionGroup>
311 <ItemGroup> 315 <ItemGroup>