aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/macos.yml2
-rw-r--r--CMakeLists.txt170
-rw-r--r--LICENSE2
-rwxr-xr-xdoc/docs/.vuepress/components/YueCompiler.vue83
-rwxr-xr-xdoc/docs/README.md2
-rwxr-xr-xdoc/docs/doc/README.md744
-rwxr-xr-xdoc/docs/zh/README.md2
-rwxr-xr-xdoc/docs/zh/doc/README.md923
-rw-r--r--makefile59
-rw-r--r--spec/inputs/destructure.yue50
-rw-r--r--spec/inputs/funcs.yue33
-rw-r--r--spec/inputs/import.yue12
-rw-r--r--spec/inputs/lists.yue190
-rw-r--r--spec/inputs/loops.yue15
-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.yue71
-rw-r--r--spec/inputs/syntax.yue12
-rw-r--r--spec/inputs/tables.yue18
-rw-r--r--spec/inputs/test/format_spec.yue2
-rw-r--r--spec/inputs/try_catch.yue122
-rw-r--r--spec/inputs/unicode/destructure.yue2
-rw-r--r--spec/inputs/unicode/funcs.yue2
-rw-r--r--spec/inputs/unicode/import.yue2
-rw-r--r--spec/inputs/unicode/macro_export.yue4
-rw-r--r--spec/inputs/unicode/syntax.yue4
-rw-r--r--spec/inputs/unicode/vararg.yue4
-rw-r--r--spec/inputs/unicode/with.yue24
-rw-r--r--spec/inputs/vararg.yue48
-rw-r--r--spec/inputs/with.yue33
-rw-r--r--spec/outputs/5.1/loops.lua28
-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.lua665
-rw-r--r--spec/outputs/codes_from_doc_zh.lua665
-rw-r--r--spec/outputs/comprehension.lua10
-rw-r--r--spec/outputs/destructure.lua110
-rw-r--r--spec/outputs/funcs.lua153
-rw-r--r--spec/outputs/import.lua10
-rw-r--r--spec/outputs/lists.lua594
-rw-r--r--spec/outputs/loops.lua28
-rw-r--r--spec/outputs/macro.lua13
-rw-r--r--spec/outputs/props.lua240
-rw-r--r--spec/outputs/string.lua41
-rw-r--r--spec/outputs/switch.lua121
-rw-r--r--spec/outputs/syntax.lua11
-rw-r--r--spec/outputs/tables.lua22
-rw-r--r--spec/outputs/test/format_spec.lua2
-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/funcs.lua2
-rw-r--r--spec/outputs/unicode/import.lua4
-rw-r--r--spec/outputs/unicode/lists.lua23
-rw-r--r--spec/outputs/unicode/macro.lua46
-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.lua100
-rw-r--r--spec/outputs/with.lua51
-rwxr-xr-xsrc/3rdParty/colib/LICENSE21
-rw-r--r--src/3rdParty/colib/ljson.c925
-rwxr-xr-xsrc/3rdParty/utf8cpp.h1277
-rw-r--r--src/yue.cpp45
-rw-r--r--src/yue_wasm.cpp2
-rw-r--r--src/yuescript/parser.cpp29
-rw-r--r--src/yuescript/parser.hpp7
-rw-r--r--src/yuescript/yue_ast.cpp264
-rw-r--r--src/yuescript/yue_ast.h159
-rw-r--r--src/yuescript/yue_compiler.cpp2037
-rw-r--r--src/yuescript/yue_compiler.h4
-rw-r--r--src/yuescript/yue_parser.cpp683
-rw-r--r--src/yuescript/yue_parser.h84
-rw-r--r--src/yuescript/yuescript.cpp41
-rw-r--r--win-build/Lua53/Lua53.vcxproj120
-rw-r--r--win-build/Lua53/Lua53.vcxproj.filters120
-rw-r--r--win-build/Yuescript/Yuescript.vcxproj53
-rw-r--r--win-build/Yuescript/Yuescript.vcxproj.filters6
-rw-r--r--win-build/YuescriptDLL/YuescriptDLL.vcxproj34
84 files changed, 10518 insertions, 1847 deletions
diff --git a/.github/workflows/macos.yml b/.github/workflows/macos.yml
index 6dede90..ddfcd2f 100644
--- a/.github/workflows/macos.yml
+++ b/.github/workflows/macos.yml
@@ -22,7 +22,7 @@ jobs:
22 sudo luarocks make 22 sudo luarocks make
23 make test 23 make test
24 - name: luarocks upload 24 - name: luarocks upload
25 if: startsWith(github.ref, 'refs/tags/') 25 if: startsWith(github.ref, 'refs/tags/') && !contains(github.event.head_commit.message, '[skip Upload]')
26 run: | 26 run: |
27 ./yue -e spec/inputs/luarocks_upload.yue ${{ secrets.LUAROCKS_KEY }} 27 ./yue -e spec/inputs/luarocks_upload.yue ${{ secrets.LUAROCKS_KEY }}
28 - name: build for luajit 28 - name: build for luajit
diff --git a/CMakeLists.txt b/CMakeLists.txt
index 613019e..5c03f23 100644
--- a/CMakeLists.txt
+++ b/CMakeLists.txt
@@ -44,19 +44,33 @@ if (LUA_LIBRARIES MATCHES "LUA_LIBRARIES-NOTFOUND")
44 endif() 44 endif()
45else () 45else ()
46 message(STATUS "Lua: using information from luarocks") 46 message(STATUS "Lua: using information from luarocks")
47endif() 47endif()
48 48
49message(STATUS "Lua: " ${LUA}) 49message(STATUS "Lua: " ${LUA})
50message(STATUS "Lua include: " ${LUA_INCLUDE_DIR}) 50message(STATUS "Lua include: " ${LUA_INCLUDE_DIR})
51message(STATUS "Lua library: ${LUA_LIBRARIES}") 51message(STATUS "Lua library: ${LUA_LIBRARIES}")
52 52
53enable_language(CXX) 53enable_language(C CXX)
54include_directories(src src/3rdParty ${LUA_INCLUDE_DIR}) 54include_directories(src src/3rdParty ${LUA_INCLUDE_DIR})
55add_definitions(-std=c++17 -O3 -fPIC) 55add_definitions(-std=c++17 -O3 -fPIC -DYUE_UTF8_IMPL)
56 56
57if (APPLE) 57# Detect Android Termux environment
58 add_compile_options(-Wno-deprecated-declarations) 58# Termux typically has ANDROID_ROOT environment variable set and PREFIX points to Termux directory
59endif () 59set(IS_TERMUX FALSE)
60if (DEFINED ENV{ANDROID_ROOT})
61 # Check if PREFIX environment variable points to Termux directory
62 if (DEFINED ENV{PREFIX})
63 if ("$ENV{PREFIX}" MATCHES "com.termux")
64 set(IS_TERMUX TRUE)
65 message(STATUS "Detected Android Termux environment (via PREFIX: $ENV{PREFIX})")
66 endif()
67 endif()
68 # Alternative check: verify if Termux installation path exists
69 if (NOT IS_TERMUX AND EXISTS "/data/data/com.termux/files/usr")
70 set(IS_TERMUX TRUE)
71 message(STATUS "Detected Android Termux environment (via filesystem check)")
72 endif()
73endif()
60 74
61add_library(libyue MODULE 75add_library(libyue MODULE
62 src/yuescript/ast.cpp 76 src/yuescript/ast.cpp
@@ -70,6 +84,11 @@ set_target_properties(libyue PROPERTIES PREFIX "")
70set_target_properties(libyue PROPERTIES OUTPUT_NAME "yue") 84set_target_properties(libyue PROPERTIES OUTPUT_NAME "yue")
71target_link_libraries(libyue ${LUA_LIBRARIES}) 85target_link_libraries(libyue ${LUA_LIBRARIES})
72 86
87# Add YUE_NO_WATCHER macro for Termux environment
88if (IS_TERMUX)
89 target_compile_definitions(libyue PRIVATE YUE_NO_WATCHER)
90endif()
91
73add_executable(yue 92add_executable(yue
74 src/yuescript/ast.cpp 93 src/yuescript/ast.cpp
75 src/yuescript/parser.cpp 94 src/yuescript/parser.cpp
@@ -78,80 +97,92 @@ add_executable(yue
78 src/yuescript/yue_compiler.cpp 97 src/yuescript/yue_compiler.cpp
79 src/yuescript/yuescript.cpp 98 src/yuescript/yuescript.cpp
80 src/yue.cpp 99 src/yue.cpp
100 src/3rdParty/colib/ljson.c
81) 101)
82 102
83target_sources(yue PRIVATE 103# Add efsw sources only if not in Termux environment
84 src/3rdParty/efsw/Debug.cpp 104if (NOT IS_TERMUX)
85 src/3rdParty/efsw/DirectorySnapshot.cpp
86 src/3rdParty/efsw/DirectorySnapshotDiff.cpp
87 src/3rdParty/efsw/DirWatcherGeneric.cpp
88 src/3rdParty/efsw/FileInfo.cpp
89 src/3rdParty/efsw/FileSystem.cpp
90 src/3rdParty/efsw/FileWatcher.cpp
91 src/3rdParty/efsw/FileWatcherCWrapper.cpp
92 src/3rdParty/efsw/FileWatcherGeneric.cpp
93 src/3rdParty/efsw/FileWatcherImpl.cpp
94 src/3rdParty/efsw/Log.cpp
95 src/3rdParty/efsw/Mutex.cpp
96 src/3rdParty/efsw/String.cpp
97 src/3rdParty/efsw/System.cpp
98 src/3rdParty/efsw/Thread.cpp
99 src/3rdParty/efsw/Watcher.cpp
100 src/3rdParty/efsw/WatcherGeneric.cpp
101)
102
103if (WIN32)
104 target_sources(yue PRIVATE
105 src/3rdParty/efsw/platform/win/FileSystemImpl.cpp
106 src/3rdParty/efsw/platform/win/MutexImpl.cpp
107 src/3rdParty/efsw/platform/win/SystemImpl.cpp
108 src/3rdParty/efsw/platform/win/ThreadImpl.cpp
109 )
110else ()
111 target_sources(yue PRIVATE
112 src/3rdParty/efsw/platform/posix/FileSystemImpl.cpp
113 src/3rdParty/efsw/platform/posix/MutexImpl.cpp
114 src/3rdParty/efsw/platform/posix/SystemImpl.cpp
115 src/3rdParty/efsw/platform/posix/ThreadImpl.cpp
116 )
117endif()
118
119if (APPLE)
120 target_sources(yue PRIVATE 105 target_sources(yue PRIVATE
121 src/3rdParty/efsw/FileWatcherFSEvents.cpp 106 src/3rdParty/efsw/Debug.cpp
122 src/3rdParty/efsw/FileWatcherKqueue.cpp 107 src/3rdParty/efsw/DirectorySnapshot.cpp
123 src/3rdParty/efsw/WatcherFSEvents.cpp 108 src/3rdParty/efsw/DirectorySnapshotDiff.cpp
124 src/3rdParty/efsw/WatcherKqueue.cpp 109 src/3rdParty/efsw/DirWatcherGeneric.cpp
110 src/3rdParty/efsw/FileInfo.cpp
111 src/3rdParty/efsw/FileSystem.cpp
112 src/3rdParty/efsw/FileWatcher.cpp
113 src/3rdParty/efsw/FileWatcherCWrapper.cpp
114 src/3rdParty/efsw/FileWatcherGeneric.cpp
115 src/3rdParty/efsw/FileWatcherImpl.cpp
116 src/3rdParty/efsw/Log.cpp
117 src/3rdParty/efsw/Mutex.cpp
118 src/3rdParty/efsw/String.cpp
119 src/3rdParty/efsw/System.cpp
120 src/3rdParty/efsw/Thread.cpp
121 src/3rdParty/efsw/Watcher.cpp
122 src/3rdParty/efsw/WatcherGeneric.cpp
125 ) 123 )
126 124
127 if (NOT CMAKE_SYSTEM_VERSION GREATER 9) 125 if (WIN32)
128 target_compile_definitions(yue PRIVATE EFSW_FSEVENTS_NOT_SUPPORTED) 126 target_sources(yue PRIVATE
127 src/3rdParty/efsw/platform/win/FileSystemImpl.cpp
128 src/3rdParty/efsw/platform/win/MutexImpl.cpp
129 src/3rdParty/efsw/platform/win/SystemImpl.cpp
130 src/3rdParty/efsw/platform/win/ThreadImpl.cpp
131 )
132 else ()
133 target_sources(yue PRIVATE
134 src/3rdParty/efsw/platform/posix/FileSystemImpl.cpp
135 src/3rdParty/efsw/platform/posix/MutexImpl.cpp
136 src/3rdParty/efsw/platform/posix/SystemImpl.cpp
137 src/3rdParty/efsw/platform/posix/ThreadImpl.cpp
138 )
129 endif() 139 endif()
130elseif (WIN32)
131 target_sources(yue PRIVATE
132 src/3rdParty/efsw/FileWatcherWin32.cpp
133 src/3rdParty/efsw/WatcherWin32.cpp
134 )
135elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
136 target_sources(yue PRIVATE
137 src/3rdParty/efsw/FileWatcherInotify.cpp
138 src/3rdParty/efsw/WatcherInotify.cpp
139 )
140 140
141 if (NOT EXISTS "/usr/include/sys/inotify.h" AND NOT EXISTS "/usr/local/include/sys/inotify.h") 141 if (APPLE)
142 target_compile_definitions(yue PRIVATE EFSW_INOTIFY_NOSYS) 142 target_sources(yue PRIVATE
143 src/3rdParty/efsw/FileWatcherFSEvents.cpp
144 src/3rdParty/efsw/FileWatcherKqueue.cpp
145 src/3rdParty/efsw/WatcherFSEvents.cpp
146 src/3rdParty/efsw/WatcherKqueue.cpp
147 )
148
149 if (NOT CMAKE_SYSTEM_VERSION GREATER 9)
150 target_compile_definitions(yue PRIVATE EFSW_FSEVENTS_NOT_SUPPORTED)
151 endif()
152 elseif (WIN32)
153 target_sources(yue PRIVATE
154 src/3rdParty/efsw/FileWatcherWin32.cpp
155 src/3rdParty/efsw/WatcherWin32.cpp
156 )
157 elseif (${CMAKE_SYSTEM_NAME} MATCHES "Linux")
158 target_sources(yue PRIVATE
159 src/3rdParty/efsw/FileWatcherInotify.cpp
160 src/3rdParty/efsw/WatcherInotify.cpp
161 )
162
163 if (NOT EXISTS "/usr/include/sys/inotify.h" AND NOT EXISTS "/usr/local/include/sys/inotify.h")
164 target_compile_definitions(yue PRIVATE EFSW_INOTIFY_NOSYS)
165 endif()
166 elseif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD")
167 target_sources(yue PRIVATE
168 src/3rdParty/efsw/FileWatcherKqueue.cpp
169 src/3rdParty/efsw/WatcherKqueue.cpp
170 )
143 endif() 171 endif()
144elseif (${CMAKE_SYSTEM_NAME} MATCHES "FreeBSD") 172else()
145 target_sources(yue PRIVATE 173 message(STATUS "Termux environment detected: excluding efsw file watcher sources")
146 src/3rdParty/efsw/FileWatcherKqueue.cpp
147 src/3rdParty/efsw/WatcherKqueue.cpp
148 )
149endif() 174endif()
150 175
151if (MSVC) 176if (MSVC)
152 target_compile_definitions(yue PRIVATE _SCL_SECURE_NO_WARNINGS) 177 target_compile_definitions(yue PRIVATE _SCL_SECURE_NO_WARNINGS)
153else () 178else ()
154 target_compile_options(yue PRIVATE -Wall -Wno-long-long -fPIC) 179 target_compile_options(yue PRIVATE -Wall -Wno-long-long -fPIC)
180 set_source_files_properties(src/3rdParty/colib/ljson.c PROPERTIES COMPILE_FLAGS "-std=c99")
181endif()
182
183# Add YUE_NO_WATCHER macro for Termux environment
184if (IS_TERMUX)
185 target_compile_definitions(yue PRIVATE YUE_NO_WATCHER)
155endif() 186endif()
156 187
157if (${CMAKE_BUILD_TYPE} MATCHES "Debug") 188if (${CMAKE_BUILD_TYPE} MATCHES "Debug")
@@ -169,10 +200,9 @@ elseif (NOT (${CMAKE_SYSTEM_NAME} MATCHES "Haiku") AND NOT WIN32)
169else () 200else ()
170 target_link_libraries(yue PRIVATE ${LUA_LIBRARIES}) 201 target_link_libraries(yue PRIVATE ${LUA_LIBRARIES})
171endif() 202endif()
172 203
173if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 204if (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
174 target_link_options(yue PRIVATE -lstdc++fs -ldl) 205 target_link_options(yue PRIVATE -ldl)
175endif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU") 206endif (CMAKE_CXX_COMPILER_ID STREQUAL "GNU")
176 207
177install(CODE "") 208install(CODE "")
178
diff --git a/LICENSE b/LICENSE
index ca28207..aebc6e7 100644
--- a/LICENSE
+++ b/LICENSE
@@ -1,6 +1,6 @@
1MIT License 1MIT License
2 2
3Copyright (c) 2017-2025 Li Jin <dragon-fly@qq.com> 3Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com>
4 4
5Permission is hereby granted, free of charge, to any person obtaining a copy 5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal 6of this software and associated documentation files (the "Software"), to deal
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/README.md b/doc/docs/README.md
index 21e47c4..098d7da 100755
--- a/doc/docs/README.md
+++ b/doc/docs/README.md
@@ -3,6 +3,6 @@ home: true
3heroImage: ./image/yuescript.svg 3heroImage: ./image/yuescript.svg
4actionText: Quick Start → 4actionText: Quick Start →
5actionLink: /doc/ 5actionLink: /doc/
6footer: MIT Licensed | Copyright © 2017-2025 Li Jin 6footer: MIT Licensed | Copyright © 2017-2026 Li Jin
7--- 7---
8 8
diff --git a/doc/docs/doc/README.md b/doc/docs/doc/README.md
index 0853391..5308ebc 100755
--- a/doc/docs/doc/README.md
+++ b/doc/docs/doc/README.md
@@ -16,17 +16,17 @@ 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 32-- list comprehension
@@ -61,17 +61,17 @@ export 🌛 = "月之脚本"
61<YueDisplay> 61<YueDisplay>
62<pre> 62<pre>
63-- import syntax 63-- import syntax
64import "yue" as :p, :to_lua 64import p, to_lua from "yue"
65 65
66-- object literals 66-- object literals
67inventory = 67inventory =
68 equipment: 68 equipment:
69 * "sword" 69 - "sword"
70 * "shield" 70 - "shield"
71 items: 71 items:
72 * name: "potion" 72 - name: "potion"
73 count: 10 73 count: 10
74 * name: "bread" 74 - name: "bread"
75 count: 3 75 count: 3
76 76
77-- list comprehension 77-- list comprehension
@@ -408,16 +408,16 @@ In YueScript, macro functions allow you to generate code at compile time. By nes
408 408
409```moonscript 409```moonscript
410macro Enum = (...) -> 410macro Enum = (...) ->
411 items = {...} 411 items = {...}
412 itemSet = {item, true for item in *items} 412 itemSet = {item, true for item in *items}
413 (item) -> 413 (item) ->
414 error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item] 414 error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item]
415 "\"#{item}\"" 415 "\"#{item}\""
416 416
417macro BodyType = $Enum( 417macro BodyType = $Enum(
418 Static 418 Static
419 Dynamic 419 Dynamic
420 Kinematic 420 Kinematic
421) 421)
422 422
423print "Valid enum type:", $BodyType Static 423print "Valid enum type:", $BodyType Static
@@ -427,16 +427,16 @@ print "Valid enum type:", $BodyType Static
427<YueDisplay> 427<YueDisplay>
428<pre> 428<pre>
429macro Enum = (...) -> 429macro Enum = (...) ->
430 items = {...} 430 items = {...}
431 itemSet = {item, true for item in *items} 431 itemSet = {item, true for item in *items}
432 (item) -> 432 (item) ->
433 error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item] 433 error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item]
434 "\"#{item}\"" 434 "\"#{item}\""
435 435
436macro BodyType = $Enum( 436macro BodyType = $Enum(
437 Static 437 Static
438 Dynamic 438 Dynamic
439 Kinematic 439 Kinematic
440) 440)
441 441
442print "Valid enum type:", $BodyType Static 442print "Valid enum type:", $BodyType Static
@@ -444,6 +444,54 @@ print "Valid enum type:", $BodyType Static
444</pre> 444</pre>
445</YueDisplay> 445</YueDisplay>
446 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
447## Operator 495## Operator
448 496
449All 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.
@@ -486,47 +534,47 @@ Note the evaluation behavior of chained comparisons:
486 534
487```moonscript 535```moonscript
488v = (x) -> 536v = (x) ->
489 print x 537 print x
490 x 538 x
491 539
492print v(1) < v(2) <= v(3) 540print v(1) < v(2) <= v(3)
493--[[ 541--[[
494 output: 542 output:
495 2 543 2
496 1 544 1
497 3 545 3
498 true 546 true
499]] 547]]
500 548
501print v(1) > v(2) <= v(3) 549print v(1) > v(2) <= v(3)
502--[[ 550--[[
503 output: 551 output:
504 2 552 2
505 1 553 1
506 false 554 false
507]] 555]]
508``` 556```
509<YueDisplay> 557<YueDisplay>
510<pre> 558<pre>
511v = (x) -> 559v = (x) ->
512 print x 560 print x
513 x 561 x
514 562
515print v(1) < v(2) <= v(3) 563print v(1) < v(2) <= v(3)
516--[[ 564--[[
517 output: 565 output:
518 2 566 2
519 1 567 1
520 3 568 3
521 true 569 true
522]] 570]]
523 571
524print v(1) > v(2) <= v(3) 572print v(1) > v(2) <= v(3)
525--[[ 573--[[
526 output: 574 output:
527 2 575 2
528 1 576 1
529 false 577 false
530]] 578]]
531</pre> 579</pre>
532</YueDisplay> 580</YueDisplay>
@@ -547,19 +595,36 @@ tab[] = "Value"
547</pre> 595</pre>
548</YueDisplay> 596</YueDisplay>
549 597
598You can also use the spread operator `...` to append all elements from one list to another:
599
600```moonscript
601tbA = [1, 2, 3]
602tbB = [4, 5, 6]
603tbA[] = ...tbB
604-- tbA is now [1, 2, 3, 4, 5, 6]
605```
606<YueDisplay>
607<pre>
608tbA = [1, 2, 3]
609tbB = [4, 5, 6]
610tbA[] = ...tbB
611-- tbA is now [1, 2, 3, 4, 5, 6]
612</pre>
613</YueDisplay>
614
550### Table Spreading 615### Table Spreading
551 616
552You can concatenate array tables or hash tables using spread operator `...` before expressions in table literals. 617You can concatenate array tables or hash tables using spread operator `...` before expressions in table literals.
553 618
554```moonscript 619```moonscript
555parts = 620parts =
556 * "shoulders" 621 * "shoulders"
557 * "knees" 622 * "knees"
558lyrics = 623lyrics =
559 * "head" 624 * "head"
560 * ...parts 625 * ...parts
561 * "and" 626 * "and"
562 * "toes" 627 * "toes"
563 628
564copy = {...other} 629copy = {...other}
565 630
@@ -570,13 +635,13 @@ merge = {...a, ...b}
570<YueDisplay> 635<YueDisplay>
571<pre> 636<pre>
572parts = 637parts =
573 * "shoulders" 638 * "shoulders"
574 * "knees" 639 * "knees"
575lyrics = 640lyrics =
576 * "head" 641 * "head"
577 * ...parts 642 * ...parts
578 * "and" 643 * "and"
579 * "toes" 644 * "toes"
580 645
581copy = {...other} 646copy = {...other}
582 647
@@ -586,6 +651,23 @@ merge = {...a, ...b}
586</pre> 651</pre>
587</YueDisplay> 652</YueDisplay>
588 653
654### Table Reversed Indexing
655
656You can use the **#** operator to get the last elements of a table.
657
658```moonscript
659last = data.items[#]
660second_last = data.items[#-1]
661data.items[#] = 1
662```
663<YueDisplay>
664<pre>
665last = data.items[#]
666second_last = data.items[#-1]
667data.items[#] = 1
668</pre>
669</YueDisplay>
670
589### Metatable 671### Metatable
590 672
591The **<>** operator can be used as a shortcut for metatable manipulation. 673The **<>** operator can be used as a shortcut for metatable manipulation.
@@ -752,34 +834,45 @@ a ??= false
752 834
753### Implicit Object 835### Implicit Object
754 836
755You 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. 837You 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.
838
756```moonscript 839```moonscript
840-- assignment with implicit object
757list = 841list =
758 * 1 842 * 1
759 * 2 843 * 2
760 * 3 844 * 3
761 845
846-- function call with implicit object
762func 847func
763 * 1 848 * 1
764 * 2 849 * 2
765 * 3 850 * 3
766 851
852-- return with implicit object
853f = ->
854 return
855 * 1
856 * 2
857 * 3
858
859-- table with implicit object
767tb = 860tb =
768 name: "abc" 861 name: "abc"
769 862
770 values: 863 values:
771 * "a" 864 - "a"
772 * "b" 865 - "b"
773 * "c" 866 - "c"
774 867
775 objects: 868 objects:
776 * name: "a" 869 - name: "a"
777 value: 1 870 value: 1
778 func: => @value + 1 871 func: => @value + 1
779 tb: 872 tb:
780 fieldA: 1 873 fieldA: 1
781 874
782 * name: "b" 875 - name: "b"
783 value: 2 876 value: 2
784 func: => @value + 2 877 func: => @value + 2
785 tb: { } 878 tb: { }
@@ -787,32 +880,42 @@ tb =
787``` 880```
788<YueDisplay> 881<YueDisplay>
789<pre> 882<pre>
883-- assignment with implicit object
790list = 884list =
791 * 1 885 * 1
792 * 2 886 * 2
793 * 3 887 * 3
794 888
889-- function call with implicit object
795func 890func
796 * 1 891 * 1
797 * 2 892 * 2
798 * 3 893 * 3
799 894
895-- return with implicit object
896f = ->
897 return
898 * 1
899 * 2
900 * 3
901
902-- table with implicit object
800tb = 903tb =
801 name: "abc" 904 name: "abc"
802 905
803 values: 906 values:
804 * "a" 907 - "a"
805 * "b" 908 - "b"
806 * "c" 909 - "c"
807 910
808 objects: 911 objects:
809 * name: "a" 912 - name: "a"
810 value: 1 913 value: 1
811 func: => @value + 1 914 func: => @value + 1
812 tb: 915 tb:
813 fieldA: 1 916 fieldA: 1
814 917
815 * name: "b" 918 - name: "b"
816 value: 2 919 value: 2
817 func: => @value + 2 920 func: => @value + 2
818 tb: { } 921 tb: { }
@@ -1222,7 +1325,7 @@ If the destructuring statement is complicated, feel free to spread it out over a
1222</pre> 1325</pre>
1223</YueDisplay> 1326</YueDisplay>
1224 1327
1225It’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: 1328It'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:
1226 1329
1227```moonscript 1330```moonscript
1228{:concat, :insert} = table 1331{:concat, :insert} = table
@@ -1266,6 +1369,52 @@ You can use `_` as placeholder when doing a list destructuring:
1266</pre> 1369</pre>
1267</YueDisplay> 1370</YueDisplay>
1268 1371
1372### Range Destructuring
1373
1374You 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.
1375
1376```moonscript
1377orders = ["first", "second", "third", "fourth", "last"]
1378[first, ...bulk, last] = orders
1379print first -- prints: first
1380print bulk -- prints: {"second", "third", "fourth"}
1381print last -- prints: last
1382```
1383<YueDisplay>
1384<pre>
1385orders = ["first", "second", "third", "fourth", "last"]
1386[first, ...bulk, last] = orders
1387print first -- prints: first
1388print bulk -- prints: {"second", "third", "fourth"}
1389print last -- prints: last
1390</pre>
1391</YueDisplay>
1392
1393The 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:
1394
1395```moonscript
1396-- Capture everything after first element
1397[first, ...rest] = orders
1398
1399-- Capture everything before last element
1400[...start, last] = orders
1401
1402-- Capture things except the middle elements
1403[first, ..._, last] = orders
1404```
1405<YueDisplay>
1406<pre>
1407-- Capture everything after first element
1408[first, ...rest] = orders
1409
1410-- Capture everything before last element
1411[...start, last] = orders
1412
1413-- Capture things except the middle elements
1414[first, ..._, last] = orders
1415</pre>
1416</YueDisplay>
1417
1269### Destructuring In Other Places 1418### Destructuring In Other Places
1270 1419
1271Destructuring can also show up in places where an assignment implicitly takes place. An example of this is a for loop: 1420Destructuring can also show up in places where an assignment implicitly takes place. An example of this is a for loop:
@@ -1495,6 +1644,47 @@ catch err
1495</pre> 1644</pre>
1496</YueDisplay> 1645</YueDisplay>
1497 1646
1647### Try?
1648
1649`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.
1650
1651```moonscript
1652a, b, c = try? func!
1653
1654-- with nil coalescing operator
1655a = (try? func!) ?? "default"
1656
1657-- as function argument
1658f try? func!
1659
1660-- with catch block
1661f try?
1662 print 123
1663 func!
1664catch e
1665 print e
1666 e
1667```
1668<YueDisplay>
1669<pre>
1670a, b, c = try? func!
1671
1672-- with nil coalescing operator
1673a = (try? func!) ?? "default"
1674
1675-- as function argument
1676f try? func!
1677
1678-- with catch block
1679f try?
1680 print 123
1681 func!
1682catch e
1683 print e
1684 e
1685</pre>
1686</YueDisplay>
1687
1498## Attributes 1688## Attributes
1499 1689
1500Syntax 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. 1690Syntax 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.
@@ -1575,6 +1765,66 @@ binary = 0B10011
1575<pre> 1765<pre>
1576integer = 1_000_000 1766integer = 1_000_000
1577hex = 0xEF_BB_BF 1767hex = 0xEF_BB_BF
1768binary = 0B10011
1769</pre>
1770</YueDisplay>
1771
1772### YAML Multiline String
1773
1774The `|` prefix introduces a YAML-style multiline string literal:
1775
1776```moonscript
1777str = |
1778 key: value
1779 list:
1780 - item1
1781 - #{expr}
1782```
1783<YueDisplay>
1784<pre>
1785str = |
1786 key: value
1787 list:
1788 - item1
1789 - #{expr}
1790</pre>
1791</YueDisplay>
1792
1793This 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)`.
1794
1795YAML 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.
1796
1797```moonscript
1798fn = ->
1799 str = |
1800 foo:
1801 bar: baz
1802 return str
1803```
1804<YueDisplay>
1805<pre>
1806fn = ->
1807 str = |
1808 foo:
1809 bar: baz
1810 return str
1811</pre>
1812</YueDisplay>
1813
1814Internal indentation is preserved relative to the removed common prefix, allowing clean nested structures.
1815
1816All 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.
1817
1818```moonscript
1819str = |
1820 path: "C:\Program Files\App"
1821 note: 'He said: "#{Hello}!"'
1822```
1823<YueDisplay>
1824<pre>
1825str = |
1826 path: "C:\Program Files\App"
1827 note: 'He said: "#{Hello}!"'
1578</pre> 1828</pre>
1579</YueDisplay> 1829</YueDisplay>
1580 1830
@@ -1895,6 +2145,138 @@ if func 1, 2, 3,
1895</pre> 2145</pre>
1896</YueDisplay> 2146</YueDisplay>
1897 2147
2148### Parameter Destructuring
2149
2150YueScript now supports destructuring function parameters when the argument is an object. Two forms of destructuring table literals are available:
2151
2152* **Curly-brace wrapped literals/object parameters**, allowing optional default values when fields are missing (e.g., `{:a, :b}`, `{a: a1 = 123}`).
2153
2154* **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.
2155
2156```moonscript
2157f1 = (:a, :b, :c) ->
2158 print a, b, c
2159
2160f1 a: 1, b: "2", c: {}
2161
2162f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) ->
2163 print a1, b, c
2164
2165arg1 = {a: 0}
2166f2 arg1, arg2
2167```
2168<YueDisplay>
2169<pre>
2170f1 = (:a, :b, :c) ->
2171 print a, b, c
2172
2173f1 a: 1, b: "2", c: {}
2174
2175f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) ->
2176print a1, b, c
2177
2178arg1 = {a: 0}
2179f2 arg1, arg2
2180</pre>
2181</YueDisplay>
2182
2183### Prefixed Return Expression
2184
2185When 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:
2186
2187```moon
2188findFirstEven = (list): nil ->
2189 for item in *list
2190 if type(item) == "table"
2191 for sub in *item
2192 if sub % 2 == 0
2193 return sub
2194```
2195<YueDisplay>
2196<pre>
2197findFirstEven = (list): nil ->
2198 for item in *list
2199 if type(item) == "table"
2200 for sub in *item
2201 if sub % 2 == 0
2202 return sub
2203</pre>
2204</YueDisplay>
2205
2206This is equivalent to:
2207
2208```moon
2209findFirstEven = (list) ->
2210 for item in *list
2211 if type(item) == "table"
2212 for sub in *item
2213 if sub % 2 == 0
2214 return sub
2215 nil
2216```
2217<YueDisplay>
2218<pre>
2219findFirstEven = (list) ->
2220 for item in *list
2221 if type(item) == "table"
2222 for sub in *item
2223 if sub % 2 == 0
2224 return sub
2225 nil
2226</pre>
2227</YueDisplay>
2228
2229The 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.
2230
2231### Named Varargs
2232
2233You can use the `(...t) ->` syntax to automatically store varargs into a named table. This table will contain all passed arguments (including `nil` values), and the `n` field of the table will store the actual number of arguments passed (including `nil` values).
2234
2235```moonscript
2236f = (...t) ->
2237 print "argument count:", t.n
2238 print "table length:", #t
2239 for i = 1, t.n
2240 print t[i]
2241
2242f 1, 2, 3
2243f "a", "b", "c", "d"
2244f!
2245
2246-- Handling cases with nil values
2247process = (...args) ->
2248 sum = 0
2249 for i = 1, args.n
2250 if args[i] != nil and type(args[i]) == "number"
2251 sum += args[i]
2252 sum
2253
2254process 1, nil, 3, nil, 5
2255```
2256<YueDisplay>
2257<pre>
2258f = (...t) ->
2259 print "argument count:", t.n
2260 print "table length:", #t
2261 for i = 1, t.n
2262 print t[i]
2263
2264f 1, 2, 3
2265f "a", "b", "c", "d"
2266f!
2267
2268-- Handling cases with nil values
2269process = (...args) ->
2270 sum = 0
2271 for i = 1, args.n
2272 if args[i] != nil and type(args[i]) == "number"
2273 sum += args[i]
2274 sum
2275
2276process 1, nil, 3, nil, 5
2277</pre>
2278</YueDisplay>
2279
1898## Backcalls 2280## Backcalls
1899 2281
1900Backcalls 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. 2282Backcalls 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.
@@ -2149,6 +2531,27 @@ doubled = [item * 2 for item in *items]
2149</pre> 2531</pre>
2150</YueDisplay> 2532</YueDisplay>
2151 2533
2534In list comprehensions, you can also use the spread operator `...` to flatten nested lists, achieving a flat map effect:
2535
2536```moonscript
2537data =
2538 a: [1, 2, 3]
2539 b: [4, 5, 6]
2540
2541flat = [...v for k,v in pairs data]
2542-- flat is now [1, 2, 3, 4, 5, 6]
2543```
2544<YueDisplay>
2545<pre>
2546data =
2547 a: [1, 2, 3]
2548 b: [4, 5, 6]
2549
2550flat = [...v for k,v in pairs data]
2551-- flat is now [1, 2, 3, 4, 5, 6]
2552</pre>
2553</YueDisplay>
2554
2152The for and when clauses can be chained as much as desired. The only requirement is that a comprehension has at least one for clause. 2555The for and when clauses can be chained as much as desired. The only requirement is that a comprehension has at least one for clause.
2153 2556
2154Using multiple for clauses is the same as using nested loops: 2557Using multiple for clauses is the same as using nested loops:
@@ -2282,6 +2685,45 @@ slice = [item for item in *items[,,2]]
2282</pre> 2685</pre>
2283</YueDisplay> 2686</YueDisplay>
2284 2687
2688Both the minimum and maximum bounds can be negative, which means that the bounds are counted from the end of the table.
2689
2690```moonscript
2691-- take the last 4 items
2692slice = [item for item in *items[-4,-1]]
2693```
2694<YueDisplay>
2695<pre>
2696-- take the last 4 items
2697slice = [item for item in *items[-4,-1]]
2698</pre>
2699</YueDisplay>
2700
2701The step size can also be negative, which means that the items are taken in reverse order.
2702
2703```moonscript
2704reverse_slice = [item for item in *items[-1,1,-1]]
2705```
2706<YueDisplay>
2707<pre>
2708reverse_slice = [item for item in *items[-1,1,-1]]
2709</pre>
2710</YueDisplay>
2711
2712#### Slicing Expression
2713
2714Slicing can also be used as an expression. This is useful for getting a sub-list of a table.
2715
2716```moonscript
2717-- take the 2nd and 4th items as a new list
2718sub_list = items[2, 4]
2719```
2720<YueDisplay>
2721<pre>
2722-- take the 2nd and 4th items as a new list
2723sub_list = items[2, 4]
2724</pre>
2725</YueDisplay>
2726
2285## For Loop 2727## For Loop
2286 2728
2287There are two for loop forms, just like in Lua. A numeric one and a generic one: 2729There are two for loop forms, just like in Lua. A numeric one and a generic one:
@@ -2396,7 +2838,7 @@ print func_b! -- prints table object
2396</pre> 2838</pre>
2397</YueDisplay> 2839</YueDisplay>
2398 2840
2399This is done to avoid the needless creation of tables for functions that don’t need to return the results of the loop. 2841This is done to avoid the needless creation of tables for functions that don't need to return the results of the loop.
2400 2842
2401## Repeat Loop 2843## Repeat Loop
2402 2844
@@ -2675,28 +3117,26 @@ reader\parse_line! until reader\eof!
2675 3117
2676## Switch 3118## Switch
2677 3119
2678The 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. 3120The 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.
2679 3121
2680```moonscript 3122```moonscript
2681name = "Dan" 3123switch name := "Dan"
2682switch name
2683 when "Robert" 3124 when "Robert"
2684 print "You are Robert" 3125 print "You are Robert"
2685 when "Dan", "Daniel" 3126 when "Dan", "Daniel"
2686 print "Your name, it's Dan" 3127 print "Your name, it's Dan"
2687 else 3128 else
2688 print "I don't know about your name" 3129 print "I don't know about you with name #{name}"
2689``` 3130```
2690<YueDisplay> 3131<YueDisplay>
2691<pre> 3132<pre>
2692name = "Dan" 3133switch name := "Dan"
2693switch name
2694 when "Robert" 3134 when "Robert"
2695 print "You are Robert" 3135 print "You are Robert"
2696 when "Dan", "Daniel" 3136 when "Dan", "Daniel"
2697 print "Your name, it's Dan" 3137 print "Your name, it's Dan"
2698 else 3138 else
2699 print "I don't know about your name" 3139 print "I don't know about you with name #{name}"
2700</pre> 3140</pre>
2701</YueDisplay> 3141</YueDisplay>
2702 3142
@@ -2727,7 +3167,7 @@ next_number = switch b
2727</pre> 3167</pre>
2728</YueDisplay> 3168</YueDisplay>
2729 3169
2730We 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. 3170We 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.
2731 3171
2732```moonscript 3172```moonscript
2733msg = switch math.random(1, 5) 3173msg = switch math.random(1, 5)
@@ -2773,7 +3213,7 @@ else
2773</pre> 3213</pre>
2774</YueDisplay> 3214</YueDisplay>
2775 3215
2776It 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. 3216It 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.
2777 3217
2778### Table Matching 3218### Table Matching
2779 3219
@@ -2929,6 +3369,27 @@ switch tb
2929</pre> 3369</pre>
2930</YueDisplay> 3370</YueDisplay>
2931 3371
3372Match against a list and capture a range of elements.
3373
3374```moonscript
3375segments = ["admin", "users", "logs", "view"]
3376switch segments
3377 when [...groups, resource, action]
3378 print "Group:", groups -- prints: {"admin", "users"}
3379 print "Resource:", resource -- prints: "logs"
3380 print "Action:", action -- prints: "view"
3381```
3382<YueDisplay>
3383<pre>
3384segments = ["admin", "users", "logs", "view"]
3385switch segments
3386 when [...groups, resource, action]
3387 print "Group:", groups -- prints: {"admin", "users"}
3388 print "Resource:", resource -- prints: "logs"
3389 print "Action:", action -- prints: "view"
3390</pre>
3391</YueDisplay>
3392
2932## Object Oriented Programming 3393## Object Oriented Programming
2933 3394
2934In 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. 3395In 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.
@@ -3060,7 +3521,7 @@ class BackPack extends Inventory
3060 3521
3061Here we extend our Inventory class, and limit the amount of items it can carry. 3522Here we extend our Inventory class, and limit the amount of items it can carry.
3062 3523
3063In 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. 3524In 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.
3064 3525
3065Whenever 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. 3526Whenever 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.
3066 3527
@@ -3147,13 +3608,13 @@ print BackPack.size -- prints 10
3147 3608
3148The 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. 3609The 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.
3149 3610
3150The 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. 3611The 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.
3151 3612
3152A 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. 3613A 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.
3153 3614
3154The 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. 3615The 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.
3155 3616
3156It 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. 3617It 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.
3157 3618
3158The class object has a couple special properties: 3619The class object has a couple special properties:
3159 3620
@@ -3226,7 +3687,7 @@ print Counter.count -- prints 2
3226</pre> 3687</pre>
3227</YueDisplay> 3688</YueDisplay>
3228 3689
3229The calling semantics of @@ are similar to @. Calling a @@ name will pass the class in as the first argument using Lua’s colon syntax. 3690The calling semantics of @@ are similar to @. Calling a @@ name will pass the class in as the first argument using Lua's colon syntax.
3230 3691
3231```moonscript 3692```moonscript
3232@@hello 1,2,3,4 3693@@hello 1,2,3,4
@@ -3241,7 +3702,7 @@ The calling semantics of @@ are similar to @. Calling a @@ name will pass the cl
3241 3702
3242In 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. 3703In 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.
3243 3704
3244Here is an alternative way to create a class variable compared to what’s described above: 3705Here is an alternative way to create a class variable compared to what's described above:
3245 3706
3246```moonscript 3707```moonscript
3247class Things 3708class Things
@@ -3507,19 +3968,19 @@ In this usage, with can be seen as a special form of the K combinator.
3507The expression in the with statement can also be an assignment, if you want to give a name to the expression. 3968The expression in the with statement can also be an assignment, if you want to give a name to the expression.
3508 3969
3509```moonscript 3970```moonscript
3510with str = "Hello" 3971with str := "Hello"
3511 print "original:", str 3972 print "original:", str
3512 print "upper:", \upper! 3973 print "upper:", \upper!
3513``` 3974```
3514<YueDisplay> 3975<YueDisplay>
3515<pre> 3976<pre>
3516with str = "Hello" 3977with str := "Hello"
3517 print "original:", str 3978 print "original:", str
3518 print "upper:", \upper! 3979 print "upper:", \upper!
3519</pre> 3980</pre>
3520</YueDisplay> 3981</YueDisplay>
3521 3982
3522Accessing special keys with `[]` in a `with` statement. 3983You can access special keys with `[]` in a `with` statement.
3523 3984
3524```moonscript 3985```moonscript
3525with tb 3986with tb
@@ -3542,6 +4003,18 @@ with tb
3542</pre> 4003</pre>
3543</YueDisplay> 4004</YueDisplay>
3544 4005
4006`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.
4007
4008```moonscript
4009with? obj
4010 print obj.name
4011```
4012<YueDisplay>
4013<pre>
4014with? obj
4015 print obj.name
4016</pre>
4017</YueDisplay>
3545 4018
3546## Do 4019## Do
3547 4020
@@ -3562,7 +4035,7 @@ print var -- nil here
3562</pre> 4035</pre>
3563</YueDisplay> 4036</YueDisplay>
3564 4037
3565YueScript’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. 4038YueScript'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.
3566 4039
3567```moonscript 4040```moonscript
3568counter = do 4041counter = do
@@ -3688,7 +4161,7 @@ print i -- will print 0
3688</pre> 4161</pre>
3689</YueDisplay> 4162</YueDisplay>
3690 4163
3691In 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. 4164In 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.
3692 4165
3693It 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. 4166It 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.
3694 4167
@@ -3804,9 +4277,9 @@ The YueScript compiling function. It compiles the YueScript code to Lua code.
3804**Signature:** 4277**Signature:**
3805```lua 4278```lua
3806to_lua: function(code: string, config?: Config): 4279to_lua: function(code: string, config?: Config):
3807 --[[codes]] string | nil, 4280 --[[codes]] string | nil,
3808 --[[error]] string | nil, 4281 --[[error]] string | nil,
3809 --[[globals]] {{string, integer, integer}} | nil 4282 --[[globals]] {{string, integer, integer}} | nil
3810``` 4283```
3811 4284
3812**Parameters:** 4285**Parameters:**
@@ -3929,8 +4402,8 @@ Loads YueScript code from a string into a function.
3929**Signature:** 4402**Signature:**
3930```lua 4403```lua
3931loadstring: function(input: string, chunkname: string, env: table, config?: Config): 4404loadstring: function(input: string, chunkname: string, env: table, config?: Config):
3932 --[[loaded function]] nil | function(...: any): (any...), 4405 --[[loaded function]] nil | function(...: any): (any...),
3933 --[[error]] string | nil 4406 --[[error]] string | nil
3934``` 4407```
3935 4408
3936**Parameters:** 4409**Parameters:**
@@ -3960,8 +4433,8 @@ Loads YueScript code from a string into a function.
3960**Signature:** 4433**Signature:**
3961```lua 4434```lua
3962loadstring: function(input: string, chunkname: string, config?: Config): 4435loadstring: function(input: string, chunkname: string, config?: Config):
3963 --[[loaded function]] nil | function(...: any): (any...), 4436 --[[loaded function]] nil | function(...: any): (any...),
3964 --[[error]] string | nil 4437 --[[error]] string | nil
3965``` 4438```
3966 4439
3967**Parameters:** 4440**Parameters:**
@@ -3990,8 +4463,8 @@ Loads YueScript code from a string into a function.
3990**Signature:** 4463**Signature:**
3991```lua 4464```lua
3992loadstring: function(input: string, config?: Config): 4465loadstring: function(input: string, config?: Config):
3993 --[[loaded function]] nil | function(...: any): (any...), 4466 --[[loaded function]] nil | function(...: any): (any...),
3994 --[[error]] string | nil 4467 --[[error]] string | nil
3995``` 4468```
3996 4469
3997**Parameters:** 4470**Parameters:**
@@ -4019,8 +4492,8 @@ Loads YueScript code from a file into a function.
4019**Signature:** 4492**Signature:**
4020```lua 4493```lua
4021loadfile: function(filename: string, env: table, config?: Config): 4494loadfile: function(filename: string, env: table, config?: Config):
4022 nil | function(...: any): (any...), 4495 nil | function(...: any): (any...),
4023 string | nil 4496 string | nil
4024``` 4497```
4025 4498
4026**Parameters:** 4499**Parameters:**
@@ -4049,8 +4522,8 @@ Loads YueScript code from a file into a function.
4049**Signature:** 4522**Signature:**
4050```lua 4523```lua
4051loadfile: function(filename: string, config?: Config): 4524loadfile: function(filename: string, config?: Config):
4052 nil | function(...: any): (any...), 4525 nil | function(...: any): (any...),
4053 string | nil 4526 string | nil
4054``` 4527```
4055 4528
4056**Parameters:** 4529**Parameters:**
@@ -4305,9 +4778,9 @@ Converts the code to the AST.
4305 4778
4306**Signature:** 4779**Signature:**
4307```lua 4780```lua
4308to_ast: function(code: string, flattenLevel?: number, astName?: string): 4781to_ast: function(code: string, flattenLevel?: number, astName?: string, reserveComment?: boolean):
4309 --[[AST]] AST | nil, 4782 --[[AST]] AST | nil,
4310 --[[error]] nil | string 4783 --[[error]] nil | string
4311``` 4784```
4312 4785
4313**Parameters:** 4786**Parameters:**
@@ -4317,6 +4790,7 @@ to_ast: function(code: string, flattenLevel?: number, astName?: string):
4317| code | string | The code. | 4790| code | string | The code. |
4318| flattenLevel | integer | [Optional] The flatten level. Higher level means more flattening. Default is 0. Maximum is 2. | 4791| flattenLevel | integer | [Optional] The flatten level. Higher level means more flattening. Default is 0. Maximum is 2. |
4319| astName | string | [Optional] The AST name. Default is "File". | 4792| astName | string | [Optional] The AST name. Default is "File". |
4793| reserveComment | boolean | [Optional] Whether to reserve the original comments. Default is false. |
4320 4794
4321**Returns:** 4795**Returns:**
4322 4796
@@ -4325,6 +4799,33 @@ to_ast: function(code: string, flattenLevel?: number, astName?: string):
4325| AST \| nil | The AST, or nil if the conversion failed. | 4799| AST \| nil | The AST, or nil if the conversion failed. |
4326| string \| nil | The error message, or nil if the conversion succeeded. | 4800| string \| nil | The error message, or nil if the conversion succeeded. |
4327 4801
4802#### format
4803
4804**Type:** Function.
4805
4806**Description:**
4807
4808Formats the YueScript code.
4809
4810**Signature:**
4811```lua
4812format: function(code: string, tabSize?: number, reserveComment?: boolean): string
4813```
4814
4815**Parameters:**
4816
4817| Parameter | Type | Description |
4818| --- | --- | --- |
4819| code | string | The code. |
4820| tabSize | integer | [Optional] The tab size. Default is 4. |
4821| reserveComment | boolean | [Optional] Whether to reserve the original comments. Default is true. |
4822
4823**Returns:**
4824
4825| Return Type | Description |
4826| --- | --- |
4827| string | The formatted code. |
4828
4328#### __call 4829#### __call
4329 4830
4330**Type:** Metamethod. 4831**Type:** Metamethod.
@@ -4396,6 +4897,19 @@ Whether the compiler should reserve the original line number in the compiled cod
4396reserve_line_number: boolean 4897reserve_line_number: boolean
4397``` 4898```
4398 4899
4900#### reserve_comment
4901
4902**Type:** Field.
4903
4904**Description:**
4905
4906Whether the compiler should reserve the original comments in the compiled code.
4907
4908**Signature:**
4909```lua
4910reserve_comment: boolean
4911```
4912
4399#### space_over_tab 4913#### space_over_tab
4400 4914
4401**Type:** Field. 4915**Type:** Field.
@@ -4446,11 +4960,11 @@ The target Lua version enumeration.
4446**Signature:** 4960**Signature:**
4447```lua 4961```lua
4448enum LuaTarget 4962enum LuaTarget
4449 "5.1" 4963 "5.1"
4450 "5.2" 4964 "5.2"
4451 "5.3" 4965 "5.3"
4452 "5.4" 4966 "5.4"
4453 "5.5" 4967 "5.5"
4454end 4968end
4455``` 4969```
4456 4970
@@ -4527,7 +5041,7 @@ simplified: boolean
4527 5041
4528## Licence: MIT 5042## Licence: MIT
4529 5043
4530Copyright (c) 2017-2025 Li Jin \<dragon-fly@qq.com\> 5044Copyright (c) 2017-2026 Li Jin \<dragon-fly@qq.com\>
4531 5045
4532Permission is hereby granted, free of charge, to any person obtaining a copy 5046Permission is hereby granted, free of charge, to any person obtaining a copy
4533of this software and associated documentation files (the "Software"), to deal 5047of this software and associated documentation files (the "Software"), to deal
diff --git a/doc/docs/zh/README.md b/doc/docs/zh/README.md
index f5c9811..05b2069 100755
--- a/doc/docs/zh/README.md
+++ b/doc/docs/zh/README.md
@@ -3,6 +3,6 @@ home: true
3heroImage: /image/yuescript.svg 3heroImage: /image/yuescript.svg
4actionText: 快速上手 → 4actionText: 快速上手 →
5actionLink: /zh/doc/ 5actionLink: /zh/doc/
6footer: MIT Licensed | Copyright © 2017-2025 Li Jin 6footer: MIT Licensed | Copyright © 2017-2026 Li Jin
7--- 7---
8 8
diff --git a/doc/docs/zh/doc/README.md b/doc/docs/zh/doc/README.md
index 2968f6e..de5dff1 100755
--- a/doc/docs/zh/doc/README.md
+++ b/doc/docs/zh/doc/README.md
@@ -9,24 +9,24 @@ title: å‚考手册
9 9
10## ä»‹ç» 10## 介ç»
11 11
12月之脚本(YueScript)是一ç§åЍæ€è¯­è¨€ï¼Œå¯ä»¥ç¼–译为Lua。它是[MoonScript](https://github.com/leafo/moonscript)çš„æ–¹è¨€ã€‚ç”¨æœˆä¹‹è„šæœ¬ç¼–å†™çš„ä»£ç æ—¢æœ‰è¡¨çŽ°åŠ›åˆéžå¸¸ç®€æ´ã€‚它适åˆç¼–写一些更易于维护的代ç ï¼Œå¹¶åœ¨åµŒå…¥ Lua 的环境中è¿è¡Œï¼Œå¦‚æ¸¸æˆæˆ–网站æœåŠ¡å™¨ã€‚ 12月之脚本(YueScript)是一ç§åЍæ€è¯­è¨€ï¼Œå¯ä»¥ç¼–译为 Lua。它是 [MoonScript](https://github.com/leafo/moonscript) çš„æ–¹è¨€ã€‚ç”¨æœˆä¹‹è„šæœ¬ç¼–å†™çš„ä»£ç æ—¢æœ‰è¡¨çŽ°åŠ›åˆéžå¸¸ç®€æ´ã€‚它适åˆç¼–写一些更易于维护的代ç ï¼Œå¹¶åœ¨åµŒå…¥ Lua 的环境中è¿è¡Œï¼Œå¦‚æ¸¸æˆæˆ–网站æœåŠ¡å™¨ã€‚
13 13
14Yue(月)是中文中“月亮â€çš„å称。 14Yue(月)是中文中“月亮â€çš„å称。
15 15
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-- 列表推导 32-- 列表推导
@@ -61,17 +61,17 @@ export 🌛 = "月之脚本"
61<YueDisplay> 61<YueDisplay>
62<pre> 62<pre>
63-- 导入语法 63-- 导入语法
64import "yue" as :p, :to_lua 64import p, to_lua from "yue"
65 65
66-- éšå¼å¯¹è±¡ 66-- éšå¼å¯¹è±¡
67inventory = 67inventory =
68 equipment: 68 equipment:
69 * "sword" 69 - "sword"
70 * "shield" 70 - "shield"
71 items: 71 items:
72 * name: "potion" 72 - name: "potion"
73 count: 10 73 count: 10
74 * name: "bread" 74 - name: "bread"
75 count: 3 75 count: 3
76 76
77-- 列表推导 77-- 列表推导
@@ -109,7 +109,7 @@ export 🌛 = "月之脚本"
109 109
110* **Lua 模å—** 110* **Lua 模å—**
111 111
112&emsp;安装 [luarocks](https://luarocks.org),一个Lua模å—的包管ç†å™¨ã€‚ç„¶åŽä½œä¸ºLua模å—å’Œå¯æ‰§è¡Œæ–‡ä»¶å®‰è£…它: 112&emsp;安装 [luarocks](https://luarocks.org),一个 Lua 模å—的包管ç†å™¨ã€‚ç„¶åŽä½œä¸º Lua 模å—å’Œå¯æ‰§è¡Œæ–‡ä»¶å®‰è£…它:
113 113
114``` 114```
115> luarocks install yuescript 115> luarocks install yuescript
@@ -150,14 +150,14 @@ export 🌛 = "月之脚本"
150 150
151### Lua æ¨¡å— 151### Lua 模å—
152 152
153在Lua中使用月之脚本模å—: 153在 Lua 中使用月之脚本模å—:
154 154
155* **用法 1** 155* **用法 1**
156在Lua中引入 "ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶.yue"。 156在 Lua 中引入 "ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶.yue"。
157```Lua 157```Lua
158require("yue")("ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶") 158require("yue")("ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶")
159``` 159```
160当你在åŒä¸€è·¯å¾„下把 "ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶.yue" 编译æˆäº† "ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶.lua" 时,ä»ç„¶å¯ä»¥ä½¿ç”¨è¿™ä¸ªä»£ç åŠ è½½ .lua ä»£ç æ–‡ä»¶ã€‚在其余的月之脚本文件中,åªéœ€æ­£å¸¸ä½¿ç”¨ **require** 或 **import**进行脚本引用å³å¯ã€‚错误消æ¯ä¸­çš„代ç è¡Œå·ä¹Ÿä¼šè¢«æ­£ç¡®å¤„ç†ã€‚ 160当你在åŒä¸€è·¯å¾„下把 "ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶.yue" 编译æˆäº† "ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶.lua" 时,ä»ç„¶å¯ä»¥ä½¿ç”¨è¿™ä¸ªä»£ç åŠ è½½ .lua ä»£ç æ–‡ä»¶ã€‚在其余的月之脚本文件中,åªéœ€æ­£å¸¸ä½¿ç”¨ **require** 或 **import** 进行脚本引用å³å¯ã€‚错误消æ¯ä¸­çš„代ç è¡Œå·ä¹Ÿä¼šè¢«æ­£ç¡®å¤„ç†ã€‚
161 161
162* **用法 2** 162* **用法 2**
163手动引入月之脚本模å—å¹¶é‡å†™é”™è¯¯æ¶ˆæ¯æ¥å¸®åŠ©è°ƒè¯•ã€‚ 163手动引入月之脚本模å—å¹¶é‡å†™é”™è¯¯æ¶ˆæ¯æ¥å¸®åŠ©è°ƒè¯•ã€‚
@@ -172,7 +172,7 @@ end)
172``` 172```
173 173
174* **用法 3** 174* **用法 3**
175在Lua中使用月之脚本编译器功能。 175在 Lua 中使用月之脚本编译器功能。
176```lua 176```lua
177local yue = require("yue") 177local yue = require("yue")
178local codes, err, globals = yue.to_lua([[ 178local codes, err, globals = yue.to_lua([[
@@ -222,12 +222,12 @@ f!
222 䏿·»åŠ ä»»ä½•é€‰é¡¹æ‰§è¡Œå‘½ä»¤å¯ä»¥è¿›å…¥REPL模å¼ï¼Œ 222 䏿·»åŠ ä»»ä½•é€‰é¡¹æ‰§è¡Œå‘½ä»¤å¯ä»¥è¿›å…¥REPL模å¼ï¼Œ
223 在å•è¡Œè¾“å…¥ç¬¦å· '$' å¹¶æ¢è¡ŒåŽï¼Œå¯ä»¥å¼€å§‹æˆ–æ˜¯åœæ­¢å¤šè¡Œè¾“å…¥æ¨¡å¼ 223 在å•è¡Œè¾“å…¥ç¬¦å· '$' å¹¶æ¢è¡ŒåŽï¼Œå¯ä»¥å¼€å§‹æˆ–æ˜¯åœæ­¢å¤šè¡Œè¾“入模å¼
224``` 224```
225&emsp;&emsp;使用案例: 225&emsp;&emsp;使用案例:
226&emsp;&emsp;递归编译当å‰è·¯å¾„下扩展å为 **.yue** çš„æ¯ä¸ªæœˆä¹‹è„šæœ¬æ–‡ä»¶ï¼š **yue .** 226&emsp;&emsp;递归编译当å‰è·¯å¾„下扩展å为 **.yue** çš„æ¯ä¸ªæœˆä¹‹è„šæœ¬æ–‡ä»¶ï¼š **yue .**
227&emsp;&emsp;编译并将结果ä¿å­˜åˆ°ç›®æ ‡è·¯å¾„: **yue -t /target/path/ .** 227&emsp;&emsp;编译并将结果ä¿å­˜åˆ°ç›®æ ‡è·¯å¾„: **yue -t /target/path/ .**
228&emsp;&emsp;编译并ä¿ç•™è°ƒè¯•ä¿¡æ¯ï¼š **yue -l .** 228&emsp;&emsp;编译并ä¿ç•™è°ƒè¯•ä¿¡æ¯ï¼š **yue -l .**
229&emsp;&emsp;编译并生æˆåŽ‹ç¼©ä»£ç ï¼š **yue -m .** 229&emsp;&emsp;编译并生æˆåŽ‹ç¼©ä»£ç ï¼š **yue -m .**
230&emsp;&emsp;直接执行代ç ï¼š **yue -e 'print 123'** 230&emsp;&emsp;直接执行代ç ï¼š **yue -e 'print 123'**
231&emsp;&emsp;执行一个月之脚本文件: **yue -e main.yue** 231&emsp;&emsp;执行一个月之脚本文件: **yue -e main.yue**
232 232
233## å® 233## å®
@@ -407,16 +407,16 @@ print $LINE -- 获å–当å‰ä»£ç è¡Œæ•°ï¼š2
407 407
408```moonscript 408```moonscript
409macro Enum = (...) -> 409macro Enum = (...) ->
410 items = {...} 410 items = {...}
411 itemSet = {item, true for item in *items} 411 itemSet = {item, true for item in *items}
412 (item) -> 412 (item) ->
413 error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item] 413 error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item]
414 "\"#{item}\"" 414 "\"#{item}\""
415 415
416macro BodyType = $Enum( 416macro BodyType = $Enum(
417 Static 417 Static
418 Dynamic 418 Dynamic
419 Kinematic 419 Kinematic
420) 420)
421 421
422print "有效的枚举类型:", $BodyType Static 422print "有效的枚举类型:", $BodyType Static
@@ -425,16 +425,16 @@ print "有效的枚举类型:", $BodyType Static
425<YueDisplay> 425<YueDisplay>
426<pre> 426<pre>
427macro Enum = (...) -> 427macro Enum = (...) ->
428 items = {...} 428 items = {...}
429 itemSet = {item, true for item in *items} 429 itemSet = {item, true for item in *items}
430 (item) -> 430 (item) ->
431 error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item] 431 error "got \"#{item}\", expecting one of #{table.concat items, ', '}" unless itemSet[item]
432 "\"#{item}\"" 432 "\"#{item}\""
433 433
434macro BodyType = $Enum( 434macro BodyType = $Enum(
435 Static 435 Static
436 Dynamic 436 Dynamic
437 Kinematic 437 Kinematic
438) 438)
439 439
440print "有效的枚举类型:", $BodyType Static 440print "有效的枚举类型:", $BodyType Static
@@ -442,9 +442,57 @@ print "有效的枚举类型:", $BodyType Static
442</pre> 442</pre>
443</YueDisplay> 443</YueDisplay>
444 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
445## æ“作符 493## æ“作符
446 494
447Lua的所有二元和一元æ“作符在月之脚本中都是å¯ç”¨çš„。此外,**!=** ç¬¦å·æ˜¯ **~=** 的别å,而 **\\** 或 **::** å‡å¯ç”¨äºŽç¼–写链å¼å‡½æ•°è°ƒç”¨ï¼Œå¦‚写作 `tb\func!` 或 `tb::func!`。此外月之脚本还æä¾›äº†ä¸€äº›å…¶ä»–特殊的æ“作符,以编写更具表达力的代ç ã€‚ 495Lua 的所有二元和一元æ“作符在月之脚本中都是å¯ç”¨çš„。此外,**!=** ç¬¦å·æ˜¯ **~=** 的别å,而 **\\** 或 **::** å‡å¯ç”¨äºŽç¼–写链å¼å‡½æ•°è°ƒç”¨ï¼Œå¦‚写作 `tb\func!` 或 `tb::func!`。此外月之脚本还æä¾›äº†ä¸€äº›å…¶ä»–特殊的æ“作符,以编写更具表达力的代ç ã€‚
448 496
449```moonscript 497```moonscript
450tb\func! if tb ~= nil 498tb\func! if tb ~= nil
@@ -484,56 +532,56 @@ print 1 <= a <= 10
484 532
485```moonscript 533```moonscript
486v = (x) -> 534v = (x) ->
487 print x 535 print x
488 x 536 x
489 537
490print v(1) < v(2) <= v(3) 538print v(1) < v(2) <= v(3)
491--[[ 539--[[
492 输出: 540 输出:
493 2 541 2
494 1 542 1
495 3 543 3
496 true 544 true
497]] 545]]
498 546
499print v(1) > v(2) <= v(3) 547print v(1) > v(2) <= v(3)
500--[[ 548--[[
501 输出: 549 输出:
502 2 550 2
503 1 551 1
504 false 552 false
505]] 553]]
506``` 554```
507<YueDisplay> 555<YueDisplay>
508<pre> 556<pre>
509v = (x) -> 557v = (x) ->
510 print x 558 print x
511 x 559 x
512 560
513print v(1) < v(2) <= v(3) 561print v(1) < v(2) <= v(3)
514--[[ 562--[[
515 输出: 563 输出:
516 2 564 2
517 1 565 1
518 3 566 3
519 true 567 true
520]] 568]]
521 569
522print v(1) > v(2) <= v(3) 570print v(1) > v(2) <= v(3)
523--[[ 571--[[
524 输出: 572 输出:
525 2 573 2
526 1 574 1
527 false 575 false
528]] 576]]
529</pre> 577</pre>
530</YueDisplay> 578</YueDisplay>
531 579
532在上é¢çš„例å­é‡Œï¼Œä¸­é—´çš„表达å¼`v(2)`仅被计算一次,如果把表达å¼å†™æˆ`v(1) < v(2) and v(2) <= v(3)`的方å¼ï¼Œä¸­é—´çš„`v(2)`æ‰ä¼šè¢«è®¡ç®—ä¸¤æ¬¡ã€‚åœ¨é“¾å¼æ¯”较中,求值的顺åºå¾€å¾€æ˜¯æœªå®šä¹‰çš„。所以强烈建议ä¸è¦åœ¨é“¾å¼æ¯”è¾ƒä¸­ä½¿ç”¨å…·æœ‰å‰¯ä½œç”¨ï¼ˆæ¯”å¦‚åšæ‰“å°æ“作)的表达å¼ã€‚如果需è¦ä½¿ç”¨æœ‰å‰¯ä½œç”¨çš„函数,应明确使用短路 `and` è¿ç®—符æ¥åšè¿žæŽ¥ã€‚ 580在上é¢çš„例å­é‡Œï¼Œä¸­é—´çš„è¡¨è¾¾å¼ `v(2)` 仅被计算一次,如果把表达å¼å†™æˆ `v(1) < v(2) and v(2) <= v(3)` 的方å¼ï¼Œä¸­é—´çš„ `v(2)` æ‰ä¼šè¢«è®¡ç®—ä¸¤æ¬¡ã€‚åœ¨é“¾å¼æ¯”较中,求值的顺åºå¾€å¾€æ˜¯æœªå®šä¹‰çš„。所以强烈建议ä¸è¦åœ¨é“¾å¼æ¯”è¾ƒä¸­ä½¿ç”¨å…·æœ‰å‰¯ä½œç”¨ï¼ˆæ¯”å¦‚åšæ‰“å°æ“作)的表达å¼ã€‚如果需è¦ä½¿ç”¨æœ‰å‰¯ä½œç”¨çš„函数,应明确使用短路 `and` è¿ç®—符æ¥åšè¿žæŽ¥ã€‚
533 581
534### 表追加 582### 表追加
535 583
536**[] =** æ“作符用于å‘Luaè¡¨çš„æœ€åŽæ’入值。 584**[] =** æ“ä½œç¬¦ç”¨äºŽå‘ Lua è¡¨çš„æœ€åŽæ’入值。
537 585
538```moonscript 586```moonscript
539tab = [] 587tab = []
@@ -546,19 +594,36 @@ tab[] = "Value"
546</pre> 594</pre>
547</YueDisplay> 595</YueDisplay>
548 596
597你还å¯ä»¥ä½¿ç”¨å±•å¼€æ“作符 `...` æ¥å°†ä¸€ä¸ªåˆ—表中的所有元素追加到å¦ä¸€ä¸ªåˆ—表中:
598
599```moonscript
600tbA = [1, 2, 3]
601tbB = [4, 5, 6]
602tbA[] = ...tbB
603-- tbA 现在为 [1, 2, 3, 4, 5, 6]
604```
605<YueDisplay>
606<pre>
607tbA = [1, 2, 3]
608tbB = [4, 5, 6]
609tbA[] = ...tbB
610-- tbA 现在为 [1, 2, 3, 4, 5, 6]
611</pre>
612</YueDisplay>
613
549### 表扩展 614### 表扩展
550 615
551ä½ å¯ä»¥ä½¿ç”¨å‰ç½® `...` æ“作符在Lua表中æ’入数组表或哈希表。 616ä½ å¯ä»¥ä½¿ç”¨å‰ç½® `...` æ“作符在 Lua 表中æ’入数组表或哈希表。
552 617
553```moonscript 618```moonscript
554parts = 619parts =
555 * "shoulders" 620 * "shoulders"
556 * "knees" 621 * "knees"
557lyrics = 622lyrics =
558 * "head" 623 * "head"
559 * ...parts 624 * ...parts
560 * "and" 625 * "and"
561 * "toes" 626 * "toes"
562 627
563copy = {...other} 628copy = {...other}
564 629
@@ -569,13 +634,13 @@ merge = {...a, ...b}
569<YueDisplay> 634<YueDisplay>
570<pre> 635<pre>
571parts = 636parts =
572 * "shoulders" 637 * "shoulders"
573 * "knees" 638 * "knees"
574lyrics = 639lyrics =
575 * "head" 640 * "head"
576 * ...parts 641 * ...parts
577 * "and" 642 * "and"
578 * "toes" 643 * "toes"
579 644
580copy = {...other} 645copy = {...other}
581 646
@@ -585,12 +650,29 @@ merge = {...a, ...b}
585</pre> 650</pre>
586</YueDisplay> 651</YueDisplay>
587 652
653### 表åå‘索引
654
655ä½ å¯ä»¥ä½¿ç”¨ **#** æ“作符æ¥åå‘索引表中的元素。
656
657```moonscript
658last = data.items[#]
659second_last = data.items[#-1]
660data.items[#] = 1
661```
662<YueDisplay>
663<pre>
664last = data.items[#]
665second_last = data.items[#-1]
666data.items[#] = 1
667</pre>
668</YueDisplay>
669
588### 元表 670### 元表
589 671
590**<>** æ“ä½œç¬¦å¯æä¾›å…ƒè¡¨æ“ä½œçš„å¿«æ·æ–¹å¼ã€‚ 672**<>** æ“ä½œç¬¦å¯æä¾›å…ƒè¡¨æ“ä½œçš„å¿«æ·æ–¹å¼ã€‚
591 673
592* **元表创建** 674* **元表创建**
593ä½¿ç”¨ç©ºæ‹¬å· **<>** 或被 **<>** 包围的元方法键创建普通的Lua表。 675ä½¿ç”¨ç©ºæ‹¬å· **<>** 或被 **<>** 包围的元方法键创建普通的 Lua 表。
594 676
595```moonscript 677```moonscript
596mt = {} 678mt = {}
@@ -732,7 +814,7 @@ readFile "example.txt"
732 814
733### 空值åˆå¹¶ 815### 空值åˆå¹¶
734 816
735如果其左æ“ä½œæ•°ä¸æ˜¯**nil**,则nilåˆå¹¶è¿ç®—符 **??** 返回其左æ“作数的值;å¦åˆ™ï¼Œå®ƒå°†è®¡ç®—峿“作数并返回其结果。如果左æ“作数计算结果为éžnil的值,**??** è¿ç®—符将ä¸å†è®¡ç®—其峿“作数。 817如果其左æ“ä½œæ•°ä¸æ˜¯ **nil**,则nilåˆå¹¶è¿ç®—符 **??** 返回其左æ“作数的值;å¦åˆ™ï¼Œå®ƒå°†è®¡ç®—峿“作数并返回其结果。如果左æ“ä½œæ•°è®¡ç®—ç»“æžœä¸ºéž nil 的值,**??** è¿ç®—符将ä¸å†è®¡ç®—其峿“作数。
736```moonscript 818```moonscript
737local a, b, c, d 819local a, b, c, d
738a = b ?? c ?? d 820a = b ?? c ?? d
@@ -751,67 +833,87 @@ a ??= false
751 833
752### éšå¼å¯¹è±¡ 834### éšå¼å¯¹è±¡
753 835
754ä½ å¯ä»¥åœ¨è¡¨æ ¼å—å†…ä½¿ç”¨ç¬¦å· **\*** 开始编写一系列éšå¼ç»“构。如果你正在创建éšå¼å¯¹è±¡ï¼Œå¯¹è±¡çš„字段必须具有相åŒçš„缩进。 836ä½ å¯ä»¥åœ¨è¡¨æ ¼å—å†…ä½¿ç”¨ç¬¦å· **\*** 或是 **-** 开始编写一系列éšå¼ç»“构。如果你正在创建éšå¼å¯¹è±¡ï¼Œå¯¹è±¡çš„字段必须具有相åŒçš„缩进。
837
755```moonscript 838```moonscript
839-- 赋值时使用éšå¼å¯¹è±¡
756list = 840list =
757 * 1 841 * 1
758 * 2 842 * 2
759 * 3 843 * 3
760 844
845-- 函数调用时使用éšå¼å¯¹è±¡
761func 846func
762 * 1 847 * 1
763 * 2 848 * 2
764 * 3 849 * 3
765 850
851-- 返回时使用éšå¼å¯¹è±¡
852f = ->
853 return
854 * 1
855 * 2
856 * 3
857
858-- 表格时使用éšå¼å¯¹è±¡
766tb = 859tb =
767 name: "abc" 860 name: "abc"
768 861
769 values: 862 values:
770 * "a" 863 - "a"
771 * "b" 864 - "b"
772 * "c" 865 - "c"
773 866
774 objects: 867 objects:
775 * name: "a" 868 - name: "a"
776 value: 1 869 value: 1
777 func: => @value + 1 870 func: => @value + 1
778 tb: 871 tb:
779 fieldA: 1 872 fieldA: 1
780 873
781 * name: "b" 874 - name: "b"
782 value: 2 875 value: 2
783 func: => @value + 2 876 func: => @value + 2
784 tb: { } 877 tb: { }
785
786``` 878```
787<YueDisplay> 879<YueDisplay>
788<pre> 880<pre>
881-- 赋值时使用éšå¼å¯¹è±¡
789list = 882list =
790 * 1 883 * 1
791 * 2 884 * 2
792 * 3 885 * 3
793 886
887-- 函数调用时使用éšå¼å¯¹è±¡
794func 888func
795 * 1 889 * 1
796 * 2 890 * 2
797 * 3 891 * 3
798 892
893-- 返回时使用éšå¼å¯¹è±¡
894f = ->
895 return
896 * 1
897 * 2
898 * 3
899
900-- 表格时使用éšå¼å¯¹è±¡
799tb = 901tb =
800 name: "abc" 902 name: "abc"
801 903
802 values: 904 values:
803 * "a" 905 - "a"
804 * "b" 906 - "b"
805 * "c" 907 - "c"
806 908
807 objects: 909 objects:
808 * name: "a" 910 - name: "a"
809 value: 1 911 value: 1
810 func: => @value + 1 912 func: => @value + 1
811 tb: 913 tb:
812 fieldA: 1 914 fieldA: 1
813 915
814 * name: "b" 916 - name: "b"
815 value: 2 917 value: 2
816 func: => @value + 2 918 func: => @value + 2
817 tb: { } 919 tb: { }
@@ -991,7 +1093,7 @@ export default ->
991 1093
992## 赋值 1094## 赋值
993 1095
994月之脚本中定义的å˜é‡æ˜¯åЍæ€ç±»åž‹çš„,并默认为局部å˜é‡ã€‚但你å¯ä»¥é€šè¿‡**local**å’Œ**global**å£°æ˜Žæ¥æ”¹å˜å£°æ˜Žå˜é‡çš„作用范围。 1096月之脚本中定义的å˜é‡æ˜¯åЍæ€ç±»åž‹çš„,并默认为局部å˜é‡ã€‚但你å¯ä»¥é€šè¿‡ **local** å’Œ **global** å£°æ˜Žæ¥æ”¹å˜å£°æ˜Žå˜é‡çš„作用范围。
995 1097
996```moonscript 1098```moonscript
997hello = "world" 1099hello = "world"
@@ -1120,9 +1222,9 @@ do
1120 1222
1121## 解构赋值 1223## 解构赋值
1122 1224
1123解构赋值是一ç§å¿«é€Ÿä»ŽLua表中按å称或基于数组中的ä½ç½®æå–值的方法。 1225解构赋值是一ç§å¿«é€Ÿä»Ž Lua 表中按å称或基于数组中的ä½ç½®æå–值的方法。
1124 1226
1125通常当你看到一个字é¢é‡çš„Lua表,比如{1,2,3},它ä½äºŽèµ‹å€¼çš„å³ä¾§ï¼Œå› ä¸ºå®ƒæ˜¯ä¸€ä¸ªå€¼ã€‚解构赋值语å¥çš„写法就是交æ¢äº†å­—é¢é‡Lua表的角色,并将其放在赋值语å¥çš„左侧。 1227通常当你看到一个字é¢é‡çš„ Lua 表,比如 `{1,2,3}`,它ä½äºŽèµ‹å€¼çš„å³ä¾§ï¼Œå› ä¸ºå®ƒæ˜¯ä¸€ä¸ªå€¼ã€‚解构赋值语å¥çš„写法就是交æ¢äº†å­—é¢é‡ Lua 表的角色,并将其放在赋值语å¥çš„左侧。
1126 1228
1127最好是通过示例æ¥è§£é‡Šã€‚以下是如何从表格中解包å‰ä¸¤ä¸ªå€¼çš„æ–¹æ³•: 1229最好是通过示例æ¥è§£é‡Šã€‚以下是如何从表格中解包å‰ä¸¤ä¸ªå€¼çš„æ–¹æ³•:
1128 1230
@@ -1221,7 +1323,7 @@ print first, second, color
1221</pre> 1323</pre>
1222</YueDisplay> 1324</YueDisplay>
1223 1325
1224有时候我们会需è¦ä»ŽLua表中æå–值并将它们赋给与键åŒå的局部å˜é‡ã€‚为了é¿å…编写é‡å¤ä»£ç ï¼Œæˆ‘们å¯ä»¥ä½¿ç”¨ **:** å‰ç¼€æ“作符: 1326有时候我们会需è¦ä»Ž Lua 表中æå–值并将它们赋给与键åŒå的局部å˜é‡ã€‚为了é¿å…编写é‡å¤ä»£ç ï¼Œæˆ‘们å¯ä»¥ä½¿ç”¨ **:** å‰ç¼€æ“作符:
1225 1327
1226```moonscript 1328```moonscript
1227{:concat, :insert} = table 1329{:concat, :insert} = table
@@ -1265,9 +1367,55 @@ print first, second, color
1265</pre> 1367</pre>
1266</YueDisplay> 1368</YueDisplay>
1267 1369
1268### 在其它地方的解构 1370### 范围解构
1371
1372ä½ å¯ä»¥ä½¿ç”¨å±•å¼€è¿ç®—符 `...` åœ¨åˆ—è¡¨è§£æž„ä¸­æ¥æ•获一个范围的值到å­åˆ—表中。这在当你想è¦ä»Žåˆ—表的开头和结尾æå–ç‰¹å®šå…ƒç´ ï¼ŒåŒæ—¶æ”¶é›†ä¸­é—´çš„元素时éžå¸¸æœ‰ç”¨ã€‚
1373
1374```moonscript
1375orders = ["first", "second", "third", "fourth", "last"]
1376[first, ...bulk, last] = orders
1377print first -- 打å°: first
1378print bulk -- 打å°: {"second", "third", "fourth"}
1379print last -- 打å°: last
1380```
1381<YueDisplay>
1382<pre>
1383orders = ["first", "second", "third", "fourth", "last"]
1384[first, ...bulk, last] = orders
1385print first -- 打å°: first
1386print bulk -- 打å°: {"second", "third", "fourth"}
1387print last -- 打å°: last
1388</pre>
1389</YueDisplay>
1269 1390
1270解构也å¯ä»¥å‡ºçŽ°åœ¨å…¶å®ƒéšå¼è¿›è¡Œèµ‹å€¼çš„åœ°æ–¹ã€‚ä¸€ä¸ªä¾‹å­æ˜¯ç”¨åœ¨for循环: 1391展开è¿ç®—符å¯ä»¥ç”¨åœ¨ä¸åŒçš„ä½ç½®æ¥æ•获ä¸åŒçš„范围,并且你å¯ä»¥ä½¿ç”¨ `_` 作为å ä½ç¬¦æ¥è¡¨ç¤ºä½ æƒ³è·³è¿‡å¯¹åº”范围的æ•获:
1392
1393```moonscript
1394-- æ•获第一个元素之åŽçš„æ‰€æœ‰å…ƒç´ 
1395[first, ...rest] = orders
1396
1397-- æ•获最åŽä¸€ä¸ªå…ƒç´ ä¹‹å‰çš„æ‰€æœ‰å…ƒç´ 
1398[...start, last] = orders
1399
1400-- è·³è¿‡ä¸­é—´çš„å…ƒç´ ï¼Œåªæ•获第一个和最åŽä¸€ä¸ªå…ƒç´ 
1401[first, ..._, last] = orders
1402```
1403<YueDisplay>
1404<pre>
1405-- æ•获第一个元素之åŽçš„æ‰€æœ‰å…ƒç´ 
1406[first, ...rest] = orders
1407
1408-- æ•获最åŽä¸€ä¸ªå…ƒç´ ä¹‹å‰çš„æ‰€æœ‰å…ƒç´ 
1409[...start, last] = orders
1410
1411-- è·³è¿‡ä¸­é—´çš„å…ƒç´ ï¼Œåªæ•获第一个和最åŽä¸€ä¸ªå…ƒç´ 
1412[first, ..._, last] = orders
1413</pre>
1414</YueDisplay>
1415
1416### 在其它地方的解构赋值
1417
1418解构赋值也å¯ä»¥å‡ºçŽ°åœ¨å…¶å®ƒéšå¼è¿›è¡Œèµ‹å€¼çš„åœ°æ–¹ã€‚ä¸€ä¸ªä¾‹å­æ˜¯ç”¨åœ¨ for 循环中:
1271 1419
1272```moonscript 1420```moonscript
1273tuples = [ 1421tuples = [
@@ -1290,7 +1438,7 @@ for [left, right] in *tuples
1290</pre> 1438</pre>
1291</YueDisplay> 1439</YueDisplay>
1292 1440
1293æˆ‘ä»¬çŸ¥é“æ•°ç»„表中的æ¯ä¸ªå…ƒç´ éƒ½æ˜¯ä¸€ä¸ªä¸¤é¡¹çš„元组,所以我们å¯ä»¥ç›´æŽ¥åœ¨for语å¥çš„åç§°å­å¥ä¸­ä½¿ç”¨è§£æž„æ¥è§£åŒ…它。 1441æˆ‘ä»¬çŸ¥é“æ•°ç»„表中的æ¯ä¸ªå…ƒç´ éƒ½æ˜¯ä¸€ä¸ªä¸¤é¡¹çš„元组,所以我们å¯ä»¥ç›´æŽ¥åœ¨ for 语å¥çš„åç§°å­å¥ä¸­ä½¿ç”¨è§£æž„æ¥è§£åŒ…它。
1294 1442
1295## If 赋值 1443## If 赋值
1296 1444
@@ -1358,7 +1506,7 @@ while byte := stream\read_one!
1358 1506
1359## å¯å˜å‚数赋值 1507## å¯å˜å‚数赋值
1360 1508
1361ä½ å¯ä»¥å°†å‡½æ•°è¿”回的结果赋值给一个å¯å˜å‚æ•°ç¬¦å· `...`。然åŽä½¿ç”¨Lua的方å¼è®¿é—®å…¶å†…容。 1509ä½ å¯ä»¥å°†å‡½æ•°è¿”回的结果赋值给一个å¯å˜å‚æ•°ç¬¦å· `...`。然åŽä½¿ç”¨ Lua 的方å¼è®¿é—®å…¶å†…容。
1362```moonscript 1510```moonscript
1363list = [1, 2, 3, 4, 5] 1511list = [1, 2, 3, 4, 5]
1364fn = (ok) -> ok, table.unpack list 1512fn = (ok) -> ok, table.unpack list
@@ -1435,7 +1583,7 @@ func --[[端å£]] 3000, --[[ip]] "192.168.1.1"
1435 1583
1436## é”™è¯¯å¤„ç† 1584## 错误处ç†
1437 1585
1438用于统一进行Lua错误处ç†çš„便æ·è¯­æ³•。 1586用于统一进行 Lua 错误处ç†çš„便æ·è¯­æ³•。
1439 1587
1440```moonscript 1588```moonscript
1441try 1589try
@@ -1494,9 +1642,50 @@ catch err
1494</pre> 1642</pre>
1495</YueDisplay> 1643</YueDisplay>
1496 1644
1645### 错误处ç†ç®€åŒ–
1646
1647`try?` 是 `try` 的功能简化语法,它ä¸å†è¿”回 `try` 语å¥çš„布尔状æ€ï¼Œå¹¶åœ¨æˆåŠŸæ—¶ç›´æŽ¥è¿”å›ž `try` 代ç å—的结果,失败时返回 `nil` 值而éžé”™è¯¯å¯¹è±¡ã€‚
1648
1649```moonscript
1650a, b, c = try? func!
1651
1652-- 与空值åˆå¹¶è¿ç®—符一起使用
1653a = (try? func!) ?? "default"
1654
1655-- ä½œä¸ºå‡½æ•°å‚æ•°
1656f try? func!
1657
1658-- 带 catch å—çš„ try!
1659f try?
1660 print 123
1661 func!
1662catch e
1663 print e
1664 e
1665```
1666<YueDisplay>
1667<pre>
1668a, b, c = try? func!
1669
1670-- 与空值åˆå¹¶è¿ç®—符一起使用
1671a = (try? func!) ?? "default"
1672
1673-- ä½œä¸ºå‡½æ•°å‚æ•°
1674f try? func!
1675
1676-- 带 catch å—çš„ try!
1677f try?
1678 print 123
1679 func!
1680catch e
1681 print e
1682 e
1683</pre>
1684</YueDisplay>
1685
1497## 属性 1686## 属性
1498 1687
1499月之脚本现在æä¾›äº†Lua 5.4新增的å«åšå±žæ€§çš„语法支æŒã€‚在月之脚本编译到的Lua目标版本低于5.4时,你ä»ç„¶å¯ä»¥åŒæ—¶ä½¿ç”¨`const`å’Œ`close`çš„å±žæ€§å£°æ˜Žè¯­æ³•ï¼Œå¹¶èŽ·å¾—å¸¸é‡æ£€æŸ¥å’Œä½œç”¨åŸŸå›žè°ƒçš„功能。 1688月之脚本现在æä¾›äº† Lua 5.4 新增的å«åšå±žæ€§çš„语法支æŒã€‚在月之脚本编译到的 Lua 目标版本低于 5.4 时,你ä»ç„¶å¯ä»¥åŒæ—¶ä½¿ç”¨`const` å’Œ `close` çš„å±žæ€§å£°æ˜Žè¯­æ³•ï¼Œå¹¶èŽ·å¾—å¸¸é‡æ£€æŸ¥å’Œä½œç”¨åŸŸå›žè°ƒçš„功能。
1500 1689
1501```moonscript 1690```moonscript
1502const a = 123 1691const a = 123
@@ -1537,9 +1726,9 @@ global const Constant = 123
1537 1726
1538## å­—é¢é‡ 1727## å­—é¢é‡
1539 1728
1540Lua中的所有基本字é¢é‡éƒ½å¯ä»¥åœ¨æœˆä¹‹è„šæœ¬ä¸­ä½¿ç”¨ã€‚åŒ…æ‹¬æ•°å­—ã€å­—符串ã€å¸ƒå°”值和**nil**。 1729Lua 中的所有基本字é¢é‡éƒ½å¯ä»¥åœ¨æœˆä¹‹è„šæœ¬ä¸­ä½¿ç”¨ã€‚åŒ…æ‹¬æ•°å­—ã€å­—符串ã€å¸ƒå°”值和 **nil**。
1541 1730
1542但与Luaä¸åŒçš„æ˜¯ï¼Œå•引å·å’ŒåŒå¼•å·å­—符串内部å…许有æ¢è¡Œï¼š 1731但与 Lua ä¸åŒçš„æ˜¯ï¼Œå•引å·å’ŒåŒå¼•å·å­—符串内部å…许有æ¢è¡Œï¼š
1543 1732
1544```moonscript 1733```moonscript
1545some_string = "这是一个字符串 1734some_string = "这是一个字符串
@@ -1574,6 +1763,66 @@ binary = 0B10011
1574<pre> 1763<pre>
1575integer = 1_000_000 1764integer = 1_000_000
1576hex = 0xEF_BB_BF 1765hex = 0xEF_BB_BF
1766binary = 0B10011
1767</pre>
1768</YueDisplay>
1769
1770### YAML 风格字符串
1771
1772使用 `|` å‰ç¼€æ ‡è®°ä¸€ä¸ªå¤šè¡Œ YAML 风格字符串:
1773
1774```moonscript
1775str = |
1776 key: value
1777 list:
1778 - item1
1779 - #{expr}
1780```
1781<YueDisplay>
1782<pre>
1783str = |
1784 key: value
1785 list:
1786 - item1
1787 - #{expr}
1788</pre>
1789</YueDisplay>
1790
1791其效果类似于原生 Lua çš„å¤šè¡Œæ‹¼æŽ¥ï¼Œæ‰€æœ‰æ–‡æœ¬ï¼ˆå«æ¢è¡Œï¼‰å°†è¢«ä¿ç•™ä¸‹æ¥ï¼Œå¹¶æ”¯æŒ `#{...}` 语法,通过 `tostring(expr)` æ’入表达å¼ç»“果。
1792
1793YAML é£Žæ ¼çš„å¤šè¡Œå­—ç¬¦ä¸²ä¼šè‡ªåŠ¨æ£€æµ‹é¦–è¡ŒåŽæœ€å°çš„公共缩进,并从所有行中删除该å‰ç¼€ç©ºç™½å­—符。这让你å¯ä»¥åœ¨ä»£ç ä¸­å¯¹é½æ–‡æœ¬ï¼Œä½†è¾“出字符串ä¸ä¼šå¸¦å¤šä½™ç¼©è¿›ã€‚
1794
1795```moonscript
1796fn = ->
1797 str = |
1798 foo:
1799 bar: baz
1800 return str
1801```
1802<YueDisplay>
1803<pre>
1804fn = ->
1805 str = |
1806 foo:
1807 bar: baz
1808 return str
1809</pre>
1810</YueDisplay>
1811
1812输出字符串中的 foo: 对é½åˆ°è¡Œé¦–,ä¸ä¼šå¸¦æœ‰å‡½æ•°ç¼©è¿›ç©ºæ ¼ã€‚ä¿ç•™å†…部缩进的相对结构,适åˆä¹¦å†™ç»“构化嵌套样å¼çš„内容。
1813
1814支æŒè‡ªåЍ处ç†å­—符中的引å·ã€åæ–œæ ç­‰ç‰¹æ®Šç¬¦å·ï¼Œæ— éœ€æ‰‹åŠ¨è½¬ä¹‰ï¼š
1815
1816```moonscript
1817str = |
1818 path: "C:\Program Files\App"
1819 note: 'He said: "#{Hello}!"'
1820```
1821<YueDisplay>
1822<pre>
1823str = |
1824 path: "C:\Program Files\App"
1825 note: 'He said: "#{Hello}!"'
1577</pre> 1826</pre>
1578</YueDisplay> 1827</YueDisplay>
1579 1828
@@ -1678,7 +1927,7 @@ print "数字的和是", sum 10, 20
1678</pre> 1927</pre>
1679</YueDisplay> 1928</YueDisplay>
1680 1929
1681如果你需è¦åšæ˜¾å¼è¿”回,å¯ä»¥ä½¿ç”¨return关键字: 1930如果你需è¦åšæ˜¾å¼è¿”回,å¯ä»¥ä½¿ç”¨ return 关键字:
1682 1931
1683```moonscript 1932```moonscript
1684sum = (x, y) -> return x + y 1933sum = (x, y) -> return x + y
@@ -1704,7 +1953,7 @@ a, b = mystery 10, 20
1704 1953
1705### 粗箭头 1954### 粗箭头
1706 1955
1707因为在Lua中调用方法时,ç»å¸¸ä¹ æƒ¯å°†å¯¹è±¡ä½œä¸ºç¬¬ä¸€ä¸ªå‚数传入,所以月之脚本æä¾›äº†ä¸€ç§ç‰¹æ®Šçš„语法æ¥åˆ›å»ºè‡ªåŠ¨åŒ…å«self傿•°çš„函数。 1956因为在 Lua 中调用方法时,ç»å¸¸ä¹ æƒ¯å°†å¯¹è±¡ä½œä¸ºç¬¬ä¸€ä¸ªå‚数传入,所以月之脚本æä¾›äº†ä¸€ç§ç‰¹æ®Šçš„语法æ¥åˆ›å»ºè‡ªåŠ¨åŒ…å« self 傿•°çš„函数。
1708 1957
1709```moonscript 1958```moonscript
1710func = (num) => @value + num 1959func = (num) => @value + num
@@ -1717,7 +1966,7 @@ func = (num) => @value + num
1717 1966
1718### 傿•°é»˜è®¤å€¼ 1967### 傿•°é»˜è®¤å€¼
1719 1968
1720å¯ä»¥ä¸ºå‡½æ•°çš„傿•°æä¾›é»˜è®¤å€¼ã€‚å¦‚æžœå‚æ•°çš„值为nilï¼Œåˆ™ç¡®å®šè¯¥å‚æ•°ä¸ºç©ºã€‚任何具有默认值的nil傿•°åœ¨å‡½æ•°ä½“è¿è¡Œä¹‹å‰éƒ½ä¼šè¢«æ›¿æ¢ã€‚ 1969å¯ä»¥ä¸ºå‡½æ•°çš„傿•°æä¾›é»˜è®¤å€¼ã€‚å¦‚æžœå‚æ•°çš„值为 nilï¼Œåˆ™ç¡®å®šè¯¥å‚æ•°ä¸ºç©ºã€‚任何具有默认值的 nil 傿•°åœ¨å‡½æ•°ä½“è¿è¡Œä¹‹å‰éƒ½ä¼šè¢«æ›¿æ¢ã€‚
1721 1970
1722```moonscript 1971```moonscript
1723my_function = (name = "æŸç‰©", height = 100) -> 1972my_function = (name = "æŸç‰©", height = 100) ->
@@ -1789,7 +2038,7 @@ my_func 5, 6, 7,
1789</pre> 2038</pre>
1790</YueDisplay> 2039</YueDisplay>
1791 2040
1792因为Lua表也使用逗å·ä½œä¸ºåˆ†éš”符,这ç§ç¼©è¿›è¯­æ³•有助于让值æˆä¸ºå‚æ•°åˆ—è¡¨çš„ä¸€éƒ¨åˆ†ï¼Œè€Œä¸æ˜¯Lua表的一部分。 2041因为 Lua 表也使用逗å·ä½œä¸ºåˆ†éš”符,这ç§ç¼©è¿›è¯­æ³•有助于让值æˆä¸ºå‚æ•°åˆ—è¡¨çš„ä¸€éƒ¨åˆ†ï¼Œè€Œä¸æ˜¯ Lua 表的一部分。
1793 2042
1794```moonscript 2043```moonscript
1795x = [ 2044x = [
@@ -1856,6 +2105,138 @@ if func 1, 2, 3,
1856</pre> 2105</pre>
1857</YueDisplay> 2106</YueDisplay>
1858 2107
2108### 傿•°è§£æž„
2109
2110月之脚本支æŒåœ¨å‡½æ•°å½¢å‚ä½ç½®å¯¹ä¼ å…¥å¯¹è±¡è¿›è¡Œè§£æž„。适用两类解构表å­é¢é‡ï¼š
2111
2112- 使用 {} 包裹的字é¢é‡/对象形å‚ï¼Œæ”¯æŒæä¾›èŽ·å¾—ç©ºå­—æ®µæ—¶çš„é»˜è®¤å€¼ï¼ˆä¾‹å¦‚ {:a, :b}ã€{a: a1 = 123})。
2113
2114- æ—  {} 包裹ã€ä»¥é”®å€¼/简写键åºåˆ—开头,直至é‡åˆ°å…¶å®ƒè¡¨è¾¾å¼ç»ˆæ­¢ï¼ˆä¾‹å¦‚ :a, b: b1, :c),表示从åŒä¸€ä¸ªå¯¹è±¡ä¸­è§£æž„多个字段。
2115
2116```moonscript
2117f1 = (:a, :b, :c) ->
2118 print a, b, c
2119
2120f1 a: 1, b: "2", c: {}
2121
2122f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) ->
2123 print a1, b, c
2124
2125arg1 = {a: 0}
2126f2 arg1, arg2
2127```
2128<YueDisplay>
2129<pre>
2130f1 = (:a, :b, :c) ->
2131 print a, b, c
2132
2133f1 a: 1, b: "2", c: {}
2134
2135f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) ->
2136 print a1, b, c
2137
2138arg1 = {a: 0}
2139f2 arg1, arg2
2140</pre>
2141</YueDisplay>
2142
2143### å‰ç½®è¿”回表达å¼
2144
2145在深度嵌套的函数体中,为了æå‡è¿”回值的å¯è¯»æ€§åŠç¼–写便利性,我们新增了 “å‰ç½®è¿”回表达å¼â€ 语法。其形å¼å¦‚下:
2146
2147```moon
2148findFirstEven = (list): nil ->
2149 for item in *list
2150 if type(item) == "table"
2151 for sub in *item
2152 if sub % 2 == 0
2153 return sub
2154```
2155<YueDisplay>
2156<pre>
2157findFirstEven = (list): nil ->
2158 for item in *list
2159 if type(item) == "table"
2160 for sub in *item
2161 if sub % 2 == 0
2162 return sub
2163</pre>
2164</YueDisplay>
2165
2166这个写法等价于:
2167
2168```moon
2169findFirstEven = (list) ->
2170 for item in *list
2171 if type(item) == "table"
2172 for sub in *item
2173 if sub % 2 == 0
2174 return sub
2175 nil
2176```
2177<YueDisplay>
2178<pre>
2179findFirstEven = (list) ->
2180 for item in *list
2181 if type(item) == "table"
2182 for sub in *item
2183 if sub % 2 == 0
2184 return sub
2185 nil
2186</pre>
2187</YueDisplay>
2188
2189唯一的区别在于:你å¯ä»¥å°†å‡½æ•°çš„è¿”å›žå€¼è¡¨è¾¾å¼æå‰å†™åœ¨ `->` 或 `=>` å‰ï¼Œç”¨ä»¥æŒ‡ç¤ºè¯¥å‡½æ•°åº”éšå¼è¿”回该表达å¼çš„值。这样å³ä½¿åœ¨å¤šå±‚循环或æ¡ä»¶åˆ¤æ–­çš„场景下,也无需编写尾行悬挂的返回表达å¼ï¼Œé€»è¾‘结构会更加直观清晰。
2190
2191### 命åå˜é•¿å‚æ•°
2192
2193ä½ å¯ä»¥ä½¿ç”¨ `(...t) ->` 语法æ¥å°†å˜é•¿å‚数自动存储到一个命åè¡¨ä¸­ã€‚è¿™ä¸ªè¡¨ä¼šåŒ…å«æ‰€æœ‰ä¼ å…¥çš„傿•°ï¼ˆåŒ…括 `nil` 值),并且会在表的 `n` å­—æ®µä¸­å­˜å‚¨å®žé™…ä¼ å…¥çš„å‚æ•°ä¸ªæ•°ï¼ˆåŒ…括 `nil` 值在内的个数)。
2194
2195```moonscript
2196f = (...t) ->
2197 print "傿•°ä¸ªæ•°:", t.n
2198 print "表长度:", #t
2199 for i = 1, t.n
2200 print t[i]
2201
2202f 1, 2, 3
2203f "a", "b", "c", "d"
2204f!
2205
2206-- 处ç†åŒ…å« nil 的情况
2207process = (...args) ->
2208 sum = 0
2209 for i = 1, args.n
2210 if args[i] != nil and type(args[i]) == "number"
2211 sum += args[i]
2212 sum
2213
2214process 1, nil, 3, nil, 5
2215```
2216<YueDisplay>
2217<pre>
2218f = (...t) ->
2219 print "傿•°ä¸ªæ•°:", t.n
2220 print "表长度:", #t
2221 for i = 1, t.n
2222 print t[i]
2223
2224f 1, 2, 3
2225f "a", "b", "c", "d"
2226f!
2227
2228-- 处ç†åŒ…å« nil 的情况
2229process = (...args) ->
2230 sum = 0
2231 for i = 1, args.n
2232 if args[i] != nil and type(args[i]) == "number"
2233 sum += args[i]
2234 sum
2235
2236process 1, nil, 3, nil, 5
2237</pre>
2238</YueDisplay>
2239
1859## åå‘回调 2240## åå‘回调
1860 2241
1861åå‘回调用于å‡å°‘函数回调的嵌套。它们使用指å‘左侧的箭头,并且默认会被定义为传入åŽç»­å‡½æ•°è°ƒç”¨çš„æœ€åŽä¸€ä¸ªå‚数。它的语法大部分与常规箭头函数相åŒï¼Œåªæ˜¯å®ƒæŒ‡å‘å¦ä¸€æ–¹å‘,并且åŽç»­çš„函数体ä¸éœ€è¦è¿›è¡Œç¼©è¿›ã€‚ 2242åå‘回调用于å‡å°‘函数回调的嵌套。它们使用指å‘左侧的箭头,并且默认会被定义为传入åŽç»­å‡½æ•°è°ƒç”¨çš„æœ€åŽä¸€ä¸ªå‚数。它的语法大部分与常规箭头函数相åŒï¼Œåªæ˜¯å®ƒæŒ‡å‘å¦ä¸€æ–¹å‘,并且åŽç»­çš„函数体ä¸éœ€è¦è¿›è¡Œç¼©è¿›ã€‚
@@ -1920,7 +2301,7 @@ print result, msg
1920 2301
1921## 表格字é¢é‡ 2302## 表格字é¢é‡
1922 2303
1923å’ŒLua一样,表格å¯ä»¥é€šè¿‡èŠ±æ‹¬å·è¿›è¡Œå®šä¹‰ã€‚ 2304å’Œ Lua 一样,表格å¯ä»¥é€šè¿‡èŠ±æ‹¬å·è¿›è¡Œå®šä¹‰ã€‚
1924 2305
1925```moonscript 2306```moonscript
1926some_values = [1, 2, 3, 4] 2307some_values = [1, 2, 3, 4]
@@ -2003,7 +2384,7 @@ y = type: "ç‹—", legs: 4, tails: 1
2003</pre> 2384</pre>
2004</YueDisplay> 2385</YueDisplay>
2005 2386
2006表格字é¢é‡çš„é”®å¯ä»¥ä½¿ç”¨Lua语言的关键字,而无需转义: 2387表格字é¢é‡çš„é”®å¯ä»¥ä½¿ç”¨ Lua 语言的关键字,而无需转义:
2007 2388
2008```moonscript 2389```moonscript
2009tbl = { 2390tbl = {
@@ -2039,7 +2420,7 @@ print_table :hair, :height
2039</pre> 2420</pre>
2040</YueDisplay> 2421</YueDisplay>
2041 2422
2042如果你希望表中字段的键是æŸä¸ªè¡¨è¾¾å¼çš„结果,那么å¯ä»¥ç”¨ **[ ]** 包裹它,就åƒåœ¨Lua中一样。如果键中有任何特殊字符,也å¯ä»¥ç›´æŽ¥ä½¿ç”¨å­—符串字é¢é‡ä½œä¸ºé”®ï¼Œçœç•¥æ–¹æ‹¬å·ã€‚ 2423如果你希望表中字段的键是æŸä¸ªè¡¨è¾¾å¼çš„结果,那么å¯ä»¥ç”¨ **[ ]** 包裹它,就åƒåœ¨ Lua 中一样。如果键中有任何特殊字符,也å¯ä»¥ç›´æŽ¥ä½¿ç”¨å­—符串字é¢é‡ä½œä¸ºé”®ï¼Œçœç•¥æ–¹æ‹¬å·ã€‚
2043 2424
2044```moonscript 2425```moonscript
2045t = { 2426t = {
@@ -2056,7 +2437,7 @@ t = {
2056</pre> 2437</pre>
2057</YueDisplay> 2438</YueDisplay>
2058 2439
2059Luaçš„è¡¨åŒæ—¶å…·æœ‰æ•°ç»„部分和哈希部分,但有时候你会希望在书写Lua表时,对Luaè¡¨åšæ•°ç»„和哈希ä¸åŒç”¨æ³•的语义区分。然åŽä½ å¯ä»¥ç”¨ **[ ]** è€Œä¸æ˜¯ **{ }** æ¥ç¼–写表示数组的 Lua 表,并且ä¸å…许在数组 Lua 表中写入任何键值对。 2440Lua çš„è¡¨åŒæ—¶å…·æœ‰æ•°ç»„部分和哈希部分,但有时候你会希望在书写 Lua 表时,对 Lua è¡¨åšæ•°ç»„和哈希ä¸åŒç”¨æ³•的语义区分。然åŽä½ å¯ä»¥ç”¨ **[ ]** è€Œä¸æ˜¯ **{ }** æ¥ç¼–写表示数组的 Lua 表,并且ä¸å…许在数组 Lua 表中写入任何键值对。
2060 2441
2061```moonscript 2442```moonscript
2062some_values = [ 1, 2, 3, 4 ] 2443some_values = [ 1, 2, 3, 4 ]
@@ -2071,11 +2452,11 @@ list_with_one_element = [ 1, ]
2071 2452
2072## æŽ¨å¯¼å¼ 2453## 推导å¼
2073 2454
2074推导å¼ä¸ºæˆ‘们æä¾›äº†ä¸€ç§ä¾¿æ·çš„语法,通过éåŽ†çŽ°æœ‰å¯¹è±¡å¹¶å¯¹å…¶å€¼åº”ç”¨è¡¨è¾¾å¼æ¥æž„é€ å‡ºæ–°çš„è¡¨æ ¼ã€‚æœˆä¹‹è„šæœ¬æœ‰ä¸¤ç§æŽ¨å¯¼å¼ï¼šåˆ—表推导å¼å’Œè¡¨æ ¼æŽ¨å¯¼å¼ã€‚它们最终都是产生Lua表格;列表推导å¼å°†å€¼ç´¯ç§¯åˆ°ç±»ä¼¼æ•°ç»„的表格中,而表格推导å¼å…è®¸ä½ åœ¨æ¯æ¬¡é历时设置新表格的键和值。 2455推导å¼ä¸ºæˆ‘们æä¾›äº†ä¸€ç§ä¾¿æ·çš„语法,通过éåŽ†çŽ°æœ‰å¯¹è±¡å¹¶å¯¹å…¶å€¼åº”ç”¨è¡¨è¾¾å¼æ¥æž„é€ å‡ºæ–°çš„è¡¨æ ¼ã€‚æœˆä¹‹è„šæœ¬æœ‰ä¸¤ç§æŽ¨å¯¼å¼ï¼šåˆ—表推导å¼å’Œè¡¨æ ¼æŽ¨å¯¼å¼ã€‚它们最终都是产生 Lua 表格;列表推导å¼å°†å€¼ç´¯ç§¯åˆ°ç±»ä¼¼æ•°ç»„的表格中,而表格推导å¼å…è®¸ä½ åœ¨æ¯æ¬¡é历时设置新表格的键和值。
2075 2456
2076### åˆ—è¡¨æŽ¨å¯¼å¼ 2457### 列表推导å¼
2077 2458
2078以下æ“作创建了一个items表的副本,但所有包å«çš„值都翻å€äº†ã€‚ 2459以下æ“作创建了一个 items 表的副本,但所有包å«çš„值都翻å€äº†ã€‚
2079 2460
2080```moonscript 2461```moonscript
2081items = [1, 2, 3, 4] 2462items = [1, 2, 3, 4]
@@ -2088,7 +2469,7 @@ doubled = [item * 2 for i, item in ipairs items]
2088</pre> 2469</pre>
2089</YueDisplay> 2470</YueDisplay>
2090 2471
2091å¯ä»¥ä½¿ç”¨whenå­å¥ç­›é€‰æ–°è¡¨ä¸­åŒ…å«çš„项目: 2472å¯ä»¥ä½¿ç”¨ `when` å­å¥ç­›é€‰æ–°è¡¨ä¸­åŒ…å«çš„项目:
2092 2473
2093```moonscript 2474```moonscript
2094slice = [item for i, item in ipairs items when i > 1 and i < 3] 2475slice = [item for i, item in ipairs items when i > 1 and i < 3]
@@ -2099,7 +2480,7 @@ slice = [item for i, item in ipairs items when i > 1 and i < 3]
2099</pre> 2480</pre>
2100</YueDisplay> 2481</YueDisplay>
2101 2482
2102因为我们常常需è¦è¿­ä»£æ•°å€¼ç´¢å¼•表的值,所以引入了 **\*** æ“作符æ¥åšè¯­æ³•简化。doubled示例å¯ä»¥é‡å†™ä¸ºï¼š 2483因为我们常常需è¦è¿­ä»£æ•°å€¼ç´¢å¼•表的值,所以引入了 **\*** æ“作符æ¥åšè¯­æ³•简化。doubled 示例å¯ä»¥é‡å†™ä¸ºï¼š
2103 2484
2104```moonscript 2485```moonscript
2105doubled = [item * 2 for item in *items] 2486doubled = [item * 2 for item in *items]
@@ -2110,9 +2491,30 @@ doubled = [item * 2 for item in *items]
2110</pre> 2491</pre>
2111</YueDisplay> 2492</YueDisplay>
2112 2493
2113forå’Œwhenå­å¥å¯ä»¥æ ¹æ®éœ€è¦è¿›è¡Œé“¾å¼æ“ä½œã€‚å”¯ä¸€çš„è¦æ±‚是推导å¼ä¸­è‡³å°‘è¦æœ‰ä¸€ä¸ªforå­å¥ã€‚ 2494在列表推导å¼ä¸­ï¼Œä½ è¿˜å¯ä»¥ä½¿ç”¨å±•å¼€æ“作符 `...` æ¥å®žçŽ°å¯¹åˆ—è¡¨åµŒå¥—å±‚çº§è¿›è¡Œæ‰å¹³åŒ–的处ç†ï¼š
2495
2496```moonscript
2497data =
2498 a: [1, 2, 3]
2499 b: [4, 5, 6]
2500
2501flat = [...v for k,v in pairs data]
2502-- flat 现在为 [1, 2, 3, 4, 5, 6]
2503```
2504<YueDisplay>
2505<pre>
2506data =
2507 a: [1, 2, 3]
2508 b: [4, 5, 6]
2509
2510flat = [...v for k,v in pairs data]
2511-- flat 现在为 [1, 2, 3, 4, 5, 6]
2512</pre>
2513</YueDisplay>
2514
2515for å’Œ when å­å¥å¯ä»¥æ ¹æ®éœ€è¦è¿›è¡Œé“¾å¼æ“ä½œã€‚å”¯ä¸€çš„è¦æ±‚是推导å¼ä¸­è‡³å°‘è¦æœ‰ä¸€ä¸ª for å­å¥ã€‚
2114 2516
2115使用多个forå­å¥ä¸Žä½¿ç”¨å¤šé‡å¾ªçŽ¯çš„æ•ˆæžœç›¸åŒï¼š 2517使用多个 for å­å¥ä¸Žä½¿ç”¨å¤šé‡å¾ªçŽ¯çš„æ•ˆæžœç›¸åŒï¼š
2116 2518
2117```moonscript 2519```moonscript
2118x_coords = [4, 5, 6, 7] 2520x_coords = [4, 5, 6, 7]
@@ -2131,7 +2533,7 @@ for y in *y_coords]
2131</pre> 2533</pre>
2132</YueDisplay> 2534</YueDisplay>
2133 2535
2134在推导å¼ä¸­ä¹Ÿå¯ä»¥ä½¿ç”¨ç®€å•的数值for循环: 2536在推导å¼ä¸­ä¹Ÿå¯ä»¥ä½¿ç”¨ç®€å•的数值 for 循环:
2135 2537
2136```moonscript 2538```moonscript
2137evens = [i for i = 1, 100 when i % 2 == 0] 2539evens = [i for i = 1, 100 when i % 2 == 0]
@@ -2146,7 +2548,7 @@ evens = [i for i = 1, 100 when i % 2 == 0]
2146 2548
2147表格推导å¼å’Œåˆ—表推导å¼çš„语法éžå¸¸ç›¸ä¼¼ï¼Œåªæ˜¯è¦ä½¿ç”¨ **{** å’Œ **}** å¹¶ä»Žæ¯æ¬¡è¿­ä»£ä¸­å–两个值。 2549表格推导å¼å’Œåˆ—表推导å¼çš„语法éžå¸¸ç›¸ä¼¼ï¼Œåªæ˜¯è¦ä½¿ç”¨ **{** å’Œ **}** å¹¶ä»Žæ¯æ¬¡è¿­ä»£ä¸­å–两个值。
2148 2550
2149以下示例生æˆäº†è¡¨æ ¼thing的副本: 2551以下示例生æˆäº†è¡¨æ ¼ thing 的副本:
2150 2552
2151```moonscript 2553```moonscript
2152thing = { 2554thing = {
@@ -2208,9 +2610,9 @@ tbl = {unpack tuple for tuple in *tuples}
2208 2610
2209### 切片 2611### 切片
2210 2612
2211当使用 **\*** æ“作符时,月之脚本还æä¾›äº†ä¸€ç§ç‰¹æ®Šçš„语法æ¥é™åˆ¶è¦é历的列表范围。这个语法也相当于在for循环中设置迭代边界和步长。 2613当使用 **\*** æ“作符时,月之脚本还æä¾›äº†ä¸€ç§ç‰¹æ®Šçš„语法æ¥é™åˆ¶è¦é历的列表范围。这个语法也相当于在 for 循环中设置迭代边界和步长。
2212 2614
2213下é¢çš„æ¡ˆä¾‹ä¸­ï¼Œæˆ‘们在切片中设置最å°å’Œæœ€å¤§è¾¹ç•Œï¼Œå–索引在1到5之间(包括1å’Œ5)的所有项目: 2615下é¢çš„æ¡ˆä¾‹ä¸­ï¼Œæˆ‘们在切片中设置最å°å’Œæœ€å¤§è¾¹ç•Œï¼Œå–索引在 1 到 5 之间(包括 1 å’Œ 5)的所有项目:
2214 2616
2215```moonscript 2617```moonscript
2216slice = [item for item in *items[1, 5]] 2618slice = [item for item in *items[1, 5]]
@@ -2232,7 +2634,7 @@ slice = [item for item in *items[2,]]
2232</pre> 2634</pre>
2233</YueDisplay> 2635</YueDisplay>
2234 2636
2235如果çœç•¥äº†æœ€å°è¾¹ç•Œï¼Œä¾¿é»˜è®¤ä¼šè®¾ç½®ä¸º1ã€‚è¿™é‡Œæˆ‘ä»¬åªæä¾›ä¸€ä¸ªæ­¥é•¿ï¼Œå¹¶ç•™ä¸‹å…¶ä»–è¾¹ç•Œä¸ºç©ºã€‚è¿™æ ·ä¼šä½¿å¾—ä»£ç å–出所有奇数索引的项目:(1, 3, 5, …) 2637如果çœç•¥äº†æœ€å°è¾¹ç•Œï¼Œä¾¿é»˜è®¤ä¼šè®¾ç½®ä¸º 1ã€‚è¿™é‡Œæˆ‘ä»¬åªæä¾›ä¸€ä¸ªæ­¥é•¿ï¼Œå¹¶ç•™ä¸‹å…¶ä»–è¾¹ç•Œä¸ºç©ºã€‚è¿™æ ·ä¼šä½¿å¾—ä»£ç å–出所有奇数索引的项目:(1, 3, 5, …)
2236 2638
2237```moonscript 2639```moonscript
2238slice = [item for item in *items[,,2]] 2640slice = [item for item in *items[,,2]]
@@ -2244,9 +2646,48 @@ slice = [item for item in *items[,,2]]
2244</pre> 2646</pre>
2245</YueDisplay> 2647</YueDisplay>
2246 2648
2649最å°å’Œæœ€å¤§è¾¹ç•Œéƒ½å¯ä»¥æ˜¯è´Ÿæ•°ï¼Œä½¿ç”¨è´Ÿæ•°æ„味ç€è¾¹ç•Œæ˜¯ä»Žè¡¨çš„æœ«å°¾å¼€å§‹è®¡ç®—的。
2650
2651```moonscript
2652-- å–æœ€åŽ4个元素
2653slice = [item for item in *items[-4,-1]]
2654```
2655<YueDisplay>
2656<pre>
2657-- å–æœ€åŽ4个元素
2658slice = [item for item in *items[-4,-1]]
2659</pre>
2660</YueDisplay>
2661
2662切片的步长也å¯ä»¥æ˜¯è´Ÿæ•°ï¼Œè¿™æ„味ç€å…ƒç´ ä¼šä»¥ç›¸å的顺åºè¢«å–出。
2663
2664```moonscript
2665reverse_slice = [item for item in *items[-1,1,-1]]
2666```
2667<YueDisplay>
2668<pre>
2669reverse_slice = [item for item in *items[-1,1,-1]]
2670</pre>
2671</YueDisplay>
2672
2673#### 切片表达å¼
2674
2675切片也å¯ä»¥ä½œä¸ºè¡¨è¾¾å¼æ¥ä½¿ç”¨ã€‚å¯ä»¥ç”¨äºŽèŽ·å–一个表包å«çš„å­åˆ—表。
2676
2677```moonscript
2678-- å–第2和第4个元素作为新的列表
2679sub_list = items[2, 4]
2680```
2681<YueDisplay>
2682<pre>
2683-- å–第2和第4个元素作为新的列表
2684sub_list = items[2, 4]
2685</pre>
2686</YueDisplay>
2687
2247## for 循环 2688## for 循环
2248 2689
2249Lua中有两ç§for循环形å¼ï¼Œæ•°å­—型和通用型: 2690Lua ä¸­æœ‰ä¸¤ç§ for 循环形å¼ï¼Œæ•°å­—型和通用型:
2250 2691
2251```moonscript 2692```moonscript
2252for i = 10, 20 2693for i = 10, 20
@@ -2299,7 +2740,7 @@ for j = 1, 10, 3 do print j
2299</pre> 2740</pre>
2300</YueDisplay> 2741</YueDisplay>
2301 2742
2302for循环也å¯ä»¥ç”¨ä½œè¡¨è¾¾å¼ã€‚for循环主体中的最åŽä¸€æ¡è¯­å¥ä¼šè¢«å¼ºåˆ¶è½¬æ¢ä¸ºä¸€ä¸ªè¿”回值的表达å¼ï¼Œå¹¶ä¼šå°†è¡¨è¾¾å¼è®¡ç®—结果的值追加到一个作为结果的数组表中。 2743for 循环也å¯ä»¥ç”¨ä½œè¡¨è¾¾å¼ã€‚for 循环主体中的最åŽä¸€æ¡è¯­å¥ä¼šè¢«å¼ºåˆ¶è½¬æ¢ä¸ºä¸€ä¸ªè¿”回值的表达å¼ï¼Œå¹¶ä¼šå°†è¡¨è¾¾å¼è®¡ç®—结果的值追加到一个作为结果的数组表中。
2303 2744
2304å°†æ¯ä¸ªå¶æ•°åŠ å€ï¼š 2745å°†æ¯ä¸ªå¶æ•°åŠ å€ï¼š
2305 2746
@@ -2320,9 +2761,9 @@ doubled_evens = for i = 1, 20
2320</pre> 2761</pre>
2321</YueDisplay> 2762</YueDisplay>
2322 2763
2323此外,for循环还支æŒå¸¦è¿”回值的break语å¥ï¼Œè¿™æ ·å¾ªçŽ¯æœ¬èº«å°±å¯ä»¥ä½œä¸ºä¸€ä¸ªè¡¨è¾¾å¼ï¼Œåœ¨æ»¡è¶³æ¡ä»¶æ—¶æå‰é€€å‡ºå¹¶è¿”回有æ„义的结果。 2764此外,for 循环还支æŒå¸¦è¿”回值的 break 语å¥ï¼Œè¿™æ ·å¾ªçŽ¯æœ¬èº«å°±å¯ä»¥ä½œä¸ºä¸€ä¸ªè¡¨è¾¾å¼ï¼Œåœ¨æ»¡è¶³æ¡ä»¶æ—¶æå‰é€€å‡ºå¹¶è¿”回有æ„义的结果。
2324 2765
2325例如,查找第一个大于10的数字: 2766例如,查找第一个大于 10 的数字:
2326 2767
2327```moonscript 2768```moonscript
2328first_large = for n in *numbers 2769first_large = for n in *numbers
@@ -2335,9 +2776,9 @@ first_large = for n in *numbers
2335</pre> 2776</pre>
2336</YueDisplay> 2777</YueDisplay>
2337 2778
2338你还å¯ä»¥ç»“åˆfor循环表达å¼ä¸Žcontinueè¯­å¥æ¥è¿‡æ»¤å€¼ã€‚ 2779你还å¯ä»¥ç»“åˆ for 循环表达å¼ä¸Ž continue è¯­å¥æ¥è¿‡æ»¤å€¼ã€‚
2339 2780
2340注æ„出现在函数体末尾的for循环,ä¸ä¼šè¢«å½“作是一个表达å¼å¹¶å°†å¾ªçŽ¯ç»“æžœç´¯ç§¯åˆ°ä¸€ä¸ªåˆ—è¡¨ä¸­ä½œä¸ºè¿”å›žå€¼ï¼ˆç›¸å,函数将返回nil)。如果è¦å‡½æ•°æœ«å°¾çš„循环转æ¢ä¸ºåˆ—表表达å¼ï¼Œå¯ä»¥æ˜¾å¼åœ°ä½¿ç”¨è¿”回语å¥åŠ for循环表达å¼ã€‚ 2781注æ„出现在函数体末尾的 for 循环,ä¸ä¼šè¢«å½“作是一个表达å¼å¹¶å°†å¾ªçŽ¯ç»“æžœç´¯ç§¯åˆ°ä¸€ä¸ªåˆ—è¡¨ä¸­ä½œä¸ºè¿”å›žå€¼ï¼ˆç›¸å,函数将返回 nil)。如果è¦å‡½æ•°æœ«å°¾çš„循环转æ¢ä¸ºåˆ—表表达å¼ï¼Œå¯ä»¥æ˜¾å¼åœ°ä½¿ç”¨è¿”回语å¥åŠ  for 循环表达å¼ã€‚
2341 2782
2342```moonscript 2783```moonscript
2343func_a = -> for i = 1, 10 do print i 2784func_a = -> for i = 1, 10 do print i
@@ -2360,7 +2801,7 @@ print func_b! -- æ‰“å° table 对象
2360 2801
2361## repeat 循环 2802## repeat 循环
2362 2803
2363repeat循环是从Lua语言中æ¬è¿‡æ¥çš„相似语法: 2804repeat 循环是从 Lua 语言中æ¬è¿‡æ¥çš„相似语法:
2364 2805
2365```moonscript 2806```moonscript
2366i = 10 2807i = 10
@@ -2381,7 +2822,7 @@ until i == 0
2381 2822
2382## while 循环 2823## while 循环
2383 2824
2384在月之脚本中的while循环有四ç§å†™æ³•: 2825在月之脚本中的 while 循环有四ç§å†™æ³•:
2385 2826
2386```moonscript 2827```moonscript
2387i = 10 2828i = 10
@@ -2420,7 +2861,7 @@ until running == false do my_function!
2420</pre> 2861</pre>
2421</YueDisplay> 2862</YueDisplay>
2422 2863
2423åƒfor循环的语法一样,while循环也å¯ä»¥ä½œä¸ºä¸€ä¸ªè¡¨è¾¾å¼ä½¿ç”¨ã€‚为了使函数返回while循环的累积列表值,必须明确使用返回语å¥è¿”回while循环表达å¼ã€‚ 2864åƒ for 循环的语法一样,while 循环也å¯ä»¥ä½œä¸ºä¸€ä¸ªè¡¨è¾¾å¼ä½¿ç”¨ã€‚为了使函数返回 while 循环的累积列表值,必须明确使用返回语å¥è¿”回 while 循环表达å¼ã€‚
2424 2865
2425## ç»§ç»­ 2866## ç»§ç»­
2426 2867
@@ -2538,13 +2979,14 @@ print message -- 打å°: 我很高
2538</pre> 2979</pre>
2539</YueDisplay> 2980</YueDisplay>
2540 2981
2541ifçš„åä¹‰è¯æ˜¯unless(相当于if not,如果 vs 除éžï¼‰ï¼š 2982if çš„åä¹‰è¯æ˜¯ unless(相当于 if not,正如“如果â€å¯¹åº”“除éžâ€ï¼‰ï¼š
2542 2983
2543```moonscript 2984```moonscript
2544unless os.date("%A") == "Monday" 2985unless os.date("%A") == "Monday"
2545 print "ä»Šå¤©ä¸æ˜¯æ˜ŸæœŸä¸€ï¼" 2986 print "ä»Šå¤©ä¸æ˜¯æ˜ŸæœŸä¸€ï¼"
2546``` 2987```
2547<YueDisplay> 2988<YueDisplay>
2989
2548<pre> 2990<pre>
2549unless os.date("%A") == "Monday" 2991unless os.date("%A") == "Monday"
2550 print "ä»Šå¤©ä¸æ˜¯æ˜ŸæœŸä¸€ï¼" 2992 print "ä»Šå¤©ä¸æ˜¯æ˜ŸæœŸä¸€ï¼"
@@ -2596,7 +3038,7 @@ print "你很幸è¿!" unless math.random! > 0.1
2596 3038
2597## 代ç è¡Œä¿®é¥°ç¬¦ 3039## 代ç è¡Œä¿®é¥°ç¬¦
2598 3040
2599为了方便编写代ç ï¼Œå¾ªçŽ¯è¯­å¥å’Œif语å¥å¯ä»¥åº”用于å•行代ç è¯­å¥çš„æœ«å°¾ï¼š 3041为了方便编写代ç ï¼Œå¾ªçŽ¯è¯­å¥å’Œ if 语å¥å¯ä»¥åº”用于å•行代ç è¯­å¥çš„æœ«å°¾ï¼š
2600 3042
2601```moonscript 3043```moonscript
2602print "你好,世界" if name == "Rob" 3044print "你好,世界" if name == "Rob"
@@ -2607,7 +3049,7 @@ print "你好,世界" if name == "Rob"
2607</pre> 3049</pre>
2608</YueDisplay> 3050</YueDisplay>
2609 3051
2610修饰for循环的示例: 3052修饰 for 循环的示例:
2611 3053
2612```moonscript 3054```moonscript
2613print "项目: ", item for item in *items 3055print "项目: ", item for item in *items
@@ -2618,7 +3060,7 @@ print "项目: ", item for item in *items
2618</pre> 3060</pre>
2619</YueDisplay> 3061</YueDisplay>
2620 3062
2621修饰while循环的示例: 3063修饰 while 循环的示例:
2622 3064
2623```moonscript 3065```moonscript
2624game\update! while game\isRunning! 3066game\update! while game\isRunning!
@@ -2635,34 +3077,32 @@ reader\parse_line! until reader\eof!
2635 3077
2636## switch è¯­å¥ 3078## switch 语å¥
2637 3079
2638switchè¯­å¥æ˜¯ä¸ºäº†ç®€åŒ–检查一系列相åŒå€¼çš„if语å¥è€Œæä¾›çš„ç®€å†™è¯­æ³•ã€‚è¦æ³¨æ„用于比较检查的目标值åªä¼šè®¡ç®—一次。和if语å¥ä¸€æ ·ï¼Œswitch语å¥åœ¨æœ€åŽå¯ä»¥æŽ¥ä¸€ä¸ªelse代ç å—æ¥å¤„ç†æ²¡æœ‰åŒ¹é…的情况。在生æˆçš„Lua代ç ä¸­ï¼Œè¿›è¡Œæ¯”较是使用==æ“作符完æˆçš„。 3080switch è¯­å¥æ˜¯ä¸ºäº†ç®€åŒ–检查一系列相åŒå€¼çš„if语å¥è€Œæä¾›çš„ç®€å†™è¯­æ³•ã€‚è¦æ³¨æ„用于比较检查的目标值åªä¼šè®¡ç®—一次。和 if 语å¥ä¸€æ ·ï¼Œswitch 语å¥åœ¨æœ€åŽå¯ä»¥æŽ¥ä¸€ä¸ª else 代ç å—æ¥å¤„ç†æ²¡æœ‰åŒ¹é…的情况。在生æˆçš„ Lua 代ç ä¸­ï¼Œè¿›è¡Œæ¯”较是使用 == æ“作符完æˆçš„。switch 语å¥ä¸­ä¹Ÿå¯ä»¥ä½¿ç”¨èµ‹å€¼è¡¨è¾¾å¼æ¥å‚¨å­˜ä¸´æ—¶å˜é‡å€¼ã€‚
2639 3081
2640```moonscript 3082```moonscript
2641name = "Dan" 3083switch name := "Dan"
2642switch name
2643 when "Robert" 3084 when "Robert"
2644 print "你是Robert" 3085 print "你是Robert"
2645 when "Dan", "Daniel" 3086 when "Dan", "Daniel"
2646 print "ä½ çš„å字是Dan" 3087 print "ä½ çš„å字是Dan"
2647 else 3088 else
2648 print "我ä¸çŸ¥é“ä½ çš„åå­—" 3089 print "我ä¸è®¤è¯†ä½ ï¼Œä½ çš„å字是#{name}"
2649``` 3090```
2650<YueDisplay> 3091<YueDisplay>
2651<pre> 3092<pre>
2652name = "Dan" 3093switch name := "Dan"
2653switch name
2654 when "Robert" 3094 when "Robert"
2655 print "你是Robert" 3095 print "你是Robert"
2656 when "Dan", "Daniel" 3096 when "Dan", "Daniel"
2657 print "ä½ çš„å字是Dan" 3097 print "ä½ çš„å字是Dan"
2658 else 3098 else
2659 print "我ä¸çŸ¥é“ä½ çš„åå­—" 3099 print "我ä¸è®¤è¯†ä½ ï¼Œä½ çš„å字是#{name}"
2660</pre> 3100</pre>
2661</YueDisplay> 3101</YueDisplay>
2662 3102
2663switch语å¥çš„whenå­å¥ä¸­å¯ä»¥é€šè¿‡ä½¿ç”¨é€—å·åˆ†éš”的列表æ¥åŒ¹é…多个值。 3103switch 语å¥çš„ when å­å¥ä¸­å¯ä»¥é€šè¿‡ä½¿ç”¨é€—å·åˆ†éš”的列表æ¥åŒ¹é…多个值。
2664 3104
2665switch语å¥ä¹Ÿå¯ä»¥ä½œä¸ºè¡¨è¾¾å¼ä½¿ç”¨ï¼Œä¸‹é¢æˆ‘们å¯ä»¥å°†switch语å¥è¿”回的结果分é…给一个å˜é‡ï¼š 3105switch 语å¥ä¹Ÿå¯ä»¥ä½œä¸ºè¡¨è¾¾å¼ä½¿ç”¨ï¼Œä¸‹é¢æˆ‘们å¯ä»¥å°† switch 语å¥è¿”回的结果分é…给一个å˜é‡ï¼š
2666 3106
2667```moonscript 3107```moonscript
2668b = 1 3108b = 1
@@ -2687,7 +3127,7 @@ next_number = switch b
2687</pre> 3127</pre>
2688</YueDisplay> 3128</YueDisplay>
2689 3129
2690我们å¯ä»¥ä½¿ç”¨then关键字在whenå­å¥çš„åŒä¸€è¡Œä¸Šç¼–写处ç†ä»£ç ã€‚else代ç å—çš„åŽç»­ä»£ç ä¸­è¦å†™åœ¨åŒä¸€è¡Œä¸Šä¸éœ€è¦é¢å¤–的关键字。 3130我们å¯ä»¥ä½¿ç”¨ then 关键字在 when å­å¥çš„åŒä¸€è¡Œä¸Šç¼–写处ç†ä»£ç ã€‚else 代ç å—çš„åŽç»­ä»£ç ä¸­è¦å†™åœ¨åŒä¸€è¡Œä¸Šä¸éœ€è¦é¢å¤–的关键字。
2691 3131
2692```moonscript 3132```moonscript
2693msg = switch math.random(1, 5) 3133msg = switch math.random(1, 5)
@@ -2704,7 +3144,7 @@ msg = switch math.random(1, 5)
2704</pre> 3144</pre>
2705</YueDisplay> 3145</YueDisplay>
2706 3146
2707如果在编写switchè¯­å¥æ—¶å¸Œæœ›å°‘写一个缩进,那么你å¯ä»¥æŠŠç¬¬ä¸€ä¸ªwhenå­å¥æ”¾åœ¨switch开始语å¥çš„第一行,然åŽåŽç»­çš„å­è¯­å¥å°±éƒ½å¯ä»¥éƒ½å°‘写一个缩进。 3147如果在编写 switch è¯­å¥æ—¶å¸Œæœ›å°‘写一个缩进,那么你å¯ä»¥æŠŠç¬¬ä¸€ä¸ª when å­å¥æ”¾åœ¨ switch 开始语å¥çš„第一行,然åŽåŽç»­çš„å­è¯­å¥å°±éƒ½å¯ä»¥éƒ½å°‘写一个缩进。
2708 3148
2709```moonscript 3149```moonscript
2710switch math.random(1, 5) 3150switch math.random(1, 5)
@@ -2733,11 +3173,11 @@ else
2733</pre> 3173</pre>
2734</YueDisplay> 3174</YueDisplay>
2735 3175
2736值得注æ„的是,在生æˆLuaä»£ç æ—¶ï¼Œæˆ‘们è¦åšæ£€æŸ¥çš„ç›®æ ‡å˜é‡ä¼šæ”¾åœ¨==表达å¼çš„å³ä¾§ã€‚当你希望给whenå­å¥çš„æ¯”较对象定义一个\_\_eq元方法æ¥é‡è½½åˆ¤æ–­é€»è¾‘时,å¯èƒ½ä¼šæœ‰ç”¨ã€‚ 3176值得注æ„çš„æ˜¯ï¼Œåœ¨ç”Ÿæˆ Lua ä»£ç æ—¶ï¼Œæˆ‘们è¦åšæ£€æŸ¥çš„ç›®æ ‡å˜é‡ä¼šæ”¾åœ¨ == 表达å¼çš„å³ä¾§ã€‚当你希望给 when å­å¥çš„æ¯”较对象定义一个 \_\_eq 元方法æ¥é‡è½½åˆ¤æ–­é€»è¾‘时,å¯èƒ½ä¼šæœ‰ç”¨ã€‚
2737 3177
2738### è¡¨æ ¼åŒ¹é… 3178### 表格匹é…
2739 3179
2740在switchçš„whenå­å¥ä¸­ï¼Œå¦‚果期待检查目标是一个表格,且å¯ä»¥é€šè¿‡ç‰¹å®šçš„结构进行解构并获得éžnil值,那么你å¯ä»¥å°è¯•使用表格匹é…的语法。 3180在 switch çš„ when å­å¥ä¸­ï¼Œå¦‚果期待检查目标是一个表格,且å¯ä»¥é€šè¿‡ç‰¹å®šçš„ç»“æž„è¿›è¡Œè§£æž„å¹¶èŽ·å¾—éž nil 值,那么你å¯ä»¥å°è¯•使用表格匹é…的语法。
2741 3181
2742```moonscript 3182```moonscript
2743items = 3183items =
@@ -2889,9 +3329,30 @@ switch tb
2889</pre> 3329</pre>
2890</YueDisplay> 3330</YueDisplay>
2891 3331
3332匹é…一个列表并æ•获特定范围内的元素。
3333
3334```moonscript
3335segments = ["admin", "users", "logs", "view"]
3336switch segments
3337 when [...groups, resource, action]
3338 print "Group:", groups -- 打å°: {"admin", "users"}
3339 print "Resource:", resource -- 打å°: "logs"
3340 print "Action:", action -- 打å°: "view"
3341```
3342<YueDisplay>
3343<pre>
3344segments = ["admin", "users", "logs", "view"]
3345switch segments
3346 when [...groups, resource, action]
3347 print "Group:", groups -- 打å°: {"admin", "users"}
3348 print "Resource:", resource -- 打å°: "logs"
3349 print "Action:", action -- 打å°: "view"
3350</pre>
3351</YueDisplay>
3352
2892## é¢å‘对象编程 3353## é¢å‘对象编程
2893 3354
2894在以下的示例中,月之脚本生æˆçš„Lua代ç å¯èƒ½çœ‹èµ·æ¥ä¼šå¾ˆå¤æ‚。所以最好主è¦å…³æ³¨æœˆä¹‹è„šæœ¬ä»£ç å±‚é¢çš„æ„ä¹‰ï¼Œç„¶åŽå¦‚果你想知é“关于é¢å‘å¯¹è±¡åŠŸèƒ½çš„å®žçŽ°ç»†èŠ‚ï¼Œå†æŸ¥çœ‹Lua代ç ã€‚ 3355在以下的示例中,月之脚本生æˆçš„ Lua 代ç å¯èƒ½çœ‹èµ·æ¥ä¼šå¾ˆå¤æ‚。所以最好主è¦å…³æ³¨æœˆä¹‹è„šæœ¬ä»£ç å±‚é¢çš„æ„ä¹‰ï¼Œç„¶åŽå¦‚果你想知é“关于é¢å‘å¯¹è±¡åŠŸèƒ½çš„å®žçŽ°ç»†èŠ‚ï¼Œå†æŸ¥çœ‹ Lua 代ç ã€‚
2895 3356
2896一个简å•的类: 3357一个简å•的类:
2897 3358
@@ -2920,11 +3381,11 @@ class Inventory
2920</pre> 3381</pre>
2921</YueDisplay> 3382</YueDisplay>
2922 3383
2923在月之脚本中采用é¢å‘å¯¹è±¡çš„ç¼–ç¨‹æ–¹å¼æ—¶ï¼Œé€šå¸¸ä¼šä½¿ç”¨ç±»å£°æ˜Žè¯­å¥ç»“åˆLua表格字é¢é‡æ¥åšç±»å®šä¹‰ã€‚这个类的定义包å«äº†å®ƒçš„æ‰€æœ‰æ–¹æ³•和属性。在这ç§ç»“构中,键å为“newâ€çš„æˆå‘˜æ‰®æ¼”äº†ä¸€ä¸ªé‡è¦çš„角色,是作为构造函数æ¥ä½¿ç”¨ã€‚ 3384在月之脚本中采用é¢å‘å¯¹è±¡çš„ç¼–ç¨‹æ–¹å¼æ—¶ï¼Œé€šå¸¸ä¼šä½¿ç”¨ç±»å£°æ˜Žè¯­å¥ç»“åˆ Lua 表格字é¢é‡æ¥åšç±»å®šä¹‰ã€‚这个类的定义包å«äº†å®ƒçš„æ‰€æœ‰æ–¹æ³•和属性。在这ç§ç»“构中,键å为 “new†的æˆå‘˜æ‰®æ¼”了一个é‡è¦çš„角色,是作为构造函数æ¥ä½¿ç”¨ã€‚
2924 3385
2925值得注æ„çš„æ˜¯ï¼Œç±»ä¸­çš„æ–¹æ³•éƒ½é‡‡ç”¨äº†ç²—ç®­å¤´å‡½æ•°è¯­æ³•ã€‚å½“åœ¨ç±»çš„å®žä¾‹ä¸Šè°ƒç”¨æ–¹æ³•æ—¶ï¼Œè¯¥å®žä¾‹ä¼šè‡ªåŠ¨ä½œä¸ºç¬¬ä¸€ä¸ªå‚æ•°è¢«ä¼ å…¥ï¼Œå› æ­¤ç²—箭头函数用于生æˆä¸€ä¸ªå为“selfâ€çš„傿•°ã€‚ 3386值得注æ„çš„æ˜¯ï¼Œç±»ä¸­çš„æ–¹æ³•éƒ½é‡‡ç”¨äº†ç²—ç®­å¤´å‡½æ•°è¯­æ³•ã€‚å½“åœ¨ç±»çš„å®žä¾‹ä¸Šè°ƒç”¨æ–¹æ³•æ—¶ï¼Œè¯¥å®žä¾‹ä¼šè‡ªåŠ¨ä½œä¸ºç¬¬ä¸€ä¸ªå‚æ•°è¢«ä¼ å…¥ï¼Œå› æ­¤ç²—箭头函数用于生æˆä¸€ä¸ªå为 “selfâ€ çš„å‚æ•°ã€‚
2926 3387
2927此外,“@â€å‰ç¼€åœ¨å˜é‡å上起到了简化作用,代表“selfâ€ã€‚例如,`@items` 就等åŒäºŽ `self.items`。 3388此外,“@†å‰ç¼€åœ¨å˜é‡å上起到了简化作用,代表 “selfâ€ã€‚例如,`@items` 就等åŒäºŽ `self.items`。
2928 3389
2929为了创建类的一个新实例,å¯ä»¥å°†ç±»å当作一个函数æ¥è°ƒç”¨ï¼Œè¿™æ ·å°±å¯ä»¥ç”Ÿæˆå¹¶è¿”回一个新的实例。 3390为了创建类的一个新实例,å¯ä»¥å°†ç±»å当作一个函数æ¥è°ƒç”¨ï¼Œè¿™æ ·å°±å¯ä»¥ç”Ÿæˆå¹¶è¿”回一个新的实例。
2930 3391
@@ -2946,7 +3407,7 @@ inv\add_item "pants"
2946 3407
2947需è¦ç‰¹åˆ«æ³¨æ„的是,类的所有属性在其实例之间是共享的。这对于函数类型的æˆå‘˜å±žæ€§é€šå¸¸ä¸ä¼šé€ æˆé—®é¢˜ï¼Œä½†å¯¹äºŽå…¶ä»–类型的属性,å¯èƒ½ä¼šå¯¼è‡´æ„外的结果。 3408需è¦ç‰¹åˆ«æ³¨æ„的是,类的所有属性在其实例之间是共享的。这对于函数类型的æˆå‘˜å±žæ€§é€šå¸¸ä¸ä¼šé€ æˆé—®é¢˜ï¼Œä½†å¯¹äºŽå…¶ä»–类型的属性,å¯èƒ½ä¼šå¯¼è‡´æ„外的结果。
2948 3409
2949例如,在下é¢çš„示例中,clothes属性在所有实例之间共享。因此,对这个属性在一个实例中的修改,将会影å“到其他所有实例。 3410例如,在下é¢çš„示例中,clothes 属性在所有实例之间共享。因此,对这个属性在一个实例中的修改,将会影å“到其他所有实例。
2950 3411
2951```moonscript 3412```moonscript
2952class Person 3413class Person
@@ -2998,7 +3459,7 @@ class Person
2998 3459
2999### 继承 3460### 继承
3000 3461
3001`extends`关键字å¯ä»¥åœ¨ç±»å£°æ˜Žä¸­ä½¿ç”¨ï¼Œä»¥ç»§æ‰¿å¦ä¸€ä¸ªç±»çš„属性和方法。 3462`extends` 关键字å¯ä»¥åœ¨ç±»å£°æ˜Žä¸­ä½¿ç”¨ï¼Œä»¥ç»§æ‰¿å¦ä¸€ä¸ªç±»çš„属性和方法。
3002 3463
3003```moonscript 3464```moonscript
3004class BackPack extends Inventory 3465class BackPack extends Inventory
@@ -3018,11 +3479,11 @@ class BackPack extends Inventory
3018</YueDisplay> 3479</YueDisplay>
3019 3480
3020 3481
3021在这一部分,我们对月之脚本中的`Inventory`类进行了扩展,加入了对å¯ä»¥æºå¸¦ç‰©å“æ•°é‡çš„é™åˆ¶ã€‚ 3482在这一部分,我们对月之脚本中的 `Inventory` 类进行了扩展,加入了对å¯ä»¥æºå¸¦ç‰©å“æ•°é‡çš„é™åˆ¶ã€‚
3022 3483
3023在这个特定的例å­ä¸­ï¼Œå­ç±»å¹¶æ²¡æœ‰å®šä¹‰è‡ªå·±çš„æž„造函数。因此,当创建一个新的实例时,系统会默认调用父类的构造函数。但如果我们在å­ç±»ä¸­å®šä¹‰äº†æž„造函数,我们å¯ä»¥åˆ©ç”¨`super`方法æ¥è°ƒç”¨å¹¶æ‰§è¡Œçˆ¶ç±»çš„æž„造函数。 3484在这个特定的例å­ä¸­ï¼Œå­ç±»å¹¶æ²¡æœ‰å®šä¹‰è‡ªå·±çš„æž„造函数。因此,当创建一个新的实例时,系统会默认调用父类的构造函数。但如果我们在å­ç±»ä¸­å®šä¹‰äº†æž„造函数,我们å¯ä»¥åˆ©ç”¨ `super` 方法æ¥è°ƒç”¨å¹¶æ‰§è¡Œçˆ¶ç±»çš„æž„造函数。
3024 3485
3025此外,当一个类继承自å¦ä¸€ä¸ªç±»æ—¶ï¼Œå®ƒä¼šå°è¯•调用父类上的`__inherited`方法(如果这个方法存在的è¯ï¼‰ï¼Œä»¥æ­¤æ¥å‘父类å‘é€é€šçŸ¥ã€‚这个`__inherited`函数接å—ä¸¤ä¸ªå‚æ•°ï¼šè¢«ç»§æ‰¿çš„父类和继承的å­ç±»ã€‚ 3486此外,当一个类继承自å¦ä¸€ä¸ªç±»æ—¶ï¼Œå®ƒä¼šå°è¯•调用父类上的 `__inherited` 方法(如果这个方法存在的è¯ï¼‰ï¼Œä»¥æ­¤æ¥å‘父类å‘é€é€šçŸ¥ã€‚这个 `__inherited` 函数接å—ä¸¤ä¸ªå‚æ•°ï¼šè¢«ç»§æ‰¿çš„父类和继承的å­ç±»ã€‚
3026 3487
3027```moonscript 3488```moonscript
3028class Shelf 3489class Shelf
@@ -3045,15 +3506,15 @@ class Cupboard extends Shelf
3045 3506
3046### super 关键字 3507### super 关键字
3047 3508
3048`super`是一个特别的关键字,它有两ç§ä¸åŒçš„使用方å¼ï¼šæ—¢å¯ä»¥å½“作一个对象æ¥çœ‹å¾…,也å¯ä»¥åƒè°ƒç”¨å‡½æ•°é‚£æ ·ä½¿ç”¨ã€‚它仅在类的内部使用时具有特殊的功能。 3509`super` 是一个特别的关键字,它有两ç§ä¸åŒçš„使用方å¼ï¼šæ—¢å¯ä»¥å½“作一个对象æ¥çœ‹å¾…,也å¯ä»¥åƒè°ƒç”¨å‡½æ•°é‚£æ ·ä½¿ç”¨ã€‚它仅在类的内部使用时具有特殊的功能。
3049 3510
3050当`super`被作为一个函数调用时,它将调用父类中与之åŒå的函数。此时,当å‰çš„`self`ä¼šè‡ªåŠ¨ä½œä¸ºç¬¬ä¸€ä¸ªå‚æ•°ä¼ é€’ï¼Œæ­£å¦‚ä¸Šé¢æåˆ°çš„ç»§æ‰¿ç¤ºä¾‹æ‰€å±•ç¤ºçš„é‚£æ ·ã€‚ 3511当 `super` 被作为一个函数调用时,它将调用父类中与之åŒå的函数。此时,当å‰çš„ `self` ä¼šè‡ªåŠ¨ä½œä¸ºç¬¬ä¸€ä¸ªå‚æ•°ä¼ é€’ï¼Œæ­£å¦‚ä¸Šé¢æåˆ°çš„ç»§æ‰¿ç¤ºä¾‹æ‰€å±•ç¤ºçš„é‚£æ ·ã€‚
3051 3512
3052在将`super`å½“ä½œæ™®é€šå€¼ä½¿ç”¨æ—¶ï¼Œå®ƒå®žé™…ä¸Šæ˜¯å¯¹çˆ¶ç±»å¯¹è±¡çš„å¼•ç”¨ã€‚é€šè¿‡è¿™ç§æ–¹å¼ï¼Œæˆ‘们å¯ä»¥è®¿é—®çˆ¶ç±»ä¸­å¯èƒ½è¢«å­ç±»è¦†ç›–的值,就åƒè®¿é—®ä»»ä½•普通对象一样。 3513在将 `super` å½“ä½œæ™®é€šå€¼ä½¿ç”¨æ—¶ï¼Œå®ƒå®žé™…ä¸Šæ˜¯å¯¹çˆ¶ç±»å¯¹è±¡çš„å¼•ç”¨ã€‚é€šè¿‡è¿™ç§æ–¹å¼ï¼Œæˆ‘们å¯ä»¥è®¿é—®çˆ¶ç±»ä¸­å¯èƒ½è¢«å­ç±»è¦†ç›–的值,就åƒè®¿é—®ä»»ä½•普通对象一样。
3053 3514
3054此外,当使用`\`æ“作符与`super`一起使用时,`self`将被æ’å…¥ä¸ºç¬¬ä¸€ä¸ªå‚æ•°ï¼Œè€Œä¸æ˜¯ä½¿ç”¨`super`本身的值。而在使用`.`æ“ä½œç¬¦æ¥æ£€ç´¢å‡½æ•°æ—¶ï¼Œåˆ™ä¼šè¿”回父类中的原始函数。 3515此外,当使用 `\` æ“作符与 `super` 一起使用时,`self`将被æ’å…¥ä¸ºç¬¬ä¸€ä¸ªå‚æ•°ï¼Œè€Œä¸æ˜¯ä½¿ç”¨ `super` 本身的值。而在使用`.`æ“ä½œç¬¦æ¥æ£€ç´¢å‡½æ•°æ—¶ï¼Œåˆ™ä¼šè¿”回父类中的原始函数。
3055 3516
3056䏋颿˜¯ä¸€äº›ä½¿ç”¨`super`çš„ä¸åŒæ–¹æ³•的示例: 3517䏋颿˜¯ä¸€äº›ä½¿ç”¨ `super` çš„ä¸åŒæ–¹æ³•的示例:
3057 3518
3058```moonscript 3519```moonscript
3059class MyClass extends ParentClass 3520class MyClass extends ParentClass
@@ -3112,9 +3573,9 @@ print BackPack.size -- æ‰“å° 10
3112 3573
3113如果在类对象的元表中找ä¸åˆ°æŸä¸ªå±žæ€§ï¼Œç³»ç»Ÿä¼šä»ŽåŸºè¡¨ä¸­æ£€ç´¢è¯¥å±žæ€§ã€‚这就æ„å‘³ç€æˆ‘们å¯ä»¥ç›´æŽ¥ä»Žç±»æœ¬èº«è®¿é—®åˆ°å…¶æ–¹æ³•和属性。 3574如果在类对象的元表中找ä¸åˆ°æŸä¸ªå±žæ€§ï¼Œç³»ç»Ÿä¼šä»ŽåŸºè¡¨ä¸­æ£€ç´¢è¯¥å±žæ€§ã€‚这就æ„å‘³ç€æˆ‘们å¯ä»¥ç›´æŽ¥ä»Žç±»æœ¬èº«è®¿é—®åˆ°å…¶æ–¹æ³•和属性。
3114 3575
3115需è¦ç‰¹åˆ«æ³¨æ„的是,对类对象的赋值并ä¸ä¼šå½±å“åˆ°åŸºè¡¨ï¼Œå› æ­¤è¿™ä¸æ˜¯å‘实例添加新方法的正确方å¼ã€‚相å,需è¦ç›´æŽ¥ä¿®æ”¹åŸºè¡¨ã€‚关于这点,å¯ä»¥å‚考下é¢çš„“__baseâ€å­—段。 3576需è¦ç‰¹åˆ«æ³¨æ„的是,对类对象的赋值并ä¸ä¼šå½±å“åˆ°åŸºè¡¨ï¼Œå› æ­¤è¿™ä¸æ˜¯å‘实例添加新方法的正确方å¼ã€‚相å,需è¦ç›´æŽ¥ä¿®æ”¹åŸºè¡¨ã€‚关于这点,å¯ä»¥å‚考下é¢çš„ “__base†字段。
3116 3577
3117此外,类对象包å«å‡ ä¸ªç‰¹æ®Šçš„属性:当类被声明时,类的å称会作为一个字符串存储在类对象的“__nameâ€å­—段中。 3578此外,类对象包å«å‡ ä¸ªç‰¹æ®Šçš„属性:当类被声明时,类的å称会作为一个字符串存储在类对象的 “__name†字段中。
3118 3579
3119```moonscript 3580```moonscript
3120print BackPack.__name -- æ‰“å° Backpack 3581print BackPack.__name -- æ‰“å° Backpack
@@ -3196,7 +3657,7 @@ print Counter.count -- 输出 2
3196 3657
3197### ç±»å£°æ˜Žè¯­å¥ 3658### 类声明语å¥
3198 3659
3199在类声明的主体中,除了键/值对外,我们还å¯ä»¥ç¼–写普通的表达å¼ã€‚在这ç§ç±»å£°æ˜Žä½“中的普通代ç çš„上下文中,selfç­‰äºŽç±»å¯¹è±¡ï¼Œè€Œä¸æ˜¯å®žä¾‹å¯¹è±¡ã€‚ 3660在类声明的主体中,除了键/值对外,我们还å¯ä»¥ç¼–写普通的表达å¼ã€‚在这ç§ç±»å£°æ˜Žä½“中的普通代ç çš„上下文中,self ç­‰äºŽç±»å¯¹è±¡ï¼Œè€Œä¸æ˜¯å®žä¾‹å¯¹è±¡ã€‚
3200 3661
3201以下是创建类å˜é‡çš„å¦ä¸€ç§æ–¹æ³•: 3662以下是创建类å˜é‡çš„å¦ä¸€ç§æ–¹æ³•:
3202 3663
@@ -3236,9 +3697,9 @@ class MoreThings
3236 3697
3237### @ 和 @@ 值 3698### @ 和 @@ 值
3238 3699
3239当@å’Œ@@å‰ç¼€åœ¨ä¸€ä¸ªå字剿—¶ï¼Œå®ƒä»¬åˆ†åˆ«ä»£è¡¨åœ¨selfå’Œself.\_\_class中访问的那个å字。 3700当 @ å’Œ @@ å‰ç¼€åœ¨ä¸€ä¸ªå字剿—¶ï¼Œå®ƒä»¬åˆ†åˆ«ä»£è¡¨åœ¨ self å’Œ self.\_\_class 中访问的那个å字。
3240 3701
3241如果它们å•独使用,它们是selfå’Œself.\_\_class的别å。 3702如果它们å•独使用,它们是 self å’Œ self.\_\_class 的别å。
3242 3703
3243```moonscript 3704```moonscript
3244assert @ == self 3705assert @ == self
@@ -3251,7 +3712,7 @@ assert @@ == self.__class
3251</pre> 3712</pre>
3252</YueDisplay> 3713</YueDisplay>
3253 3714
3254例如,使用@@从实例方法快速创建åŒä¸€ç±»çš„æ–°å®žä¾‹çš„æ–¹æ³•: 3715例如,使用 @@ 从实例方法快速创建åŒä¸€ç±»çš„æ–°å®žä¾‹çš„æ–¹æ³•:
3255 3716
3256```moonscript 3717```moonscript
3257some_instance_method = (...) => @@ ... 3718some_instance_method = (...) => @@ ...
@@ -3329,7 +3790,7 @@ x = class Bucket
3329 3790
3330### 匿åç±» 3791### 匿åç±»
3331 3792
3332声明类时å¯ä»¥çœç•¥å称。如果类的表达å¼ä¸åœ¨èµ‹å€¼è¯­å¥ä¸­ï¼Œ\_\_name属性将为nil。如果出现在赋值语å¥ä¸­ï¼Œèµ‹å€¼æ“作左侧的å称将代替nil。 3793声明类时å¯ä»¥çœç•¥å称。如果类的表达å¼ä¸åœ¨èµ‹å€¼è¯­å¥ä¸­ï¼Œ\_\_name 属性将为 nil。如果出现在赋值语å¥ä¸­ï¼Œèµ‹å€¼æ“作左侧的å称将代替 nil。
3333 3794
3334```moonscript 3795```moonscript
3335BigBucket = class extends Bucket 3796BigBucket = class extends Bucket
@@ -3400,11 +3861,11 @@ assert y.__class.__parent ~= X -- X 䏿˜¯ Y 的父类
3400 3861
3401## with è¯­å¥ 3862## with 语å¥
3402 3863
3403在编写Luaä»£ç æ—¶ï¼Œæˆ‘们在创建对象åŽçš„å¸¸è§æ“作是立å³è°ƒç”¨è¿™ä¸ªå¯¹è±¡ä¸€ç³»åˆ—æ“作函数并设置一系列属性。 3864在编写 Lua ä»£ç æ—¶ï¼Œæˆ‘们在创建对象åŽçš„å¸¸è§æ“作是立å³è°ƒç”¨è¿™ä¸ªå¯¹è±¡ä¸€ç³»åˆ—æ“作函数并设置一系列属性。
3404 3865
3405这导致在代ç ä¸­å¤šæ¬¡é‡å¤å¼•用对象的å称,增加了ä¸å¿…è¦çš„æ–‡æœ¬å™ªéŸ³ã€‚一个常è§çš„解决方案是在创建对象时,在构造函数传入一个表,该表包å«è¦è¦†ç›–设置的键和值的集åˆã€‚这样åšçš„缺点是该对象的构造函数必须支æŒè¿™ç§åˆå§‹åŒ–å½¢å¼ã€‚ 3866这导致在代ç ä¸­å¤šæ¬¡é‡å¤å¼•用对象的å称,增加了ä¸å¿…è¦çš„æ–‡æœ¬å™ªéŸ³ã€‚一个常è§çš„解决方案是在创建对象时,在构造函数传入一个表,该表包å«è¦è¦†ç›–设置的键和值的集åˆã€‚这样åšçš„缺点是该对象的构造函数必须支æŒè¿™ç§åˆå§‹åŒ–å½¢å¼ã€‚
3406 3867
3407withå—æœ‰åŠ©äºŽç®€åŒ–ç¼–å†™è¿™æ ·çš„ä»£ç ã€‚在withå—内,我们å¯ä»¥ä½¿ç”¨ä»¥.或\开头的特殊语å¥ï¼Œè¿™äº›è¯­å¥ä»£è¡¨æˆ‘们正在使用的对象的æ“作。 3868with å—æœ‰åŠ©äºŽç®€åŒ–ç¼–å†™è¿™æ ·çš„ä»£ç ã€‚在 with å—内,我们å¯ä»¥ä½¿ç”¨ä»¥ . 或 \ 开头的特殊语å¥ï¼Œè¿™äº›è¯­å¥ä»£è¡¨æˆ‘们正在使用的对象的æ“作。
3408 3869
3409例如,我们å¯ä»¥è¿™æ ·å¤„ç†ä¸€ä¸ªæ–°åˆ›å»ºçš„对象: 3870例如,我们å¯ä»¥è¿™æ ·å¤„ç†ä¸€ä¸ªæ–°åˆ›å»ºçš„对象:
3410 3871
@@ -3425,7 +3886,7 @@ with Person!
3425</pre> 3886</pre>
3426</YueDisplay> 3887</YueDisplay>
3427 3888
3428with语å¥ä¹Ÿå¯ä»¥ç”¨ä½œä¸€ä¸ªè¡¨è¾¾å¼ï¼Œå¹¶è¿”回它的代ç å—正在处ç†çš„对象。 3889with 语å¥ä¹Ÿå¯ä»¥ç”¨ä½œä¸€ä¸ªè¡¨è¾¾å¼ï¼Œå¹¶è¿”回它的代ç å—正在处ç†çš„对象。
3429 3890
3430```moonscript 3891```moonscript
3431file = with File "favorite_foods.txt" 3892file = with File "favorite_foods.txt"
@@ -3459,24 +3920,24 @@ me = create_person "Leaf", [dad, mother, sister]
3459</pre> 3920</pre>
3460</YueDisplay> 3921</YueDisplay>
3461 3922
3462在此用法中,withå¯ä»¥è¢«è§†ä¸ºK组åˆå­ï¼ˆk-combinator)的一ç§ç‰¹æ®Šå½¢å¼ã€‚ 3923在此用法中,with å¯ä»¥è¢«è§†ä¸ºK组åˆå­ï¼ˆk-combinator)的一ç§ç‰¹æ®Šå½¢å¼ã€‚
3463 3924
3464如果你想给表达å¼å¦å¤–起一个åç§°çš„è¯ï¼Œwith语å¥ä¸­çš„表达å¼ä¹Ÿå¯ä»¥æ˜¯ä¸€ä¸ªèµ‹å€¼è¯­å¥ã€‚ 3925如果你想给表达å¼å¦å¤–起一个åç§°çš„è¯ï¼Œwith 语å¥ä¸­çš„表达å¼ä¹Ÿå¯ä»¥æ˜¯ä¸€ä¸ªèµ‹å€¼è¯­å¥ã€‚
3465 3926
3466```moonscript 3927```moonscript
3467with str = "你好" 3928with str := "你好"
3468 print "原始:", str 3929 print "原始:", str
3469 print "大写:", \upper! 3930 print "大写:", \upper!
3470``` 3931```
3471<YueDisplay> 3932<YueDisplay>
3472<pre> 3933<pre>
3473with str = "你好" 3934with str := "你好"
3474 print "原始:", str 3935 print "原始:", str
3475 print "大写:", \upper! 3936 print "大写:", \upper!
3476</pre> 3937</pre>
3477</YueDisplay> 3938</YueDisplay>
3478 3939
3479在with语å¥ä¸­å¯ä»¥ä½¿ç”¨`[]`访问特殊键。 3940ä½ å¯ä»¥åœ¨ `with` 语å¥ä¸­ä½¿ç”¨ `[]` 访问特殊键。
3480 3941
3481```moonscript 3942```moonscript
3482with tb 3943with tb
@@ -3499,9 +3960,22 @@ with tb
3499</pre> 3960</pre>
3500</YueDisplay> 3961</YueDisplay>
3501 3962
3963`with?` 是 `with` è¯­æ³•çš„ä¸€ä¸ªå¢žå¼ºç‰ˆæœ¬ï¼Œå¼•å…¥äº†å­˜åœ¨æ€§æ£€æŸ¥ï¼Œç”¨äºŽåœ¨ä¸æ˜¾å¼åˆ¤ç©ºçš„æƒ…况下安全访问å¯èƒ½ä¸º nil 的对象。
3964
3965```moonscript
3966with? obj
3967 print obj.name
3968```
3969<YueDisplay>
3970<pre>
3971with? obj
3972 print obj.name
3973</pre>
3974</YueDisplay>
3975
3502## do è¯­å¥ 3976## do 语å¥
3503 3977
3504å½“ç”¨ä½œè¯­å¥æ—¶ï¼Œdo语å¥çš„作用就åƒåœ¨Lua中差ä¸å¤šã€‚ 3978å½“ç”¨ä½œè¯­å¥æ—¶ï¼Œdo 语å¥çš„作用就åƒåœ¨ Lua 中差ä¸å¤šã€‚
3505 3979
3506```moonscript 3980```moonscript
3507do 3981do
@@ -3518,7 +3992,7 @@ print var -- 这里是nil
3518</pre> 3992</pre>
3519</YueDisplay> 3993</YueDisplay>
3520 3994
3521月之脚本的 **do** 也å¯ä»¥ç”¨ä½œè¡¨è¾¾å¼ã€‚å…许你将多行代ç çš„处ç†åˆå¹¶ä¸ºä¸€ä¸ªè¡¨è¾¾å¼ï¼Œå¹¶å°†do语å¥ä»£ç å—的最åŽä¸€ä¸ªè¯­å¥ä½œä¸ºè¡¨è¾¾å¼è¿”回的结果。 3995月之脚本的 **do** 也å¯ä»¥ç”¨ä½œè¡¨è¾¾å¼ã€‚å…许你将多行代ç çš„处ç†åˆå¹¶ä¸ºä¸€ä¸ªè¡¨è¾¾å¼ï¼Œå¹¶å°† do 语å¥ä»£ç å—的最åŽä¸€ä¸ªè¯­å¥ä½œä¸ºè¡¨è¾¾å¼è¿”回的结果。
3522 3996
3523```moonscript 3997```moonscript
3524counter = do 3998counter = do
@@ -3702,7 +4176,7 @@ print i, k -- 这些已ç»è¢«æ›´æ–°
3702 4176
3703## 月之脚本语言库 4177## 月之脚本语言库
3704 4178
3705使用`require("yue")`æ¥è®¿é—®ã€‚ 4179使用 `require("yue")` æ¥è®¿é—®ã€‚
3706 4180
3707### yue 4181### yue
3708 4182
@@ -3760,9 +4234,9 @@ yue_compiled: {string: string}
3760**ç­¾å:** 4234**ç­¾å:**
3761```lua 4235```lua
3762to_lua: function(code: string, config?: Config): 4236to_lua: function(code: string, config?: Config):
3763 --[[codes]] string | nil, 4237 --[[codes]] string | nil,
3764 --[[error]] string | nil, 4238 --[[error]] string | nil,
3765 --[[globals]] {{string, integer, integer}} | nil 4239 --[[globals]] {{string, integer, integer}} | nil
3766``` 4240```
3767 4241
3768**傿•°ï¼š** 4242**傿•°ï¼š**
@@ -3885,8 +4359,8 @@ remove_loader: function(): boolean
3885**ç­¾å:** 4359**ç­¾å:**
3886```lua 4360```lua
3887loadstring: function(input: string, chunkname: string, env: table, config?: Config): 4361loadstring: function(input: string, chunkname: string, env: table, config?: Config):
3888 --[[loaded function]] nil | function(...: any): (any...), 4362 --[[loaded function]] nil | function(...: any): (any...),
3889 --[[error]] string | nil 4363 --[[error]] string | nil
3890``` 4364```
3891 4365
3892**傿•°ï¼š** 4366**傿•°ï¼š**
@@ -3916,8 +4390,8 @@ loadstring: function(input: string, chunkname: string, env: table, config?: Conf
3916**ç­¾å:** 4390**ç­¾å:**
3917```lua 4391```lua
3918loadstring: function(input: string, chunkname: string, config?: Config): 4392loadstring: function(input: string, chunkname: string, config?: Config):
3919 --[[loaded function]] nil | function(...: any): (any...), 4393 --[[loaded function]] nil | function(...: any): (any...),
3920 --[[error]] string | nil 4394 --[[error]] string | nil
3921``` 4395```
3922 4396
3923**傿•°ï¼š** 4397**傿•°ï¼š**
@@ -3946,8 +4420,8 @@ loadstring: function(input: string, chunkname: string, config?: Config):
3946**ç­¾å:** 4420**ç­¾å:**
3947```lua 4421```lua
3948loadstring: function(input: string, config?: Config): 4422loadstring: function(input: string, config?: Config):
3949 --[[loaded function]] nil | function(...: any): (any...), 4423 --[[loaded function]] nil | function(...: any): (any...),
3950 --[[error]] string | nil 4424 --[[error]] string | nil
3951``` 4425```
3952 4426
3953**傿•°ï¼š** 4427**傿•°ï¼š**
@@ -3975,8 +4449,8 @@ loadstring: function(input: string, config?: Config):
3975**ç­¾å:** 4449**ç­¾å:**
3976```lua 4450```lua
3977loadfile: function(filename: string, env: table, config?: Config): 4451loadfile: function(filename: string, env: table, config?: Config):
3978 nil | function(...: any): (any...), 4452 nil | function(...: any): (any...),
3979 string | nil 4453 string | nil
3980``` 4454```
3981 4455
3982**傿•°ï¼š** 4456**傿•°ï¼š**
@@ -4005,8 +4479,8 @@ loadfile: function(filename: string, env: table, config?: Config):
4005**ç­¾å:** 4479**ç­¾å:**
4006```lua 4480```lua
4007loadfile: function(filename: string, config?: Config): 4481loadfile: function(filename: string, config?: Config):
4008 nil | function(...: any): (any...), 4482 nil | function(...: any): (any...),
4009 string | nil 4483 string | nil
4010``` 4484```
4011 4485
4012**傿•°ï¼š** 4486**傿•°ï¼š**
@@ -4261,9 +4735,9 @@ type AST = {string, integer, integer, any}
4261 4735
4262**ç­¾å:** 4736**ç­¾å:**
4263```lua 4737```lua
4264to_ast: function(code: string, flattenLevel?: number, astName?: string): 4738to_ast: function(code: string, flattenLevel?: number, astName?: string, reserveComment?: boolean):
4265 --[[AST]] AST | nil, 4739 --[[AST]] AST | nil,
4266 --[[error]] nil | string 4740 --[[error]] nil | string
4267``` 4741```
4268 4742
4269**傿•°ï¼š** 4743**傿•°ï¼š**
@@ -4272,6 +4746,42 @@ to_ast: function(code: string, flattenLevel?: number, astName?: string):
4272| --- | --- | --- | 4746| --- | --- | --- |
4273| code | string | 代ç ã€‚ | 4747| code | string | 代ç ã€‚ |
4274| flattenLevel | integer | [å¯é€‰] æ‰å¹³åŒ–级别。级别越高,会消除更多的 AST 结构的嵌套。默认为 0。最大为 2。 | 4748| flattenLevel | integer | [å¯é€‰] æ‰å¹³åŒ–级别。级别越高,会消除更多的 AST 结构的嵌套。默认为 0。最大为 2。 |
4749| astName | string | [å¯é€‰] AST å称。默认为 "File"。 |
4750| reserveComment | boolean | [å¯é€‰] 是å¦ä¿ç•™åŽŸå§‹æ³¨é‡Šã€‚é»˜è®¤ä¸º false。 |
4751
4752**返回值:**
4753
4754| 返回类型 | æè¿° |
4755| --- | --- |
4756| AST \| nil | AST,如果转æ¢å¤±è´¥åˆ™ä¸º nil。 |
4757| string \| nil | 错误消æ¯ï¼Œå¦‚æžœè½¬æ¢æˆåŠŸåˆ™ä¸º nil。 |
4758
4759#### format
4760
4761**类型:** 函数。
4762
4763**æè¿°ï¼š**
4764
4765æ ¼å¼åŒ– YueScript 代ç ã€‚
4766
4767**ç­¾å:**
4768```lua
4769format: function(code: string, tabSize?: number, reserveComment?: boolean): string
4770```
4771
4772**傿•°ï¼š**
4773
4774| 傿•°å | 类型 | æè¿° |
4775| --- | --- | --- |
4776| code | string | 代ç ã€‚ |
4777| tabSize | integer | [å¯é€‰] 制表符大å°ã€‚默认为 4。 |
4778| reserveComment | boolean | [å¯é€‰] 是å¦ä¿ç•™åŽŸå§‹æ³¨é‡Šã€‚é»˜è®¤ä¸º true。 |
4779
4780**返回值:**
4781
4782| 返回类型 | æè¿° |
4783| --- | --- |
4784| string | æ ¼å¼åŒ–åŽçš„代ç ã€‚ |
4275 4785
4276#### __call 4786#### __call
4277 4787
@@ -4344,6 +4854,19 @@ implicit_return_root: boolean
4344reserve_line_number: boolean 4854reserve_line_number: boolean
4345``` 4855```
4346 4856
4857#### reserve_comment
4858
4859**类型:** æˆå‘˜å˜é‡ã€‚
4860
4861**æè¿°ï¼š**
4862
4863编译器是å¦åº”该在编译åŽçš„代ç ä¸­ä¿ç•™åŽŸå§‹æ³¨é‡Šã€‚
4864
4865**ç­¾å:**
4866```lua
4867reserve_comment: boolean
4868```
4869
4347#### space_over_tab 4870#### space_over_tab
4348 4871
4349**类型:** æˆå‘˜å˜é‡ã€‚ 4872**类型:** æˆå‘˜å˜é‡ã€‚
@@ -4394,11 +4917,11 @@ line_offset: integer
4394**ç­¾å:** 4917**ç­¾å:**
4395```lua 4918```lua
4396enum LuaTarget 4919enum LuaTarget
4397 "5.1" 4920 "5.1"
4398 "5.2" 4921 "5.2"
4399 "5.3" 4922 "5.3"
4400 "5.4" 4923 "5.4"
4401 "5.5" 4924 "5.5"
4402end 4925end
4403``` 4926```
4404 4927
diff --git a/makefile b/makefile
index d7e85d3..e0cdd91 100644
--- a/makefile
+++ b/makefile
@@ -3,6 +3,7 @@
3BIN_NAME := yue 3BIN_NAME := yue
4# Compiler used 4# Compiler used
5CXX ?= g++ 5CXX ?= g++
6CC ?= gcc
6# Extension of source files used in the project 7# Extension of source files used in the project
7SRC_EXT = cpp 8SRC_EXT = cpp
8# Path to the source directory, relative to the makefile 9# Path to the source directory, relative to the makefile
@@ -10,7 +11,7 @@ SRC_PATH = ./src
10# Space-separated pkg-config libraries used by this project 11# Space-separated pkg-config libraries used by this project
11LIBS = 12LIBS =
12# General compiler flags 13# General compiler flags
13COMPILE_FLAGS = -std=c++17 -Wall -Wextra -Wno-deprecated-declarations 14COMPILE_FLAGS = -std=c++17 -Wall -Wextra -DYUE_UTF8_IMPL
14# Additional release-specific flags 15# Additional release-specific flags
15RCOMPILE_FLAGS = -D NDEBUG -O3 16RCOMPILE_FLAGS = -D NDEBUG -O3
16# Additional debug-specific flags 17# Additional debug-specific flags
@@ -54,13 +55,42 @@ endif
54 INCLUDES += -I $(SRC_PATH)/3rdParty/lua 55 INCLUDES += -I $(SRC_PATH)/3rdParty/lua
55 LINK_FLAGS += -L $(SRC_PATH)/3rdParty/lua -llua -ldl 56 LINK_FLAGS += -L $(SRC_PATH)/3rdParty/lua -llua -ldl
56endif 57endif
58
59# Detect Android Termux environment
60# Termux typically has ANDROID_ROOT environment variable set and PREFIX points to Termux directory
61IS_TERMUX := false
62ANDROID_ROOT_VAR := $(shell echo $$ANDROID_ROOT)
63PREFIX_VAR := $(shell echo $$PREFIX)
64ifneq ($(ANDROID_ROOT_VAR),)
65 # Check if PREFIX environment variable points to Termux directory
66 ifneq ($(PREFIX_VAR),)
67 ifneq ($(findstring com.termux,$(PREFIX_VAR)),)
68 IS_TERMUX := true
69 endif
70 endif
71 # Alternative check: verify if Termux installation path exists
72 ifeq ($(IS_TERMUX),false)
73 ifneq ($(shell test -d /data/data/com.termux/files/usr && echo yes),)
74 IS_TERMUX := true
75 endif
76 endif
77endif
78
79# Auto-set NO_WATCHER for Termux environment if not explicitly set
80ifeq ($(IS_TERMUX),true)
81 ifeq ($(NO_WATCHER),)
82 NO_WATCHER := true
83 $(info Detected Android Termux environment, automatically setting NO_WATCHER=true)
84 endif
85endif
86
57ifeq ($(NO_WATCHER),true) 87ifeq ($(NO_WATCHER),true)
58 COMPILE_FLAGS += -DYUE_NO_WATCHER 88 COMPILE_FLAGS += -DYUE_NO_WATCHER
59endif 89endif
60 90
61# Add platform related linker flag 91# Add platform related linker flag
62ifneq ($(UNAME_S),Darwin) 92ifneq ($(UNAME_S),Darwin)
63 LINK_FLAGS += -lstdc++fs -Wl,-E 93 LINK_FLAGS += -Wl,-E
64 PLAT = linux 94 PLAT = linux
65else 95else
66 LINK_FLAGS += -framework CoreFoundation -framework CoreServices 96 LINK_FLAGS += -framework CoreFoundation -framework CoreServices
@@ -96,10 +126,13 @@ endif
96 126
97# Combine compiler and linker flags 127# Combine compiler and linker flags
98release: export CXXFLAGS := $(CXXFLAGS) $(COMPILE_FLAGS) $(RCOMPILE_FLAGS) 128release: export CXXFLAGS := $(CXXFLAGS) $(COMPILE_FLAGS) $(RCOMPILE_FLAGS)
129release: export CFLAGS := $(CFLAGS) $(filter-out -std=c++17,$(COMPILE_FLAGS)) $(RCOMPILE_FLAGS)
99release: export LDFLAGS := $(LDFLAGS) $(LINK_FLAGS) $(RLINK_FLAGS) 130release: export LDFLAGS := $(LDFLAGS) $(LINK_FLAGS) $(RLINK_FLAGS)
100debug: export CXXFLAGS := $(CXXFLAGS) $(COMPILE_FLAGS) $(DCOMPILE_FLAGS) 131debug: export CXXFLAGS := $(CXXFLAGS) $(COMPILE_FLAGS) $(DCOMPILE_FLAGS)
132debug: export CFLAGS := $(CFLAGS) $(filter-out -std=c++17,$(COMPILE_FLAGS)) $(DCOMPILE_FLAGS)
101debug: export LDFLAGS := $(LDFLAGS) $(LINK_FLAGS) $(DLINK_FLAGS) 133debug: export LDFLAGS := $(LDFLAGS) $(LINK_FLAGS) $(DLINK_FLAGS)
102shared: export CXXFLAGS := $(CXXFLAGS) $(COMPILE_FLAGS) $(RCOMPILE_FLAGS) $(TARGET_FLAGS) 134shared: export CXXFLAGS := $(CXXFLAGS) $(COMPILE_FLAGS) $(RCOMPILE_FLAGS) $(TARGET_FLAGS)
135shared: export CFLAGS := $(CFLAGS) $(filter-out -std=c++17,$(COMPILE_FLAGS)) $(RCOMPILE_FLAGS) $(TARGET_FLAGS)
103 136
104# Build and output paths 137# Build and output paths
105release: export BUILD_PATH := build/release 138release: export BUILD_PATH := build/release
@@ -134,9 +167,15 @@ ifeq ($(NO_LUA),true)
134 SOURCES := $(filter-out $(SRC_PATH)/yuescript/yuescript.cpp, $(SOURCES)) 167 SOURCES := $(filter-out $(SRC_PATH)/yuescript/yuescript.cpp, $(SOURCES))
135endif 168endif
136 169
170# Add colib ljson.c source file
171SOURCES += $(SRC_PATH)/3rdParty/colib/ljson.c
172
137# Set the object file names, with the source directory stripped 173# Set the object file names, with the source directory stripped
138# from the path, and the build path prepended in its place 174# from the path, and the build path prepended in its place
139OBJECTS = $(SOURCES:$(SRC_PATH)/%.$(SRC_EXT)=$(BUILD_PATH)/%.o) 175CPP_SOURCES = $(filter %.cpp,$(SOURCES))
176C_SOURCES = $(filter %.c,$(SOURCES))
177OBJECTS = $(CPP_SOURCES:$(SRC_PATH)/%.cpp=$(BUILD_PATH)/%.o)
178OBJECTS += $(C_SOURCES:$(SRC_PATH)/%.c=$(BUILD_PATH)/%.o)
140# Set the dependency files that will be used to add header dependencies 179# Set the dependency files that will be used to add header dependencies
141DEPS = $(OBJECTS:.o=.d) 180DEPS = $(OBJECTS:.o=.d)
142 181
@@ -225,8 +264,10 @@ wasm-node: clean
225 -O2 \ 264 -O2 \
226 -o wasm/dist/esm/yuescript.mjs \ 265 -o wasm/dist/esm/yuescript.mjs \
227 -I $(SRC_PATH) \ 266 -I $(SRC_PATH) \
267 -I $(SRC_PATH)/3rdParty/ \
228 -I $(SRC_PATH)/3rdParty/lua \ 268 -I $(SRC_PATH)/3rdParty/lua \
229 -std=c++17 \ 269 -std=c++17 \
270 -DYUE_UTF8_IMPL \
230 --bind \ 271 --bind \
231 -fexceptions \ 272 -fexceptions \
232 -Wno-deprecated-declarations \ 273 -Wno-deprecated-declarations \
@@ -265,8 +306,10 @@ wasm-node: clean
265 -o wasm/dist/cjs/yuescript.cjs \ 306 -o wasm/dist/cjs/yuescript.cjs \
266 --emit-tsd="yuescript.d.ts" \ 307 --emit-tsd="yuescript.d.ts" \
267 -I $(SRC_PATH) \ 308 -I $(SRC_PATH) \
309 -I $(SRC_PATH)/3rdParty/ \
268 -I $(SRC_PATH)/3rdParty/lua \ 310 -I $(SRC_PATH)/3rdParty/lua \
269 -std=c++17 \ 311 -std=c++17 \
312 -DYUE_UTF8_IMPL \
270 --bind \ 313 --bind \
271 -fexceptions \ 314 -fexceptions \
272 -Wno-deprecated-declarations \ 315 -Wno-deprecated-declarations \
@@ -309,8 +352,10 @@ wasm: clean
309 -O2 \ 352 -O2 \
310 -o doc/docs/.vuepress/public/js/yuescript.js \ 353 -o doc/docs/.vuepress/public/js/yuescript.js \
311 -I $(SRC_PATH) \ 354 -I $(SRC_PATH) \
355 -I $(SRC_PATH)/3rdParty/ \
312 -I $(SRC_PATH)/3rdParty/lua \ 356 -I $(SRC_PATH)/3rdParty/lua \
313 -std=c++17 \ 357 -std=c++17 \
358 -DYUE_UTF8_IMPL \
314 --bind \ 359 --bind \
315 -fexceptions \ 360 -fexceptions \
316 -Wno-deprecated-declarations 361 -Wno-deprecated-declarations
@@ -440,3 +485,11 @@ $(BUILD_PATH)/%.o: $(SRC_PATH)/%.$(SRC_EXT)
440 $(CMD_PREFIX)$(CXX) $(CXXFLAGS) $(INCLUDES) -MP -MMD -c $< -o $@ 485 $(CMD_PREFIX)$(CXX) $(CXXFLAGS) $(INCLUDES) -MP -MMD -c $< -o $@
441 @echo -en "\t Compile time: " 486 @echo -en "\t Compile time: "
442 @$(END_TIME) 487 @$(END_TIME)
488
489# C source file rules
490$(BUILD_PATH)/%.o: $(SRC_PATH)/%.c
491 @echo "Compiling: $< -> $@"
492 @$(START_TIME)
493 $(CMD_PREFIX)$(CC) $(CFLAGS) $(INCLUDES) -MP -MMD -c $< -o $@
494 @echo -en "\t Compile time: "
495 @$(END_TIME)
diff --git a/spec/inputs/destructure.yue b/spec/inputs/destructure.yue
index 674dfe4..179056c 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,53 @@ 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
281do
282 for {:a, :b} in *items
283 print a, b
284
285 for :a, :b in *items
286 print a, b
287
288 for :body in pairs data
289 print body if body
290
243nil 291nil
244 292
diff --git a/spec/inputs/funcs.yue b/spec/inputs/funcs.yue
index e647edc..d19c2d1 100644
--- a/spec/inputs/funcs.yue
+++ b/spec/inputs/funcs.yue
@@ -98,7 +98,7 @@ f(
98 98
99x = (a, 99x = (a,
100 b) -> 100 b) ->
101 print "what" 101 print "what"
102 102
103 103
104y = (a="hi", 104y = (a="hi",
@@ -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/import.yue b/spec/inputs/import.yue
index b8ffc24..ee1fdfc 100644
--- a/spec/inputs/import.yue
+++ b/spec/inputs/import.yue
@@ -23,7 +23,7 @@ do
23 b, c from z 23 b, c from z
24 24
25do 25do
26 import a 26 import a,
27 b 27 b
28 c from z 28 c from z
29 29
@@ -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..dd951a5 100644
--- a/spec/inputs/lists.yue
+++ b/spec/inputs/lists.yue
@@ -87,4 +87,194 @@ 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
137do
138 tb = [1, 2, 3]
139 tb[#] = 40
140 tb[# - 1] = 20
141
142do
143 a = b = c = "x"
144 lst = []
145 lst[#] = a
146 lst[# - 1] = b
147
148do
149 x, y, z = 1, 2, 3
150 arr = []
151 arr[#], head = x, y
152 arr[#] = z
153
154do
155 triple = ["keep", "skip", "tail"]
156 [head, _, tailv] = triple
157 buf = []
158 buf[#] = head
159 buf[#] = tailv
160
161do
162 src = ["a", "", "c", nil, "d"]
163 collected = []
164 for item in *src
165 if item and #item > 0
166 collected[#] = item
167
168do
169 nums = [1, 2, 3, 4, 5]
170 last_two = [v for v in *nums when v > 3]
171 nums[#] = last_two[1]
172 nums[#] = last_two[2]
173
174do
175 store = []
176 store[#] = { meta: { id: 1, ok: true }, payload: [10, 20] }
177 store[#] = { meta: { id: 1, ok: false }, payload: [10, 20, 30] }
178
179do
180 f = ->
181 q = []
182 tb.tmp = [n for n = 1, 4]
183 if #tb.tmp >= 3
184 q[#] = {head: tb.tmp[1], tail: tb.tmp[#]}
185
186do
187 make_pair = (a, b) -> [a, b]
188 pairs = []
189 p1 = make_pair 7, 8
190 pairs[#] = p1
191 k, v = "key", 42
192 pairs[#] = {k: k, v: v}
193
194do
195 cfg = {mode: "safe", tags: []}
196 if cfg.mode == "safe"
197 cfg.mode = "fast"
198 cfg.tags[#] = "newbie"
199
200do
201 mat = [ [1,2], [3,4], [5,6]]
202 last_row = mat[#]
203 rows = []
204 rows[#] = last_row[1]
205
206do
207 kv = []
208 kv[#] = {k: "a", v: 1}
209 kv[#] = {k: "b", v: 2}
210 pair_last = kv[#]
211 dict = {}
212 dict[pair_last.k] = pair_last.v
213 dict[pair_last.k] = 3
214
215do
216 base = [ i for i = 1, 4 ]
217 pack = []
218 pack[#] = [ base[1], base[#] ]
219 pack[#] = { first: base[1], last: base[#] }
220
221do
222 opts = {limit: 10}
223 {:limit, :offset = 0} = opts
224 pages = []
225 pages[#] = {limit: limit, offset: offset}
226
227do
228 chain = { a: { b: { c: 0 } }, list: [ {x:0}, {x:0} ] }
229 chain.a.b.c = 1
230 chain.list[1].x = 10
231 chain.list[#].x = 20
232 chain.list[# - 1] = { x: 30 }
233
234do
235 node = {left: {v:0}, right: {v:0}}
236 bag = []
237 { :left, :right } = node
238 bag[#], left.v, right.v = "k", 1, 2
239
240do
241 a1, a2, a3 = 100, 200, 300
242 mix = []
243 mix[#], mix[#], meta = a1, a2, {tag: "ok"}
244
245do
246 cfg2 = {limit: 5, opts: {flag: false}}
247 {limit: lim, opts: opt2} = cfg2
248 bucket = {xs: []}
249 bucket.xs[#], bucket.flag, opt2.flags[] = lim, true, 123
250
251do
252 ret2 = ()-> 7, 8
253 box = []
254 box[#], x1 = ret2!
255
256do
257 q = [1, 2]
258 lastq = q[#]
259 q[# - 1] = lastq * 10
260
261do
262 mat2 = [[9,8], [7,6]]
263 t = { hold: nil }
264 t.hold = mat2[#][1]
265
266do
267 f = -> globalTB[#][#] = 1
268 f1 = -> globalTB[#][# - 1]
269
270do
271 tbA[] = ...tbB
272 a, tb[], b[], c = 1, ...x, 3, 4
273
274 data =
275 a: {1,2,3}
276 b: {4,5,6}
277
278 flat = [...v for k,v in pairs data]
279
90nil 280nil
diff --git a/spec/inputs/loops.yue b/spec/inputs/loops.yue
index 9a91b42..5df10ca 100644
--- a/spec/inputs/loops.yue
+++ b/spec/inputs/loops.yue
@@ -251,4 +251,17 @@ do
251 if value > 5 251 if value > 5
252 item 252 item
253 253
254 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..611205d 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 7ff3118..2b0669c 100644
--- a/spec/inputs/switch.yue
+++ b/spec/inputs/switch.yue
@@ -220,4 +220,73 @@ do
220 ] 220 ]
221 print "matched", sixth 221 print "matched", sixth
222 222
223nil \ No newline at end of file 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/syntax.yue b/spec/inputs/syntax.yue
index a414d6f..eee518a 100644
--- a/spec/inputs/syntax.yue
+++ b/spec/inputs/syntax.yue
@@ -392,7 +392,7 @@ invokeA(
392v = { 392v = {
393 a -1 393 a -1
394 a( 394 a(
395-1) 395 -1)
396 a \ 396 a \
397- 1 397- 1
398 a-1 398 a-1
@@ -405,7 +405,7 @@ v = {
405 405
406 a ~1 406 a ~1
407 a( 407 a(
408~1) 408 ~1)
409 a \ 409 a \
410~ 1 410~ 1
411 a~1 411 a~1
@@ -478,5 +478,13 @@ do
478 f2 = -> 478 f2 = ->
479 -- 479 --
480 480
481do
482 return res if res ~= ""
483
484
485do
486 return res if res ~= ""
487 --
488
481nil 489nil
482 490
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/test/format_spec.yue b/spec/inputs/test/format_spec.yue
index cbd9d22..3ad2c7f 100644
--- a/spec/inputs/test/format_spec.yue
+++ b/spec/inputs/test/format_spec.yue
@@ -119,7 +119,7 @@ for file in *files
119 original_ast = yue.to_ast code 119 original_ast = yue.to_ast code
120 assert.is_not_nil original_ast 120 assert.is_not_nil original_ast
121 rewriteLineCol original_ast 121 rewriteLineCol original_ast
122 formated = yue.format code 122 formated = yue.format code, 0, false
123 ast = yue.to_ast formated 123 ast = yue.to_ast formated
124 assert.is_not_nil ast 124 assert.is_not_nil ast
125 rewriteLineCol ast 125 rewriteLineCol ast
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/funcs.yue b/spec/inputs/unicode/funcs.yue
index c563356..cb35500 100644
--- a/spec/inputs/unicode/funcs.yue
+++ b/spec/inputs/unicode/funcs.yue
@@ -98,7 +98,7 @@ _无效å˜é‡ = -> 真å if æŸç‰©
98 98
99å˜é‡x = (傿•°a, 99å˜é‡x = (傿•°a,
100 傿•°b) -> 100 傿•°b) ->
101 æ‰“å° "什么" 101 æ‰“å° "什么"
102 102
103 103
104å˜é‡y = (傿•°a="hi", 104å˜é‡y = (傿•°a="hi",
diff --git a/spec/inputs/unicode/import.yue b/spec/inputs/unicode/import.yue
index c229edb..a7724ab 100644
--- a/spec/inputs/unicode/import.yue
+++ b/spec/inputs/unicode/import.yue
@@ -23,7 +23,7 @@ do
23 字段b, 字段c from 对象z 23 字段b, 字段c from 对象z
24 24
25do 25do
26 import 字段a 26 import 字段a,
27 字段b 27 字段b
28 字段c from 对象z 28 字段c from 对象z
29 29
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/syntax.yue b/spec/inputs/unicode/syntax.yue
index 8a98416..01d5c87 100644
--- a/spec/inputs/unicode/syntax.yue
+++ b/spec/inputs/unicode/syntax.yue
@@ -376,7 +376,7 @@ with 对象
376å˜é‡v = { 376å˜é‡v = {
377 å˜é‡a -1 377 å˜é‡a -1
378 å˜é‡a( 378 å˜é‡a(
379-1) 379 -1)
380 å˜é‡a \ 380 å˜é‡a \
381- 1 381- 1
382 å˜é‡a-1 382 å˜é‡a-1
@@ -389,7 +389,7 @@ with 对象
389 389
390 å˜é‡a ~1 390 å˜é‡a ~1
391 å˜é‡a( 391 å˜é‡a(
392~1) 392 ~1)
393 å˜é‡a \ 393 å˜é‡a \
394~ 1 394~ 1
395 å˜é‡a~1 395 å˜é‡a~1
diff --git a/spec/inputs/unicode/vararg.yue b/spec/inputs/unicode/vararg.yue
index e59e114..b508fbb 100644
--- a/spec/inputs/unicode/vararg.yue
+++ b/spec/inputs/unicode/vararg.yue
@@ -55,12 +55,12 @@
55 _ = -> 55 _ = ->
56 列表 = {1, 2, 3, 4, 5} 56 列表 = {1, 2, 3, 4, 5}
57 函数å = (确定) -> 57 函数å = (确定) ->
58 确定, table.unpack 列表 58 确定, table.unpack 列表
59 确定, ... = 函数å true 59 确定, ... = 函数å true
60 æ‰“å° ç¡®å®š, ... 60 æ‰“å° ç¡®å®š, ...
61 61
62 å¤šå‚æ•°å‡½æ•° = -> 62 å¤šå‚æ•°å‡½æ•° = ->
63 10, nil, 20, nil, 30 63 10, nil, 20, nil, 30
64 64
65 ... = å¤šå‚æ•°å‡½æ•°! 65 ... = å¤šå‚æ•°å‡½æ•°!
66 æ‰“å° select "#", ... 66 æ‰“å° select "#", ...
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/vararg.yue b/spec/inputs/vararg.yue
index 941cd97..4f8a0d7 100644
--- a/spec/inputs/vararg.yue
+++ b/spec/inputs/vararg.yue
@@ -55,12 +55,12 @@ join = (...) ->
55 _ = -> 55 _ = ->
56 list = {1, 2, 3, 4, 5} 56 list = {1, 2, 3, 4, 5}
57 fn = (ok) -> 57 fn = (ok) ->
58 ok, table.unpack list 58 ok, table.unpack list
59 ok, ... = fn true 59 ok, ... = fn true
60 print ok, ... 60 print ok, ...
61 61
62 fn_many_args = -> 62 fn_many_args = ->
63 10, nil, 20, nil, 30 63 10, nil, 20, nil, 30
64 64
65 ... = fn_many_args! 65 ... = fn_many_args!
66 print select "#", ... 66 print select "#", ...
@@ -86,3 +86,47 @@ join = (...) ->
86 print ... 86 print ...
87 nil 87 nil
88 88
89do
90 f1 = (...t) ->
91 print t.n
92 print #t
93 for i = 1, t.n
94 print t[i]
95
96 f1 1, 2, 3
97 f1 "a", "b", "c", "d"
98 f1!
99
100 f2 = (...args) ->
101 print "args count:", args.n
102 print "args length:", #args
103 for i = 1, args.n
104 if args[i] == nil
105 print "position", i, "is nil"
106 else
107 print "position", i, ":", args[i]
108
109 f2 1, nil, 3, nil, 5
110
111 f3 = (prefix, ...items) ->
112 result = {}
113 for i = 1, items.n
114 result[i] = prefix .. tostring items[i]
115 result
116
117 f3 "item_", 1, 2, 3
118
119 f4 = (...empty) ->
120 print "empty count:", empty.n
121 print "empty length:", #empty
122
123 f4!
124
125 process = (...data) ->
126 sum = 0
127 for i = 1, data.n
128 if type(data[i]) == "number"
129 sum += data[i]
130 sum
131
132 process 1, 2, 3, "skip", 5
diff --git a/spec/inputs/with.yue b/spec/inputs/with.yue
index 3fee48e..19ed2a7 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
@@ -161,4 +161,13 @@ do
161 if .v 161 if .v
162 break .a 162 break .a
163 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
164nil 173nil
diff --git a/spec/outputs/5.1/loops.lua b/spec/outputs/5.1/loops.lua
index bc720f6..e4f2871 100644
--- a/spec/outputs/5.1/loops.lua
+++ b/spec/outputs/5.1/loops.lua
@@ -587,3 +587,31 @@ do
587 end 587 end
588 list = _accum_0 588 list = _accum_0
589end 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 3ee20bb..de5abdd 100644
--- a/spec/outputs/codes_from_doc.lua
+++ b/spec/outputs/codes_from_doc.lua
@@ -73,8 +73,8 @@ local apple = setmetatable({
73if (getmetatable(apple) ~= nil) then 73if (getmetatable(apple) ~= nil) then
74 p(apple.size, apple.color, getmetatable(apple).__index) 74 p(apple.size, apple.color, getmetatable(apple).__index)
75end 75end
76local _ud83c_udf1b = "月之脚本" 76local _u1f31b = "月之脚本"
77_module_0["🌛"] = _ud83c_udf1b 77_module_0["🌛"] = _u1f31b
78return _module_0 78return _module_0
79local area = 6.2831853071796 * 5 79local area = 6.2831853071796 * 5
80print('hello world') 80print('hello world')
@@ -109,6 +109,12 @@ end
109print("yuescript") 109print("yuescript")
110print(3) 110print(3)
111print("Valid enum type:", "Static") 111print("Valid enum type:", "Static")
112do
113 print(123, "hello")
114end
115do
116 print(123, "hello")
117end
112if tb ~= nil then 118if tb ~= nil then
113 tb:func() 119 tb:func()
114end 120end
@@ -141,6 +147,21 @@ print((function()
141end)()) 147end)())
142local tab = { } 148local tab = { }
143tab[#tab + 1] = "Value" 149tab[#tab + 1] = "Value"
150local tbA = {
151 1,
152 2,
153 3
154}
155local tbB = {
156 4,
157 5,
158 6
159}
160local _len_0 = #tbA + 1
161for _index_0 = 1, #tbB do
162 local _elm_0 = tbB[_index_0]
163 tbA[_len_0], _len_0 = _elm_0, _len_0 + 1
164end
144local parts = { 165local parts = {
145 "shoulders", 166 "shoulders",
146 "knees" 167 "knees"
@@ -209,6 +230,18 @@ for _key_0, _value_0 in pairs(b) do
209 end 230 end
210end 231end
211merge = _tab_0 232merge = _tab_0
233local last
234do
235 local _item_0 = data.items
236 last = _item_0[#_item_0]
237end
238local second_last
239do
240 local _item_0 = data.items
241 second_last = _item_0[#_item_0 - 1]
242end
243local _obj_0 = data.items
244_obj_0[#_obj_0] = 1
212local mt = { } 245local mt = { }
213local add 246local add
214add = function(self, right) 247add = function(self, right)
@@ -339,6 +372,14 @@ func({
339 2, 372 2,
340 3 373 3
341}) 374})
375local f
376f = function()
377 return {
378 1,
379 2,
380 3
381 }
382end
342local tb = { 383local tb = {
343 name = "abc", 384 name = "abc",
344 values = { 385 values = {
@@ -579,6 +620,59 @@ end
579local two, four 620local two, four
580local _obj_0 = items 621local _obj_0 = items
581two, four = _obj_0[2], _obj_0[4] 622two, four = _obj_0[2], _obj_0[4]
623local orders = {
624 "first",
625 "second",
626 "third",
627 "fourth",
628 "last"
629}
630local first, bulk, last = orders[1], (function()
631 local _accum_0 = { }
632 local _len_0 = 1
633 local _max_0 = #orders + -2 + 1
634 for _index_0 = 2, _max_0 do
635 local _item_0 = orders[_index_0]
636 _accum_0[_len_0] = _item_0
637 _len_0 = _len_0 + 1
638 end
639 return _accum_0
640end)(), orders[#orders]
641print(first)
642print(bulk)
643print(last)
644local first, rest
645do
646 local _obj_0 = orders
647 first, rest = _obj_0[1], (function()
648 local _accum_0 = { }
649 local _len_0 = 1
650 local _max_0 = #_obj_0
651 for _index_0 = 2, _max_0 do
652 local _item_0 = _obj_0[_index_0]
653 _accum_0[_len_0] = _item_0
654 _len_0 = _len_0 + 1
655 end
656 return _accum_0
657 end)()
658end
659local start, last
660do
661 local _obj_0 = orders
662 start, last = (function()
663 local _accum_0 = { }
664 local _len_0 = 1
665 local _max_0 = #_obj_0 + -2 + 1
666 for _index_0 = 1, _max_0 do
667 local _item_0 = _obj_0[_index_0]
668 _accum_0[_len_0] = _item_0
669 _len_0 = _len_0 + 1
670 end
671 return _accum_0
672 end)(), _obj_0[#_obj_0]
673end
674local _obj_0 = orders
675first, last = _obj_0[1], _obj_0[#_obj_0]
582local tuples = { 676local tuples = {
583 { 677 {
584 "hello", 678 "hello",
@@ -643,6 +737,36 @@ end
643 local first = select(1, ...) 737 local first = select(1, ...)
644 return print(ok, count, first) 738 return print(ok, count, first)
645end)(fn(true)) 739end)(fn(true))
740local f
741f = function(...)
742 local t = {
743 n = select("#", ...),
744 ...
745 }
746 print("argument count:", t.n)
747 print("table length:", #t)
748 for i = 1, t.n do
749 print(t[i])
750 end
751end
752f(1, 2, 3)
753f("a", "b", "c", "d")
754f()
755local process
756process = function(...)
757 local args = {
758 n = select("#", ...),
759 ...
760 }
761 local sum = 0
762 for i = 1, args.n do
763 if args[i] ~= nil and type(args[i]) == "number" then
764 sum = sum + args[i]
765 end
766 end
767 return sum
768end
769process(1, nil, 3, nil, 5)
646Rx.Observable.fromRange(1, 8):filter(function(x) 770Rx.Observable.fromRange(1, 8):filter(function(x)
647 return x % 2 == 0 771 return x % 2 == 0
648end):concat(Rx.Observable.of('who do we appreciate')):map(function(value) 772end):concat(Rx.Observable.of('who do we appreciate')):map(function(value)
@@ -680,6 +804,56 @@ end)
680if success then 804if success then
681 print(result) 805 print(result)
682end 806end
807local a, b, c
808do
809 local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function()
810 return func()
811 end)
812 if _ok_0 then
813 a, b, c = _ret_0, _ret_1, _ret_2
814 end
815end
816do
817 local _exp_0 = ((function()
818 return (function(_arg_0, ...)
819 local _ok_0 = _arg_0
820 if _ok_0 then
821 return ...
822 end
823 end)(pcall(function()
824 return func()
825 end))
826 end)())
827 if _exp_0 ~= nil then
828 a = _exp_0
829 else
830 a = "default"
831 end
832end
833f((function()
834 return (function(_arg_0, ...)
835 local _ok_0 = _arg_0
836 if _ok_0 then
837 return ...
838 end
839 end)(pcall(function()
840 return func()
841 end))
842end)())
843f((function()
844 return (function(_arg_0, ...)
845 local _ok_0 = _arg_0
846 if _ok_0 then
847 return ...
848 end
849 end)(xpcall(function()
850 print(123)
851 return func()
852 end, function(e)
853 print(e)
854 return e
855 end))
856end)())
683local a <const> = 123 857local a <const> = 123
684local _ <close> = setmetatable({ }, { 858local _ <close> = setmetatable({ }, {
685 __close = function() 859 __close = function()
@@ -695,6 +869,13 @@ print("I am " .. tostring(math.random() * 100) .. "% sure.")
695local integer = 1000000 869local integer = 1000000
696local hex = 0xEFBBBF 870local hex = 0xEFBBBF
697local binary = 19 871local binary = 19
872local str = "key: value\nlist:\n - item1\n - " .. tostring(expr)
873local fn
874fn = function()
875 local str = "foo:\n bar: baz"
876 return str
877end
878local str = "path: \"C:\\Program Files\\App\"\nnote: 'He said: \"" .. tostring(Hello) .. "!\"'"
698local my_function 879local my_function
699my_function = function() end 880my_function = function() end
700my_function() 881my_function()
@@ -789,6 +970,36 @@ if func(1, 2, 3, "hello", "world") then
789 print("hello") 970 print("hello")
790 print("I am inside if") 971 print("I am inside if")
791end 972end
973local f1
974f1 = function(_arg_0)
975 local a, b, c
976 a, b, c = _arg_0.a, _arg_0.b, _arg_0.c
977 return print(a, b, c)
978end
979f1({
980 a = 1,
981 b = "2",
982 c = { }
983})
984local f2
985f2 = function(_arg_0, c)
986 local a1, b
987 a1, b = _arg_0.a, _arg_0.b
988 if a1 == nil then
989 a1 = 123
990 end
991 if b == nil then
992 b = 'abc'
993 end
994 if c == nil then
995 c = { }
996 end
997 return print(a1, b, c)
998end
999local arg1 = {
1000 a = 0
1001}
1002f2(arg1, arg2)
792f(function() 1003f(function()
793 return print("hello") 1004 return print("hello")
794end) 1005end)
@@ -914,6 +1125,28 @@ for _index_0 = 1, #_list_0 do
914 _len_0 = _len_0 + 1 1125 _len_0 = _len_0 + 1
915end 1126end
916doubled = _accum_0 1127doubled = _accum_0
1128local data = {
1129 a = {
1130 1,
1131 2,
1132 3
1133 },
1134 b = {
1135 4,
1136 5,
1137 6
1138 }
1139}
1140local flat
1141local _accum_0 = { }
1142for k, v in pairs(data) do
1143 local _len_0 = #_accum_0 + 1
1144 for _index_0 = 1, #v do
1145 local _elm_0 = v[_index_0]
1146 _accum_0[_len_0], _len_0 = _elm_0, _len_0 + 1
1147 end
1148end
1149flat = _accum_0
917local x_coords = { 1150local x_coords = {
918 4, 1151 4,
919 5, 1152 5,
@@ -1004,8 +1237,18 @@ local slice
1004local _accum_0 = { } 1237local _accum_0 = { }
1005local _len_0 = 1 1238local _len_0 = 1
1006local _list_0 = items 1239local _list_0 = items
1007local _max_0 = 5 1240for _index_0 = 1, 5 do
1008for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do 1241 local item = _list_0[_index_0]
1242 _accum_0[_len_0] = item
1243 _len_0 = _len_0 + 1
1244end
1245slice = _accum_0
1246local slice
1247local _accum_0 = { }
1248local _len_0 = 1
1249local _list_0 = items
1250local _max_0 = #_list_0
1251for _index_0 = 2, _max_0 do
1009 local item = _list_0[_index_0] 1252 local item = _list_0[_index_0]
1010 _accum_0[_len_0] = item 1253 _accum_0[_len_0] = item
1011 _len_0 = _len_0 + 1 1254 _len_0 = _len_0 + 1
@@ -1015,7 +1258,8 @@ local slice
1015local _accum_0 = { } 1258local _accum_0 = { }
1016local _len_0 = 1 1259local _len_0 = 1
1017local _list_0 = items 1260local _list_0 = items
1018for _index_0 = 2, #_list_0 do 1261local _max_0 = #_list_0
1262for _index_0 = 1, _max_0, 2 do
1019 local item = _list_0[_index_0] 1263 local item = _list_0[_index_0]
1020 _accum_0[_len_0] = item 1264 _accum_0[_len_0] = item
1021 _len_0 = _len_0 + 1 1265 _len_0 = _len_0 + 1
@@ -1025,12 +1269,35 @@ local slice
1025local _accum_0 = { } 1269local _accum_0 = { }
1026local _len_0 = 1 1270local _len_0 = 1
1027local _list_0 = items 1271local _list_0 = items
1028for _index_0 = 1, #_list_0, 2 do 1272local _min_0 = #_list_0 + -4 + 1
1273local _max_0 = #_list_0 + -1 + 1
1274for _index_0 = _min_0, _max_0 do
1029 local item = _list_0[_index_0] 1275 local item = _list_0[_index_0]
1030 _accum_0[_len_0] = item 1276 _accum_0[_len_0] = item
1031 _len_0 = _len_0 + 1 1277 _len_0 = _len_0 + 1
1032end 1278end
1033slice = _accum_0 1279slice = _accum_0
1280local reverse_slice
1281local _accum_0 = { }
1282local _len_0 = 1
1283local _list_0 = items
1284local _min_0 = #_list_0 + -1 + 1
1285for _index_0 = _min_0, 1, -1 do
1286 local item = _list_0[_index_0]
1287 _accum_0[_len_0] = item
1288 _len_0 = _len_0 + 1
1289end
1290reverse_slice = _accum_0
1291local sub_list
1292local _accum_0 = { }
1293local _len_0 = 1
1294local _list_0 = items
1295for _index_0 = 2, 4 do
1296 local _item_0 = _list_0[_index_0]
1297 _accum_0[_len_0] = _item_0
1298 _len_0 = _len_0 + 1
1299end
1300sub_list = _accum_0
1034for i = 10, 20 do 1301for i = 10, 20 do
1035 print(i) 1302 print(i)
1036end 1303end
@@ -1041,8 +1308,7 @@ for key, value in pairs(object) do
1041 print(key, value) 1308 print(key, value)
1042end 1309end
1043local _list_0 = items 1310local _list_0 = items
1044local _max_0 = 4 1311for _index_0 = 2, 4 do
1045for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do
1046 local item = _list_0[_index_0] 1312 local item = _list_0[_index_0]
1047 print(item) 1313 print(item)
1048end 1314end
@@ -1226,7 +1492,7 @@ if "Robert" == name then
1226elseif "Dan" == name or "Daniel" == name then 1492elseif "Dan" == name or "Daniel" == name then
1227 print("Your name, it's Dan") 1493 print("Your name, it's Dan")
1228else 1494else
1229 print("I don't know about your name") 1495 print("I don't know about you with name " .. tostring(name))
1230end 1496end
1231local b = 1 1497local b = 1
1232local next_number 1498local next_number
@@ -1483,6 +1749,35 @@ if _tab_0 then
1483 print("matched", fourth) 1749 print("matched", fourth)
1484 end 1750 end
1485end 1751end
1752local segments = {
1753 "admin",
1754 "users",
1755 "logs",
1756 "view"
1757}
1758local _type_0 = type(segments)
1759local _tab_0 = "table" == _type_0 or "userdata" == _type_0
1760if _tab_0 then
1761 local groups
1762 do
1763 local _accum_0 = { }
1764 local _len_0 = 1
1765 local _max_0 = #segments + -3 + 1
1766 for _index_0 = 1, _max_0 do
1767 local _item_0 = segments[_index_0]
1768 _accum_0[_len_0] = _item_0
1769 _len_0 = _len_0 + 1
1770 end
1771 groups = _accum_0
1772 end
1773 local resource = segments[#segments - 1]
1774 local action = segments[#segments]
1775 if resource ~= nil and action ~= nil then
1776 print("Group:", groups)
1777 print("Resource:", resource)
1778 print("Action:", action)
1779 end
1780end
1486local Inventory 1781local Inventory
1487local _class_0 1782local _class_0
1488local _base_0 = { 1783local _base_0 = {
@@ -2139,6 +2434,10 @@ do
2139 _with_1["key-name"] = value 2434 _with_1["key-name"] = value
2140end 2435end
2141_with_0[#_with_0 + 1] = "abc" 2436_with_0[#_with_0 + 1] = "abc"
2437local _with_0 = obj
2438if _with_0 ~= nil then
2439 print(obj.name)
2440end
2142do 2441do
2143 local var = "hello" 2442 local var = "hello"
2144 print(var) 2443 print(var)
@@ -2282,8 +2581,8 @@ local apple = setmetatable({
2282if (getmetatable(apple) ~= nil) then 2581if (getmetatable(apple) ~= nil) then
2283 p(apple.size, apple.color, getmetatable(apple).__index) 2582 p(apple.size, apple.color, getmetatable(apple).__index)
2284end 2583end
2285local _ud83c_udf1b = "月之脚本" 2584local _u1f31b = "月之脚本"
2286_module_0["🌛"] = _ud83c_udf1b 2585_module_0["🌛"] = _u1f31b
2287return _module_0 2586return _module_0
2288local area = 6.2831853071796 * 5 2587local area = 6.2831853071796 * 5
2289print('hello world') 2588print('hello world')
@@ -2318,6 +2617,12 @@ end
2318print("yuescript") 2617print("yuescript")
2319print(3) 2618print(3)
2320print("Valid enum type:", "Static") 2619print("Valid enum type:", "Static")
2620do
2621 print(123, "hello")
2622end
2623do
2624 print(123, "hello")
2625end
2321if tb ~= nil then 2626if tb ~= nil then
2322 tb:func() 2627 tb:func()
2323end 2628end
@@ -2350,6 +2655,21 @@ print((function()
2350end)()) 2655end)())
2351local tab = { } 2656local tab = { }
2352tab[#tab + 1] = "Value" 2657tab[#tab + 1] = "Value"
2658local tbA = {
2659 1,
2660 2,
2661 3
2662}
2663local tbB = {
2664 4,
2665 5,
2666 6
2667}
2668local _len_0 = #tbA + 1
2669for _index_0 = 1, #tbB do
2670 local _elm_0 = tbB[_index_0]
2671 tbA[_len_0], _len_0 = _elm_0, _len_0 + 1
2672end
2353local parts = { 2673local parts = {
2354 "shoulders", 2674 "shoulders",
2355 "knees" 2675 "knees"
@@ -2418,6 +2738,18 @@ for _key_0, _value_0 in pairs(b) do
2418 end 2738 end
2419end 2739end
2420merge = _tab_0 2740merge = _tab_0
2741local last
2742do
2743 local _item_0 = data.items
2744 last = _item_0[#_item_0]
2745end
2746local second_last
2747do
2748 local _item_0 = data.items
2749 second_last = _item_0[#_item_0 - 1]
2750end
2751local _obj_0 = data.items
2752_obj_0[#_obj_0] = 1
2421local mt = { } 2753local mt = { }
2422local add 2754local add
2423add = function(self, right) 2755add = function(self, right)
@@ -2548,6 +2880,14 @@ func({
2548 2, 2880 2,
2549 3 2881 3
2550}) 2882})
2883local f
2884f = function()
2885 return {
2886 1,
2887 2,
2888 3
2889 }
2890end
2551local tb = { 2891local tb = {
2552 name = "abc", 2892 name = "abc",
2553 values = { 2893 values = {
@@ -2788,6 +3128,59 @@ end
2788local two, four 3128local two, four
2789local _obj_0 = items 3129local _obj_0 = items
2790two, four = _obj_0[2], _obj_0[4] 3130two, four = _obj_0[2], _obj_0[4]
3131local orders = {
3132 "first",
3133 "second",
3134 "third",
3135 "fourth",
3136 "last"
3137}
3138local first, bulk, last = orders[1], (function()
3139 local _accum_0 = { }
3140 local _len_0 = 1
3141 local _max_0 = #orders + -2 + 1
3142 for _index_0 = 2, _max_0 do
3143 local _item_0 = orders[_index_0]
3144 _accum_0[_len_0] = _item_0
3145 _len_0 = _len_0 + 1
3146 end
3147 return _accum_0
3148end)(), orders[#orders]
3149print(first)
3150print(bulk)
3151print(last)
3152local first, rest
3153do
3154 local _obj_0 = orders
3155 first, rest = _obj_0[1], (function()
3156 local _accum_0 = { }
3157 local _len_0 = 1
3158 local _max_0 = #_obj_0
3159 for _index_0 = 2, _max_0 do
3160 local _item_0 = _obj_0[_index_0]
3161 _accum_0[_len_0] = _item_0
3162 _len_0 = _len_0 + 1
3163 end
3164 return _accum_0
3165 end)()
3166end
3167local start, last
3168do
3169 local _obj_0 = orders
3170 start, last = (function()
3171 local _accum_0 = { }
3172 local _len_0 = 1
3173 local _max_0 = #_obj_0 + -2 + 1
3174 for _index_0 = 1, _max_0 do
3175 local _item_0 = _obj_0[_index_0]
3176 _accum_0[_len_0] = _item_0
3177 _len_0 = _len_0 + 1
3178 end
3179 return _accum_0
3180 end)(), _obj_0[#_obj_0]
3181end
3182local _obj_0 = orders
3183first, last = _obj_0[1], _obj_0[#_obj_0]
2791local tuples = { 3184local tuples = {
2792 { 3185 {
2793 "hello", 3186 "hello",
@@ -2852,6 +3245,36 @@ end
2852 local first = select(1, ...) 3245 local first = select(1, ...)
2853 return print(ok, count, first) 3246 return print(ok, count, first)
2854end)(fn(true)) 3247end)(fn(true))
3248local f
3249f = function(...)
3250 local t = {
3251 n = select("#", ...),
3252 ...
3253 }
3254 print("argument count:", t.n)
3255 print("table length:", #t)
3256 for i = 1, t.n do
3257 print(t[i])
3258 end
3259end
3260f(1, 2, 3)
3261f("a", "b", "c", "d")
3262f()
3263local process
3264process = function(...)
3265 local args = {
3266 n = select("#", ...),
3267 ...
3268 }
3269 local sum = 0
3270 for i = 1, args.n do
3271 if args[i] ~= nil and type(args[i]) == "number" then
3272 sum = sum + args[i]
3273 end
3274 end
3275 return sum
3276end
3277process(1, nil, 3, nil, 5)
2855Rx.Observable.fromRange(1, 8):filter(function(x) 3278Rx.Observable.fromRange(1, 8):filter(function(x)
2856 return x % 2 == 0 3279 return x % 2 == 0
2857end):concat(Rx.Observable.of('who do we appreciate')):map(function(value) 3280end):concat(Rx.Observable.of('who do we appreciate')):map(function(value)
@@ -2889,6 +3312,56 @@ end)
2889if success then 3312if success then
2890 print(result) 3313 print(result)
2891end 3314end
3315local a, b, c
3316do
3317 local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function()
3318 return func()
3319 end)
3320 if _ok_0 then
3321 a, b, c = _ret_0, _ret_1, _ret_2
3322 end
3323end
3324do
3325 local _exp_0 = ((function()
3326 return (function(_arg_0, ...)
3327 local _ok_0 = _arg_0
3328 if _ok_0 then
3329 return ...
3330 end
3331 end)(pcall(function()
3332 return func()
3333 end))
3334 end)())
3335 if _exp_0 ~= nil then
3336 a = _exp_0
3337 else
3338 a = "default"
3339 end
3340end
3341f((function()
3342 return (function(_arg_0, ...)
3343 local _ok_0 = _arg_0
3344 if _ok_0 then
3345 return ...
3346 end
3347 end)(pcall(function()
3348 return func()
3349 end))
3350end)())
3351f((function()
3352 return (function(_arg_0, ...)
3353 local _ok_0 = _arg_0
3354 if _ok_0 then
3355 return ...
3356 end
3357 end)(xpcall(function()
3358 print(123)
3359 return func()
3360 end, function(e)
3361 print(e)
3362 return e
3363 end))
3364end)())
2892local a <const> = 123 3365local a <const> = 123
2893local _ <close> = setmetatable({ }, { 3366local _ <close> = setmetatable({ }, {
2894 __close = function() 3367 __close = function()
@@ -2903,6 +3376,14 @@ local some_string = "Here is a string\n that has a line break in it."
2903print("I am " .. tostring(math.random() * 100) .. "% sure.") 3376print("I am " .. tostring(math.random() * 100) .. "% sure.")
2904local integer = 1000000 3377local integer = 1000000
2905local hex = 0xEFBBBF 3378local hex = 0xEFBBBF
3379local binary = 19
3380local str = "key: value\nlist:\n - item1\n - " .. tostring(expr)
3381local fn
3382fn = function()
3383 local str = "foo:\n bar: baz"
3384 return str
3385end
3386local str = "path: \"C:\\Program Files\\App\"\nnote: 'He said: \"" .. tostring(Hello) .. "!\"'"
2906local my_function 3387local my_function
2907my_function = function() end 3388my_function = function() end
2908my_function() 3389my_function()
@@ -2997,6 +3478,66 @@ if func(1, 2, 3, "hello", "world") then
2997 print("hello") 3478 print("hello")
2998 print("I am inside if") 3479 print("I am inside if")
2999end 3480end
3481local f1
3482f1 = function(_arg_0)
3483 local a, b, c
3484 a, b, c = _arg_0.a, _arg_0.b, _arg_0.c
3485 return print(a, b, c)
3486end
3487f1({
3488 a = 1,
3489 b = "2",
3490 c = { }
3491})
3492local f2
3493f2 = function(_arg_0, c)
3494 local a1, b
3495 a1, b = _arg_0.a, _arg_0.b
3496 if a1 == nil then
3497 a1 = 123
3498 end
3499 if b == nil then
3500 b = 'abc'
3501 end
3502 if c == nil then
3503 c = { }
3504 end
3505end
3506print(a1, b, c)
3507local arg1 = {
3508 a = 0
3509}
3510f2(arg1, arg2)
3511local findFirstEven
3512findFirstEven = function(list)
3513 for _index_0 = 1, #list do
3514 local item = list[_index_0]
3515 if type(item) == "table" then
3516 for _index_1 = 1, #item do
3517 local sub = item[_index_1]
3518 if sub % 2 == 0 then
3519 return sub
3520 end
3521 end
3522 end
3523 end
3524 return nil
3525end
3526local findFirstEven
3527findFirstEven = function(list)
3528 for _index_0 = 1, #list do
3529 local item = list[_index_0]
3530 if type(item) == "table" then
3531 for _index_1 = 1, #item do
3532 local sub = item[_index_1]
3533 if sub % 2 == 0 then
3534 return sub
3535 end
3536 end
3537 end
3538 end
3539 return nil
3540end
3000f(function() 3541f(function()
3001 return print("hello") 3542 return print("hello")
3002end) 3543end)
@@ -3122,6 +3663,28 @@ for _index_0 = 1, #_list_0 do
3122 _len_0 = _len_0 + 1 3663 _len_0 = _len_0 + 1
3123end 3664end
3124doubled = _accum_0 3665doubled = _accum_0
3666local data = {
3667 a = {
3668 1,
3669 2,
3670 3
3671 },
3672 b = {
3673 4,
3674 5,
3675 6
3676 }
3677}
3678local flat
3679local _accum_0 = { }
3680for k, v in pairs(data) do
3681 local _len_0 = #_accum_0 + 1
3682 for _index_0 = 1, #v do
3683 local _elm_0 = v[_index_0]
3684 _accum_0[_len_0], _len_0 = _elm_0, _len_0 + 1
3685 end
3686end
3687flat = _accum_0
3125local x_coords = { 3688local x_coords = {
3126 4, 3689 4,
3127 5, 3690 5,
@@ -3212,8 +3775,7 @@ local slice
3212local _accum_0 = { } 3775local _accum_0 = { }
3213local _len_0 = 1 3776local _len_0 = 1
3214local _list_0 = items 3777local _list_0 = items
3215local _max_0 = 5 3778for _index_0 = 1, 5 do
3216for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do
3217 local item = _list_0[_index_0] 3779 local item = _list_0[_index_0]
3218 _accum_0[_len_0] = item 3780 _accum_0[_len_0] = item
3219 _len_0 = _len_0 + 1 3781 _len_0 = _len_0 + 1
@@ -3223,7 +3785,8 @@ local slice
3223local _accum_0 = { } 3785local _accum_0 = { }
3224local _len_0 = 1 3786local _len_0 = 1
3225local _list_0 = items 3787local _list_0 = items
3226for _index_0 = 2, #_list_0 do 3788local _max_0 = #_list_0
3789for _index_0 = 2, _max_0 do
3227 local item = _list_0[_index_0] 3790 local item = _list_0[_index_0]
3228 _accum_0[_len_0] = item 3791 _accum_0[_len_0] = item
3229 _len_0 = _len_0 + 1 3792 _len_0 = _len_0 + 1
@@ -3233,12 +3796,46 @@ local slice
3233local _accum_0 = { } 3796local _accum_0 = { }
3234local _len_0 = 1 3797local _len_0 = 1
3235local _list_0 = items 3798local _list_0 = items
3236for _index_0 = 1, #_list_0, 2 do 3799local _max_0 = #_list_0
3800for _index_0 = 1, _max_0, 2 do
3237 local item = _list_0[_index_0] 3801 local item = _list_0[_index_0]
3238 _accum_0[_len_0] = item 3802 _accum_0[_len_0] = item
3239 _len_0 = _len_0 + 1 3803 _len_0 = _len_0 + 1
3240end 3804end
3241slice = _accum_0 3805slice = _accum_0
3806local slice
3807local _accum_0 = { }
3808local _len_0 = 1
3809local _list_0 = items
3810local _min_0 = #_list_0 + -4 + 1
3811local _max_0 = #_list_0 + -1 + 1
3812for _index_0 = _min_0, _max_0 do
3813 local item = _list_0[_index_0]
3814 _accum_0[_len_0] = item
3815 _len_0 = _len_0 + 1
3816end
3817slice = _accum_0
3818local reverse_slice
3819local _accum_0 = { }
3820local _len_0 = 1
3821local _list_0 = items
3822local _min_0 = #_list_0 + -1 + 1
3823for _index_0 = _min_0, 1, -1 do
3824 local item = _list_0[_index_0]
3825 _accum_0[_len_0] = item
3826 _len_0 = _len_0 + 1
3827end
3828reverse_slice = _accum_0
3829local sub_list
3830local _accum_0 = { }
3831local _len_0 = 1
3832local _list_0 = items
3833for _index_0 = 2, 4 do
3834 local _item_0 = _list_0[_index_0]
3835 _accum_0[_len_0] = _item_0
3836 _len_0 = _len_0 + 1
3837end
3838sub_list = _accum_0
3242for i = 10, 20 do 3839for i = 10, 20 do
3243 print(i) 3840 print(i)
3244end 3841end
@@ -3249,8 +3846,7 @@ for key, value in pairs(object) do
3249 print(key, value) 3846 print(key, value)
3250end 3847end
3251local _list_0 = items 3848local _list_0 = items
3252local _max_0 = 4 3849for _index_0 = 2, 4 do
3253for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do
3254 local item = _list_0[_index_0] 3850 local item = _list_0[_index_0]
3255 print(item) 3851 print(item)
3256end 3852end
@@ -3434,7 +4030,7 @@ if "Robert" == name then
3434elseif "Dan" == name or "Daniel" == name then 4030elseif "Dan" == name or "Daniel" == name then
3435 print("Your name, it's Dan") 4031 print("Your name, it's Dan")
3436else 4032else
3437 print("I don't know about your name") 4033 print("I don't know about you with name " .. tostring(name))
3438end 4034end
3439local b = 1 4035local b = 1
3440local next_number 4036local next_number
@@ -3691,6 +4287,35 @@ if _tab_0 then
3691 print("matched", fourth) 4287 print("matched", fourth)
3692 end 4288 end
3693end 4289end
4290local segments = {
4291 "admin",
4292 "users",
4293 "logs",
4294 "view"
4295}
4296local _type_0 = type(segments)
4297local _tab_0 = "table" == _type_0 or "userdata" == _type_0
4298if _tab_0 then
4299 local groups
4300 do
4301 local _accum_0 = { }
4302 local _len_0 = 1
4303 local _max_0 = #segments + -3 + 1
4304 for _index_0 = 1, _max_0 do
4305 local _item_0 = segments[_index_0]
4306 _accum_0[_len_0] = _item_0
4307 _len_0 = _len_0 + 1
4308 end
4309 groups = _accum_0
4310 end
4311 local resource = segments[#segments - 1]
4312 local action = segments[#segments]
4313 if resource ~= nil and action ~= nil then
4314 print("Group:", groups)
4315 print("Resource:", resource)
4316 print("Action:", action)
4317 end
4318end
3694local Inventory 4319local Inventory
3695local _class_0 4320local _class_0
3696local _base_0 = { 4321local _base_0 = {
@@ -4347,6 +4972,10 @@ do
4347 _with_1["key-name"] = value 4972 _with_1["key-name"] = value
4348end 4973end
4349_with_0[#_with_0 + 1] = "abc" 4974_with_0[#_with_0 + 1] = "abc"
4975local _with_0 = obj
4976if _with_0 ~= nil then
4977 print(obj.name)
4978end
4350do 4979do
4351 local var = "hello" 4980 local var = "hello"
4352 print(var) 4981 print(var)
diff --git a/spec/outputs/codes_from_doc_zh.lua b/spec/outputs/codes_from_doc_zh.lua
index 52204b7..6a6c38c 100644
--- a/spec/outputs/codes_from_doc_zh.lua
+++ b/spec/outputs/codes_from_doc_zh.lua
@@ -73,8 +73,8 @@ local apple = setmetatable({
73if (getmetatable(apple) ~= nil) then 73if (getmetatable(apple) ~= nil) then
74 p(apple.size, apple.color, getmetatable(apple).__index) 74 p(apple.size, apple.color, getmetatable(apple).__index)
75end 75end
76local _ud83c_udf1b = "月之脚本" 76local _u1f31b = "月之脚本"
77_module_0["🌛"] = _ud83c_udf1b 77_module_0["🌛"] = _u1f31b
78return _module_0 78return _module_0
79local area = 6.2831853071796 * 5 79local area = 6.2831853071796 * 5
80print('你好 世界') 80print('你好 世界')
@@ -109,6 +109,12 @@ end
109print("yuescript") 109print("yuescript")
110print(3) 110print(3)
111print("有效的枚举类型:", "Static") 111print("有效的枚举类型:", "Static")
112do
113 print(123, "hello")
114end
115do
116 print(123, "hello")
117end
112if tb ~= nil then 118if tb ~= nil then
113 tb:func() 119 tb:func()
114end 120end
@@ -141,6 +147,21 @@ print((function()
141end)()) 147end)())
142local tab = { } 148local tab = { }
143tab[#tab + 1] = "Value" 149tab[#tab + 1] = "Value"
150local tbA = {
151 1,
152 2,
153 3
154}
155local tbB = {
156 4,
157 5,
158 6
159}
160local _len_0 = #tbA + 1
161for _index_0 = 1, #tbB do
162 local _elm_0 = tbB[_index_0]
163 tbA[_len_0], _len_0 = _elm_0, _len_0 + 1
164end
144local parts = { 165local parts = {
145 "shoulders", 166 "shoulders",
146 "knees" 167 "knees"
@@ -209,6 +230,18 @@ for _key_0, _value_0 in pairs(b) do
209 end 230 end
210end 231end
211merge = _tab_0 232merge = _tab_0
233local last
234do
235 local _item_0 = data.items
236 last = _item_0[#_item_0]
237end
238local second_last
239do
240 local _item_0 = data.items
241 second_last = _item_0[#_item_0 - 1]
242end
243local _obj_0 = data.items
244_obj_0[#_obj_0] = 1
212local mt = { } 245local mt = { }
213local add 246local add
214add = function(self, right) 247add = function(self, right)
@@ -339,6 +372,14 @@ func({
339 2, 372 2,
340 3 373 3
341}) 374})
375local f
376f = function()
377 return {
378 1,
379 2,
380 3
381 }
382end
342local tb = { 383local tb = {
343 name = "abc", 384 name = "abc",
344 values = { 385 values = {
@@ -579,6 +620,59 @@ end
579local two, four 620local two, four
580local _obj_0 = items 621local _obj_0 = items
581two, four = _obj_0[2], _obj_0[4] 622two, four = _obj_0[2], _obj_0[4]
623local orders = {
624 "first",
625 "second",
626 "third",
627 "fourth",
628 "last"
629}
630local first, bulk, last = orders[1], (function()
631 local _accum_0 = { }
632 local _len_0 = 1
633 local _max_0 = #orders + -2 + 1
634 for _index_0 = 2, _max_0 do
635 local _item_0 = orders[_index_0]
636 _accum_0[_len_0] = _item_0
637 _len_0 = _len_0 + 1
638 end
639 return _accum_0
640end)(), orders[#orders]
641print(first)
642print(bulk)
643print(last)
644local first, rest
645do
646 local _obj_0 = orders
647 first, rest = _obj_0[1], (function()
648 local _accum_0 = { }
649 local _len_0 = 1
650 local _max_0 = #_obj_0
651 for _index_0 = 2, _max_0 do
652 local _item_0 = _obj_0[_index_0]
653 _accum_0[_len_0] = _item_0
654 _len_0 = _len_0 + 1
655 end
656 return _accum_0
657 end)()
658end
659local start, last
660do
661 local _obj_0 = orders
662 start, last = (function()
663 local _accum_0 = { }
664 local _len_0 = 1
665 local _max_0 = #_obj_0 + -2 + 1
666 for _index_0 = 1, _max_0 do
667 local _item_0 = _obj_0[_index_0]
668 _accum_0[_len_0] = _item_0
669 _len_0 = _len_0 + 1
670 end
671 return _accum_0
672 end)(), _obj_0[#_obj_0]
673end
674local _obj_0 = orders
675first, last = _obj_0[1], _obj_0[#_obj_0]
582local tuples = { 676local tuples = {
583 { 677 {
584 "hello", 678 "hello",
@@ -643,6 +737,36 @@ end
643 local first = select(1, ...) 737 local first = select(1, ...)
644 return print(ok, count, first) 738 return print(ok, count, first)
645end)(fn(true)) 739end)(fn(true))
740local f
741f = function(...)
742 local t = {
743 n = select("#", ...),
744 ...
745 }
746 print("傿•°ä¸ªæ•°:", t.n)
747 print("表长度:", #t)
748 for i = 1, t.n do
749 print(t[i])
750 end
751end
752f(1, 2, 3)
753f("a", "b", "c", "d")
754f()
755local process
756process = function(...)
757 local args = {
758 n = select("#", ...),
759 ...
760 }
761 local sum = 0
762 for i = 1, args.n do
763 if args[i] ~= nil and type(args[i]) == "number" then
764 sum = sum + args[i]
765 end
766 end
767 return sum
768end
769process(1, nil, 3, nil, 5)
646Rx.Observable.fromRange(1, 8):filter(function(x) 770Rx.Observable.fromRange(1, 8):filter(function(x)
647 return x % 2 == 0 771 return x % 2 == 0
648end):concat(Rx.Observable.of('who do we appreciate')):map(function(value) 772end):concat(Rx.Observable.of('who do we appreciate')):map(function(value)
@@ -680,6 +804,56 @@ end)
680if success then 804if success then
681 print(result) 805 print(result)
682end 806end
807local a, b, c
808do
809 local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function()
810 return func()
811 end)
812 if _ok_0 then
813 a, b, c = _ret_0, _ret_1, _ret_2
814 end
815end
816do
817 local _exp_0 = ((function()
818 return (function(_arg_0, ...)
819 local _ok_0 = _arg_0
820 if _ok_0 then
821 return ...
822 end
823 end)(pcall(function()
824 return func()
825 end))
826 end)())
827 if _exp_0 ~= nil then
828 a = _exp_0
829 else
830 a = "default"
831 end
832end
833f((function()
834 return (function(_arg_0, ...)
835 local _ok_0 = _arg_0
836 if _ok_0 then
837 return ...
838 end
839 end)(pcall(function()
840 return func()
841 end))
842end)())
843f((function()
844 return (function(_arg_0, ...)
845 local _ok_0 = _arg_0
846 if _ok_0 then
847 return ...
848 end
849 end)(xpcall(function()
850 print(123)
851 return func()
852 end, function(e)
853 print(e)
854 return e
855 end))
856end)())
683local a <const> = 123 857local a <const> = 123
684local _ <close> = setmetatable({ }, { 858local _ <close> = setmetatable({ }, {
685 __close = function() 859 __close = function()
@@ -695,6 +869,13 @@ print("我有" .. tostring(math.random() * 100) .. "%的把æ¡ã€‚")
695local integer = 1000000 869local integer = 1000000
696local hex = 0xEFBBBF 870local hex = 0xEFBBBF
697local binary = 19 871local binary = 19
872local str = "key: value\nlist:\n - item1\n - " .. tostring(expr)
873local fn
874fn = function()
875 local str = "foo:\n bar: baz"
876 return str
877end
878local str = "path: \"C:\\Program Files\\App\"\nnote: 'He said: \"" .. tostring(Hello) .. "!\"'"
698local my_function 879local my_function
699my_function = function() end 880my_function = function() end
700my_function() 881my_function()
@@ -783,6 +964,36 @@ if func(1, 2, 3, "你好", "世界") then
783 print("hello") 964 print("hello")
784 print("我在if内部") 965 print("我在if内部")
785end 966end
967local f1
968f1 = function(_arg_0)
969 local a, b, c
970 a, b, c = _arg_0.a, _arg_0.b, _arg_0.c
971 return print(a, b, c)
972end
973f1({
974 a = 1,
975 b = "2",
976 c = { }
977})
978local f2
979f2 = function(_arg_0, c)
980 local a1, b
981 a1, b = _arg_0.a, _arg_0.b
982 if a1 == nil then
983 a1 = 123
984 end
985 if b == nil then
986 b = 'abc'
987 end
988 if c == nil then
989 c = { }
990 end
991 return print(a1, b, c)
992end
993local arg1 = {
994 a = 0
995}
996f2(arg1, arg2)
786f(function() 997f(function()
787 return print("hello") 998 return print("hello")
788end) 999end)
@@ -908,6 +1119,28 @@ for _index_0 = 1, #_list_0 do
908 _len_0 = _len_0 + 1 1119 _len_0 = _len_0 + 1
909end 1120end
910doubled = _accum_0 1121doubled = _accum_0
1122local data = {
1123 a = {
1124 1,
1125 2,
1126 3
1127 },
1128 b = {
1129 4,
1130 5,
1131 6
1132 }
1133}
1134local flat
1135local _accum_0 = { }
1136for k, v in pairs(data) do
1137 local _len_0 = #_accum_0 + 1
1138 for _index_0 = 1, #v do
1139 local _elm_0 = v[_index_0]
1140 _accum_0[_len_0], _len_0 = _elm_0, _len_0 + 1
1141 end
1142end
1143flat = _accum_0
911local x_coords = { 1144local x_coords = {
912 4, 1145 4,
913 5, 1146 5,
@@ -998,8 +1231,18 @@ local slice
998local _accum_0 = { } 1231local _accum_0 = { }
999local _len_0 = 1 1232local _len_0 = 1
1000local _list_0 = items 1233local _list_0 = items
1001local _max_0 = 5 1234for _index_0 = 1, 5 do
1002for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do 1235 local item = _list_0[_index_0]
1236 _accum_0[_len_0] = item
1237 _len_0 = _len_0 + 1
1238end
1239slice = _accum_0
1240local slice
1241local _accum_0 = { }
1242local _len_0 = 1
1243local _list_0 = items
1244local _max_0 = #_list_0
1245for _index_0 = 2, _max_0 do
1003 local item = _list_0[_index_0] 1246 local item = _list_0[_index_0]
1004 _accum_0[_len_0] = item 1247 _accum_0[_len_0] = item
1005 _len_0 = _len_0 + 1 1248 _len_0 = _len_0 + 1
@@ -1009,7 +1252,8 @@ local slice
1009local _accum_0 = { } 1252local _accum_0 = { }
1010local _len_0 = 1 1253local _len_0 = 1
1011local _list_0 = items 1254local _list_0 = items
1012for _index_0 = 2, #_list_0 do 1255local _max_0 = #_list_0
1256for _index_0 = 1, _max_0, 2 do
1013 local item = _list_0[_index_0] 1257 local item = _list_0[_index_0]
1014 _accum_0[_len_0] = item 1258 _accum_0[_len_0] = item
1015 _len_0 = _len_0 + 1 1259 _len_0 = _len_0 + 1
@@ -1019,12 +1263,35 @@ local slice
1019local _accum_0 = { } 1263local _accum_0 = { }
1020local _len_0 = 1 1264local _len_0 = 1
1021local _list_0 = items 1265local _list_0 = items
1022for _index_0 = 1, #_list_0, 2 do 1266local _min_0 = #_list_0 + -4 + 1
1267local _max_0 = #_list_0 + -1 + 1
1268for _index_0 = _min_0, _max_0 do
1023 local item = _list_0[_index_0] 1269 local item = _list_0[_index_0]
1024 _accum_0[_len_0] = item 1270 _accum_0[_len_0] = item
1025 _len_0 = _len_0 + 1 1271 _len_0 = _len_0 + 1
1026end 1272end
1027slice = _accum_0 1273slice = _accum_0
1274local reverse_slice
1275local _accum_0 = { }
1276local _len_0 = 1
1277local _list_0 = items
1278local _min_0 = #_list_0 + -1 + 1
1279for _index_0 = _min_0, 1, -1 do
1280 local item = _list_0[_index_0]
1281 _accum_0[_len_0] = item
1282 _len_0 = _len_0 + 1
1283end
1284reverse_slice = _accum_0
1285local sub_list
1286local _accum_0 = { }
1287local _len_0 = 1
1288local _list_0 = items
1289for _index_0 = 2, 4 do
1290 local _item_0 = _list_0[_index_0]
1291 _accum_0[_len_0] = _item_0
1292 _len_0 = _len_0 + 1
1293end
1294sub_list = _accum_0
1028for i = 10, 20 do 1295for i = 10, 20 do
1029 print(i) 1296 print(i)
1030end 1297end
@@ -1035,8 +1302,7 @@ for key, value in pairs(object) do
1035 print(key, value) 1302 print(key, value)
1036end 1303end
1037local _list_0 = items 1304local _list_0 = items
1038local _max_0 = 4 1305for _index_0 = 2, 4 do
1039for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do
1040 local item = _list_0[_index_0] 1306 local item = _list_0[_index_0]
1041 print(item) 1307 print(item)
1042end 1308end
@@ -1220,7 +1486,7 @@ if "Robert" == name then
1220elseif "Dan" == name or "Daniel" == name then 1486elseif "Dan" == name or "Daniel" == name then
1221 print("ä½ çš„å字是Dan") 1487 print("ä½ çš„å字是Dan")
1222else 1488else
1223 print("我ä¸çŸ¥é“ä½ çš„åå­—") 1489 print("我ä¸è®¤è¯†ä½ ï¼Œä½ çš„å字是" .. tostring(name))
1224end 1490end
1225local b = 1 1491local b = 1
1226local next_number 1492local next_number
@@ -1477,6 +1743,35 @@ if _tab_0 then
1477 print("åŒ¹é…æˆåŠŸ", fourth) 1743 print("åŒ¹é…æˆåŠŸ", fourth)
1478 end 1744 end
1479end 1745end
1746local segments = {
1747 "admin",
1748 "users",
1749 "logs",
1750 "view"
1751}
1752local _type_0 = type(segments)
1753local _tab_0 = "table" == _type_0 or "userdata" == _type_0
1754if _tab_0 then
1755 local groups
1756 do
1757 local _accum_0 = { }
1758 local _len_0 = 1
1759 local _max_0 = #segments + -3 + 1
1760 for _index_0 = 1, _max_0 do
1761 local _item_0 = segments[_index_0]
1762 _accum_0[_len_0] = _item_0
1763 _len_0 = _len_0 + 1
1764 end
1765 groups = _accum_0
1766 end
1767 local resource = segments[#segments - 1]
1768 local action = segments[#segments]
1769 if resource ~= nil and action ~= nil then
1770 print("Group:", groups)
1771 print("Resource:", resource)
1772 print("Action:", action)
1773 end
1774end
1480local Inventory 1775local Inventory
1481local _class_0 1776local _class_0
1482local _base_0 = { 1777local _base_0 = {
@@ -2133,6 +2428,10 @@ do
2133 _with_1["key-name"] = value 2428 _with_1["key-name"] = value
2134end 2429end
2135_with_0[#_with_0 + 1] = "abc" 2430_with_0[#_with_0 + 1] = "abc"
2431local _with_0 = obj
2432if _with_0 ~= nil then
2433 print(obj.name)
2434end
2136do 2435do
2137 local var = "hello" 2436 local var = "hello"
2138 print(var) 2437 print(var)
@@ -2276,8 +2575,8 @@ local apple = setmetatable({
2276if (getmetatable(apple) ~= nil) then 2575if (getmetatable(apple) ~= nil) then
2277 p(apple.size, apple.color, getmetatable(apple).__index) 2576 p(apple.size, apple.color, getmetatable(apple).__index)
2278end 2577end
2279local _ud83c_udf1b = "月之脚本" 2578local _u1f31b = "月之脚本"
2280_module_0["🌛"] = _ud83c_udf1b 2579_module_0["🌛"] = _u1f31b
2281return _module_0 2580return _module_0
2282local area = 6.2831853071796 * 5 2581local area = 6.2831853071796 * 5
2283print('你好 世界') 2582print('你好 世界')
@@ -2312,6 +2611,12 @@ end
2312print("yuescript") 2611print("yuescript")
2313print(3) 2612print(3)
2314print("有效的枚举类型:", "Static") 2613print("有效的枚举类型:", "Static")
2614do
2615 print(123, "hello")
2616end
2617do
2618 print(123, "hello")
2619end
2315if tb ~= nil then 2620if tb ~= nil then
2316 tb:func() 2621 tb:func()
2317end 2622end
@@ -2344,6 +2649,21 @@ print((function()
2344end)()) 2649end)())
2345local tab = { } 2650local tab = { }
2346tab[#tab + 1] = "Value" 2651tab[#tab + 1] = "Value"
2652local tbA = {
2653 1,
2654 2,
2655 3
2656}
2657local tbB = {
2658 4,
2659 5,
2660 6
2661}
2662local _len_0 = #tbA + 1
2663for _index_0 = 1, #tbB do
2664 local _elm_0 = tbB[_index_0]
2665 tbA[_len_0], _len_0 = _elm_0, _len_0 + 1
2666end
2347local parts = { 2667local parts = {
2348 "shoulders", 2668 "shoulders",
2349 "knees" 2669 "knees"
@@ -2412,6 +2732,18 @@ for _key_0, _value_0 in pairs(b) do
2412 end 2732 end
2413end 2733end
2414merge = _tab_0 2734merge = _tab_0
2735local last
2736do
2737 local _item_0 = data.items
2738 last = _item_0[#_item_0]
2739end
2740local second_last
2741do
2742 local _item_0 = data.items
2743 second_last = _item_0[#_item_0 - 1]
2744end
2745local _obj_0 = data.items
2746_obj_0[#_obj_0] = 1
2415local mt = { } 2747local mt = { }
2416local add 2748local add
2417add = function(self, right) 2749add = function(self, right)
@@ -2542,6 +2874,14 @@ func({
2542 2, 2874 2,
2543 3 2875 3
2544}) 2876})
2877local f
2878f = function()
2879 return {
2880 1,
2881 2,
2882 3
2883 }
2884end
2545local tb = { 2885local tb = {
2546 name = "abc", 2886 name = "abc",
2547 values = { 2887 values = {
@@ -2782,6 +3122,59 @@ end
2782local two, four 3122local two, four
2783local _obj_0 = items 3123local _obj_0 = items
2784two, four = _obj_0[2], _obj_0[4] 3124two, four = _obj_0[2], _obj_0[4]
3125local orders = {
3126 "first",
3127 "second",
3128 "third",
3129 "fourth",
3130 "last"
3131}
3132local first, bulk, last = orders[1], (function()
3133 local _accum_0 = { }
3134 local _len_0 = 1
3135 local _max_0 = #orders + -2 + 1
3136 for _index_0 = 2, _max_0 do
3137 local _item_0 = orders[_index_0]
3138 _accum_0[_len_0] = _item_0
3139 _len_0 = _len_0 + 1
3140 end
3141 return _accum_0
3142end)(), orders[#orders]
3143print(first)
3144print(bulk)
3145print(last)
3146local first, rest
3147do
3148 local _obj_0 = orders
3149 first, rest = _obj_0[1], (function()
3150 local _accum_0 = { }
3151 local _len_0 = 1
3152 local _max_0 = #_obj_0
3153 for _index_0 = 2, _max_0 do
3154 local _item_0 = _obj_0[_index_0]
3155 _accum_0[_len_0] = _item_0
3156 _len_0 = _len_0 + 1
3157 end
3158 return _accum_0
3159 end)()
3160end
3161local start, last
3162do
3163 local _obj_0 = orders
3164 start, last = (function()
3165 local _accum_0 = { }
3166 local _len_0 = 1
3167 local _max_0 = #_obj_0 + -2 + 1
3168 for _index_0 = 1, _max_0 do
3169 local _item_0 = _obj_0[_index_0]
3170 _accum_0[_len_0] = _item_0
3171 _len_0 = _len_0 + 1
3172 end
3173 return _accum_0
3174 end)(), _obj_0[#_obj_0]
3175end
3176local _obj_0 = orders
3177first, last = _obj_0[1], _obj_0[#_obj_0]
2785local tuples = { 3178local tuples = {
2786 { 3179 {
2787 "hello", 3180 "hello",
@@ -2846,6 +3239,36 @@ end
2846 local first = select(1, ...) 3239 local first = select(1, ...)
2847 return print(ok, count, first) 3240 return print(ok, count, first)
2848end)(fn(true)) 3241end)(fn(true))
3242local f
3243f = function(...)
3244 local t = {
3245 n = select("#", ...),
3246 ...
3247 }
3248 print("傿•°ä¸ªæ•°:", t.n)
3249 print("表长度:", #t)
3250 for i = 1, t.n do
3251 print(t[i])
3252 end
3253end
3254f(1, 2, 3)
3255f("a", "b", "c", "d")
3256f()
3257local process
3258process = function(...)
3259 local args = {
3260 n = select("#", ...),
3261 ...
3262 }
3263 local sum = 0
3264 for i = 1, args.n do
3265 if args[i] ~= nil and type(args[i]) == "number" then
3266 sum = sum + args[i]
3267 end
3268 end
3269 return sum
3270end
3271process(1, nil, 3, nil, 5)
2849Rx.Observable.fromRange(1, 8):filter(function(x) 3272Rx.Observable.fromRange(1, 8):filter(function(x)
2850 return x % 2 == 0 3273 return x % 2 == 0
2851end):concat(Rx.Observable.of('who do we appreciate')):map(function(value) 3274end):concat(Rx.Observable.of('who do we appreciate')):map(function(value)
@@ -2883,6 +3306,56 @@ end)
2883if success then 3306if success then
2884 print(result) 3307 print(result)
2885end 3308end
3309local a, b, c
3310do
3311 local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function()
3312 return func()
3313 end)
3314 if _ok_0 then
3315 a, b, c = _ret_0, _ret_1, _ret_2
3316 end
3317end
3318do
3319 local _exp_0 = ((function()
3320 return (function(_arg_0, ...)
3321 local _ok_0 = _arg_0
3322 if _ok_0 then
3323 return ...
3324 end
3325 end)(pcall(function()
3326 return func()
3327 end))
3328 end)())
3329 if _exp_0 ~= nil then
3330 a = _exp_0
3331 else
3332 a = "default"
3333 end
3334end
3335f((function()
3336 return (function(_arg_0, ...)
3337 local _ok_0 = _arg_0
3338 if _ok_0 then
3339 return ...
3340 end
3341 end)(pcall(function()
3342 return func()
3343 end))
3344end)())
3345f((function()
3346 return (function(_arg_0, ...)
3347 local _ok_0 = _arg_0
3348 if _ok_0 then
3349 return ...
3350 end
3351 end)(xpcall(function()
3352 print(123)
3353 return func()
3354 end, function(e)
3355 print(e)
3356 return e
3357 end))
3358end)())
2886local a <const> = 123 3359local a <const> = 123
2887local _ <close> = setmetatable({ }, { 3360local _ <close> = setmetatable({ }, {
2888 __close = function() 3361 __close = function()
@@ -2897,6 +3370,14 @@ local some_string = "这是一个字符串\n 并包括一个æ¢è¡Œã€‚"
2897print("我有" .. tostring(math.random() * 100) .. "%的把æ¡ã€‚") 3370print("我有" .. tostring(math.random() * 100) .. "%的把æ¡ã€‚")
2898local integer = 1000000 3371local integer = 1000000
2899local hex = 0xEFBBBF 3372local hex = 0xEFBBBF
3373local binary = 19
3374local str = "key: value\nlist:\n - item1\n - " .. tostring(expr)
3375local fn
3376fn = function()
3377 local str = "foo:\n bar: baz"
3378 return str
3379end
3380local str = "path: \"C:\\Program Files\\App\"\nnote: 'He said: \"" .. tostring(Hello) .. "!\"'"
2900local my_function 3381local my_function
2901my_function = function() end 3382my_function = function() end
2902my_function() 3383my_function()
@@ -2985,6 +3466,66 @@ if func(1, 2, 3, "你好", "世界") then
2985 print("你好") 3466 print("你好")
2986 print("我在if内部") 3467 print("我在if内部")
2987end 3468end
3469local f1
3470f1 = function(_arg_0)
3471 local a, b, c
3472 a, b, c = _arg_0.a, _arg_0.b, _arg_0.c
3473 return print(a, b, c)
3474end
3475f1({
3476 a = 1,
3477 b = "2",
3478 c = { }
3479})
3480local f2
3481f2 = function(_arg_0, c)
3482 local a1, b
3483 a1, b = _arg_0.a, _arg_0.b
3484 if a1 == nil then
3485 a1 = 123
3486 end
3487 if b == nil then
3488 b = 'abc'
3489 end
3490 if c == nil then
3491 c = { }
3492 end
3493 return print(a1, b, c)
3494end
3495local arg1 = {
3496 a = 0
3497}
3498f2(arg1, arg2)
3499local findFirstEven
3500findFirstEven = function(list)
3501 for _index_0 = 1, #list do
3502 local item = list[_index_0]
3503 if type(item) == "table" then
3504 for _index_1 = 1, #item do
3505 local sub = item[_index_1]
3506 if sub % 2 == 0 then
3507 return sub
3508 end
3509 end
3510 end
3511 end
3512 return nil
3513end
3514local findFirstEven
3515findFirstEven = function(list)
3516 for _index_0 = 1, #list do
3517 local item = list[_index_0]
3518 if type(item) == "table" then
3519 for _index_1 = 1, #item do
3520 local sub = item[_index_1]
3521 if sub % 2 == 0 then
3522 return sub
3523 end
3524 end
3525 end
3526 end
3527 return nil
3528end
2988f(function() 3529f(function()
2989 return print("hello") 3530 return print("hello")
2990end) 3531end)
@@ -3110,6 +3651,28 @@ for _index_0 = 1, #_list_0 do
3110 _len_0 = _len_0 + 1 3651 _len_0 = _len_0 + 1
3111end 3652end
3112doubled = _accum_0 3653doubled = _accum_0
3654local data = {
3655 a = {
3656 1,
3657 2,
3658 3
3659 },
3660 b = {
3661 4,
3662 5,
3663 6
3664 }
3665}
3666local flat
3667local _accum_0 = { }
3668for k, v in pairs(data) do
3669 local _len_0 = #_accum_0 + 1
3670 for _index_0 = 1, #v do
3671 local _elm_0 = v[_index_0]
3672 _accum_0[_len_0], _len_0 = _elm_0, _len_0 + 1
3673 end
3674end
3675flat = _accum_0
3113local x_coords = { 3676local x_coords = {
3114 4, 3677 4,
3115 5, 3678 5,
@@ -3200,8 +3763,7 @@ local slice
3200local _accum_0 = { } 3763local _accum_0 = { }
3201local _len_0 = 1 3764local _len_0 = 1
3202local _list_0 = items 3765local _list_0 = items
3203local _max_0 = 5 3766for _index_0 = 1, 5 do
3204for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do
3205 local item = _list_0[_index_0] 3767 local item = _list_0[_index_0]
3206 _accum_0[_len_0] = item 3768 _accum_0[_len_0] = item
3207 _len_0 = _len_0 + 1 3769 _len_0 = _len_0 + 1
@@ -3211,7 +3773,8 @@ local slice
3211local _accum_0 = { } 3773local _accum_0 = { }
3212local _len_0 = 1 3774local _len_0 = 1
3213local _list_0 = items 3775local _list_0 = items
3214for _index_0 = 2, #_list_0 do 3776local _max_0 = #_list_0
3777for _index_0 = 2, _max_0 do
3215 local item = _list_0[_index_0] 3778 local item = _list_0[_index_0]
3216 _accum_0[_len_0] = item 3779 _accum_0[_len_0] = item
3217 _len_0 = _len_0 + 1 3780 _len_0 = _len_0 + 1
@@ -3221,12 +3784,46 @@ local slice
3221local _accum_0 = { } 3784local _accum_0 = { }
3222local _len_0 = 1 3785local _len_0 = 1
3223local _list_0 = items 3786local _list_0 = items
3224for _index_0 = 1, #_list_0, 2 do 3787local _max_0 = #_list_0
3788for _index_0 = 1, _max_0, 2 do
3225 local item = _list_0[_index_0] 3789 local item = _list_0[_index_0]
3226 _accum_0[_len_0] = item 3790 _accum_0[_len_0] = item
3227 _len_0 = _len_0 + 1 3791 _len_0 = _len_0 + 1
3228end 3792end
3229slice = _accum_0 3793slice = _accum_0
3794local slice
3795local _accum_0 = { }
3796local _len_0 = 1
3797local _list_0 = items
3798local _min_0 = #_list_0 + -4 + 1
3799local _max_0 = #_list_0 + -1 + 1
3800for _index_0 = _min_0, _max_0 do
3801 local item = _list_0[_index_0]
3802 _accum_0[_len_0] = item
3803 _len_0 = _len_0 + 1
3804end
3805slice = _accum_0
3806local reverse_slice
3807local _accum_0 = { }
3808local _len_0 = 1
3809local _list_0 = items
3810local _min_0 = #_list_0 + -1 + 1
3811for _index_0 = _min_0, 1, -1 do
3812 local item = _list_0[_index_0]
3813 _accum_0[_len_0] = item
3814 _len_0 = _len_0 + 1
3815end
3816reverse_slice = _accum_0
3817local sub_list
3818local _accum_0 = { }
3819local _len_0 = 1
3820local _list_0 = items
3821for _index_0 = 2, 4 do
3822 local _item_0 = _list_0[_index_0]
3823 _accum_0[_len_0] = _item_0
3824 _len_0 = _len_0 + 1
3825end
3826sub_list = _accum_0
3230for i = 10, 20 do 3827for i = 10, 20 do
3231 print(i) 3828 print(i)
3232end 3829end
@@ -3237,8 +3834,7 @@ for key, value in pairs(object) do
3237 print(key, value) 3834 print(key, value)
3238end 3835end
3239local _list_0 = items 3836local _list_0 = items
3240local _max_0 = 4 3837for _index_0 = 2, 4 do
3241for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do
3242 local item = _list_0[_index_0] 3838 local item = _list_0[_index_0]
3243 print(item) 3839 print(item)
3244end 3840end
@@ -3422,7 +4018,7 @@ if "Robert" == name then
3422elseif "Dan" == name or "Daniel" == name then 4018elseif "Dan" == name or "Daniel" == name then
3423 print("ä½ çš„å字是Dan") 4019 print("ä½ çš„å字是Dan")
3424else 4020else
3425 print("我ä¸çŸ¥é“ä½ çš„åå­—") 4021 print("我ä¸è®¤è¯†ä½ ï¼Œä½ çš„å字是" .. tostring(name))
3426end 4022end
3427local b = 1 4023local b = 1
3428local next_number 4024local next_number
@@ -3679,6 +4275,35 @@ if _tab_0 then
3679 print("åŒ¹é…æˆåŠŸ", fourth) 4275 print("åŒ¹é…æˆåŠŸ", fourth)
3680 end 4276 end
3681end 4277end
4278local segments = {
4279 "admin",
4280 "users",
4281 "logs",
4282 "view"
4283}
4284local _type_0 = type(segments)
4285local _tab_0 = "table" == _type_0 or "userdata" == _type_0
4286if _tab_0 then
4287 local groups
4288 do
4289 local _accum_0 = { }
4290 local _len_0 = 1
4291 local _max_0 = #segments + -3 + 1
4292 for _index_0 = 1, _max_0 do
4293 local _item_0 = segments[_index_0]
4294 _accum_0[_len_0] = _item_0
4295 _len_0 = _len_0 + 1
4296 end
4297 groups = _accum_0
4298 end
4299 local resource = segments[#segments - 1]
4300 local action = segments[#segments]
4301 if resource ~= nil and action ~= nil then
4302 print("Group:", groups)
4303 print("Resource:", resource)
4304 print("Action:", action)
4305 end
4306end
3682local Inventory 4307local Inventory
3683local _class_0 4308local _class_0
3684local _base_0 = { 4309local _base_0 = {
@@ -4335,6 +4960,10 @@ do
4335 _with_1["key-name"] = value 4960 _with_1["key-name"] = value
4336end 4961end
4337_with_0[#_with_0 + 1] = "abc" 4962_with_0[#_with_0 + 1] = "abc"
4963local _with_0 = obj
4964if _with_0 ~= nil then
4965 print(obj.name)
4966end
4338do 4967do
4339 local var = "hello" 4968 local var = "hello"
4340 print(var) 4969 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..4e19aca 100644
--- a/spec/outputs/destructure.lua
+++ b/spec/outputs/destructure.lua
@@ -621,4 +621,114 @@ 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
714do
715 local _list_0 = items
716 for _index_0 = 1, #_list_0 do
717 local _des_0 = _list_0[_index_0]
718 local a, b = _des_0.a, _des_0.b
719 print(a, b)
720 end
721 local _list_1 = items
722 for _index_0 = 1, #_list_1 do
723 local _des_0 = _list_1[_index_0]
724 local a, b = _des_0.a, _des_0.b
725 print(a, b)
726 end
727 for _des_0 in pairs(data) do
728 local body = _des_0.body
729 if body then
730 print(body)
731 end
732 end
733end
624return nil 734return 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/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..75f04fa 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,570 @@ 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 _call_0
474 do
475 local _item_0 = globalTB
476 _call_0 = _item_0[#_item_0]
477 end
478 return _call_0["end"](_call_0, 123)
479end
480local _anon_func_1 = function(a)
481 local _item_0
482 do
483 local _accum_0 = { }
484 local _len_0 = 1
485 local _list_0 = a.b.c
486 local _max_5 = #_list_0 + -5 + 1
487 for _index_0 = 5, _max_5 do
488 local _item_1 = _list_0[_index_0]
489 _accum_0[_len_0] = _item_1
490 _len_0 = _len_0 + 1
491 end
492 _item_0 = _accum_0
493 end
494 return _item_0[#_item_0 - 2]
495end
496local _anon_func_2 = function(x)
497 if x ~= nil then
498 local _obj_0 = x.y
499 if _obj_0 ~= nil then
500 local _obj_1 = _obj_0(x).z
501 if _obj_1 ~= nil then
502 local _obj_2 = _obj_1[#_obj_1 - 3]
503 if _obj_2 ~= nil then
504 local _accum_0 = { }
505 local _len_0 = 1
506 local _max_5 = #_obj_2 + -3 + 1
507 for _index_0 = 1, _max_5 do
508 local _item_0 = _obj_2[_index_0]
509 _accum_0[_len_0] = _item_0
510 _len_0 = _len_0 + 1
511 end
512 return _accum_0
513 end
514 return nil
515 end
516 return nil
517 end
518 return nil
519 end
520 return nil
521end
522do
523 local f
524 f = function()
525 return print(_anon_func_0(globalTB), _anon_func_1(a), _anon_func_2(x))
526 end
527end
528do
529 local tb = {
530 1,
531 2,
532 3
533 }
534 tb[#tb] = 40
535 tb[#tb - 1] = 20
536end
537do
538 a = "x"
539 b = a
540 c = a
541 local lst = { }
542 lst[#lst] = a
543 lst[#lst - 1] = b
544end
545do
546 local y, z
547 x, y, z = 1, 2, 3
548 local arr = { }
549 local head
550 arr[#arr], head = x, y
551 arr[#arr] = z
552end
553do
554 local triple = {
555 "keep",
556 "skip",
557 "tail"
558 }
559 local head, tailv = triple[1], triple[3]
560 local buf = { }
561 buf[#buf] = head
562 buf[#buf] = tailv
563end
564do
565 local src = {
566 "a",
567 "",
568 "c",
569 nil,
570 "d"
571 }
572 local collected = { }
573 for _index_0 = 1, #src do
574 local item = src[_index_0]
575 if item and #item > 0 then
576 collected[#collected] = item
577 end
578 end
579end
580do
581 local nums = {
582 1,
583 2,
584 3,
585 4,
586 5
587 }
588 local last_two
589 do
590 local _accum_0 = { }
591 local _len_0 = 1
592 for _index_0 = 1, #nums do
593 local v = nums[_index_0]
594 if v > 3 then
595 _accum_0[_len_0] = v
596 _len_0 = _len_0 + 1
597 end
598 end
599 last_two = _accum_0
600 end
601 nums[#nums] = last_two[1]
602 nums[#nums] = last_two[2]
603end
604do
605 local store = { }
606 store[#store] = {
607 meta = {
608 id = 1,
609 ok = true
610 },
611 payload = {
612 10,
613 20
614 }
615 }
616 store[#store] = {
617 meta = {
618 id = 1,
619 ok = false
620 },
621 payload = {
622 10,
623 20,
624 30
625 }
626 }
627end
628local _anon_func_3 = function(tb)
629 local _item_0 = tb.tmp
630 return _item_0[#_item_0]
631end
632do
633 local f
634 f = function()
635 local q = { }
636 do
637 local _accum_0 = { }
638 local _len_0 = 1
639 for n = 1, 4 do
640 _accum_0[_len_0] = n
641 _len_0 = _len_0 + 1
642 end
643 tb.tmp = _accum_0
644 end
645 if #tb.tmp >= 3 then
646 q[#q] = {
647 head = tb.tmp[1],
648 tail = _anon_func_3(tb)
649 }
650 end
651 end
652end
653do
654 local make_pair
655 make_pair = function(a, b)
656 return {
657 a,
658 b
659 }
660 end
661 local pairs = { }
662 local p1 = make_pair(7, 8)
663 pairs[#pairs] = p1
664 local k, v = "key", 42
665 pairs[#pairs] = {
666 k = k,
667 v = v
668 }
669end
670do
671 local cfg = {
672 mode = "safe",
673 tags = { }
674 }
675 if cfg.mode == "safe" then
676 cfg.mode = "fast"
677 local _obj_0 = cfg.tags
678 _obj_0[#_obj_0] = "newbie"
679 end
680end
681do
682 local mat = {
683 {
684 1,
685 2
686 },
687 {
688 3,
689 4
690 },
691 {
692 5,
693 6
694 }
695 }
696 local last_row = mat[#mat]
697 local rows = { }
698 rows[#rows] = last_row[1]
699end
700do
701 local kv = { }
702 kv[#kv] = {
703 k = "a",
704 v = 1
705 }
706 kv[#kv] = {
707 k = "b",
708 v = 2
709 }
710 local pair_last = kv[#kv]
711 local dict = { }
712 dict[pair_last.k] = pair_last.v
713 dict[pair_last.k] = 3
714end
715do
716 local base
717 do
718 local _accum_0 = { }
719 local _len_0 = 1
720 for i = 1, 4 do
721 _accum_0[_len_0] = i
722 _len_0 = _len_0 + 1
723 end
724 base = _accum_0
725 end
726 local pack = { }
727 pack[#pack] = {
728 base[1],
729 base[#base]
730 }
731 pack[#pack] = {
732 first = base[1],
733 last = base[#base]
734 }
735end
736do
737 local opts = {
738 limit = 10
739 }
740 local limit, offset = opts.limit, opts.offset
741 if offset == nil then
742 offset = 0
743 end
744 local pages = { }
745 pages[#pages] = {
746 limit = limit,
747 offset = offset
748 }
749end
750do
751 local chain = {
752 a = {
753 b = {
754 c = 0
755 }
756 },
757 list = {
758 {
759 x = 0
760 },
761 {
762 x = 0
763 }
764 }
765 }
766 chain.a.b.c = 1
767 chain.list[1].x = 10;
768 ((function()
769 local _item_0 = chain.list
770 return _item_0[#_item_0]
771 end)()).x = 20
772 local _obj_0 = chain.list
773 _obj_0[#_obj_0 - 1] = {
774 x = 30
775 }
776end
777do
778 local node = {
779 left = {
780 v = 0
781 },
782 right = {
783 v = 0
784 }
785 }
786 local bag = { }
787 local left, right = node.left, node.right
788 bag[#bag], left.v, right.v = "k", 1, 2
789end
790do
791 local a1, a2, a3 = 100, 200, 300
792 local mix = { }
793 local meta
794 mix[#mix], mix[#mix], meta = a1, a2, {
795 tag = "ok"
796 }
797end
798do
799 local cfg2 = {
800 limit = 5,
801 opts = {
802 flag = false
803 }
804 }
805 local lim, opt2 = cfg2.limit, cfg2.opts
806 local bucket = {
807 xs = { }
808 }
809 local _obj_0 = bucket.xs
810 _obj_0[#_obj_0] = lim
811 bucket.flag = true
812 local _obj_1 = opt2.flags
813 _obj_1[#_obj_1 + 1] = 123
814end
815do
816 local ret2
817 ret2 = function()
818 return 7, 8
819 end
820 local box = { }
821 local x1
822 box[#box], x1 = ret2()
823end
824do
825 local q = {
826 1,
827 2
828 }
829 local lastq = q[#q]
830 q[#q - 1] = lastq * 10
831end
832do
833 local mat2 = [[9,8], [7,6]]
834 local t = {
835 hold = nil
836 }
837 t.hold = mat2[#mat2][1]
838end
839do
840 local f
841 f = function()
842 local _obj_0
843 do
844 local _item_0 = globalTB
845 _obj_0 = _item_0[#_item_0]
846 end
847 _obj_0[#_obj_0] = 1
848 end
849 local f1
850 f1 = function()
851 do
852 local _item_0 = globalTB
853 do
854 local _item_1 = _item_0[#_item_0]
855 return _item_1[#_item_1 - 1]
856 end
857 end
858 end
859end
860do
861 do
862 local _obj_0 = tbA
863 local _len_0 = #_obj_0 + 1
864 local _list_0 = tbB
865 for _index_0 = 1, #_list_0 do
866 local _elm_0 = _list_0[_index_0]
867 _obj_0[_len_0], _len_0 = _elm_0, _len_0 + 1
868 end
869 end
870 a = 1
871 do
872 local _obj_0 = tb
873 local _len_0 = #_obj_0 + 1
874 for _index_0 = 1, #x do
875 local _elm_0 = x[_index_0]
876 _obj_0[_len_0], _len_0 = _elm_0, _len_0 + 1
877 end
878 end
879 b[#b + 1] = 3
880 c = 4
881 local data = {
882 a = {
883 1,
884 2,
885 3
886 },
887 b = {
888 4,
889 5,
890 6
891 }
892 }
893 local flat
894 local _accum_0 = { }
895 for k, v in pairs(data) do
896 local _len_0 = #_accum_0 + 1
897 for _index_0 = 1, #v do
898 local _elm_0 = v[_index_0]
899 _accum_0[_len_0], _len_0 = _elm_0, _len_0 + 1
900 end
901 end
902 flat = _accum_0
903end
330return nil 904return nil
diff --git a/spec/outputs/loops.lua b/spec/outputs/loops.lua
index 9a47579..6ab4bbb 100644
--- a/spec/outputs/loops.lua
+++ b/spec/outputs/loops.lua
@@ -468,3 +468,31 @@ do
468 end 468 end
469 list = _accum_0 469 list = _accum_0
470end 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 9f5507c..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
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..bdfd676 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\t- \"one\"\n\t- \"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 0f8bba2..7c1004b 100644
--- a/spec/outputs/switch.lua
+++ b/spec/outputs/switch.lua
@@ -656,4 +656,125 @@ do
656 end 656 end
657 end 657 end
658end 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
659return nil 780return nil
diff --git a/spec/outputs/syntax.lua b/spec/outputs/syntax.lua
index 040a325..2df3473 100644
--- a/spec/outputs/syntax.lua
+++ b/spec/outputs/syntax.lua
@@ -430,4 +430,15 @@ do
430 local f2 430 local f2
431 f2 = function() end 431 f2 = function() end
432end 432end
433do
434 if res ~= "" then
435 return res
436 end
437end
438do
439 return res((function()
440 if res ~= "" then
441 end
442 end)())
443end
433return nil 444return 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/test/format_spec.lua b/spec/outputs/test/format_spec.lua
index ed0fbee..7aa85cd 100644
--- a/spec/outputs/test/format_spec.lua
+++ b/spec/outputs/test/format_spec.lua
@@ -122,7 +122,7 @@ return describe("format", function()
122 local original_ast = yue.to_ast(code) 122 local original_ast = yue.to_ast(code)
123 assert.is_not_nil(original_ast) 123 assert.is_not_nil(original_ast)
124 rewriteLineCol(original_ast) 124 rewriteLineCol(original_ast)
125 local formated = yue.format(code) 125 local formated = yue.format(code, 0, false)
126 local ast = yue.to_ast(formated) 126 local ast = yue.to_ast(formated)
127 assert.is_not_nil(ast) 127 assert.is_not_nil(ast)
128 rewriteLineCol(ast) 128 rewriteLineCol(ast)
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/funcs.lua b/spec/outputs/unicode/funcs.lua
index 6e94587..06b24b1 100644
--- a/spec/outputs/unicode/funcs.lua
+++ b/spec/outputs/unicode/funcs.lua
@@ -24,7 +24,7 @@ _u5f00(function()
24end) 24end)
25local _u53d8_u91cfh 25local _u53d8_u91cfh
26_u53d8_u91cfh = function() 26_u53d8_u91cfh = function()
27 return _ud83d_udc4b 27 return _u1f44b
28end 28end
29_u5403(function() end, _u4e16_u754c); 29_u5403(function() end, _u4e16_u754c);
30(function() end)() 30(function() end)()
diff --git a/spec/outputs/unicode/import.lua b/spec/outputs/unicode/import.lua
index 7c31ceb..e055c81 100644
--- a/spec/outputs/unicode/import.lua
+++ b/spec/outputs/unicode/import.lua
@@ -11,10 +11,10 @@ local _u5b57_u6bb5x, _u5b57_u6bb5y, _u5b57_u6bb5z = _u9053_u5177_u7ec4["字段x"
11 return _fn_0(_base_0, ...) 11 return _fn_0(_base_0, ...)
12 end 12 end
13end)(), _u9053_u5177_u7ec4["字段z"] 13end)(), _u9053_u5177_u7ec4["字段z"]
14local _u9886_u4e3b, _ud83d_udc7b 14local _u9886_u4e3b, _u1f47b
15do 15do
16 local _obj_1 = _u627e_u5230("我的表") 16 local _obj_1 = _u627e_u5230("我的表")
17 _u9886_u4e3b, _ud83d_udc7b = _obj_1["领主"], (function() 17 _u9886_u4e3b, _u1f47b = _obj_1["领主"], (function()
18 local _base_0 = _obj_1 18 local _base_0 = _obj_1
19 local _fn_0 = _base_0["👻"] 19 local _fn_0 = _base_0["👻"]
20 return _fn_0 and function(...) 20 return _fn_0 and function(...)
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/macro.lua b/spec/outputs/unicode/macro.lua
index 3b9327a..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()
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..9f97681 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(...)
@@ -306,3 +294,75 @@ join = function(...)
306 end 294 end
307 return nil 295 return nil
308end 296end
297do
298 local f1
299 f1 = function(...)
300 local t = {
301 n = select("#", ...),
302 ...
303 }
304 print(t.n)
305 print(#t)
306 for i = 1, t.n do
307 print(t[i])
308 end
309 end
310 f1(1, 2, 3)
311 f1("a", "b", "c", "d")
312 f1()
313 local f2
314 f2 = function(...)
315 local args = {
316 n = select("#", ...),
317 ...
318 }
319 print("args count:", args.n)
320 print("args length:", #args)
321 for i = 1, args.n do
322 if args[i] == nil then
323 print("position", i, "is nil")
324 else
325 print("position", i, ":", args[i])
326 end
327 end
328 end
329 f2(1, nil, 3, nil, 5)
330 local f3
331 f3 = function(prefix, ...)
332 local items = {
333 n = select("#", ...),
334 ...
335 }
336 local result = { }
337 for i = 1, items.n do
338 result[i] = prefix .. tostring(items[i])
339 end
340 return result
341 end
342 f3("item_", 1, 2, 3)
343 local f4
344 f4 = function(...)
345 local empty = {
346 n = select("#", ...),
347 ...
348 }
349 print("empty count:", empty.n)
350 return print("empty length:", #empty)
351 end
352 f4()
353 local process
354 process = function(...)
355 local data = {
356 n = select("#", ...),
357 ...
358 }
359 local sum = 0
360 for i = 1, data.n do
361 if type(data[i]) == "number" then
362 sum = sum + data[i]
363 end
364 end
365 return sum
366 end
367 return process(1, 2, 3, "skip", 5)
368end
diff --git a/spec/outputs/with.lua b/spec/outputs/with.lua
index 20c5d44..530915e 100644
--- a/spec/outputs/with.lua
+++ b/spec/outputs/with.lua
@@ -192,26 +192,61 @@ do
192 local _with_0 = item 192 local _with_0 = item
193 do 193 do
194 local _accum_0 194 local _accum_0
195 while true do 195 repeat
196 if _with_0.id > 0 then 196 if _with_0.id > 0 then
197 _accum_0 = _with_0.content 197 _accum_0 = _with_0.content
198 break 198 break
199 end 199 end
200 end 200 until true
201 _with_0 = _accum_0 201 _with_0 = _accum_0
202 end 202 end
203 return _with_0 203 return _with_0
204 end)()) 204 end)())
205 local a 205 local a
206 local _with_0 = tb 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
207 local _accum_0 220 local _accum_0
208 while true do 221 while true do
209 if _with_0.v then 222 local _with_0 = tb
210 _accum_0 = _with_0.a 223 local _accum_1
211 break 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
212 end 248 end
213 end 249 end
214 _with_0 = _accum_0 250 a = _accum_0
215 a = _with_0
216end 251end
217return nil 252return nil
diff --git a/src/3rdParty/colib/LICENSE b/src/3rdParty/colib/LICENSE
new file mode 100755
index 0000000..e0eddeb
--- /dev/null
+++ b/src/3rdParty/colib/LICENSE
@@ -0,0 +1,21 @@
1MIT License
2
3Copyright (c) 2020 colin
4
5Permission is hereby granted, free of charge, to any person obtaining a copy
6of this software and associated documentation files (the "Software"), to deal
7in the Software without restriction, including without limitation the rights
8to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9copies of the Software, and to permit persons to whom the Software is
10furnished to do so, subject to the following conditions:
11
12The above copyright notice and this permission notice shall be included in all
13copies or substantial portions of the Software.
14
15THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21SOFTWARE.
diff --git a/src/3rdParty/colib/ljson.c b/src/3rdParty/colib/ljson.c
new file mode 100644
index 0000000..4daba07
--- /dev/null
+++ b/src/3rdParty/colib/ljson.c
@@ -0,0 +1,925 @@
1/**
2 * jsonè§£æžå™¨ï¼šåªæ”¯æŒutf-8æ ¼å¼ï¼ŒLuaåªæ”¯æŒ64ä½çš„æ•°å­—
3 */
4#define LUA_LIB
5#include <stdlib.h>
6#include <string.h>
7#include <stdint.h>
8#include <stdio.h>
9#include <ctype.h>
10#include <assert.h>
11#include <errno.h>
12#include <setjmp.h>
13#include <ctype.h>
14#include <limits.h>
15#include <float.h>
16#include <math.h>
17#include "lua.h"
18#include "lauxlib.h"
19
20#if LUA_VERSION_NUM > 501
21#ifndef LUA_COMPAT_5_1
22#ifndef lua_objlen
23#define lua_objlen lua_rawlen
24#endif // lua_objlen
25#endif // LUA_COMPAT_5_1
26#endif // LUA_VERSION_NUM
27
28// 内存分é…函数,方便替æ¢
29#define co_malloc malloc
30#define co_free free
31#define co_realloc realloc
32#define co_calloc calloc
33
34
35#if !defined(likely)
36#if defined(__GNUC__)
37#define likely(x) (__builtin_expect(((x) != 0), 1))
38#define unlikely(x) (__builtin_expect(((x) != 0), 0))
39#else
40#define likely(x) (x)
41#define unlikely(x) (x)
42#endif
43
44#endif
45
46//-----------------------------------------------------------------------------
47// membuffer
48
49#define STACK_BUFF_SIZE 512
50
51typedef struct membuffer {
52 char *b; // 内存buffer
53 size_t sz; // buffer已用长度
54 size_t cap; // buffer实际大å°
55 char s[STACK_BUFF_SIZE];
56} membuffer_t;
57
58// åˆå§‹åŒ–buffer
59static inline void membuffer_init(membuffer_t *buff) {
60 buff->b = buff->s;
61 buff->cap = STACK_BUFF_SIZE;
62 buff->sz = 0;
63}
64
65static inline void membuffer_add_size(membuffer_t *buff, size_t sz) {
66 buff->sz += sz;
67}
68
69static inline void membuffer_reset(membuffer_t *buff) {
70 buff->sz = 0;
71}
72
73static inline void membuffer_free(membuffer_t *buff) {
74 if (buff->b && buff->b != buff->s) {
75 co_free(buff->b);
76 buff->b = NULL;
77 }
78}
79
80static inline void _membuffer_grow(membuffer_t *buff, size_t needsz) {
81 if (buff->cap < needsz) {
82 size_t newcap = buff->cap * 2;
83 if (newcap < needsz)
84 newcap = needsz;
85 if (buff->b == buff->s) {
86 buff->b = (char*)co_malloc(newcap);
87 memcpy(buff->b, buff->s, buff->sz);
88 } else {
89 buff->b = (char*)co_realloc(buff->b, newcap);
90 }
91 buff->cap = newcap;
92 }
93}
94
95// ç¡®ä¿ç¼“存中还有szçš„å¯ç”¨ç©ºé—´
96static inline void membuffer_ensure_space(membuffer_t *buff, size_t sz) {
97 if (buff->sz + sz > buff->cap) {
98 _membuffer_grow(buff, buff->sz+sz);
99 }
100}
101
102// 压入一个字符
103static inline void membuffer_putc(membuffer_t *buff, char c) {
104 membuffer_ensure_space(buff, 1);
105 buff->b[buff->sz++] = c;
106}
107
108// 写入一段内存
109static inline void membuffer_putb(membuffer_t *buff, const void *b, size_t sz) {
110 membuffer_ensure_space(buff, sz);
111 memcpy(buff->b + buff->sz, b, sz);
112 buff->sz += sz;
113}
114
115// åŽ‹å…¥ä¸€ä¸ªå­—ç¬¦ï¼šä¸æ£€æŸ¥ç©ºé—´(ä¸å®‰å…¨ç‰ˆæœ¬)
116static inline void membuffer_putc_unsafe(membuffer_t *buff, char c) {
117 buff->b[buff->sz++] = c;
118}
119
120#if LUA_VERSION_NUM > 501
121// å†™å…¥ä¸€æ®µå†…å­˜ï¼šä¸æ£€æŸ¥ç©ºé—´(ä¸å®‰å…¨ç‰ˆæœ¬)
122static inline void membuffer_putb_unsafe(membuffer_t *buff, const void *b, size_t sz) {
123 memcpy(buff->b + buff->sz, b, sz);
124 buff->sz += sz;
125}
126#endif
127
128// å–当å‰çš„æŒ‡é’ˆ
129static inline char* membuffer_getp(membuffer_t *buff) {
130 return buff->b + buff->sz;
131}
132
133//-----------------------------------------------------------------------------
134// parser
135
136//-------------------------------------
137// 与Lua相关的代ç 
138
139static inline void l_add_object(lua_State *L) {
140 luaL_checkstack(L, 6, NULL);
141 lua_createtable(L, 0, 4);
142}
143static inline void l_begin_pair(lua_State *L, const char *k, size_t sz) {
144 lua_pushlstring(L, k, sz);
145}
146static inline void l_end_pair(lua_State *L) {
147 lua_rawset(L, -3);
148}
149static inline void l_add_array(lua_State *L) {
150 luaL_checkstack(L, 6, NULL);
151 lua_createtable(L, 4, 0);
152}
153static inline void l_add_index(lua_State *L, int i) {
154 lua_rawseti(L, -2, i+1);
155}
156static inline void l_add_string(lua_State *L, const char *s, size_t sz) {
157 lua_pushlstring(L, s, sz);
158}
159static inline void l_add_float(lua_State *L, double f) {
160 lua_pushnumber(L, (lua_Number)f);
161}
162static inline void l_add_integer(lua_State *L, int64_t i) {
163 lua_pushinteger(L, (lua_Integer)i);
164}
165static inline void l_add_boolean(lua_State *L, int b) {
166 lua_pushboolean(L, b);
167}
168static inline void l_add_null(lua_State *L) {
169 lua_pushlightuserdata(L, NULL);
170}
171static inline void l_error(lua_State *L, const char *msg) {
172 luaL_error(L, msg);
173}
174
175// è§£æžäº‹ä»¶
176#define ON_ADD_OBJECT(ud) l_add_object((lua_State*)(ud))
177#define ON_BEGIN_PAIR(ud, k, sz) l_begin_pair((lua_State*)(ud), k, sz)
178#define ON_END_PAIR(ud) l_end_pair((lua_State*)(ud))
179#define ON_ADD_ARRAY(ud) l_add_array((lua_State*)(ud))
180#define ON_ADD_INDEX(ud, i) l_add_index((lua_State*)(ud), i)
181#define ON_ADD_STRING(ud, s, sz) l_add_string((lua_State*)(ud), s, sz)
182#define ON_ADD_FLOAT(ud, f) l_add_float((lua_State*)(ud), f)
183#define ON_ADD_INTEGER(ud, i) l_add_integer((lua_State*)(ud), i)
184#define ON_ADD_BOOLEAN(ud, b) l_add_boolean((lua_State*)(ud), b)
185#define ON_ADD_NULL(ud) l_add_null((lua_State*)(ud))
186#define ON_ERROR(ud, msg) l_error((lua_State*)(ud), msg)
187
188//-------------------------------------
189// è§£æžjson,这部分代ç ä¸ŽLua无关,是通用的解æžå™¨ï¼›å¦‚æžœè¦ç§»æ¤è¿™éƒ¨åˆ†ä»£ç ï¼Œéœ€è¦æŠŠ //>>> 开头的注释去掉
190
191// 错误消æ¯çš„大å°
192#define ERRMSG_SIZE 256
193
194// jsonè§£æžå™¨
195typedef struct {
196 const char *str; // json字符串
197 const char *ptr; // jsonå­—ç¬¦ä¸²è§£æžæŒ‡é’ˆ
198 void *ud; // è§£æžäº‹ä»¶çš„用户数æ®
199 membuffer_t buff; // 临时缓存
200 int curdepth; // 当å‰å±‚次
201 int maxdepth; // 最大层次
202 int allowcomment; // 是å¦å…许注释
203 char errmsg[ERRMSG_SIZE]; // ä¿å­˜é”™è¯¯æ¶ˆæ¯
204 //>>>jmp_buf jb; // 用于实现从解æžä¸­å‡ºé”™ç›´æŽ¥è·³å‡º
205} json_parser_t;
206
207static inline void parser_init(json_parser_t *parser, const char *str, size_t size, void *ud,
208 int maxdepth, int allowcomment) {
209 membuffer_init(&parser->buff);
210 membuffer_ensure_space(&parser->buff, size);
211 parser->str = str;
212 parser->ptr = str;
213 parser->ud = ud;
214 parser->maxdepth = maxdepth;
215 parser->curdepth = 0;
216 parser->allowcomment = allowcomment;
217}
218
219static inline void parser_free(json_parser_t *parser) {
220 membuffer_free(&parser->buff);
221}
222
223// 抛出错误
224static void parser_throw_error(json_parser_t *parser, const char *fmt, ...) {
225 membuffer_free(&parser->buff);
226 va_list arg;
227 va_start(arg, fmt);
228 vsnprintf(parser->errmsg, ERRMSG_SIZE, fmt, arg);
229 va_end(arg);
230 ON_ERROR(parser->ud, parser->errmsg);
231 // 直接跳出解æžä»£ç ï¼Œç”±äºŽLuaçš„lua_error也是用longjmp,所以下é¢çš„ä»£ç æ²¡æœ‰æœºä¼šæ‰§è¡Œåˆ°ã€‚但其他语言就ä¸ä¸€å®šã€‚
232 //>>>longjmp(parser->jb, 1);
233}
234
235// 辅助å®
236#define peekchar(p) (*(p)->ptr)
237#define skipchar(p) (++(p)->ptr)
238#define get_and_next(p) (*(p)->ptr++)
239#define next_and_get(p) (*(++(p)->ptr))
240#define savechar(p, c) membuffer_putc_unsafe(&(p)->buff, (c))
241#define currpos(p) (size_t)((p)->ptr - (p)->str)
242
243// å–è§£æžåˆ°çš„错误内容
244static const char* parser_error_content(json_parser_t *p) {
245 size_t n = currpos(p);
246 if (n > 50) n = 50; // 调整这个数获得更长的内容
247 membuffer_reset(&p->buff);
248 membuffer_putb(&p->buff, p->ptr - n, n);
249 membuffer_putc(&p->buff, '\0');
250 return p->buff.b;
251}
252
253// 增加深度
254static inline void parser_add_depth(json_parser_t *p) {
255 p->curdepth++;
256 if (p->curdepth >= p->maxdepth)
257 parser_throw_error(p, "Too many nested data, max depth is %d, at: %s[:%lu]", p->maxdepth,
258 parser_error_content(p), currpos(p));
259}
260
261static inline void parser_skip_whitespaces(json_parser_t *p) {
262 // colin: è¦æ”¯æŒæ³¨é‡Šï¼Œè¯·å°†ä¸‹é¢æ³¨é‡ŠåŽ»æŽ‰
263 // if (likely(!p->allowcomment)) {
264 char ch = peekchar(p);
265 while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')
266 ch = next_and_get(p);
267 // } else {
268 // char ch = peekchar(p);
269 // for (;;) {
270 // while (ch == ' ' || ch == '\t' || ch == '\n' || ch == '\r')
271 // ch = next_and_get(p);
272 // if (ch == '/') {
273 // ch = next_and_get(p);
274 // if (ch == '/') {
275 // ch = next_and_get(p);
276 // while (ch != '\n' && ch != '\r' && ch != '\0')
277 // ch = next_and_get(p);
278 // continue;
279 // } else {
280 // parser_throw_error(p, "Invalid comment, at: %s[:%lu]", parser_error_content(p), currpos(p));
281 // }
282 // }
283 // break;
284 // }
285 // }
286}
287
288static inline void parser_expect_char(json_parser_t *p, char c) {
289 if (likely(peekchar(p) == c))
290 skipchar(p);
291 else
292 parser_throw_error(p, "Expect '%c' at: %s[:%lu]", c, parser_error_content(p), currpos(p));
293}
294
295static inline void parser_process_false(json_parser_t *p) {
296 if (likely(p->ptr[0] == 'a' && p->ptr[1] == 'l' && p->ptr[2] == 's' && p->ptr[3] == 'e')) {
297 p->ptr += 4;
298 ON_ADD_BOOLEAN(p->ud, 0);
299 } else {
300 parser_throw_error(p, "Invalid boolean, at: %s[:%lu]", parser_error_content(p), currpos(p));
301 }
302}
303
304static inline void parser_process_true(json_parser_t *p) {
305 if (likely(p->ptr[0] == 'r' && p->ptr[1] == 'u' && p->ptr[2] == 'e')) {
306 p->ptr += 3;
307 ON_ADD_BOOLEAN(p->ud, 1);
308 } else {
309 parser_throw_error(p, "Invalid boolean, at: %s[:%lu]", parser_error_content(p), currpos(p));
310 }
311}
312
313static inline void parser_process_null(json_parser_t *p) {
314 if (likely(p->ptr[0] == 'u' && p->ptr[1] == 'l' && p->ptr[2] == 'l')) {
315 p->ptr += 3;
316 ON_ADD_NULL(p->ud);
317 } else {
318 parser_throw_error(p, "Invalid null, at: %s[:%lu]", parser_error_content(p), currpos(p));
319 }
320}
321
322static inline uint32_t parser_read_hex(json_parser_t *p) {
323 uint32_t cp = 0;
324 unsigned char ch;
325 int i = 4;
326 while (i--) {
327 ch = (unsigned char)get_and_next(p);
328 if ('0' <= ch && ch <= '9')
329 ch -= '0';
330 else if (ch >= 'a' && ch <= 'f')
331 ch = ch - 'a' + 10;
332 else if (ch >= 'A' && ch <= 'F')
333 ch = ch - 'A' + 10;
334 else {
335 parser_throw_error(p, "Invalid utf8 escape sequence, at: %s[:%lu]", parser_error_content(p), currpos(p));
336 return cp;
337 }
338 cp = (cp << 4) + ch;
339 }
340 return cp;
341}
342
343static inline void parser_process_utf8esc(json_parser_t *p) {
344 uint32_t cp = parser_read_hex(p);
345 // UTF-16 surrogate pairs, see https://unicodebook.readthedocs.io/unicode_encodings.html#utf-16-surrogate-pairs
346 if (cp >= 0xD800 && cp <= 0xDBFF) {
347 char p0 = p->ptr[0];
348 char p1 = p->ptr[1];
349 if (p0 != '\\' || p1 != 'u')
350 parser_throw_error(p, "Invalid utf8 escape sequence, at: %s[:%lu]", parser_error_content(p), currpos(p));
351 p->ptr += 2;
352 uint32_t cp2 = parser_read_hex(p);
353 if (cp2 < 0xDC00 || cp2 > 0xDFFF)
354 parser_throw_error(p, "Invalid utf8 escape sequence, at: %s[:%lu]", parser_error_content(p), currpos(p));
355 cp = 0x10000 + (((cp & 0x03FF) << 10) | (cp2 & 0x03FF));
356 }
357 if (cp < 0x80) {
358 membuffer_putc_unsafe(&p->buff, (char)cp);
359 } else if (cp < 0x800) {
360 membuffer_putc_unsafe(&p->buff, 0xC0 | (cp >> 6));
361 membuffer_putc_unsafe(&p->buff, 0x80 | (cp & 0x3F));
362 } else if (cp < 0x10000) {
363 membuffer_putc_unsafe(&p->buff, 0xE0 | (cp >> 12));
364 membuffer_putc_unsafe(&p->buff, 0x80 | ((cp >> 6) & 0x3F));
365 membuffer_putc_unsafe(&p->buff, 0x80 | (cp & 0x3F));
366 } else {
367 membuffer_putc_unsafe(&p->buff, 0xF0 | (cp >> 18));
368 membuffer_putc_unsafe(&p->buff, 0x80 | ((cp >> 12) & 0x3F));
369 membuffer_putc_unsafe(&p->buff, 0x80 | ((cp >> 6) & 0x3F));
370 membuffer_putc_unsafe(&p->buff, 0x80 | (cp & 0x3F));
371 }
372}
373
374static const char escape2char[256] = {
375 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 0~19
376 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\"',0, 0, 0, 0, 0, // 20~39
377 0, 0, 0, 0, 0, 0, 0, '/', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40~59
378 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60~79
379 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\\',0, 0, 0, 0, 0, '\b',0, // 80~99
380 0, 0, '\f',0, 0, 0, 0, 0, 0, 0, '\n',0, 0, 0, '\r',0, '\t',0, 0, 0, // 100~119
381 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 120~139
382 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 140~159
383 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160~179
384 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 180~199
385 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 200~219
386 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 220~239
387 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 240~256
388};
389
390static inline void parser_process_string(json_parser_t *p) {
391 membuffer_reset(&p->buff);
392 char ch = get_and_next(p);
393 for (;;) {
394 if (ch == '\\') {
395 unsigned char nch = (unsigned char)peekchar(p);
396 if (likely(escape2char[nch])) {
397 savechar(p, escape2char[nch]);
398 skipchar(p);
399 } else if (nch == 'u') {
400 skipchar(p);
401 parser_process_utf8esc(p);
402 } else {
403 parser_throw_error(p, "Invalid escape sequence, at: %s[:%lu]", parser_error_content(p), currpos(p));
404 }
405 } else if (ch == '"') {
406 break;
407 } else if ((unsigned char)ch < 0x20) {
408 parser_throw_error(p, "Invalid string, at: %s[:%lu]", parser_error_content(p), currpos(p));
409 } else {
410 savechar(p, ch);
411 }
412 ch = get_and_next(p);
413 }
414}
415
416#define invalid_number(p) parser_throw_error(p, "Invalid value, at: %s[:%lu]", parser_error_content(p), currpos(p))
417#define MAXBY10 (int64_t)(922337203685477580)
418#define MAXLASTD (int)(7)
419static double powersOf10[] = {10., 100., 1.0e4, 1.0e8, 1.0e16, 1.0e32, 1.0e64, 1.0e128, 1.0e256};
420static inline void parser_process_number(json_parser_t *p, char ch) {
421 double db; // 浮点数
422 int64_t in = 0; // 整型值
423 int isdouble = 0; // æ˜¯å¦æ˜¯æµ®ç‚¹æ•°
424 int neg = 0; // æ˜¯å¦æ˜¯è´Ÿæ•°
425 int exponent = 0; // æŒ‡æ•°ä½æ•°
426
427 if (ch == '-') { // 负值
428 neg = 1;
429 ch = get_and_next(p);
430 }
431 if (unlikely(ch == '0')) { // 0开头的åŽé¢åªèƒ½æ˜¯ï¼š.eE或\0
432 ch = peekchar(p);
433 } else if (likely(ch >= '1' && ch <= '9')) {
434 in = ch - '0';
435 ch = peekchar(p);
436 while (ch >= '0' && ch <= '9') {
437 if (unlikely(in >= MAXBY10 && (in > MAXBY10 || (ch - '0') > MAXLASTD + neg))) { // 更大的数字就用浮点数表示
438 isdouble = 1;
439 db = (double)in;
440 do {
441 db = db * 10.0 + (ch - '0');
442 ch = next_and_get(p);
443 } while (ch >= '0' && ch <= '9');
444 break;
445 }
446 in = in * 10 + (ch - '0');
447 ch = next_and_get(p);
448 }
449 } else {
450 invalid_number(p);
451 }
452
453 if (ch == '.') { // å°æ•°ç‚¹éƒ¨åˆ†
454 if (likely(!isdouble)) {
455 isdouble = 1;
456 db = (double)in;
457 }
458 ch = next_and_get(p);
459 if (unlikely(!(ch >= '0' && ch <= '9')))
460 invalid_number(p); // .åŽé¢ä¸€å®šæ˜¯æ•°å­—
461 do {
462 db = db * 10. + (ch - '0');
463 exponent--;
464 ch = next_and_get(p);
465 } while (ch >= '0' && ch <= '9');
466 }
467
468 if (ch == 'e' || ch == 'E') { // 指数部分
469 if (!isdouble) { // 有e强制认为是浮点数
470 isdouble = 1;
471 db = (double)in;
472 }
473 ch = next_and_get(p);
474 int eneg = 0;
475 if (ch == '-') {
476 eneg = 1;
477 ch = next_and_get(p);
478 } else if (ch == '+') {
479 ch = next_and_get(p);
480 }
481 if (unlikely(!(ch >= '0' && ch <= '9')))
482 invalid_number(p); // åŽé¢ä¸€å®šæ˜¯æ•°å­—
483 int exp = 0;
484 do {
485 exp = exp * 10. + (ch - '0');
486 ch = next_and_get(p);
487 } while (ch >= '0' && ch <= '9');
488 exponent += eneg ? (-exp) : (exp);
489 }
490
491 if (isdouble) {
492 int n = exponent < 0 ? -exponent : exponent;
493 if (unlikely(n>511))
494 n = 511; // inf
495 double p10 = 1.0;
496 double *d;
497 for (d = powersOf10; n != 0; n >>= 1, d += 1) {
498 if (n & 1) p10 *= *d;
499 }
500 if (exponent < 0)
501 db /= p10;
502 else
503 db *= p10;
504 if (neg) db = -db;
505 ON_ADD_FLOAT(p->ud, db);
506 } else {
507 if (neg) in = -in;
508 ON_ADD_INTEGER(p->ud, in);
509 }
510}
511
512static void parser_process_value(json_parser_t *p);
513
514static inline void parser_process_object(json_parser_t *p) {
515 parser_add_depth(p);
516 ON_ADD_OBJECT(p->ud);
517 parser_skip_whitespaces(p);
518 char ch = peekchar(p);
519 if (ch == '}') {
520 skipchar(p);
521 p->curdepth--;
522 return;
523 }
524 for (;;) {
525 parser_expect_char(p, '"');
526 parser_process_string(p); // key
527 ON_BEGIN_PAIR(p->ud, p->buff.b, p->buff.sz);
528
529 parser_skip_whitespaces(p);
530 parser_expect_char(p, ':');
531
532 parser_process_value(p); // value
533 ON_END_PAIR(p->ud);
534
535 parser_skip_whitespaces(p);
536 if (peekchar(p) == '}') {
537 skipchar(p);
538 p->curdepth--;
539 return;
540 }
541 else {
542 parser_expect_char(p, ',');
543 parser_skip_whitespaces(p);
544 }
545 }
546}
547
548static inline void parser_process_array(json_parser_t *p) {
549 parser_add_depth(p);
550 ON_ADD_ARRAY(p->ud);
551 parser_skip_whitespaces(p);
552 char ch = peekchar(p);
553 if (ch == ']') {
554 skipchar(p);
555 p->curdepth--;
556 return;
557 }
558 int i;
559 for (i = 0; ;++i) {
560 parser_process_value(p);
561 ON_ADD_INDEX(p->ud, i);
562
563 parser_skip_whitespaces(p);
564 if (peekchar(p) == ']') {
565 skipchar(p);
566 p->curdepth--;
567 return;
568 }
569 else {
570 parser_expect_char(p, ',');
571 }
572 }
573}
574
575static void parser_process_value(json_parser_t *p) {
576 parser_skip_whitespaces(p);
577 char ch = get_and_next(p);
578 switch (ch) {
579 case 'f':
580 parser_process_false(p);
581 break;
582 case 't':
583 parser_process_true(p);
584 break;
585 case 'n':
586 parser_process_null(p);
587 break;
588 case '"':
589 parser_process_string(p);
590 ON_ADD_STRING(p->ud, p->buff.b, p->buff.sz);
591 break;
592 case '{':
593 parser_process_object(p);
594 break;
595 case '[':
596 parser_process_array(p);
597 break;
598 default:
599 parser_process_number(p, ch);
600 break;
601 }
602}
603
604// è§£æžjson文本
605static void parser_do_parse(const char *str, size_t size, void *ud, int maxdepth, int allowcomment) {
606 json_parser_t p;
607 parser_init(&p, str, size, ud, maxdepth, allowcomment);
608 //>>>if (setjmp(p.jb) == 0) {
609 parser_process_value(&p);
610 parser_skip_whitespaces(&p);
611 if (peekchar(&p) != '\0') {
612 parser_throw_error(&p, "Expect '<eof>' but got '%c', at: %s[:%lu]", peekchar(&p),
613 parser_error_content(&p), currpos(&p));
614 }
615 parser_free(&p);
616 //>>>}
617}
618
619//-----------------------------------------------------------------------------
620// dumpper
621
622typedef struct {
623 membuffer_t buff; // 临时缓存
624 int maxdepth; // 最大层次
625 int format; // æ˜¯å¦æ ¼å¼åŒ–
626 int empty_as_array; // 空表是å¦å½“æˆæ•°ç»„
627 int num_as_str; // 数字Key转为字符串
628 char errmsg[ERRMSG_SIZE]; // ä¿å­˜é”™è¯¯æ¶ˆæ¯
629} json_dumpper_t;
630
631// è¶³å¤Ÿè½¬æ¢æ•°å­—的缓存大å°
632#define NUMBER_BUFF_SZ 44
633#define INTEGER_BUFF_SZ 24
634
635// 抛出错误
636static void dumpper_throw_error(json_dumpper_t *d, lua_State *L, const char *fmt, ...) {
637 membuffer_free(&d->buff);
638 va_list arg;
639 va_start(arg, fmt);
640 vsnprintf(d->errmsg, ERRMSG_SIZE, fmt, arg);
641 va_end(arg);
642 luaL_error(L, d->errmsg);
643}
644
645#if LUA_VERSION_NUM > 501
646static void dumpper_process_integer(json_dumpper_t *d, lua_State *L, int idx) {
647 char nbuff[INTEGER_BUFF_SZ];
648 int i = INTEGER_BUFF_SZ;
649 membuffer_ensure_space(&d->buff, INTEGER_BUFF_SZ);
650 int64_t x = (int64_t)lua_tointeger(L, idx);
651 uint64_t ux = (uint64_t)x;
652 if (x < 0) {
653 membuffer_putc_unsafe(&d->buff, '-');
654 ux = ~ux + 1;
655 }
656 do {
657 nbuff[--i] = (ux % 10) + '0';
658 } while (ux /= 10);
659 membuffer_putb_unsafe(&d->buff, nbuff+i, INTEGER_BUFF_SZ-i);
660}
661#endif
662
663static void dumpper_process_number(json_dumpper_t *d, lua_State *L, int idx) {
664 lua_Number num = lua_tonumber(L, idx);
665 if (isinf(num) || isnan(num))
666 dumpper_throw_error(d, L, "The number is NaN or Infinity");
667 membuffer_ensure_space(&d->buff, NUMBER_BUFF_SZ);
668 char *p = membuffer_getp(&d->buff);
669 int len = sprintf(p, LUA_NUMBER_FMT, num);
670 membuffer_add_size(&d->buff, len);
671}
672
673// 字符转义表
674static const char char2escape[256] = {
675 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'b', 't', 'n', 'u', 'f', 'r', 'u', 'u', 'u', 'u', 'u', 'u', // 0~19
676 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 'u', 0, 0, '"', 0, 0, 0, 0, 0, // 20~39
677 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 40~59
678 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 60~79
679 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\\', 0, 0, 0, 0, 0, 0, 0, // 80~99
680 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 100~119
681 0, 0, 0, 0, 0, 0, 0, 'u', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 120~139
682 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 140~159
683 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 160~179
684 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 180~199
685 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 200~219
686 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 220~239
687 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 240~256
688};
689static const char hex_digits[16] = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
690
691static void dumpper_process_string(json_dumpper_t *d, lua_State *L, int idx) {
692 membuffer_t *buff = &d->buff;
693 size_t len, i;
694 const char *str = lua_tolstring(L, idx, &len);
695 membuffer_ensure_space(buff, len * 6 + 2);
696 membuffer_putc_unsafe(buff, '\"');
697 char esc;
698 unsigned char ch;
699 for (i = 0; i < len; ++i) {
700 ch = (unsigned char)str[i];
701 esc = char2escape[ch];
702 if (likely(!esc))
703 membuffer_putc_unsafe(buff, (char)ch);
704 else {
705 membuffer_putc_unsafe(buff, '\\');
706 membuffer_putc_unsafe(buff, esc);
707 if (esc == 'u') {
708 membuffer_putc_unsafe(buff, '0');
709 membuffer_putc_unsafe(buff, '0');
710 membuffer_putc_unsafe(buff, hex_digits[(unsigned char)esc >> 4]);
711 membuffer_putc_unsafe(buff, hex_digits[(unsigned char)esc & 0xF]);
712 }
713 }
714 }
715 membuffer_putc_unsafe(buff, '\"');
716}
717
718static void dumpper_process_value(json_dumpper_t *d, lua_State *L, int depth);
719
720static int dumpper_check_array(json_dumpper_t *d, lua_State *L, int *len) {
721 int asize = lua_objlen(L, -1);
722 if (asize > 0) {
723 lua_pushinteger(L, asize);
724 if (lua_next(L, -2) == 0) {
725 *len = asize;
726 return 1;
727 } else {
728 lua_pop(L, 2);
729 return 0;
730 }
731 } else {
732 lua_pushnil(L);
733 if (lua_next(L, -2) == 0) {
734 *len = asize;
735 return d->empty_as_array;
736 } else {
737 lua_pop(L, 2);
738 return 0;
739 }
740 }
741}
742
743static inline void dumpper_add_indent(json_dumpper_t *d, int count) {
744 membuffer_ensure_space(&d->buff, count);
745 int i;
746 for (i = 0; i < count; ++i)
747 membuffer_putc_unsafe(&d->buff, '\t');
748}
749
750static void dumpper_process_array(json_dumpper_t *d, lua_State *L, int len, int depth) {
751 membuffer_t *buff = &d->buff;
752 membuffer_putc(buff, '[');
753
754 int i;
755 for (i = 1; i <= len; ++i) {
756 if (unlikely(d->format && i == 1)) membuffer_putc(buff, '\n');
757 lua_rawgeti(L, -1, i);
758 if (unlikely(d->format)) dumpper_add_indent(d, depth);
759 dumpper_process_value(d, L, depth);
760 lua_pop(L, 1);
761 if (i < len)
762 membuffer_putc(buff, ',');
763 if (unlikely(d->format)) membuffer_putc(buff, '\n');
764 }
765
766 if (unlikely(d->format && i > 1)) dumpper_add_indent(d, depth-1);
767 membuffer_putc(buff, ']');
768}
769
770static void dumpper_process_object(json_dumpper_t *d, lua_State *L, int depth) {
771 membuffer_t *buff = &d->buff;
772 membuffer_putc(buff, '{');
773
774 int ktp;
775 int comma = 0;
776 lua_pushnil(L); // t nil
777 while (lua_next(L, -2) != 0) { // t k v
778 if (comma) {
779 membuffer_putc(buff, ',');
780 if (unlikely(d->format)) membuffer_putc(buff, '\n');
781 } else {
782 comma = 1;
783 if (unlikely(d->format)) membuffer_putc(buff, '\n');
784 }
785 // key
786 ktp = lua_type(L, -2);
787 if (ktp == LUA_TSTRING) {
788 if (unlikely(d->format)) dumpper_add_indent(d, depth);
789 dumpper_process_string(d, L, -2);
790 if (likely(!d->format))
791 membuffer_putc(buff, ':');
792 else
793 membuffer_putb(buff, " : ", 3);
794 } else if (ktp == LUA_TNUMBER && d->num_as_str) {
795 if (unlikely(d->format)) dumpper_add_indent(d, depth);
796 membuffer_putc(buff, '\"');
797#if LUA_VERSION_NUM > 501
798 if (lua_isinteger(L, -2))
799 dumpper_process_integer(d, L, -2);
800 else
801#endif
802 dumpper_process_number(d, L, -2);
803 if (likely(!d->format))
804 membuffer_putb(buff, "\":", 2);
805 else
806 membuffer_putb(buff, "\" : ", 4);
807 } else {
808 dumpper_throw_error(d, L, "Table key must be a string");
809 }
810 // value
811 dumpper_process_value(d, L, depth);
812 lua_pop(L, 1);
813 }
814 if (unlikely(d->format && comma)) {
815 membuffer_putc(buff, '\n');
816 dumpper_add_indent(d, depth-1);
817 }
818 membuffer_putc(buff, '}');
819}
820
821static inline void dumpper_process_table(json_dumpper_t *d, lua_State *L, int depth) {
822 depth++;
823 if (depth > d->maxdepth)
824 dumpper_throw_error(d, L, "Too many nested data, max depth is %d", d->maxdepth);
825 luaL_checkstack(L, 6, NULL);
826
827 int len;
828 if (dumpper_check_array(d, L, &len))
829 dumpper_process_array(d, L, len, depth);
830 else
831 dumpper_process_object(d, L, depth);
832}
833
834static void dumpper_process_value(json_dumpper_t *d, lua_State *L, int depth) {
835 int tp = lua_type(L, -1);
836 switch (tp) {
837 case LUA_TSTRING:
838 dumpper_process_string(d, L, -1);
839 break;
840 case LUA_TNUMBER:
841#if LUA_VERSION_NUM > 501
842 if (lua_isinteger(L, -1))
843 dumpper_process_integer(d, L, -1);
844 else
845#endif
846 dumpper_process_number(d, L, -1);
847 break;
848 case LUA_TBOOLEAN:
849 if (lua_toboolean(L, -1))
850 membuffer_putb(&d->buff, "true", 4);
851 else
852 membuffer_putb(&d->buff, "false", 5);
853 break;
854 case LUA_TTABLE:
855 dumpper_process_table(d, L, depth);
856 break;
857 case LUA_TNIL:
858 membuffer_putb(&d->buff, "null", 4);
859 break;
860 case LUA_TLIGHTUSERDATA:
861 if (lua_touserdata(L, -1) == NULL) {
862 membuffer_putb(&d->buff, "null", 4);
863 break;
864 }
865 goto error;
866 default:
867 error:
868 dumpper_throw_error(d, L, "Unsupport type %s", lua_typename(L, tp));
869 }
870}
871
872//-----------------------------------------------------------------------------
873// 接å£
874#define DEF_MAX_DEPTH 128
875
876// 从字符串加载:json.decode(str, maxdepth) -> obj
877// è¦æ±‚字符串必须以0结尾
878int colibc_json_decode(lua_State *L) {
879 size_t size;
880 const char *str = luaL_checklstring(L, 1, &size);
881 int maxdepth = (int)luaL_optinteger(L, 2, DEF_MAX_DEPTH);
882 int allowcomment = lua_toboolean(L, 3);
883 parser_do_parse(str, size, L, maxdepth, allowcomment);
884 return 1;
885}
886
887// ä¿å­˜åˆ°å­—符串: json.encode(obj) -> str
888int colibc_json_encode(lua_State *L) {
889 luaL_checkany(L, 1);
890 json_dumpper_t dumpper;
891 membuffer_init(&dumpper.buff);
892 dumpper.format = lua_toboolean(L, 2);
893 dumpper.empty_as_array = lua_toboolean(L, 3);
894 dumpper.num_as_str = lua_toboolean(L, 4);
895 dumpper.maxdepth = (int)luaL_optinteger(L, 5, DEF_MAX_DEPTH);
896
897 lua_settop(L, 1);
898 dumpper_process_value(&dumpper, L, 0);
899 lua_pushlstring(L, dumpper.buff.b, dumpper.buff.sz);
900 membuffer_free(&dumpper.buff);
901 return 1;
902}
903
904static const luaL_Reg lib[] = {
905 {"decode", colibc_json_decode},
906 {"encode", colibc_json_encode},
907 {NULL, NULL},
908};
909
910LUALIB_API int luaopen_colibc_json(lua_State* L) {
911#if LUA_VERSION_NUM > 501
912 luaL_newlib(L, lib); // json
913#else
914 lua_getglobal(L, "package"); // package
915 lua_getfield(L, -1, "loaded"); // package loaded
916 lua_createtable(L, 0, 0); // package loaded json
917 lua_pushvalue(L, -1); // package loaded json json
918 lua_setfield(L, -3, "cojson"); // loaded["cojson"] = json, package loaded json
919 luaL_register(L, NULL, lib); // package loaded json
920#endif
921 // json.null
922 lua_pushlightuserdata(L, NULL);
923 lua_setfield(L, -2, "null");
924 return 1;
925}
diff --git a/src/3rdParty/utf8cpp.h b/src/3rdParty/utf8cpp.h
new file mode 100755
index 0000000..76f0fa1
--- /dev/null
+++ b/src/3rdParty/utf8cpp.h
@@ -0,0 +1,1277 @@
1// Copyright 2006 Nemanja Trifunovic
2
3/*
4Permission is hereby granted, free of charge, to any person or organization
5obtaining a copy of the software and accompanying documentation covered by
6this license (the "Software") to use, reproduce, display, distribute,
7execute, and transmit the Software, and to prepare derivative works of the
8Software, and to permit third-parties to whom the Software is furnished to
9do so, all subject to the following:
10
11The copyright notices in the Software and this entire statement, including
12the above license grant, this restriction and the following disclaimer,
13must be included in all copies of the Software, in whole or in part, and
14all derivative works of the Software, unless such copies or derivative
15works are solely in the form of machine-executable object code generated by
16a source language processor.
17
18THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
19IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
20FITNESS FOR A PARTICULAR PURPOSE, TITLE AND NON-INFRINGEMENT. IN NO EVENT
21SHALL THE COPYRIGHT HOLDERS OR ANYONE DISTRIBUTING THE SOFTWARE BE LIABLE
22FOR ANY DAMAGES OR OTHER LIABILITY, WHETHER IN CONTRACT, TORT OR OTHERWISE,
23ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
24DEALINGS IN THE SOFTWARE.
25*/
26
27
28#ifndef UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
29#define UTF8_FOR_CPP_2675DCD0_9480_4c0c_B92A_CC14C027B731
30
31/*
32To control the C++ language version used by the library, you can define UTF_CPP_CPLUSPLUS macro
33and set it to one of the values used by the __cplusplus predefined macro.
34
35For instance,
36 #define UTF_CPP_CPLUSPLUS 199711L
37will cause the UTF-8 CPP library to use only types and language features available in the C++ 98 standard.
38Some library features will be disabled.
39
40If you leave UTF_CPP_CPLUSPLUS undefined, it will be internally assigned to __cplusplus.
41*/
42
43#include <iterator>
44#include <cstring>
45#include <string>
46
47// Determine the C++ standard version.
48// If the user defines UTF_CPP_CPLUSPLUS, use that.
49// Otherwise, trust the unreliable predefined macro __cplusplus
50
51#if !defined UTF_CPP_CPLUSPLUS
52 #define UTF_CPP_CPLUSPLUS __cplusplus
53#endif
54
55#if UTF_CPP_CPLUSPLUS >= 201103L // C++ 11 or later
56 #define UTF_CPP_OVERRIDE override
57 #define UTF_CPP_NOEXCEPT noexcept
58 #define UTF_CPP_STATIC_ASSERT(condition) static_assert(condition, "UTFCPP static assert");
59#else // C++ 98/03
60 #define UTF_CPP_OVERRIDE
61 #define UTF_CPP_NOEXCEPT throw()
62 // Simulate static_assert:
63 template<bool> struct UtfCppCompileTimeAssert;
64 template<> struct UtfCppCompileTimeAssert <true> { };
65 #define UTF_CPP_STATIC_ASSERT(condition) (UtfCppCompileTimeAssert <(condition) != 0>())
66#endif // C++ 11 or later
67
68
69namespace utf8
70{
71// The typedefs for 8-bit, 16-bit and 32-bit code units
72#if UTF_CPP_CPLUSPLUS >= 201103L // C++ 11 or later
73 #if UTF_CPP_CPLUSPLUS >= 202002L // C++ 20 or later
74 typedef char8_t utfchar8_t;
75 #else // C++ 11/14/17
76 typedef unsigned char utfchar8_t;
77 #endif
78 typedef char16_t utfchar16_t;
79 typedef char32_t utfchar32_t;
80#else // C++ 98/03
81 typedef unsigned char utfchar8_t;
82 typedef unsigned short utfchar16_t;
83 typedef unsigned int utfchar32_t;
84#endif // C++ 11 or later
85
86// Helper code - not intended to be directly called by the library users. May be changed at any time
87namespace internal
88{
89 // Unicode constants
90 // Leading (high) surrogates: 0xd800 - 0xdbff
91 // Trailing (low) surrogates: 0xdc00 - 0xdfff
92 const utfchar16_t LEAD_SURROGATE_MIN = 0xd800u;
93 const utfchar16_t LEAD_SURROGATE_MAX = 0xdbffu;
94 const utfchar16_t TRAIL_SURROGATE_MIN = 0xdc00u;
95 const utfchar16_t TRAIL_SURROGATE_MAX = 0xdfffu;
96 const utfchar16_t LEAD_OFFSET = 0xd7c0u; // LEAD_SURROGATE_MIN - (0x10000 >> 10)
97 const utfchar32_t SURROGATE_OFFSET = 0xfca02400u; // 0x10000u - (LEAD_SURROGATE_MIN << 10) - TRAIL_SURROGATE_MIN
98
99 // Maximum valid value for a Unicode code point
100 const utfchar32_t CODE_POINT_MAX = 0x0010ffffu;
101
102 template<typename octet_type>
103 inline utfchar8_t mask8(octet_type oc)
104 {
105 return static_cast<utfchar8_t>(0xff & oc);
106 }
107
108 template<typename u16_type>
109 inline utfchar16_t mask16(u16_type oc)
110 {
111 return static_cast<utfchar16_t>(0xffff & oc);
112 }
113
114 template<typename octet_type>
115 inline bool is_trail(octet_type oc)
116 {
117 return ((utf8::internal::mask8(oc) >> 6) == 0x2);
118 }
119
120 inline bool is_lead_surrogate(utfchar32_t cp)
121 {
122 return (cp >= static_cast<utfchar32_t>(LEAD_SURROGATE_MIN) && cp <= static_cast<utfchar32_t>(LEAD_SURROGATE_MAX));
123 }
124
125 inline bool is_trail_surrogate(utfchar32_t cp)
126 {
127 return (cp >= static_cast<utfchar32_t>(TRAIL_SURROGATE_MIN) && cp <= static_cast<utfchar32_t>(TRAIL_SURROGATE_MAX));
128 }
129
130 inline bool is_surrogate(utfchar32_t cp)
131 {
132 return (cp >= static_cast<utfchar32_t>(LEAD_SURROGATE_MIN) && cp <= static_cast<utfchar32_t>(TRAIL_SURROGATE_MAX));
133 }
134
135 inline bool is_code_point_valid(utfchar32_t cp)
136 {
137 return (cp <= CODE_POINT_MAX && !utf8::internal::is_surrogate(cp));
138 }
139
140 inline bool is_in_bmp(utfchar32_t cp)
141 {
142 return cp < utfchar32_t(0x10000);
143 }
144
145 template <typename octet_iterator>
146 int sequence_length(octet_iterator lead_it)
147 {
148 const utfchar8_t lead = utf8::internal::mask8(*lead_it);
149 if (lead < 0x80)
150 return 1;
151 else if ((lead >> 5) == 0x6)
152 return 2;
153 else if ((lead >> 4) == 0xe)
154 return 3;
155 else if ((lead >> 3) == 0x1e)
156 return 4;
157 else
158 return 0;
159 }
160
161 inline bool is_overlong_sequence(utfchar32_t cp, int length)
162 {
163 if (cp < 0x80) {
164 if (length != 1)
165 return true;
166 }
167 else if (cp < 0x800) {
168 if (length != 2)
169 return true;
170 }
171 else if (cp < 0x10000) {
172 if (length != 3)
173 return true;
174 }
175 return false;
176 }
177
178 enum utf_error {UTF8_OK, NOT_ENOUGH_ROOM, INVALID_LEAD, INCOMPLETE_SEQUENCE, OVERLONG_SEQUENCE, INVALID_CODE_POINT};
179
180 /// Helper for get_sequence_x
181 template <typename octet_iterator>
182 utf_error increase_safely(octet_iterator& it, const octet_iterator end)
183 {
184 if (++it == end)
185 return NOT_ENOUGH_ROOM;
186
187 if (!utf8::internal::is_trail(*it))
188 return INCOMPLETE_SEQUENCE;
189
190 return UTF8_OK;
191 }
192
193 #define UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(IT, END) {utf_error ret = increase_safely(IT, END); if (ret != UTF8_OK) return ret;}
194
195 /// get_sequence_x functions decode utf-8 sequences of the length x
196 template <typename octet_iterator>
197 utf_error get_sequence_1(octet_iterator& it, octet_iterator end, utfchar32_t& code_point)
198 {
199 if (it == end)
200 return NOT_ENOUGH_ROOM;
201
202 code_point = static_cast<utfchar32_t>(utf8::internal::mask8(*it));
203
204 return UTF8_OK;
205 }
206
207 template <typename octet_iterator>
208 utf_error get_sequence_2(octet_iterator& it, octet_iterator end, utfchar32_t& code_point)
209 {
210 if (it == end)
211 return NOT_ENOUGH_ROOM;
212
213 code_point = static_cast<utfchar32_t>(utf8::internal::mask8(*it));
214
215 UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
216
217 code_point = ((code_point << 6) & 0x7ff) + ((*it) & 0x3f);
218
219 return UTF8_OK;
220 }
221
222 template <typename octet_iterator>
223 utf_error get_sequence_3(octet_iterator& it, octet_iterator end, utfchar32_t& code_point)
224 {
225 if (it == end)
226 return NOT_ENOUGH_ROOM;
227
228 code_point = static_cast<utfchar32_t>(utf8::internal::mask8(*it));
229
230 UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
231
232 code_point = ((code_point << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
233
234 UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
235
236 code_point = static_cast<utfchar32_t>(code_point + ((*it) & 0x3f));
237
238 return UTF8_OK;
239 }
240
241 template <typename octet_iterator>
242 utf_error get_sequence_4(octet_iterator& it, octet_iterator end, utfchar32_t& code_point)
243 {
244 if (it == end)
245 return NOT_ENOUGH_ROOM;
246
247 code_point = static_cast<utfchar32_t>(utf8::internal::mask8(*it));
248
249 UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
250
251 code_point = ((code_point << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
252
253 UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
254
255 code_point = static_cast<utfchar32_t>(code_point + ((utf8::internal::mask8(*it) << 6) & 0xfff));
256
257 UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR(it, end)
258
259 code_point = static_cast<utfchar32_t>(code_point + ((*it) & 0x3f));
260
261 return UTF8_OK;
262 }
263
264 #undef UTF8_CPP_INCREASE_AND_RETURN_ON_ERROR
265
266 template <typename octet_iterator>
267 utf_error validate_next(octet_iterator& it, octet_iterator end, utfchar32_t& code_point)
268 {
269 if (it == end)
270 return NOT_ENOUGH_ROOM;
271
272 // Save the original value of it so we can go back in case of failure
273 // Of course, it does not make much sense with i.e. stream iterators
274 octet_iterator original_it = it;
275
276 utfchar32_t cp = 0;
277 // Determine the sequence length based on the lead octet
278 const int length = utf8::internal::sequence_length(it);
279
280 // Get trail octets and calculate the code point
281 utf_error err = UTF8_OK;
282 switch (length) {
283 case 0:
284 return INVALID_LEAD;
285 case 1:
286 err = utf8::internal::get_sequence_1(it, end, cp);
287 break;
288 case 2:
289 err = utf8::internal::get_sequence_2(it, end, cp);
290 break;
291 case 3:
292 err = utf8::internal::get_sequence_3(it, end, cp);
293 break;
294 case 4:
295 err = utf8::internal::get_sequence_4(it, end, cp);
296 break;
297 }
298
299 if (err == UTF8_OK) {
300 // Decoding succeeded. Now, security checks...
301 if (utf8::internal::is_code_point_valid(cp)) {
302 if (!utf8::internal::is_overlong_sequence(cp, length)){
303 // Passed! Return here.
304 code_point = cp;
305 ++it;
306 return UTF8_OK;
307 }
308 else
309 err = OVERLONG_SEQUENCE;
310 }
311 else
312 err = INVALID_CODE_POINT;
313 }
314
315 // Failure branch - restore the original value of the iterator
316 it = original_it;
317 return err;
318 }
319
320 template <typename octet_iterator>
321 inline utf_error validate_next(octet_iterator& it, octet_iterator end) {
322 utfchar32_t ignored;
323 return utf8::internal::validate_next(it, end, ignored);
324 }
325
326 template <typename word_iterator>
327 utf_error validate_next16(word_iterator& it, word_iterator end, utfchar32_t& code_point)
328 {
329 // Make sure the iterator dereferences a large enough type
330 typedef typename std::iterator_traits<word_iterator>::value_type word_type;
331 UTF_CPP_STATIC_ASSERT(sizeof(word_type) >= sizeof(utfchar16_t));
332 // Check the edge case:
333 if (it == end)
334 return NOT_ENOUGH_ROOM;
335 // Save the original value of it so we can go back in case of failure
336 // Of course, it does not make much sense with i.e. stream iterators
337 word_iterator original_it = it;
338
339 utf_error err = UTF8_OK;
340
341 const utfchar16_t first_word = *it++;
342 if (!is_surrogate(first_word)) {
343 code_point = first_word;
344 return UTF8_OK;
345 }
346 else {
347 if (it == end)
348 err = NOT_ENOUGH_ROOM;
349 else if (is_lead_surrogate(first_word)) {
350 const utfchar16_t second_word = *it++;
351 if (is_trail_surrogate(static_cast<utfchar32_t>(second_word))) {
352 code_point = static_cast<utfchar32_t>(first_word << 10) + static_cast<utfchar32_t>(second_word) + SURROGATE_OFFSET;
353 return UTF8_OK;
354 } else
355 err = INCOMPLETE_SEQUENCE;
356
357 } else {
358 err = INVALID_LEAD;
359 }
360 }
361 // error branch
362 it = original_it;
363 return err;
364 }
365
366 // Internal implementation of both checked and unchecked append() function
367 // This function will be invoked by the overloads below, as they will know
368 // the octet_type.
369 template <typename octet_iterator, typename octet_type>
370 octet_iterator append(utfchar32_t cp, octet_iterator result) {
371 if (cp < 0x80) // one octet
372 *(result++) = static_cast<octet_type>(cp);
373 else if (cp < 0x800) { // two octets
374 *(result++) = static_cast<octet_type>((cp >> 6) | 0xc0);
375 *(result++) = static_cast<octet_type>((cp & 0x3f) | 0x80);
376 }
377 else if (cp < 0x10000) { // three octets
378 *(result++) = static_cast<octet_type>((cp >> 12) | 0xe0);
379 *(result++) = static_cast<octet_type>(((cp >> 6) & 0x3f) | 0x80);
380 *(result++) = static_cast<octet_type>((cp & 0x3f) | 0x80);
381 }
382 else { // four octets
383 *(result++) = static_cast<octet_type>((cp >> 18) | 0xf0);
384 *(result++) = static_cast<octet_type>(((cp >> 12) & 0x3f)| 0x80);
385 *(result++) = static_cast<octet_type>(((cp >> 6) & 0x3f) | 0x80);
386 *(result++) = static_cast<octet_type>((cp & 0x3f) | 0x80);
387 }
388 return result;
389 }
390
391 // One of the following overloads will be invoked from the API calls
392
393 // A simple (but dangerous) case: the caller appends byte(s) to a char array
394 inline char* append(utfchar32_t cp, char* result) {
395 return append<char*, char>(cp, result);
396 }
397
398 // Hopefully, most common case: the caller uses back_inserter
399 // i.e. append(cp, std::back_inserter(str));
400 template<typename container_type>
401 std::back_insert_iterator<container_type> append
402 (utfchar32_t cp, std::back_insert_iterator<container_type> result) {
403 return append<std::back_insert_iterator<container_type>,
404 typename container_type::value_type>(cp, result);
405 }
406
407 // The caller uses some other kind of output operator - not covered above
408 // Note that in this case we are not able to determine octet_type
409 // so we assume it's utfchar8_t; that can cause a conversion warning if we are wrong.
410 template <typename octet_iterator>
411 octet_iterator append(utfchar32_t cp, octet_iterator result) {
412 return append<octet_iterator, utfchar8_t>(cp, result);
413 }
414
415 // Internal implementation of both checked and unchecked append16() function
416 // This function will be invoked by the overloads below, as they will know
417 // the word_type.
418 template <typename word_iterator, typename word_type>
419 word_iterator append16(utfchar32_t cp, word_iterator result) {
420 UTF_CPP_STATIC_ASSERT(sizeof(word_type) >= sizeof(utfchar16_t));
421 if (is_in_bmp(cp))
422 *(result++) = static_cast<word_type>(cp);
423 else {
424 // Code points from the supplementary planes are encoded via surrogate pairs
425 *(result++) = static_cast<word_type>(LEAD_OFFSET + (cp >> 10));
426 *(result++) = static_cast<word_type>(TRAIL_SURROGATE_MIN + (cp & 0x3FF));
427 }
428 return result;
429 }
430
431 // Hopefully, most common case: the caller uses back_inserter
432 // i.e. append16(cp, std::back_inserter(str));
433 template<typename container_type>
434 std::back_insert_iterator<container_type> append16
435 (utfchar32_t cp, std::back_insert_iterator<container_type> result) {
436 return append16<std::back_insert_iterator<container_type>,
437 typename container_type::value_type>(cp, result);
438 }
439
440 // The caller uses some other kind of output operator - not covered above
441 // Note that in this case we are not able to determine word_type
442 // so we assume it's utfchar16_t; that can cause a conversion warning if we are wrong.
443 template <typename word_iterator>
444 word_iterator append16(utfchar32_t cp, word_iterator result) {
445 return append16<word_iterator, utfchar16_t>(cp, result);
446 }
447
448} // namespace internal
449
450 /// The library API - functions intended to be called by the users
451
452 // Byte order mark
453 const utfchar8_t bom[] = {0xef, 0xbb, 0xbf};
454
455 template <typename octet_iterator>
456 octet_iterator find_invalid(octet_iterator start, octet_iterator end)
457 {
458 octet_iterator result = start;
459 while (result != end) {
460 utf8::internal::utf_error err_code = utf8::internal::validate_next(result, end);
461 if (err_code != internal::UTF8_OK)
462 return result;
463 }
464 return result;
465 }
466
467 inline const char* find_invalid(const char* str)
468 {
469 const char* end = str + std::strlen(str);
470 return find_invalid(str, end);
471 }
472
473 inline std::size_t find_invalid(const std::string& s)
474 {
475 std::string::const_iterator invalid = find_invalid(s.begin(), s.end());
476 return (invalid == s.end()) ? std::string::npos : static_cast<std::size_t>(invalid - s.begin());
477 }
478
479 template <typename octet_iterator>
480 inline bool is_valid(octet_iterator start, octet_iterator end)
481 {
482 return (utf8::find_invalid(start, end) == end);
483 }
484
485 inline bool is_valid(const char* str)
486 {
487 return (*(utf8::find_invalid(str)) == '\0');
488 }
489
490 inline bool is_valid(const std::string& s)
491 {
492 return is_valid(s.begin(), s.end());
493 }
494
495
496
497 template <typename octet_iterator>
498 inline bool starts_with_bom (octet_iterator it, octet_iterator end)
499 {
500 return (
501 ((it != end) && (utf8::internal::mask8(*it++)) == bom[0]) &&
502 ((it != end) && (utf8::internal::mask8(*it++)) == bom[1]) &&
503 ((it != end) && (utf8::internal::mask8(*it)) == bom[2])
504 );
505 }
506
507 inline bool starts_with_bom(const std::string& s)
508 {
509 return starts_with_bom(s.begin(), s.end());
510 }
511} // namespace utf8
512
513#include <stdexcept>
514
515namespace utf8
516{
517 // Base for the exceptions that may be thrown from the library
518 class exception : public ::std::exception {
519 };
520
521 // Exceptions that may be thrown from the library functions.
522 class invalid_code_point : public exception {
523 utfchar32_t cp;
524 public:
525 invalid_code_point(utfchar32_t codepoint) : cp(codepoint) {}
526 virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid code point"; }
527 utfchar32_t code_point() const {return cp;}
528 };
529
530 class invalid_utf8 : public exception {
531 utfchar8_t u8;
532 public:
533 invalid_utf8 (utfchar8_t u) : u8(u) {}
534 invalid_utf8 (char c) : u8(static_cast<utfchar8_t>(c)) {}
535 virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid UTF-8"; }
536 utfchar8_t utf8_octet() const {return u8;}
537 };
538
539 class invalid_utf16 : public exception {
540 utfchar16_t u16;
541 public:
542 invalid_utf16 (utfchar16_t u) : u16(u) {}
543 virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Invalid UTF-16"; }
544 utfchar16_t utf16_word() const {return u16;}
545 };
546
547 class not_enough_room : public exception {
548 public:
549 virtual const char* what() const UTF_CPP_NOEXCEPT UTF_CPP_OVERRIDE { return "Not enough space"; }
550 };
551
552 /// The library API - functions intended to be called by the users
553
554 template <typename octet_iterator>
555 octet_iterator append(utfchar32_t cp, octet_iterator result)
556 {
557 if (!utf8::internal::is_code_point_valid(cp))
558 throw invalid_code_point(cp);
559
560 return internal::append(cp, result);
561 }
562
563 inline void append(utfchar32_t cp, std::string& s)
564 {
565 append(cp, std::back_inserter(s));
566 }
567
568 template <typename word_iterator>
569 word_iterator append16(utfchar32_t cp, word_iterator result)
570 {
571 if (!utf8::internal::is_code_point_valid(cp))
572 throw invalid_code_point(cp);
573
574 return internal::append16(cp, result);
575 }
576
577 template <typename octet_iterator, typename output_iterator>
578 output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, utfchar32_t replacement)
579 {
580 while (start != end) {
581 octet_iterator sequence_start = start;
582 internal::utf_error err_code = utf8::internal::validate_next(start, end);
583 switch (err_code) {
584 case internal::UTF8_OK :
585 for (octet_iterator it = sequence_start; it != start; ++it)
586 *out++ = *it;
587 break;
588 case internal::NOT_ENOUGH_ROOM:
589 out = utf8::append (replacement, out);
590 start = end;
591 break;
592 case internal::INVALID_LEAD:
593 out = utf8::append (replacement, out);
594 ++start;
595 break;
596 case internal::INCOMPLETE_SEQUENCE:
597 case internal::OVERLONG_SEQUENCE:
598 case internal::INVALID_CODE_POINT:
599 out = utf8::append (replacement, out);
600 ++start;
601 // just one replacement mark for the sequence
602 while (start != end && utf8::internal::is_trail(*start))
603 ++start;
604 break;
605 }
606 }
607 return out;
608 }
609
610 template <typename octet_iterator, typename output_iterator>
611 inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out)
612 {
613 static const utfchar32_t replacement_marker = static_cast<utfchar32_t>(utf8::internal::mask16(0xfffd));
614 return utf8::replace_invalid(start, end, out, replacement_marker);
615 }
616
617 inline std::string replace_invalid(const std::string& s, utfchar32_t replacement)
618 {
619 std::string result;
620 replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement);
621 return result;
622 }
623
624 inline std::string replace_invalid(const std::string& s)
625 {
626 std::string result;
627 replace_invalid(s.begin(), s.end(), std::back_inserter(result));
628 return result;
629 }
630
631 template <typename octet_iterator>
632 utfchar32_t next(octet_iterator& it, octet_iterator end)
633 {
634 utfchar32_t cp = 0;
635 internal::utf_error err_code = utf8::internal::validate_next(it, end, cp);
636 switch (err_code) {
637 case internal::UTF8_OK :
638 break;
639 case internal::NOT_ENOUGH_ROOM :
640 throw not_enough_room();
641 case internal::INVALID_LEAD :
642 case internal::INCOMPLETE_SEQUENCE :
643 case internal::OVERLONG_SEQUENCE :
644 throw invalid_utf8(static_cast<utfchar8_t>(*it));
645 case internal::INVALID_CODE_POINT :
646 throw invalid_code_point(cp);
647 }
648 return cp;
649 }
650
651 template <typename word_iterator>
652 utfchar32_t next16(word_iterator& it, word_iterator end)
653 {
654 utfchar32_t cp = 0;
655 internal::utf_error err_code = utf8::internal::validate_next16(it, end, cp);
656 if (err_code == internal::NOT_ENOUGH_ROOM)
657 throw not_enough_room();
658 return cp;
659 }
660
661 template <typename octet_iterator>
662 utfchar32_t peek_next(octet_iterator it, octet_iterator end)
663 {
664 return utf8::next(it, end);
665 }
666
667 template <typename octet_iterator>
668 utfchar32_t prior(octet_iterator& it, octet_iterator start)
669 {
670 // can't do much if it == start
671 if (it == start)
672 throw not_enough_room();
673
674 octet_iterator end = it;
675 // Go back until we hit either a lead octet or start
676 while (utf8::internal::is_trail(*(--it)))
677 if (it == start)
678 throw invalid_utf8(*it); // error - no lead byte in the sequence
679 return utf8::peek_next(it, end);
680 }
681
682 template <typename octet_iterator, typename distance_type>
683 void advance (octet_iterator& it, distance_type n, octet_iterator end)
684 {
685 const distance_type zero(0);
686 if (n < zero) {
687 // backward
688 for (distance_type i = n; i < zero; ++i)
689 utf8::prior(it, end);
690 } else {
691 // forward
692 for (distance_type i = zero; i < n; ++i)
693 utf8::next(it, end);
694 }
695 }
696
697 template <typename octet_iterator>
698 typename std::iterator_traits<octet_iterator>::difference_type
699 distance (octet_iterator first, octet_iterator last)
700 {
701 typename std::iterator_traits<octet_iterator>::difference_type dist;
702 for (dist = 0; first < last; ++dist)
703 utf8::next(first, last);
704 return dist;
705 }
706
707 template <typename u16bit_iterator, typename octet_iterator>
708 octet_iterator utf16to8 (u16bit_iterator start, u16bit_iterator end, octet_iterator result)
709 {
710 while (start != end) {
711 utfchar32_t cp = static_cast<utfchar32_t>(utf8::internal::mask16(*start++));
712 // Take care of surrogate pairs first
713 if (utf8::internal::is_lead_surrogate(cp)) {
714 if (start != end) {
715 const utfchar32_t trail_surrogate = static_cast<utfchar32_t>(utf8::internal::mask16(*start++));
716 if (utf8::internal::is_trail_surrogate(trail_surrogate))
717 cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
718 else
719 throw invalid_utf16(static_cast<utfchar16_t>(trail_surrogate));
720 }
721 else
722 throw invalid_utf16(static_cast<utfchar16_t>(cp));
723
724 }
725 // Lone trail surrogate
726 else if (utf8::internal::is_trail_surrogate(cp))
727 throw invalid_utf16(static_cast<utfchar16_t>(cp));
728
729 result = utf8::append(cp, result);
730 }
731 return result;
732 }
733
734 template <typename u16bit_iterator, typename octet_iterator>
735 u16bit_iterator utf8to16 (octet_iterator start, octet_iterator end, u16bit_iterator result)
736 {
737 while (start < end) {
738 const utfchar32_t cp = utf8::next(start, end);
739 if (cp > 0xffff) { //make a surrogate pair
740 *result++ = static_cast<utfchar16_t>((cp >> 10) + internal::LEAD_OFFSET);
741 *result++ = static_cast<utfchar16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
742 }
743 else
744 *result++ = static_cast<utfchar16_t>(cp);
745 }
746 return result;
747 }
748
749 template <typename octet_iterator, typename u32bit_iterator>
750 octet_iterator utf32to8 (u32bit_iterator start, u32bit_iterator end, octet_iterator result)
751 {
752 while (start != end)
753 result = utf8::append(*(start++), result);
754
755 return result;
756 }
757
758 template <typename octet_iterator, typename u32bit_iterator>
759 u32bit_iterator utf8to32 (octet_iterator start, octet_iterator end, u32bit_iterator result)
760 {
761 while (start < end)
762 (*result++) = utf8::next(start, end);
763
764 return result;
765 }
766
767 // The iterator class
768 template <typename octet_iterator>
769 class iterator {
770 octet_iterator it;
771 octet_iterator range_start;
772 octet_iterator range_end;
773 public:
774 typedef utfchar32_t value_type;
775 typedef utfchar32_t* pointer;
776 typedef utfchar32_t& reference;
777 typedef std::ptrdiff_t difference_type;
778 typedef std::bidirectional_iterator_tag iterator_category;
779 iterator () {}
780 explicit iterator (const octet_iterator& octet_it,
781 const octet_iterator& rangestart,
782 const octet_iterator& rangeend) :
783 it(octet_it), range_start(rangestart), range_end(rangeend)
784 {
785 if (it < range_start || it > range_end)
786 throw std::out_of_range("Invalid utf-8 iterator position");
787 }
788 // the default "big three" are OK
789 octet_iterator base () const { return it; }
790 utfchar32_t operator * () const
791 {
792 octet_iterator temp = it;
793 return utf8::next(temp, range_end);
794 }
795 bool operator == (const iterator& rhs) const
796 {
797 if (range_start != rhs.range_start || range_end != rhs.range_end)
798 throw std::logic_error("Comparing utf-8 iterators defined with different ranges");
799 return (it == rhs.it);
800 }
801 bool operator != (const iterator& rhs) const
802 {
803 return !(operator == (rhs));
804 }
805 iterator& operator ++ ()
806 {
807 utf8::next(it, range_end);
808 return *this;
809 }
810 iterator operator ++ (int)
811 {
812 iterator temp = *this;
813 utf8::next(it, range_end);
814 return temp;
815 }
816 iterator& operator -- ()
817 {
818 utf8::prior(it, range_start);
819 return *this;
820 }
821 iterator operator -- (int)
822 {
823 iterator temp = *this;
824 utf8::prior(it, range_start);
825 return temp;
826 }
827 }; // class iterator
828
829} // namespace utf8
830
831#if UTF_CPP_CPLUSPLUS >= 201103L // C++ 11 or later
832namespace utf8
833{
834 inline void append16(utfchar32_t cp, std::u16string& s)
835 {
836 append16(cp, std::back_inserter(s));
837 }
838
839 inline std::string utf16to8(const std::u16string& s)
840 {
841 std::string result;
842 utf16to8(s.begin(), s.end(), std::back_inserter(result));
843 return result;
844 }
845
846 inline std::u16string utf8to16(const std::string& s)
847 {
848 std::u16string result;
849 utf8to16(s.begin(), s.end(), std::back_inserter(result));
850 return result;
851 }
852
853 inline std::string utf32to8(const std::u32string& s)
854 {
855 std::string result;
856 utf32to8(s.begin(), s.end(), std::back_inserter(result));
857 return result;
858 }
859
860 inline std::u32string utf8to32(const std::string& s)
861 {
862 std::u32string result;
863 utf8to32(s.begin(), s.end(), std::back_inserter(result));
864 return result;
865 }
866} // namespace utf8
867#endif // C++ 11 or later
868
869#if UTF_CPP_CPLUSPLUS >= 201703L // C++ 17 or later
870namespace utf8
871{
872 inline std::string utf16to8(std::u16string_view s)
873 {
874 std::string result;
875 utf16to8(s.begin(), s.end(), std::back_inserter(result));
876 return result;
877 }
878
879 inline std::u16string utf8to16(std::string_view s)
880 {
881 std::u16string result;
882 utf8to16(s.begin(), s.end(), std::back_inserter(result));
883 return result;
884 }
885
886 inline std::string utf32to8(std::u32string_view s)
887 {
888 std::string result;
889 utf32to8(s.begin(), s.end(), std::back_inserter(result));
890 return result;
891 }
892
893 inline std::u32string utf8to32(std::string_view s)
894 {
895 std::u32string result;
896 utf8to32(s.begin(), s.end(), std::back_inserter(result));
897 return result;
898 }
899
900 inline std::size_t find_invalid(std::string_view s)
901 {
902 std::string_view::const_iterator invalid = find_invalid(s.begin(), s.end());
903 return (invalid == s.end()) ? std::string_view::npos : static_cast<std::size_t>(invalid - s.begin());
904 }
905
906 inline bool is_valid(std::string_view s)
907 {
908 return is_valid(s.begin(), s.end());
909 }
910
911 inline std::string replace_invalid(std::string_view s, char32_t replacement)
912 {
913 std::string result;
914 replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement);
915 return result;
916 }
917
918 inline std::string replace_invalid(std::string_view s)
919 {
920 std::string result;
921 replace_invalid(s.begin(), s.end(), std::back_inserter(result));
922 return result;
923 }
924
925 inline bool starts_with_bom(std::string_view s)
926 {
927 return starts_with_bom(s.begin(), s.end());
928 }
929
930} // namespace utf8
931#endif // C++ 17 or later
932
933#if UTF_CPP_CPLUSPLUS >= 202002L // C++ 20 or later
934namespace utf8
935{
936 inline std::u8string utf16tou8(const std::u16string& s)
937 {
938 std::u8string result;
939 utf16to8(s.begin(), s.end(), std::back_inserter(result));
940 return result;
941 }
942
943 inline std::u8string utf16tou8(std::u16string_view s)
944 {
945 std::u8string result;
946 utf16to8(s.begin(), s.end(), std::back_inserter(result));
947 return result;
948 }
949
950 inline std::u16string utf8to16(const std::u8string& s)
951 {
952 std::u16string result;
953 utf8to16(s.begin(), s.end(), std::back_inserter(result));
954 return result;
955 }
956
957 inline std::u16string utf8to16(const std::u8string_view& s)
958 {
959 std::u16string result;
960 utf8to16(s.begin(), s.end(), std::back_inserter(result));
961 return result;
962 }
963
964 inline std::u8string utf32tou8(const std::u32string& s)
965 {
966 std::u8string result;
967 utf32to8(s.begin(), s.end(), std::back_inserter(result));
968 return result;
969 }
970
971 inline std::u8string utf32tou8(const std::u32string_view& s)
972 {
973 std::u8string result;
974 utf32to8(s.begin(), s.end(), std::back_inserter(result));
975 return result;
976 }
977
978 inline std::u32string utf8to32(const std::u8string& s)
979 {
980 std::u32string result;
981 utf8to32(s.begin(), s.end(), std::back_inserter(result));
982 return result;
983 }
984
985 inline std::u32string utf8to32(const std::u8string_view& s)
986 {
987 std::u32string result;
988 utf8to32(s.begin(), s.end(), std::back_inserter(result));
989 return result;
990 }
991
992 inline std::size_t find_invalid(const std::u8string& s)
993 {
994 std::u8string::const_iterator invalid = find_invalid(s.begin(), s.end());
995 return (invalid == s.end()) ? std::string_view::npos : static_cast<std::size_t>(invalid - s.begin());
996 }
997
998 inline bool is_valid(const std::u8string& s)
999 {
1000 return is_valid(s.begin(), s.end());
1001 }
1002
1003 inline std::u8string replace_invalid(const std::u8string& s, char32_t replacement)
1004 {
1005 std::u8string result;
1006 replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement);
1007 return result;
1008 }
1009
1010 inline std::u8string replace_invalid(const std::u8string& s)
1011 {
1012 std::u8string result;
1013 replace_invalid(s.begin(), s.end(), std::back_inserter(result));
1014 return result;
1015 }
1016
1017 inline bool starts_with_bom(const std::u8string& s)
1018 {
1019 return starts_with_bom(s.begin(), s.end());
1020 }
1021
1022} // namespace utf8
1023#endif // C++ 20 or later
1024
1025namespace utf8
1026{
1027 namespace unchecked
1028 {
1029 template <typename octet_iterator>
1030 octet_iterator append(utfchar32_t cp, octet_iterator result)
1031 {
1032 return internal::append(cp, result);
1033 }
1034
1035 template <typename word_iterator>
1036 word_iterator append16(utfchar32_t cp, word_iterator result)
1037 {
1038 return internal::append16(cp, result);
1039 }
1040
1041 template <typename octet_iterator, typename output_iterator>
1042 output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out, utfchar32_t replacement)
1043 {
1044 while (start != end) {
1045 octet_iterator sequence_start = start;
1046 internal::utf_error err_code = utf8::internal::validate_next(start, end);
1047 switch (err_code) {
1048 case internal::UTF8_OK :
1049 for (octet_iterator it = sequence_start; it != start; ++it)
1050 *out++ = *it;
1051 break;
1052 case internal::NOT_ENOUGH_ROOM:
1053 out = utf8::unchecked::append(replacement, out);
1054 start = end;
1055 break;
1056 case internal::INVALID_LEAD:
1057 out = utf8::unchecked::append(replacement, out);
1058 ++start;
1059 break;
1060 case internal::INCOMPLETE_SEQUENCE:
1061 case internal::OVERLONG_SEQUENCE:
1062 case internal::INVALID_CODE_POINT:
1063 out = utf8::unchecked::append(replacement, out);
1064 ++start;
1065 // just one replacement mark for the sequence
1066 while (start != end && utf8::internal::is_trail(*start))
1067 ++start;
1068 break;
1069 }
1070 }
1071 return out;
1072 }
1073
1074 template <typename octet_iterator, typename output_iterator>
1075 inline output_iterator replace_invalid(octet_iterator start, octet_iterator end, output_iterator out)
1076 {
1077 static const utfchar32_t replacement_marker = static_cast<utfchar32_t>(utf8::internal::mask16(0xfffd));
1078 return utf8::unchecked::replace_invalid(start, end, out, replacement_marker);
1079 }
1080
1081 inline std::string replace_invalid(const std::string& s, utfchar32_t replacement)
1082 {
1083 std::string result;
1084 replace_invalid(s.begin(), s.end(), std::back_inserter(result), replacement);
1085 return result;
1086 }
1087
1088 inline std::string replace_invalid(const std::string& s)
1089 {
1090 std::string result;
1091 replace_invalid(s.begin(), s.end(), std::back_inserter(result));
1092 return result;
1093 }
1094
1095 template <typename octet_iterator>
1096 utfchar32_t next(octet_iterator& it)
1097 {
1098 utfchar32_t cp = utf8::internal::mask8(*it);
1099 switch (utf8::internal::sequence_length(it)) {
1100 case 1:
1101 break;
1102 case 2:
1103 ++it;
1104 cp = ((cp << 6) & 0x7ff) + ((*it) & 0x3f);
1105 break;
1106 case 3:
1107 ++it;
1108 cp = ((cp << 12) & 0xffff) + ((utf8::internal::mask8(*it) << 6) & 0xfff);
1109 ++it;
1110 cp = static_cast<utfchar32_t>(cp + ((*it) & 0x3f));
1111 break;
1112 case 4:
1113 ++it;
1114 cp = ((cp << 18) & 0x1fffff) + ((utf8::internal::mask8(*it) << 12) & 0x3ffff);
1115 ++it;
1116 cp = static_cast<utfchar32_t>(cp + ((utf8::internal::mask8(*it) << 6) & 0xfff));
1117 ++it;
1118 cp = static_cast<utfchar32_t>(cp + ((*it) & 0x3f));
1119 break;
1120 }
1121 ++it;
1122 return cp;
1123 }
1124
1125 template <typename octet_iterator>
1126 utfchar32_t peek_next(octet_iterator it)
1127 {
1128 return utf8::unchecked::next(it);
1129 }
1130
1131 template <typename word_iterator>
1132 utfchar32_t next16(word_iterator& it)
1133 {
1134 utfchar32_t cp = utf8::internal::mask16(*it++);
1135 if (utf8::internal::is_lead_surrogate(cp))
1136 return (cp << 10) + *it++ + utf8::internal::SURROGATE_OFFSET;
1137 return cp;
1138 }
1139
1140 template <typename octet_iterator>
1141 utfchar32_t prior(octet_iterator& it)
1142 {
1143 while (utf8::internal::is_trail(*(--it))) ;
1144 octet_iterator temp = it;
1145 return utf8::unchecked::next(temp);
1146 }
1147
1148 template <typename octet_iterator, typename distance_type>
1149 void advance(octet_iterator& it, distance_type n)
1150 {
1151 const distance_type zero(0);
1152 if (n < zero) {
1153 // backward
1154 for (distance_type i = n; i < zero; ++i)
1155 utf8::unchecked::prior(it);
1156 } else {
1157 // forward
1158 for (distance_type i = zero; i < n; ++i)
1159 utf8::unchecked::next(it);
1160 }
1161 }
1162
1163 template <typename octet_iterator>
1164 typename std::iterator_traits<octet_iterator>::difference_type
1165 distance(octet_iterator first, octet_iterator last)
1166 {
1167 typename std::iterator_traits<octet_iterator>::difference_type dist;
1168 for (dist = 0; first < last; ++dist)
1169 utf8::unchecked::next(first);
1170 return dist;
1171 }
1172
1173 template <typename u16bit_iterator, typename octet_iterator>
1174 octet_iterator utf16to8(u16bit_iterator start, u16bit_iterator end, octet_iterator result)
1175 {
1176 while (start != end) {
1177 utfchar32_t cp = utf8::internal::mask16(*start++);
1178 // Take care of surrogate pairs first
1179 if (utf8::internal::is_lead_surrogate(cp)) {
1180 if (start == end)
1181 return result;
1182 utfchar32_t trail_surrogate = utf8::internal::mask16(*start++);
1183 cp = (cp << 10) + trail_surrogate + internal::SURROGATE_OFFSET;
1184 }
1185 result = utf8::unchecked::append(cp, result);
1186 }
1187 return result;
1188 }
1189
1190 template <typename u16bit_iterator, typename octet_iterator>
1191 u16bit_iterator utf8to16(octet_iterator start, octet_iterator end, u16bit_iterator result)
1192 {
1193 while (start < end) {
1194 utfchar32_t cp = utf8::unchecked::next(start);
1195 if (cp > 0xffff) { //make a surrogate pair
1196 *result++ = static_cast<utfchar16_t>((cp >> 10) + internal::LEAD_OFFSET);
1197 *result++ = static_cast<utfchar16_t>((cp & 0x3ff) + internal::TRAIL_SURROGATE_MIN);
1198 }
1199 else
1200 *result++ = static_cast<utfchar16_t>(cp);
1201 }
1202 return result;
1203 }
1204
1205 template <typename octet_iterator, typename u32bit_iterator>
1206 octet_iterator utf32to8(u32bit_iterator start, u32bit_iterator end, octet_iterator result)
1207 {
1208 while (start != end)
1209 result = utf8::unchecked::append(*(start++), result);
1210
1211 return result;
1212 }
1213
1214 template <typename octet_iterator, typename u32bit_iterator>
1215 u32bit_iterator utf8to32(octet_iterator start, octet_iterator end, u32bit_iterator result)
1216 {
1217 while (start < end)
1218 (*result++) = utf8::unchecked::next(start);
1219
1220 return result;
1221 }
1222
1223 // The iterator class
1224 template <typename octet_iterator>
1225 class iterator {
1226 octet_iterator it;
1227 public:
1228 typedef utfchar32_t value_type;
1229 typedef utfchar32_t* pointer;
1230 typedef utfchar32_t& reference;
1231 typedef std::ptrdiff_t difference_type;
1232 typedef std::bidirectional_iterator_tag iterator_category;
1233 iterator () {}
1234 explicit iterator (const octet_iterator& octet_it): it(octet_it) {}
1235 // the default "big three" are OK
1236 octet_iterator base () const { return it; }
1237 utfchar32_t operator * () const
1238 {
1239 octet_iterator temp = it;
1240 return utf8::unchecked::next(temp);
1241 }
1242 bool operator == (const iterator& rhs) const
1243 {
1244 return (it == rhs.it);
1245 }
1246 bool operator != (const iterator& rhs) const
1247 {
1248 return !(operator == (rhs));
1249 }
1250 iterator& operator ++ ()
1251 {
1252 ::std::advance(it, utf8::internal::sequence_length(it));
1253 return *this;
1254 }
1255 iterator operator ++ (int)
1256 {
1257 iterator temp = *this;
1258 ::std::advance(it, utf8::internal::sequence_length(it));
1259 return temp;
1260 }
1261 iterator& operator -- ()
1262 {
1263 utf8::unchecked::prior(it);
1264 return *this;
1265 }
1266 iterator operator -- (int)
1267 {
1268 iterator temp = *this;
1269 utf8::unchecked::prior(it);
1270 return temp;
1271 }
1272 }; // class iterator
1273
1274 } // namespace utf8::unchecked
1275} // namespace utf8
1276
1277#endif // header guard
diff --git a/src/yue.cpp b/src/yue.cpp
index fc57767..b93f75e 100644
--- a/src/yue.cpp
+++ b/src/yue.cpp
@@ -1,4 +1,4 @@
1/* Copyright (c) 2017-2025 Li Jin <dragon-fly@qq.com> 1/* Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com>
2 2
3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 4
@@ -30,6 +30,38 @@ using namespace std::chrono_literals;
30#include "ghc/fs_std.hpp" 30#include "ghc/fs_std.hpp"
31#include "linenoise.hpp" 31#include "linenoise.hpp"
32 32
33#if __has_include(<pthread.h>)
34#include <pthread.h>
35template<class R>
36std::future<R> async(const std::function<R()>& f) {
37 using Fn = std::packaged_task<R()>;
38 auto task = new Fn(f);
39 std::future<R> fut = task->get_future();
40
41 pthread_attr_t attr;
42 pthread_attr_init(&attr);
43 pthread_attr_setstacksize(&attr, 8 * 1024 * 1024);
44
45 pthread_t th;
46 pthread_create(&th, &attr,
47 [](void* p)->void* {
48 std::unique_ptr<Fn> fn(static_cast<Fn*>(p));
49 (*fn)();
50 return nullptr;
51 },
52 task);
53 pthread_attr_destroy(&attr);
54 pthread_detach(th);
55 return fut;
56}
57#else
58template<class R>
59std::future<R> async(const std::function<R()>& f) {
60 // fallback: ignore stack size
61 return std::async(std::launch::async, f);
62}
63#endif
64
33#if not(defined YUE_NO_MACRO && defined YUE_COMPILER_ONLY) 65#if not(defined YUE_NO_MACRO && defined YUE_COMPILER_ONLY)
34#define _DEFER(code, line) std::shared_ptr<void> _defer_##line(nullptr, [&](auto) { \ 66#define _DEFER(code, line) std::shared_ptr<void> _defer_##line(nullptr, [&](auto) { \
35 code; \ 67 code; \
@@ -40,18 +72,23 @@ extern "C" {
40#include "lua.h" 72#include "lua.h"
41#include "lualib.h" 73#include "lualib.h"
42int luaopen_yue(lua_State* L); 74int luaopen_yue(lua_State* L);
75int luaopen_colibc_json(lua_State* L);
43} // extern "C" 76} // extern "C"
44 77
45static void openlibs(void* state) { 78static void openlibs(void* state) {
46 lua_State* L = static_cast<lua_State*>(state); 79 lua_State* L = static_cast<lua_State*>(state);
80 int top = lua_gettop(L);
81 DEFER(lua_settop(L, top));
47 luaL_openlibs(L); 82 luaL_openlibs(L);
48#if LUA_VERSION_NUM > 501 83#if LUA_VERSION_NUM > 501
49 luaL_requiref(L, "yue", luaopen_yue, 0); 84 luaL_requiref(L, "yue", luaopen_yue, 0);
85 luaL_requiref(L, "cojson", luaopen_colibc_json, 0);
50#else 86#else
51 lua_pushcfunction(L, luaopen_yue); 87 lua_pushcfunction(L, luaopen_yue);
52 lua_call(L, 0, 0); 88 lua_call(L, 0, 0);
89 lua_pushcfunction(L, luaopen_colibc_json);
90 lua_call(L, 0, 0);
53#endif 91#endif
54 lua_pop(L, 1);
55} 92}
56 93
57void pushYue(lua_State* L, std::string_view name) { 94void pushYue(lua_State* L, std::string_view name) {
@@ -699,7 +736,7 @@ int main(int narg, const char** args) {
699 } 736 }
700 std::list<std::future<std::string>> results; 737 std::list<std::future<std::string>> results;
701 for (const auto& file : files) { 738 for (const auto& file : files) {
702 auto task = std::async(std::launch::async, [=]() { 739 auto task = async<std::string>([=]() {
703#ifndef YUE_COMPILER_ONLY 740#ifndef YUE_COMPILER_ONLY
704 return compileFile(fs::absolute(file.first), config, fullWorkPath, fullTargetPath, minify, rewrite); 741 return compileFile(fs::absolute(file.first), config, fullWorkPath, fullTargetPath, minify, rewrite);
705#else 742#else
@@ -737,7 +774,7 @@ int main(int narg, const char** args) {
737#endif // YUE_NO_WATCHER 774#endif // YUE_NO_WATCHER
738 std::list<std::future<std::tuple<int, std::string, std::string>>> results; 775 std::list<std::future<std::tuple<int, std::string, std::string>>> results;
739 for (const auto& file : files) { 776 for (const auto& file : files) {
740 auto task = std::async(std::launch::async, [=]() { 777 auto task = async<std::tuple<int, std::string, std::string>>([=]() {
741 std::ifstream input(file.first, std::ios::in); 778 std::ifstream input(file.first, std::ios::in);
742 if (input) { 779 if (input) {
743 std::string s( 780 std::string s(
diff --git a/src/yue_wasm.cpp b/src/yue_wasm.cpp
index 20f3794..abb291e 100644
--- a/src/yue_wasm.cpp
+++ b/src/yue_wasm.cpp
@@ -1,4 +1,4 @@
1/* Copyright (c) 2017-2025 Li Jin <dragon-fly@qq.com> 1/* Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com>
2 2
3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 4
diff --git a/src/yuescript/parser.cpp b/src/yuescript/parser.cpp
index f0ddd06..5910348 100644
--- a/src/yuescript/parser.cpp
+++ b/src/yuescript/parser.cpp
@@ -18,8 +18,33 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
18 18
19#include "yuescript/parser.hpp" 19#include "yuescript/parser.hpp"
20 20
21#ifndef YUE_UTF8_IMPL
22namespace CodeCvt {
23 std::u32string utf8to32(const std::string& str);
24 std::string utf32to8(const std::u32string& str);
25} // namespace CodeCvt
26#else
27#include "utf8cpp.h"
28namespace CodeCvt {
29 std::u32string utf8to32(const std::string& str) {
30 return utf8::utf8to32(str);
31 }
32 std::string utf32to8(const std::u32string& str) {
33 return utf8::utf32to8(str);
34 }
35} // namespace CodeCvt
36#endif // YUE_UTF8_IMPL
37
21namespace parserlib { 38namespace parserlib {
22 39
40input utf8_decode(const std::string& str) {
41 return CodeCvt::utf8to32(str);
42}
43
44std::string utf8_encode(const input& str) {
45 return CodeCvt::utf32to8(str);
46}
47
23// internal private class that manages access to the public classes' internals. 48// internal private class that manages access to the public classes' internals.
24class _private { 49class _private {
25public: 50public:
@@ -241,7 +266,7 @@ class _string : public _expr {
241public: 266public:
242 // constructor from ansi string. 267 // constructor from ansi string.
243 _string(const char* s) 268 _string(const char* s)
244 : m_string(Converter{}.from_bytes(s)) { 269 : m_string(utf8_decode(s)) {
245 } 270 }
246 271
247 // parse with whitespace 272 // parse with whitespace
@@ -279,7 +304,7 @@ class _set : public _expr {
279public: 304public:
280 // constructor from ansi string. 305 // constructor from ansi string.
281 _set(const char* s) { 306 _set(const char* s) {
282 auto str = Converter{}.from_bytes(s); 307 auto str = utf8_decode(s);
283 for (auto ch : str) { 308 for (auto ch : str) {
284 _add(ch); 309 _add(ch);
285 } 310 }
diff --git a/src/yuescript/parser.hpp b/src/yuescript/parser.hpp
index c544785..4742539 100644
--- a/src/yuescript/parser.hpp
+++ b/src/yuescript/parser.hpp
@@ -17,7 +17,6 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17#pragma warning(disable : 4521) 17#pragma warning(disable : 4521)
18#endif 18#endif
19 19
20#include <codecvt>
21#include <functional> 20#include <functional>
22#include <list> 21#include <list>
23#include <locale> 22#include <locale>
@@ -27,9 +26,11 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
27namespace parserlib { 26namespace parserlib {
28 27
29/// type of the parser's input. 28/// type of the parser's input.
30typedef std::basic_string<wchar_t> input; 29typedef std::basic_string<char32_t> input;
31typedef input::iterator input_it; 30typedef input::iterator input_it;
32typedef std::wstring_convert<std::codecvt_utf8_utf16<input::value_type>> Converter; 31
32input utf8_decode(const std::string& str);
33std::string utf8_encode(const input& str);
33 34
34class _private; 35class _private;
35class _expr; 36class _expr;
diff --git a/src/yuescript/yue_ast.cpp b/src/yuescript/yue_ast.cpp
index fdb1d20..14d8db8 100644
--- a/src/yuescript/yue_ast.cpp
+++ b/src/yuescript/yue_ast.cpp
@@ -1,4 +1,4 @@
1/* Copyright (c) 2017-2025 Li Jin <dragon-fly@qq.com> 1/* Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com>
2 2
3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 4
@@ -30,7 +30,7 @@ std::string YueFormat::ind() const {
30} 30}
31 31
32std::string YueFormat::convert(const ast_node* node) { 32std::string YueFormat::convert(const ast_node* node) {
33 return converter.to_bytes(std::wstring(node->m_begin.m_it, node->m_end.m_it)); 33 return utf8_encode({node->m_begin.m_it, node->m_end.m_it});
34} 34}
35 35
36std::string YueFormat::toString(ast_node* node) { 36std::string YueFormat::toString(ast_node* node) {
@@ -82,6 +82,13 @@ std::string SelfClass_t::to_string(void*) const {
82std::string VarArg_t::to_string(void*) const { 82std::string VarArg_t::to_string(void*) const {
83 return "..."s; 83 return "..."s;
84} 84}
85std::string VarArgDef_t::to_string(void* ud) const {
86 if (name) {
87 return "..."s + name->to_string(ud);
88 } else {
89 return "..."s;
90 }
91}
85std::string Seperator_t::to_string(void*) const { 92std::string Seperator_t::to_string(void*) const {
86 return {}; 93 return {};
87} 94}
@@ -167,7 +174,7 @@ std::string ExistentialOp_t::to_string(void*) const {
167std::string TableAppendingOp_t::to_string(void*) const { 174std::string TableAppendingOp_t::to_string(void*) const {
168 return "[]"s; 175 return "[]"s;
169} 176}
170std::string PlainItem_t::to_string(void *) const { 177std::string PlainItem_t::to_string(void*) const {
171 return {}; 178 return {};
172} 179}
173std::string GlobalOp_t::to_string(void*) const { 180std::string GlobalOp_t::to_string(void*) const {
@@ -203,14 +210,18 @@ std::string YueLineComment_t::to_string(void* ud) const {
203 auto info = reinterpret_cast<YueFormat*>(ud); 210 auto info = reinterpret_cast<YueFormat*>(ud);
204 return "--"s + info->convert(this); 211 return "--"s + info->convert(this);
205} 212}
206std::string MultilineCommentInner_t::to_string(void* ud) const { 213std::string YueMultilineComment_t::to_string(void* ud) const {
207 auto info = reinterpret_cast<YueFormat*>(ud); 214 auto info = reinterpret_cast<YueFormat*>(ud);
208 return info->convert(this); 215 return "--[["s + info->convert(this) + "]]"s;
209} 216}
210std::string Variable_t::to_string(void* ud) const { 217std::string YueComment_t::to_string(void* ud) const {
211 return name->to_string(ud); 218 if (comment) {
219 return comment->to_string(ud);
220 } else {
221 return {};
222 }
212} 223}
213std::string LabelName_t::to_string(void* ud) const { 224std::string Variable_t::to_string(void* ud) const {
214 return name->to_string(ud); 225 return name->to_string(ud);
215} 226}
216std::string LuaKeyword_t::to_string(void* ud) const { 227std::string LuaKeyword_t::to_string(void* ud) const {
@@ -304,6 +315,17 @@ std::string ImportAs_t::to_string(void* ud) const {
304 } 315 }
305 return join(temp, " "s); 316 return join(temp, " "s);
306} 317}
318std::string ImportGlobal_t::to_string(void* ud) const {
319 str_list temp;
320 for (auto seg : segs.objects()) {
321 temp.emplace_back(seg->to_string(ud));
322 }
323 auto item = join(temp, "."s);
324 if (target) {
325 return item + " as "s + target->to_string(ud);
326 }
327 return item;
328}
307std::string Import_t::to_string(void* ud) const { 329std::string Import_t::to_string(void* ud) const {
308 if (ast_is<FromImport_t>(content)) { 330 if (ast_is<FromImport_t>(content)) {
309 return content->to_string(ud); 331 return content->to_string(ud);
@@ -372,8 +394,8 @@ std::string With_t::to_string(void* ud) const {
372 str_list temp{ 394 str_list temp{
373 eop ? "with?"s : "with"s, 395 eop ? "with?"s : "with"s,
374 valueList->to_string(ud)}; 396 valueList->to_string(ud)};
375 if (assigns) { 397 if (assign) {
376 temp.push_back(assigns->to_string(ud)); 398 temp.push_back(':' + assign->to_string(ud));
377 } 399 }
378 if (body.is<Statement_t>()) { 400 if (body.is<Statement_t>()) {
379 return join(temp, " "sv) + " do "s + body->to_string(ud); 401 return join(temp, " "sv) + " do "s + body->to_string(ud);
@@ -419,6 +441,9 @@ std::string SwitchCase_t::to_string(void* ud) const {
419std::string Switch_t::to_string(void* ud) const { 441std::string Switch_t::to_string(void* ud) const {
420 auto info = reinterpret_cast<YueFormat*>(ud); 442 auto info = reinterpret_cast<YueFormat*>(ud);
421 str_list temp{"switch "s + target->to_string(ud)}; 443 str_list temp{"switch "s + target->to_string(ud)};
444 if (assignment) {
445 temp.back().append(assignment->to_string(ud));
446 }
422 info->pushScope(); 447 info->pushScope();
423 for (auto branch : branches.objects()) { 448 for (auto branch : branches.objects()) {
424 temp.emplace_back(info->ind() + branch->to_string(ud)); 449 temp.emplace_back(info->ind() + branch->to_string(ud));
@@ -462,41 +487,75 @@ std::string If_t::to_string(void* ud) const {
462 temp.back() += " then"s; 487 temp.back() += " then"s;
463 } 488 }
464 ++it; 489 ++it;
465 bool condition = true; 490 enum class NType {
491 Cond,
492 Stat,
493 Block
494 };
495 NType lastType = NType::Cond;
466 for (; it != nodes.objects().end(); ++it) { 496 for (; it != nodes.objects().end(); ++it) {
467 auto node = *it; 497 auto node = *it;
468 switch (node->get_id()) { 498 switch (node->get_id()) {
469 case id<IfCond_t>(): 499 case id<IfCond_t>():
470 temp.emplace_back(info->ind() + "elseif "s + node->to_string(ud)); 500 temp.emplace_back(info->ind() + "elseif "s + node->to_string(ud));
471 condition = true; 501 lastType = NType::Cond;
472 break; 502 break;
473 case id<Statement_t>(): { 503 case id<Statement_t>(): {
474 if (condition) { 504 switch (lastType) {
475 temp.back() += " then "s + node->to_string(ud); 505 case NType::Cond:
476 } else { 506 temp.back() += " then "s + node->to_string(ud);
477 temp.emplace_back(info->ind() + "else "s + node->to_string(ud)); 507 break;
508 case NType::Stat:
509 if (temp.back().back() == '\n') {
510 temp.emplace_back(info->ind() + "else "s + node->to_string(ud));
511 } else {
512 temp.back() += " else "s + node->to_string(ud);
513 }
514 break;
515 case NType::Block:
516 temp.emplace_back(info->ind() + "else "s + node->to_string(ud));
517 break;
478 } 518 }
479 condition = false; 519 lastType = NType::Stat;
480 break; 520 break;
481 } 521 }
482 case id<Block_t>(): { 522 case id<Block_t>(): {
483 if (condition) { 523 switch (lastType) {
484 info->pushScope(); 524 case NType::Cond: {
485 temp.emplace_back(node->to_string(ud)); 525 info->pushScope();
486 if (temp.back().empty()) { 526 temp.emplace_back(node->to_string(ud));
487 temp.back() = info->ind() + "--"s; 527 if (temp.back().empty()) {
528 temp.back() = info->ind() + "--"s;
529 }
530 info->popScope();
531 break;
532 }
533 case NType::Stat: {
534 if (temp.back().back() == '\n') {
535 temp.emplace_back(info->ind() + "else"s);
536 } else {
537 temp.back() += " else"s;
538 }
539 info->pushScope();
540 temp.emplace_back(node->to_string(ud));
541 if (temp.back().empty()) {
542 temp.back() = info->ind() + "--"s;
543 }
544 info->popScope();
545 break;
488 } 546 }
489 info->popScope(); 547 case NType::Block: {
490 } else { 548 temp.emplace_back(info->ind() + "else"s);
491 temp.emplace_back(info->ind() + "else"s); 549 info->pushScope();
492 info->pushScope(); 550 temp.emplace_back(node->to_string(ud));
493 temp.emplace_back(node->to_string(ud)); 551 if (temp.back().empty()) {
494 if (temp.back().empty()) { 552 temp.back() = info->ind() + "--"s;
495 temp.back() = info->ind() + "--"s; 553 }
554 info->popScope();
555 break;
496 } 556 }
497 info->popScope();
498 } 557 }
499 condition = false; 558 lastType = NType::Block;
500 break; 559 break;
501 } 560 }
502 } 561 }
@@ -524,10 +583,10 @@ std::string While_t::to_string(void* ud) const {
524} 583}
525std::string Repeat_t::to_string(void* ud) const { 584std::string Repeat_t::to_string(void* ud) const {
526 auto info = reinterpret_cast<YueFormat*>(ud); 585 auto info = reinterpret_cast<YueFormat*>(ud);
527 str_list temp; 586 if (body.is<Statement_t>()) {
528 if (body->content.is<Statement_t>()) { 587 return "repeat "s + body->to_string(ud) + " until "s + condition->to_string(ud);
529 temp.emplace_back("repeat "s + body->to_string(ud));
530 } else { 588 } else {
589 str_list temp;
531 temp.emplace_back("repeat"s); 590 temp.emplace_back("repeat"s);
532 info->pushScope(); 591 info->pushScope();
533 temp.emplace_back(body->to_string(ud)); 592 temp.emplace_back(body->to_string(ud));
@@ -535,14 +594,14 @@ std::string Repeat_t::to_string(void* ud) const {
535 temp.back() = info->ind() + "--"s; 594 temp.back() = info->ind() + "--"s;
536 } 595 }
537 info->popScope(); 596 info->popScope();
597 temp.emplace_back(info->ind() + "until "s + condition->to_string(ud));
598 return join(temp, "\n"sv);
538 } 599 }
539 temp.emplace_back(info->ind() + "until "s + condition->to_string(ud));
540 return join(temp, "\n"sv);
541} 600}
542std::string ForStepValue_t::to_string(void* ud) const { 601std::string ForStepValue_t::to_string(void* ud) const {
543 return value->to_string(ud); 602 return value->to_string(ud);
544} 603}
545std::string For_t::to_string(void* ud) const { 604std::string ForNum_t::to_string(void* ud) const {
546 auto info = reinterpret_cast<YueFormat*>(ud); 605 auto info = reinterpret_cast<YueFormat*>(ud);
547 auto line = "for "s + varName->to_string(ud) + " = "s + startValue->to_string(ud) + ", "s + stopValue->to_string(ud); 606 auto line = "for "s + varName->to_string(ud) + " = "s + startValue->to_string(ud) + ", "s + stopValue->to_string(ud);
548 if (stepValue) { 607 if (stepValue) {
@@ -581,6 +640,9 @@ std::string ForEach_t::to_string(void* ud) const {
581 return line + '\n' + block; 640 return line + '\n' + block;
582 } 641 }
583} 642}
643std::string For_t::to_string(void* ud) const {
644 return forLoop->to_string(ud);
645}
584std::string Do_t::to_string(void* ud) const { 646std::string Do_t::to_string(void* ud) const {
585 auto info = reinterpret_cast<YueFormat*>(ud); 647 auto info = reinterpret_cast<YueFormat*>(ud);
586 if (body->content.is<Statement_t>()) { 648 if (body->content.is<Statement_t>()) {
@@ -609,10 +671,13 @@ std::string CatchBlock_t::to_string(void* ud) const {
609std::string Try_t::to_string(void* ud) const { 671std::string Try_t::to_string(void* ud) const {
610 auto info = reinterpret_cast<YueFormat*>(ud); 672 auto info = reinterpret_cast<YueFormat*>(ud);
611 str_list temp; 673 str_list temp;
674 temp.emplace_back("try"s);
675 if (eop) {
676 temp.back() += eop->to_string(ud);
677 }
612 if (func.is<Exp_t>()) { 678 if (func.is<Exp_t>()) {
613 temp.emplace_back("try "s + func->to_string(ud)); 679 temp.back() += (" "s + func->to_string(ud));
614 } else { 680 } else {
615 temp.emplace_back("try"s);
616 info->pushScope(); 681 info->pushScope();
617 temp.emplace_back(func->to_string(ud)); 682 temp.emplace_back(func->to_string(ud));
618 if (temp.back().empty()) { 683 if (temp.back().empty()) {
@@ -729,7 +794,7 @@ static bool isInBlockExp(ast_node* node, bool last = false) {
729 return false; 794 return false;
730} 795}
731std::string Comprehension_t::to_string(void* ud) const { 796std::string Comprehension_t::to_string(void* ud) const {
732 if (items.size() != 2 || !ast_is<CompInner_t>(items.back())) { 797 if (items.size() != 2 || !ast_is<CompFor_t>(items.back())) {
733 if (items.size() == 1) { 798 if (items.size() == 1) {
734 str_list temp; 799 str_list temp;
735 for (const auto& item : items.objects()) { 800 for (const auto& item : items.objects()) {
@@ -796,14 +861,14 @@ std::string StarExp_t::to_string(void* ud) const {
796std::string CompForEach_t::to_string(void* ud) const { 861std::string CompForEach_t::to_string(void* ud) const {
797 return "for "s + nameList->to_string(ud) + " in "s + loopValue->to_string(ud); 862 return "for "s + nameList->to_string(ud) + " in "s + loopValue->to_string(ud);
798} 863}
799std::string CompFor_t::to_string(void* ud) const { 864std::string CompForNum_t::to_string(void* ud) const {
800 auto line = "for "s + varName->to_string(ud) + " = "s + startValue->to_string(ud) + ", "s + stopValue->to_string(ud); 865 auto line = "for "s + varName->to_string(ud) + " = "s + startValue->to_string(ud) + ", "s + stopValue->to_string(ud);
801 if (stepValue) { 866 if (stepValue) {
802 line += stepValue->to_string(ud); 867 line += stepValue->to_string(ud);
803 } 868 }
804 return line; 869 return line;
805} 870}
806std::string CompInner_t::to_string(void* ud) const { 871std::string CompFor_t::to_string(void* ud) const {
807 str_list temp; 872 str_list temp;
808 for (auto item : items.objects()) { 873 for (auto item : items.objects()) {
809 if (ast_is<Exp_t>(item)) { 874 if (ast_is<Exp_t>(item)) {
@@ -864,6 +929,12 @@ std::string Exp_t::to_string(void* ud) const {
864 } 929 }
865 return join(temp, " "sv); 930 return join(temp, " "sv);
866} 931}
932std::string ReversedIndex_t::to_string(void* ud) const {
933 if (modifier) {
934 return "[# - "s + modifier->to_string(ud) + ']';
935 }
936 return "[#]"s;
937}
867std::string Callable_t::to_string(void* ud) const { 938std::string Callable_t::to_string(void* ud) const {
868 return item->to_string(ud); 939 return item->to_string(ud);
869} 940}
@@ -950,6 +1021,51 @@ std::string DoubleString_t::to_string(void* ud) const {
950 } 1021 }
951 return '"' + join(temp) + '"'; 1022 return '"' + join(temp) + '"';
952} 1023}
1024std::string YAMLIndent_t::to_string(void* ud) const {
1025 auto info = reinterpret_cast<YueFormat*>(ud);
1026 return info->convert(this);
1027}
1028std::string YAMLLineInner_t::to_string(void* ud) const {
1029 auto info = reinterpret_cast<YueFormat*>(ud);
1030 return info->convert(this);
1031}
1032std::string YAMLLineContent_t::to_string(void* ud) const {
1033 if (content.is<Exp_t>()) {
1034 return "#{"s + content->to_string(ud) + '}';
1035 }
1036 return content->to_string(ud);
1037}
1038std::string YAMLLine_t::to_string(void* ud) const {
1039 str_list temp;
1040 for (auto seg : segments.objects()) {
1041 temp.emplace_back(seg->to_string(ud));
1042 }
1043 return join(temp);
1044}
1045std::string YAMLMultiline_t::to_string(void* ud) const {
1046 auto info = reinterpret_cast<YueFormat*>(ud);
1047 int currentIndent = info->indent;
1048 str_list temp;
1049 int lastIndent = -1;
1050 for (auto line_ : lines.objects()) {
1051 auto line = static_cast<YAMLLine_t*>(line_);
1052 auto indent = line->indent->to_string(ud);
1053 int ind = 0;
1054 for (auto c : indent) {
1055 if (c == ' ') ind++;
1056 if (c == '\t') ind += 4;
1057 }
1058 if (lastIndent < ind) {
1059 info->pushScope();
1060 } else if (lastIndent > ind) {
1061 info->popScope();
1062 }
1063 lastIndent = ind;
1064 temp.emplace_back(indent + line->to_string(ud));
1065 }
1066 info->indent = currentIndent;
1067 return "|\n" + join(temp, "\n"sv) + '\n';
1068}
953std::string String_t::to_string(void* ud) const { 1069std::string String_t::to_string(void* ud) const {
954 return str->to_string(ud); 1070 return str->to_string(ud);
955} 1071}
@@ -1248,6 +1364,9 @@ std::string FnArgDef_t::to_string(void* ud) const {
1248 if (op) { 1364 if (op) {
1249 line += op->to_string(ud); 1365 line += op->to_string(ud);
1250 } 1366 }
1367 if (label) {
1368 line += '`' + label->to_string(ud);
1369 }
1251 if (defaultValue) { 1370 if (defaultValue) {
1252 line += " = "s + defaultValue->to_string(ud); 1371 line += " = "s + defaultValue->to_string(ud);
1253 } 1372 }
@@ -1270,6 +1389,9 @@ std::string FnArgDefList_t::to_string(void* ud) const {
1270 } 1389 }
1271 if (varArg) { 1390 if (varArg) {
1272 temp.emplace_back(info->ind() + varArg->to_string(ud)); 1391 temp.emplace_back(info->ind() + varArg->to_string(ud));
1392 if (label) {
1393 temp.back().append('`' + label->to_string(ud));
1394 }
1273 } 1395 }
1274 return join(temp, "\n"sv); 1396 return join(temp, "\n"sv);
1275 } else { 1397 } else {
@@ -1278,6 +1400,9 @@ std::string FnArgDefList_t::to_string(void* ud) const {
1278 } 1400 }
1279 if (varArg) { 1401 if (varArg) {
1280 temp.emplace_back(varArg->to_string(ud)); 1402 temp.emplace_back(varArg->to_string(ud));
1403 if (label) {
1404 temp.back().append('`' + label->to_string(ud));
1405 }
1281 } 1406 }
1282 return join(temp, ", "sv); 1407 return join(temp, ", "sv);
1283 } 1408 }
@@ -1488,37 +1613,17 @@ std::string StatementAppendix_t::to_string(void* ud) const {
1488 return item->to_string(ud); 1613 return item->to_string(ud);
1489} 1614}
1490std::string Statement_t::to_string(void* ud) const { 1615std::string Statement_t::to_string(void* ud) const {
1491 std::string line; 1616 if (appendix) {
1492 if (!comments.empty()) { 1617 return content->to_string(ud) + ' ' + appendix->to_string(ud);
1493 auto info = reinterpret_cast<YueFormat*>(ud);
1494 str_list temp;
1495 for (ast_node* comment : comments.objects()) {
1496 if (comment == comments.front()) {
1497 temp.push_back(comment->to_string(ud));
1498 } else {
1499 temp.push_back(info->ind() + comment->to_string(ud));
1500 }
1501 }
1502 if (appendix) {
1503 temp.push_back(info->ind() + content->to_string(ud) + ' ' + appendix->to_string(ud));
1504 return join(temp, "\n"sv);
1505 } else {
1506 temp.push_back(info->ind() + content->to_string(ud));
1507 return join(temp, "\n"sv);
1508 }
1509 } else { 1618 } else {
1510 if (appendix) { 1619 return content->to_string(ud);
1511 return content->to_string(ud) + ' ' + appendix->to_string(ud);
1512 } else {
1513 return content->to_string(ud);
1514 }
1515 } 1620 }
1516} 1621}
1517std::string StatementSep_t::to_string(void*) const { 1622std::string StatementSep_t::to_string(void*) const {
1518 return {}; 1623 return {};
1519} 1624}
1520std::string YueMultilineComment_t::to_string(void* ud) const { 1625std::string EmptyLine_t::to_string(void*) const {
1521 return "--[["s + inner->to_string(ud) + "]]"s; 1626 return {};
1522} 1627}
1523std::string ChainAssign_t::to_string(void* ud) const { 1628std::string ChainAssign_t::to_string(void* ud) const {
1524 str_list temp; 1629 str_list temp;
@@ -1533,14 +1638,22 @@ std::string Body_t::to_string(void* ud) const {
1533std::string Block_t::to_string(void* ud) const { 1638std::string Block_t::to_string(void* ud) const {
1534 auto info = reinterpret_cast<YueFormat*>(ud); 1639 auto info = reinterpret_cast<YueFormat*>(ud);
1535 str_list temp; 1640 str_list temp;
1536 for (auto stmt_ : statements.objects()) { 1641 for (auto stmt_ : statementOrComments.objects()) {
1537 auto stmt = static_cast<Statement_t*>(stmt_); 1642 if (auto stmt = ast_cast<Statement_t>(stmt_)) {
1538 if (stmt->content.is<PipeBody_t>()) { 1643 if (stmt->content.is<PipeBody_t>()) {
1539 info->pushScope(); 1644 info->pushScope();
1540 temp.emplace_back(stmt->to_string(ud)); 1645 temp.emplace_back(stmt->to_string(ud));
1541 info->popScope(); 1646 info->popScope();
1542 } else { 1647 } else {
1543 temp.emplace_back(info->ind() + stmt->to_string(ud)); 1648 temp.emplace_back(info->ind() + stmt->to_string(ud));
1649 }
1650 } else if (info->reserveComment) {
1651 if (auto comment = ast_cast<YueComment_t>(stmt_)) {
1652 temp.emplace_back(info->ind() + comment->to_string(ud));
1653 } else {
1654 auto empty = ast_to<EmptyLine_t>(stmt_);
1655 temp.emplace_back(empty->to_string(ud));
1656 }
1544 } 1657 }
1545 } 1658 }
1546 return join(temp, "\n"sv); 1659 return join(temp, "\n"sv);
@@ -1559,3 +1672,4 @@ std::string File_t::to_string(void* ud) const {
1559} // namespace yue 1672} // namespace yue
1560 1673
1561} // namespace parserlib 1674} // namespace parserlib
1675
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h
index 0c15fac..ba4186d 100644
--- a/src/yuescript/yue_ast.h
+++ b/src/yuescript/yue_ast.h
@@ -1,4 +1,4 @@
1/* Copyright (c) 2017-2025 Li Jin <dragon-fly@qq.com> 1/* Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com>
2 2
3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 4
@@ -68,7 +68,7 @@ class Statement_t;
68class Body_t; 68class Body_t;
69class AssignableNameList_t; 69class AssignableNameList_t;
70class StarExp_t; 70class StarExp_t;
71class CompInner_t; 71class CompFor_t;
72class AssignableChain_t; 72class AssignableChain_t;
73class UnaryExp_t; 73class UnaryExp_t;
74class Parens_t; 74class Parens_t;
@@ -103,11 +103,6 @@ AST_NODE(Variable)
103 AST_MEMBER(Variable, &name) 103 AST_MEMBER(Variable, &name)
104AST_END(Variable) 104AST_END(Variable)
105 105
106AST_NODE(LabelName)
107 ast_ptr<true, UnicodeName_t> name;
108 AST_MEMBER(LabelName, &name)
109AST_END(LabelName)
110
111AST_NODE(LuaKeyword) 106AST_NODE(LuaKeyword)
112 ast_ptr<true, Name_t> name; 107 ast_ptr<true, Name_t> name;
113 AST_MEMBER(LuaKeyword, &name) 108 AST_MEMBER(LuaKeyword, &name)
@@ -139,6 +134,11 @@ AST_NODE(KeyName)
139 AST_MEMBER(KeyName, &name) 134 AST_MEMBER(KeyName, &name)
140AST_END(KeyName) 135AST_END(KeyName)
141 136
137AST_NODE(VarArgDef)
138 ast_ptr<false, Variable_t> name;
139 AST_MEMBER(VarArgDef, &name)
140AST_END(VarArgDef)
141
142AST_LEAF(VarArg) 142AST_LEAF(VarArg)
143AST_END(VarArg) 143AST_END(VarArg)
144 144
@@ -233,18 +233,25 @@ 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
241AST_NODE(Label) 248AST_NODE(Label)
242 ast_ptr<true, LabelName_t> label; 249 ast_ptr<true, UnicodeName_t> label;
243 AST_MEMBER(Label, &label) 250 AST_MEMBER(Label, &label)
244AST_END(Label) 251AST_END(Label)
245 252
246AST_NODE(Goto) 253AST_NODE(Goto)
247 ast_ptr<true, LabelName_t> label; 254 ast_ptr<true, UnicodeName_t> label;
248 AST_MEMBER(Goto, &label) 255 AST_MEMBER(Goto, &label)
249AST_END(Goto) 256AST_END(Goto)
250 257
@@ -287,9 +294,9 @@ AST_END(Return)
287AST_NODE(With) 294AST_NODE(With)
288 ast_ptr<false, ExistentialOp_t> eop; 295 ast_ptr<false, ExistentialOp_t> eop;
289 ast_ptr<true, ExpList_t> valueList; 296 ast_ptr<true, ExpList_t> valueList;
290 ast_ptr<false, Assign_t> assigns; 297 ast_ptr<false, Assign_t> assign;
291 ast_sel<true, Block_t, Statement_t> body; 298 ast_sel<true, Block_t, Statement_t> body;
292 AST_MEMBER(With, &eop, &valueList, &assigns, &body) 299 AST_MEMBER(With, &eop, &valueList, &assign, &body)
293AST_END(With) 300AST_END(With)
294 301
295AST_NODE(SwitchList) 302AST_NODE(SwitchList)
@@ -304,20 +311,21 @@ AST_NODE(SwitchCase)
304 AST_MEMBER(SwitchCase, &condition, &body) 311 AST_MEMBER(SwitchCase, &condition, &body)
305AST_END(SwitchCase) 312AST_END(SwitchCase)
306 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
307AST_NODE(Switch) 320AST_NODE(Switch)
308 ast_ptr<true, Exp_t> target; 321 ast_ptr<true, Exp_t> target;
322 ast_ptr<false, Assignment_t> assignment;
309 ast_ptr<true, Seperator_t> sep; 323 ast_ptr<true, Seperator_t> sep;
310 ast_list<true, SwitchCase_t> branches; 324 ast_list<true, SwitchCase_t> branches;
311 ast_sel<false, Block_t, Statement_t> lastBranch; 325 ast_sel<false, Block_t, Statement_t> lastBranch;
312 AST_MEMBER(Switch, &target, &sep, &branches, &lastBranch) 326 AST_MEMBER(Switch, &target, &assignment, &sep, &branches, &lastBranch)
313AST_END(Switch) 327AST_END(Switch)
314 328
315AST_NODE(Assignment)
316 ast_ptr<false, ExpList_t> expList;
317 ast_ptr<true, Assign_t> assign;
318 AST_MEMBER(Assignment, &expList, &assign)
319AST_END(Assignment)
320
321AST_NODE(IfCond) 329AST_NODE(IfCond)
322 ast_ptr<true, Exp_t> condition; 330 ast_ptr<true, Exp_t> condition;
323 ast_ptr<false, Assignment_t> assignment; 331 ast_ptr<false, Assignment_t> assignment;
@@ -345,7 +353,7 @@ AST_NODE(While)
345AST_END(While) 353AST_END(While)
346 354
347AST_NODE(Repeat) 355AST_NODE(Repeat)
348 ast_ptr<true, Body_t> body; 356 ast_sel<true, Block_t, Statement_t> body;
349 ast_ptr<true, Exp_t> condition; 357 ast_ptr<true, Exp_t> condition;
350 AST_MEMBER(Repeat, &body, &condition) 358 AST_MEMBER(Repeat, &body, &condition)
351AST_END(Repeat) 359AST_END(Repeat)
@@ -355,14 +363,14 @@ AST_NODE(ForStepValue)
355 AST_MEMBER(ForStepValue, &value) 363 AST_MEMBER(ForStepValue, &value)
356AST_END(ForStepValue) 364AST_END(ForStepValue)
357 365
358AST_NODE(For) 366AST_NODE(ForNum)
359 ast_ptr<true, Variable_t> varName; 367 ast_ptr<true, Variable_t> varName;
360 ast_ptr<true, Exp_t> startValue; 368 ast_ptr<true, Exp_t> startValue;
361 ast_ptr<true, Exp_t> stopValue; 369 ast_ptr<true, Exp_t> stopValue;
362 ast_ptr<false, ForStepValue_t> stepValue; 370 ast_ptr<false, ForStepValue_t> stepValue;
363 ast_sel<true, Block_t, Statement_t> body; 371 ast_sel<true, Block_t, Statement_t> body;
364 AST_MEMBER(For, &varName, &startValue, &stopValue, &stepValue, &body) 372 AST_MEMBER(ForNum, &varName, &startValue, &stopValue, &stepValue, &body)
365AST_END(For) 373AST_END(ForNum)
366 374
367AST_NODE(ForEach) 375AST_NODE(ForEach)
368 ast_ptr<true, AssignableNameList_t> nameList; 376 ast_ptr<true, AssignableNameList_t> nameList;
@@ -371,6 +379,11 @@ AST_NODE(ForEach)
371 AST_MEMBER(ForEach, &nameList, &loopValue, &body) 379 AST_MEMBER(ForEach, &nameList, &loopValue, &body)
372AST_END(ForEach) 380AST_END(ForEach)
373 381
382AST_NODE(For)
383 ast_sel<true, ForEach_t, ForNum_t> forLoop;
384 AST_MEMBER(For, &forLoop)
385AST_END(For)
386
374AST_NODE(Do) 387AST_NODE(Do)
375 ast_ptr<true, Body_t> body; 388 ast_ptr<true, Body_t> body;
376 AST_MEMBER(Do, &body) 389 AST_MEMBER(Do, &body)
@@ -383,14 +396,15 @@ AST_NODE(CatchBlock)
383AST_END(CatchBlock) 396AST_END(CatchBlock)
384 397
385AST_NODE(Try) 398AST_NODE(Try)
399 ast_ptr<false, ExistentialOp_t> eop;
386 ast_sel<true, Block_t, Exp_t> func; 400 ast_sel<true, Block_t, Exp_t> func;
387 ast_ptr<false, CatchBlock_t> catchBlock; 401 ast_ptr<false, CatchBlock_t> catchBlock;
388 AST_MEMBER(Try, &func, &catchBlock) 402 AST_MEMBER(Try, &eop, &func, &catchBlock)
389AST_END(Try) 403AST_END(Try)
390 404
391AST_NODE(Comprehension) 405AST_NODE(Comprehension)
392 ast_ptr<true, Seperator_t> sep; 406 ast_ptr<true, Seperator_t> sep;
393 ast_sel_list<false, NormalDef_t, SpreadListExp_t, CompInner_t, 407 ast_sel_list<false, NormalDef_t, SpreadListExp_t, CompFor_t,
394 /*non-syntax-rule*/ Statement_t> items; 408 /*non-syntax-rule*/ Statement_t> items;
395 AST_MEMBER(Comprehension, &sep, &items) 409 AST_MEMBER(Comprehension, &sep, &items)
396AST_END(Comprehension) 410AST_END(Comprehension)
@@ -403,7 +417,7 @@ AST_END(CompValue)
403AST_NODE(TblComprehension) 417AST_NODE(TblComprehension)
404 ast_ptr<true, Exp_t> key; 418 ast_ptr<true, Exp_t> key;
405 ast_ptr<false, CompValue_t> value; 419 ast_ptr<false, CompValue_t> value;
406 ast_ptr<true, CompInner_t> forLoop; 420 ast_ptr<true, CompFor_t> forLoop;
407 AST_MEMBER(TblComprehension, &key, &value, &forLoop) 421 AST_MEMBER(TblComprehension, &key, &value, &forLoop)
408AST_END(TblComprehension) 422AST_END(TblComprehension)
409 423
@@ -418,23 +432,23 @@ AST_NODE(CompForEach)
418 AST_MEMBER(CompForEach, &nameList, &loopValue) 432 AST_MEMBER(CompForEach, &nameList, &loopValue)
419AST_END(CompForEach) 433AST_END(CompForEach)
420 434
421AST_NODE(CompFor) 435AST_NODE(CompForNum)
422 ast_ptr<true, Variable_t> varName; 436 ast_ptr<true, Variable_t> varName;
423 ast_ptr<true, Exp_t> startValue; 437 ast_ptr<true, Exp_t> startValue;
424 ast_ptr<true, Exp_t> stopValue; 438 ast_ptr<true, Exp_t> stopValue;
425 ast_ptr<false, ForStepValue_t> stepValue; 439 ast_ptr<false, ForStepValue_t> stepValue;
426 AST_MEMBER(CompFor, &varName, &startValue, &stopValue, &stepValue) 440 AST_MEMBER(CompForNum, &varName, &startValue, &stopValue, &stepValue)
427AST_END(CompFor) 441AST_END(CompForNum)
428 442
429AST_NODE(CompInner) 443AST_NODE(CompFor)
430 ast_ptr<true, Seperator_t> sep; 444 ast_ptr<true, Seperator_t> sep;
431 ast_sel_list<true, CompFor_t, CompForEach_t, Exp_t> items; 445 ast_sel_list<true, CompForNum_t, CompForEach_t, Exp_t> items;
432 AST_MEMBER(CompInner, &sep, &items) 446 AST_MEMBER(CompFor, &sep, &items)
433AST_END(CompInner) 447AST_END(CompFor)
434 448
435AST_NODE(Assign) 449AST_NODE(Assign)
436 ast_ptr<true, Seperator_t> sep; 450 ast_ptr<true, Seperator_t> sep;
437 ast_sel_list<true, With_t, If_t, Switch_t, TableBlock_t, Exp_t> values; 451 ast_sel_list<true, With_t, If_t, Switch_t, TableBlock_t, Exp_t, SpreadListExp_t> values;
438 AST_MEMBER(Assign, &sep, &values) 452 AST_MEMBER(Assign, &sep, &values)
439AST_END(Assign) 453AST_END(Assign)
440 454
@@ -549,8 +563,8 @@ AST_NODE(SimpleValue)
549 ast_sel<true, 563 ast_sel<true,
550 TableLit_t, ConstValue_t, 564 TableLit_t, ConstValue_t,
551 If_t, Switch_t, With_t, ClassDecl_t, 565 If_t, Switch_t, With_t, ClassDecl_t,
552 ForEach_t, For_t, While_t, Do_t, Try_t, 566 For_t, While_t, Repeat_t,
553 UnaryValue_t, 567 Do_t, Try_t, UnaryValue_t,
554 TblComprehension_t, Comprehension_t, 568 TblComprehension_t, Comprehension_t,
555 FunLit_t, Num_t, VarArg_t> value; 569 FunLit_t, Num_t, VarArg_t> value;
556 AST_MEMBER(SimpleValue, &value) 570 AST_MEMBER(SimpleValue, &value)
@@ -589,8 +603,31 @@ AST_NODE(DoubleString)
589 AST_MEMBER(DoubleString, &sep, &segments) 603 AST_MEMBER(DoubleString, &sep, &segments)
590AST_END(DoubleString) 604AST_END(DoubleString)
591 605
606AST_LEAF(YAMLIndent)
607AST_END(YAMLIndent)
608
609AST_LEAF(YAMLLineInner)
610AST_END(YAMLLineInner)
611
612AST_NODE(YAMLLineContent)
613 ast_sel<true, YAMLLineInner_t, Exp_t> content;
614 AST_MEMBER(YAMLLineContent, &content)
615AST_END(YAMLLineContent)
616
617AST_NODE(YAMLLine)
618 ast_ptr<true, YAMLIndent_t> indent;
619 ast_list<true, YAMLLineContent_t> segments;
620 AST_MEMBER(YAMLLine, &indent, &segments)
621AST_END(YAMLLine)
622
623AST_NODE(YAMLMultiline)
624 ast_ptr<true, Seperator_t> sep;
625 ast_list<true, YAMLLine_t> lines;
626 AST_MEMBER(YAMLMultiline, &sep, &lines)
627AST_END(YAMLMultiline)
628
592AST_NODE(String) 629AST_NODE(String)
593 ast_sel<true, DoubleString_t, SingleString_t, LuaString_t> str; 630 ast_sel<true, DoubleString_t, SingleString_t, LuaString_t, YAMLMultiline_t> str;
594 AST_MEMBER(String, &str) 631 AST_MEMBER(String, &str)
595AST_END(String) 632AST_END(String)
596 633
@@ -641,9 +678,14 @@ AST_END(TableAppendingOp)
641AST_LEAF(PlainItem) 678AST_LEAF(PlainItem)
642AST_END(PlainItem) 679AST_END(PlainItem)
643 680
681AST_NODE(ReversedIndex)
682 ast_ptr<false, Exp_t> modifier;
683 AST_MEMBER(ReversedIndex, &modifier)
684AST_END(ReversedIndex)
685
644AST_NODE(ChainValue) 686AST_NODE(ChainValue)
645 ast_ptr<true, Seperator_t> sep; 687 ast_ptr<true, Seperator_t> sep;
646 ast_sel_list<true, Callable_t, Invoke_t, DotChainItem_t, ColonChainItem_t, Slice_t, Exp_t, String_t, InvokeArgs_t, ExistentialOp_t, TableAppendingOp_t, 688 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,
647 /*non-syntax-rule*/ PlainItem_t> items; 689 /*non-syntax-rule*/ PlainItem_t> items;
648 AST_MEMBER(ChainValue, &sep, &items) 690 AST_MEMBER(ChainValue, &sep, &items)
649AST_END(ChainValue) 691AST_END(ChainValue)
@@ -743,17 +785,19 @@ AST_NODE(Export)
743AST_END(Export) 785AST_END(Export)
744 786
745AST_NODE(FnArgDef) 787AST_NODE(FnArgDef)
746 ast_sel<true, Variable_t, SelfItem_t> name; 788 ast_sel<true, Variable_t, SelfItem_t, SimpleTable_t, TableLit_t> name;
747 ast_ptr<false, ExistentialOp_t> op; 789 ast_ptr<false, ExistentialOp_t> op;
790 ast_ptr<false, Name_t> label;
748 ast_ptr<false, Exp_t> defaultValue; 791 ast_ptr<false, Exp_t> defaultValue;
749 AST_MEMBER(FnArgDef, &name, &op, &defaultValue) 792 AST_MEMBER(FnArgDef, &name, &op, &label, &defaultValue)
750AST_END(FnArgDef) 793AST_END(FnArgDef)
751 794
752AST_NODE(FnArgDefList) 795AST_NODE(FnArgDefList)
753 ast_ptr<true, Seperator_t> sep; 796 ast_ptr<true, Seperator_t> sep;
754 ast_list<false, FnArgDef_t> definitions; 797 ast_list<false, FnArgDef_t> definitions;
755 ast_ptr<false, VarArg_t> varArg; 798 ast_ptr<false, VarArgDef_t> varArg;
756 AST_MEMBER(FnArgDefList, &sep, &definitions, &varArg) 799 ast_ptr<false, Name_t> label;
800 AST_MEMBER(FnArgDefList, &sep, &definitions, &varArg, &label)
757AST_END(FnArgDefList) 801AST_END(FnArgDefList)
758 802
759AST_NODE(OuterVarShadow) 803AST_NODE(OuterVarShadow)
@@ -809,7 +853,7 @@ AST_NODE(Macro)
809AST_END(Macro) 853AST_END(Macro)
810 854
811AST_NODE(NameOrDestructure) 855AST_NODE(NameOrDestructure)
812 ast_sel<true, Variable_t, TableLit_t, Comprehension_t> item; 856 ast_sel<true, Variable_t, SimpleTable_t, TableLit_t, Comprehension_t> item;
813 AST_MEMBER(NameOrDestructure, &item) 857 AST_MEMBER(NameOrDestructure, &item)
814AST_END(NameOrDestructure) 858AST_END(NameOrDestructure)
815 859
@@ -885,7 +929,7 @@ AST_NODE(PipeBody)
885AST_END(PipeBody) 929AST_END(PipeBody)
886 930
887AST_NODE(StatementAppendix) 931AST_NODE(StatementAppendix)
888 ast_sel<true, IfLine_t, WhileLine_t, CompInner_t> item; 932 ast_sel<true, IfLine_t, WhileLine_t, CompFor_t> item;
889 AST_MEMBER(StatementAppendix, &item) 933 AST_MEMBER(StatementAppendix, &item)
890AST_END(StatementAppendix) 934AST_END(StatementAppendix)
891 935
@@ -895,14 +939,17 @@ AST_END(StatementSep)
895AST_LEAF(YueLineComment) 939AST_LEAF(YueLineComment)
896AST_END(YueLineComment) 940AST_END(YueLineComment)
897 941
898AST_LEAF(MultilineCommentInner) 942AST_LEAF(YueMultilineComment)
899AST_END(MultilineCommentInner)
900
901AST_NODE(YueMultilineComment)
902 ast_ptr<true, MultilineCommentInner_t> inner;
903 AST_MEMBER(YueMultilineComment, &inner)
904AST_END(YueMultilineComment) 943AST_END(YueMultilineComment)
905 944
945AST_NODE(YueComment)
946 ast_sel<true, YueLineComment_t, YueMultilineComment_t> comment;
947 AST_MEMBER(YueComment, &comment)
948AST_END(YueComment)
949
950AST_LEAF(EmptyLine)
951AST_END(EmptyLine)
952
906AST_NODE(ChainAssign) 953AST_NODE(ChainAssign)
907 ast_ptr<true, Seperator_t> sep; 954 ast_ptr<true, Seperator_t> sep;
908 ast_list<true, Exp_t> exprs; 955 ast_list<true, Exp_t> exprs;
@@ -911,16 +958,14 @@ AST_NODE(ChainAssign)
911AST_END(ChainAssign) 958AST_END(ChainAssign)
912 959
913AST_NODE(Statement) 960AST_NODE(Statement)
914 ast_ptr<true, Seperator_t> sep;
915 ast_sel_list<false, YueLineComment_t, YueMultilineComment_t> comments;
916 ast_sel<true, 961 ast_sel<true,
917 Import_t, While_t, Repeat_t, For_t, ForEach_t, 962 Import_t, While_t, Repeat_t, For_t,
918 Return_t, Local_t, Global_t, Export_t, Macro_t, MacroInPlace_t, 963 Return_t, Local_t, Global_t, Export_t, Macro_t, MacroInPlace_t,
919 BreakLoop_t, Label_t, Goto_t, ShortTabAppending_t, 964 BreakLoop_t, Label_t, Goto_t, ShortTabAppending_t,
920 Backcall_t, LocalAttrib_t, PipeBody_t, ExpListAssign_t, ChainAssign_t 965 Backcall_t, LocalAttrib_t, PipeBody_t, ExpListAssign_t, ChainAssign_t
921 > content; 966 > content;
922 ast_ptr<false, StatementAppendix_t> appendix; 967 ast_ptr<false, StatementAppendix_t> appendix;
923 AST_MEMBER(Statement, &sep, &comments, &content, &appendix) 968 AST_MEMBER(Statement, &content, &appendix)
924AST_END(Statement) 969AST_END(Statement)
925 970
926AST_NODE(Body) 971AST_NODE(Body)
@@ -930,8 +975,8 @@ AST_END(Body)
930 975
931AST_NODE(Block) 976AST_NODE(Block)
932 ast_ptr<true, Seperator_t> sep; 977 ast_ptr<true, Seperator_t> sep;
933 ast_list<false, Statement_t> statements; 978 ast_sel_list<false, Statement_t, YueComment_t, EmptyLine_t> statementOrComments;
934 AST_MEMBER(Block, &sep, &statements) 979 AST_MEMBER(Block, &sep, &statementOrComments)
935AST_END(Block) 980AST_END(Block)
936 981
937AST_NODE(BlockEnd) 982AST_NODE(BlockEnd)
@@ -950,9 +995,9 @@ struct YueFormat {
950 int indent = 0; 995 int indent = 0;
951 bool spaceOverTab = false; 996 bool spaceOverTab = false;
952 int tabSpaces = 4; 997 int tabSpaces = 4;
998 bool reserveComment = true;
953 std::string toString(ast_node* node); 999 std::string toString(ast_node* node);
954 1000
955 Converter converter{};
956 void pushScope(); 1001 void pushScope();
957 void popScope(); 1002 void popScope();
958 std::string convert(const ast_node* node); 1003 std::string convert(const ast_node* node);
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp
index 7abc929..cffa7a8 100644
--- a/src/yuescript/yue_compiler.cpp
+++ b/src/yuescript/yue_compiler.cpp
@@ -1,4 +1,4 @@
1/* Copyright (c) 2017-2025 Li Jin <dragon-fly@qq.com> 1/* Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com>
2 2
3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 4
@@ -78,7 +78,7 @@ static std::unordered_set<std::string> Metamethods = {
78 "close"s // Lua 5.4 78 "close"s // Lua 5.4
79}; 79};
80 80
81const std::string_view version = "0.28.3"sv; 81const std::string_view version = "0.30.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;
@@ -182,8 +182,9 @@ public:
182 try { 182 try {
183 auto block = _info.node.to<File_t>()->block.get(); 183 auto block = _info.node.to<File_t>()->block.get();
184 if (_info.exportMacro) { 184 if (_info.exportMacro) {
185 for (auto stmt_ : block->statements.objects()) { 185 for (auto stmt_ : block->statementOrComments.objects()) {
186 auto stmt = static_cast<Statement_t*>(stmt_); 186 auto stmt = ast_cast<Statement_t>(stmt_);
187 if (!stmt) continue;
187 switch (stmt->content->get_id()) { 188 switch (stmt->content->get_id()) {
188 case id<MacroInPlace_t>(): 189 case id<MacroInPlace_t>():
189 case id<Macro_t>(): 190 case id<Macro_t>():
@@ -258,8 +259,8 @@ public:
258 if (config.lintGlobalVariable) { 259 if (config.lintGlobalVariable) {
259 globals = std::make_unique<GlobalVars>(); 260 globals = std::make_unique<GlobalVars>();
260 for (const auto& var : _globals) { 261 for (const auto& var : _globals) {
261 auto [name, line, col, accessType] = var.second; 262 auto [name, line, col, accessType, defined] = var.second;
262 globals->push_back({name, line + _config.lineOffset, col, accessType}); 263 globals->push_back({name, line + _config.lineOffset, col, accessType, defined});
263 } 264 }
264 std::sort(globals->begin(), globals->end(), [](const GlobalVar& varA, const GlobalVar& varB) { 265 std::sort(globals->begin(), globals->end(), [](const GlobalVar& varA, const GlobalVar& varB) {
265 if (varA.line < varB.line) { 266 if (varA.line < varB.line) {
@@ -396,7 +397,7 @@ private:
396 }; 397 };
397 std::stack<ContinueVar> _continueVars; 398 std::stack<ContinueVar> _continueVars;
398 std::list<std::unique_ptr<input>> _codeCache; 399 std::list<std::unique_ptr<input>> _codeCache;
399 std::unordered_map<std::string, std::tuple<std::string, int, int, AccessType>> _globals; 400 std::unordered_map<std::string, std::tuple<std::string, int, int, AccessType, bool>> _globals;
400 std::ostringstream _buf; 401 std::ostringstream _buf;
401 std::ostringstream _joinBuf; 402 std::ostringstream _joinBuf;
402 const std::string _newLine = "\n"; 403 const std::string _newLine = "\n";
@@ -875,6 +876,10 @@ private:
875 return false; 876 return false;
876 } 877 }
877 878
879 bool isListComp(Comprehension_t* comp) const {
880 return comp->items.size() == 2 && ast_is<CompFor_t>(comp->items.back());
881 }
882
878 void markVarLocalConst(const std::string& name) { 883 void markVarLocalConst(const std::string& name) {
879 auto& scope = _scopes.back(); 884 auto& scope = _scopes.back();
880 scope.vars->insert_or_assign(name, VarType::LocalConst); 885 scope.vars->insert_or_assign(name, VarType::LocalConst);
@@ -967,7 +972,7 @@ private:
967 } 972 }
968 } 973 }
969 974
970 const std::string nll(ast_node* node) const { 975 const std::string nl(ast_node* node) const {
971 if (_config.reserveLineNumber) { 976 if (_config.reserveLineNumber) {
972 return " -- "s + std::to_string(node->m_begin.m_line + _config.lineOffset) + _newLine; 977 return " -- "s + std::to_string(node->m_begin.m_line + _config.lineOffset) + _newLine;
973 } else { 978 } else {
@@ -975,14 +980,6 @@ private:
975 } 980 }
976 } 981 }
977 982
978 const std::string nlr(ast_node* node) const {
979 if (_config.reserveLineNumber) {
980 return " -- "s + std::to_string(node->m_end.m_line + _config.lineOffset) + _newLine;
981 } else {
982 return _newLine;
983 }
984 }
985
986 void incIndentOffset() { 983 void incIndentOffset() {
987 _indentOffset++; 984 _indentOffset++;
988 } 985 }
@@ -1169,14 +1166,22 @@ private:
1169 return nullptr; 1166 return nullptr;
1170 } 1167 }
1171 1168
1172 Statement_t* lastStatementFrom(const node_container& stmts) const { 1169 Statement_t* lastStatementFrom(const node_container& statementOrComments) const {
1173 if (!stmts.empty()) { 1170 if (!statementOrComments.empty()) {
1174 auto it = stmts.end(); 1171 for (auto it = statementOrComments.rbegin(); it != statementOrComments.rend(); ++it) {
1175 --it; 1172 if (auto stmt = ast_cast<Statement_t>(*it)) {
1176 while (!static_cast<Statement_t*>(*it)->content && it != stmts.begin()) { 1173 return stmt;
1177 --it; 1174 }
1175 }
1176 }
1177 return nullptr;
1178 }
1179
1180 Statement_t* firstStatementFrom(Block_t* block) const {
1181 for (auto stmt_ : block->statementOrComments.objects()) {
1182 if (auto stmt = ast_cast<Statement_t>(stmt_)) {
1183 return stmt;
1178 } 1184 }
1179 return static_cast<Statement_t*>(*it);
1180 } 1185 }
1181 return nullptr; 1186 return nullptr;
1182 } 1187 }
@@ -1185,16 +1190,26 @@ private:
1185 if (auto stmt = body->content.as<Statement_t>()) { 1190 if (auto stmt = body->content.as<Statement_t>()) {
1186 return stmt; 1191 return stmt;
1187 } else { 1192 } else {
1188 const auto& stmts = body->content.to<Block_t>()->statements.objects(); 1193 const auto& stmts = body->content.to<Block_t>()->statementOrComments.objects();
1189 return lastStatementFrom(stmts); 1194 return lastStatementFrom(stmts);
1190 } 1195 }
1191 } 1196 }
1192 1197
1193 Statement_t* lastStatementFrom(Block_t* block) const { 1198 Statement_t* lastStatementFrom(Block_t* block) const {
1194 const auto& stmts = block->statements.objects(); 1199 const auto& stmts = block->statementOrComments.objects();
1195 return lastStatementFrom(stmts); 1200 return lastStatementFrom(stmts);
1196 } 1201 }
1197 1202
1203 int countStatementFrom(Block_t* block) const {
1204 int count = 0;
1205 for (auto stmt_ : block->statementOrComments.objects()) {
1206 if (ast_is<Statement_t>(stmt_)) {
1207 count++;
1208 }
1209 }
1210 return count;
1211 }
1212
1198 Exp_t* lastExpFromAssign(ast_node* action) { 1213 Exp_t* lastExpFromAssign(ast_node* action) {
1199 switch (action->get_id()) { 1214 switch (action->get_id()) {
1200 case id<Update_t>(): { 1215 case id<Update_t>(): {
@@ -1258,7 +1273,7 @@ private:
1258 1273
1259 template <class T> 1274 template <class T>
1260 ast_ptr<false, T> toAst(std::string_view codes, ast_node* parent) { 1275 ast_ptr<false, T> toAst(std::string_view codes, ast_node* parent) {
1261 auto res = _parser.parse<T>(std::string(codes)); 1276 auto res = _parser.parse<T>(std::string(codes), false);
1262 if (res.error) { 1277 if (res.error) {
1263 throw CompileError(res.error.value().msg, parent); 1278 throw CompileError(res.error.value().msg, parent);
1264 } 1279 }
@@ -1281,6 +1296,8 @@ private:
1281 Common, 1296 Common,
1282 EndWithColon, 1297 EndWithColon,
1283 EndWithEOP, 1298 EndWithEOP,
1299 EndWithSlice,
1300 HasRIndex,
1284 HasEOP, 1301 HasEOP,
1285 HasKeyword, 1302 HasKeyword,
1286 HasUnicode, 1303 HasUnicode,
@@ -1299,6 +1316,9 @@ private:
1299 if (ast_is<ExistentialOp_t>(chainValue->items.back())) { 1316 if (ast_is<ExistentialOp_t>(chainValue->items.back())) {
1300 return ChainType::EndWithEOP; 1317 return ChainType::EndWithEOP;
1301 } 1318 }
1319 if (ast_is<Slice_t>(chainValue->items.back())) {
1320 return ChainType::EndWithSlice;
1321 }
1302 if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) { 1322 if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) {
1303 if (dot->name.is<Metatable_t>()) { 1323 if (dot->name.is<Metatable_t>()) {
1304 return ChainType::Metatable; 1324 return ChainType::Metatable;
@@ -1324,6 +1344,8 @@ private:
1324 } 1344 }
1325 } else if (ast_is<ExistentialOp_t>(item)) { 1345 } else if (ast_is<ExistentialOp_t>(item)) {
1326 return ChainType::HasEOP; 1346 return ChainType::HasEOP;
1347 } else if (ast_is<ReversedIndex_t>(item)) {
1348 return ChainType::HasRIndex;
1327 } 1349 }
1328 } 1350 }
1329 return type; 1351 return type;
@@ -1353,10 +1375,10 @@ private:
1353 std::ostringstream buf; 1375 std::ostringstream buf;
1354 for (auto it = uname->m_begin.m_it; it != uname->m_end.m_it; ++it) { 1376 for (auto it = uname->m_begin.m_it; it != uname->m_end.m_it; ++it) {
1355 auto ch = *it; 1377 auto ch = *it;
1356 if (ch > 255) { 1378 if (ch <= 0x7F && ((ch == '_') || ((ch | 0x20) >= 'a' && (ch | 0x20) <= 'z') || (ch >= '0' && ch <= '9'))) {
1357 buf << "_u"sv << std::hex << static_cast<int>(ch);
1358 } else {
1359 buf << static_cast<char>(ch); 1379 buf << static_cast<char>(ch);
1380 } else {
1381 buf << "_u"sv << std::hex << static_cast<uint32_t>(ch);
1360 } 1382 }
1361 } 1383 }
1362 return buf.str(); 1384 return buf.str();
@@ -1438,6 +1460,7 @@ private:
1438 case id<DotChainItem_t>(): 1460 case id<DotChainItem_t>():
1439 case id<Exp_t>(): 1461 case id<Exp_t>():
1440 case id<TableAppendingOp_t>(): 1462 case id<TableAppendingOp_t>():
1463 case id<ReversedIndex_t>():
1441 return true; 1464 return true;
1442 } 1465 }
1443 } 1466 }
@@ -1455,7 +1478,7 @@ private:
1455 if (simpleValue->value.is<TableLit_t>()) { 1478 if (simpleValue->value.is<TableLit_t>()) {
1456 return true; 1479 return true;
1457 } else if (auto comp = simpleValue->value.as<Comprehension_t>()) { 1480 } else if (auto comp = simpleValue->value.as<Comprehension_t>()) {
1458 if (comp->items.size() != 2 || !ast_is<CompInner_t>(comp->items.back())) { 1481 if (!isListComp(comp)) {
1459 return true; 1482 return true;
1460 } 1483 }
1461 } 1484 }
@@ -1596,7 +1619,7 @@ private:
1596 if (accessType == AccessType::Read && _funcLevel > 1) { 1619 if (accessType == AccessType::Read && _funcLevel > 1) {
1597 accessType = AccessType::Capture; 1620 accessType = AccessType::Capture;
1598 } 1621 }
1599 _globals[key] = {str, x->m_begin.m_line, x->m_begin.m_col, accessType}; 1622 _globals[key] = {str, x->m_begin.m_line, x->m_begin.m_col, accessType, isSolidDefined(str)};
1600 } 1623 }
1601 } 1624 }
1602 } 1625 }
@@ -1638,24 +1661,31 @@ private:
1638 return; 1661 return;
1639 } 1662 }
1640 1663
1641 void transformStatement(Statement_t* statement, str_list& out) { 1664 void transformComment(YueComment_t* comment, str_list& out) {
1642 auto x = statement; 1665 if (!_config.reserveComment) {
1643 if (_config.reserveComment && !x->comments.empty()) { 1666 return;
1644 for (ast_node* node : x->comments.objects()) { 1667 }
1645 switch (node->get_id()) { 1668 auto node = comment->comment.get();
1646 case id<YueLineComment_t>(): { 1669 if (!node) {
1647 auto comment = ast_cast<YueLineComment_t>(node); 1670 out.push_back("\n"s);
1648 out.push_back(indent() + "--"s + _parser.toString(comment) + '\n'); 1671 return;
1649 break; 1672 }
1650 } 1673 switch (node->get_id()) {
1651 case id<YueMultilineComment_t>(): { 1674 case id<YueLineComment_t>(): {
1652 auto comment = ast_cast<YueMultilineComment_t>(node); 1675 auto content = static_cast<YueLineComment_t*>(node);
1653 out.push_back(indent() + _parser.toString(comment) + '\n'); 1676 out.push_back(indent() + "--"s + _parser.toString(content) + '\n');
1654 break; 1677 break;
1655 } 1678 }
1656 } 1679 case id<YueMultilineComment_t>(): {
1680 auto content = static_cast<YueMultilineComment_t*>(node);
1681 out.push_back(indent() + "--[["s + _parser.toString(content) + "]]\n"s);
1682 break;
1657 } 1683 }
1658 } 1684 }
1685 }
1686
1687 void transformStatement(Statement_t* statement, str_list& out) {
1688 auto x = statement;
1659 if (statement->appendix) { 1689 if (statement->appendix) {
1660 if (auto assignment = assignmentFrom(statement)) { 1690 if (auto assignment = assignmentFrom(statement)) {
1661 auto preDefine = getPreDefineLine(assignment); 1691 auto preDefine = getPreDefineLine(assignment);
@@ -1719,7 +1749,7 @@ private:
1719 throw CompileError("while-loop line decorator is not supported here"sv, appendix->item.get()); 1749 throw CompileError("while-loop line decorator is not supported here"sv, appendix->item.get());
1720 break; 1750 break;
1721 } 1751 }
1722 case id<CompInner_t>(): { 1752 case id<CompFor_t>(): {
1723 throw CompileError("for-loop line decorator is not supported here"sv, appendix->item.get()); 1753 throw CompileError("for-loop line decorator is not supported here"sv, appendix->item.get());
1724 break; 1754 break;
1725 } 1755 }
@@ -1780,8 +1810,8 @@ private:
1780 statement->content.set(expListAssign); 1810 statement->content.set(expListAssign);
1781 break; 1811 break;
1782 } 1812 }
1783 case id<CompInner_t>(): { 1813 case id<CompFor_t>(): {
1784 auto compInner = appendix->item.to<CompInner_t>(); 1814 auto compInner = appendix->item.to<CompFor_t>();
1785 auto comp = x->new_ptr<Comprehension_t>(); 1815 auto comp = x->new_ptr<Comprehension_t>();
1786 auto stmt = x->new_ptr<Statement_t>(); 1816 auto stmt = x->new_ptr<Statement_t>();
1787 stmt->content.set(statement->content); 1817 stmt->content.set(statement->content);
@@ -1846,11 +1876,12 @@ private:
1846 case id<ForEach_t>(): transformForEach(static_cast<ForEach_t*>(value), out); break; 1876 case id<ForEach_t>(): transformForEach(static_cast<ForEach_t*>(value), out); break;
1847 case id<For_t>(): transformFor(static_cast<For_t*>(value), out); break; 1877 case id<For_t>(): transformFor(static_cast<For_t*>(value), out); break;
1848 case id<While_t>(): transformWhile(static_cast<While_t*>(value), out); break; 1878 case id<While_t>(): transformWhile(static_cast<While_t*>(value), out); break;
1879 case id<Repeat_t>(): transformRepeat(static_cast<Repeat_t*>(value), out); break;
1849 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Common); break; 1880 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Common); break;
1850 case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Common); break; 1881 case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Common); break;
1851 case id<Comprehension_t>(): { 1882 case id<Comprehension_t>(): {
1852 auto comp = static_cast<Comprehension_t*>(value); 1883 auto comp = static_cast<Comprehension_t*>(value);
1853 if (comp->items.size() == 2 && ast_is<CompInner_t>(comp->items.back())) { 1884 if (isListComp(comp)) {
1854 transformCompCommon(comp, out); 1885 transformCompCommon(comp, out);
1855 } else { 1886 } else {
1856 specialSingleValue = false; 1887 specialSingleValue = false;
@@ -1974,7 +2005,7 @@ private:
1974 return indent() + "local "s + join(defs, ", "sv); 2005 return indent() + "local "s + join(defs, ", "sv);
1975 } 2006 }
1976 2007
1977 std::string getDestrucureDefine(ExpListAssign_t* assignment) { 2008 std::string getDestructureDefine(ExpListAssign_t* assignment) {
1978 auto info = extractDestructureInfo(assignment, true, false); 2009 auto info = extractDestructureInfo(assignment, true, false);
1979 if (!info.destructures.empty()) { 2010 if (!info.destructures.empty()) {
1980 str_list defs; 2011 str_list defs;
@@ -2005,8 +2036,31 @@ private:
2005 return clearBuf(); 2036 return clearBuf();
2006 } 2037 }
2007 2038
2039 str_list getArgDestructureList(ExpListAssign_t* assignment) {
2040 str_list defs;
2041 auto info = extractDestructureInfo(assignment, true, false);
2042 if (!info.destructures.empty()) {
2043 for (const auto& des : info.destructures) {
2044 if (std::holds_alternative<Destructure>(des)) {
2045 const auto& destruct = std::get<Destructure>(des);
2046 for (const auto& item : destruct.items) {
2047 if (item.targetVar.empty()) {
2048 throw CompileError("can only destruct argument to variable"sv, item.target);
2049 } else {
2050 defs.push_back(item.targetVar);
2051 }
2052 }
2053 } else {
2054 const auto& assignment = std::get<AssignmentPtr>(des);
2055 YUEE("AST node mismatch", assignment.ptr);
2056 }
2057 }
2058 }
2059 return defs;
2060 }
2061
2008 std::string getPreDefine(ExpListAssign_t* assignment) { 2062 std::string getPreDefine(ExpListAssign_t* assignment) {
2009 auto preDefine = getDestrucureDefine(assignment); 2063 auto preDefine = getDestructureDefine(assignment);
2010 if (preDefine.empty()) { 2064 if (preDefine.empty()) {
2011 preDefine = toLocalDecl(transformAssignDefs(assignment->expList, DefOp::Mark)); 2065 preDefine = toLocalDecl(transformAssignDefs(assignment->expList, DefOp::Mark));
2012 } 2066 }
@@ -2015,7 +2069,7 @@ private:
2015 2069
2016 std::string getPreDefineLine(ExpListAssign_t* assignment) { 2070 std::string getPreDefineLine(ExpListAssign_t* assignment) {
2017 auto preDefine = getPreDefine(assignment); 2071 auto preDefine = getPreDefine(assignment);
2018 if (!preDefine.empty()) preDefine += nll(assignment); 2072 if (!preDefine.empty()) preDefine += nl(assignment);
2019 return preDefine; 2073 return preDefine;
2020 } 2074 }
2021 2075
@@ -2171,14 +2225,14 @@ private:
2171 temp.push_back(getPreDefineLine(assignment)); 2225 temp.push_back(getPreDefineLine(assignment));
2172 bool needScope = !currentScope().lastStatement; 2226 bool needScope = !currentScope().lastStatement;
2173 if (needScope) { 2227 if (needScope) {
2174 temp.push_back(indent() + "do"s + nll(assignment)); 2228 temp.push_back(indent() + "do"s + nl(assignment));
2175 pushScope(); 2229 pushScope();
2176 } 2230 }
2177 transformAssignment(preAssignment, temp); 2231 transformAssignment(preAssignment, temp);
2178 transformAssignment(assignment, temp); 2232 transformAssignment(assignment, temp);
2179 if (needScope) { 2233 if (needScope) {
2180 popScope(); 2234 popScope();
2181 temp.push_back(indent() + "end"s + nll(assignment)); 2235 temp.push_back(indent() + "end"s + nl(assignment));
2182 } 2236 }
2183 out.push_back(join(temp)); 2237 out.push_back(join(temp));
2184 return false; 2238 return false;
@@ -2223,7 +2277,8 @@ private:
2223 BREAK_IF(!value); 2277 BREAK_IF(!value);
2224 auto chainValue = value->item.as<ChainValue_t>(); 2278 auto chainValue = value->item.as<ChainValue_t>();
2225 BREAK_IF(!chainValue); 2279 BREAK_IF(!chainValue);
2226 if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) { 2280 auto last = chainValue->items.back();
2281 if (auto dot = ast_cast<DotChainItem_t>(last)) {
2227 BREAK_IF(!dot->name.is<Metatable_t>()); 2282 BREAK_IF(!dot->name.is<Metatable_t>());
2228 str_list temp; 2283 str_list temp;
2229 auto [beforeAssignment, afterAssignment] = splitAssignment(); 2284 auto [beforeAssignment, afterAssignment] = splitAssignment();
@@ -2247,14 +2302,14 @@ private:
2247 throw CompileError("right value missing"sv, values.front()); 2302 throw CompileError("right value missing"sv, values.front());
2248 } 2303 }
2249 transformAssignItem(*vit, args); 2304 transformAssignItem(*vit, args);
2250 _buf << indent() << globalVar("setmetatable"sv, x, AccessType::Read) << '(' << join(args, ", "sv) << ')' << nll(x); 2305 _buf << indent() << globalVar("setmetatable"sv, x, AccessType::Read) << '(' << join(args, ", "sv) << ')' << nl(x);
2251 temp.push_back(clearBuf()); 2306 temp.push_back(clearBuf());
2252 if (!afterAssignment->expList->exprs.empty()) { 2307 if (!afterAssignment->expList->exprs.empty()) {
2253 transformAssignment(afterAssignment, temp); 2308 transformAssignment(afterAssignment, temp);
2254 } 2309 }
2255 out.push_back(join(temp)); 2310 out.push_back(join(temp));
2256 return false; 2311 return false;
2257 } else if (ast_is<TableAppendingOp_t>(chainValue->items.back())) { 2312 } else if (ast_is<TableAppendingOp_t>(last)) {
2258 str_list temp; 2313 str_list temp;
2259 auto [beforeAssignment, afterAssignment] = splitAssignment(); 2314 auto [beforeAssignment, afterAssignment] = splitAssignment();
2260 if (!beforeAssignment->expList->exprs.empty()) { 2315 if (!beforeAssignment->expList->exprs.empty()) {
@@ -2276,7 +2331,7 @@ private:
2276 if (varName.empty() || !isLocal(varName)) { 2331 if (varName.empty() || !isLocal(varName)) {
2277 if (needScope) { 2332 if (needScope) {
2278 extraScoped = true; 2333 extraScoped = true;
2279 temp.push_back(indent() + "do"s + nll(x)); 2334 temp.push_back(indent() + "do"s + nl(x));
2280 pushScope(); 2335 pushScope();
2281 } 2336 }
2282 auto objVar = getUnusedName("_obj_"sv); 2337 auto objVar = getUnusedName("_obj_"sv);
@@ -2288,19 +2343,69 @@ private:
2288 transformAssignment(newAssignment, temp); 2343 transformAssignment(newAssignment, temp);
2289 varName = objVar; 2344 varName = objVar;
2290 } 2345 }
2291 auto newAssignment = x->new_ptr<ExpListAssign_t>(); 2346 if (auto spread = ast_cast<SpreadListExp_t>(*vit)) {
2292 newAssignment->expList.set(toAst<ExpList_t>(varName + "[#"s + varName + "+1]"s, x)); 2347 auto lenVar = getUnusedName("_len_"sv);
2293 auto assign = x->new_ptr<Assign_t>(); 2348 forceAddToScope(lenVar);
2294 if (vit == values.end()) { 2349 temp.push_back(indent() + "local "s + lenVar + " = #"s + varName + " + 1"s + nl(spread));
2295 throw CompileError("right value missing"sv, values.front()); 2350 auto elmVar = getUnusedName("_elm_"sv);
2351 _buf << varName << '[' << lenVar << "],"s << lenVar << "="s << elmVar << ',' << lenVar << "+1 for "s << elmVar << " in *nil"s;
2352 auto stmt = toAst<Statement_t>(clearBuf(), spread);
2353 auto comp = stmt->appendix->item.to<CompFor_t>();
2354 ast_to<CompForEach_t>(comp->items.front())->loopValue.to<StarExp_t>()->value.set(spread->exp);
2355 transformStatement(stmt, temp);
2356 } else {
2357 auto newAssignment = x->new_ptr<ExpListAssign_t>();
2358 newAssignment->expList.set(toAst<ExpList_t>(varName + "[#"s + varName + "+1]"s, x));
2359 auto assign = x->new_ptr<Assign_t>();
2360 if (vit == values.end()) {
2361 throw CompileError("right value missing"sv, values.front());
2362 }
2363 assign->values.push_back(*vit);
2364 newAssignment->action.set(assign);
2365 transformAssignment(newAssignment, temp);
2296 } 2366 }
2297 assign->values.push_back(*vit);
2298 newAssignment->action.set(assign);
2299 transformAssignment(newAssignment, temp);
2300 if (extraScoped) { 2367 if (extraScoped) {
2301 popScope(); 2368 popScope();
2302 temp.push_back(indent() + "end"s + nlr(x)); 2369 temp.push_back(indent() + "end"s + nl(x));
2370 }
2371 if (!afterAssignment->expList->exprs.empty()) {
2372 transformAssignment(afterAssignment, temp);
2373 }
2374 out.push_back(join(temp));
2375 return false;
2376 } else if (ast_is<ReversedIndex_t>(last)) {
2377 if (chainValue->items.size() == 1) {
2378 if (_withVars.empty()) {
2379 throw CompileError("short dot/colon syntax must be called within a with block"sv, x);
2380 } else {
2381 break;
2382 }
2383 }
2384 auto tmpChain = chainValue->new_ptr<ChainValue_t>();
2385 tmpChain->items.dup(chainValue->items);
2386 tmpChain->items.pop_back();
2387 auto tmpLeft = newExp(tmpChain, tmpChain);
2388 auto leftVar = singleVariableFrom(tmpLeft, AccessType::Read);
2389 if (!leftVar.empty() && isLocal(leftVar)) {
2390 break;
2391 }
2392 leftVar = getUnusedName("_obj_"sv);
2393 auto tmpAsmt = assignmentFrom(toAst<Exp_t>(leftVar, tmpLeft), tmpLeft, tmpLeft);
2394 str_list temp;
2395 transformAssignment(tmpAsmt, temp);
2396 auto [beforeAssignment, afterAssignment] = splitAssignment();
2397 if (!beforeAssignment->expList->exprs.empty()) {
2398 transformAssignment(beforeAssignment, temp);
2303 } 2399 }
2400 if (vit == values.end()) {
2401 throw CompileError("right value missing"sv, values.front());
2402 }
2403 auto newChain = chainValue->new_ptr<ChainValue_t>();
2404 newChain->items.push_back(toAst<Callable_t>(leftVar, newChain));
2405 newChain->items.push_back(chainValue->items.back());
2406 auto newLeft = newExp(newChain, newChain);
2407 auto newAsmt = assignmentFrom(newLeft, *vit, newLeft);
2408 transformAssignment(newAsmt, temp);
2304 if (!afterAssignment->expList->exprs.empty()) { 2409 if (!afterAssignment->expList->exprs.empty()) {
2305 transformAssignment(afterAssignment, temp); 2410 transformAssignment(afterAssignment, temp);
2306 } 2411 }
@@ -2329,6 +2434,17 @@ private:
2329 out.back().insert(0, preDefine); 2434 out.back().insert(0, preDefine);
2330 return false; 2435 return false;
2331 } 2436 }
2437 case id<Try_t>(): {
2438 auto tryNode = static_cast<Try_t*>(value);
2439 if (tryNode->eop) {
2440 auto assignList = assignment->expList.get();
2441 std::string preDefine = getPreDefineLine(assignment);
2442 transformTry(tryNode, out, ExpUsage::Assignment, assignList);
2443 out.back().insert(0, preDefine);
2444 return false;
2445 }
2446 break;
2447 }
2332 case id<Switch_t>(): { 2448 case id<Switch_t>(): {
2333 auto switchNode = static_cast<Switch_t*>(value); 2449 auto switchNode = static_cast<Switch_t*>(value);
2334 auto assignList = assignment->expList.get(); 2450 auto assignList = assignment->expList.get();
@@ -2356,7 +2472,7 @@ private:
2356 case id<Comprehension_t>(): { 2472 case id<Comprehension_t>(): {
2357 auto comp = static_cast<Comprehension_t*>(value); 2473 auto comp = static_cast<Comprehension_t*>(value);
2358 auto expList = assignment->expList.get(); 2474 auto expList = assignment->expList.get();
2359 if (comp->items.size() == 2 && ast_is<CompInner_t>(comp->items.back())) { 2475 if (isListComp(comp)) {
2360 std::string preDefine = getPreDefineLine(assignment); 2476 std::string preDefine = getPreDefineLine(assignment);
2361 transformComprehension(comp, out, ExpUsage::Assignment, expList); 2477 transformComprehension(comp, out, ExpUsage::Assignment, expList);
2362 out.back().insert(0, preDefine); 2478 out.back().insert(0, preDefine);
@@ -2400,6 +2516,13 @@ private:
2400 out.back().insert(0, preDefine); 2516 out.back().insert(0, preDefine);
2401 return false; 2517 return false;
2402 } 2518 }
2519 case id<Repeat_t>(): {
2520 auto expList = assignment->expList.get();
2521 std::string preDefine = getPreDefineLine(assignment);
2522 transformRepeatInPlace(static_cast<Repeat_t*>(value), out, expList);
2523 out.back().insert(0, preDefine);
2524 return false;
2525 }
2403 case id<TableLit_t>(): { 2526 case id<TableLit_t>(): {
2404 auto tableLit = static_cast<TableLit_t*>(value); 2527 auto tableLit = static_cast<TableLit_t*>(value);
2405 if (hasSpreadExp(tableLit->values.objects())) { 2528 if (hasSpreadExp(tableLit->values.objects())) {
@@ -2452,12 +2575,14 @@ private:
2452 switch (type) { 2575 switch (type) {
2453 case ChainType::HasEOP: 2576 case ChainType::HasEOP:
2454 case ChainType::EndWithColon: 2577 case ChainType::EndWithColon:
2578 case ChainType::EndWithSlice:
2455 case ChainType::MetaFieldInvocation: { 2579 case ChainType::MetaFieldInvocation: {
2456 std::string preDefine = getPreDefineLine(assignment); 2580 std::string preDefine = getPreDefineLine(assignment);
2457 transformChainValue(chainValue, out, ExpUsage::Assignment, expList, false, optionalDestruct); 2581 transformChainValue(chainValue, out, ExpUsage::Assignment, expList, false, optionalDestruct);
2458 out.back().insert(0, preDefine); 2582 out.back().insert(0, preDefine);
2459 return false; 2583 return false;
2460 } 2584 }
2585 case ChainType::HasRIndex:
2461 case ChainType::HasKeyword: 2586 case ChainType::HasKeyword:
2462 case ChainType::HasUnicode: 2587 case ChainType::HasUnicode:
2463 case ChainType::Macro: 2588 case ChainType::Macro:
@@ -2512,11 +2637,11 @@ private:
2512 checkConst(def, x); 2637 checkConst(def, x);
2513 addToScope(def); 2638 addToScope(def);
2514 } 2639 }
2515 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nll(x)); 2640 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nl(x));
2516 } 2641 }
2517 if (needScope) { 2642 if (needScope) {
2518 extraScope = true; 2643 extraScope = true;
2519 temp.push_back(indent() + "do"s + nll(x)); 2644 temp.push_back(indent() + "do"s + nl(x));
2520 pushScope(); 2645 pushScope();
2521 } 2646 }
2522 } 2647 }
@@ -2568,13 +2693,13 @@ private:
2568 continue; 2693 continue;
2569 } 2694 }
2570 if (extraScope) { 2695 if (extraScope) {
2571 temp.push_back(indent() + "do"s + nll(x)); 2696 temp.push_back(indent() + "do"s + nl(x));
2572 pushScope(); 2697 pushScope();
2573 } 2698 }
2574 if (!pair.targetVar.empty()) { 2699 if (!pair.targetVar.empty()) {
2575 checkConst(pair.targetVar, x); 2700 checkConst(pair.targetVar, x);
2576 if (addToScope(pair.targetVar)) { 2701 if (addToScope(pair.targetVar)) {
2577 _buf << indent() << "local "sv << pair.targetVar << nll(x); 2702 _buf << indent() << "local "sv << pair.targetVar << nl(x);
2578 temp.push_back(clearBuf()); 2703 temp.push_back(clearBuf());
2579 } 2704 }
2580 } 2705 }
@@ -2584,7 +2709,7 @@ private:
2584 objVar = destruct.valueVar; 2709 objVar = destruct.valueVar;
2585 } else { 2710 } else {
2586 if (needScope) { 2711 if (needScope) {
2587 temp.push_back(indent() + "do"s + nll(x)); 2712 temp.push_back(indent() + "do"s + nl(x));
2588 pushScope(); 2713 pushScope();
2589 } 2714 }
2590 objVar = getUnusedName("_obj_"sv); 2715 objVar = getUnusedName("_obj_"sv);
@@ -2600,7 +2725,7 @@ private:
2600 if (!isLocalValue) { 2725 if (!isLocalValue) {
2601 if (needScope) { 2726 if (needScope) {
2602 popScope(); 2727 popScope();
2603 _buf << indent() << "end"sv << nlr(x); 2728 _buf << indent() << "end"sv << nl(x);
2604 temp.push_back(clearBuf()); 2729 temp.push_back(clearBuf());
2605 } 2730 }
2606 } 2731 }
@@ -2638,9 +2763,9 @@ private:
2638 checkConst(def, x); 2763 checkConst(def, x);
2639 addToScope(def); 2764 addToScope(def);
2640 } 2765 }
2641 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nll(x)); 2766 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nl(x));
2642 } 2767 }
2643 temp.push_back(indent() + "do"s + nll(x)); 2768 temp.push_back(indent() + "do"s + nl(x));
2644 pushScope(); 2769 pushScope();
2645 } 2770 }
2646 } else { 2771 } else {
@@ -2649,11 +2774,11 @@ private:
2649 checkConst(def, x); 2774 checkConst(def, x);
2650 addToScope(def); 2775 addToScope(def);
2651 } 2776 }
2652 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nll(x)); 2777 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nl(x));
2653 } 2778 }
2654 if (needScope) { 2779 if (needScope) {
2655 extraScope = true; 2780 extraScope = true;
2656 temp.push_back(indent() + "do"s + nll(x)); 2781 temp.push_back(indent() + "do"s + nl(x));
2657 pushScope(); 2782 pushScope();
2658 } 2783 }
2659 auto valVar = getUnusedName("_obj_"sv); 2784 auto valVar = getUnusedName("_obj_"sv);
@@ -2668,7 +2793,7 @@ private:
2668 if (destruct.inlineAssignment) { 2793 if (destruct.inlineAssignment) {
2669 if (needScope && !extraScope) { 2794 if (needScope && !extraScope) {
2670 extraScope = true; 2795 extraScope = true;
2671 temp.push_back(indent() + "do"s + nll(x)); 2796 temp.push_back(indent() + "do"s + nl(x));
2672 pushScope(); 2797 pushScope();
2673 } 2798 }
2674 transformAssignment(destruct.inlineAssignment, temp); 2799 transformAssignment(destruct.inlineAssignment, temp);
@@ -2733,13 +2858,13 @@ private:
2733 } 2858 }
2734 if (extraScope) { 2859 if (extraScope) {
2735 popScope(); 2860 popScope();
2736 _buf << indent() << "end"sv << nlr(x); 2861 _buf << indent() << "end"sv << nl(x);
2737 temp.push_back(clearBuf()); 2862 temp.push_back(clearBuf());
2738 } 2863 }
2739 } 2864 }
2740 if (extraScope) { 2865 if (extraScope) {
2741 popScope(); 2866 popScope();
2742 temp.push_back(indent() + "end"s + nlr(x)); 2867 temp.push_back(indent() + "end"s + nl(x));
2743 } 2868 }
2744 out.push_back(join(temp)); 2869 out.push_back(join(temp));
2745 if (assignment->expList->followStmt) { 2870 if (assignment->expList->followStmt) {
@@ -2757,6 +2882,7 @@ private:
2757 case id<Switch_t>(): transformSwitch(static_cast<Switch_t*>(value), out, ExpUsage::Closure); break; 2882 case id<Switch_t>(): transformSwitch(static_cast<Switch_t*>(value), out, ExpUsage::Closure); break;
2758 case id<TableBlock_t>(): transformTableBlock(static_cast<TableBlock_t*>(value), out); break; 2883 case id<TableBlock_t>(): transformTableBlock(static_cast<TableBlock_t*>(value), out); break;
2759 case id<Exp_t>(): transformExp(static_cast<Exp_t*>(value), out, ExpUsage::Closure); break; 2884 case id<Exp_t>(): transformExp(static_cast<Exp_t*>(value), out, ExpUsage::Closure); break;
2885 case id<SpreadListExp_t>(): throw CompileError("can only be used for ranged table append assignments"sv, value); break;
2760 default: YUEE("AST node mismatch", value); break; 2886 default: YUEE("AST node mismatch", value); break;
2761 } 2887 }
2762 } 2888 }
@@ -2771,7 +2897,7 @@ private:
2771 if (auto tbA = item->get_by_path<TableLit_t>()) { 2897 if (auto tbA = item->get_by_path<TableLit_t>()) {
2772 tableItems = &tbA->values.objects(); 2898 tableItems = &tbA->values.objects();
2773 } else if (auto tbB = item->get_by_path<Comprehension_t>()) { 2899 } else if (auto tbB = item->get_by_path<Comprehension_t>()) {
2774 if (tbB->items.size() == 2 && ast_is<CompInner_t>(tbB->items.back())) { 2900 if (isListComp(tbB)) {
2775 throw CompileError("invalid destructure value"sv, tbB); 2901 throw CompileError("invalid destructure value"sv, tbB);
2776 } 2902 }
2777 tableItems = &tbB->items.objects(); 2903 tableItems = &tbB->items.objects();
@@ -2802,7 +2928,7 @@ private:
2802 } 2928 }
2803 case id<Comprehension_t>(): { 2929 case id<Comprehension_t>(): {
2804 auto table = static_cast<Comprehension_t*>(node); 2930 auto table = static_cast<Comprehension_t*>(node);
2805 if (table->items.size() == 2 && ast_is<CompInner_t>(table->items.back())) { 2931 if (isListComp(table)) {
2806 throw CompileError("invalid destructure value"sv, table); 2932 throw CompileError("invalid destructure value"sv, table);
2807 } 2933 }
2808 tableItems = &table->items.objects(); 2934 tableItems = &table->items.objects();
@@ -2813,17 +2939,19 @@ private:
2813 if (!tableItems) throw CompileError("invalid destructure value"sv, node); 2939 if (!tableItems) throw CompileError("invalid destructure value"sv, node);
2814 std::list<DestructItem> pairs; 2940 std::list<DestructItem> pairs;
2815 int index = 0; 2941 int index = 0;
2942 int count = 0;
2943 bool hasSpread = false;
2816 auto subMetaDestruct = node->new_ptr<TableLit_t>(); 2944 auto subMetaDestruct = node->new_ptr<TableLit_t>();
2817 for (auto pair : *tableItems) { 2945 for (auto pair : *tableItems) {
2818 switch (pair->get_id()) { 2946 switch (pair->get_id()) {
2819 case id<Exp_t>(): 2947 case id<Exp_t>():
2820 case id<NormalDef_t>(): { 2948 case id<NormalDef_t>(): {
2949 ++index;
2821 Exp_t* defVal = nullptr; 2950 Exp_t* defVal = nullptr;
2822 if (auto nd = ast_cast<NormalDef_t>(pair)) { 2951 if (auto nd = ast_cast<NormalDef_t>(pair)) {
2823 pair = nd->item.get(); 2952 pair = nd->item.get();
2824 defVal = nd->defVal.get(); 2953 defVal = nd->defVal.get();
2825 } 2954 }
2826 ++index;
2827 bool assignable = false; 2955 bool assignable = false;
2828 try { 2956 try {
2829 assignable = isAssignable(static_cast<Exp_t*>(pair)); 2957 assignable = isAssignable(static_cast<Exp_t*>(pair));
@@ -2834,13 +2962,19 @@ private:
2834 if (optional) break; 2962 if (optional) break;
2835 throw CompileError("can't destructure value"sv, pair); 2963 throw CompileError("can't destructure value"sv, pair);
2836 } 2964 }
2965 ast_ptr<true, ast_node> indexItem;
2966 if (hasSpread) {
2967 int rIndex = count - index;
2968 indexItem.set(toAst<ReversedIndex_t>('#' + (rIndex == 0 ? Empty : "-"s + std::to_string(rIndex)), pair));
2969 } else {
2970 indexItem.set(toAst<Exp_t>(std::to_string(index), pair));
2971 }
2837 if (optional && varDefOnly && !assignable) { 2972 if (optional && varDefOnly && !assignable) {
2838 if (defVal) { 2973 if (defVal) {
2839 throw CompileError("default value is not supported here"sv, defVal); 2974 throw CompileError("default value is not supported here"sv, defVal);
2840 } 2975 }
2841 auto exp = static_cast<Exp_t*>(pair); 2976 auto exp = static_cast<Exp_t*>(pair);
2842 auto chain = exp->new_ptr<ChainValue_t>(); 2977 auto chain = exp->new_ptr<ChainValue_t>();
2843 auto indexItem = toAst<Exp_t>(std::to_string(index), exp);
2844 chain->items.push_back(indexItem); 2978 chain->items.push_back(indexItem);
2845 pairs.push_back({exp, Empty, chain, nullptr}); 2979 pairs.push_back({exp, Empty, chain, nullptr});
2846 break; 2980 break;
@@ -2855,7 +2989,6 @@ private:
2855 throw CompileError("default value is not supported here"sv, defVal); 2989 throw CompileError("default value is not supported here"sv, defVal);
2856 } 2990 }
2857 } 2991 }
2858 auto indexItem = toAst<Exp_t>(std::to_string(index), value);
2859 for (auto& p : subPairs) { 2992 for (auto& p : subPairs) {
2860 if (sep) p.structure->items.push_front(sep); 2993 if (sep) p.structure->items.push_front(sep);
2861 p.structure->items.push_front(indexItem); 2994 p.structure->items.push_front(indexItem);
@@ -2866,7 +2999,6 @@ private:
2866 auto varName = singleVariableFrom(exp, AccessType::None); 2999 auto varName = singleVariableFrom(exp, AccessType::None);
2867 if (varName == "_"sv) break; 3000 if (varName == "_"sv) break;
2868 auto chain = exp->new_ptr<ChainValue_t>(); 3001 auto chain = exp->new_ptr<ChainValue_t>();
2869 auto indexItem = toAst<Exp_t>(std::to_string(index), exp);
2870 chain->items.push_back(indexItem); 3002 chain->items.push_back(indexItem);
2871 pairs.push_back({exp, 3003 pairs.push_back({exp,
2872 varName, 3004 varName,
@@ -2991,7 +3123,13 @@ private:
2991 auto tb = static_cast<TableBlockIndent_t*>(pair); 3123 auto tb = static_cast<TableBlockIndent_t*>(pair);
2992 ++index; 3124 ++index;
2993 auto subPairs = destructFromExp(tb, varDefOnly, optional); 3125 auto subPairs = destructFromExp(tb, varDefOnly, optional);
2994 auto indexItem = toAst<Exp_t>(std::to_string(index), tb); 3126 ast_ptr<true, ast_node> indexItem;
3127 if (hasSpread) {
3128 int rIndex = count - index;
3129 indexItem.set(toAst<ReversedIndex_t>('#' + (rIndex == 0 ? Empty : "-"s + std::to_string(rIndex)), tb));
3130 } else {
3131 indexItem.set(toAst<Exp_t>(std::to_string(index), tb));
3132 }
2995 for (auto& p : subPairs) { 3133 for (auto& p : subPairs) {
2996 if (sep) p.structure->items.push_front(sep); 3134 if (sep) p.structure->items.push_front(sep);
2997 p.structure->items.push_front(indexItem); 3135 p.structure->items.push_front(indexItem);
@@ -3048,6 +3186,42 @@ private:
3048 subMetaDestruct->values.push_back(newPairDef); 3186 subMetaDestruct->values.push_back(newPairDef);
3049 break; 3187 break;
3050 } 3188 }
3189 case id<SpreadListExp_t>():
3190 case id<SpreadExp_t>(): {
3191 ++index;
3192 if (hasSpread) {
3193 throw CompileError("duplicated spread expression"sv, pair);
3194 }
3195 hasSpread = true;
3196 for (auto item : *tableItems) {
3197 if (ast_is<
3198 SpreadListExp_t, SpreadExp_t,
3199 TableBlockIndent_t,
3200 Exp_t, NormalDef_t>(item)) {
3201 count++;
3202 }
3203 }
3204 Exp_t* exp = nullptr;
3205 if (auto se = ast_cast<SpreadExp_t>(pair)) {
3206 exp = se->exp.get();
3207 } else {
3208 exp = ast_to<SpreadListExp_t>(pair)->exp.get();
3209 }
3210 auto varName = singleVariableFrom(exp, AccessType::None);
3211 if (varName == "_"sv) break;
3212 int start = index;
3213 int stop = index - count - 1;
3214 auto chain = exp->new_ptr<ChainValue_t>();
3215 auto slice = toAst<Slice_t>(
3216 '[' + (start == 1 ? Empty : std::to_string(start)) + ',' + (stop == -1 ? Empty : std::to_string(stop)) + ']', exp);
3217 chain->items.push_back(slice);
3218 auto nil = toAst<Exp_t>("nil"sv, slice);
3219 pairs.push_back({exp,
3220 varName,
3221 chain,
3222 nil.get()});
3223 break;
3224 }
3051 default: YUEE("AST node mismatch", pair); break; 3225 default: YUEE("AST node mismatch", pair); break;
3052 } 3226 }
3053 } 3227 }
@@ -3125,7 +3299,7 @@ private:
3125 if (auto tab = sVal->value.as<TableLit_t>()) { 3299 if (auto tab = sVal->value.as<TableLit_t>()) {
3126 destructNode = tab; 3300 destructNode = tab;
3127 } else if (auto comp = sVal->value.as<Comprehension_t>()) { 3301 } else if (auto comp = sVal->value.as<Comprehension_t>()) {
3128 if (comp->items.size() != 2 || !ast_is<CompInner_t>(comp->items.back())) { 3302 if (!isListComp(comp)) {
3129 destructNode = comp; 3303 destructNode = comp;
3130 } 3304 }
3131 } 3305 }
@@ -3512,7 +3686,7 @@ private:
3512 _buf << defs; 3686 _buf << defs;
3513 else 3687 else
3514 _buf << indent() << left; 3688 _buf << indent() << left;
3515 _buf << " = "sv << left << ' ' << op << ' ' << right << nll(assignment); 3689 _buf << " = "sv << left << ' ' << op << ' ' << right << nl(assignment);
3516 out.push_back(clearBuf()); 3690 out.push_back(clearBuf());
3517 break; 3691 break;
3518 } 3692 }
@@ -3559,9 +3733,9 @@ private:
3559 transformExpList(expList, temp); 3733 transformExpList(expList, temp);
3560 std::string left = std::move(temp.back()); 3734 std::string left = std::move(temp.back());
3561 temp.pop_back(); 3735 temp.pop_back();
3562 out.push_back(indent() + left + " = "s + join(temp, ", "sv) + nll(assignment)); 3736 out.push_back(indent() + left + " = "s + join(temp, ", "sv) + nl(assignment));
3563 } else { 3737 } else {
3564 out.push_back(preDefine + " = "s + join(temp, ", "sv) + nll(assignment)); 3738 out.push_back(preDefine + " = "s + join(temp, ", "sv) + nl(assignment));
3565 } 3739 }
3566 } else { 3740 } else {
3567 std::string preDefine = toLocalDecl(defs); 3741 std::string preDefine = toLocalDecl(defs);
@@ -3577,7 +3751,7 @@ private:
3577 for (auto value : assign->values.objects()) { 3751 for (auto value : assign->values.objects()) {
3578 transformAssignItem(value, temp); 3752 transformAssignItem(value, temp);
3579 } 3753 }
3580 out.push_back((preDefine.empty() ? Empty : preDefine + nll(assignment)) + indent() + left + " = "s + join(temp, ", "sv) + nll(assignment)); 3754 out.push_back((preDefine.empty() ? Empty : preDefine + nl(assignment)) + indent() + left + " = "s + join(temp, ", "sv) + nl(assignment));
3581 } 3755 }
3582 break; 3756 break;
3583 } 3757 }
@@ -3678,7 +3852,7 @@ private:
3678 if (usage != ExpUsage::Closure) { 3852 if (usage != ExpUsage::Closure) {
3679 if (!currentScope().lastStatement) { 3853 if (!currentScope().lastStatement) {
3680 extraScope = true; 3854 extraScope = true;
3681 temp.push_back(indent() + "do"s + nll(asmt)); 3855 temp.push_back(indent() + "do"s + nl(asmt));
3682 pushScope(); 3856 pushScope();
3683 } 3857 }
3684 } 3858 }
@@ -3711,7 +3885,7 @@ private:
3711 if (usage != ExpUsage::Closure) { 3885 if (usage != ExpUsage::Closure) {
3712 if (!currentScope().lastStatement) { 3886 if (!currentScope().lastStatement) {
3713 extraScope = true; 3887 extraScope = true;
3714 temp.push_back(indent() + "do"s + nll(asmt)); 3888 temp.push_back(indent() + "do"s + nl(asmt));
3715 pushScope(); 3889 pushScope();
3716 } 3890 }
3717 } 3891 }
@@ -3740,12 +3914,12 @@ private:
3740 if (pair != ifCondPairs.front()) { 3914 if (pair != ifCondPairs.front()) {
3741 _buf << "else"sv; 3915 _buf << "else"sv;
3742 } 3916 }
3743 _buf << "if "sv << condStr << " then"sv << nll(condition); 3917 _buf << "if "sv << condStr << " then"sv << nl(condition);
3744 temp.push_back(clearBuf()); 3918 temp.push_back(clearBuf());
3745 } 3919 }
3746 if (pair.second) { 3920 if (pair.second) {
3747 if (!pair.first) { 3921 if (!pair.first) {
3748 temp.push_back(indent() + "else"s + nll(pair.second)); 3922 temp.push_back(indent() + "else"s + nl(pair.second));
3749 } 3923 }
3750 pushScope(); 3924 pushScope();
3751 if (pair == ifCondPairs.front() && extraAssignment) { 3925 if (pair == ifCondPairs.front() && extraAssignment) {
@@ -3755,17 +3929,17 @@ private:
3755 popScope(); 3929 popScope();
3756 } 3930 }
3757 if (!pair.first) { 3931 if (!pair.first) {
3758 temp.push_back(indent() + "end"s + nll(nodes.front())); 3932 temp.push_back(indent() + "end"s + nl(nodes.front()));
3759 break; 3933 break;
3760 } 3934 }
3761 } 3935 }
3762 if (extraScope) { 3936 if (extraScope) {
3763 popScope(); 3937 popScope();
3764 temp.push_back(indent() + "end"s + nlr(nodes.front())); 3938 temp.push_back(indent() + "end"s + nl(nodes.front()));
3765 } 3939 }
3766 if (usage == ExpUsage::Closure) { 3940 if (usage == ExpUsage::Closure) {
3767 popScope(); 3941 popScope();
3768 *funcStart = anonFuncStart() + nll(nodes.front()); 3942 *funcStart = anonFuncStart() + nl(nodes.front());
3769 temp.push_back(indent() + anonFuncEnd()); 3943 temp.push_back(indent() + anonFuncEnd());
3770 popAnonVarArg(); 3944 popAnonVarArg();
3771 popFunctionScope(); 3945 popFunctionScope();
@@ -3860,7 +4034,7 @@ private:
3860 } else { 4034 } else {
3861 transformExp(arg, out, ExpUsage::Closure); 4035 transformExp(arg, out, ExpUsage::Closure);
3862 out.back().insert(0, indent()); 4036 out.back().insert(0, indent());
3863 out.back().append(nlr(x)); 4037 out.back().append(nl(x));
3864 } 4038 }
3865 return; 4039 return;
3866 } 4040 }
@@ -3984,7 +4158,7 @@ private:
3984 auto stmt = exp->new_ptr<Statement_t>(); 4158 auto stmt = exp->new_ptr<Statement_t>();
3985 stmt->content.set(preDefine); 4159 stmt->content.set(preDefine);
3986 preDefine.set(nullptr); 4160 preDefine.set(nullptr);
3987 block->statements.push_back(stmt); 4161 block->statementOrComments.push_back(stmt);
3988 auto simpleValue = exp->new_ptr<SimpleValue_t>(); 4162 auto simpleValue = exp->new_ptr<SimpleValue_t>();
3989 simpleValue->value.set(ifNode); 4163 simpleValue->value.set(ifNode);
3990 auto explist = exp->new_ptr<ExpList_t>(); 4164 auto explist = exp->new_ptr<ExpList_t>();
@@ -3993,7 +4167,7 @@ private:
3993 expListAssign->expList.set(explist); 4167 expListAssign->expList.set(explist);
3994 stmt = exp->new_ptr<Statement_t>(); 4168 stmt = exp->new_ptr<Statement_t>();
3995 stmt->content.set(expListAssign); 4169 stmt->content.set(expListAssign);
3996 block->statements.push_back(stmt); 4170 block->statementOrComments.push_back(stmt);
3997 nodes->push_back(block); 4171 nodes->push_back(block);
3998 nodes = &ifNode->nodes; 4172 nodes = &ifNode->nodes;
3999 } else { 4173 } else {
@@ -4001,7 +4175,7 @@ private:
4001 auto stmt = exp->new_ptr<Statement_t>(); 4175 auto stmt = exp->new_ptr<Statement_t>();
4002 stmt->content.set(preDefine); 4176 stmt->content.set(preDefine);
4003 preDefine.set(nullptr); 4177 preDefine.set(nullptr);
4004 block->statements.push_back(stmt); 4178 block->statementOrComments.push_back(stmt);
4005 auto simpleValue = exp->new_ptr<SimpleValue_t>(); 4179 auto simpleValue = exp->new_ptr<SimpleValue_t>();
4006 simpleValue->value.set(ifNode); 4180 simpleValue->value.set(ifNode);
4007 auto explist = exp->new_ptr<ExpList_t>(); 4181 auto explist = exp->new_ptr<ExpList_t>();
@@ -4010,7 +4184,7 @@ private:
4010 expListAssign->expList.set(explist); 4184 expListAssign->expList.set(explist);
4011 stmt = exp->new_ptr<Statement_t>(); 4185 stmt = exp->new_ptr<Statement_t>();
4012 stmt->content.set(expListAssign); 4186 stmt->content.set(expListAssign);
4013 block->statements.push_back(stmt); 4187 block->statementOrComments.push_back(stmt);
4014 auto body = exp->new_ptr<Body_t>(); 4188 auto body = exp->new_ptr<Body_t>();
4015 body->content.set(block); 4189 body->content.set(block);
4016 auto doNode = exp->new_ptr<Do_t>(); 4190 auto doNode = exp->new_ptr<Do_t>();
@@ -4172,7 +4346,7 @@ private:
4172 auto stmt = x->new_ptr<Statement_t>(); 4346 auto stmt = x->new_ptr<Statement_t>();
4173 stmt->content.set(expListAssign); 4347 stmt->content.set(expListAssign);
4174 auto blk = x->new_ptr<Block_t>(); 4348 auto blk = x->new_ptr<Block_t>();
4175 blk->statements.push_back(stmt); 4349 blk->statementOrComments.push_back(stmt);
4176 newBlock.set(blk); 4350 newBlock.set(blk);
4177 } 4351 }
4178 if (!globals.empty()) { 4352 if (!globals.empty()) {
@@ -4264,15 +4438,25 @@ private:
4264 4438
4265 std::optional<std::pair<std::string, str_list>> upValueFuncFromExp(Exp_t* exp, str_list* ensureArgListInTheEnd, bool blockRewrite) { 4439 std::optional<std::pair<std::string, str_list>> upValueFuncFromExp(Exp_t* exp, str_list* ensureArgListInTheEnd, bool blockRewrite) {
4266 if (checkUpValueFuncAvailable(exp)) { 4440 if (checkUpValueFuncAvailable(exp)) {
4441 auto block = exp->new_ptr<Block_t>();
4442 if (auto sVal = simpleSingleValueFrom(exp)) {
4443 if (auto doNode = sVal->value.as<Do_t>()) {
4444 if (auto blk = doNode->body->content.as<Block_t>()) {
4445 block->statementOrComments.dup(blk->statementOrComments);
4446 } else {
4447 block->statementOrComments.push_back(doNode->body->content.to<Statement_t>());
4448 }
4449 return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, false, blockRewrite);
4450 }
4451 }
4267 auto returnNode = exp->new_ptr<Return_t>(); 4452 auto returnNode = exp->new_ptr<Return_t>();
4268 returnNode->explicitReturn = false; 4453 returnNode->explicitReturn = false;
4269 auto returnList = exp->new_ptr<ExpListLow_t>(); 4454 auto returnList = exp->new_ptr<ExpListLow_t>();
4270 returnList->exprs.push_back(exp); 4455 returnList->exprs.push_back(exp);
4271 returnNode->valueList.set(returnList); 4456 returnNode->valueList.set(returnList);
4272 auto block = exp->new_ptr<Block_t>();
4273 auto stmt = exp->new_ptr<Statement_t>(); 4457 auto stmt = exp->new_ptr<Statement_t>();
4274 stmt->content.set(returnNode); 4458 stmt->content.set(returnNode);
4275 block->statements.push_back(stmt); 4459 block->statementOrComments.push_back(stmt);
4276 return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, false, blockRewrite); 4460 return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, false, blockRewrite);
4277 } 4461 }
4278 return std::nullopt; 4462 return std::nullopt;
@@ -4329,7 +4513,7 @@ private:
4329 bool extraScope = !currentScope().lastStatement; 4513 bool extraScope = !currentScope().lastStatement;
4330 if (forAssignment) { 4514 if (forAssignment) {
4331 if (extraScope) { 4515 if (extraScope) {
4332 temp.push_back(indent() + "do"s + nll(x)); 4516 temp.push_back(indent() + "do"s + nl(x));
4333 pushScope(); 4517 pushScope();
4334 } 4518 }
4335 } 4519 }
@@ -4352,9 +4536,9 @@ private:
4352 case ExpUsage::Return: 4536 case ExpUsage::Return:
4353 case ExpUsage::Closure: { 4537 case ExpUsage::Closure: {
4354 prepareValue(); 4538 prepareValue();
4355 _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x); 4539 _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nl(x);
4356 _buf << indent(1) << "return "s << objVar << nll(x); 4540 _buf << indent(1) << "return "s << objVar << nl(x);
4357 _buf << indent() << "else"s << nll(x); 4541 _buf << indent() << "else"s << nl(x);
4358 temp.push_back(clearBuf()); 4542 temp.push_back(clearBuf());
4359 auto ret = x->new_ptr<Return_t>(); 4543 auto ret = x->new_ptr<Return_t>();
4360 ret->explicitReturn = false; 4544 ret->explicitReturn = false;
@@ -4364,10 +4548,10 @@ private:
4364 incIndentOffset(); 4548 incIndentOffset();
4365 transformReturn(ret, temp); 4549 transformReturn(ret, temp);
4366 decIndentOffset(); 4550 decIndentOffset();
4367 temp.push_back(indent() + "end"s + nll(x)); 4551 temp.push_back(indent() + "end"s + nl(x));
4368 if (usage == ExpUsage::Closure) { 4552 if (usage == ExpUsage::Closure) {
4369 popScope(); 4553 popScope();
4370 *funcStart = anonFuncStart() + nll(x); 4554 *funcStart = anonFuncStart() + nl(x);
4371 temp.push_back(indent() + anonFuncEnd()); 4555 temp.push_back(indent() + anonFuncEnd());
4372 popAnonVarArg(); 4556 popAnonVarArg();
4373 popFunctionScope(); 4557 popFunctionScope();
@@ -4384,14 +4568,14 @@ private:
4384 assign->values.push_back(exp); 4568 assign->values.push_back(exp);
4385 temp.push_back(getPreDefineLine(assignment)); 4569 temp.push_back(getPreDefineLine(assignment));
4386 extraScope = prepareValue(true); 4570 extraScope = prepareValue(true);
4387 _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x); 4571 _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nl(x);
4388 temp.push_back(clearBuf()); 4572 temp.push_back(clearBuf());
4389 pushScope(); 4573 pushScope();
4390 assign->values.clear(); 4574 assign->values.clear();
4391 assign->values.push_back(toAst<Exp_t>(objVar, x)); 4575 assign->values.push_back(toAst<Exp_t>(objVar, x));
4392 transformAssignment(assignment, temp); 4576 transformAssignment(assignment, temp);
4393 popScope(); 4577 popScope();
4394 temp.push_back(indent() + "else"s + nll(x)); 4578 temp.push_back(indent() + "else"s + nl(x));
4395 assign->values.clear(); 4579 assign->values.clear();
4396 assign->values.push_back(exp->nilCoalesed); 4580 assign->values.push_back(exp->nilCoalesed);
4397 } else { 4581 } else {
@@ -4399,17 +4583,17 @@ private:
4399 assign->values.push_back(exp->nilCoalesed); 4583 assign->values.push_back(exp->nilCoalesed);
4400 temp.push_back(getPreDefineLine(assignment)); 4584 temp.push_back(getPreDefineLine(assignment));
4401 transformExp(left, temp, ExpUsage::Closure); 4585 transformExp(left, temp, ExpUsage::Closure);
4402 _buf << indent() << "if "sv << temp.back() << " == nil then"sv << nll(x); 4586 _buf << indent() << "if "sv << temp.back() << " == nil then"sv << nl(x);
4403 temp.pop_back(); 4587 temp.pop_back();
4404 temp.push_back(clearBuf()); 4588 temp.push_back(clearBuf());
4405 } 4589 }
4406 pushScope(); 4590 pushScope();
4407 transformAssignment(assignment, temp); 4591 transformAssignment(assignment, temp);
4408 popScope(); 4592 popScope();
4409 temp.push_back(indent() + "end"s + nlr(x)); 4593 temp.push_back(indent() + "end"s + nl(x));
4410 if (extraScope) { 4594 if (extraScope) {
4411 popScope(); 4595 popScope();
4412 temp.push_back(indent() + "end"s + nlr(x)); 4596 temp.push_back(indent() + "end"s + nl(x));
4413 } 4597 }
4414 break; 4598 break;
4415 } 4599 }
@@ -4439,7 +4623,7 @@ private:
4439 if (accessType == AccessType::Read && _funcLevel > 1) { 4623 if (accessType == AccessType::Read && _funcLevel > 1) {
4440 accessType = AccessType::Capture; 4624 accessType = AccessType::Capture;
4441 } 4625 }
4442 _globals[key] = {out.back(), item->m_begin.m_line, item->m_begin.m_col, accessType}; 4626 _globals[key] = {out.back(), item->m_begin.m_line, item->m_begin.m_col, accessType, isSolidDefined(out.back())};
4443 } 4627 }
4444 } 4628 }
4445 break; 4629 break;
@@ -4471,6 +4655,7 @@ private:
4471 case id<ForEach_t>(): transformForEachClosure(static_cast<ForEach_t*>(value), out); break; 4655 case id<ForEach_t>(): transformForEachClosure(static_cast<ForEach_t*>(value), out); break;
4472 case id<For_t>(): transformForClosure(static_cast<For_t*>(value), out); break; 4656 case id<For_t>(): transformForClosure(static_cast<For_t*>(value), out); break;
4473 case id<While_t>(): transformWhileClosure(static_cast<While_t*>(value), out); break; 4657 case id<While_t>(): transformWhileClosure(static_cast<While_t*>(value), out); break;
4658 case id<Repeat_t>(): transformRepeatClosure(static_cast<Repeat_t*>(value), out); break;
4474 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Closure); break; 4659 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Closure); break;
4475 case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Closure); break; 4660 case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Closure); break;
4476 case id<UnaryValue_t>(): transformUnaryValue(static_cast<UnaryValue_t*>(value), out); break; 4661 case id<UnaryValue_t>(): transformUnaryValue(static_cast<UnaryValue_t*>(value), out); break;
@@ -4507,11 +4692,11 @@ private:
4507 switch (content->get_id()) { 4692 switch (content->get_id()) {
4508 case id<Block_t>(): { 4693 case id<Block_t>(): {
4509 auto block = static_cast<Block_t*>(content); 4694 auto block = static_cast<Block_t*>(content);
4510 newBlock->statements.dup(block->statements); 4695 newBlock->statementOrComments.dup(block->statementOrComments);
4511 break; 4696 break;
4512 } 4697 }
4513 case id<Statement_t>(): { 4698 case id<Statement_t>(): {
4514 newBlock->statements.push_back(content); 4699 newBlock->statementOrComments.push_back(content);
4515 break; 4700 break;
4516 } 4701 }
4517 default: YUEE("AST node mismatch", content); break; 4702 default: YUEE("AST node mismatch", content); break;
@@ -4523,7 +4708,7 @@ private:
4523 returnNode->valueList.set(funLit->defaultReturn); 4708 returnNode->valueList.set(funLit->defaultReturn);
4524 auto stmt = newBlock->new_ptr<Statement_t>(); 4709 auto stmt = newBlock->new_ptr<Statement_t>();
4525 stmt->content.set(returnNode); 4710 stmt->content.set(returnNode);
4526 newBlock->statements.push_back(stmt); 4711 newBlock->statementOrComments.push_back(stmt);
4527 } 4712 }
4528 transformBlock(newBlock, temp, ExpUsage::Common); 4713 transformBlock(newBlock, temp, ExpUsage::Common);
4529 } else { 4714 } else {
@@ -4545,7 +4730,7 @@ private:
4545 } 4730 }
4546 _buf << args << ')'; 4731 _buf << args << ')';
4547 if (!initArgs.empty() || !bodyCodes.empty()) { 4732 if (!initArgs.empty() || !bodyCodes.empty()) {
4548 _buf << nlr(argsDef) << initArgs << bodyCodes; 4733 _buf << nl(argsDef) << initArgs << bodyCodes;
4549 popScope(); 4734 popScope();
4550 _buf << indent() << "end"sv; 4735 _buf << indent() << "end"sv;
4551 } else { 4736 } else {
@@ -4556,7 +4741,7 @@ private:
4556 auto& bodyCodes = temp.back(); 4741 auto& bodyCodes = temp.back();
4557 _buf << "function("sv << (isFatArrow ? "self"s : Empty) << ')'; 4742 _buf << "function("sv << (isFatArrow ? "self"s : Empty) << ')';
4558 if (!bodyCodes.empty()) { 4743 if (!bodyCodes.empty()) {
4559 _buf << nll(funLit) << bodyCodes; 4744 _buf << nl(funLit) << bodyCodes;
4560 popScope(); 4745 popScope();
4561 _buf << indent() << "end"sv; 4746 _buf << indent() << "end"sv;
4562 } else { 4747 } else {
@@ -4573,7 +4758,7 @@ private:
4573 auto x = body; 4758 auto x = body;
4574 if (auto stmt = body->content.as<Statement_t>()) { 4759 if (auto stmt = body->content.as<Statement_t>()) {
4575 auto block = x->new_ptr<Block_t>(); 4760 auto block = x->new_ptr<Block_t>();
4576 block->statements.push_back(stmt); 4761 block->statementOrComments.push_back(stmt);
4577 transformBlock(block, out, usage, assignList); 4762 transformBlock(block, out, usage, assignList);
4578 } else { 4763 } else {
4579 transformBlock(body->content.to<Block_t>(), out, usage, assignList); 4764 transformBlock(body->content.to<Block_t>(), out, usage, assignList);
@@ -4585,13 +4770,15 @@ private:
4585 out.push_back(Empty); 4770 out.push_back(Empty);
4586 return; 4771 return;
4587 } 4772 }
4588 const auto& nodes = block->statements.objects(); 4773 const auto& nodes = block->statementOrComments.objects();
4774 auto lastStmt = lastStatementFrom(nodes);
4589 LocalMode mode = LocalMode::None; 4775 LocalMode mode = LocalMode::None;
4590 Local_t *any = nullptr, *capital = nullptr; 4776 Local_t *any = nullptr, *capital = nullptr;
4591 for (auto it = nodes.begin(); it != nodes.end(); ++it) { 4777 for (auto it = nodes.begin(); it != nodes.end(); ++it) {
4592 auto node = *it; 4778 auto node = *it;
4593 auto stmt = static_cast<Statement_t*>(node); 4779 auto stmt = ast_cast<Statement_t>(node);
4594 if (!stmt->appendix && stmt->content.is<Return_t>() && stmt != nodes.back()) { 4780 if (!stmt) continue;
4781 if (!stmt->appendix && stmt->content.is<Return_t>() && stmt != lastStmt) {
4595 throw CompileError("'return' statement must be the last line in the block"sv, stmt->content); 4782 throw CompileError("'return' statement must be the last line in the block"sv, stmt->content);
4596 } else if (auto pipeBody = stmt->content.as<PipeBody_t>()) { 4783 } else if (auto pipeBody = stmt->content.as<PipeBody_t>()) {
4597 auto x = stmt; 4784 auto x = stmt;
@@ -4600,6 +4787,16 @@ private:
4600 BREAK_IF(it == nodes.begin()); 4787 BREAK_IF(it == nodes.begin());
4601 auto last = it; 4788 auto last = it;
4602 --last; 4789 --last;
4790 bool found = true;
4791 while (!ast_is<Statement_t>(*last)) {
4792 if (last == nodes.begin()) {
4793 found = false;
4794 break;
4795 } else {
4796 --last;
4797 }
4798 }
4799 BREAK_IF(!found);
4603 auto lst = static_cast<Statement_t*>(*last); 4800 auto lst = static_cast<Statement_t*>(*last);
4604 if (lst->appendix) { 4801 if (lst->appendix) {
4605 throw CompileError("statement decorator must be placed at the end of pipe chain"sv, lst->appendix.get()); 4802 throw CompileError("statement decorator must be placed at the end of pipe chain"sv, lst->appendix.get());
@@ -4617,9 +4814,17 @@ private:
4617 stmt->content.set(nullptr); 4814 stmt->content.set(nullptr);
4618 auto next = it; 4815 auto next = it;
4619 ++next; 4816 ++next;
4817 Statement_t* nextStmt = nullptr;
4818 while (next != nodes.end()) {
4819 nextStmt = ast_cast<Statement_t>(*next);
4820 if (nextStmt) {
4821 break;
4822 }
4823 ++next;
4824 }
4620 BLOCK_START 4825 BLOCK_START
4621 BREAK_IF(next == nodes.end()); 4826 BREAK_IF(!nextStmt);
4622 BREAK_IF(!static_cast<Statement_t*>(*next)->content.as<PipeBody_t>()); 4827 BREAK_IF(!nextStmt->content.as<PipeBody_t>());
4623 throw CompileError("indent mismatch in pipe chain"sv, *next); 4828 throw CompileError("indent mismatch in pipe chain"sv, *next);
4624 BLOCK_END 4829 BLOCK_END
4625 } else if (auto backcall = stmt->content.as<Backcall_t>()) { 4830 } else if (auto backcall = stmt->content.as<Backcall_t>()) {
@@ -4627,7 +4832,7 @@ private:
4627 auto newBlock = x->new_ptr<Block_t>(); 4832 auto newBlock = x->new_ptr<Block_t>();
4628 if (it != nodes.begin()) { 4833 if (it != nodes.begin()) {
4629 for (auto i = nodes.begin(); i != it; ++i) { 4834 for (auto i = nodes.begin(); i != it; ++i) {
4630 newBlock->statements.push_back(*i); 4835 newBlock->statementOrComments.push_back(*i);
4631 } 4836 }
4632 } 4837 }
4633 x = backcall; 4838 x = backcall;
@@ -4638,7 +4843,7 @@ private:
4638 ++next; 4843 ++next;
4639 if (next != nodes.end()) { 4844 if (next != nodes.end()) {
4640 for (auto i = next; i != nodes.end(); ++i) { 4845 for (auto i = next; i != nodes.end(); ++i) {
4641 block->statements.push_back(*i); 4846 block->statementOrComments.push_back(*i);
4642 } 4847 }
4643 } 4848 }
4644 auto body = x->new_ptr<Body_t>(); 4849 auto body = x->new_ptr<Body_t>();
@@ -4690,7 +4895,7 @@ private:
4690 expListAssign->expList.set(expList); 4895 expListAssign->expList.set(expList);
4691 newStmt->content.set(expListAssign); 4896 newStmt->content.set(expListAssign);
4692 newStmt->appendix.set(stmt->appendix); 4897 newStmt->appendix.set(stmt->appendix);
4693 newBlock->statements.push_back(newStmt); 4898 newBlock->statementOrComments.push_back(newStmt);
4694 } 4899 }
4695 transformBlock(newBlock, out, usage, assignList, isRoot); 4900 transformBlock(newBlock, out, usage, assignList, isRoot);
4696 return; 4901 return;
@@ -4717,7 +4922,7 @@ private:
4717 throw CompileError("while-loop line decorator is not supported here"sv, appendix->item.get()); 4922 throw CompileError("while-loop line decorator is not supported here"sv, appendix->item.get());
4718 break; 4923 break;
4719 } 4924 }
4720 case id<CompInner_t>(): { 4925 case id<CompFor_t>(): {
4721 throw CompileError("for-loop line decorator is not supported here"sv, appendix->item.get()); 4926 throw CompileError("for-loop line decorator is not supported here"sv, appendix->item.get());
4722 break; 4927 break;
4723 } 4928 }
@@ -4746,7 +4951,7 @@ private:
4746 auto newBlock = x->new_ptr<Block_t>(); 4951 auto newBlock = x->new_ptr<Block_t>();
4747 if (it != nodes.begin()) { 4952 if (it != nodes.begin()) {
4748 for (auto i = nodes.begin(); i != it; ++i) { 4953 for (auto i = nodes.begin(); i != it; ++i) {
4749 newBlock->statements.push_back(*i); 4954 newBlock->statementOrComments.push_back(*i);
4750 } 4955 }
4751 } 4956 }
4752 x = expListAssign; 4957 x = expListAssign;
@@ -4756,7 +4961,7 @@ private:
4756 ++next; 4961 ++next;
4757 if (next != nodes.end()) { 4962 if (next != nodes.end()) {
4758 for (auto i = next; i != nodes.end(); ++i) { 4963 for (auto i = next; i != nodes.end(); ++i) {
4759 followingBlock->statements.push_back(*i); 4964 followingBlock->statementOrComments.push_back(*i);
4760 } 4965 }
4761 } 4966 }
4762 } 4967 }
@@ -4784,17 +4989,13 @@ private:
4784 newAssignment->action.set(newAssign); 4989 newAssignment->action.set(newAssign);
4785 auto newStatement = x->new_ptr<Statement_t>(); 4990 auto newStatement = x->new_ptr<Statement_t>();
4786 newStatement->content.set(newAssignment); 4991 newStatement->content.set(newAssignment);
4787 followingBlock->statements.push_front(newStatement); 4992 followingBlock->statementOrComments.push_front(newStatement);
4788 } 4993 }
4789 argNames.push_back("..."s); 4994 argNames.push_back("..."s);
4790 auto newBody = x->new_ptr<Body_t>(); 4995 auto newBody = x->new_ptr<Body_t>();
4791 newBody->content.set(followingBlock); 4996 newBody->content.set(followingBlock);
4792 { 4997 {
4793 auto doNode = x->new_ptr<Do_t>(); 4998 if (auto result = upValueFuncFromBlock(followingBlock.get(), &argNames, false, true)) {
4794 doNode->body.set(newBody);
4795 auto simpleValue = x->new_ptr<SimpleValue_t>();
4796 simpleValue->value.set(doNode);
4797 if (auto result = upValueFuncFromExp(newExp(simpleValue, x), &argNames, true)) {
4798 auto [funcName, args] = std::move(*result); 4999 auto [funcName, args] = std::move(*result);
4799 str_list finalArgs; 5000 str_list finalArgs;
4800 for (const auto& arg : args) { 5001 for (const auto& arg : args) {
@@ -4802,9 +5003,14 @@ private:
4802 finalArgs.push_back(arg); 5003 finalArgs.push_back(arg);
4803 } 5004 }
4804 } 5005 }
4805 newBlock->statements.push_back(toAst<Statement_t>(funcName + ' ' + join(finalArgs, ","sv), x)); 5006 auto lastNewStmt = toAst<Statement_t>(funcName + ' ' + (finalArgs.empty() ? "nil"s : join(finalArgs, ","sv)), x);
4806 auto sVal = singleValueFrom(static_cast<Statement_t*>(newBlock->statements.back())->content.to<ExpListAssign_t>()->expList); 5007 newBlock->statementOrComments.push_back(lastNewStmt);
4807 ast_to<InvokeArgs_t>(sVal->item.to<ChainValue_t>()->items.back())->args.dup(newInvoke->args); 5008 auto sVal = singleValueFrom(lastNewStmt->content.to<ExpListAssign_t>()->expList);
5009 auto invokArgs = ast_to<InvokeArgs_t>(sVal->item.to<ChainValue_t>()->items.back());
5010 if (finalArgs.empty()) {
5011 invokArgs->args.clear();
5012 }
5013 invokArgs->args.dup(newInvoke->args);
4808 transformBlock(newBlock, out, usage, assignList, isRoot); 5014 transformBlock(newBlock, out, usage, assignList, isRoot);
4809 return; 5015 return;
4810 } 5016 }
@@ -4829,7 +5035,7 @@ private:
4829 newItemListAssign->expList.set(newItemList); 5035 newItemListAssign->expList.set(newItemList);
4830 auto newItemStatement = x->new_ptr<Statement_t>(); 5036 auto newItemStatement = x->new_ptr<Statement_t>();
4831 newItemStatement->content.set(newItemListAssign); 5037 newItemStatement->content.set(newItemListAssign);
4832 newBlock->statements.push_back(newItemStatement); 5038 newBlock->statementOrComments.push_back(newItemStatement);
4833 transformBlock(newBlock, out, usage, assignList, isRoot); 5039 transformBlock(newBlock, out, usage, assignList, isRoot);
4834 return; 5040 return;
4835 BLOCK_END 5041 BLOCK_END
@@ -4838,11 +5044,11 @@ private:
4838 auto newBlock = x->new_ptr<Block_t>(); 5044 auto newBlock = x->new_ptr<Block_t>();
4839 if (it != nodes.begin()) { 5045 if (it != nodes.begin()) {
4840 for (auto i = nodes.begin(); i != it; ++i) { 5046 for (auto i = nodes.begin(); i != it; ++i) {
4841 newBlock->statements.push_back(*i); 5047 newBlock->statementOrComments.push_back(*i);
4842 } 5048 }
4843 } 5049 }
4844 localAttrib->attrib.set(localAttrib->new_ptr<ConstAttrib_t>()); 5050 localAttrib->attrib.set(localAttrib->new_ptr<ConstAttrib_t>());
4845 newBlock->statements.push_back(*it); 5051 newBlock->statementOrComments.push_back(*it);
4846 x = localAttrib; 5052 x = localAttrib;
4847 auto followingBlock = x->new_ptr<Block_t>(); 5053 auto followingBlock = x->new_ptr<Block_t>();
4848 { 5054 {
@@ -4850,7 +5056,7 @@ private:
4850 ++next; 5056 ++next;
4851 if (next != nodes.end()) { 5057 if (next != nodes.end()) {
4852 for (auto i = next; i != nodes.end(); ++i) { 5058 for (auto i = next; i != nodes.end(); ++i) {
4853 followingBlock->statements.push_back(*i); 5059 followingBlock->statementOrComments.push_back(*i);
4854 } 5060 }
4855 } 5061 }
4856 } 5062 }
@@ -4872,13 +5078,13 @@ private:
4872 auto value = singleValueFrom(pCallExp); 5078 auto value = singleValueFrom(pCallExp);
4873 value->item.to<SimpleValue_t>()->value.to<Try_t>()->func.set(followingBlock); 5079 value->item.to<SimpleValue_t>()->value.to<Try_t>()->func.set(followingBlock);
4874 for (const auto& stmt : getCloses) { 5080 for (const auto& stmt : getCloses) {
4875 newBlock->statements.push_back(toAst<Statement_t>(stmt, x)); 5081 newBlock->statementOrComments.push_back(toAst<Statement_t>(stmt, x));
4876 } 5082 }
4877 newBlock->statements.push_back(pCallStmt); 5083 newBlock->statementOrComments.push_back(pCallStmt);
4878 for (const auto& stmt : doCloses) { 5084 for (const auto& stmt : doCloses) {
4879 newBlock->statements.push_back(toAst<Statement_t>(stmt, x)); 5085 newBlock->statementOrComments.push_back(toAst<Statement_t>(stmt, x));
4880 } 5086 }
4881 newBlock->statements.push_back(toAst<Statement_t>("if "s + okVar + " then return ... else error ..."s, x)); 5087 newBlock->statementOrComments.push_back(toAst<Statement_t>("if "s + okVar + " then return ... else error ..."s, x));
4882 transformBlock(newBlock, out, usage, assignList, isRoot); 5088 transformBlock(newBlock, out, usage, assignList, isRoot);
4883 return; 5089 return;
4884 } else if (auto expListAssign = stmt->content.as<ExpListAssign_t>(); 5090 } else if (auto expListAssign = stmt->content.as<ExpListAssign_t>();
@@ -4887,7 +5093,7 @@ private:
4887 auto newBlock = x->new_ptr<Block_t>(); 5093 auto newBlock = x->new_ptr<Block_t>();
4888 if (it != nodes.begin()) { 5094 if (it != nodes.begin()) {
4889 for (auto i = nodes.begin(); i != it; ++i) { 5095 for (auto i = nodes.begin(); i != it; ++i) {
4890 newBlock->statements.push_back(*i); 5096 newBlock->statementOrComments.push_back(*i);
4891 } 5097 }
4892 } 5098 }
4893 auto doBackcall = static_cast<SubBackcall_t*>(expListAssign->action.get()); 5099 auto doBackcall = static_cast<SubBackcall_t*>(expListAssign->action.get());
@@ -4904,12 +5110,11 @@ private:
4904 backcall->value.set(doBackcall->value); 5110 backcall->value.set(doBackcall->value);
4905 auto newStmt = backcall->new_ptr<Statement_t>(); 5111 auto newStmt = backcall->new_ptr<Statement_t>();
4906 newStmt->content.set(backcall); 5112 newStmt->content.set(backcall);
4907 newStmt->comments.dup(stmt->comments);
4908 newStmt->appendix.set(stmt->appendix); 5113 newStmt->appendix.set(stmt->appendix);
4909 newBlock->statements.push_back(newStmt); 5114 newBlock->statementOrComments.push_back(newStmt);
4910 auto ait = it; 5115 auto ait = it;
4911 for (auto i = ++ait; i != nodes.end(); ++i) { 5116 for (auto i = ++ait; i != nodes.end(); ++i) {
4912 newBlock->statements.push_back(*i); 5117 newBlock->statementOrComments.push_back(*i);
4913 } 5118 }
4914 transformBlock(newBlock, out, usage, assignList, isRoot); 5119 transformBlock(newBlock, out, usage, assignList, isRoot);
4915 return; 5120 return;
@@ -5021,7 +5226,7 @@ private:
5021 } 5226 }
5022 } 5227 }
5023 if (isRoot && !_info.moduleName.empty() && !_info.exportMacro) { 5228 if (isRoot && !_info.moduleName.empty() && !_info.exportMacro) {
5024 block->statements.push_front(toAst<Statement_t>(_info.moduleName + (_info.exportDefault ? "=nil"s : (_info.exportMetatable ? "=<>:{}"s : "={}"s)), block)); 5229 block->statementOrComments.push_front(toAst<Statement_t>(_info.moduleName + (_info.exportDefault ? "=nil"s : (_info.exportMetatable ? "=<>:{}"s : "={}"s)), block));
5025 } 5230 }
5026 switch (usage) { 5231 switch (usage) {
5027 case ExpUsage::Closure: 5232 case ExpUsage::Closure:
@@ -5058,7 +5263,7 @@ private:
5058 break; 5263 break;
5059 } 5264 }
5060 } 5265 }
5061 bool lastAssignable = (expListFrom(last) || ast_is<For_t, ForEach_t, While_t>(last->content)); 5266 bool lastAssignable = (expListFrom(last) || ast_is<For_t, While_t>(last->content));
5062 if (lastAssignable) { 5267 if (lastAssignable) {
5063 auto x = last; 5268 auto x = last;
5064 auto newAssignment = x->new_ptr<ExpListAssign_t>(); 5269 auto newAssignment = x->new_ptr<ExpListAssign_t>();
@@ -5083,37 +5288,54 @@ private:
5083 } 5288 }
5084 if (!nodes.empty()) { 5289 if (!nodes.empty()) {
5085 str_list temp; 5290 str_list temp;
5291 auto lastStmt = lastStatementFrom(nodes);
5086 for (auto node : nodes) { 5292 for (auto node : nodes) {
5087 currentScope().lastStatement = (node == nodes.back()) && currentScope().mode == GlobalMode::None; 5293 if (auto comment = ast_cast<YueComment_t>(node)) {
5088 transformStatement(static_cast<Statement_t*>(node), temp); 5294 transformComment(comment, temp);
5089 if (isRoot && !_rootDefs.empty()) { 5295 continue;
5090 auto last = std::move(temp.back()); 5296 }
5091 temp.pop_back(); 5297 if (!ast_is<Statement_t>(node)) {
5092 temp.insert(temp.end(), _rootDefs.begin(), _rootDefs.end()); 5298 continue;
5093 _rootDefs.clear(); 5299 }
5094 temp.push_back(std::move(last)); 5300 auto transformNode = [&]() {
5095 } 5301 currentScope().lastStatement = (node == lastStmt) && currentScope().mode == GlobalMode::None;
5096 if (!temp.empty() && _parser.startWith<StatementSep_t>(temp.back())) { 5302 transformStatement(static_cast<Statement_t*>(node), temp);
5097 auto rit = ++temp.rbegin(); 5303 if (isRoot && !_rootDefs.empty()) {
5098 if (rit != temp.rend() && !rit->empty()) { 5304 auto last = std::move(temp.back());
5099 auto index = std::string::npos; 5305 temp.pop_back();
5100 if (_config.reserveLineNumber) { 5306 temp.insert(temp.end(), _rootDefs.begin(), _rootDefs.end());
5101 index = rit->rfind(" -- "sv); 5307 _rootDefs.clear();
5102 } else { 5308 temp.push_back(std::move(last));
5103 index = rit->find_last_not_of('\n'); 5309 }
5104 if (index != std::string::npos) index++; 5310 if (!temp.empty() && _parser.startWith<StatementSep_t>(temp.back())) {
5105 } 5311 auto rit = ++temp.rbegin();
5106 if (index != std::string::npos) { 5312 if (rit != temp.rend() && !rit->empty()) {
5107 auto ending = rit->substr(0, index); 5313 auto index = std::string::npos;
5108 auto ind = ending.find_last_of(" \t\n"sv); 5314 if (_config.reserveLineNumber) {
5109 if (ind != std::string::npos) { 5315 index = rit->rfind(" -- "sv);
5110 ending = ending.substr(ind + 1); 5316 } else {
5317 index = rit->find_last_not_of('\n');
5318 if (index != std::string::npos) index++;
5111 } 5319 }
5112 if (LuaKeywords.find(ending) == LuaKeywords.end()) { 5320 if (index != std::string::npos) {
5113 rit->insert(index, ";"sv); 5321 auto ending = rit->substr(0, index);
5322 auto ind = ending.find_last_of(" \t\n"sv);
5323 if (ind != std::string::npos) {
5324 ending = ending.substr(ind + 1);
5325 }
5326 if (LuaKeywords.find(ending) == LuaKeywords.end()) {
5327 rit->insert(index, ";"sv);
5328 }
5114 } 5329 }
5115 } 5330 }
5116 } 5331 }
5332 };
5333 if (_config.lax) {
5334 try {
5335 transformNode();
5336 } catch (const CompileError&) { }
5337 } else {
5338 transformNode();
5117 } 5339 }
5118 } 5340 }
5119 out.push_back(join(temp)); 5341 out.push_back(join(temp));
@@ -5121,7 +5343,7 @@ private:
5121 out.push_back(Empty); 5343 out.push_back(Empty);
5122 } 5344 }
5123 if (isRoot && !_info.moduleName.empty() && !_info.exportMacro) { 5345 if (isRoot && !_info.moduleName.empty() && !_info.exportMacro) {
5124 out.back().append(indent() + "return "s + _info.moduleName + nlr(block)); 5346 out.back().append(indent() + "return "s + _info.moduleName + nl(block));
5125 } 5347 }
5126 } 5348 }
5127 5349
@@ -5322,18 +5544,29 @@ private:
5322 auto macroLit = macro->decl.to<MacroLit_t>(); 5544 auto macroLit = macro->decl.to<MacroLit_t>();
5323 auto argsDef = macroLit->argsDef.get(); 5545 auto argsDef = macroLit->argsDef.get();
5324 str_list newArgs; 5546 str_list newArgs;
5547 str_list argChecks;
5548 bool hasCheck = false;
5325 if (argsDef) { 5549 if (argsDef) {
5326 for (auto def_ : argsDef->definitions.objects()) { 5550 for (auto def_ : argsDef->definitions.objects()) {
5327 auto def = static_cast<FnArgDef_t*>(def_); 5551 auto def = static_cast<FnArgDef_t*>(def_);
5328 if (def->name.is<SelfItem_t>()) { 5552 if (def->name.is<SelfItem_t>()) {
5329 throw CompileError("self name is not supported for macro function argument"sv, def->name); 5553 throw CompileError("self name is not supported for macro function argument"sv, def->name);
5330 } else { 5554 } else {
5555 if (def->op) throw CompileError("invalid existence checking"sv, def->op);
5556 if (def->label) {
5557 hasCheck = true;
5558 const auto& astName = argChecks.emplace_back(_parser.toString(def->label));
5559 if (!_parser.hasAST(astName)) {
5560 throw CompileError("invalid AST name"sv, def->label);
5561 }
5562 } else {
5563 argChecks.emplace_back();
5564 }
5331 std::string defVal; 5565 std::string defVal;
5332 if (def->defaultValue) { 5566 if (def->defaultValue) {
5333 defVal = _parser.toString(def->defaultValue); 5567 defVal = _parser.toString(def->defaultValue);
5334 Utils::trim(defVal); 5568 Utils::trim(defVal);
5335 defVal.insert(0, "=[==========["sv); 5569 defVal = '=' + Utils::toLuaDoubleString(defVal);
5336 defVal.append("]==========]"sv);
5337 } 5570 }
5338 newArgs.emplace_back(_parser.toString(def->name) + defVal); 5571 newArgs.emplace_back(_parser.toString(def->name) + defVal);
5339 } 5572 }
@@ -5341,6 +5574,14 @@ private:
5341 if (argsDef->varArg) { 5574 if (argsDef->varArg) {
5342 newArgs.emplace_back(_parser.toString(argsDef->varArg)); 5575 newArgs.emplace_back(_parser.toString(argsDef->varArg));
5343 } 5576 }
5577 if (argsDef->label) {
5578 hasCheck = true;
5579 const auto& astName = _parser.toString(argsDef->label);
5580 if (!_parser.hasAST(astName)) {
5581 throw CompileError("invalid AST name"sv, argsDef->label);
5582 }
5583 argChecks.emplace_back("..."s + astName);
5584 }
5344 } 5585 }
5345 std::string macroCodes = "_ENV=require('yue').macro_env\n("s + join(newArgs, ","sv) + ")->"s + _parser.toString(macroLit->body); 5586 std::string macroCodes = "_ENV=require('yue').macro_env\n("s + join(newArgs, ","sv) + ")->"s + _parser.toString(macroLit->body);
5346 auto chunkName = "=(macro "s + macroName + ')'; 5587 auto chunkName = "=(macro "s + macroName + ')';
@@ -5371,6 +5612,24 @@ private:
5371 throw CompileError("failed to generate macro function\n"s + err, macroLit); 5612 throw CompileError("failed to generate macro function\n"s + err, macroLit);
5372 } // cur true macro 5613 } // cur true macro
5373 lua_remove(L, -2); // cur macro 5614 lua_remove(L, -2); // cur macro
5615 if (hasCheck) {
5616 lua_createtable(L, 0, 0); // cur macro checks
5617 int i = 1;
5618 for (const auto& check : argChecks) {
5619 if (check.empty()) {
5620 lua_pushboolean(L, 0);
5621 lua_rawseti(L, -2, i);
5622 } else {
5623 lua_pushlstring(L, check.c_str(), check.size());
5624 lua_rawseti(L, -2, i);
5625 }
5626 i++;
5627 }
5628 lua_createtable(L, 2, 0); // cur macro checks macrotab
5629 lua_insert(L, -3); // cur macrotab macro checks
5630 lua_rawseti(L, -3, 1); // macrotab[1] = checks, cur macrotab macro
5631 lua_rawseti(L, -2, 2); // macrotab[2] = macro, cur macrotab
5632 } // cur macro
5374 if (exporting && _config.exporting && !_config.module.empty()) { 5633 if (exporting && _config.exporting && !_config.module.empty()) {
5375 pushModuleTable(_config.module); // cur macro module 5634 pushModuleTable(_config.module); // cur macro module
5376 lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro module name 5635 lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro module name
@@ -5445,11 +5704,11 @@ private:
5445 case id<While_t>(): 5704 case id<While_t>():
5446 transformWhileInPlace(static_cast<While_t*>(value), out); 5705 transformWhileInPlace(static_cast<While_t*>(value), out);
5447 return; 5706 return;
5448 case id<For_t>(): 5707 case id<Repeat_t>():
5449 transformForInPlace(static_cast<For_t*>(value), out); 5708 transformRepeatInPlace(static_cast<Repeat_t*>(value), out);
5450 return; 5709 return;
5451 case id<ForEach_t>(): 5710 case id<For_t>():
5452 transformForEachInPlace(static_cast<ForEach_t*>(value), out); 5711 transformForInPlace(static_cast<For_t*>(value), out, nullptr);
5453 return; 5712 return;
5454 case id<If_t>(): 5713 case id<If_t>():
5455 transformIf(static_cast<If_t*>(value), out, ExpUsage::Return); 5714 transformIf(static_cast<If_t*>(value), out, ExpUsage::Return);
@@ -5469,12 +5728,12 @@ private:
5469 } 5728 }
5470 } 5729 }
5471 transformValue(singleValue, out); 5730 transformValue(singleValue, out);
5472 out.back() = indent() + "return "s + out.back() + nlr(returnNode); 5731 out.back() = indent() + "return "s + out.back() + nl(returnNode);
5473 return; 5732 return;
5474 } else { 5733 } else {
5475 str_list temp; 5734 str_list temp;
5476 transformExpListLow(valueList, temp); 5735 transformExpListLow(valueList, temp);
5477 out.push_back(indent() + "return "s + temp.back() + nlr(returnNode)); 5736 out.push_back(indent() + "return "s + temp.back() + nl(returnNode));
5478 } 5737 }
5479 } else if (auto tableBlock = returnNode->valueList.as<TableBlock_t>()) { 5738 } else if (auto tableBlock = returnNode->valueList.as<TableBlock_t>()) {
5480 const auto& values = tableBlock->values.objects(); 5739 const auto& values = tableBlock->values.objects();
@@ -5482,10 +5741,10 @@ private:
5482 transformSpreadTable(values, out, ExpUsage::Return, nullptr, false); 5741 transformSpreadTable(values, out, ExpUsage::Return, nullptr, false);
5483 } else { 5742 } else {
5484 transformTable(values, out); 5743 transformTable(values, out);
5485 out.back() = indent() + "return "s + out.back() + nlr(returnNode); 5744 out.back() = indent() + "return "s + out.back() + nl(returnNode);
5486 } 5745 }
5487 } else { 5746 } else {
5488 out.push_back(indent() + "return"s + nll(returnNode)); 5747 out.push_back(indent() + "return"s + nl(returnNode));
5489 } 5748 }
5490 } 5749 }
5491 5750
@@ -5516,6 +5775,7 @@ private:
5516 bool checkExistence = false; 5775 bool checkExistence = false;
5517 std::string name; 5776 std::string name;
5518 std::string assignSelf; 5777 std::string assignSelf;
5778 ast_ptr<false, ExpListAssign_t> assignment;
5519 }; 5779 };
5520 std::list<ArgItem> argItems; 5780 std::list<ArgItem> argItems;
5521 str_list temp; 5781 str_list temp;
@@ -5525,7 +5785,11 @@ private:
5525 auto def = static_cast<FnArgDef_t*>(_def); 5785 auto def = static_cast<FnArgDef_t*>(_def);
5526 auto& arg = argItems.emplace_back(); 5786 auto& arg = argItems.emplace_back();
5527 switch (def->name->get_id()) { 5787 switch (def->name->get_id()) {
5528 case id<Variable_t>(): arg.name = variableToString(static_cast<Variable_t*>(def->name.get())); break; 5788 case id<Variable_t>(): {
5789 if (def->op) throw CompileError("invalid existence checking"sv, def->op);
5790 arg.name = variableToString(static_cast<Variable_t*>(def->name.get()));
5791 break;
5792 }
5529 case id<SelfItem_t>(): { 5793 case id<SelfItem_t>(): {
5530 assignSelf = true; 5794 assignSelf = true;
5531 if (def->op) { 5795 if (def->op) {
@@ -5566,6 +5830,22 @@ private:
5566 } 5830 }
5567 break; 5831 break;
5568 } 5832 }
5833 case id<TableLit_t>(): {
5834 arg.name = getUnusedName("_arg_"sv);
5835 auto simpleValue = def->new_ptr<SimpleValue_t>();
5836 simpleValue->value.set(def->name);
5837 auto asmt = assignmentFrom(newExp(simpleValue, def), toAst<Exp_t>(arg.name, def), def);
5838 arg.assignment = asmt;
5839 break;
5840 }
5841 case id<SimpleTable_t>(): {
5842 arg.name = getUnusedName("_arg_"sv);
5843 auto value = def->new_ptr<Value_t>();
5844 value->item.set(def->name);
5845 auto asmt = assignmentFrom(newExp(value, def), toAst<Exp_t>(arg.name, def), def);
5846 arg.assignment = asmt;
5847 break;
5848 }
5569 default: YUEE("AST node mismatch", def->name.get()); break; 5849 default: YUEE("AST node mismatch", def->name.get()); break;
5570 } 5850 }
5571 forceAddToScope(arg.name); 5851 forceAddToScope(arg.name);
@@ -5579,23 +5859,46 @@ private:
5579 assignment->action.set(assign); 5859 assignment->action.set(assign);
5580 transformAssignment(assignment, temp); 5860 transformAssignment(assignment, temp);
5581 popScope(); 5861 popScope();
5582 _buf << indent() << "if "sv << arg.name << " == nil then"sv << nll(def); 5862 _buf << indent() << "if "sv << arg.name << " == nil then"sv << nl(def);
5583 _buf << temp.back(); 5863 _buf << temp.back();
5584 _buf << indent() << "end"sv << nll(def); 5864 _buf << indent() << "end"sv << nl(def);
5585 temp.back() = clearBuf(); 5865 temp.back() = clearBuf();
5586 } 5866 }
5587 if (varNames.empty()) 5867 if (arg.assignment) {
5868 auto names = getArgDestructureList(arg.assignment);
5869 for (const auto& name : names) {
5870 forceAddToScope(name);
5871 }
5872 temp.emplace_back(indent() + "local "s + join(names, ", "sv) + nl(def));
5873 transformAssignment(arg.assignment, temp);
5874 }
5875 if (varNames.empty()) {
5588 varNames = arg.name; 5876 varNames = arg.name;
5589 else 5877 } else {
5590 varNames.append(", "s + arg.name); 5878 varNames.append(", "s + arg.name);
5879 }
5591 } 5880 }
5592 if (argDefList->varArg) { 5881 if (argDefList->varArg) {
5882 std::string varStr;
5883 if (auto varName = argDefList->varArg->name.get()) {
5884 varStr = variableToString(varName);
5885 int target = getLuaTarget(varName);
5886 forceAddToScope(varStr);
5887 if (target < 505) {
5888 temp.push_back(indent() + "local "s + varStr + " = {"s + nl(varName));
5889 temp.push_back(indent(1) + "n = "s + globalVar("select", varName, AccessType::Read) + "(\"#\", ...),"s + nl(varName));
5890 temp.push_back(indent(1) + "..."s + nl(varName));
5891 temp.push_back(indent() + '}' + nl(varName));
5892 varStr.clear();
5893 }
5894 }
5593 auto& arg = argItems.emplace_back(); 5895 auto& arg = argItems.emplace_back();
5594 arg.name = "..."sv; 5896 arg.name = "..."sv;
5595 if (varNames.empty()) 5897 if (varNames.empty()) {
5596 varNames = arg.name; 5898 varNames = arg.name + varStr;
5597 else 5899 } else {
5598 varNames.append(", "s + arg.name); 5900 varNames.append(", "s + arg.name + varStr);
5901 }
5599 _varArgs.top().hasVar = true; 5902 _varArgs.top().hasVar = true;
5600 } 5903 }
5601 if (assignSelf) { 5904 if (assignSelf) {
@@ -5664,6 +5967,45 @@ private:
5664 } 5967 }
5665 } 5968 }
5666 5969
5970 bool transformChainEndWithSlice(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) {
5971 auto x = chainList.front();
5972 if (ast_is<Slice_t>(chainList.back())) {
5973 auto comp = x->new_ptr<Comprehension_t>();
5974 {
5975 auto chainValue = x->new_ptr<ChainValue_t>();
5976 for (auto item : chainList) {
5977 chainValue->items.push_back(item);
5978 }
5979 auto itemVar = getUnusedName("_item_"sv);
5980 auto expCode = YueFormat{}.toString(chainValue);
5981 auto compCode = '[' + itemVar + " for "s + itemVar + " in *"s + expCode + ']';
5982 comp.set(toAst<Comprehension_t>(compCode, x));
5983 }
5984 switch (usage) {
5985 case ExpUsage::Assignment: {
5986 auto simpleValue = x->new_ptr<SimpleValue_t>();
5987 simpleValue->value.set(comp);
5988 auto exp = newExp(simpleValue, x);
5989 auto assignment = x->new_ptr<ExpListAssign_t>();
5990 assignment->expList.set(assignList);
5991 auto assign = x->new_ptr<Assign_t>();
5992 assign->values.push_back(exp);
5993 assignment->action.set(assign);
5994 transformAssignment(assignment, out);
5995 break;
5996 }
5997 case ExpUsage::Return:
5998 transformComprehension(comp, out, ExpUsage::Return);
5999 break;
6000 default:
6001 transformComprehension(comp, out, ExpUsage::Closure);
6002 break;
6003 }
6004 return true;
6005 }
6006 return false;
6007 }
6008
5667 bool transformChainEndWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) { 6009 bool transformChainEndWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) {
5668 auto x = chainList.front(); 6010 auto x = chainList.front();
5669 if (ast_is<ExistentialOp_t>(chainList.back())) { 6011 if (ast_is<ExistentialOp_t>(chainList.back())) {
@@ -5698,7 +6040,7 @@ private:
5698 case ExpUsage::Return: 6040 case ExpUsage::Return:
5699 transformParens(parens, out); 6041 transformParens(parens, out);
5700 out.back().insert(0, indent() + "return "s); 6042 out.back().insert(0, indent() + "return "s);
5701 out.back().append(nlr(x)); 6043 out.back().append(nl(x));
5702 break; 6044 break;
5703 default: 6045 default:
5704 transformParens(parens, out); 6046 transformParens(parens, out);
@@ -5769,7 +6111,7 @@ private:
5769 } 6111 }
5770 } 6112 }
5771 if (isScoped) { 6113 if (isScoped) {
5772 temp.push_back(indent() + "do"s + nll(x)); 6114 temp.push_back(indent() + "do"s + nl(x));
5773 pushScope(); 6115 pushScope();
5774 } 6116 }
5775 objVar = getUnusedName("_obj_"sv); 6117 objVar = getUnusedName("_obj_"sv);
@@ -5829,9 +6171,9 @@ private:
5829 _buf << typeVar << "=type "sv << objVar; 6171 _buf << typeVar << "=type "sv << objVar;
5830 auto typeAssign = toAst<ExpListAssign_t>(clearBuf(), partOne); 6172 auto typeAssign = toAst<ExpListAssign_t>(clearBuf(), partOne);
5831 transformAssignment(typeAssign, temp); 6173 transformAssignment(typeAssign, temp);
5832 _buf << indent() << "if \"table\" == " << typeVar << " or \"userdata\" == "sv << typeVar << " then"sv << nll(x); 6174 _buf << indent() << "if \"table\" == " << typeVar << " or \"userdata\" == "sv << typeVar << " then"sv << nl(x);
5833 } else { 6175 } else {
5834 _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x); 6176 _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nl(x);
5835 } 6177 }
5836 temp.push_back(clearBuf()); 6178 temp.push_back(clearBuf());
5837 pushScope(); 6179 pushScope();
@@ -5867,15 +6209,15 @@ private:
5867 } 6209 }
5868 } 6210 }
5869 popScope(); 6211 popScope();
5870 temp.push_back(indent() + "end"s + nlr(x)); 6212 temp.push_back(indent() + "end"s + nl(x));
5871 switch (usage) { 6213 switch (usage) {
5872 case ExpUsage::Return: 6214 case ExpUsage::Return:
5873 temp.push_back(indent() + "return nil"s + nlr(x)); 6215 temp.push_back(indent() + "return nil"s + nl(x));
5874 break; 6216 break;
5875 case ExpUsage::Closure: 6217 case ExpUsage::Closure:
5876 temp.push_back(indent() + "return nil"s + nlr(x)); 6218 temp.push_back(indent() + "return nil"s + nl(x));
5877 popScope(); 6219 popScope();
5878 *funcStart = anonFuncStart() + nll(x); 6220 *funcStart = anonFuncStart() + nl(x);
5879 temp.push_back(indent() + anonFuncEnd()); 6221 temp.push_back(indent() + anonFuncEnd());
5880 popAnonVarArg(); 6222 popAnonVarArg();
5881 popFunctionScope(); 6223 popFunctionScope();
@@ -5885,7 +6227,7 @@ private:
5885 } 6227 }
5886 if (isScoped) { 6228 if (isScoped) {
5887 popScope(); 6229 popScope();
5888 temp.push_back(indent() + "end"s + nlr(x)); 6230 temp.push_back(indent() + "end"s + nl(x));
5889 } 6231 }
5890 out.push_back(join(temp)); 6232 out.push_back(join(temp));
5891 return true; 6233 return true;
@@ -5902,7 +6244,7 @@ private:
5902 switch (usage) { 6244 switch (usage) {
5903 case ExpUsage::Assignment: 6245 case ExpUsage::Assignment:
5904 if (isScoped) { 6246 if (isScoped) {
5905 temp.push_back(indent() + "do"s + nll(x)); 6247 temp.push_back(indent() + "do"s + nl(x));
5906 pushScope(); 6248 pushScope();
5907 } 6249 }
5908 break; 6250 break;
@@ -5980,12 +6322,12 @@ private:
5980 case ExpUsage::Assignment: 6322 case ExpUsage::Assignment:
5981 if (isScoped) { 6323 if (isScoped) {
5982 popScope(); 6324 popScope();
5983 temp.push_back(indent() + "end"s + nlr(x)); 6325 temp.push_back(indent() + "end"s + nl(x));
5984 } 6326 }
5985 break; 6327 break;
5986 case ExpUsage::Closure: 6328 case ExpUsage::Closure:
5987 popScope(); 6329 popScope();
5988 *funcStart = anonFuncStart() + nll(x); 6330 *funcStart = anonFuncStart() + nl(x);
5989 temp.push_back(indent() + anonFuncEnd()); 6331 temp.push_back(indent() + anonFuncEnd());
5990 popAnonVarArg(); 6332 popAnonVarArg();
5991 popFunctionScope(); 6333 popFunctionScope();
@@ -6061,7 +6403,7 @@ private:
6061 pushScope(); 6403 pushScope();
6062 } else if (usage != ExpUsage::Return) { 6404 } else if (usage != ExpUsage::Return) {
6063 if (isScoped) { 6405 if (isScoped) {
6064 temp.push_back(indent() + "do"s + nll(x)); 6406 temp.push_back(indent() + "do"s + nl(x));
6065 pushScope(); 6407 pushScope();
6066 } 6408 }
6067 } 6409 }
@@ -6098,7 +6440,7 @@ private:
6098 returnNode->valueList.set(values); 6440 returnNode->valueList.set(values);
6099 transformReturn(returnNode, temp); 6441 transformReturn(returnNode, temp);
6100 popScope(); 6442 popScope();
6101 *funcStart = anonFuncStart() + nll(x); 6443 *funcStart = anonFuncStart() + nl(x);
6102 temp.push_back(indent() + anonFuncEnd()); 6444 temp.push_back(indent() + anonFuncEnd());
6103 popAnonVarArg(); 6445 popAnonVarArg();
6104 popFunctionScope(); 6446 popFunctionScope();
@@ -6122,7 +6464,7 @@ private:
6122 transformAssignment(assignment, temp); 6464 transformAssignment(assignment, temp);
6123 if (isScoped) { 6465 if (isScoped) {
6124 popScope(); 6466 popScope();
6125 temp.push_back(indent() + "end"s + nlr(x)); 6467 temp.push_back(indent() + "end"s + nl(x));
6126 } 6468 }
6127 break; 6469 break;
6128 } 6470 }
@@ -6130,7 +6472,7 @@ private:
6130 transformExp(newChainExp, temp, usage); 6472 transformExp(newChainExp, temp, usage);
6131 if (isScoped) { 6473 if (isScoped) {
6132 popScope(); 6474 popScope();
6133 temp.push_back(indent() + "end"s + nlr(x)); 6475 temp.push_back(indent() + "end"s + nl(x));
6134 } 6476 }
6135 break; 6477 break;
6136 } 6478 }
@@ -6181,7 +6523,7 @@ private:
6181 case id<ColonChainItem_t>(): 6523 case id<ColonChainItem_t>():
6182 case id<Exp_t>(): 6524 case id<Exp_t>():
6183 if (_withVars.empty()) { 6525 if (_withVars.empty()) {
6184 throw CompileError("short dot/colon and indexing syntax must be called within a with block"sv, x); 6526 throw CompileError("short dot/colon/indexing syntax must be called within a with block"sv, x);
6185 } else { 6527 } else {
6186 temp.push_back(_withVars.top()); 6528 temp.push_back(_withVars.top());
6187 } 6529 }
@@ -6235,7 +6577,7 @@ private:
6235 assignment->action.set(assign); 6577 assignment->action.set(assign);
6236 auto stmt = x->new_ptr<Statement_t>(); 6578 auto stmt = x->new_ptr<Statement_t>();
6237 stmt->content.set(assignment); 6579 stmt->content.set(assignment);
6238 block->statements.push_back(stmt); 6580 block->statementOrComments.push_back(stmt);
6239 } 6581 }
6240 } 6582 }
6241 ast_ptr<false, Exp_t> nexp; 6583 ast_ptr<false, Exp_t> nexp;
@@ -6281,7 +6623,7 @@ private:
6281 expListAssign->expList.set(expList); 6623 expListAssign->expList.set(expList);
6282 auto stmt = x->new_ptr<Statement_t>(); 6624 auto stmt = x->new_ptr<Statement_t>();
6283 stmt->content.set(expListAssign); 6625 stmt->content.set(expListAssign);
6284 block->statements.push_back(stmt); 6626 block->statementOrComments.push_back(stmt);
6285 } 6627 }
6286 switch (usage) { 6628 switch (usage) {
6287 case ExpUsage::Common: 6629 case ExpUsage::Common:
@@ -6295,7 +6637,7 @@ private:
6295 default: 6637 default:
6296 break; 6638 break;
6297 } 6639 }
6298 if (block->statements.size() == 1) { 6640 if (block->statementOrComments.size() == 1) {
6299 transformExp(nexp, out, usage, assignList); 6641 transformExp(nexp, out, usage, assignList);
6300 } else { 6642 } else {
6301 auto body = x->new_ptr<Body_t>(); 6643 auto body = x->new_ptr<Body_t>();
@@ -6327,6 +6669,120 @@ private:
6327 } 6669 }
6328 return; 6670 return;
6329 } 6671 }
6672 break;
6673 }
6674 case id<ReversedIndex_t>(): {
6675 auto rIndex = static_cast<ReversedIndex_t*>(*it);
6676 auto current = it;
6677 auto prevChain = x->new_ptr<ChainValue_t>();
6678 for (auto i = chainList.begin(); i != current; ++i) {
6679 prevChain->items.push_back(*i);
6680 }
6681 auto var = singleVariableFrom(prevChain, AccessType::None);
6682 if (!var.empty() && isLocal(var)) {
6683 auto indexNode = toAst<Exp_t>('#' + var, rIndex);
6684 if (rIndex->modifier) {
6685 auto opValue = rIndex->new_ptr<ExpOpValue_t>();
6686 opValue->op.set(toAst<BinaryOperator_t>("-"sv, rIndex));
6687 opValue->pipeExprs.dup(rIndex->modifier->pipeExprs);
6688 indexNode->opValues.push_back(opValue);
6689 indexNode->opValues.dup(rIndex->modifier->opValues);
6690 indexNode->nilCoalesed.set(rIndex->modifier->nilCoalesed);
6691 }
6692 prevChain->items.push_back(indexNode);
6693 auto next = current;
6694 ++next;
6695 for (auto i = next; i != chainList.end(); ++i) {
6696 prevChain->items.push_back(*i);
6697 }
6698 if (usage == ExpUsage::Assignment) {
6699 auto assignment = x->new_ptr<ExpListAssign_t>();
6700 assignment->expList.set(assignList);
6701 auto assign = x->new_ptr<Assign_t>();
6702 assign->values.push_back(newExp(prevChain, x));
6703 assignment->action.set(assign);
6704 transformAssignment(assignment, out);
6705 return;
6706 }
6707 transformChainValue(prevChain, out, usage, assignList);
6708 return;
6709 } else {
6710 auto itemVar = getUnusedName("_item_"sv);
6711 auto asmt = assignmentFrom(toAst<Exp_t>(itemVar, x), newExp(prevChain, x), x);
6712 auto stmt1 = x->new_ptr<Statement_t>();
6713 stmt1->content.set(asmt);
6714 auto newChain = x->new_ptr<ChainValue_t>();
6715 newChain->items.push_back(toAst<Callable_t>(itemVar, x));
6716 auto indexNode = toAst<Exp_t>('#' + itemVar, rIndex);
6717 if (rIndex->modifier) {
6718 auto opValue = rIndex->new_ptr<ExpOpValue_t>();
6719 opValue->op.set(toAst<BinaryOperator_t>("-"sv, rIndex));
6720 opValue->pipeExprs.dup(rIndex->modifier->pipeExprs);
6721 indexNode->opValues.push_back(opValue);
6722 indexNode->opValues.dup(rIndex->modifier->opValues);
6723 indexNode->nilCoalesed.set(rIndex->modifier->nilCoalesed);
6724 }
6725 newChain->items.push_back(indexNode);
6726 auto expList = x->new_ptr<ExpList_t>();
6727 expList->exprs.push_back(newExp(newChain, x));
6728 auto expListAssign = x->new_ptr<ExpListAssign_t>();
6729 expListAssign->expList.set(expList);
6730 auto stmt2 = x->new_ptr<Statement_t>();
6731 stmt2->content.set(expListAssign);
6732 auto block = x->new_ptr<Block_t>();
6733 block->statementOrComments.push_back(stmt1);
6734 block->statementOrComments.push_back(stmt2);
6735 auto body = x->new_ptr<Body_t>();
6736 body->content.set(block);
6737 auto doNode = x->new_ptr<Do_t>();
6738 doNode->body.set(body);
6739 if (usage == ExpUsage::Assignment) {
6740 auto next = current;
6741 ++next;
6742 for (auto i = next; i != chainList.end(); ++i) {
6743 newChain->items.push_back(*i);
6744 }
6745 auto assignment = x->new_ptr<ExpListAssign_t>();
6746 assignment->expList.set(assignList);
6747 auto assign = x->new_ptr<Assign_t>();
6748 auto sVal = x->new_ptr<SimpleValue_t>();
6749 sVal->value.set(doNode);
6750 assign->values.push_back(newExp(sVal, x));
6751 assignment->action.set(assign);
6752 transformAssignment(assignment, out);
6753 return;
6754 }
6755 if (usage == ExpUsage::Closure) {
6756 auto next = current;
6757 ++next;
6758 if (next != chainList.end()) {
6759 doNode->new_ptr<ChainValue_t>();
6760 auto dVal = doNode->new_ptr<SimpleValue_t>();
6761 dVal->value.set(doNode);
6762 auto dExp = newExp(dVal, dVal);
6763 auto dParen = dExp->new_ptr<Parens_t>();
6764 dParen->extra = true;
6765 dParen->expr.set(dExp);
6766 auto dCallable = dExp->new_ptr<Callable_t>();
6767 dCallable->item.set(dParen);
6768 auto dChain = doNode->new_ptr<ChainValue_t>();
6769 dChain->items.push_back(dCallable);
6770 for (auto i = next; i != chainList.end(); ++i) {
6771 dChain->items.push_back(*i);
6772 }
6773 transformExp(newExp(dChain, dExp), out, usage);
6774 return;
6775 }
6776 }
6777 auto next = current;
6778 ++next;
6779 for (auto i = next; i != chainList.end(); ++i) {
6780 newChain->items.push_back(*i);
6781 }
6782 transformDo(doNode, out, usage);
6783 return;
6784 }
6785 break;
6330 } 6786 }
6331 } 6787 }
6332 } 6788 }
@@ -6376,10 +6832,10 @@ private:
6376 } 6832 }
6377 switch (usage) { 6833 switch (usage) {
6378 case ExpUsage::Common: 6834 case ExpUsage::Common:
6379 out.push_back(indent() + join(temp) + nll(x)); 6835 out.push_back(indent() + join(temp) + nl(x));
6380 break; 6836 break;
6381 case ExpUsage::Return: 6837 case ExpUsage::Return:
6382 out.push_back(indent() + "return "s + join(temp) + nll(x)); 6838 out.push_back(indent() + "return "s + join(temp) + nl(x));
6383 break; 6839 break;
6384 case ExpUsage::Assignment: YUEE("invalid expression usage", x); break; 6840 case ExpUsage::Assignment: YUEE("invalid expression usage", x); break;
6385 default: 6841 default:
@@ -6511,7 +6967,7 @@ private:
6511 } 6967 }
6512 } 6968 }
6513 } 6969 }
6514 int len = lua_objlen(L, -1); 6970 int len = static_cast<int>(lua_objlen(L, -1));
6515 lua_pushnil(L); // cur nil 6971 lua_pushnil(L); // cur nil
6516 for (int i = len; i >= 1; i--) { 6972 for (int i = len; i >= 1; i--) {
6517 lua_pop(L, 1); // cur 6973 lua_pop(L, 1); // cur
@@ -6523,7 +6979,25 @@ private:
6523 break; 6979 break;
6524 } 6980 }
6525 } 6981 }
6526 if (!lua_isfunction(L, -1)) { 6982 str_list checks;
6983 if (lua_istable(L, -1)) {
6984 lua_rawgeti(L, -1, 1); // cur macrotab checks
6985 int len = static_cast<int>(lua_objlen(L, -1));
6986 for (int i = 1; i <= len; i++) {
6987 lua_rawgeti(L, -1, i);
6988 if (lua_toboolean(L, -1) == 0) {
6989 checks.emplace_back();
6990 } else {
6991 size_t str_len = 0;
6992 auto str = lua_tolstring(L, -1, &str_len);
6993 checks.emplace_back(std::string{str, str_len});
6994 }
6995 lua_pop(L, 1);
6996 }
6997 lua_pop(L, 1);
6998 lua_rawgeti(L, -1, 2); // cur macrotab macroFunc
6999 lua_remove(L, -2); // cur macroFunc
7000 } else if (!lua_isfunction(L, -1)) {
6527 auto code = expandBuiltinMacro(macroName, x); 7001 auto code = expandBuiltinMacro(macroName, x);
6528 if (!code.empty()) return code; 7002 if (!code.empty()) return code;
6529 if (macroName == "is_ast"sv) { 7003 if (macroName == "is_ast"sv) {
@@ -6568,11 +7042,34 @@ private:
6568 } // cur macroFunc 7042 } // cur macroFunc
6569 pushYue("pcall"sv); // cur macroFunc pcall 7043 pushYue("pcall"sv); // cur macroFunc pcall
6570 lua_insert(L, -2); // cur pcall macroFunc 7044 lua_insert(L, -2); // cur pcall macroFunc
6571 if (!lua_checkstack(L, argStrs.size())) { 7045 if (!lua_checkstack(L, static_cast<int>(argStrs.size()))) {
6572 throw CompileError("too much macro params"s, x); 7046 throw CompileError("too much macro params"s, x);
6573 } 7047 }
7048 auto checkIt = checks.begin();
7049 node_container::const_iterator argIt;
7050 if (args) {
7051 argIt = args->begin();
7052 }
6574 for (const auto& arg : argStrs) { 7053 for (const auto& arg : argStrs) {
7054 if (checkIt != checks.end()) {
7055 if (checkIt->empty()) {
7056 ++checkIt;
7057 } else {
7058 if ((*checkIt)[0] == '.') {
7059 auto astName = checkIt->substr(3);
7060 if (!_parser.match(astName, arg)) {
7061 throw CompileError("expecting \""s + astName + "\", AST mismatch"s, *argIt);
7062 }
7063 } else {
7064 if (!_parser.match(*checkIt, arg)) {
7065 throw CompileError("expecting \""s + *checkIt + "\", AST mismatch"s, *argIt);
7066 }
7067 ++checkIt;
7068 }
7069 }
7070 }
6575 lua_pushlstring(L, arg.c_str(), arg.size()); 7071 lua_pushlstring(L, arg.c_str(), arg.size());
7072 ++argIt;
6576 } // cur pcall macroFunc args... 7073 } // cur pcall macroFunc args...
6577 bool success = lua_pcall(L, static_cast<int>(argStrs.size()), 1, 0) == 0; 7074 bool success = lua_pcall(L, static_cast<int>(argStrs.size()), 1, 0) == 0;
6578 if (!success) { // cur err 7075 if (!success) { // cur err
@@ -6664,8 +7161,8 @@ private:
6664 throw CompileError("lua macro is not expanding to valid block\n"s + err, x); 7161 throw CompileError("lua macro is not expanding to valid block\n"s + err, x);
6665 } 7162 }
6666 if (!codes.empty()) { 7163 if (!codes.empty()) {
6667 codes.insert(0, indent() + "do"s + nll(chainValue)); 7164 codes.insert(0, indent() + "do"s + nl(chainValue));
6668 codes.append(_newLine + indent() + "end"s + nlr(chainValue)); 7165 codes.append(_newLine + indent() + "end"s + nl(chainValue));
6669 } 7166 }
6670 return {nullptr, nullptr, std::move(codes), std::move(localVars)}; 7167 return {nullptr, nullptr, std::move(codes), std::move(localVars)};
6671 } else { 7168 } else {
@@ -6702,14 +7199,14 @@ private:
6702 } else { 7199 } else {
6703 if (!codes.empty()) { 7200 if (!codes.empty()) {
6704 if (isBlock) { 7201 if (isBlock) {
6705 info = _parser.parse<BlockEnd_t>(codes); 7202 info = _parser.parse<BlockEnd_t>(codes, false);
6706 if (info.error) { 7203 if (info.error) {
6707 throw CompileError("failed to expand macro as block: "s + info.error.value().msg, x); 7204 throw CompileError("failed to expand macro as block: "s + info.error.value().msg, x);
6708 } 7205 }
6709 } else { 7206 } else {
6710 info = _parser.parse<Exp_t>(codes); 7207 info = _parser.parse<Exp_t>(codes, false);
6711 if (!info.node && allowBlockMacroReturn) { 7208 if (!info.node && allowBlockMacroReturn) {
6712 info = _parser.parse<BlockEnd_t>(codes); 7209 info = _parser.parse<BlockEnd_t>(codes, false);
6713 if (info.error) { 7210 if (info.error) {
6714 throw CompileError("failed to expand macro as expr or block: "s + info.error.value().msg, x); 7211 throw CompileError("failed to expand macro as expr or block: "s + info.error.value().msg, x);
6715 } 7212 }
@@ -6754,7 +7251,7 @@ private:
6754 auto stmt = x->new_ptr<Statement_t>(); 7251 auto stmt = x->new_ptr<Statement_t>();
6755 stmt->content.set(exps); 7252 stmt->content.set(exps);
6756 auto block = x->new_ptr<Block_t>(); 7253 auto block = x->new_ptr<Block_t>();
6757 block->statements.push_back(stmt); 7254 block->statementOrComments.push_back(stmt);
6758 info.node.set(block); 7255 info.node.set(block);
6759 } else { 7256 } else {
6760 info.node.set(exp); 7257 info.node.set(exp);
@@ -6791,7 +7288,7 @@ private:
6791 return; 7288 return;
6792 } 7289 }
6793 if (usage == ExpUsage::Common || (usage == ExpUsage::Return && node.is<Block_t>())) { 7290 if (usage == ExpUsage::Common || (usage == ExpUsage::Return && node.is<Block_t>())) {
6794 if (node.to<Block_t>()->statements.empty()) { 7291 if (node.to<Block_t>()->statementOrComments.empty()) {
6795 out.push_back(Empty); 7292 out.push_back(Empty);
6796 } else { 7293 } else {
6797 auto doBody = node->new_ptr<Body_t>(); 7294 auto doBody = node->new_ptr<Body_t>();
@@ -6845,6 +7342,9 @@ private:
6845 if (transformChainEndWithColonItem(chainList, out, usage, assignList)) { 7342 if (transformChainEndWithColonItem(chainList, out, usage, assignList)) {
6846 return; 7343 return;
6847 } 7344 }
7345 if (transformChainEndWithSlice(chainList, out, usage, assignList)) {
7346 return;
7347 }
6848 transformChainList(chainList, out, usage, assignList); 7348 transformChainList(chainList, out, usage, assignList);
6849 } 7349 }
6850 7350
@@ -6941,7 +7441,7 @@ private:
6941 } 7441 }
6942 } 7442 }
6943 } else if (auto comp = sval->value.as<Comprehension_t>()) { 7443 } else if (auto comp = sval->value.as<Comprehension_t>()) {
6944 if (comp->items.size() != 2 || !ast_is<CompInner_t>(comp->items.back())) { 7444 if (!isListComp(comp)) {
6945 discrete = inExp->new_ptr<ExpList_t>(); 7445 discrete = inExp->new_ptr<ExpList_t>();
6946 for (ast_node* val : comp->items.objects()) { 7446 for (ast_node* val : comp->items.objects()) {
6947 if (auto def = ast_cast<NormalDef_t>(val)) { 7447 if (auto def = ast_cast<NormalDef_t>(val)) {
@@ -6970,7 +7470,7 @@ private:
6970 auto assignment = assignmentFrom(toAst<Exp_t>(checkVar, inExp), newExp(inExp, inExp), inExp); 7470 auto assignment = assignmentFrom(toAst<Exp_t>(checkVar, inExp), newExp(inExp, inExp), inExp);
6971 auto stmt = x->new_ptr<Statement_t>(); 7471 auto stmt = x->new_ptr<Statement_t>();
6972 stmt->content.set(assignment); 7472 stmt->content.set(assignment);
6973 block->statements.push_back(stmt); 7473 block->statementOrComments.push_back(stmt);
6974 } 7474 }
6975 if (varName.empty()) { 7475 if (varName.empty()) {
6976 auto newUnaryExp = x->new_ptr<UnaryExp_t>(); 7476 auto newUnaryExp = x->new_ptr<UnaryExp_t>();
@@ -6982,7 +7482,7 @@ private:
6982 auto assignment = assignmentFrom(assignExp, exp, x); 7482 auto assignment = assignmentFrom(assignExp, exp, x);
6983 auto stmt = x->new_ptr<Statement_t>(); 7483 auto stmt = x->new_ptr<Statement_t>();
6984 stmt->content.set(assignment); 7484 stmt->content.set(assignment);
6985 block->statements.push_back(stmt); 7485 block->statementOrComments.push_back(stmt);
6986 } 7486 }
6987 auto findVar = getUnusedName("_find_"); 7487 auto findVar = getUnusedName("_find_");
6988 auto itemVar = getUnusedName("_item_"); 7488 auto itemVar = getUnusedName("_item_");
@@ -6998,7 +7498,7 @@ private:
6998 } 7498 }
6999 auto blockStr = clearBuf(); 7499 auto blockStr = clearBuf();
7000 auto checkBlock = toAst<Block_t>(blockStr, inExp); 7500 auto checkBlock = toAst<Block_t>(blockStr, inExp);
7001 block->statements.dup(checkBlock->statements); 7501 block->statementOrComments.dup(checkBlock->statementOrComments);
7002 auto body = x->new_ptr<Body_t>(); 7502 auto body = x->new_ptr<Body_t>();
7003 body->content.set(block); 7503 body->content.set(block);
7004 auto doNode = x->new_ptr<Do_t>(); 7504 auto doNode = x->new_ptr<Do_t>();
@@ -7018,16 +7518,16 @@ private:
7018 } else { 7518 } else {
7019 auto arrayCheck = [&](bool exist) { 7519 auto arrayCheck = [&](bool exist) {
7020 auto indexVar = getUnusedName("_index_"); 7520 auto indexVar = getUnusedName("_index_");
7021 _buf << indent() << "for "sv << indexVar << " = 1, #"sv << checkVar << " do"sv << nll(x); 7521 _buf << indent() << "for "sv << indexVar << " = 1, #"sv << checkVar << " do"sv << nl(x);
7022 incIndentOffset(); 7522 incIndentOffset();
7023 _buf << indent() << "if "sv << checkVar << '[' << indexVar << "] == "sv << varName << " then"sv << nll(x); 7523 _buf << indent() << "if "sv << checkVar << '[' << indexVar << "] == "sv << varName << " then"sv << nl(x);
7024 incIndentOffset(); 7524 incIndentOffset();
7025 _buf << indent() << "return "sv << (exist ? "true"sv : "false"sv) << nll(x); 7525 _buf << indent() << "return "sv << (exist ? "true"sv : "false"sv) << nl(x);
7026 decIndentOffset(); 7526 decIndentOffset();
7027 _buf << indent() << "end"sv << nll(x); 7527 _buf << indent() << "end"sv << nl(x);
7028 decIndentOffset(); 7528 decIndentOffset();
7029 _buf << indent() << "end"sv << nll(x); 7529 _buf << indent() << "end"sv << nl(x);
7030 _buf << indent() << "return "sv << (exist ? "false"sv : "true"sv) << nll(x); 7530 _buf << indent() << "return "sv << (exist ? "false"sv : "true"sv) << nl(x);
7031 temp.push_back(clearBuf()); 7531 temp.push_back(clearBuf());
7032 }; 7532 };
7033 bool useShortCheck = (usage == ExpUsage::Closure) && !varName.empty() && !checkVar.empty() && isLocal(checkVar); 7533 bool useShortCheck = (usage == ExpUsage::Closure) && !varName.empty() && !checkVar.empty() && isLocal(checkVar);
@@ -7043,7 +7543,7 @@ private:
7043 pushAnonVarArg(); 7543 pushAnonVarArg();
7044 pushScope(); 7544 pushScope();
7045 arrayCheck(true); 7545 arrayCheck(true);
7046 temp.push_front("(#"s + checkVar + " > 0 and "s + anonFuncStart() + nll(x)); 7546 temp.push_front("(#"s + checkVar + " > 0 and "s + anonFuncStart() + nl(x));
7047 popScope(); 7547 popScope();
7048 temp.push_back(indent() + anonFuncEnd() + ')'); 7548 temp.push_back(indent() + anonFuncEnd() + ')');
7049 if (unary_exp->inExp->not_) { 7549 if (unary_exp->inExp->not_) {
@@ -7080,7 +7580,7 @@ private:
7080 arrayCheck(!unary_exp->inExp->not_); 7580 arrayCheck(!unary_exp->inExp->not_);
7081 } else { 7581 } else {
7082 arrayCheck(!unary_exp->inExp->not_); 7582 arrayCheck(!unary_exp->inExp->not_);
7083 temp.push_front(anonFuncStart() + nll(x)); 7583 temp.push_front(anonFuncStart() + nl(x));
7084 popScope(); 7584 popScope();
7085 temp.push_back(indent() + anonFuncEnd()); 7585 temp.push_back(indent() + anonFuncEnd());
7086 popAnonVarArg(); 7586 popAnonVarArg();
@@ -7120,7 +7620,7 @@ private:
7120 pushScope(); 7620 pushScope();
7121 } else if (usage == ExpUsage::Assignment) { 7621 } else if (usage == ExpUsage::Assignment) {
7122 if (isScoped) { 7622 if (isScoped) {
7123 temp.push_back(indent() + "do"s + nll(x)); 7623 temp.push_back(indent() + "do"s + nl(x));
7124 pushScope(); 7624 pushScope();
7125 } 7625 }
7126 } 7626 }
@@ -7160,10 +7660,10 @@ private:
7160 if (unary_exp->inExp->not_) { 7660 if (unary_exp->inExp->not_) {
7161 _buf << ")"sv; 7661 _buf << ")"sv;
7162 } 7662 }
7163 _buf << nll(x); 7663 _buf << nl(x);
7164 temp.push_back(clearBuf()); 7664 temp.push_back(clearBuf());
7165 if (usage == ExpUsage::Closure) { 7665 if (usage == ExpUsage::Closure) {
7166 temp.push_front(anonFuncStart() + nll(x)); 7666 temp.push_front(anonFuncStart() + nl(x));
7167 popScope(); 7667 popScope();
7168 temp.push_back(indent() + anonFuncEnd()); 7668 temp.push_back(indent() + anonFuncEnd());
7169 out.push_back(join(temp)); 7669 out.push_back(join(temp));
@@ -7172,7 +7672,7 @@ private:
7172 } else if (usage == ExpUsage::Assignment) { 7672 } else if (usage == ExpUsage::Assignment) {
7173 if (isScoped) { 7673 if (isScoped) {
7174 popScope(); 7674 popScope();
7175 temp.push_back(indent() + "end"s + nll(x)); 7675 temp.push_back(indent() + "end"s + nl(x));
7176 } 7676 }
7177 out.push_back(join(temp)); 7677 out.push_back(join(temp));
7178 } else { 7678 } else {
@@ -7206,7 +7706,7 @@ private:
7206 } 7706 }
7207 _buf << ')'; 7707 _buf << ')';
7208 if (usage == ExpUsage::Assignment || usage == ExpUsage::Return) { 7708 if (usage == ExpUsage::Assignment || usage == ExpUsage::Return) {
7209 _buf << nll(discrete); 7709 _buf << nl(discrete);
7210 } 7710 }
7211 out.push_back(clearBuf()); 7711 out.push_back(clearBuf());
7212 } 7712 }
@@ -7326,7 +7826,7 @@ private:
7326 forceAddToScope(tableVar); 7826 forceAddToScope(tableVar);
7327 auto it = values.begin(); 7827 auto it = values.begin();
7328 if (ast_is<SpreadExp_t, SpreadListExp_t>(*it)) { 7828 if (ast_is<SpreadExp_t, SpreadListExp_t>(*it)) {
7329 temp.push_back(indent() + "local "s + tableVar + " = { }"s + nll(x)); 7829 temp.push_back(indent() + "local "s + tableVar + " = { }"s + nl(x));
7330 } else { 7830 } else {
7331 auto initialTab = x->new_ptr<TableLit_t>(); 7831 auto initialTab = x->new_ptr<TableLit_t>();
7332 while (it != values.end() && !ast_is<SpreadExp_t, SpreadListExp_t>(*it)) { 7832 while (it != values.end() && !ast_is<SpreadExp_t, SpreadListExp_t>(*it)) {
@@ -7334,7 +7834,7 @@ private:
7334 ++it; 7834 ++it;
7335 } 7835 }
7336 transformTable(initialTab->values.objects(), temp); 7836 transformTable(initialTab->values.objects(), temp);
7337 temp.back() = indent() + "local "s + tableVar + " = "s + temp.back() + nll(*it); 7837 temp.back() = indent() + "local "s + tableVar + " = "s + temp.back() + nl(*it);
7338 } 7838 }
7339 for (; it != values.end(); ++it) { 7839 for (; it != values.end(); ++it) {
7340 auto item = *it; 7840 auto item = *it;
@@ -7354,14 +7854,14 @@ private:
7354 transformAssignment(assignment, temp); 7854 transformAssignment(assignment, temp);
7355 } 7855 }
7356 forceAddToScope(indexVar); 7856 forceAddToScope(indexVar);
7357 temp.push_back(indent() + "local "s + indexVar + " = 1"s + nll(item)); 7857 temp.push_back(indent() + "local "s + indexVar + " = 1"s + nl(item));
7358 _buf << "for "sv << keyVar << ',' << valueVar << " in pairs "sv << objVar 7858 _buf << "for "sv << keyVar << ',' << valueVar << " in pairs "sv << objVar
7359 << "\n\tif "sv << indexVar << "=="sv << keyVar 7859 << "\n\tif "sv << indexVar << "=="sv << keyVar
7360 << "\n\t\t"sv << tableVar << "[]="sv << valueVar 7860 << "\n\t\t"sv << tableVar << "[]="sv << valueVar
7361 << "\n\t\t"sv << indexVar << "+=1"sv 7861 << "\n\t\t"sv << indexVar << "+=1"sv
7362 << "\n\telse "sv << tableVar << '[' << keyVar << "]="sv << valueVar; 7862 << "\n\telse "sv << tableVar << '[' << keyVar << "]="sv << valueVar;
7363 auto forEach = toAst<ForEach_t>(clearBuf(), item); 7863 auto forNode = toAst<For_t>(clearBuf(), item);
7364 transformForEach(forEach, temp); 7864 transformFor(forNode, temp);
7365 break; 7865 break;
7366 } 7866 }
7367 case id<SpreadListExp_t>(): { 7867 case id<SpreadListExp_t>(): {
@@ -7378,12 +7878,12 @@ private:
7378 transformAssignment(assignment, temp); 7878 transformAssignment(assignment, temp);
7379 } 7879 }
7380 forceAddToScope(indexVar); 7880 forceAddToScope(indexVar);
7381 temp.push_back(indent() + "local "s + indexVar + " = #"s + tableVar + " + 1"s + nll(item)); 7881 temp.push_back(indent() + "local "s + indexVar + " = #"s + tableVar + " + 1"s + nl(item));
7382 _buf << "for "sv << valueVar << " in *"sv << objVar 7882 _buf << "for "sv << valueVar << " in *"sv << objVar
7383 << "\n\t"sv << tableVar << '[' << indexVar << "]="sv << valueVar 7883 << "\n\t"sv << tableVar << '[' << indexVar << "]="sv << valueVar
7384 << "\n\t"sv << indexVar << "+=1"sv; 7884 << "\n\t"sv << indexVar << "+=1"sv;
7385 auto forEach = toAst<ForEach_t>(clearBuf(), item); 7885 auto forNode = toAst<For_t>(clearBuf(), item);
7386 transformForEach(forEach, temp); 7886 transformFor(forNode, temp);
7387 break; 7887 break;
7388 } 7888 }
7389 case id<VariablePair_t>(): 7889 case id<VariablePair_t>():
@@ -7561,9 +8061,9 @@ private:
7561 break; 8061 break;
7562 case ExpUsage::Closure: { 8062 case ExpUsage::Closure: {
7563 out.push_back(join(temp)); 8063 out.push_back(join(temp));
7564 out.back().append(indent() + "return "s + tableVar + nlr(x)); 8064 out.back().append(indent() + "return "s + tableVar + nl(x));
7565 popScope(); 8065 popScope();
7566 out.back().insert(0, anonFuncStart() + nll(x)); 8066 out.back().insert(0, anonFuncStart() + nl(x));
7567 out.back().append(indent() + anonFuncEnd()); 8067 out.back().append(indent() + anonFuncEnd());
7568 popAnonVarArg(); 8068 popAnonVarArg();
7569 popFunctionScope(); 8069 popFunctionScope();
@@ -7579,13 +8079,13 @@ private:
7579 if (extraScope) popScope(); 8079 if (extraScope) popScope();
7580 out.push_back(join(temp)); 8080 out.push_back(join(temp));
7581 if (extraScope) { 8081 if (extraScope) {
7582 out.back() = indent() + "do"s + nll(x) + out.back() + indent() + "end"s + nlr(x); 8082 out.back() = indent() + "do"s + nl(x) + out.back() + indent() + "end"s + nl(x);
7583 } 8083 }
7584 break; 8084 break;
7585 } 8085 }
7586 case ExpUsage::Return: 8086 case ExpUsage::Return:
7587 out.push_back(join(temp)); 8087 out.push_back(join(temp));
7588 out.back().append(indent() + "return "s + tableVar + nlr(x)); 8088 out.back().append(indent() + "return "s + tableVar + nl(x));
7589 break; 8089 break;
7590 default: 8090 default:
7591 break; 8091 break;
@@ -7706,11 +8206,11 @@ private:
7706 default: YUEE("AST node mismatch", item); break; 8206 default: YUEE("AST node mismatch", item); break;
7707 } 8207 }
7708 if (!isMetamethod) { 8208 if (!isMetamethod) {
7709 temp.back() = indent() + (value == values.back() ? temp.back() : temp.back() + ',') + nll(value); 8209 temp.back() = indent() + (value == values.back() ? temp.back() : temp.back() + ',') + nl(value);
7710 } 8210 }
7711 } 8211 }
7712 if (metatable->pairs.empty() && !metatableItem) { 8212 if (metatable->pairs.empty() && !metatableItem) {
7713 out.push_back('{' + nll(x) + join(temp)); 8213 out.push_back('{' + nl(x) + join(temp));
7714 decIndentOffset(); 8214 decIndentOffset();
7715 out.back() += (indent() + '}'); 8215 out.back() += (indent() + '}');
7716 } else { 8216 } else {
@@ -7720,7 +8220,7 @@ private:
7720 decIndentOffset(); 8220 decIndentOffset();
7721 tabStr += "{ }"sv; 8221 tabStr += "{ }"sv;
7722 } else { 8222 } else {
7723 tabStr += ('{' + nll(x) + join(temp)); 8223 tabStr += ('{' + nl(x) + join(temp));
7724 decIndentOffset(); 8224 decIndentOffset();
7725 tabStr += (indent() + '}'); 8225 tabStr += (indent() + '}');
7726 } 8226 }
@@ -7764,18 +8264,18 @@ private:
7764 void transformCompCommon(Comprehension_t* comp, str_list& out) { 8264 void transformCompCommon(Comprehension_t* comp, str_list& out) {
7765 str_list temp; 8265 str_list temp;
7766 auto x = comp; 8266 auto x = comp;
7767 auto compInner = static_cast<CompInner_t*>(comp->items.back()); 8267 auto compFor = static_cast<CompFor_t*>(comp->items.back());
7768 for (auto item : compInner->items.objects()) { 8268 for (auto item : compFor->items.objects()) {
7769 switch (item->get_id()) { 8269 switch (item->get_id()) {
7770 case id<CompForEach_t>(): 8270 case id<CompForEach_t>():
7771 transformCompForEach(static_cast<CompForEach_t*>(item), temp); 8271 transformCompForEach(static_cast<CompForEach_t*>(item), temp);
7772 break; 8272 break;
7773 case id<CompFor_t>(): 8273 case id<CompForNum_t>():
7774 transformCompFor(static_cast<CompFor_t*>(item), temp); 8274 transformCompForNum(static_cast<CompForNum_t*>(item), temp);
7775 break; 8275 break;
7776 case id<Exp_t>(): 8276 case id<Exp_t>():
7777 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure); 8277 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure);
7778 temp.back() = indent() + "if "s + temp.back() + " then"s + nll(item); 8278 temp.back() = indent() + "if "s + temp.back() + " then"s + nl(item);
7779 pushScope(); 8279 pushScope();
7780 break; 8280 break;
7781 default: YUEE("AST node mismatch", item); break; 8281 default: YUEE("AST node mismatch", item); break;
@@ -7795,16 +8295,16 @@ private:
7795 auto value = std::move(temp.back()); 8295 auto value = std::move(temp.back());
7796 temp.pop_back(); 8296 temp.pop_back();
7797 _buf << join(temp) << value; 8297 _buf << join(temp) << value;
7798 for (size_t i = 0; i < compInner->items.objects().size(); ++i) { 8298 for (size_t i = 0; i < compFor->items.objects().size(); ++i) {
7799 popScope(); 8299 popScope();
7800 _buf << indent() << "end"sv << nll(comp); 8300 _buf << indent() << "end"sv << nl(comp);
7801 } 8301 }
7802 out.push_back(clearBuf()); 8302 out.push_back(clearBuf());
7803 } 8303 }
7804 8304
7805 void transformComprehension(Comprehension_t* comp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { 8305 void transformComprehension(Comprehension_t* comp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
7806 auto x = comp; 8306 auto x = comp;
7807 if (comp->items.size() != 2 || !ast_is<CompInner_t>(comp->items.back())) { 8307 if (!isListComp(comp)) {
7808 switch (usage) { 8308 switch (usage) {
7809 case ExpUsage::Assignment: { 8309 case ExpUsage::Assignment: {
7810 auto tableLit = x->new_ptr<TableLit_t>(); 8310 auto tableLit = x->new_ptr<TableLit_t>();
@@ -7843,9 +8343,16 @@ private:
7843 } 8343 }
7844 return; 8344 return;
7845 } 8345 }
7846 auto def = ast_cast<NormalDef_t>(comp->items.front()); 8346 ast_node* value = nullptr;
7847 if (!def || def->defVal) { 8347 bool isSpread = ast_is<SpreadListExp_t>(comp->items.front());
7848 throw CompileError("invalid comprehension expression", comp->items.front()); 8348 if (isSpread) {
8349 value = comp->items.front();
8350 } else {
8351 auto def = ast_cast<NormalDef_t>(comp->items.front());
8352 if (!def || def->defVal) {
8353 throw CompileError("invalid comprehension expression", comp->items.front());
8354 }
8355 value = def->item.get();
7849 } 8356 }
7850 bool extraScope = false; 8357 bool extraScope = false;
7851 switch (usage) { 8358 switch (usage) {
@@ -7869,31 +8376,33 @@ private:
7869 default: 8376 default:
7870 break; 8377 break;
7871 } 8378 }
7872 auto value = def->item.get(); 8379 auto compFor = static_cast<CompFor_t*>(comp->items.back());
7873 auto compInner = static_cast<CompInner_t*>(comp->items.back());
7874 str_list temp; 8380 str_list temp;
7875 std::string accumVar = getUnusedName("_accum_"sv); 8381 std::string accumVar = getUnusedName("_accum_"sv);
7876 std::string lenVar = getUnusedName("_len_"sv);
7877 addToScope(accumVar); 8382 addToScope(accumVar);
7878 addToScope(lenVar); 8383 std::string lenVar;
7879 for (auto item : compInner->items.objects()) { 8384 if (!isSpread) {
8385 lenVar = getUnusedName("_len_"sv);
8386 addToScope(lenVar);
8387 }
8388 for (auto item : compFor->items.objects()) {
7880 switch (item->get_id()) { 8389 switch (item->get_id()) {
7881 case id<CompForEach_t>(): 8390 case id<CompForEach_t>():
7882 transformCompForEach(static_cast<CompForEach_t*>(item), temp); 8391 transformCompForEach(static_cast<CompForEach_t*>(item), temp);
7883 break; 8392 break;
7884 case id<CompFor_t>(): 8393 case id<CompForNum_t>():
7885 transformCompFor(static_cast<CompFor_t*>(item), temp); 8394 transformCompForNum(static_cast<CompForNum_t*>(item), temp);
7886 break; 8395 break;
7887 case id<Exp_t>(): 8396 case id<Exp_t>():
7888 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure); 8397 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure);
7889 temp.back() = indent() + "if "s + temp.back() + " then"s + nll(item); 8398 temp.back() = indent() + "if "s + temp.back() + " then"s + nl(item);
7890 pushScope(); 8399 pushScope();
7891 break; 8400 break;
7892 default: YUEE("AST node mismatch", item); break; 8401 default: YUEE("AST node mismatch", item); break;
7893 } 8402 }
7894 } 8403 }
7895 { 8404 {
7896 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); 8405 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + (isSpread ? "]"s : lenVar + ']'), x);
7897 auto assign = x->new_ptr<Assign_t>(); 8406 auto assign = x->new_ptr<Assign_t>();
7898 assign->values.push_back(value); 8407 assign->values.push_back(value);
7899 auto assignment = x->new_ptr<ExpListAssign_t>(); 8408 auto assignment = x->new_ptr<ExpListAssign_t>();
@@ -7903,25 +8412,30 @@ private:
7903 } 8412 }
7904 auto assignStr = std::move(temp.back()); 8413 auto assignStr = std::move(temp.back());
7905 temp.pop_back(); 8414 temp.pop_back();
7906 for (size_t i = 0; i < compInner->items.objects().size(); ++i) { 8415 for (size_t i = 0; i < compFor->items.objects().size(); ++i) {
7907 popScope(); 8416 popScope();
7908 } 8417 }
7909 _buf << indent() << "local "sv << accumVar << " = { }"sv << nll(comp); 8418 _buf << indent() << "local "sv << accumVar << " = { }"sv << nl(comp);
7910 _buf << indent() << "local "sv << lenVar << " = 1"sv << nll(comp); 8419 if (isSpread) {
7911 _buf << join(temp); 8420 _buf << join(temp);
7912 _buf << assignStr; 8421 _buf << assignStr;
7913 _buf << indent(int(temp.size())) << lenVar << " = "sv << lenVar << " + 1"sv << nll(comp); 8422 } else {
8423 _buf << indent() << "local "sv << lenVar << " = 1"sv << nl(comp);
8424 _buf << join(temp);
8425 _buf << assignStr;
8426 _buf << indent(int(temp.size())) << lenVar << " = "sv << lenVar << " + 1"sv << nl(comp);
8427 }
7914 for (int ind = int(temp.size()) - 1; ind > -1; --ind) { 8428 for (int ind = int(temp.size()) - 1; ind > -1; --ind) {
7915 _buf << indent(ind) << "end"sv << nll(comp); 8429 _buf << indent(ind) << "end"sv << nl(comp);
7916 } 8430 }
7917 switch (usage) { 8431 switch (usage) {
7918 case ExpUsage::Common: 8432 case ExpUsage::Common:
7919 break; 8433 break;
7920 case ExpUsage::Closure: { 8434 case ExpUsage::Closure: {
7921 out.push_back(clearBuf()); 8435 out.push_back(clearBuf());
7922 out.back().append(indent() + "return "s + accumVar + nlr(comp)); 8436 out.back().append(indent() + "return "s + accumVar + nl(comp));
7923 popScope(); 8437 popScope();
7924 out.back().insert(0, anonFuncStart() + nll(comp)); 8438 out.back().insert(0, anonFuncStart() + nl(comp));
7925 out.back().append(indent() + anonFuncEnd()); 8439 out.back().append(indent() + anonFuncEnd());
7926 popAnonVarArg(); 8440 popAnonVarArg();
7927 popFunctionScope(); 8441 popFunctionScope();
@@ -7938,13 +8452,13 @@ private:
7938 out.back().append(temp.back()); 8452 out.back().append(temp.back());
7939 if (extraScope) { 8453 if (extraScope) {
7940 popScope(); 8454 popScope();
7941 out.back() = indent() + "do"s + nll(comp) + out.back() + indent() + "end"s + nlr(comp); 8455 out.back() = indent() + "do"s + nl(comp) + out.back() + indent() + "end"s + nl(comp);
7942 } 8456 }
7943 break; 8457 break;
7944 } 8458 }
7945 case ExpUsage::Return: 8459 case ExpUsage::Return:
7946 out.push_back(clearBuf()); 8460 out.push_back(clearBuf());
7947 out.back().append(indent() + "return "s + accumVar + nlr(comp)); 8461 out.back().append(indent() + "return "s + accumVar + nl(comp));
7948 break; 8462 break;
7949 default: 8463 default:
7950 break; 8464 break;
@@ -7952,6 +8466,11 @@ private:
7952 } 8466 }
7953 8467
7954 bool transformForEachHead(AssignableNameList_t* nameList, ast_node* loopTarget, str_list& out, bool inClosure) { 8468 bool transformForEachHead(AssignableNameList_t* nameList, ast_node* loopTarget, str_list& out, bool inClosure) {
8469 enum class NumState {
8470 Unknown,
8471 Positive,
8472 Negtive
8473 };
7955 auto x = nameList; 8474 auto x = nameList;
7956 str_list temp; 8475 str_list temp;
7957 str_list vars; 8476 str_list vars;
@@ -7970,13 +8489,8 @@ private:
7970 varConstAfter = vars.back(); 8489 varConstAfter = vars.back();
7971 } 8490 }
7972 break; 8491 break;
7973 case id<TableLit_t>(): { 8492 case id<SimpleTable_t>():
7974 auto desVar = getUnusedName("_des_"sv); 8493 case id<TableLit_t>():
7975 destructPairs.emplace_back(item, toAst<Exp_t>(desVar, x));
7976 vars.push_back(desVar);
7977 varAfter.push_back(desVar);
7978 break;
7979 }
7980 case id<Comprehension_t>(): { 8494 case id<Comprehension_t>(): {
7981 auto desVar = getUnusedName("_des_"sv); 8495 auto desVar = getUnusedName("_des_"sv);
7982 destructPairs.emplace_back(item, toAst<Exp_t>(desVar, x)); 8496 destructPairs.emplace_back(item, toAst<Exp_t>(desVar, x));
@@ -8018,15 +8532,35 @@ private:
8018 for (auto item : chainList) { 8532 for (auto item : chainList) {
8019 chain->items.push_back(item); 8533 chain->items.push_back(item);
8020 } 8534 }
8021 std::string startValue("1"sv); 8535 std::string startValue;
8536 NumState startStatus = NumState::Unknown;
8022 if (auto exp = slice->startValue.as<Exp_t>()) { 8537 if (auto exp = slice->startValue.as<Exp_t>()) {
8023 transformExp(exp, temp, ExpUsage::Closure); 8538 transformExp(exp, temp, ExpUsage::Closure);
8539 if (temp.back().at(0) == '-') {
8540 if (_parser.match<Num_t>(temp.back().substr(1))) {
8541 startStatus = NumState::Negtive;
8542 }
8543 } else {
8544 if (_parser.match<Num_t>(temp.back())) {
8545 startStatus = NumState::Positive;
8546 }
8547 }
8024 startValue = std::move(temp.back()); 8548 startValue = std::move(temp.back());
8025 temp.pop_back(); 8549 temp.pop_back();
8026 } 8550 }
8027 std::string stopValue; 8551 std::string stopValue;
8552 NumState stopStatus = NumState::Unknown;
8028 if (auto exp = slice->stopValue.as<Exp_t>()) { 8553 if (auto exp = slice->stopValue.as<Exp_t>()) {
8029 transformExp(exp, temp, ExpUsage::Closure); 8554 transformExp(exp, temp, ExpUsage::Closure);
8555 if (temp.back().at(0) == '-') {
8556 if (_parser.match<Num_t>(temp.back().substr(1))) {
8557 stopStatus = NumState::Negtive;
8558 }
8559 } else {
8560 if (_parser.match<Num_t>(temp.back())) {
8561 stopStatus = NumState::Positive;
8562 }
8563 }
8030 stopValue = std::move(temp.back()); 8564 stopValue = std::move(temp.back());
8031 temp.pop_back(); 8565 temp.pop_back();
8032 } 8566 }
@@ -8040,38 +8574,94 @@ private:
8040 std::string prefix; 8574 std::string prefix;
8041 if (!inClosure && needScope) { 8575 if (!inClosure && needScope) {
8042 extraScope = true; 8576 extraScope = true;
8043 prefix = indent() + "do"s + nll(x); 8577 prefix = indent() + "do"s + nl(x);
8044 pushScope(); 8578 pushScope();
8045 } 8579 }
8046 listVar = getUnusedName("_list_"sv); 8580 listVar = getUnusedName("_list_"sv);
8047 varBefore.push_back(listVar); 8581 varBefore.push_back(listVar);
8048 transformChainValue(chain, temp, ExpUsage::Closure); 8582 transformChainValue(chain, temp, ExpUsage::Closure);
8049 _buf << prefix << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList); 8583 _buf << prefix << indent() << "local "sv << listVar << " = "sv << temp.back() << nl(nameList);
8584 }
8585 if (startValue.empty()) {
8586 startValue = "1"s;
8587 startStatus = NumState::Positive;
8588 }
8589 std::string minVar;
8590 if (startStatus != NumState::Positive) {
8591 std::string prefix;
8592 if (!extraScope && !inClosure && needScope) {
8593 extraScope = true;
8594 prefix = indent() + "do"s + nl(x);
8595 pushScope();
8596 }
8597 minVar = getUnusedName("_min_"sv);
8598 varBefore.push_back(minVar);
8599 if (startStatus == NumState::Negtive) {
8600 _buf << prefix << indent() << "local "sv << minVar << " = "sv << "#"sv << listVar << " + "sv << startValue << " + 1"sv << nl(nameList);
8601 } else {
8602 _buf << prefix << indent() << "local "sv << minVar << " = "sv << startValue << nl(nameList);
8603 }
8604 }
8605 bool defaultStop = false;
8606 if (stopValue.empty()) {
8607 stopValue = "#"s + listVar;
8608 defaultStop = true;
8050 } 8609 }
8051 std::string maxVar; 8610 std::string maxVar;
8052 if (!stopValue.empty()) { 8611 if (stopStatus != NumState::Positive) {
8053 std::string prefix; 8612 std::string prefix;
8054 if (!extraScope && !inClosure && needScope) { 8613 if (!extraScope && !inClosure && needScope) {
8055 extraScope = true; 8614 extraScope = true;
8056 prefix = indent() + "do"s + nll(x); 8615 prefix = indent() + "do"s + nl(x);
8057 pushScope(); 8616 pushScope();
8058 } 8617 }
8059 maxVar = getUnusedName("_max_"sv); 8618 maxVar = getUnusedName("_max_"sv);
8060 varBefore.push_back(maxVar); 8619 varBefore.push_back(maxVar);
8061 _buf << prefix << indent() << "local "sv << maxVar << " = "sv << stopValue << nll(nameList); 8620 if (stopStatus == NumState::Negtive) {
8621 _buf << indent() << "local "sv << maxVar << " = "sv << "#"sv << listVar << " + "sv << stopValue << " + 1"sv << nl(nameList);
8622 } else {
8623 _buf << prefix << indent() << "local "sv << maxVar << " = "sv << stopValue << nl(nameList);
8624 }
8625 }
8626 if (startStatus == NumState::Unknown) {
8627 _buf << indent() << minVar << " = "sv << minVar << " < 0 and #"sv << listVar << " + "sv << minVar << " + 1 or "sv << minVar << nl(nameList);
8628 }
8629 if (!defaultStop && stopStatus == NumState::Unknown) {
8630 _buf << indent() << maxVar << " = "sv << maxVar << " < 0 and #"sv << listVar << " + "sv << maxVar << " + 1 or "sv << maxVar << nl(nameList);
8062 } 8631 }
8063 _buf << indent() << "for "sv << indexVar << " = "sv; 8632 _buf << indent() << "for "sv << indexVar << " = "sv;
8064 _buf << startValue << ", "sv; 8633 if (startValue.empty()) {
8634 _buf << "1"sv;
8635 } else {
8636 switch (startStatus) {
8637 case NumState::Unknown:
8638 case NumState::Negtive:
8639 _buf << minVar;
8640 break;
8641 case NumState::Positive:
8642 _buf << startValue;
8643 break;
8644 }
8645 }
8646 _buf << ", "sv;
8065 if (stopValue.empty()) { 8647 if (stopValue.empty()) {
8066 _buf << "#"sv << listVar; 8648 _buf << "#"sv << listVar;
8067 } else { 8649 } else {
8068 _buf << maxVar << " < 0 and #"sv << listVar << " + "sv << maxVar << " or "sv << maxVar; 8650 switch (stopStatus) {
8651 case NumState::Unknown:
8652 case NumState::Negtive:
8653 _buf << maxVar;
8654 break;
8655 case NumState::Positive:
8656 _buf << stopValue;
8657 break;
8658 }
8069 } 8659 }
8070 if (!stepValue.empty()) { 8660 if (!stepValue.empty()) {
8071 _buf << ", "sv << stepValue; 8661 _buf << ", "sv << stepValue;
8072 } 8662 }
8073 _buf << " do"sv << nlr(loopTarget); 8663 _buf << " do"sv << nl(loopTarget);
8074 _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nll(nameList); 8664 _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nl(nameList);
8075 out.push_back(clearBuf()); 8665 out.push_back(clearBuf());
8076 BLOCK_END 8666 BLOCK_END
8077 bool newListVal = false; 8667 bool newListVal = false;
@@ -8082,21 +8672,21 @@ private:
8082 } 8672 }
8083 if (!endWithSlice) { 8673 if (!endWithSlice) {
8084 transformExp(star_exp->value, temp, ExpUsage::Closure); 8674 transformExp(star_exp->value, temp, ExpUsage::Closure);
8085 if (newListVal) _buf << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList); 8675 if (newListVal) _buf << indent() << "local "sv << listVar << " = "sv << temp.back() << nl(nameList);
8086 _buf << indent() << "for "sv << indexVar << " = 1, #"sv << listVar << " do"sv << nlr(loopTarget); 8676 _buf << indent() << "for "sv << indexVar << " = 1, #"sv << listVar << " do"sv << nl(loopTarget);
8087 _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nll(nameList); 8677 _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nl(nameList);
8088 out.push_back(clearBuf()); 8678 out.push_back(clearBuf());
8089 } 8679 }
8090 break; 8680 break;
8091 } 8681 }
8092 case id<Exp_t>(): 8682 case id<Exp_t>():
8093 transformExp(static_cast<Exp_t*>(loopTarget), temp, ExpUsage::Closure); 8683 transformExp(static_cast<Exp_t*>(loopTarget), temp, ExpUsage::Closure);
8094 _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nlr(loopTarget); 8684 _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nl(loopTarget);
8095 out.push_back(clearBuf()); 8685 out.push_back(clearBuf());
8096 break; 8686 break;
8097 case id<ExpList_t>(): 8687 case id<ExpList_t>():
8098 transformExpList(static_cast<ExpList_t*>(loopTarget), temp); 8688 transformExpList(static_cast<ExpList_t*>(loopTarget), temp);
8099 _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nlr(loopTarget); 8689 _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nl(loopTarget);
8100 out.push_back(clearBuf()); 8690 out.push_back(clearBuf());
8101 break; 8691 break;
8102 default: YUEE("AST node mismatch", loopTarget); break; 8692 default: YUEE("AST node mismatch", loopTarget); break;
@@ -8109,11 +8699,18 @@ private:
8109 if (!destructPairs.empty()) { 8699 if (!destructPairs.empty()) {
8110 temp.clear(); 8700 temp.clear();
8111 for (auto& pair : destructPairs) { 8701 for (auto& pair : destructPairs) {
8112 auto sValue = x->new_ptr<SimpleValue_t>();
8113 sValue->value.set(pair.first);
8114 auto exp = newExp(sValue, x);
8115 auto expList = x->new_ptr<ExpList_t>(); 8702 auto expList = x->new_ptr<ExpList_t>();
8116 expList->exprs.push_back(exp); 8703 if (ast_is<SimpleTable_t>(pair.first)) {
8704 auto value = x->new_ptr<Value_t>();
8705 value->item.set(pair.first);
8706 auto exp = newExp(value, x);
8707 expList->exprs.push_back(exp);
8708 } else {
8709 auto sValue = x->new_ptr<SimpleValue_t>();
8710 sValue->value.set(pair.first);
8711 auto exp = newExp(sValue, x);
8712 expList->exprs.push_back(exp);
8713 }
8117 auto assign = x->new_ptr<Assign_t>(); 8714 auto assign = x->new_ptr<Assign_t>();
8118 assign->values.push_back(pair.second); 8715 assign->values.push_back(pair.second);
8119 auto assignment = x->new_ptr<ExpListAssign_t>(); 8716 auto assignment = x->new_ptr<ExpListAssign_t>();
@@ -8173,7 +8770,7 @@ private:
8173 out.push_back('(' + join(temp, ", "sv) + ')'); 8770 out.push_back('(' + join(temp, ", "sv) + ')');
8174 } 8771 }
8175 8772
8176 void transformForHead(Variable_t* var, Exp_t* startVal, Exp_t* stopVal, ForStepValue_t* stepVal, str_list& out) { 8773 void transformForNumHead(Variable_t* var, Exp_t* startVal, Exp_t* stopVal, ForStepValue_t* stepVal, str_list& out) {
8177 str_list temp; 8774 str_list temp;
8178 std::string varName = variableToString(var); 8775 std::string varName = variableToString(var);
8179 transformExp(startVal, temp, ExpUsage::Closure); 8776 transformExp(startVal, temp, ExpUsage::Closure);
@@ -8187,15 +8784,15 @@ private:
8187 const auto& start = *it; 8784 const auto& start = *it;
8188 const auto& stop = *(++it); 8785 const auto& stop = *(++it);
8189 const auto& step = *(++it); 8786 const auto& step = *(++it);
8190 _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : ", "s + step) << " do"sv << nll(var); 8787 _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : ", "s + step) << " do"sv << nl(var);
8191 pushScope(); 8788 pushScope();
8192 forceAddToScope(varName); 8789 forceAddToScope(varName);
8193 markVarLocalConst(varName); 8790 markVarLocalConst(varName);
8194 out.push_back(clearBuf()); 8791 out.push_back(clearBuf());
8195 } 8792 }
8196 8793
8197 void transformForHead(For_t* forNode, str_list& out) { 8794 void transformForNumHead(ForNum_t* forNum, str_list& out) {
8198 transformForHead(forNode->varName, forNode->startValue, forNode->stopValue, forNode->stepValue, out); 8795 transformForNumHead(forNum->varName, forNum->startValue, forNum->stopValue, forNum->stepValue, out);
8199 } 8796 }
8200 8797
8201 void transform_plain_body(ast_node* bodyOrStmt, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { 8798 void transform_plain_body(ast_node* bodyOrStmt, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
@@ -8205,7 +8802,7 @@ private:
8205 break; 8802 break;
8206 case id<Statement_t>(): { 8803 case id<Statement_t>(): {
8207 auto newBlock = bodyOrStmt->new_ptr<Block_t>(); 8804 auto newBlock = bodyOrStmt->new_ptr<Block_t>();
8208 newBlock->statements.push_back(bodyOrStmt); 8805 newBlock->statementOrComments.push_back(bodyOrStmt);
8209 transformBlock(newBlock, out, usage, assignList); 8806 transformBlock(newBlock, out, usage, assignList);
8210 break; 8807 break;
8211 } 8808 }
@@ -8302,9 +8899,9 @@ private:
8302 } 8899 }
8303 8900
8304 void addDoToLastLineReturn(ast_node* body) { 8901 void addDoToLastLineReturn(ast_node* body) {
8305 if (auto block = ast_cast<Block_t>(body); block && !block->statements.empty()) { 8902 if (auto block = ast_cast<Block_t>(body); block && !block->statementOrComments.empty()) {
8306 auto last = static_cast<Statement_t*>(block->statements.back()); 8903 auto last = lastStatementFrom(block);
8307 if (last->content.is<Return_t>()) { 8904 if (last && last->content.is<Return_t>()) {
8308 auto doNode = last->new_ptr<Do_t>(); 8905 auto doNode = last->new_ptr<Do_t>();
8309 auto newBody = last->new_ptr<Body_t>(); 8906 auto newBody = last->new_ptr<Body_t>();
8310 auto newStmt = last->new_ptr<Statement_t>(); 8907 auto newStmt = last->new_ptr<Statement_t>();
@@ -8331,8 +8928,8 @@ private:
8331 if (withContinue) { 8928 if (withContinue) {
8332 if (target < 502) { 8929 if (target < 502) {
8333 if (auto block = ast_cast<Block_t>(body)) { 8930 if (auto block = ast_cast<Block_t>(body)) {
8334 if (!block->statements.empty()) { 8931 if (!block->statementOrComments.empty()) {
8335 auto stmt = static_cast<Statement_t*>(block->statements.back()); 8932 auto stmt = lastStatementFrom(block);
8336 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { 8933 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) {
8337 extraDo = breakLoop->type.is<Break_t>(); 8934 extraDo = breakLoop->type.is<Break_t>();
8338 } 8935 }
@@ -8341,11 +8938,11 @@ private:
8341 auto continueVar = getUnusedName("_continue_"sv); 8938 auto continueVar = getUnusedName("_continue_"sv);
8342 addToScope(continueVar); 8939 addToScope(continueVar);
8343 _continueVars.push({continueVar, nullptr}); 8940 _continueVars.push({continueVar, nullptr});
8344 _buf << indent() << "local "sv << continueVar << " = false"sv << nll(body); 8941 _buf << indent() << "local "sv << continueVar << " = false"sv << nl(body);
8345 _buf << indent() << "repeat"sv << nll(body); 8942 _buf << indent() << "repeat"sv << nl(body);
8346 pushScope(); 8943 pushScope();
8347 if (extraDo) { 8944 if (extraDo) {
8348 _buf << indent() << "do"sv << nll(body); 8945 _buf << indent() << "do"sv << nl(body);
8349 pushScope(); 8946 pushScope();
8350 } 8947 }
8351 temp.push_back(clearBuf()); 8948 temp.push_back(clearBuf());
@@ -8365,14 +8962,14 @@ private:
8365 if (target < 502) { 8962 if (target < 502) {
8366 if (extraDo) { 8963 if (extraDo) {
8367 popScope(); 8964 popScope();
8368 _buf << indent() << "end"sv << nll(body); 8965 _buf << indent() << "end"sv << nl(body);
8369 } 8966 }
8370 _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); 8967 _buf << indent() << _continueVars.top().var << " = true"sv << nl(body);
8371 popScope(); 8968 popScope();
8372 _buf << indent() << "until true"sv << nlr(body); 8969 _buf << indent() << "until true"sv << nl(body);
8373 _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nlr(body); 8970 _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nl(body);
8374 _buf << indent(1) << "break"sv << nlr(body); 8971 _buf << indent(1) << "break"sv << nl(body);
8375 _buf << indent() << "end"sv << nlr(body); 8972 _buf << indent() << "end"sv << nl(body);
8376 temp.push_back(clearBuf()); 8973 temp.push_back(clearBuf());
8377 _continueVars.pop(); 8974 _continueVars.pop();
8378 } else { 8975 } else {
@@ -8386,7 +8983,7 @@ private:
8386 std::string transformRepeatBody(Repeat_t* repeatNode, str_list& out) { 8983 std::string transformRepeatBody(Repeat_t* repeatNode, str_list& out) {
8387 str_list temp; 8984 str_list temp;
8388 bool extraDo = false; 8985 bool extraDo = false;
8389 auto body = repeatNode->body->content.get(); 8986 auto body = repeatNode->body.get();
8390 auto breakLoopType = getBreakLoopType(body, Empty); 8987 auto breakLoopType = getBreakLoopType(body, Empty);
8391 bool withContinue = hasContinue(breakLoopType); 8988 bool withContinue = hasContinue(breakLoopType);
8392 std::string conditionVar; 8989 std::string conditionVar;
@@ -8396,8 +8993,8 @@ private:
8396 if (withContinue) { 8993 if (withContinue) {
8397 if (target < 502) { 8994 if (target < 502) {
8398 if (auto block = ast_cast<Block_t>(body)) { 8995 if (auto block = ast_cast<Block_t>(body)) {
8399 if (!block->statements.empty()) { 8996 if (!block->statementOrComments.empty()) {
8400 auto stmt = static_cast<Statement_t*>(block->statements.back()); 8997 auto stmt = lastStatementFrom(block);
8401 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { 8998 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) {
8402 extraDo = breakLoop->type.is<Break_t>(); 8999 extraDo = breakLoop->type.is<Break_t>();
8403 } 9000 }
@@ -8414,12 +9011,12 @@ private:
8414 assign->values.push_back(repeatNode->condition); 9011 assign->values.push_back(repeatNode->condition);
8415 _continueVars.push({continueVar, assignment.get()}); 9012 _continueVars.push({continueVar, assignment.get()});
8416 } 9013 }
8417 _buf << indent() << "local "sv << conditionVar << " = false"sv << nll(body); 9014 _buf << indent() << "local "sv << conditionVar << " = false"sv << nl(body);
8418 _buf << indent() << "local "sv << continueVar << " = false"sv << nll(body); 9015 _buf << indent() << "local "sv << continueVar << " = false"sv << nl(body);
8419 _buf << indent() << "repeat"sv << nll(body); 9016 _buf << indent() << "repeat"sv << nl(body);
8420 pushScope(); 9017 pushScope();
8421 if (extraDo) { 9018 if (extraDo) {
8422 _buf << indent() << "do"sv << nll(body); 9019 _buf << indent() << "do"sv << nl(body);
8423 pushScope(); 9020 pushScope();
8424 } 9021 }
8425 temp.push_back(clearBuf()); 9022 temp.push_back(clearBuf());
@@ -8440,14 +9037,14 @@ private:
8440 transformAssignment(_continueVars.top().condAssign, temp); 9037 transformAssignment(_continueVars.top().condAssign, temp);
8441 if (extraDo) { 9038 if (extraDo) {
8442 popScope(); 9039 popScope();
8443 _buf << indent() << "end"sv << nll(body); 9040 _buf << indent() << "end"sv << nl(body);
8444 } 9041 }
8445 _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); 9042 _buf << indent() << _continueVars.top().var << " = true"sv << nl(body);
8446 popScope(); 9043 popScope();
8447 _buf << indent() << "until true"sv << nlr(body); 9044 _buf << indent() << "until true"sv << nl(body);
8448 _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nlr(body); 9045 _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nl(body);
8449 _buf << indent(1) << "break"sv << nlr(body); 9046 _buf << indent(1) << "break"sv << nl(body);
8450 _buf << indent() << "end"sv << nlr(body); 9047 _buf << indent() << "end"sv << nl(body);
8451 temp.push_back(clearBuf()); 9048 temp.push_back(clearBuf());
8452 _continueVars.pop(); 9049 _continueVars.pop();
8453 } else { 9050 } else {
@@ -8459,46 +9056,48 @@ private:
8459 return conditionVar; 9056 return conditionVar;
8460 } 9057 }
8461 9058
8462 void transformFor(For_t* forNode, str_list& out) { 9059 void transformForNum(ForNum_t* forNum, str_list& out) {
8463 str_list temp; 9060 str_list temp;
8464 transformForHead(forNode, temp); 9061 transformForNumHead(forNum, temp);
8465 auto breakLoopType = getBreakLoopType(forNode->body, Empty); 9062 auto breakLoopType = getBreakLoopType(forNum->body, Empty);
8466 transformLoopBody(forNode->body, temp, breakLoopType, ExpUsage::Common); 9063 transformLoopBody(forNum->body, temp, breakLoopType, ExpUsage::Common);
8467 popScope(); 9064 popScope();
8468 out.push_back(join(temp) + indent() + "end"s + nlr(forNode)); 9065 out.push_back(join(temp) + indent() + "end"s + nl(forNum));
8469 } 9066 }
8470 9067
8471 std::string transformForInner(For_t* forNode, str_list& out) { 9068 std::string transformForNumInner(ForNum_t* forNum, str_list& out) {
8472 auto x = forNode; 9069 auto x = forNum;
8473 std::string accum = getUnusedName("_accum_"sv); 9070 std::string accum = getUnusedName("_accum_"sv);
8474 addToScope(accum); 9071 addToScope(accum);
8475 std::string len = getUnusedName("_len_"sv); 9072 std::string len = getUnusedName("_len_"sv);
8476 addToScope(len); 9073 addToScope(len);
8477 auto breakLoopType = getBreakLoopType(forNode->body, accum); 9074 auto breakLoopType = getBreakLoopType(forNum->body, accum);
8478 _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(forNode); 9075 _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(forNum);
8479 out.emplace_back(clearBuf()); 9076 out.emplace_back(clearBuf());
8480 _buf << indent() << "local "sv << len << " = 1"sv << nll(forNode); 9077 _buf << indent() << "local "sv << len << " = 1"sv << nl(forNum);
8481 auto& lenAssign = out.emplace_back(clearBuf()); 9078 auto& lenAssign = out.emplace_back(clearBuf());
8482 transformForHead(forNode, out); 9079 transformForNumHead(forNum, out);
8483 if (hasBreakWithValue(breakLoopType)) { 9080 if (hasBreakWithValue(breakLoopType)) {
8484 lenAssign.clear(); 9081 lenAssign.clear();
8485 transformLoopBody(forNode->body, out, breakLoopType, ExpUsage::Common); 9082 transformLoopBody(forNum->body, out, breakLoopType, ExpUsage::Common);
8486 } else { 9083 } else {
8487 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); 9084 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x);
8488 auto followStmt = toAst<Statement_t>(len + "+=1"s, forNode->body); 9085 auto followStmt = toAst<Statement_t>(len + "+=1"s, forNum->body);
8489 expList->followStmt = followStmt.get(); 9086 expList->followStmt = followStmt.get();
8490 transformLoopBody(forNode->body, out, breakLoopType, ExpUsage::Assignment, expList); 9087 transformLoopBody(forNum->body, out, breakLoopType, ExpUsage::Assignment, expList);
8491 if (!expList->followStmtProcessed) { 9088 if (!expList->followStmtProcessed) {
8492 lenAssign.clear(); 9089 lenAssign.clear();
8493 } 9090 }
8494 } 9091 }
8495 popScope(); 9092 popScope();
8496 out.push_back(indent() + "end"s + nlr(forNode)); 9093 out.push_back(indent() + "end"s + nl(forNum));
8497 return accum; 9094 return accum;
8498 } 9095 }
8499 9096
8500 void transformForClosure(For_t* forNode, str_list& out) { 9097 void transformForNumClosure(ForNum_t* forNum, str_list& out) {
8501 auto simpleValue = forNode->new_ptr<SimpleValue_t>(); 9098 auto forNode = forNum->new_ptr<For_t>();
9099 forNode->forLoop.set(forNum);
9100 auto simpleValue = forNum->new_ptr<SimpleValue_t>();
8502 simpleValue->value.set(forNode); 9101 simpleValue->value.set(forNode);
8503 if (transformAsUpValueFunc(newExp(simpleValue, forNode), out)) { 9102 if (transformAsUpValueFunc(newExp(simpleValue, forNode), out)) {
8504 return; 9103 return;
@@ -8508,26 +9107,26 @@ private:
8508 pushAnonVarArg(); 9107 pushAnonVarArg();
8509 std::string& funcStart = temp.emplace_back(); 9108 std::string& funcStart = temp.emplace_back();
8510 pushScope(); 9109 pushScope();
8511 auto accum = transformForInner(forNode, temp); 9110 auto accum = transformForNumInner(forNum, temp);
8512 temp.push_back(indent() + "return "s + accum + nlr(forNode)); 9111 temp.push_back(indent() + "return "s + accum + nl(forNum));
8513 popScope(); 9112 popScope();
8514 funcStart = anonFuncStart() + nll(forNode); 9113 funcStart = anonFuncStart() + nl(forNum);
8515 temp.push_back(indent() + anonFuncEnd()); 9114 temp.push_back(indent() + anonFuncEnd());
8516 popAnonVarArg(); 9115 popAnonVarArg();
8517 popFunctionScope(); 9116 popFunctionScope();
8518 out.push_back(join(temp)); 9117 out.push_back(join(temp));
8519 } 9118 }
8520 9119
8521 void transformForInPlace(For_t* forNode, str_list& out, ExpList_t* assignExpList = nullptr) { 9120 void transformForNumInPlace(ForNum_t* forNum, str_list& out, ExpList_t* assignExpList) {
8522 auto x = forNode; 9121 auto x = forNum;
8523 str_list temp; 9122 str_list temp;
8524 bool isScoped = !currentScope().lastStatement; 9123 bool isScoped = !currentScope().lastStatement;
8525 if (assignExpList) { 9124 if (assignExpList) {
8526 if (isScoped) { 9125 if (isScoped) {
8527 _buf << indent() << "do"sv << nll(forNode); 9126 _buf << indent() << "do"sv << nl(forNum);
8528 pushScope(); 9127 pushScope();
8529 } 9128 }
8530 auto accum = transformForInner(forNode, temp); 9129 auto accum = transformForNumInner(forNum, temp);
8531 auto assign = x->new_ptr<Assign_t>(); 9130 auto assign = x->new_ptr<Assign_t>();
8532 assign->values.push_back(toAst<Exp_t>(accum, x)); 9131 assign->values.push_back(toAst<Exp_t>(accum, x));
8533 auto assignment = x->new_ptr<ExpListAssign_t>(); 9132 auto assignment = x->new_ptr<ExpListAssign_t>();
@@ -8536,10 +9135,10 @@ private:
8536 transformAssignment(assignment, temp); 9135 transformAssignment(assignment, temp);
8537 if (isScoped) { 9136 if (isScoped) {
8538 popScope(); 9137 popScope();
8539 temp.push_back(indent() + "end"s + nlr(forNode)); 9138 temp.push_back(indent() + "end"s + nl(forNum));
8540 } 9139 }
8541 } else { 9140 } else {
8542 auto accum = transformForInner(forNode, temp); 9141 auto accum = transformForNumInner(forNum, temp);
8543 auto returnNode = x->new_ptr<Return_t>(); 9142 auto returnNode = x->new_ptr<Return_t>();
8544 returnNode->explicitReturn = false; 9143 returnNode->explicitReturn = false;
8545 auto expListLow = toAst<ExpListLow_t>(accum, x); 9144 auto expListLow = toAst<ExpListLow_t>(accum, x);
@@ -8573,10 +9172,10 @@ private:
8573 auto breakLoopType = getBreakLoopType(forEach->body, Empty); 9172 auto breakLoopType = getBreakLoopType(forEach->body, Empty);
8574 transformLoopBody(forEach->body, temp, breakLoopType, ExpUsage::Common); 9173 transformLoopBody(forEach->body, temp, breakLoopType, ExpUsage::Common);
8575 popScope(); 9174 popScope();
8576 out.push_back(temp.front() + temp.back() + indent() + "end"s + nlr(forEach)); 9175 out.push_back(temp.front() + temp.back() + indent() + "end"s + nl(forEach));
8577 if (extraScoped) { 9176 if (extraScoped) {
8578 popScope(); 9177 popScope();
8579 out.back().append(indent() + "end"s + nlr(forEach)); 9178 out.back().append(indent() + "end"s + nl(forEach));
8580 } 9179 }
8581 } 9180 }
8582 9181
@@ -8587,9 +9186,9 @@ private:
8587 std::string len = getUnusedName("_len_"sv); 9186 std::string len = getUnusedName("_len_"sv);
8588 addToScope(len); 9187 addToScope(len);
8589 auto breakLoopType = getBreakLoopType(forEach->body, accum); 9188 auto breakLoopType = getBreakLoopType(forEach->body, accum);
8590 _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(forEach); 9189 _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(forEach);
8591 out.emplace_back(clearBuf()); 9190 out.emplace_back(clearBuf());
8592 _buf << indent() << "local "sv << len << " = 1"sv << nll(forEach); 9191 _buf << indent() << "local "sv << len << " = 1"sv << nl(forEach);
8593 auto& lenAssign = out.emplace_back(clearBuf()); 9192 auto& lenAssign = out.emplace_back(clearBuf());
8594 transformForEachHead(forEach->nameList, forEach->loopValue, out, true); 9193 transformForEachHead(forEach->nameList, forEach->loopValue, out, true);
8595 if (hasBreakWithValue(breakLoopType)) { 9194 if (hasBreakWithValue(breakLoopType)) {
@@ -8605,14 +9204,16 @@ private:
8605 } 9204 }
8606 } 9205 }
8607 popScope(); 9206 popScope();
8608 out.push_back(indent() + "end"s + nlr(forEach)); 9207 out.push_back(indent() + "end"s + nl(forEach));
8609 return accum; 9208 return accum;
8610 } 9209 }
8611 9210
8612 void transformForEachClosure(ForEach_t* forEach, str_list& out) { 9211 void transformForEachClosure(ForEach_t* forEach, str_list& out) {
9212 auto forNode = forEach->new_ptr<For_t>();
9213 forNode->forLoop.set(forEach);
8613 auto simpleValue = forEach->new_ptr<SimpleValue_t>(); 9214 auto simpleValue = forEach->new_ptr<SimpleValue_t>();
8614 simpleValue->value.set(forEach); 9215 simpleValue->value.set(forNode);
8615 if (transformAsUpValueFunc(newExp(simpleValue, forEach), out)) { 9216 if (transformAsUpValueFunc(newExp(simpleValue, forNode), out)) {
8616 return; 9217 return;
8617 } 9218 }
8618 str_list temp; 9219 str_list temp;
@@ -8621,22 +9222,22 @@ private:
8621 std::string& funcStart = temp.emplace_back(); 9222 std::string& funcStart = temp.emplace_back();
8622 pushScope(); 9223 pushScope();
8623 auto accum = transformForEachInner(forEach, temp); 9224 auto accum = transformForEachInner(forEach, temp);
8624 temp.push_back(indent() + "return "s + accum + nlr(forEach)); 9225 temp.push_back(indent() + "return "s + accum + nl(forEach));
8625 popScope(); 9226 popScope();
8626 funcStart = anonFuncStart() + nll(forEach); 9227 funcStart = anonFuncStart() + nl(forEach);
8627 temp.push_back(indent() + anonFuncEnd()); 9228 temp.push_back(indent() + anonFuncEnd());
8628 popAnonVarArg(); 9229 popAnonVarArg();
8629 popFunctionScope(); 9230 popFunctionScope();
8630 out.push_back(join(temp)); 9231 out.push_back(join(temp));
8631 } 9232 }
8632 9233
8633 void transformForEachInPlace(ForEach_t* forEach, str_list& out, ExpList_t* assignExpList = nullptr) { 9234 void transformForEachInPlace(ForEach_t* forEach, str_list& out, ExpList_t* assignExpList) {
8634 auto x = forEach; 9235 auto x = forEach;
8635 str_list temp; 9236 str_list temp;
8636 bool isScoped = !currentScope().lastStatement; 9237 bool isScoped = !currentScope().lastStatement;
8637 if (assignExpList) { 9238 if (assignExpList) {
8638 if (isScoped) { 9239 if (isScoped) {
8639 _buf << indent() << "do"sv << nll(forEach); 9240 _buf << indent() << "do"sv << nl(forEach);
8640 pushScope(); 9241 pushScope();
8641 } 9242 }
8642 auto accum = transformForEachInner(forEach, temp); 9243 auto accum = transformForEachInner(forEach, temp);
@@ -8648,7 +9249,7 @@ private:
8648 transformAssignment(assignment, temp); 9249 transformAssignment(assignment, temp);
8649 if (isScoped) { 9250 if (isScoped) {
8650 popScope(); 9251 popScope();
8651 temp.push_back(indent() + "end"s + nlr(forEach)); 9252 temp.push_back(indent() + "end"s + nl(forEach));
8652 } 9253 }
8653 } else { 9254 } else {
8654 auto accum = transformForEachInner(forEach, temp); 9255 auto accum = transformForEachInner(forEach, temp);
@@ -8661,6 +9262,48 @@ private:
8661 out.push_back(join(temp)); 9262 out.push_back(join(temp));
8662 } 9263 }
8663 9264
9265 void transformFor(For_t* forNode, str_list& out) {
9266 switch (forNode->forLoop->get_id()) {
9267 case id<ForNum_t>():
9268 transformForNum(static_cast<ForNum_t*>(forNode->forLoop.get()), out);
9269 break;
9270 case id<ForEach_t>():
9271 transformForEach(static_cast<ForEach_t*>(forNode->forLoop.get()), out);
9272 break;
9273 default:
9274 YUEE("AST node mismatch", forNode->forLoop.get());
9275 break;
9276 }
9277 }
9278
9279 void transformForClosure(For_t* forNode, str_list& out) {
9280 switch (forNode->forLoop->get_id()) {
9281 case id<ForNum_t>():
9282 transformForNumClosure(static_cast<ForNum_t*>(forNode->forLoop.get()), out);
9283 break;
9284 case id<ForEach_t>():
9285 transformForEachClosure(static_cast<ForEach_t*>(forNode->forLoop.get()), out);
9286 break;
9287 default:
9288 YUEE("AST node mismatch", forNode->forLoop.get());
9289 break;
9290 }
9291 }
9292
9293 void transformForInPlace(For_t* forNode, str_list& out, ExpList_t* assignExpList) {
9294 switch (forNode->forLoop->get_id()) {
9295 case id<ForNum_t>():
9296 transformForNumInPlace(static_cast<ForNum_t*>(forNode->forLoop.get()), out, assignExpList);
9297 break;
9298 case id<ForEach_t>():
9299 transformForEachInPlace(static_cast<ForEach_t*>(forNode->forLoop.get()), out, assignExpList);
9300 break;
9301 default:
9302 YUEE("AST node mismatch", forNode->forLoop.get());
9303 break;
9304 }
9305 }
9306
8664 void transform_variable_pair(VariablePair_t* pair, str_list& out) { 9307 void transform_variable_pair(VariablePair_t* pair, str_list& out) {
8665 auto name = _parser.toString(pair->name); 9308 auto name = _parser.toString(pair->name);
8666 if (pair->name->name.is<UnicodeName_t>()) { 9309 if (pair->name->name.is<UnicodeName_t>()) {
@@ -8672,8 +9315,8 @@ private:
8672 } 9315 }
8673 if (_config.lintGlobalVariable && !isLocal(name)) { 9316 if (_config.lintGlobalVariable && !isLocal(name)) {
8674 auto key = name + ':' + std::to_string(pair->name->m_begin.m_line) + ':' + std::to_string(pair->name->m_begin.m_col); 9317 auto key = name + ':' + std::to_string(pair->name->m_begin.m_line) + ':' + std::to_string(pair->name->m_begin.m_col);
8675 if (_globals.find(key) != _globals.end()) { 9318 if (_globals.find(key) == _globals.end()) {
8676 _globals[key] = {name, pair->name->m_begin.m_line, pair->name->m_begin.m_col, _funcLevel > 1 ? AccessType::Capture : AccessType::Read}; 9319 _globals[key] = {name, pair->name->m_begin.m_line, pair->name->m_begin.m_col, _funcLevel > 1 ? AccessType::Capture : AccessType::Read, isSolidDefined(name)};
8677 } 9320 }
8678 } 9321 }
8679 } 9322 }
@@ -8787,12 +9430,64 @@ private:
8787 out.push_back(temp.empty() ? "\"\""s : join(temp, " .. "sv)); 9430 out.push_back(temp.empty() ? "\"\""s : join(temp, " .. "sv));
8788 } 9431 }
8789 9432
9433 void transformYAMLMultiline(YAMLMultiline_t* multiline, str_list& out) {
9434 std::optional<std::string> indent;
9435 str_list temp;
9436 for (auto line_ : multiline->lines.objects()) {
9437 auto line = static_cast<YAMLLine_t*>(line_);
9438 auto indentStr = _parser.toString(line->indent);
9439 if (!indent) {
9440 indent = indentStr;
9441 }
9442 if (std::string_view{indentStr.c_str(), indent.value().size()} != indent.value()) {
9443 throw CompileError("inconsistent indent"sv, line);
9444 }
9445 indentStr = indentStr.substr(indent.value().size());
9446 str_list segs;
9447 bool firstSeg = true;
9448 for (auto seg_ : line->segments.objects()) {
9449 auto content = static_cast<YAMLLineContent_t*>(seg_)->content.get();
9450 switch (content->get_id()) {
9451 case id<YAMLLineInner_t>(): {
9452 auto seqStr = _parser.toString(content);
9453 Utils::replace(seqStr, "\\#"sv, "#"sv);
9454 if (firstSeg) {
9455 firstSeg = false;
9456 seqStr.insert(0, indentStr);
9457 }
9458 segs.push_back(Utils::toLuaDoubleString(seqStr));
9459 break;
9460 }
9461 case id<Exp_t>(): {
9462 if (firstSeg) {
9463 firstSeg = false;
9464 if (!indentStr.empty()) {
9465 segs.push_back(Utils::toLuaDoubleString(indentStr));
9466 }
9467 }
9468 transformExp(static_cast<Exp_t*>(content), segs, ExpUsage::Closure);
9469 segs.back() = globalVar("tostring"sv, content, AccessType::Read) + '(' + segs.back() + ')';
9470 break;
9471 }
9472 default: YUEE("AST node mismatch", content); break;
9473 }
9474 }
9475 temp.push_back(join(segs, " .. "sv));
9476 }
9477 auto str = join(temp, " .. '\\n' .. "sv);
9478 Utils::replace(str, "\" .. '\\n' .. \""sv, "\\n"sv);
9479 Utils::replace(str, "\" .. '\\n'"sv, "\\n\""sv);
9480 Utils::replace(str, "'\\n' .. \""sv, "\"\\n"sv);
9481 out.push_back(str);
9482 }
9483
8790 void transformString(String_t* string, str_list& out) { 9484 void transformString(String_t* string, str_list& out) {
8791 auto str = string->str.get(); 9485 auto str = string->str.get();
8792 switch (str->get_id()) { 9486 switch (str->get_id()) {
8793 case id<SingleString_t>(): transformSingleString(static_cast<SingleString_t*>(str), out); break; 9487 case id<SingleString_t>(): transformSingleString(static_cast<SingleString_t*>(str), out); break;
8794 case id<DoubleString_t>(): transformDoubleString(static_cast<DoubleString_t*>(str), out); break; 9488 case id<DoubleString_t>(): transformDoubleString(static_cast<DoubleString_t*>(str), out); break;
8795 case id<LuaString_t>(): transformLuaString(static_cast<LuaString_t*>(str), out); break; 9489 case id<LuaString_t>(): transformLuaString(static_cast<LuaString_t*>(str), out); break;
9490 case id<YAMLMultiline_t>(): transformYAMLMultiline(static_cast<YAMLMultiline_t*>(str), out); break;
8796 default: YUEE("AST node mismatch", str); break; 9491 default: YUEE("AST node mismatch", str); break;
8797 } 9492 }
8798 } 9493 }
@@ -8823,7 +9518,7 @@ private:
8823 pushScope(); 9518 pushScope();
8824 transformClassDecl(classDecl, temp, ExpUsage::Return); 9519 transformClassDecl(classDecl, temp, ExpUsage::Return);
8825 popScope(); 9520 popScope();
8826 funcStart = anonFuncStart() + nll(classDecl); 9521 funcStart = anonFuncStart() + nl(classDecl);
8827 temp.push_back(indent() + anonFuncEnd()); 9522 temp.push_back(indent() + anonFuncEnd());
8828 popAnonVarArg(); 9523 popAnonVarArg();
8829 popFunctionScope(); 9524 popFunctionScope();
@@ -8847,7 +9542,7 @@ private:
8847 bool newDefined = false; 9542 bool newDefined = false;
8848 std::tie(className, newDefined, classTextName) = defineClassVariable(assignable); 9543 std::tie(className, newDefined, classTextName) = defineClassVariable(assignable);
8849 if (newDefined) { 9544 if (newDefined) {
8850 temp.push_back(indent() + "local "s + className + nll(classDecl)); 9545 temp.push_back(indent() + "local "s + className + nl(classDecl));
8851 } 9546 }
8852 if (classTextName.empty()) { 9547 if (classTextName.empty()) {
8853 if (auto chain = ast_cast<AssignableChain_t>(assignable->item)) { 9548 if (auto chain = ast_cast<AssignableChain_t>(assignable->item)) {
@@ -8884,12 +9579,12 @@ private:
8884 } 9579 }
8885 } 9580 }
8886 if (isScoped) { 9581 if (isScoped) {
8887 temp.push_back(indent() + "do"s + nll(classDecl)); 9582 temp.push_back(indent() + "do"s + nl(classDecl));
8888 pushScope(); 9583 pushScope();
8889 } 9584 }
8890 auto classVar = getUnusedName("_class_"sv); 9585 auto classVar = getUnusedName("_class_"sv);
8891 addToScope(classVar); 9586 addToScope(classVar);
8892 temp.push_back(indent() + "local "s + classVar + nll(classDecl)); 9587 temp.push_back(indent() + "local "s + classVar + nl(classDecl));
8893 auto block = classDecl->new_ptr<Block_t>(); 9588 auto block = classDecl->new_ptr<Block_t>();
8894 str_list classConstVars; 9589 str_list classConstVars;
8895 if (body) { 9590 if (body) {
@@ -8898,7 +9593,7 @@ private:
8898 if (auto statement = ast_cast<Statement_t>(item)) { 9593 if (auto statement = ast_cast<Statement_t>(item)) {
8899 ClassDecl_t* clsDecl = nullptr; 9594 ClassDecl_t* clsDecl = nullptr;
8900 if (auto assignment = assignmentFrom(statement)) { 9595 if (auto assignment = assignmentFrom(statement)) {
8901 block->statements.push_back(statement); 9596 block->statementOrComments.push_back(statement);
8902 auto names = transformAssignDefs(assignment->expList.get(), DefOp::Mark); 9597 auto names = transformAssignDefs(assignment->expList.get(), DefOp::Mark);
8903 for (const auto& name : names) { 9598 for (const auto& name : names) {
8904 varDefs.push_back(name.first); 9599 varDefs.push_back(name.first);
@@ -8928,12 +9623,12 @@ private:
8928 clsDecl = value->get_by_path<SimpleValue_t, ClassDecl_t>(); 9623 clsDecl = value->get_by_path<SimpleValue_t, ClassDecl_t>();
8929 BLOCK_END 9624 BLOCK_END
8930 } else if (auto expList = expListFrom(statement)) { 9625 } else if (auto expList = expListFrom(statement)) {
8931 block->statements.push_back(statement); 9626 block->statementOrComments.push_back(statement);
8932 if (auto value = singleValueFrom(expList)) { 9627 if (auto value = singleValueFrom(expList)) {
8933 clsDecl = value->get_by_path<SimpleValue_t, ClassDecl_t>(); 9628 clsDecl = value->get_by_path<SimpleValue_t, ClassDecl_t>();
8934 } 9629 }
8935 } else if (auto local = statement->content.as<Local_t>()) { 9630 } else if (auto local = statement->content.as<Local_t>()) {
8936 block->statements.push_back(statement); 9631 block->statementOrComments.push_back(statement);
8937 if (auto values = local->item.as<LocalValues_t>()) { 9632 if (auto values = local->item.as<LocalValues_t>()) {
8938 for (auto name : values->nameList->names.objects()) { 9633 for (auto name : values->nameList->names.objects()) {
8939 auto varName = variableToString(static_cast<Variable_t*>(name)); 9634 auto varName = variableToString(static_cast<Variable_t*>(name));
@@ -8996,7 +9691,6 @@ private:
8996 } 9691 }
8997 } 9692 }
8998 auto stmt = statement->new_ptr<Statement_t>(); 9693 auto stmt = statement->new_ptr<Statement_t>();
8999 stmt->comments.dup(statement->comments);
9000 auto newAttrib = localAttrib->new_ptr<LocalAttrib_t>(); 9694 auto newAttrib = localAttrib->new_ptr<LocalAttrib_t>();
9001 newAttrib->attrib.set(localAttrib->attrib); 9695 newAttrib->attrib.set(localAttrib->attrib);
9002 newAttrib->leftList.dup(localAttrib->leftList); 9696 newAttrib->leftList.dup(localAttrib->leftList);
@@ -9004,7 +9698,7 @@ private:
9004 newAttrib->forceLocal = false; 9698 newAttrib->forceLocal = false;
9005 stmt->content.set(newAttrib); 9699 stmt->content.set(newAttrib);
9006 stmt->appendix.set(statement->appendix); 9700 stmt->appendix.set(statement->appendix);
9007 block->statements.push_back(stmt); 9701 block->statementOrComments.push_back(stmt);
9008 } else if (statement->content.is<Global_t>()) { 9702 } else if (statement->content.is<Global_t>()) {
9009 throw CompileError("global statement is not allowed here"sv, statement->content); 9703 throw CompileError("global statement is not allowed here"sv, statement->content);
9010 } 9704 }
@@ -9018,7 +9712,7 @@ private:
9018 } 9712 }
9019 } 9713 }
9020 if (!varDefs.empty()) { 9714 if (!varDefs.empty()) {
9021 temp.push_back(indent() + "local "s + join(varDefs, ", "sv) + nll(body)); 9715 temp.push_back(indent() + "local "s + join(varDefs, ", "sv) + nl(body));
9022 } 9716 }
9023 } 9717 }
9024 std::string parent, parentVar; 9718 std::string parent, parentVar;
@@ -9028,7 +9722,7 @@ private:
9028 transformExp(extend, temp, ExpUsage::Closure); 9722 transformExp(extend, temp, ExpUsage::Closure);
9029 parent = std::move(temp.back()); 9723 parent = std::move(temp.back());
9030 temp.pop_back(); 9724 temp.pop_back();
9031 temp.push_back(indent() + "local "s + parentVar + " = "s + parent + nll(classDecl)); 9725 temp.push_back(indent() + "local "s + parentVar + " = "s + parent + nl(classDecl));
9032 } 9726 }
9033 auto baseVar = getUnusedName("_base_"sv); 9727 auto baseVar = getUnusedName("_base_"sv);
9034 addToScope(baseVar); 9728 addToScope(baseVar);
@@ -9047,7 +9741,7 @@ private:
9047 for (; it != members.end(); ++it) { 9741 for (; it != members.end(); ++it) {
9048 auto& member = *it; 9742 auto& member = *it;
9049 if (member.type == MemType::Property) { 9743 if (member.type == MemType::Property) {
9050 statements.push_back(indent() + member.item + nll(content)); 9744 statements.push_back(indent() + member.item + nl(content));
9051 } else { 9745 } else {
9052 member.item = indent(1) + member.item; 9746 member.item = indent(1) + member.item;
9053 } 9747 }
@@ -9059,32 +9753,34 @@ private:
9059 } 9753 }
9060 } 9754 }
9061 for (const auto& classVar : classConstVars) { 9755 for (const auto& classVar : classConstVars) {
9062 auto& scope = _scopes.back(); 9756 forceAddToScope(classVar);
9063 scope.vars->insert_or_assign(classVar, VarType::Local);
9064 } 9757 }
9065 for (auto stmt_ : block->statements.objects()) { 9758 forceAddToScope("self"s);
9066 transformStatement(static_cast<Statement_t*>(stmt_), statements); 9759 for (auto stmt_ : block->statementOrComments.objects()) {
9760 if (auto stmt = ast_cast<Statement_t>(stmt_)) {
9761 transformStatement(stmt, statements);
9762 }
9067 } 9763 }
9068 for (auto& member : members) { 9764 for (auto& member : members) {
9069 switch (member.type) { 9765 switch (member.type) {
9070 case MemType::Common: 9766 case MemType::Common:
9071 commons.push_back((commons.empty() ? Empty : ',' + nll(member.node)) + member.item); 9767 commons.push_back((commons.empty() ? Empty : ',' + nl(member.node)) + member.item);
9072 break; 9768 break;
9073 case MemType::Builtin: 9769 case MemType::Builtin:
9074 builtins.push_back((builtins.empty() ? Empty : ',' + nll(member.node)) + member.item); 9770 builtins.push_back((builtins.empty() ? Empty : ',' + nl(member.node)) + member.item);
9075 break; 9771 break;
9076 default: break; 9772 default: break;
9077 } 9773 }
9078 } 9774 }
9079 if (!commons.empty()) { 9775 if (!commons.empty()) {
9080 temp.back() += '{' + nll(body); 9776 temp.back() += '{' + nl(body);
9081 temp.push_back(join(commons) + nll(body)); 9777 temp.push_back(join(commons) + nl(body));
9082 temp.push_back(indent() + '}' + nll(body)); 9778 temp.push_back(indent() + '}' + nl(body));
9083 } else { 9779 } else {
9084 temp.back() += "{ }"s + nll(body); 9780 temp.back() += "{ }"s + nl(body);
9085 } 9781 }
9086 } else { 9782 } else {
9087 temp.back() += "{ }"s + nll(classDecl); 9783 temp.back() += "{ }"s + nl(classDecl);
9088 } 9784 }
9089 if (classDecl->mixes) { 9785 if (classDecl->mixes) {
9090 auto item = getUnusedName("_item_"sv); 9786 auto item = getUnusedName("_item_"sv);
@@ -9117,72 +9813,72 @@ private:
9117 transformAssignment(assignment, tmp); 9813 transformAssignment(assignment, tmp);
9118 } 9814 }
9119 if (extend) { 9815 if (extend) {
9120 _buf << indent() << "setmetatable("sv << baseVar << ", "sv << parentVar << ".__base)"sv << nll(classDecl); 9816 _buf << indent() << "setmetatable("sv << baseVar << ", "sv << parentVar << ".__base)"sv << nl(classDecl);
9121 } 9817 }
9122 _buf << indent() << classVar << " = "sv << globalVar("setmetatable"sv, classDecl, AccessType::Read) << "({"sv << nll(classDecl); 9818 _buf << indent() << classVar << " = "sv << globalVar("setmetatable"sv, classDecl, AccessType::Read) << "({"sv << nl(classDecl);
9123 if (!builtins.empty()) { 9819 if (!builtins.empty()) {
9124 _buf << join(builtins) << ',' << nll(classDecl); 9820 _buf << join(builtins) << ',' << nl(classDecl);
9125 } else { 9821 } else {
9126 if (extend) { 9822 if (extend) {
9127 _buf << indent(1) << "__init = function(self, ...)"sv << nll(classDecl); 9823 _buf << indent(1) << "__init = function(self, ...)"sv << nl(classDecl);
9128 _buf << indent(2) << "return "sv << classVar << ".__parent.__init(self, ...)"sv << nll(classDecl); 9824 _buf << indent(2) << "return "sv << classVar << ".__parent.__init(self, ...)"sv << nl(classDecl);
9129 _buf << indent(1) << "end,"sv << nll(classDecl); 9825 _buf << indent(1) << "end,"sv << nl(classDecl);
9130 } else { 9826 } else {
9131 _buf << indent(1) << "__init = function() end,"sv << nll(classDecl); 9827 _buf << indent(1) << "__init = function() end,"sv << nl(classDecl);
9132 } 9828 }
9133 } 9829 }
9134 _buf << indent(1) << "__base = "sv << baseVar; 9830 _buf << indent(1) << "__base = "sv << baseVar;
9135 if (!classTextName.empty()) { 9831 if (!classTextName.empty()) {
9136 _buf << ","sv << nll(classDecl); 9832 _buf << ","sv << nl(classDecl);
9137 _buf << indent(1) << "__name = "sv << classTextName; 9833 _buf << indent(1) << "__name = "sv << classTextName;
9138 } 9834 }
9139 if (extend) { 9835 if (extend) {
9140 _buf << ","sv << nll(classDecl); 9836 _buf << ","sv << nl(classDecl);
9141 _buf << indent(1) << "__parent = "sv << parentVar; 9837 _buf << indent(1) << "__parent = "sv << parentVar;
9142 } 9838 }
9143 _buf << nll(classDecl); 9839 _buf << nl(classDecl);
9144 _buf << indent() << "}, {"sv << nll(classDecl); 9840 _buf << indent() << "}, {"sv << nl(classDecl);
9145 if (extend) { 9841 if (extend) {
9146 _buf << indent(1) << "__index = function(cls, name)"sv << nll(classDecl); 9842 _buf << indent(1) << "__index = function(cls, name)"sv << nl(classDecl);
9147 _buf << indent(2) << "local val = rawget("sv << baseVar << ", name)"sv << nll(classDecl); 9843 _buf << indent(2) << "local val = rawget("sv << baseVar << ", name)"sv << nl(classDecl);
9148 _buf << indent(2) << "if val == nil then"sv << nll(classDecl); 9844 _buf << indent(2) << "if val == nil then"sv << nl(classDecl);
9149 _buf << indent(3) << "local parent = rawget(cls, \"__parent\")"sv << nll(classDecl); 9845 _buf << indent(3) << "local parent = rawget(cls, \"__parent\")"sv << nl(classDecl);
9150 _buf << indent(3) << "if parent then"sv << nll(classDecl); 9846 _buf << indent(3) << "if parent then"sv << nl(classDecl);
9151 _buf << indent(4) << "return parent[name]"sv << nll(classDecl); 9847 _buf << indent(4) << "return parent[name]"sv << nl(classDecl);
9152 _buf << indent(3) << "end"sv << nll(classDecl); 9848 _buf << indent(3) << "end"sv << nl(classDecl);
9153 _buf << indent(2) << "else"sv << nll(classDecl); 9849 _buf << indent(2) << "else"sv << nl(classDecl);
9154 _buf << indent(3) << "return val"sv << nll(classDecl); 9850 _buf << indent(3) << "return val"sv << nl(classDecl);
9155 _buf << indent(2) << "end"sv << nll(classDecl); 9851 _buf << indent(2) << "end"sv << nl(classDecl);
9156 _buf << indent(1) << "end,"sv << nll(classDecl); 9852 _buf << indent(1) << "end,"sv << nl(classDecl);
9157 } else { 9853 } else {
9158 _buf << indent(1) << "__index = "sv << baseVar << ","sv << nll(classDecl); 9854 _buf << indent(1) << "__index = "sv << baseVar << ","sv << nl(classDecl);
9159 } 9855 }
9160 _buf << indent(1) << "__call = function(cls, ...)"sv << nll(classDecl); 9856 _buf << indent(1) << "__call = function(cls, ...)"sv << nl(classDecl);
9161 pushScope(); 9857 pushScope();
9162 auto selfVar = getUnusedName("_self_"sv); 9858 auto selfVar = getUnusedName("_self_"sv);
9163 addToScope(selfVar); 9859 addToScope(selfVar);
9164 _buf << indent(1) << "local "sv << selfVar << " = setmetatable({ }, "sv << baseVar << ")"sv << nll(classDecl); 9860 _buf << indent(1) << "local "sv << selfVar << " = setmetatable({ }, "sv << baseVar << ")"sv << nl(classDecl);
9165 _buf << indent(1) << "cls.__init("sv << selfVar << ", ...)"sv << nll(classDecl); 9861 _buf << indent(1) << "cls.__init("sv << selfVar << ", ...)"sv << nl(classDecl);
9166 _buf << indent(1) << "return "sv << selfVar << nll(classDecl); 9862 _buf << indent(1) << "return "sv << selfVar << nl(classDecl);
9167 popScope(); 9863 popScope();
9168 _buf << indent(1) << "end"sv << nll(classDecl); 9864 _buf << indent(1) << "end"sv << nl(classDecl);
9169 _buf << indent() << "})"sv << nll(classDecl); 9865 _buf << indent() << "})"sv << nl(classDecl);
9170 _buf << indent() << baseVar << ".__class = "sv << classVar << nll(classDecl); 9866 _buf << indent() << baseVar << ".__class = "sv << classVar << nl(classDecl);
9171 if (!statements.empty()) { 9867 if (!statements.empty()) {
9172 _buf << indent() << "local self = "sv << classVar << ';' << nll(classDecl); 9868 _buf << indent() << "local self = "sv << classVar << ';' << nl(classDecl);
9173 } 9869 }
9174 _buf << join(statements); 9870 _buf << join(statements);
9175 if (extend) { 9871 if (extend) {
9176 _buf << indent() << "if "sv << parentVar << ".__inherited then"sv << nll(classDecl); 9872 _buf << indent() << "if "sv << parentVar << ".__inherited then"sv << nl(classDecl);
9177 _buf << indent(1) << parentVar << ".__inherited("sv << parentVar << ", "sv << classVar << ")"sv << nll(classDecl); 9873 _buf << indent(1) << parentVar << ".__inherited("sv << parentVar << ", "sv << classVar << ")"sv << nl(classDecl);
9178 _buf << indent() << "end"sv << nll(classDecl); 9874 _buf << indent() << "end"sv << nl(classDecl);
9179 } 9875 }
9180 if (!assignItem.empty()) { 9876 if (!assignItem.empty()) {
9181 _buf << indent() << assignItem << " = "sv << classVar << nll(classDecl); 9877 _buf << indent() << assignItem << " = "sv << classVar << nl(classDecl);
9182 } 9878 }
9183 switch (usage) { 9879 switch (usage) {
9184 case ExpUsage::Return: { 9880 case ExpUsage::Return: {
9185 _buf << indent() << "return "sv << classVar << nlr(classDecl); 9881 _buf << indent() << "return "sv << classVar << nl(classDecl);
9186 break; 9882 break;
9187 } 9883 }
9188 case ExpUsage::Assignment: { 9884 case ExpUsage::Assignment: {
@@ -9194,7 +9890,7 @@ private:
9194 temp.push_back(clearBuf()); 9890 temp.push_back(clearBuf());
9195 if (isScoped) { 9891 if (isScoped) {
9196 popScope(); 9892 popScope();
9197 temp.push_back(indent() + "end"s + nlr(classDecl)); 9893 temp.push_back(indent() + "end"s + nl(classDecl));
9198 } 9894 }
9199 out.push_back(join(temp)); 9895 out.push_back(join(temp));
9200 } 9896 }
@@ -9357,7 +10053,7 @@ private:
9357 pushScope(); 10053 pushScope();
9358 transformWith(with, temp, nullptr, true); 10054 transformWith(with, temp, nullptr, true);
9359 popScope(); 10055 popScope();
9360 funcStart = anonFuncStart() + nll(with); 10056 funcStart = anonFuncStart() + nl(with);
9361 temp.push_back(indent() + anonFuncEnd()); 10057 temp.push_back(indent() + anonFuncEnd());
9362 popAnonVarArg(); 10058 popAnonVarArg();
9363 popFunctionScope(); 10059 popFunctionScope();
@@ -9370,11 +10066,11 @@ private:
9370 std::string withVar; 10066 std::string withVar;
9371 bool needScope = !currentScope().lastStatement && !returnValue; 10067 bool needScope = !currentScope().lastStatement && !returnValue;
9372 bool extraScope = false; 10068 bool extraScope = false;
9373 if (with->assigns) { 10069 if (with->assign) {
9374 auto vars = getAssignVars(with); 10070 auto vars = getAssignVars(with);
9375 if (vars.front().empty() || isDeclaredAsGlobal(vars.front())) { 10071 if (vars.front().empty() || isDeclaredAsGlobal(vars.front())) {
9376 if (with->assigns->values.objects().size() == 1) { 10072 if (with->assign->values.objects().size() == 1) {
9377 auto var = singleVariableFrom(with->assigns->values.objects().front(), AccessType::Read); 10073 auto var = singleVariableFrom(with->assign->values.objects().front(), AccessType::Read);
9378 if (!var.empty() && isLocal(var)) { 10074 if (!var.empty() && isLocal(var)) {
9379 withVar = var; 10075 withVar = var;
9380 } 10076 }
@@ -9384,11 +10080,11 @@ private:
9384 auto assignment = x->new_ptr<ExpListAssign_t>(); 10080 auto assignment = x->new_ptr<ExpListAssign_t>();
9385 assignment->expList.set(toAst<ExpList_t>(withVar, x)); 10081 assignment->expList.set(toAst<ExpList_t>(withVar, x));
9386 auto assign = x->new_ptr<Assign_t>(); 10082 auto assign = x->new_ptr<Assign_t>();
9387 assign->values.push_back(with->assigns->values.objects().front()); 10083 assign->values.push_back(with->assign->values.objects().front());
9388 assignment->action.set(assign); 10084 assignment->action.set(assign);
9389 if (needScope) { 10085 if (needScope) {
9390 extraScope = true; 10086 extraScope = true;
9391 temp.push_back(indent() + "do"s + nll(with)); 10087 temp.push_back(indent() + "do"s + nl(with));
9392 pushScope(); 10088 pushScope();
9393 } 10089 }
9394 transformAssignment(assignment, temp); 10090 transformAssignment(assignment, temp);
@@ -9398,7 +10094,7 @@ private:
9398 auto assign = x->new_ptr<Assign_t>(); 10094 auto assign = x->new_ptr<Assign_t>();
9399 assign->values.push_back(toAst<Exp_t>(withVar, x)); 10095 assign->values.push_back(toAst<Exp_t>(withVar, x));
9400 bool skipFirst = true; 10096 bool skipFirst = true;
9401 for (auto value : with->assigns->values.objects()) { 10097 for (auto value : with->assign->values.objects()) {
9402 if (skipFirst) { 10098 if (skipFirst) {
9403 skipFirst = false; 10099 skipFirst = false;
9404 continue; 10100 continue;
@@ -9411,10 +10107,10 @@ private:
9411 withVar = vars.front(); 10107 withVar = vars.front();
9412 auto assignment = x->new_ptr<ExpListAssign_t>(); 10108 auto assignment = x->new_ptr<ExpListAssign_t>();
9413 assignment->expList.set(with->valueList); 10109 assignment->expList.set(with->valueList);
9414 assignment->action.set(with->assigns); 10110 assignment->action.set(with->assign);
9415 if (needScope) { 10111 if (needScope) {
9416 extraScope = true; 10112 extraScope = true;
9417 temp.push_back(indent() + "do"s + nll(with)); 10113 temp.push_back(indent() + "do"s + nl(with));
9418 pushScope(); 10114 pushScope();
9419 } 10115 }
9420 transformAssignment(assignment, temp); 10116 transformAssignment(assignment, temp);
@@ -9430,7 +10126,7 @@ private:
9430 assignment->action.set(assign); 10126 assignment->action.set(assign);
9431 if (needScope) { 10127 if (needScope) {
9432 extraScope = true; 10128 extraScope = true;
9433 temp.push_back(indent() + "do"s + nll(with)); 10129 temp.push_back(indent() + "do"s + nl(with));
9434 pushScope(); 10130 pushScope();
9435 } 10131 }
9436 transformAssignment(assignment, temp); 10132 transformAssignment(assignment, temp);
@@ -9484,7 +10180,7 @@ private:
9484 }); 10180 });
9485 popScope(); 10181 popScope();
9486 if (extraScope) { 10182 if (extraScope) {
9487 temp.push_back(indent() + "do"s + nll(with)); 10183 temp.push_back(indent() + "do"s + nl(with));
9488 pushScope(); 10184 pushScope();
9489 } 10185 }
9490 } 10186 }
@@ -9513,49 +10209,40 @@ private:
9513 expListAssign->expList.set(expList); 10209 expListAssign->expList.set(expList);
9514 auto stmt = x->new_ptr<Statement_t>(); 10210 auto stmt = x->new_ptr<Statement_t>();
9515 stmt->content.set(expListAssign); 10211 stmt->content.set(expListAssign);
9516 auto whileNode = toAst<While_t>("while true do break"s, x); 10212 auto repeatNode = toAst<Repeat_t>("repeat\n\t--\nuntil true"s, x);
9517 auto block = x->new_ptr<Block_t>(); 10213 auto block = x->new_ptr<Block_t>();
9518 block->statements.push_back(stmt); 10214 block->statementOrComments.push_back(stmt);
9519 block->statements.push_back(whileNode->body); 10215 repeatNode->body.set(block);
9520 auto body = x->new_ptr<Body_t>();
9521 body->content.set(block);
9522 whileNode->body.set(block);
9523 auto sVal = x->new_ptr<SimpleValue_t>(); 10216 auto sVal = x->new_ptr<SimpleValue_t>();
9524 sVal->value.set(whileNode); 10217 sVal->value.set(repeatNode);
9525 auto asmt = assignmentFrom(toAst<Exp_t>(breakWithVar, x), newExp(sVal, x), x); 10218 auto asmt = assignmentFrom(toAst<Exp_t>(breakWithVar, x), newExp(sVal, x), x);
9526 transformAssignment(asmt, temp); 10219 transformAssignment(asmt, temp);
9527 } 10220 }
9528 } else { 10221 } else {
9529 bool transformed = false; 10222 bool transformed = false;
9530 if (!breakWithVar.empty()) { 10223 if (!breakWithVar.empty()) {
9531 auto whileNode = toAst<While_t>("while true do break"s, x); 10224 auto repeatNode = toAst<Repeat_t>("repeat\n\t--\nuntil true"s, x);
9532 auto block = x->new_ptr<Block_t>(); 10225 auto block = x->new_ptr<Block_t>();
9533 if (auto blk = with->body.as<Block_t>()) { 10226 if (auto blk = with->body.as<Block_t>()) {
9534 block->statements.dup(blk->statements); 10227 block->statementOrComments.dup(blk->statementOrComments);
9535 } else { 10228 } else {
9536 auto stmt = with->body.to<Statement_t>(); 10229 auto stmt = with->body.to<Statement_t>();
9537 block->statements.push_back(stmt); 10230 block->statementOrComments.push_back(stmt);
9538 }
9539 auto breakLoop = whileNode->body.to<Statement_t>()->content.as<BreakLoop_t>();
9540 if (!(breakLoop && breakLoop->type.is<Break_t>())) {
9541 block->statements.push_back(whileNode->body);
9542 } 10231 }
9543 auto body = x->new_ptr<Body_t>(); 10232 repeatNode->body.set(block);
9544 body->content.set(block);
9545 whileNode->body.set(block);
9546 auto sVal = x->new_ptr<SimpleValue_t>(); 10233 auto sVal = x->new_ptr<SimpleValue_t>();
9547 sVal->value.set(whileNode); 10234 sVal->value.set(repeatNode);
9548 auto asmt = assignmentFrom(toAst<Exp_t>(breakWithVar, x), newExp(sVal, x), x); 10235 auto asmt = assignmentFrom(toAst<Exp_t>(breakWithVar, x), newExp(sVal, x), x);
9549 transformAssignment(asmt, temp); 10236 transformAssignment(asmt, temp);
9550 transformed = true; 10237 transformed = true;
9551 } else if (!extraScope && assignList) { 10238 } else if (!extraScope && assignList) {
9552 if (auto block = with->body.as<Block_t>()) { 10239 if (auto block = with->body.as<Block_t>()) {
9553 if (!block->statements.empty()) { 10240 if (!block->statementOrComments.empty()) {
9554 Statement_t* stmt = static_cast<Statement_t*>(block->statements.back()); 10241 Statement_t* stmt = lastStatementFrom(block);
9555 if (stmt->content.is<Return_t>()) { 10242 if (stmt && stmt->content.is<Return_t>()) {
9556 auto newBlock = with->body->new_ptr<Block_t>(); 10243 auto newBlock = with->body->new_ptr<Block_t>();
9557 newBlock->statements.dup(block->statements); 10244 newBlock->statementOrComments.dup(block->statementOrComments);
9558 newBlock->statements.pop_back(); 10245 newBlock->statementOrComments.pop_back();
9559 transform_plain_body(newBlock, temp, ExpUsage::Common); 10246 transform_plain_body(newBlock, temp, ExpUsage::Common);
9560 auto newBody = stmt->new_ptr<Body_t>(); 10247 auto newBody = stmt->new_ptr<Body_t>();
9561 newBody->content.set(stmt); 10248 newBody->content.set(stmt);
@@ -9593,12 +10280,12 @@ private:
9593 if (returnValue) { 10280 if (returnValue) {
9594 auto last = lastStatementFrom(with->body); 10281 auto last = lastStatementFrom(with->body);
9595 if (last && !last->content.is<Return_t>()) { 10282 if (last && !last->content.is<Return_t>()) {
9596 temp.push_back(indent() + "return "s + withVar + nll(with)); 10283 temp.push_back(indent() + "return "s + withVar + nl(with));
9597 } 10284 }
9598 } 10285 }
9599 if (extraScope) { 10286 if (extraScope) {
9600 popScope(); 10287 popScope();
9601 temp.push_back(indent() + "end"s + nll(with)); 10288 temp.push_back(indent() + "end"s + nl(with));
9602 } 10289 }
9603 out.push_back(join(temp)); 10290 out.push_back(join(temp));
9604 } 10291 }
@@ -9808,7 +10495,7 @@ private:
9808 } 10495 }
9809 } 10496 }
9810 if (_info.exportDefault) { 10497 if (_info.exportDefault) {
9811 out.back().append(indent() + _info.moduleName + " = "s + names.back().first + nlr(exportNode)); 10498 out.back().append(indent() + _info.moduleName + " = "s + names.back().first + nl(exportNode));
9812 } else { 10499 } else {
9813 str_list lefts, rights; 10500 str_list lefts, rights;
9814 for (const auto& name : names) { 10501 for (const auto& name : names) {
@@ -9821,7 +10508,7 @@ private:
9821 lefts.push_back(_info.moduleName + "[\""s + realName + "\"]"s); 10508 lefts.push_back(_info.moduleName + "[\""s + realName + "\"]"s);
9822 rights.push_back(name.first); 10509 rights.push_back(name.first);
9823 } 10510 }
9824 out.back().append(indent() + join(lefts, ", "sv) + " = "s + join(rights, ", "sv) + nlr(exportNode)); 10511 out.back().append(indent() + join(lefts, ", "sv) + " = "s + join(rights, ", "sv) + nl(exportNode));
9825 } 10512 }
9826 } 10513 }
9827 } else { 10514 } else {
@@ -9905,12 +10592,12 @@ private:
9905 case id<CompForEach_t>(): 10592 case id<CompForEach_t>():
9906 transformCompForEach(static_cast<CompForEach_t*>(item), temp); 10593 transformCompForEach(static_cast<CompForEach_t*>(item), temp);
9907 break; 10594 break;
9908 case id<CompFor_t>(): 10595 case id<CompForNum_t>():
9909 transformCompFor(static_cast<CompFor_t*>(item), temp); 10596 transformCompForNum(static_cast<CompForNum_t*>(item), temp);
9910 break; 10597 break;
9911 case id<Exp_t>(): 10598 case id<Exp_t>():
9912 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure); 10599 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure);
9913 temp.back() = indent() + "if "s + temp.back() + " then"s + nll(item); 10600 temp.back() = indent() + "if "s + temp.back() + " then"s + nl(item);
9914 pushScope(); 10601 pushScope();
9915 break; 10602 break;
9916 default: YUEE("AST node mismatch", item); break; 10603 default: YUEE("AST node mismatch", item); break;
@@ -9923,27 +10610,27 @@ private:
9923 for (size_t i = 0; i < compInner->items.objects().size(); ++i) { 10610 for (size_t i = 0; i < compInner->items.objects().size(); ++i) {
9924 popScope(); 10611 popScope();
9925 } 10612 }
9926 _buf << indent() << "local "sv << tbl << " = { }"sv << nll(comp); 10613 _buf << indent() << "local "sv << tbl << " = { }"sv << nl(comp);
9927 _buf << join(temp); 10614 _buf << join(temp);
9928 pushScope(); 10615 pushScope();
9929 if (!comp->value) { 10616 if (!comp->value) {
9930 auto keyVar = getUnusedName("_key_"sv); 10617 auto keyVar = getUnusedName("_key_"sv);
9931 auto valVar = getUnusedName("_val_"sv); 10618 auto valVar = getUnusedName("_val_"sv);
9932 _buf << indent(int(temp.size()) - 1) << "local "sv << keyVar << ", "sv << valVar << " = "sv << kv.front() << nll(comp); 10619 _buf << indent(int(temp.size()) - 1) << "local "sv << keyVar << ", "sv << valVar << " = "sv << kv.front() << nl(comp);
9933 kv.front() = keyVar; 10620 kv.front() = keyVar;
9934 kv.push_back(valVar); 10621 kv.push_back(valVar);
9935 } 10622 }
9936 _buf << indent(int(temp.size()) - 1) << tbl << "["sv << kv.front() << "] = "sv << kv.back() << nll(comp); 10623 _buf << indent(int(temp.size()) - 1) << tbl << "["sv << kv.front() << "] = "sv << kv.back() << nl(comp);
9937 for (int ind = int(temp.size()) - 2; ind > -1; --ind) { 10624 for (int ind = int(temp.size()) - 2; ind > -1; --ind) {
9938 _buf << indent(ind) << "end"sv << nll(comp); 10625 _buf << indent(ind) << "end"sv << nl(comp);
9939 } 10626 }
9940 popScope(); 10627 popScope();
9941 _buf << indent() << "end"sv << nll(comp); 10628 _buf << indent() << "end"sv << nl(comp);
9942 switch (usage) { 10629 switch (usage) {
9943 case ExpUsage::Closure: 10630 case ExpUsage::Closure:
9944 out.push_back(clearBuf() + indent() + "return "s + tbl + nlr(comp)); 10631 out.push_back(clearBuf() + indent() + "return "s + tbl + nl(comp));
9945 popScope(); 10632 popScope();
9946 out.back().insert(0, anonFuncStart() + nll(comp)); 10633 out.back().insert(0, anonFuncStart() + nl(comp));
9947 out.back().append(indent() + anonFuncEnd()); 10634 out.back().append(indent() + anonFuncEnd());
9948 popAnonVarArg(); 10635 popAnonVarArg();
9949 popFunctionScope(); 10636 popFunctionScope();
@@ -9959,21 +10646,21 @@ private:
9959 out.back().append(temp.back()); 10646 out.back().append(temp.back());
9960 if (extraScope) { 10647 if (extraScope) {
9961 popScope(); 10648 popScope();
9962 out.back().insert(0, indent() + "do"s + nll(comp)); 10649 out.back().insert(0, indent() + "do"s + nl(comp));
9963 out.back().append(indent() + "end"s + nlr(comp)); 10650 out.back().append(indent() + "end"s + nl(comp));
9964 } 10651 }
9965 break; 10652 break;
9966 } 10653 }
9967 case ExpUsage::Return: 10654 case ExpUsage::Return:
9968 out.push_back(clearBuf() + indent() + "return "s + tbl + nlr(comp)); 10655 out.push_back(clearBuf() + indent() + "return "s + tbl + nl(comp));
9969 break; 10656 break;
9970 default: 10657 default:
9971 break; 10658 break;
9972 } 10659 }
9973 } 10660 }
9974 10661
9975 void transformCompFor(CompFor_t* comp, str_list& out) { 10662 void transformCompForNum(CompForNum_t* comp, str_list& out) {
9976 transformForHead(comp->varName, comp->startValue, comp->stopValue, comp->stepValue, out); 10663 transformForNumHead(comp->varName, comp->startValue, comp->stopValue, comp->stepValue, out);
9977 } 10664 }
9978 10665
9979 void transformTableBlockIndent(TableBlockIndent_t* table, str_list& out) { 10666 void transformTableBlockIndent(TableBlockIndent_t* table, str_list& out) {
@@ -10003,25 +10690,64 @@ private:
10003 funcStart = &temp.emplace_back(); 10690 funcStart = &temp.emplace_back();
10004 pushScope(); 10691 pushScope();
10005 } else { 10692 } else {
10006 temp.push_back(indent() + "do"s + nll(doNode)); 10693 temp.push_back(indent() + "do"s + nl(doNode));
10007 pushScope(); 10694 pushScope();
10008 } 10695 }
10009 transformBody(doNode->body, temp, usage, assignList); 10696 transformBody(doNode->body, temp, usage, assignList);
10010 if (usage == ExpUsage::Closure) { 10697 if (usage == ExpUsage::Closure) {
10011 popScope(); 10698 popScope();
10012 *funcStart = anonFuncStart() + nll(doNode); 10699 *funcStart = anonFuncStart() + nl(doNode);
10013 temp.push_back(indent() + anonFuncEnd()); 10700 temp.push_back(indent() + anonFuncEnd());
10014 popAnonVarArg(); 10701 popAnonVarArg();
10015 popFunctionScope(); 10702 popFunctionScope();
10016 } else { 10703 } else {
10017 popScope(); 10704 popScope();
10018 temp.push_back(indent() + "end"s + nlr(doNode)); 10705 temp.push_back(indent() + "end"s + nl(doNode));
10019 } 10706 }
10020 out.push_back(join(temp)); 10707 out.push_back(join(temp));
10021 } 10708 }
10022 10709
10023 void transformTry(Try_t* tryNode, str_list& out, ExpUsage usage) { 10710 void transformTry(Try_t* tryNode, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
10024 auto x = tryNode; 10711 auto x = tryNode;
10712 if (tryNode->eop && usage == ExpUsage::Assignment) {
10713 str_list rets;
10714 pushScope();
10715 auto okVar = getUnusedName("_ok_"sv);
10716 for (size_t i = 0; i < assignList->exprs.size(); i++) {
10717 auto retVar = getUnusedName("_ret_"sv);
10718 rets.emplace_back(retVar);
10719 addToScope(retVar);
10720 }
10721 popScope();
10722 auto varList = join(rets, ","sv);
10723 auto ifNode = toAst<If_t>("if "s + okVar + ',' + varList + ":=try nil then "s + varList, x);
10724 auto exp = ast_to<IfCond_t>(ifNode->nodes.front())->assignment->assign->values.front();
10725 auto sVal = simpleSingleValueFrom(exp);
10726 auto newTry = sVal->value.to<Try_t>();
10727 newTry->func.set(tryNode->func);
10728 newTry->catchBlock.set(tryNode->catchBlock);
10729 auto assignment = x->new_ptr<ExpListAssign_t>();
10730 assignment->expList.set(assignList);
10731 auto assign = x->new_ptr<Assign_t>();
10732 assign->values.push_back(ifNode);
10733 assignment->action.set(assign);
10734 transformAssignment(assignment, out);
10735 return;
10736 }
10737 if (tryNode->eop && usage != ExpUsage::Common) {
10738 auto okVar = getUnusedName("_ok_"sv);
10739 auto code = "do\n\t"s + okVar + ", ... = try nil\n\t... if "s + okVar;
10740 auto doNode = toAst<Do_t>(code, x);
10741 auto block = doNode->body->content.to<Block_t>();
10742 auto asmt = static_cast<Statement_t*>(block->statementOrComments.front())->content.to<ExpListAssign_t>();
10743 auto assign = asmt->action.to<Assign_t>();
10744 auto sVal = simpleSingleValueFrom(assign->values.back());
10745 auto newTry = sVal->value.to<Try_t>();
10746 newTry->func.set(tryNode->func);
10747 newTry->catchBlock.set(tryNode->catchBlock);
10748 transformDo(doNode, out, usage);
10749 return;
10750 }
10025 ast_ptr<true, Exp_t> errHandler; 10751 ast_ptr<true, Exp_t> errHandler;
10026 if (tryNode->catchBlock) { 10752 if (tryNode->catchBlock) {
10027 auto catchBlock = tryNode->catchBlock.get(); 10753 auto catchBlock = tryNode->catchBlock.get();
@@ -10037,8 +10763,8 @@ private:
10037 tryFunc.set(tryNode->func); 10763 tryFunc.set(tryNode->func);
10038 if (auto tryBlock = tryFunc.as<Block_t>()) { 10764 if (auto tryBlock = tryFunc.as<Block_t>()) {
10039 BLOCK_START 10765 BLOCK_START
10040 BREAK_IF(tryBlock->statements.size() != 1); 10766 BREAK_IF(countStatementFrom(tryBlock) != 1);
10041 auto stmt = static_cast<Statement_t*>(tryBlock->statements.front()); 10767 auto stmt = firstStatementFrom(tryBlock);
10042 auto expListAssign = stmt->content.as<ExpListAssign_t>(); 10768 auto expListAssign = stmt->content.as<ExpListAssign_t>();
10043 BREAK_IF(!expListAssign); 10769 BREAK_IF(!expListAssign);
10044 BREAK_IF(expListAssign->action); 10770 BREAK_IF(expListAssign->action);
@@ -10102,7 +10828,7 @@ private:
10102 auto stmt = x->new_ptr<Statement_t>(); 10828 auto stmt = x->new_ptr<Statement_t>();
10103 stmt->content.set(expListAssign); 10829 stmt->content.set(expListAssign);
10104 auto block = x->new_ptr<Block_t>(); 10830 auto block = x->new_ptr<Block_t>();
10105 block->statements.push_back(stmt); 10831 block->statementOrComments.push_back(stmt);
10106 tryFunc.set(block); 10832 tryFunc.set(block);
10107 } 10833 }
10108 } 10834 }
@@ -10130,7 +10856,7 @@ private:
10130 } 10856 }
10131 if (usage == ExpUsage::Common) { 10857 if (usage == ExpUsage::Common) {
10132 out.back().insert(0, indent()); 10858 out.back().insert(0, indent());
10133 out.back().append(nlr(x)); 10859 out.back().append(nl(x));
10134 } 10860 }
10135 return; 10861 return;
10136 } 10862 }
@@ -10155,7 +10881,7 @@ private:
10155 } 10881 }
10156 if (usage == ExpUsage::Common) { 10882 if (usage == ExpUsage::Common) {
10157 out.back().insert(0, indent()); 10883 out.back().insert(0, indent());
10158 out.back().append(nlr(x)); 10884 out.back().append(nl(x));
10159 } 10885 }
10160 return; 10886 return;
10161 } else if (auto value = singleValueFrom(tryFunc)) { 10887 } else if (auto value = singleValueFrom(tryFunc)) {
@@ -10216,7 +10942,7 @@ private:
10216 } 10942 }
10217 if (usage == ExpUsage::Common) { 10943 if (usage == ExpUsage::Common) {
10218 out.back().insert(0, indent()); 10944 out.back().insert(0, indent());
10219 out.back().append(nlr(x)); 10945 out.back().append(nl(x));
10220 } 10946 }
10221 return; 10947 return;
10222 BLOCK_END 10948 BLOCK_END
@@ -10235,13 +10961,13 @@ private:
10235 } 10961 }
10236 if (usage == ExpUsage::Common) { 10962 if (usage == ExpUsage::Common) {
10237 out.back().insert(0, indent()); 10963 out.back().insert(0, indent());
10238 out.back().append(nlr(x)); 10964 out.back().append(nl(x));
10239 } 10965 }
10240 } 10966 }
10241 10967
10242 void transformImportFrom(ImportFrom_t* importNode, str_list& out) { 10968 void transformImportFrom(ImportFrom_t* importNode, str_list& out) {
10243 str_list temp; 10969 str_list temp;
10244 auto x = importNode; 10970 auto x = importNode->item.get();
10245 auto objVar = singleVariableFrom(importNode->item, AccessType::Read); 10971 auto objVar = singleVariableFrom(importNode->item, AccessType::Read);
10246 ast_ptr<false, ExpListAssign_t> objAssign; 10972 ast_ptr<false, ExpListAssign_t> objAssign;
10247 if (objVar.empty()) { 10973 if (objVar.empty()) {
@@ -10311,11 +11037,11 @@ private:
10311 if (objAssign) { 11037 if (objAssign) {
10312 auto preDef = toLocalDecl(transformAssignDefs(expList, DefOp::Mark)); 11038 auto preDef = toLocalDecl(transformAssignDefs(expList, DefOp::Mark));
10313 if (!preDef.empty()) { 11039 if (!preDef.empty()) {
10314 temp.push_back(preDef + nll(importNode)); 11040 temp.push_back(preDef + nl(importNode));
10315 } 11041 }
10316 if (!currentScope().lastStatement) { 11042 if (!currentScope().lastStatement) {
10317 extraScope = true; 11043 extraScope = true;
10318 temp.push_back(indent() + "do"s + nll(importNode)); 11044 temp.push_back(indent() + "do"s + nl(importNode));
10319 pushScope(); 11045 pushScope();
10320 } 11046 }
10321 transformAssignment(objAssign, temp); 11047 transformAssignment(objAssign, temp);
@@ -10327,7 +11053,7 @@ private:
10327 if (objAssign) { 11053 if (objAssign) {
10328 if (extraScope) { 11054 if (extraScope) {
10329 popScope(); 11055 popScope();
10330 temp.push_back(indent() + "end"s + nlr(importNode)); 11056 temp.push_back(indent() + "end"s + nl(importNode));
10331 } 11057 }
10332 } 11058 }
10333 out.push_back(join(temp)); 11059 out.push_back(join(temp));
@@ -10567,6 +11293,30 @@ private:
10567 } 11293 }
10568 } 11294 }
10569 11295
11296 void transformImportGlobal(ImportGlobal_t* importNode, str_list& out) {
11297 auto uname = static_cast<UnicodeName_t*>(importNode->segs.front());
11298 auto var = _parser.toString(uname);
11299 auto isNormal = _parser.match<Name_t>(var) && _parser.match<Variable_t>(var);
11300 auto varName = unicodeVariableFrom(uname);
11301 str_list temp;
11302 auto it = ++importNode->segs.objects().begin();
11303 for (; it != importNode->segs.objects().end(); ++it) {
11304 temp.emplace_back(_parser.toString(*it));
11305 }
11306 temp.emplace_front(var);
11307 if (isLocal(varName) || !isNormal) {
11308 temp.emplace_front("_G"s);
11309 }
11310 std::string stmt;
11311 if (importNode->target) {
11312 stmt = "const "s + _parser.toString(importNode->target) + '=' + join(temp, "."sv);
11313 } else {
11314 stmt = "const "s + temp.back() + '=' + join(temp, "."sv);
11315 }
11316 auto localAttrib = toAst<LocalAttrib_t>(stmt, importNode);
11317 transformLocalAttrib(localAttrib, out);
11318 }
11319
10570 void transformImport(Import_t* import, str_list& out) { 11320 void transformImport(Import_t* import, str_list& out) {
10571 auto content = import->content.get(); 11321 auto content = import->content.get();
10572 switch (content->get_id()) { 11322 switch (content->get_id()) {
@@ -10579,6 +11329,9 @@ private:
10579 case id<FromImport_t>(): 11329 case id<FromImport_t>():
10580 transformFromImport(static_cast<FromImport_t*>(content), out); 11330 transformFromImport(static_cast<FromImport_t*>(content), out);
10581 break; 11331 break;
11332 case id<ImportGlobal_t>():
11333 transformImportGlobal(static_cast<ImportGlobal_t*>(content), out);
11334 break;
10582 default: YUEE("AST node mismatch", content); break; 11335 default: YUEE("AST node mismatch", content); break;
10583 } 11336 }
10584 } 11337 }
@@ -10590,7 +11343,7 @@ private:
10590 if (expList) { 11343 if (expList) {
10591 if (!currentScope().lastStatement) { 11344 if (!currentScope().lastStatement) {
10592 extraScope = true; 11345 extraScope = true;
10593 temp.push_back(indent() + "do"s + nll(whileNode)); 11346 temp.push_back(indent() + "do"s + nl(whileNode));
10594 pushScope(); 11347 pushScope();
10595 } 11348 }
10596 } 11349 }
@@ -10599,13 +11352,13 @@ private:
10599 auto lenVar = getUnusedName("_len_"sv); 11352 auto lenVar = getUnusedName("_len_"sv);
10600 addToScope(lenVar); 11353 addToScope(lenVar);
10601 auto breakLoopType = getBreakLoopType(whileNode->body, accumVar); 11354 auto breakLoopType = getBreakLoopType(whileNode->body, accumVar);
10602 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(whileNode); 11355 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(whileNode);
10603 temp.emplace_back(clearBuf()); 11356 temp.emplace_back(clearBuf());
10604 _buf << indent() << "local "s << lenVar << " = 1"s << nll(whileNode); 11357 _buf << indent() << "local "s << lenVar << " = 1"s << nl(whileNode);
10605 auto& lenAssign = temp.emplace_back(clearBuf()); 11358 auto& lenAssign = temp.emplace_back(clearBuf());
10606 bool isUntil = _parser.toString(whileNode->type) == "until"sv; 11359 bool isUntil = _parser.toString(whileNode->type) == "until"sv;
10607 auto condStr = transformCondExp(whileNode->condition, isUntil); 11360 auto condStr = transformCondExp(whileNode->condition, isUntil);
10608 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); 11361 temp.push_back(indent() + "while "s + condStr + " do"s + nl(whileNode));
10609 pushScope(); 11362 pushScope();
10610 if (hasBreakWithValue(breakLoopType)) { 11363 if (hasBreakWithValue(breakLoopType)) {
10611 lenAssign.clear(); 11364 lenAssign.clear();
@@ -10620,7 +11373,7 @@ private:
10620 } 11373 }
10621 } 11374 }
10622 popScope(); 11375 popScope();
10623 temp.push_back(indent() + "end"s + nlr(whileNode)); 11376 temp.push_back(indent() + "end"s + nl(whileNode));
10624 if (expList) { 11377 if (expList) {
10625 auto assign = x->new_ptr<Assign_t>(); 11378 auto assign = x->new_ptr<Assign_t>();
10626 assign->values.push_back(toAst<Exp_t>(accumVar, x)); 11379 assign->values.push_back(toAst<Exp_t>(accumVar, x));
@@ -10630,10 +11383,10 @@ private:
10630 transformAssignment(assignment, temp); 11383 transformAssignment(assignment, temp);
10631 if (extraScope) popScope(); 11384 if (extraScope) popScope();
10632 } else { 11385 } else {
10633 temp.push_back(indent() + "return "s + accumVar + nlr(whileNode)); 11386 temp.push_back(indent() + "return "s + accumVar + nl(whileNode));
10634 } 11387 }
10635 if (expList && extraScope) { 11388 if (expList && extraScope) {
10636 temp.push_back(indent() + "end"s + nlr(whileNode)); 11389 temp.push_back(indent() + "end"s + nl(whileNode));
10637 } 11390 }
10638 out.push_back(join(temp)); 11391 out.push_back(join(temp));
10639 } 11392 }
@@ -10655,12 +11408,12 @@ private:
10655 auto lenVar = getUnusedName("_len_"sv); 11408 auto lenVar = getUnusedName("_len_"sv);
10656 addToScope(lenVar); 11409 addToScope(lenVar);
10657 auto breakLoopType = getBreakLoopType(whileNode->body, accumVar); 11410 auto breakLoopType = getBreakLoopType(whileNode->body, accumVar);
10658 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nll(whileNode); 11411 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(whileNode);
10659 temp.emplace_back(clearBuf()); 11412 temp.emplace_back(clearBuf());
10660 auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nll(whileNode)); 11413 auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nl(whileNode));
10661 bool isUntil = _parser.toString(whileNode->type) == "until"sv; 11414 bool isUntil = _parser.toString(whileNode->type) == "until"sv;
10662 auto condStr = transformCondExp(whileNode->condition, isUntil); 11415 auto condStr = transformCondExp(whileNode->condition, isUntil);
10663 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); 11416 temp.push_back(indent() + "while "s + condStr + " do"s + nl(whileNode));
10664 pushScope(); 11417 pushScope();
10665 if (hasBreakWithValue(breakLoopType)) { 11418 if (hasBreakWithValue(breakLoopType)) {
10666 lenAssign.clear(); 11419 lenAssign.clear();
@@ -10675,10 +11428,10 @@ private:
10675 } 11428 }
10676 } 11429 }
10677 popScope(); 11430 popScope();
10678 temp.push_back(indent() + "end"s + nlr(whileNode)); 11431 temp.push_back(indent() + "end"s + nl(whileNode));
10679 temp.push_back(indent() + "return "s + accumVar + nlr(whileNode)); 11432 temp.push_back(indent() + "return "s + accumVar + nl(whileNode));
10680 popScope(); 11433 popScope();
10681 funcStart = anonFuncStart() + nll(whileNode); 11434 funcStart = anonFuncStart() + nl(whileNode);
10682 temp.push_back(indent() + anonFuncEnd()); 11435 temp.push_back(indent() + anonFuncEnd());
10683 popAnonVarArg(); 11436 popAnonVarArg();
10684 popFunctionScope(); 11437 popFunctionScope();
@@ -10708,9 +11461,7 @@ private:
10708 expListAssign->expList.set(expList); 11461 expListAssign->expList.set(expList);
10709 auto stmt = x->new_ptr<Statement_t>(); 11462 auto stmt = x->new_ptr<Statement_t>();
10710 stmt->content.set(expListAssign); 11463 stmt->content.set(expListAssign);
10711 auto body = x->new_ptr<Body_t>(); 11464 repeat->body.set(stmt);
10712 body->content.set(stmt);
10713 repeat->body.set(body);
10714 transformRepeat(repeat, out); 11465 transformRepeat(repeat, out);
10715 return; 11466 return;
10716 } 11467 }
@@ -10721,12 +11472,112 @@ private:
10721 auto breakLoopType = getBreakLoopType(whileNode->body, Empty); 11472 auto breakLoopType = getBreakLoopType(whileNode->body, Empty);
10722 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common); 11473 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common);
10723 popScope(); 11474 popScope();
10724 _buf << indent() << "while "sv << condStr << " do"sv << nll(whileNode); 11475 _buf << indent() << "while "sv << condStr << " do"sv << nl(whileNode);
10725 _buf << temp.back(); 11476 _buf << temp.back();
10726 _buf << indent() << "end"sv << nlr(whileNode); 11477 _buf << indent() << "end"sv << nl(whileNode);
10727 out.push_back(clearBuf()); 11478 out.push_back(clearBuf());
10728 } 11479 }
10729 11480
11481 void transformRepeatInPlace(Repeat_t* repeatNode, str_list& out, ExpList_t* expList = nullptr) {
11482 auto x = repeatNode;
11483 str_list temp;
11484 bool extraScope = false;
11485 if (expList) {
11486 if (!currentScope().lastStatement) {
11487 extraScope = true;
11488 temp.push_back(indent() + "do"s + nl(repeatNode));
11489 pushScope();
11490 }
11491 }
11492 auto accumVar = getUnusedName("_accum_"sv);
11493 addToScope(accumVar);
11494 auto lenVar = getUnusedName("_len_"sv);
11495 addToScope(lenVar);
11496 auto breakLoopType = getBreakLoopType(repeatNode->body, accumVar);
11497 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(repeatNode);
11498 temp.emplace_back(clearBuf());
11499 _buf << indent() << "local "s << lenVar << " = 1"s << nl(repeatNode);
11500 auto& lenAssign = temp.emplace_back(clearBuf());
11501 auto condStr = transformCondExp(repeatNode->condition, false);
11502 temp.push_back(indent() + "repeat"s + nl(repeatNode));
11503 pushScope();
11504 if (hasBreakWithValue(breakLoopType)) {
11505 lenAssign.clear();
11506 transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Common);
11507 } else {
11508 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x);
11509 auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, repeatNode);
11510 assignLeft->followStmt = followStmt.get();
11511 transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft);
11512 if (!assignLeft->followStmtProcessed) {
11513 lenAssign.clear();
11514 }
11515 }
11516 popScope();
11517 temp.push_back(indent() + "until "s + condStr + nl(repeatNode));
11518 if (expList) {
11519 auto assign = x->new_ptr<Assign_t>();
11520 assign->values.push_back(toAst<Exp_t>(accumVar, x));
11521 auto assignment = x->new_ptr<ExpListAssign_t>();
11522 assignment->expList.set(expList);
11523 assignment->action.set(assign);
11524 transformAssignment(assignment, temp);
11525 if (extraScope) popScope();
11526 } else {
11527 temp.push_back(indent() + "return "s + accumVar + nl(repeatNode));
11528 }
11529 if (expList && extraScope) {
11530 temp.push_back(indent() + "end"s + nl(repeatNode));
11531 }
11532 out.push_back(join(temp));
11533 }
11534
11535 void transformRepeatClosure(Repeat_t* repeatNode, str_list& out) {
11536 auto x = repeatNode;
11537 auto simpleValue = x->new_ptr<SimpleValue_t>();
11538 simpleValue->value.set(repeatNode);
11539 if (transformAsUpValueFunc(newExp(simpleValue, x), out)) {
11540 return;
11541 }
11542 str_list temp;
11543 pushAnonFunctionScope();
11544 pushAnonVarArg();
11545 std::string& funcStart = temp.emplace_back();
11546 pushScope();
11547 auto accumVar = getUnusedName("_accum_"sv);
11548 addToScope(accumVar);
11549 auto lenVar = getUnusedName("_len_"sv);
11550 addToScope(lenVar);
11551 auto breakLoopType = getBreakLoopType(repeatNode->body, accumVar);
11552 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(repeatNode);
11553 temp.emplace_back(clearBuf());
11554 auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nl(repeatNode));
11555 auto condStr = transformCondExp(repeatNode->condition, false);
11556 temp.push_back(indent() + "repeat"s + nl(repeatNode));
11557 pushScope();
11558 if (hasBreakWithValue(breakLoopType)) {
11559 lenAssign.clear();
11560 transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Common);
11561 } else {
11562 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x);
11563 auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, repeatNode);
11564 assignLeft->followStmt = followStmt.get();
11565 transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft);
11566 if (!assignLeft->followStmtProcessed) {
11567 lenAssign.clear();
11568 }
11569 }
11570 popScope();
11571 temp.push_back(indent() + "until "s + condStr + nl(repeatNode));
11572 temp.push_back(indent() + "return "s + accumVar + nl(repeatNode));
11573 popScope();
11574 funcStart = anonFuncStart() + nl(repeatNode);
11575 temp.push_back(indent() + anonFuncEnd());
11576 popAnonVarArg();
11577 popFunctionScope();
11578 out.push_back(join(temp));
11579 }
11580
10730 void transformRepeat(Repeat_t* repeat, str_list& out) { 11581 void transformRepeat(Repeat_t* repeat, str_list& out) {
10731 str_list temp; 11582 str_list temp;
10732 pushScope(); 11583 pushScope();
@@ -10737,9 +11588,9 @@ private:
10737 temp.push_back(condVar); 11588 temp.push_back(condVar);
10738 } 11589 }
10739 popScope(); 11590 popScope();
10740 _buf << indent() << "repeat"sv << nll(repeat); 11591 _buf << indent() << "repeat"sv << nl(repeat);
10741 _buf << temp.front(); 11592 _buf << temp.front();
10742 _buf << indent() << "until "sv << temp.back() << nlr(repeat); 11593 _buf << indent() << "until "sv << temp.back() << nl(repeat);
10743 out.push_back(clearBuf()); 11594 out.push_back(clearBuf());
10744 } 11595 }
10745 11596
@@ -10760,12 +11611,28 @@ private:
10760 pushScope(); 11611 pushScope();
10761 } 11612 }
10762 bool extraScope = false; 11613 bool extraScope = false;
11614 if (switchNode->assignment) {
11615 if (needScope) {
11616 extraScope = true;
11617 temp.push_back(indent() + "do"s + nl(x));
11618 pushScope();
11619 }
11620 auto asmt = x->new_ptr<ExpListAssign_t>();
11621 auto expList = x->new_ptr<ExpList_t>();
11622 expList->exprs.push_back(switchNode->target);
11623 if (switchNode->assignment->expList) {
11624 expList->exprs.dup(switchNode->assignment->expList->exprs);
11625 }
11626 asmt->expList.set(expList);
11627 asmt->action.set(switchNode->assignment->assign);
11628 transformAssignment(asmt, temp);
11629 }
10763 auto objVar = singleVariableFrom(switchNode->target, AccessType::Read); 11630 auto objVar = singleVariableFrom(switchNode->target, AccessType::Read);
10764 if (objVar.empty() || !isLocal(objVar)) { 11631 if (objVar.empty() || !isLocal(objVar)) {
10765 if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) { 11632 if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) {
10766 if (needScope) { 11633 if (needScope && !extraScope) {
10767 extraScope = true; 11634 extraScope = true;
10768 temp.push_back(indent() + "do"s + nll(x)); 11635 temp.push_back(indent() + "do"s + nl(x));
10769 pushScope(); 11636 pushScope();
10770 } 11637 }
10771 } 11638 }
@@ -10795,13 +11662,13 @@ private:
10795 } 11662 }
10796 if (tableMatching) { 11663 if (tableMatching) {
10797 if (!firstBranch) { 11664 if (!firstBranch) {
10798 temp.push_back(indent() + "else"s + nll(branch)); 11665 temp.push_back(indent() + "else"s + nl(branch));
10799 pushScope(); 11666 pushScope();
10800 addScope++; 11667 addScope++;
10801 } 11668 }
10802 if (tabCheckVar.empty()) { 11669 if (tabCheckVar.empty()) {
10803 if (!extraScope && needScope) { 11670 if (!extraScope && needScope) {
10804 temp.push_back(indent() + "do"s + nll(branch)); 11671 temp.push_back(indent() + "do"s + nl(branch));
10805 pushScope(); 11672 pushScope();
10806 extraScope = true; 11673 extraScope = true;
10807 } 11674 }
@@ -10809,17 +11676,17 @@ private:
10809 forceAddToScope(typeVar); 11676 forceAddToScope(typeVar);
10810 tabCheckVar = getUnusedName("_tab_"sv); 11677 tabCheckVar = getUnusedName("_tab_"sv);
10811 forceAddToScope(tabCheckVar); 11678 forceAddToScope(tabCheckVar);
10812 temp.push_back(indent() + "local "s + typeVar + " = "s + globalVar("type"sv, branch, AccessType::Read) + '(' + objVar + ')' + nll(branch)); 11679 temp.push_back(indent() + "local "s + typeVar + " = "s + globalVar("type"sv, branch, AccessType::Read) + '(' + objVar + ')' + nl(branch));
10813 temp.push_back(indent() + "local "s + tabCheckVar + " = \"table\" == "s + typeVar + " or \"userdata\" == "s + typeVar + nll(branch)); 11680 temp.push_back(indent() + "local "s + tabCheckVar + " = \"table\" == "s + typeVar + " or \"userdata\" == "s + typeVar + nl(branch));
10814 } 11681 }
10815 std::string matchVar; 11682 std::string matchVar;
10816 bool lastBranch = branches.back() == branch_ && !switchNode->lastBranch; 11683 bool lastBranch = branches.back() == branch_ && !switchNode->lastBranch;
10817 if (!lastBranch) { 11684 if (!lastBranch) {
10818 matchVar = getUnusedName("_match_"sv); 11685 matchVar = getUnusedName("_match_"sv);
10819 forceAddToScope(matchVar); 11686 forceAddToScope(matchVar);
10820 temp.push_back(indent() + "local "s + matchVar + " = false"s + nll(branch)); 11687 temp.push_back(indent() + "local "s + matchVar + " = false"s + nl(branch));
10821 } 11688 }
10822 temp.back().append(indent() + "if "s + tabCheckVar + " then"s + nll(branch)); 11689 temp.back().append(indent() + "if "s + tabCheckVar + " then"s + nl(branch));
10823 pushScope(); 11690 pushScope();
10824 auto chainValue = toAst<ChainValue_t>(objVar, branch); 11691 auto chainValue = toAst<ChainValue_t>(objVar, branch);
10825 auto assignment = assignmentFrom(static_cast<Exp_t*>(valueList->exprs.front()), newExp(chainValue, branch), branch); 11692 auto assignment = assignmentFrom(static_cast<Exp_t*>(valueList->exprs.front()), newExp(chainValue, branch), branch);
@@ -10862,21 +11729,21 @@ private:
10862 } 11729 }
10863 } 11730 }
10864 if (!conds.empty()) { 11731 if (!conds.empty()) {
10865 temp.push_back(indent() + "if "s + join(conds, " and "sv) + " then"s + nll(branch)); 11732 temp.push_back(indent() + "if "s + join(conds, " and "sv) + " then"s + nl(branch));
10866 pushScope(); 11733 pushScope();
10867 } 11734 }
10868 if (!lastBranch) { 11735 if (!lastBranch) {
10869 temp.push_back(indent() + matchVar + " = true"s + nll(branch)); 11736 temp.push_back(indent() + matchVar + " = true"s + nl(branch));
10870 } 11737 }
10871 transform_plain_body(branch->body, temp, usage, assignList); 11738 transform_plain_body(branch->body, temp, usage, assignList);
10872 if (!conds.empty()) { 11739 if (!conds.empty()) {
10873 popScope(); 11740 popScope();
10874 temp.push_back(indent() + "end"s + nll(branch)); 11741 temp.push_back(indent() + "end"s + nl(branch));
10875 } 11742 }
10876 if (!lastBranch) { 11743 if (!lastBranch) {
10877 popScope(); 11744 popScope();
10878 temp.push_back(indent() + "end"s + nll(branch)); 11745 temp.push_back(indent() + "end"s + nl(branch));
10879 temp.push_back(indent() + "if not "s + matchVar + " then"s + nll(branch)); 11746 temp.push_back(indent() + "if not "s + matchVar + " then"s + nl(branch));
10880 pushScope(); 11747 pushScope();
10881 addScope++; 11748 addScope++;
10882 } else { 11749 } else {
@@ -10896,7 +11763,7 @@ private:
10896 } 11763 }
10897 temp.back().append(' ' + tmp.back() + " == "s + (exp == exprs.back() ? objVar : objVar + " or"s)); 11764 temp.back().append(' ' + tmp.back() + " == "s + (exp == exprs.back() ? objVar : objVar + " or"s));
10898 } 11765 }
10899 temp.back().append(" then"s + nll(branch)); 11766 temp.back().append(" then"s + nl(branch));
10900 pushScope(); 11767 pushScope();
10901 transform_plain_body(branch->body, temp, usage, assignList); 11768 transform_plain_body(branch->body, temp, usage, assignList);
10902 popScope(); 11769 popScope();
@@ -10904,7 +11771,7 @@ private:
10904 } 11771 }
10905 if (switchNode->lastBranch) { 11772 if (switchNode->lastBranch) {
10906 if (!firstBranch) { 11773 if (!firstBranch) {
10907 temp.push_back(indent() + "else"s + nll(switchNode->lastBranch)); 11774 temp.push_back(indent() + "else"s + nl(switchNode->lastBranch));
10908 pushScope(); 11775 pushScope();
10909 } else { 11776 } else {
10910 addScope--; 11777 addScope--;
@@ -10914,20 +11781,20 @@ private:
10914 } 11781 }
10915 while (addScope > 0) { 11782 while (addScope > 0) {
10916 addScope--; 11783 addScope--;
10917 temp.push_back(indent() + "end"s + nlr(switchNode)); 11784 temp.push_back(indent() + "end"s + nl(switchNode));
10918 popScope(); 11785 popScope();
10919 } 11786 }
10920 temp.push_back(indent() + "end"s + nlr(switchNode)); 11787 temp.push_back(indent() + "end"s + nl(switchNode));
10921 if (usage == ExpUsage::Closure) { 11788 if (usage == ExpUsage::Closure) {
10922 popFunctionScope(); 11789 popFunctionScope();
10923 popScope(); 11790 popScope();
10924 *funcStart = anonFuncStart() + nll(switchNode); 11791 *funcStart = anonFuncStart() + nl(switchNode);
10925 temp.push_back(indent() + anonFuncEnd()); 11792 temp.push_back(indent() + anonFuncEnd());
10926 popAnonVarArg(); 11793 popAnonVarArg();
10927 } 11794 }
10928 if (extraScope) { 11795 if (extraScope) {
10929 popScope(); 11796 popScope();
10930 temp.push_back(indent() + "end"s + nlr(switchNode)); 11797 temp.push_back(indent() + "end"s + nl(switchNode));
10931 } 11798 }
10932 out.push_back(join(temp)); 11799 out.push_back(join(temp));
10933 } 11800 }
@@ -10946,7 +11813,7 @@ private:
10946 } 11813 }
10947 auto preDefine = toLocalDecl(defs); 11814 auto preDefine = toLocalDecl(defs);
10948 if (!preDefine.empty()) { 11815 if (!preDefine.empty()) {
10949 out.push_back(preDefine + nll(local)); 11816 out.push_back(preDefine + nl(local));
10950 } 11817 }
10951 } 11818 }
10952 } 11819 }
@@ -11151,7 +12018,7 @@ private:
11151 } 12018 }
11152 str_list temp; 12019 str_list temp;
11153 if (localAttrib->forceLocal) { 12020 if (localAttrib->forceLocal) {
11154 temp.push_back(indent() + "local "s + join(vars, ", "sv) + nll(x)); 12021 temp.push_back(indent() + "local "s + join(vars, ", "sv) + nl(x));
11155 } 12022 }
11156 transformAssignment(assignment, temp); 12023 transformAssignment(assignment, temp);
11157 for (const auto& name : vars) { 12024 for (const auto& name : vars) {
@@ -11197,13 +12064,13 @@ private:
11197 auto rit = items.begin(); 12064 auto rit = items.begin();
11198 str_list tmp; 12065 str_list tmp;
11199 while (lit != vars.end()) { 12066 while (lit != vars.end()) {
11200 tmp.push_back(indent() + "local "s + *lit + (target >= 504 ? " <close> = "s : " = "s) + *rit + nll(x)); 12067 tmp.push_back(indent() + "local "s + *lit + (target >= 504 ? " <close> = "s : " = "s) + *rit + nl(x));
11201 lit++; 12068 lit++;
11202 rit++; 12069 rit++;
11203 } 12070 }
11204 temp.push_back(join(tmp)); 12071 temp.push_back(join(tmp));
11205 } else { 12072 } else {
11206 temp.push_back(indent() + "local "s + join(vars, ", "sv) + " = "s + join(items, ", "sv) + nll(x)); 12073 temp.push_back(indent() + "local "s + join(vars, ", "sv) + " = "s + join(items, ", "sv) + nl(x));
11207 str_list leftVars; 12074 str_list leftVars;
11208 pushScope(); 12075 pushScope();
11209 for (size_t i = 0; i < vars.size(); i++) { 12076 for (size_t i = 0; i < vars.size(); i++) {
@@ -11224,7 +12091,7 @@ private:
11224 for (auto item : assignA->values.objects()) { 12091 for (auto item : assignA->values.objects()) {
11225 transformAssignItem(item, items); 12092 transformAssignItem(item, items);
11226 } 12093 }
11227 temp.push_back(indent() + "local "s + join(leftVars, ", "sv) + " = "s + join(items, ", "sv) + nll(x)); 12094 temp.push_back(indent() + "local "s + join(leftVars, ", "sv) + " = "s + join(items, ", "sv) + nl(x));
11228 } 12095 }
11229 for (const auto& var : vars) { 12096 for (const auto& var : vars) {
11230 markVarLocalConst(var); 12097 markVarLocalConst(var);
@@ -11249,7 +12116,7 @@ private:
11249 vars.push_back(item.targetVar); 12116 vars.push_back(item.targetVar);
11250 } 12117 }
11251 } 12118 }
11252 temp.push_back(indent() + "local "s + join(vars, ", "sv) + nll(x)); 12119 temp.push_back(indent() + "local "s + join(vars, ", "sv) + nl(x));
11253 transformAssignment(assignment, temp); 12120 transformAssignment(assignment, temp);
11254 for (const auto& name : vars) { 12121 for (const auto& name : vars) {
11255 markVarLocalConst(name); 12122 markVarLocalConst(name);
@@ -11270,7 +12137,7 @@ private:
11270 auto assignment = assignmentFrom(exp, breakLoop->value, breakLoop); 12137 auto assignment = assignmentFrom(exp, breakLoop->value, breakLoop);
11271 transformAssignment(assignment, out); 12138 transformAssignment(assignment, out);
11272 } 12139 }
11273 out.push_back(indent() + keyword + nll(breakLoop)); 12140 out.push_back(indent() + keyword + nl(breakLoop));
11274 return; 12141 return;
11275 } 12142 }
11276 if (_continueVars.empty()) throw CompileError("continue is not inside a loop"sv, breakLoop); 12143 if (_continueVars.empty()) throw CompileError("continue is not inside a loop"sv, breakLoop);
@@ -11283,8 +12150,8 @@ private:
11283 if (!temp.empty()) { 12150 if (!temp.empty()) {
11284 _buf << temp.back(); 12151 _buf << temp.back();
11285 } 12152 }
11286 _buf << indent() << item.var << " = true"sv << nll(breakLoop); 12153 _buf << indent() << item.var << " = true"sv << nl(breakLoop);
11287 _buf << indent() << "break"sv << nll(breakLoop); 12154 _buf << indent() << "break"sv << nl(breakLoop);
11288 out.push_back(clearBuf()); 12155 out.push_back(clearBuf());
11289 } else { 12156 } else {
11290 transformGoto(toAst<Goto_t>("goto "s + item.var, breakLoop), temp); 12157 transformGoto(toAst<Goto_t>("goto "s + item.var, breakLoop), temp);
@@ -11296,7 +12163,7 @@ private:
11296 if (getLuaTarget(label) < 502) { 12163 if (getLuaTarget(label) < 502) {
11297 throw CompileError("label statement is not available when not targeting Lua version 5.2 or higher"sv, label); 12164 throw CompileError("label statement is not available when not targeting Lua version 5.2 or higher"sv, label);
11298 } 12165 }
11299 auto labelStr = unicodeVariableFrom(label->label->name); 12166 auto labelStr = unicodeVariableFrom(label->label);
11300 int currentScope = _gotoScopes.top(); 12167 int currentScope = _gotoScopes.top();
11301 if (static_cast<int>(_labels.size()) <= currentScope) { 12168 if (static_cast<int>(_labels.size()) <= currentScope) {
11302 _labels.resize(currentScope + 1, std::nullopt); 12169 _labels.resize(currentScope + 1, std::nullopt);
@@ -11310,16 +12177,16 @@ private:
11310 throw CompileError("label '"s + labelStr + "' already defined at line "s + std::to_string(it->second.line), label); 12177 throw CompileError("label '"s + labelStr + "' already defined at line "s + std::to_string(it->second.line), label);
11311 } 12178 }
11312 scope[labelStr] = {label->m_begin.m_line, static_cast<int>(_scopes.size())}; 12179 scope[labelStr] = {label->m_begin.m_line, static_cast<int>(_scopes.size())};
11313 out.push_back(indent() + "::"s + labelStr + "::"s + nll(label)); 12180 out.push_back(indent() + "::"s + labelStr + "::"s + nl(label));
11314 } 12181 }
11315 12182
11316 void transformGoto(Goto_t* gotoNode, str_list& out) { 12183 void transformGoto(Goto_t* gotoNode, str_list& out) {
11317 if (getLuaTarget(gotoNode) < 502) { 12184 if (getLuaTarget(gotoNode) < 502) {
11318 throw CompileError("goto statement is not available when not targeting Lua version 5.2 or higher"sv, gotoNode); 12185 throw CompileError("goto statement is not available when not targeting Lua version 5.2 or higher"sv, gotoNode);
11319 } 12186 }
11320 auto labelStr = unicodeVariableFrom(gotoNode->label->name); 12187 auto labelStr = unicodeVariableFrom(gotoNode->label);
11321 gotos.push_back({gotoNode, labelStr, _gotoScopes.top(), static_cast<int>(_scopes.size())}); 12188 gotos.push_back({gotoNode, labelStr, _gotoScopes.top(), static_cast<int>(_scopes.size())});
11322 out.push_back(indent() + "goto "s + labelStr + nll(gotoNode)); 12189 out.push_back(indent() + "goto "s + labelStr + nl(gotoNode));
11323 } 12190 }
11324 12191
11325 void transformShortTabAppending(ShortTabAppending_t* tab, str_list& out) { 12192 void transformShortTabAppending(ShortTabAppending_t* tab, str_list& out) {
@@ -11383,13 +12250,13 @@ private:
11383 temp.push_back(getPreDefineLine(assignment)); 12250 temp.push_back(getPreDefineLine(assignment));
11384 } 12251 }
11385 assignments.push_front(assignmentFrom(newValue, value, value)); 12252 assignments.push_front(assignmentFrom(newValue, value, value));
11386 temp.push_back(indent() + "do"s + nll(x)); 12253 temp.push_back(indent() + "do"s + nl(x));
11387 pushScope(); 12254 pushScope();
11388 for (auto item : assignments.objects()) { 12255 for (auto item : assignments.objects()) {
11389 transformAssignment(static_cast<ExpListAssign_t*>(item), temp); 12256 transformAssignment(static_cast<ExpListAssign_t*>(item), temp);
11390 } 12257 }
11391 popScope(); 12258 popScope();
11392 temp.push_back(indent() + "end"s + nll(x)); 12259 temp.push_back(indent() + "end"s + nl(x));
11393 out.push_back(join(temp)); 12260 out.push_back(join(temp));
11394 } 12261 }
11395}; 12262};
diff --git a/src/yuescript/yue_compiler.h b/src/yuescript/yue_compiler.h
index d352636..eb5fb16 100644
--- a/src/yuescript/yue_compiler.h
+++ b/src/yuescript/yue_compiler.h
@@ -1,4 +1,4 @@
1/* Copyright (c) 2017-2025 Li Jin <dragon-fly@qq.com> 1/* Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com>
2 2
3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 4
@@ -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;
@@ -51,6 +52,7 @@ struct GlobalVar {
51 int line; 52 int line;
52 int col; 53 int col;
53 AccessType accessType; 54 AccessType accessType;
55 bool defined;
54}; 56};
55 57
56using GlobalVars = std::vector<GlobalVar>; 58using GlobalVars = std::vector<GlobalVar>;
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp
index cd1fd48..1dfe978 100644
--- a/src/yuescript/yue_parser.cpp
+++ b/src/yuescript/yue_parser.cpp
@@ -1,4 +1,4 @@
1/* Copyright (c) 2017-2025 Li Jin <dragon-fly@qq.com> 1/* Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com>
2 2
3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 4
@@ -41,6 +41,24 @@ public:
41 int col; 41 int col;
42}; 42};
43 43
44#define RaiseError(msg, item) \
45 do { \
46 if (reinterpret_cast<State*>(item.user_data)->lax) { \
47 return false; \
48 } else { \
49 throw ParserError(msg, item.begin); \
50 } \
51 } while (false)
52
53#define RaiseErrorI(msg, item) \
54 do { \
55 if (reinterpret_cast<State*>(item.user_data)->lax) { \
56 return -1; \
57 } else { \
58 throw ParserError(msg, item.begin); \
59 } \
60 } while (false)
61
44// clang-format off 62// clang-format off
45YueParser::YueParser() { 63YueParser::YueParser() {
46 plain_space = *set(" \t"); 64 plain_space = *set(" \t");
@@ -57,18 +75,20 @@ YueParser::YueParser() {
57 space = -(and_(set(" \t-\\")) >> *space_one >> -comment); 75 space = -(and_(set(" \t-\\")) >> *space_one >> -comment);
58 space_break = space >> line_break; 76 space_break = space >> line_break;
59 white = space >> *(line_break >> space); 77 white = space >> *(line_break >> space);
78 plain_white = plain_space >> *(line_break >> plain_space);
60 alpha_num = range('a', 'z') | range('A', 'Z') | range('0', '9') | '_'; 79 alpha_num = range('a', 'z') | range('A', 'Z') | range('0', '9') | '_';
61 not_alpha_num = not_(alpha_num); 80 not_alpha_num = not_(alpha_num);
62 Name = (range('a', 'z') | range('A', 'Z') | '_') >> *alpha_num >> not_(larger(255)); 81 Name = (range('a', 'z') | range('A', 'Z') | '_') >> *alpha_num >> not_(larger(255));
63 UnicodeName = (range('a', 'z') | range('A', 'Z') | '_' | larger(255)) >> *(larger(255) | alpha_num); 82 UnicodeName = (range('a', 'z') | range('A', 'Z') | '_' | larger(255)) >> *(larger(255) | alpha_num);
64 num_expo = set("eE") >> -set("+-") >> num_char; 83 must_num_char = num_char | invalid_number_literal_error;
65 num_expo_hex = set("pP") >> -set("+-") >> num_char; 84 num_expo = set("eE") >> -set("+-") >> must_num_char;
85 num_expo_hex = set("pP") >> -set("+-") >> must_num_char;
66 lj_num = -set("uU") >> set("lL") >> set("lL"); 86 lj_num = -set("uU") >> set("lL") >> set("lL");
67 num_char = range('0', '9') >> *(range('0', '9') | '_' >> and_(range('0', '9'))); 87 num_char = range('0', '9') >> *(range('0', '9') | '_' >> and_(range('0', '9')));
68 num_char_hex = range('0', '9') | range('a', 'f') | range('A', 'F'); 88 num_char_hex = range('0', '9') | range('a', 'f') | range('A', 'F');
69 num_lit = num_char_hex >> *(num_char_hex | '_' >> and_(num_char_hex)); 89 num_lit = num_char_hex >> *(num_char_hex | '_' >> and_(num_char_hex));
70 num_bin_lit = set("01") >> *(set("01") | '_' >> and_(set("01"))); 90 num_bin_lit = set("01") >> *(set("01") | '_' >> and_(set("01")));
71 Num = 91 Num = (
72 '0' >> ( 92 '0' >> (
73 set("xX") >> ( 93 set("xX") >> (
74 num_lit >> ( 94 num_lit >> (
@@ -78,50 +98,122 @@ YueParser::YueParser() {
78 true_() 98 true_()
79 ) | ( 99 ) | (
80 '.' >> num_lit >> -num_expo_hex 100 '.' >> num_lit >> -num_expo_hex
81 ) 101 ) | invalid_number_literal_error
82 ) | 102 ) |
83 set("bB") >> num_bin_lit 103 set("bB") >> (num_bin_lit | invalid_number_literal_error)
84 ) | 104 ) |
85 num_char >> ( 105 num_char >> (
86 '.' >> num_char >> -num_expo | 106 '.' >> must_num_char >> -num_expo |
87 num_expo | 107 num_expo |
88 lj_num | 108 lj_num |
89 true_() 109 true_()
90 ) | 110 )
91 '.' >> num_char >> -num_expo; 111 ) >> -(and_(alpha_num) >> invalid_number_literal_error) |
112 '.' >> num_char >> -num_expo >> -(and_(alpha_num) >> invalid_number_literal_error);
92 113
93 cut = false_(); 114 cut = false_();
94 Seperator = true_(); 115 Seperator = true_();
95 116
96 empty_block_error = pl::user(true_(), [](const item_t& item) { 117 auto expect_error = [](std::string_view msg) {
97 throw ParserError("must be followed by a statement or an indented block"sv, item.begin); 118 return pl::user(true_(), [msg](const item_t& item) {
98 return false; 119 RaiseError(msg, item);
99 }); 120 return false;
100 121 });
101 export_expression_error = pl::user(true_(), [](const item_t& item) { 122 };
102 throw ParserError("invalid export expression"sv, item.begin);
103 return false;
104 });
105 123
106 invalid_interpolation_error = pl::user(true_(), [](const item_t& item) { 124 empty_block_error = expect_error(
107 throw ParserError("invalid string interpolation"sv, item.begin); 125 "expected a valid statement or indented block"sv
108 return false; 126 );
109 }); 127 export_expression_error = expect_error(
110 128 "invalid export expression"sv
111 confusing_unary_not_error = pl::user(true_(), [](const item_t& item) { 129 );
112 throw ParserError("deprecated use for unary operator 'not' to be here"sv, item.begin); 130 invalid_interpolation_error = expect_error(
113 return false; 131 "invalid string interpolation"sv
114 }); 132 );
115 133 confusing_unary_not_error = expect_error(
116 table_key_pair_error = pl::user(true_(), [](const item_t& item) { 134 "deprecated use for unary operator 'not' to be here"sv
117 throw ParserError("can not put hash pair in a list"sv, item.begin); 135 );
118 return false; 136 table_key_pair_error = expect_error(
119 }); 137 "can not put hash pair in a list"sv
120 138 );
121 if_assignment_syntax_error = pl::user(true_(), [](const item_t& item) { 139 assignment_expression_syntax_error = expect_error(
122 throw ParserError("use := for if-assignment expression"sv, item.begin); 140 "use := for assignment expression"sv
123 return false; 141 );
124 }); 142 braces_expression_error = expect_error(
143 "syntax error in brace expression"sv
144 );
145 brackets_expression_error = expect_error(
146 "unclosed bracket expression"sv
147 );
148 slice_expression_error = expect_error(
149 "syntax error in slice expression"sv
150 );
151 unclosed_single_string_error = expect_error(
152 "unclosed single-quoted string"sv
153 );
154 unclosed_double_string_error = expect_error(
155 "unclosed double-quoted string"sv
156 );
157 unclosed_lua_string_error = expect_error(
158 "unclosed Lua string"sv
159 );
160 unexpected_comma_error = expect_error(
161 "got unexpected comma"sv
162 );
163 parenthesis_error = expect_error(
164 "expected only one expression in parenthesis"sv
165 );
166 dangling_clause_error = expect_error(
167 "dangling control clause"sv
168 );
169 keyword_as_label_error = expect_error(
170 "keyword cannot be used as a label name"sv
171 );
172 vararg_position_error = expect_error(
173 "vararg '...' must be the last parameter in function argument list"sv
174 );
175 invalid_import_syntax_error = expect_error(
176 "invalid import syntax, expected `import \"X.mod\"`, `import \"X.mod\" as {:name}`, `from mod import name` or `import mod.name`"sv
177 );
178 invalid_import_as_syntax_error = expect_error(
179 "invalid import syntax, expected `import \"X.mod\" as modname` or `import \"X.mod\" as {:name}`"sv
180 );
181 expected_expression_error = expect_error(
182 "expected valid expression"sv
183 );
184 invalid_from_import_error = expect_error(
185 "invalid import syntax, expected `from \"X.mod\" import name` or `from mod import name`"sv
186 );
187 invalid_export_syntax_error = expect_error(
188 "invalid export syntax, expected `export item`, `export item = x`, `export.item = x` or `export default item`"sv
189 );
190 invalid_macro_definition_error = expect_error(
191 "invalid macro definition, expected `macro Name = -> body` or `macro Name = $Name(...)`"sv
192 );
193 invalid_global_declaration_error = expect_error(
194 "invalid global declaration, expected `global name`, `global name = ...`, `global *`, `global ^` or `global class ...`"sv
195 );
196 invalid_local_declaration_error = expect_error(
197 "invalid local declaration, expected `local name`, `local name = ...`, `local *` or `local ^`"sv
198 );
199 invalid_with_syntax_error = expect_error(
200 "invalid 'with' statement"sv
201 );
202 invalid_try_syntax_error = expect_error(
203 "invalid 'try' expression, expected `try expr` or `try block` optionally followed by `catch err` with a handling block"sv
204 );
205 keyword_as_identifier_syntax_error = expect_error(
206 "can not use keyword as identifier"sv
207 );
208 invalid_number_literal_error = expect_error(
209 "invalid numeric literal"sv
210 );
211 invalid_import_literal_error = expect_error(
212 "invalid import path literal, expected a dotted path like X.Y.Z"sv
213 );
214 expected_indentifier_error = expect_error(
215 "expected valid identifer"sv
216 );
125 217
126 #define ensure(patt, finally) ((patt) >> (finally) | (finally) >> cut) 218 #define ensure(patt, finally) ((patt) >> (finally) | (finally) >> cut)
127 219
@@ -162,6 +254,13 @@ YueParser::YueParser() {
162 ) \ 254 ) \
163 ) 255 )
164 256
257 #define disable_until_rule(patt) ( \
258 disable_until >> ( \
259 (patt) >> enable_until | \
260 enable_until >> cut \
261 ) \
262 )
263
165 #define body_with(str) ( \ 264 #define body_with(str) ( \
166 key(str) >> space >> (in_block | Statement) | \ 265 key(str) >> space >> (in_block | Statement) | \
167 in_block | \ 266 in_block | \
@@ -194,20 +293,6 @@ YueParser::YueParser() {
194 return isValid; 293 return isValid;
195 }); 294 });
196 295
197 LabelName = pl::user(UnicodeName, [](const item_t& item) {
198 State* st = reinterpret_cast<State*>(item.user_data);
199 for (auto it = item.begin->m_it; it != item.end->m_it; ++it) {
200 if (*it > 255) {
201 st->buffer.clear();
202 return true;
203 }
204 st->buffer += static_cast<char>(*it);
205 }
206 auto isValid = LuaKeywords.find(st->buffer) == LuaKeywords.end();
207 st->buffer.clear();
208 return isValid;
209 });
210
211 LuaKeyword = pl::user(Name, [](const item_t& item) { 296 LuaKeyword = pl::user(Name, [](const item_t& item) {
212 State* st = reinterpret_cast<State*>(item.user_data); 297 State* st = reinterpret_cast<State*>(item.user_data);
213 for (auto it = item.begin->m_it; it != item.end->m_it; ++it) st->buffer += static_cast<char>(*it); 298 for (auto it = item.begin->m_it; it != item.end->m_it; ++it) st->buffer += static_cast<char>(*it);
@@ -223,29 +308,46 @@ YueParser::YueParser() {
223 308
224 SelfItem = SelfClassName | SelfClass | SelfName | Self; 309 SelfItem = SelfClassName | SelfClass | SelfName | Self;
225 KeyName = SelfItem | Name | UnicodeName; 310 KeyName = SelfItem | Name | UnicodeName;
311 VarArgDef = "..." >> -(space >> Variable);
226 VarArg = "..."; 312 VarArg = "...";
227 313
228 check_indent = pl::user(plain_space, [](const item_t& item) { 314 auto getIndent = [](const item_t& item) -> int {
315 if (item.begin->m_it == item.end->m_it) return 0;
316 State* st = reinterpret_cast<State*>(item.user_data);
317 bool useTab = false;
318 if (st->useTab) {
319 useTab = st->useTab.value();
320 } else {
321 useTab = *item.begin->m_it == '\t';
322 st->useTab = useTab;
323 }
229 int indent = 0; 324 int indent = 0;
230 for (input_it i = item.begin->m_it; i != item.end->m_it; ++i) { 325 if (useTab) {
231 switch (*i) { 326 for (input_it i = item.begin->m_it; i != item.end->m_it; ++i) {
232 case ' ': indent++; break; 327 switch (*i) {
233 case '\t': indent += 4; break; 328 case '\t': indent += 4; break;
329 default: RaiseErrorI("can not mix the use of tabs and spaces as indents"sv, item); break;
330 }
331 }
332 } else {
333 for (input_it i = item.begin->m_it; i != item.end->m_it; ++i) {
334 switch (*i) {
335 case ' ': indent++; break;
336 default: RaiseErrorI("can not mix the use of tabs and spaces as indents"sv, item); break;
337 }
234 } 338 }
235 } 339 }
340 return indent;
341 };
342
343 check_indent = pl::user(plain_space, [getIndent](const item_t& item) {
236 State* st = reinterpret_cast<State*>(item.user_data); 344 State* st = reinterpret_cast<State*>(item.user_data);
237 return st->indents.top() == indent; 345 return st->indents.top() == getIndent(item);
238 }); 346 });
239 check_indent_match = and_(check_indent); 347 check_indent_match = and_(check_indent);
240 348
241 advance = pl::user(plain_space, [](const item_t& item) { 349 advance = pl::user(plain_space, [getIndent](const item_t& item) {
242 int indent = 0; 350 int indent = getIndent(item);
243 for (input_it i = item.begin->m_it; i != item.end->m_it; ++i) {
244 switch (*i) {
245 case ' ': indent++; break;
246 case '\t': indent += 4; break;
247 }
248 }
249 State* st = reinterpret_cast<State*>(item.user_data); 351 State* st = reinterpret_cast<State*>(item.user_data);
250 int top = st->indents.top(); 352 int top = st->indents.top();
251 if (top != -1 && indent > top) { 353 if (top != -1 && indent > top) {
@@ -265,6 +367,12 @@ YueParser::YueParser() {
265 } 367 }
266 } 368 }
267 State* st = reinterpret_cast<State*>(item.user_data); 369 State* st = reinterpret_cast<State*>(item.user_data);
370 if (st->indents.empty()) {
371 RaiseError("unknown indent level"sv, item);
372 }
373 if (st->indents.top() > indent) {
374 RaiseError("unexpected dedent"sv, item);
375 }
268 st->indents.push(indent); 376 st->indents.push(indent);
269 return true; 377 return true;
270 }); 378 });
@@ -285,31 +393,41 @@ YueParser::YueParser() {
285 in_block = space_break >> *(*set(" \t") >> line_break) >> advance_match >> ensure(Block, pop_indent); 393 in_block = space_break >> *(*set(" \t") >> line_break) >> advance_match >> ensure(Block, pop_indent);
286 394
287 LocalFlag = expr('*') | '^'; 395 LocalFlag = expr('*') | '^';
288 LocalValues = NameList >> -(space >> '=' >> space >> (TableBlock | ExpListLow)); 396 LocalValues = NameList >> -(space >> '=' >> space >> (TableBlock | ExpListLow | expected_expression_error));
289 Local = key("local") >> space >> (LocalFlag | LocalValues); 397 Local = key("local") >> space >> (LocalFlag | LocalValues | invalid_local_declaration_error);
290 398
291 ConstAttrib = key("const"); 399 ConstAttrib = key("const");
292 CloseAttrib = key("close"); 400 CloseAttrib = key("close");
293 local_const_item = Variable | SimpleTable | TableLit | Comprehension; 401 local_const_item = Variable | SimpleTable | TableLit | Comprehension;
294 LocalAttrib = ( 402 LocalAttrib = (
295 ConstAttrib >> Seperator >> space >> local_const_item >> *(space >> ',' >> space >> local_const_item) | 403 ConstAttrib >> Seperator >> space >> local_const_item >> *(space >> ',' >> space >> local_const_item) |
296 CloseAttrib >> Seperator >> space >> Variable >> *(space >> ',' >> space >> Variable) 404 CloseAttrib >> Seperator >> space >> must_variable >> *(space >> ',' >> space >> must_variable)
297 ) >> space >> Assign; 405 ) >> space >> Assign;
298 406
299 ColonImportName = '\\' >> space >> Variable; 407 ColonImportName = '\\' >> must_variable;
300 import_name = ColonImportName | Variable; 408 import_name = not_(key("from")) >> (ColonImportName | must_variable);
301 import_name_list = Seperator >> *space_break >> space >> import_name >> *((+space_break | space >> ',' >> *space_break) >> space >> import_name); 409 import_name_list = Seperator >> *space_break >> space >> import_name >> *(
302 ImportFrom = import_name_list >> *space_break >> space >> key("from") >> space >> (ImportLiteral | not_(String) >> Exp); 410 (+space_break | space >> ',' >> *space_break) >> space >> import_name
303 from_import_name_list_line = import_name >> *(space >> ',' >> space >> import_name); 411 );
412 ImportFrom = import_name_list >> *space_break >> space >> key("from") >> space >> (ImportLiteral | not_(String) >> must_exp);
413 from_import_name_list_line = import_name >> *(space >> ',' >> space >> not_(line_break) >> import_name);
304 from_import_name_in_block = +space_break >> advance_match >> ensure(space >> from_import_name_list_line >> *(-(space >> ',') >> +space_break >> check_indent_match >> space >> from_import_name_list_line), pop_indent); 414 from_import_name_in_block = +space_break >> advance_match >> ensure(space >> from_import_name_list_line >> *(-(space >> ',') >> +space_break >> check_indent_match >> space >> from_import_name_list_line), pop_indent);
305 FromImport = key("from") >> space >> (ImportLiteral | not_(String) >> Exp) >> *space_break >> space >> key("import") >> space >> Seperator >> (from_import_name_list_line >> -(space >> ',') >> -from_import_name_in_block | from_import_name_in_block); 415 FromImport = key("from") >> space >> (
416 ImportLiteral | not_(String) >> Exp | invalid_from_import_error
417 ) >> *space_break >> space >> (
418 key("import") | invalid_from_import_error
419 ) >> space >> Seperator >> (
420 from_import_name_in_block |
421 from_import_name_list_line >> -(space >> ',') >> -from_import_name_in_block |
422 invalid_from_import_error
423 );
306 424
307 ImportLiteralInner = (range('a', 'z') | range('A', 'Z') | set("_-") | larger(255)) >> *(alpha_num | '-' | larger(255)); 425 ImportLiteralInner = (range('a', 'z') | range('A', 'Z') | set("_-") | larger(255)) >> *(alpha_num | '-' | larger(255));
308 import_literal_chain = Seperator >> ImportLiteralInner >> *('.' >> ImportLiteralInner); 426 import_literal_chain = Seperator >> ImportLiteralInner >> *('.' >> ImportLiteralInner);
309 ImportLiteral = ( 427 ImportLiteral = (
310 '\'' >> import_literal_chain >> '\'' 428 '\'' >> import_literal_chain >> -(not_('\'') >> invalid_import_literal_error) >> '\''
311 ) | ( 429 ) | (
312 '"' >> import_literal_chain >> '"' 430 '"' >> import_literal_chain >> -(not_('"') >> invalid_import_literal_error) >> '"'
313 ); 431 );
314 432
315 MacroNamePair = MacroName >> ':' >> space >> MacroName; 433 MacroNamePair = MacroName >> ':' >> space >> MacroName;
@@ -325,7 +443,7 @@ YueParser::YueParser() {
325 Exp; 443 Exp;
326 import_tab_list = import_tab_item >> *(space >> ',' >> space >> import_tab_item); 444 import_tab_list = import_tab_item >> *(space >> ',' >> space >> import_tab_item);
327 import_tab_line = ( 445 import_tab_line = (
328 push_indent_match >> (space >> import_tab_list >> pop_indent | pop_indent) 446 push_indent_match >> ensure(space >> import_tab_list, pop_indent)
329 ) | space; 447 ) | space;
330 import_tab_lines = space_break >> import_tab_line >> *(-(space >> ',') >> space_break >> import_tab_line) >> -(space >> ','); 448 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; 449 import_tab_key_value = key_value | ':' >> MacroName | MacroNamePair | ImportAllMacro;
@@ -335,18 +453,22 @@ YueParser::YueParser() {
335 -(space >> ',') >> 453 -(space >> ',') >>
336 -import_tab_lines >> 454 -import_tab_lines >>
337 white >> 455 white >>
338 '}' 456 end_braces_expression
339 ) | ( 457 ) | (
340 Seperator >> import_tab_key_value >> *(space >> ',' >> space >> import_tab_key_value) 458 Seperator >> import_tab_key_value >> *(space >> ',' >> space >> import_tab_key_value)
341 ); 459 );
342 460
343 ImportAs = ImportLiteral >> -(space >> key("as") >> space >> (ImportTabLit | Variable | ImportAllMacro)); 461 ImportAs = ImportLiteral >> -(space >> key("as") >> space >> (
462 ImportTabLit | Variable | ImportAllMacro | invalid_import_as_syntax_error
463 ));
464
465 ImportGlobal = Seperator >> UnicodeName >> *('.' >> UnicodeName) >> space >> not_(',' | key("from")) >> -(key("as") >> space >> must_variable);
344 466
345 Import = key("import") >> space >> (ImportAs | ImportFrom) | FromImport; 467 Import = key("import") >> space >> (ImportGlobal | ImportAs | ImportFrom | invalid_import_syntax_error) | FromImport;
346 468
347 Label = "::" >> LabelName >> "::"; 469 Label = "::" >> (and_(LuaKeyword >> "::") >> keyword_as_label_error | UnicodeName >> "::");
348 470
349 Goto = key("goto") >> space >> LabelName; 471 Goto = key("goto") >> space >> (and_(LuaKeyword >> not_alpha_num) >> keyword_as_label_error | UnicodeName);
350 472
351 ShortTabAppending = "[]" >> space >> Assign; 473 ShortTabAppending = "[]" >> space >> Assign;
352 474
@@ -356,9 +478,14 @@ YueParser::YueParser() {
356 478
357 Return = key("return") >> -(space >> (TableBlock | ExpListLow)); 479 Return = key("return") >> -(space >> (TableBlock | ExpListLow));
358 480
359 with_exp = ExpList >> -(space >> Assign); 481 must_exp = Exp | expected_expression_error;
360 482
361 With = key("with") >> -ExistentialOp >> space >> disable_do_chain_arg_table_block_rule(with_exp) >> space >> body_with("do"); 483 with_exp = ExpList >> -(space >> (':' >> Assign | and_('=') >> assignment_expression_syntax_error)) | expected_expression_error;
484
485 With = key("with") >> -ExistentialOp >> space >> (
486 disable_do_chain_arg_table_block_rule(with_exp) >> space >> body_with("do") |
487 invalid_with_syntax_error
488 );
362 SwitchCase = key("when") >> space >> disable_chain_rule(disable_arg_table_block_rule(SwitchList)) >> space >> body_with("then"); 489 SwitchCase = key("when") >> space >> disable_chain_rule(disable_arg_table_block_rule(SwitchList)) >> space >> body_with("then");
363 switch_else = key("else") >> space >> body; 490 switch_else = key("else") >> space >> body;
364 491
@@ -370,9 +497,11 @@ YueParser::YueParser() {
370 497
371 SwitchList = Seperator >> ( 498 SwitchList = Seperator >> (
372 and_(SimpleTable | TableLit) >> Exp | 499 and_(SimpleTable | TableLit) >> Exp |
373 exp_not_tab >> *(space >> ',' >> space >> exp_not_tab) 500 exp_not_tab >> *(space >> ',' >> space >> exp_not_tab) |
501 expected_expression_error
374 ); 502 );
375 Switch = key("switch") >> space >> Exp >> 503 Switch = key("switch") >> space >>
504 must_exp >> -(space >> Assignment) >>
376 space >> Seperator >> ( 505 space >> Seperator >> (
377 SwitchCase >> space >> ( 506 SwitchCase >> space >> (
378 switch_block | 507 switch_block |
@@ -381,45 +510,53 @@ YueParser::YueParser() {
381 +space_break >> advance_match >> space >> SwitchCase >> switch_block >> pop_indent 510 +space_break >> advance_match >> space >> SwitchCase >> switch_block >> pop_indent
382 ); 511 );
383 512
384 Assignment = -(',' >> space >> ExpList >> space) >> (':' >> Assign | and_('=') >> if_assignment_syntax_error); 513 Assignment = -(',' >> space >> ExpList >> space) >> (':' >> Assign | and_('=') >> assignment_expression_syntax_error);
385 IfCond = disable_chain_rule(disable_arg_table_block_rule(Exp >> -(space >> Assignment))); 514 IfCond = disable_chain_rule(disable_arg_table_block_rule(Exp >> -(space >> Assignment))) | expected_expression_error;
386 if_else_if = -(line_break >> *space_break >> check_indent_match) >> space >> key("elseif") >> space >> IfCond >> space >> body_with("then"); 515 if_else_if = -(line_break >> *space_break >> check_indent_match) >> space >> key("elseif") >> space >> IfCond >> space >> body_with("then");
387 if_else = -(line_break >> *space_break >> check_indent_match) >> space >> key("else") >> space >> body; 516 if_else = -(line_break >> *space_break >> check_indent_match) >> space >> key("else") >> space >> body;
388 IfType = (expr("if") | "unless") >> not_alpha_num; 517 IfType = (expr("if") | "unless") >> not_alpha_num;
389 If = IfType >> space >> IfCond >> space >> opt_body_with("then") >> *if_else_if >> -if_else; 518 If = IfType >> space >> IfCond >> space >> opt_body_with("then") >> *if_else_if >> -if_else;
390 519
391 WhileType = (expr("while") | "until") >> not_alpha_num; 520 WhileType = (expr("while") | pl::user("until", [](const item_t& item) {
392 While = WhileType >> space >> disable_do_chain_arg_table_block_rule(Exp >> -(space >> Assignment)) >> space >> opt_body_with("do"); 521 State* st = reinterpret_cast<State*>(item.user_data);
393 Repeat = key("repeat") >> space >> Body >> line_break >> *space_break >> check_indent_match >> space >> key("until") >> space >> Exp; 522 return st->noUntilStack.empty() || !st->noUntilStack.back();
523 })) >> not_alpha_num;
524 While = key(WhileType) >> space >> (disable_do_chain_arg_table_block_rule(Exp >> -(space >> Assignment)) | expected_expression_error) >> space >> opt_body_with("do");
525 Repeat = key("repeat") >> space >> (
526 in_block >> line_break >> *space_break >> check_indent_match |
527 disable_until_rule(Statement)
528 ) >> space >> key("until") >> space >> must_exp;
394 529
395 for_key = pl::user(key("for"), [](const item_t& item) { 530 for_key = pl::user(key("for"), [](const item_t& item) {
396 State* st = reinterpret_cast<State*>(item.user_data); 531 State* st = reinterpret_cast<State*>(item.user_data);
397 return st->noForStack.empty() || !st->noForStack.top(); 532 return st->noForStack.empty() || !st->noForStack.back();
398 }); 533 });
399 ForStepValue = ',' >> space >> Exp; 534 ForStepValue = ',' >> space >> must_exp;
400 for_args = Variable >> space >> '=' >> space >> Exp >> space >> ',' >> space >> Exp >> space >> -ForStepValue; 535 for_args = Variable >> space >> '=' >> space >> must_exp >> space >> ',' >> space >> must_exp >> space >> -ForStepValue;
401 536
402 For = for_key >> space >> disable_do_chain_arg_table_block_rule(for_args) >> space >> opt_body_with("do"); 537 ForNum = disable_do_chain_arg_table_block_rule(for_args) >> space >> opt_body_with("do");
403 538
404 for_in = StarExp | ExpList; 539 for_in = StarExp | ExpList | expected_expression_error;
405 540
406 ForEach = for_key >> space >> AssignableNameList >> space >> key("in") >> space >> 541 ForEach = AssignableNameList >> space >> key("in") >> space >>
407 disable_do_chain_arg_table_block_rule(for_in) >> space >> opt_body_with("do"); 542 disable_do_chain_arg_table_block_rule(for_in) >> space >> opt_body_with("do");
408 543
544 For = for_key >> space >> (ForNum | ForEach);
545
409 Do = pl::user(key("do"), [](const item_t& item) { 546 Do = pl::user(key("do"), [](const item_t& item) {
410 State* st = reinterpret_cast<State*>(item.user_data); 547 State* st = reinterpret_cast<State*>(item.user_data);
411 return st->noDoStack.empty() || !st->noDoStack.top(); 548 return st->noDoStack.empty() || !st->noDoStack.back();
412 }) >> space >> Body; 549 }) >> space >> Body;
413 550
414 disable_do = pl::user(true_(), [](const item_t& item) { 551 disable_do = pl::user(true_(), [](const item_t& item) {
415 State* st = reinterpret_cast<State*>(item.user_data); 552 State* st = reinterpret_cast<State*>(item.user_data);
416 st->noDoStack.push(true); 553 st->noDoStack.push_back(true);
417 return true; 554 return true;
418 }); 555 });
419 556
420 enable_do = pl::user(true_(), [](const item_t& item) { 557 enable_do = pl::user(true_(), [](const item_t& item) {
421 State* st = reinterpret_cast<State*>(item.user_data); 558 State* st = reinterpret_cast<State*>(item.user_data);
422 st->noDoStack.pop(); 559 st->noDoStack.pop_back();
423 return true; 560 return true;
424 }); 561 });
425 562
@@ -437,46 +574,58 @@ YueParser::YueParser() {
437 574
438 disable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) { 575 disable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) {
439 State* st = reinterpret_cast<State*>(item.user_data); 576 State* st = reinterpret_cast<State*>(item.user_data);
440 st->noDoStack.push(true); 577 st->noDoStack.push_back(true);
441 st->noChainBlockStack.push(true); 578 st->noChainBlockStack.push_back(true);
442 st->noTableBlockStack.push(true); 579 st->noTableBlockStack.push_back(true);
443 return true; 580 return true;
444 }); 581 });
445 582
446 enable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) { 583 enable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) {
447 State* st = reinterpret_cast<State*>(item.user_data); 584 State* st = reinterpret_cast<State*>(item.user_data);
448 st->noDoStack.pop(); 585 st->noDoStack.pop_back();
449 st->noChainBlockStack.pop(); 586 st->noChainBlockStack.pop_back();
450 st->noTableBlockStack.pop(); 587 st->noTableBlockStack.pop_back();
451 return true; 588 return true;
452 }); 589 });
453 590
454 disable_arg_table_block = pl::user(true_(), [](const item_t& item) { 591 disable_arg_table_block = pl::user(true_(), [](const item_t& item) {
455 State* st = reinterpret_cast<State*>(item.user_data); 592 State* st = reinterpret_cast<State*>(item.user_data);
456 st->noTableBlockStack.push(true); 593 st->noTableBlockStack.push_back(true);
457 return true; 594 return true;
458 }); 595 });
459 596
460 enable_arg_table_block = pl::user(true_(), [](const item_t& item) { 597 enable_arg_table_block = pl::user(true_(), [](const item_t& item) {
461 State* st = reinterpret_cast<State*>(item.user_data); 598 State* st = reinterpret_cast<State*>(item.user_data);
462 st->noTableBlockStack.pop(); 599 st->noTableBlockStack.pop_back();
463 return true; 600 return true;
464 }); 601 });
465 602
466 disable_for = pl::user(true_(), [](const item_t& item) { 603 disable_for = pl::user(true_(), [](const item_t& item) {
467 State* st = reinterpret_cast<State*>(item.user_data); 604 State* st = reinterpret_cast<State*>(item.user_data);
468 st->noForStack.push(true); 605 st->noForStack.push_back(true);
469 return true; 606 return true;
470 }); 607 });
471 608
472 enable_for = pl::user(true_(), [](const item_t& item) { 609 enable_for = pl::user(true_(), [](const item_t& item) {
473 State* st = reinterpret_cast<State*>(item.user_data); 610 State* st = reinterpret_cast<State*>(item.user_data);
474 st->noForStack.pop(); 611 st->noForStack.pop_back();
475 return true; 612 return true;
476 }); 613 });
477 614
478 CatchBlock = line_break >> *space_break >> check_indent_match >> space >> key("catch") >> space >> Variable >> space >> in_block; 615 disable_until = pl::user(true_(), [](const item_t& item) {
479 Try = key("try") >> space >> (in_block | Exp) >> -CatchBlock; 616 State* st = reinterpret_cast<State*>(item.user_data);
617 st->noUntilStack.push_back(true);
618 return true;
619 });
620
621 enable_until = pl::user(true_(), [](const item_t& item) {
622 State* st = reinterpret_cast<State*>(item.user_data);
623 st->noUntilStack.pop_back();
624 return true;
625 });
626
627 CatchBlock = line_break >> *space_break >> check_indent_match >> space >> key("catch") >> space >> must_variable >> space >> (in_block | invalid_try_syntax_error);
628 Try = key("try") >> -ExistentialOp >> space >> (in_block | Exp | invalid_try_syntax_error) >> -CatchBlock;
480 629
481 list_value = 630 list_value =
482 and_( 631 and_(
@@ -498,28 +647,33 @@ YueParser::YueParser() {
498 647
499 list_lit_lines = +space_break >> list_lit_line >> *(-(space >> ',') >> space_break >> list_lit_line) >> -(space >> ','); 648 list_lit_lines = +space_break >> list_lit_line >> *(-(space >> ',') >> space_break >> list_lit_line) >> -(space >> ',');
500 649
650 end_brackets_expression = ']' | brackets_expression_error;
651
501 Comprehension = '[' >> not_('[') >> 652 Comprehension = '[' >> not_('[') >>
502 Seperator >> space >> ( 653 Seperator >> space >> (
503 disable_for_rule(list_value) >> space >> ( 654 disable_for_rule(list_value) >> space >> (
504 CompInner >> space >> ']' | 655 CompFor >> space >> end_brackets_expression |
505 (list_value_list >> -(space >> ',') | space >> ',') >> -list_lit_lines >> white >> ']' 656 (list_value_list >> -(space >> ',') | space >> ',') >> -list_lit_lines >> white >> end_brackets_expression
506 ) | 657 ) |
507 list_lit_lines >> white >> ']' | 658 list_lit_lines >> white >> end_brackets_expression |
508 white >> ']' >> not_(space >> '=') 659 white >> ']' >> not_(space >> '=')
509 ); 660 );
510 661
511 CompValue = ',' >> space >> Exp; 662 end_braces_expression = '}' | braces_expression_error;
512 TblComprehension = and_('{') >> ('{' >> space >> disable_for_rule(Exp >> space >> -(CompValue >> space)) >> CompInner >> space >> '}' | braces_expression_error);
513 663
514 CompInner = Seperator >> (CompForEach | CompFor) >> *(space >> comp_clause); 664 CompValue = ',' >> space >> must_exp;
515 StarExp = '*' >> space >> Exp; 665 TblComprehension = '{' >> space >> disable_for_rule(Exp >> space >> -(CompValue >> space)) >> (CompFor | braces_expression_error) >> space >> end_braces_expression;
516 CompForEach = key("for") >> space >> AssignableNameList >> space >> key("in") >> space >> (StarExp | Exp); 666
517 CompFor = key("for") >> space >> Variable >> space >> '=' >> space >> Exp >> space >> ',' >> space >> Exp >> -ForStepValue; 667 CompFor = key("for") >> space >> Seperator >> (CompForNum | CompForEach) >> *(space >> comp_clause);
518 comp_clause = CompFor | CompForEach | key("when") >> space >> Exp; 668 StarExp = '*' >> space >> must_exp;
669 CompForEach = AssignableNameList >> space >> key("in") >> space >> (StarExp | must_exp);
670 CompForNum = Variable >> space >> '=' >> space >> must_exp >> space >> ',' >> space >> must_exp >> -ForStepValue;
671 comp_clause = key("when") >> space >> must_exp | key("for") >> space >> (CompForNum | CompForEach);
519 672
520 Assign = '=' >> space >> Seperator >> ( 673 Assign = '=' >> space >> Seperator >> (
521 With | If | Switch | TableBlock | 674 With | If | Switch | TableBlock |
522 Exp >> *(space >> set(",;") >> space >> Exp) 675 (SpreadListExp | Exp) >> *(space >> set(",;") >> space >> (SpreadListExp | Exp)) |
676 expected_expression_error
523 ); 677 );
524 678
525 UpdateOp = 679 UpdateOp =
@@ -527,7 +681,7 @@ YueParser::YueParser() {
527 ">>" | "<<" | "??" | 681 ">>" | "<<" | "??" |
528 set("+-*/%&|^"); 682 set("+-*/%&|^");
529 683
530 Update = UpdateOp >> '=' >> space >> Exp; 684 Update = UpdateOp >> '=' >> space >> must_exp;
531 685
532 Assignable = AssignableChain | Variable | SelfItem; 686 Assignable = AssignableChain | Variable | SelfItem;
533 687
@@ -548,35 +702,38 @@ YueParser::YueParser() {
548 UnaryExp = *(UnaryOperator >> space) >> expo_exp >> -(space >> In); 702 UnaryExp = *(UnaryOperator >> space) >> expo_exp >> -(space >> In);
549 703
550 pipe_operator = "|>"; 704 pipe_operator = "|>";
551 pipe_value = pipe_operator >> *space_break >> space >> UnaryExp; 705 pipe_value = pipe_operator >> *space_break >> space >> must_unary_exp;
552 pipe_exp = UnaryExp >> *(space >> pipe_value); 706 pipe_exp = UnaryExp >> *(space >> pipe_value);
553 707
554 BinaryOperator = 708 BinaryOperator = (
555 key("or") | 709 key("or") |
556 key("and") | 710 key("and") |
557 "<=" | ">=" | "~=" | "!=" | "==" | 711 "<=" | ">=" | "~=" | "!=" | "==" |
558 ".." | "<<" | ">>" | "//" | 712 ".." | "<<" | ">>" | "//" |
559 set("+-*/%><|&~"); 713 set("+*/%>|&~") |
714 '-' >> not_('>') |
715 '<' >> not_('-')
716 ) >> not_('=');
560 717
561 ExpOpValue = BinaryOperator >> *space_break >> space >> pipe_exp; 718 ExpOpValue = BinaryOperator >> *space_break >> space >> (pipe_exp | expected_expression_error);
562 Exp = Seperator >> pipe_exp >> *(space >> ExpOpValue) >> -(space >> "??" >> space >> Exp); 719 Exp = Seperator >> pipe_exp >> *(space >> ExpOpValue) >> -(space >> "??" >> not_('=') >> *space_break >> space >> must_exp);
563 720
564 disable_chain = pl::user(true_(), [](const item_t& item) { 721 disable_chain = pl::user(true_(), [](const item_t& item) {
565 State* st = reinterpret_cast<State*>(item.user_data); 722 State* st = reinterpret_cast<State*>(item.user_data);
566 st->noChainBlockStack.push(true); 723 st->noChainBlockStack.push_back(true);
567 return true; 724 return true;
568 }); 725 });
569 726
570 enable_chain = pl::user(true_(), [](const item_t& item) { 727 enable_chain = pl::user(true_(), [](const item_t& item) {
571 State* st = reinterpret_cast<State*>(item.user_data); 728 State* st = reinterpret_cast<State*>(item.user_data);
572 st->noChainBlockStack.pop(); 729 st->noChainBlockStack.pop_back();
573 return true; 730 return true;
574 }); 731 });
575 732
576 chain_line = check_indent_match >> space >> (chain_dot_chain | colon_chain) >> -InvokeArgs; 733 chain_line = check_indent_match >> space >> (chain_dot_chain | colon_chain) >> -InvokeArgs;
577 chain_block = pl::user(true_(), [](const item_t& item) { 734 chain_block = pl::user(true_(), [](const item_t& item) {
578 State* st = reinterpret_cast<State*>(item.user_data); 735 State* st = reinterpret_cast<State*>(item.user_data);
579 return st->noChainBlockStack.empty() || !st->noChainBlockStack.top(); 736 return st->noChainBlockStack.empty() || !st->noChainBlockStack.back();
580 }) >> +space_break >> advance_match >> ensure( 737 }) >> +space_break >> advance_match >> ensure(
581 chain_line >> *(+space_break >> chain_line), pop_indent); 738 chain_line >> *(+space_break >> chain_line), pop_indent);
582 ChainValue = 739 ChainValue =
@@ -591,7 +748,7 @@ YueParser::YueParser() {
591 st->expLevel++; 748 st->expLevel++;
592 const int max_exp_level = 100; 749 const int max_exp_level = 100;
593 if (st->expLevel > max_exp_level) { 750 if (st->expLevel > max_exp_level) {
594 throw ParserError("nesting expressions exceeds 100 levels"sv, item.begin); 751 RaiseError("nesting expressions exceeds 100 levels"sv, item);
595 } 752 }
596 return true; 753 return true;
597 }); 754 });
@@ -606,14 +763,22 @@ YueParser::YueParser() {
606 Value = inc_exp_level >> ensure(SimpleValue | SimpleTable | ChainValue | String, dec_exp_level); 763 Value = inc_exp_level >> ensure(SimpleValue | SimpleTable | ChainValue | String, dec_exp_level);
607 764
608 single_string_inner = '\\' >> set("'\\") | not_('\'') >> any_char; 765 single_string_inner = '\\' >> set("'\\") | not_('\'') >> any_char;
609 SingleString = '\'' >> *single_string_inner >> '\''; 766 SingleString = '\'' >> *single_string_inner >> ('\'' | unclosed_single_string_error);
610 767
611 interp = "#{" >> space >> (Exp >> space >> '}' | invalid_interpolation_error); 768 interp = "#{" >> space >> (Exp >> space >> '}' | invalid_interpolation_error);
612 double_string_plain = '\\' >> set("\"\\#") | not_('"') >> any_char; 769 double_string_plain = '\\' >> set("\"\\#") | not_('"') >> any_char;
613 DoubleStringInner = +(not_("#{") >> double_string_plain); 770 DoubleStringInner = +(not_("#{") >> double_string_plain);
614 DoubleStringContent = DoubleStringInner | interp; 771 DoubleStringContent = DoubleStringInner | interp;
615 DoubleString = '"' >> Seperator >> *DoubleStringContent >> '"'; 772 DoubleString = '"' >> Seperator >> *DoubleStringContent >> ('"' | unclosed_double_string_error);
616 String = DoubleString | SingleString | LuaString; 773
774 YAMLIndent = +set(" \t");
775 YAMLLineInner = +('\\' >> set("\"\\#") | not_("#{" | stop) >> any_char);
776 YAMLLineContent = YAMLLineInner | interp;
777 YAMLLine = check_indent_match >> YAMLIndent >> +(YAMLLineContent) |
778 advance_match >> YAMLIndent >> ensure(+YAMLLineContent, pop_indent);
779 YAMLMultiline = '|' >> space >> Seperator >> +(*set(" \t") >> line_break) >> advance_match >> ensure(YAMLLine >> *(+(*set(" \t") >> line_break) >> YAMLLine), pop_indent);
780
781 String = DoubleString | SingleString | LuaString | YAMLMultiline;
617 782
618 lua_string_open = '[' >> *expr('=') >> '['; 783 lua_string_open = '[' >> *expr('=') >> '[';
619 lua_string_close = ']' >> *expr('=') >> ']'; 784 lua_string_close = ']' >> *expr('=') >> ']';
@@ -633,15 +798,15 @@ YueParser::YueParser() {
633 798
634 LuaStringContent = *(not_(LuaStringClose) >> any_char); 799 LuaStringContent = *(not_(LuaStringClose) >> any_char);
635 800
636 LuaString = LuaStringOpen >> -line_break >> LuaStringContent >> LuaStringClose; 801 LuaString = LuaStringOpen >> -line_break >> LuaStringContent >> (LuaStringClose | unclosed_lua_string_error);
637 802
638 Parens = '(' >> *space_break >> space >> Exp >> *space_break >> space >> ')'; 803 Parens = '(' >> (*space_break >> space >> Exp >> *space_break >> space >> ')' | parenthesis_error);
639 Callable = Variable | SelfItem | MacroName | Parens; 804 Callable = Variable | SelfItem | MacroName | Parens;
640 805
641 fn_args_value_list = Exp >> *(space >> ',' >> space >> Exp); 806 fn_args_value_list = Exp >> *(space >> ',' >> space >> Exp);
642 807
643 fn_args_lit_line = ( 808 fn_args_lit_line = (
644 push_indent_match >> (space >> fn_args_value_list >> pop_indent | pop_indent) 809 push_indent_match >> ensure(space >> fn_args_value_list, pop_indent)
645 ) | ( 810 ) | (
646 space 811 space
647 ); 812 );
@@ -651,14 +816,14 @@ YueParser::YueParser() {
651 fn_args = 816 fn_args =
652 '(' >> -(space >> fn_args_value_list >> -(space >> ',')) >> 817 '(' >> -(space >> fn_args_value_list >> -(space >> ',')) >>
653 -fn_args_lit_lines >> 818 -fn_args_lit_lines >>
654 white >> ')' | space >> '!' >> not_('='); 819 white >> -(and_(',') >> unexpected_comma_error) >>')' | space >> '!' >> not_('=');
655 820
656 meta_index = Name | index | String; 821 meta_index = Name | index | String;
657 Metatable = '<' >> space >> '>'; 822 Metatable = '<' >> space >> '>';
658 Metamethod = '<' >> space >> meta_index >> space >> '>'; 823 Metamethod = '<' >> space >> meta_index >> space >> '>';
659 824
660 ExistentialOp = '?' >> not_('?'); 825 ExistentialOp = '?' >> not_('?');
661 TableAppendingOp = and_('[') >> ("[]" | brackets_expression_error); 826 TableAppendingOp = and_('[') >> "[]";
662 PlainItem = +any_char; 827 PlainItem = +any_char;
663 828
664 chain_call = ( 829 chain_call = (
@@ -683,7 +848,8 @@ YueParser::YueParser() {
683 chain_with_colon = +chain_item >> -colon_chain; 848 chain_with_colon = +chain_item >> -colon_chain;
684 chain_items = chain_with_colon | colon_chain; 849 chain_items = chain_with_colon | colon_chain;
685 850
686 index = '[' >> not_('[') >> space >> Exp >> space >> ']'; 851 index = '[' >> not_('[') >> space >> (ReversedIndex >> and_(space >> ']') | Exp) >> space >> ']';
852 ReversedIndex = '#' >> space >> -('-' >> space >> Exp);
687 chain_item = 853 chain_item =
688 Invoke >> -ExistentialOp | 854 Invoke >> -ExistentialOp |
689 DotChainItem >> -ExistentialOp | 855 DotChainItem >> -ExistentialOp |
@@ -722,10 +888,8 @@ YueParser::YueParser() {
722 SpreadExp | 888 SpreadExp |
723 NormalDef; 889 NormalDef;
724 890
725 table_value_list = table_value >> *(space >> ',' >> space >> table_value);
726
727 table_lit_line = ( 891 table_lit_line = (
728 push_indent_match >> (space >> table_value_list >> pop_indent | pop_indent) 892 push_indent_match >> (space >> not_(line_break | '}') >> (table_value | expected_expression_error) >> *(space >> ',' >> space >> table_value) >> pop_indent | pop_indent)
729 ) | ( 893 ) | (
730 space 894 space
731 ); 895 );
@@ -734,13 +898,15 @@ YueParser::YueParser() {
734 898
735 TableLit = 899 TableLit =
736 '{' >> Seperator >> 900 '{' >> Seperator >>
737 -(space >> table_value_list >> -(space >> ',')) >> 901 -(space >> table_value >> *(space >> ',' >> space >> table_value) >> -(space >> ',')) >>
738 -table_lit_lines >> 902 (
739 white >> '}'; 903 table_lit_lines >> white >> end_braces_expression |
904 white >> '}'
905 );
740 906
741 table_block_inner = Seperator >> key_value_line >> *(+space_break >> key_value_line); 907 table_block_inner = Seperator >> key_value_line >> *(+space_break >> key_value_line);
742 TableBlock = +space_break >> advance_match >> ensure(table_block_inner, pop_indent); 908 TableBlock = +space_break >> advance_match >> ensure(table_block_inner, pop_indent);
743 TableBlockIndent = '*' >> Seperator >> disable_arg_table_block_rule( 909 TableBlockIndent = ('*' | '-' >> space_one) >> Seperator >> disable_arg_table_block_rule(
744 space >> key_value_list >> -(space >> ',') >> 910 space >> key_value_list >> -(space >> ',') >>
745 -(+space_break >> advance_match >> space >> ensure(key_value_list >> -(space >> ',') >> *(+space_break >> key_value_line), pop_indent))); 911 -(+space_break >> advance_match >> space >> ensure(key_value_list >> -(space >> ',') >> *(+space_break >> key_value_line), pop_indent)));
746 912
@@ -755,13 +921,18 @@ YueParser::YueParser() {
755 ClassDecl = 921 ClassDecl =
756 key("class") >> not_(':') >> disable_arg_table_block_rule( 922 key("class") >> not_(':') >> disable_arg_table_block_rule(
757 -(space >> Assignable) >> 923 -(space >> Assignable) >>
758 -(space >> key("extends") >> prevent_indent >> space >> ensure(Exp, pop_indent)) >> 924 -(space >> key("extends") >> prevent_indent >> space >> ensure(must_exp, pop_indent)) >>
759 -(space >> key("using") >> prevent_indent >> space >> ensure(ExpList, pop_indent)) 925 -(space >> key("using") >> prevent_indent >> space >> ensure(ExpList | expected_expression_error, pop_indent))
760 ) >> -ClassBlock; 926 ) >> -ClassBlock;
761 927
762 GlobalValues = NameList >> -(space >> '=' >> space >> (TableBlock | ExpListLow)); 928 GlobalValues = NameList >> -(space >> '=' >> space >> (TableBlock | ExpListLow | expected_expression_error));
763 GlobalOp = expr('*') | '^'; 929 GlobalOp = expr('*') | '^';
764 Global = key("global") >> space >> (-(ConstAttrib >> space) >> ClassDecl | GlobalOp | -(ConstAttrib >> space) >> GlobalValues); 930 Global = key("global") >> space >> (
931 -(ConstAttrib >> space) >> ClassDecl |
932 GlobalOp |
933 -(ConstAttrib >> space) >> GlobalValues |
934 invalid_global_declaration_error
935 );
765 936
766 ExportDefault = key("default"); 937 ExportDefault = key("default");
767 938
@@ -773,10 +944,10 @@ YueParser::YueParser() {
773 pl::user(space >> ExportDefault >> space >> Exp, [](const item_t& item) { 944 pl::user(space >> ExportDefault >> space >> Exp, [](const item_t& item) {
774 State* st = reinterpret_cast<State*>(item.user_data); 945 State* st = reinterpret_cast<State*>(item.user_data);
775 if (st->exportDefault) { 946 if (st->exportDefault) {
776 throw ParserError("export default has already been declared"sv, item.begin); 947 RaiseError("export default has already been declared"sv, item);
777 } 948 }
778 if (st->exportCount > 1) { 949 if (st->exportCount > 1) {
779 throw ParserError("there are items already being exported"sv, item.begin); 950 RaiseError("there are items already being exported"sv, item);
780 } 951 }
781 st->exportDefault = true; 952 st->exportDefault = true;
782 return true; 953 return true;
@@ -784,17 +955,17 @@ YueParser::YueParser() {
784 not_(space >> ExportDefault) >> pl::user(true_(), [](const item_t& item) { 955 not_(space >> ExportDefault) >> pl::user(true_(), [](const item_t& item) {
785 State* st = reinterpret_cast<State*>(item.user_data); 956 State* st = reinterpret_cast<State*>(item.user_data);
786 if (st->exportDefault && st->exportCount > 1) { 957 if (st->exportDefault && st->exportCount > 1) {
787 throw ParserError("can not export any more items when 'export default' is declared"sv, item.begin); 958 RaiseError("can not export any more items when 'export default' is declared"sv, item);
788 } 959 }
789 return true; 960 return true;
790 }) >> ( 961 }) >> (
791 and_(set(".[")) >> ((pl::user(and_('.' >> Metatable), [](const item_t& item) { 962 and_(set(".[")) >> ((pl::user(and_('.' >> Metatable), [](const item_t& item) {
792 State* st = reinterpret_cast<State*>(item.user_data); 963 State* st = reinterpret_cast<State*>(item.user_data);
793 if (st->exportMetatable) { 964 if (st->exportMetatable) {
794 throw ParserError("module metatable duplicated"sv, item.begin); 965 RaiseError("module metatable duplicated"sv, item);
795 } 966 }
796 if (st->exportMetamethod) { 967 if (st->exportMetamethod) {
797 throw ParserError("metatable should be exported before metamethod"sv, item.begin); 968 RaiseError("metatable should be exported before metamethod"sv, item);
798 } 969 }
799 st->exportMetatable = true; 970 st->exportMetatable = true;
800 return true; 971 return true;
@@ -809,7 +980,8 @@ YueParser::YueParser() {
809 State* st = reinterpret_cast<State*>(item.user_data); 980 State* st = reinterpret_cast<State*>(item.user_data);
810 st->exportMacro = true; 981 st->exportMacro = true;
811 return true; 982 return true;
812 }) 983 }) |
984 invalid_export_syntax_error
813 ) >> not_(space >> StatementAppendix); 985 ) >> not_(space >> StatementAppendix);
814 986
815 VariablePair = ':' >> Variable; 987 VariablePair = ':' >> Variable;
@@ -819,13 +991,13 @@ YueParser::YueParser() {
819 KeyName | 991 KeyName |
820 '[' >> not_('[') >> space >> Exp >> space >> ']' | 992 '[' >> not_('[') >> space >> Exp >> space >> ']' |
821 String 993 String
822 ) >> ':' >> not_(':') >> space >> 994 ) >> ':' >> not_(':' | '=' >> not_('>')) >> space >>
823 (Exp | TableBlock | +space_break >> space >> Exp); 995 (Exp | TableBlock | +space_break >> space >> Exp | expected_expression_error);
824 996
825 MetaVariablePair = ":<" >> space >> Variable >> space >> '>'; 997 MetaVariablePair = ":<" >> space >> must_variable >> space >> '>';
826 998
827 MetaNormalPair = '<' >> space >> -meta_index >> space >> ">:" >> space >> 999 MetaNormalPair = '<' >> space >> -meta_index >> space >> ">:" >> space >>
828 (Exp | TableBlock | +space_break >> space >> Exp); 1000 (Exp | TableBlock | +space_break >> space >> Exp | expected_expression_error);
829 1001
830 destruct_def = -(space >> '=' >> space >> Exp); 1002 destruct_def = -(space >> '=' >> space >> Exp);
831 VariablePairDef = VariablePair >> destruct_def; 1003 VariablePairDef = VariablePair >> destruct_def;
@@ -843,29 +1015,39 @@ YueParser::YueParser() {
843 key_value_line = check_indent_match >> space >> ( 1015 key_value_line = check_indent_match >> space >> (
844 key_value_list >> -(space >> ',') | 1016 key_value_list >> -(space >> ',') |
845 TableBlockIndent | 1017 TableBlockIndent |
846 '*' >> space >> (SpreadExp | Exp | TableBlock) 1018 ('*' | '-' >> space_one) >> space >> (SpreadExp | Exp | TableBlock)
847 ); 1019 );
848 1020
849 fn_arg_def_list = FnArgDef >> *(space >> ',' >> space >> FnArgDef); 1021 fn_arg_def_list = FnArgDef >> *(space >> ',' >> space >> FnArgDef);
850 1022
851 fn_arg_def_lit_line = ( 1023 fn_arg_def_lit_line = (
852 push_indent_match >> (space >> fn_arg_def_list >> pop_indent | pop_indent) 1024 push_indent_match >> ensure(space >> fn_arg_def_list, pop_indent)
853 ) | ( 1025 ) | (
854 space 1026 space
855 ); 1027 );
856 1028
857 fn_arg_def_lit_lines = fn_arg_def_lit_line >> *(-(space >> ',') >> space_break >> fn_arg_def_lit_line); 1029 fn_arg_def_lit_lines = fn_arg_def_lit_line >> *(-(space >> ',') >> space_break >> fn_arg_def_lit_line);
858 1030
859 FnArgDef = (Variable | SelfItem >> -ExistentialOp) >> -(space >> '=' >> space >> Exp); 1031 FnArgDef = (Variable | SelfItem >> -ExistentialOp) >> -(space >> '`' >> space >> Name) >> -(space >> '=' >> space >> Exp) | TableLit | SimpleTable;
860 1032
861 FnArgDefList = Seperator >> ( 1033 check_vararg_position = and_(white >> (')' | key("using"))) | white >> -(',' >> white) >> vararg_position_error;
862 fn_arg_def_lit_lines >> -(-(space >> ',') >> white >> VarArg) |
863 white >> VarArg
864 );
865 1034
866 OuterVarShadow = key("using") >> space >> (NameList | key("nil")); 1035 var_arg_def = (
1036 VarArgDef |
1037 +space_break >> push_indent_match >> ensure(space >> VarArgDef >> -(space >> '`' >> space >> Name), pop_indent)
1038 ) >> check_vararg_position;
867 1039
868 FnArgsDef = '(' >> *space_break >> -FnArgDefList >> -(white >> OuterVarShadow) >> white >> ')'; 1040 FnArgDefList = Seperator >>
1041 -fn_arg_def_list >>
1042 -(-(space >> ',') >> +space_break >> fn_arg_def_lit_lines) >>
1043 -(-(space >> ',') >> space >> var_arg_def);
1044
1045 OuterVarShadow = key("using") >> space >> (key("nil") | NameList);
1046
1047 outer_var_shadow_def = OuterVarShadow |
1048 +space_break >> push_indent_match >> ensure(space >> OuterVarShadow, pop_indent);
1049
1050 FnArgsDef = '(' >> space >> -FnArgDefList >> -(space >> outer_var_shadow_def) >> white >> -(and_(',') >> unexpected_comma_error) >> ')';
869 FnArrow = expr("->") | "=>"; 1051 FnArrow = expr("->") | "=>";
870 FunLit = pl::user(true_(), [](const item_t& item) { 1052 FunLit = pl::user(true_(), [](const item_t& item) {
871 State* st = reinterpret_cast<State*>(item.user_data); 1053 State* st = reinterpret_cast<State*>(item.user_data);
@@ -877,23 +1059,30 @@ YueParser::YueParser() {
877 ) >> space >> FnArrow >> -(space >> Body); 1059 ) >> space >> FnArrow >> -(space >> Body);
878 1060
879 MacroName = '$' >> UnicodeName; 1061 MacroName = '$' >> UnicodeName;
880 macro_args_def = '(' >> white >> -FnArgDefList >> white >> ')'; 1062 macro_args_def = '(' >> space >> -FnArgDefList >> white >> -(and_(',') >> unexpected_comma_error) >> ')';
881 MacroLit = -(macro_args_def >> space) >> "->" >> space >> Body; 1063 MacroLit = -(macro_args_def >> space) >> "->" >> space >> Body;
882 MacroFunc = MacroName >> (Invoke | InvokeArgs); 1064 MacroFunc = MacroName >> (Invoke | InvokeArgs);
883 Macro = key("macro") >> space >> UnicodeName >> space >> '=' >> space >> (MacroLit | MacroFunc); 1065 Macro = key("macro") >> space >> (
1066 UnicodeName >> space >> '=' >> space >> (MacroLit | MacroFunc | invalid_macro_definition_error) |
1067 invalid_macro_definition_error
1068 );
884 MacroInPlace = '$' >> space >> "->" >> space >> Body; 1069 MacroInPlace = '$' >> space >> "->" >> space >> Body;
885 1070
886 NameList = Seperator >> Variable >> *(space >> ',' >> space >> Variable); 1071 must_variable = Variable | and_(LuaKeyword >> not_alpha_num) >> keyword_as_identifier_syntax_error | expected_indentifier_error;
887 NameOrDestructure = Variable | TableLit | Comprehension; 1072
1073 NameList = Seperator >> must_variable >> *(space >> ',' >> space >> must_variable);
1074 NameOrDestructure = Variable | TableLit | Comprehension | SimpleTable | expected_expression_error;
888 AssignableNameList = Seperator >> NameOrDestructure >> *(space >> ',' >> space >> NameOrDestructure); 1075 AssignableNameList = Seperator >> NameOrDestructure >> *(space >> ',' >> space >> NameOrDestructure);
889 1076
890 FnArrowBack = '<' >> set("-="); 1077 FnArrowBack = '<' >> set("-=");
891 Backcall = -(FnArgsDef >> space) >> FnArrowBack >> space >> ChainValue; 1078 Backcall = -(FnArgsDef >> space) >> FnArrowBack >> space >> ChainValue;
892 SubBackcall = FnArrowBack >> space >> ChainValue; 1079 SubBackcall = FnArrowBack >> space >> ChainValue;
893 1080
1081 must_unary_exp = UnaryExp | expected_expression_error;
1082
894 PipeBody = Seperator >> 1083 PipeBody = Seperator >>
895 pipe_operator >> space >> UnaryExp >> 1084 pipe_operator >> space >> must_unary_exp >>
896 *(+space_break >> check_indent_match >> space >> pipe_operator >> space >> UnaryExp); 1085 *(+space_break >> check_indent_match >> space >> pipe_operator >> space >> must_unary_exp);
897 1086
898 ExpList = Seperator >> Exp >> *(space >> ',' >> space >> Exp); 1087 ExpList = Seperator >> Exp >> *(space >> ',' >> space >> Exp);
899 ExpListLow = Seperator >> Exp >> *(space >> set(",;") >> space >> Exp); 1088 ExpListLow = Seperator >> Exp >> *(space >> set(",;") >> space >> Exp);
@@ -903,7 +1092,7 @@ YueParser::YueParser() {
903 1092
904 arg_table_block = pl::user(true_(), [](const item_t& item) { 1093 arg_table_block = pl::user(true_(), [](const item_t& item) {
905 State* st = reinterpret_cast<State*>(item.user_data); 1094 State* st = reinterpret_cast<State*>(item.user_data);
906 return st->noTableBlockStack.empty() || !st->noTableBlockStack.top(); 1095 return st->noTableBlockStack.empty() || !st->noTableBlockStack.back();
907 }) >> TableBlock; 1096 }) >> TableBlock;
908 1097
909 invoke_args_with_table = 1098 invoke_args_with_table =
@@ -912,38 +1101,17 @@ YueParser::YueParser() {
912 space_break >> advance_match >> arg_block >> -(-(space >> ',') >> arg_table_block) 1101 space_break >> advance_match >> arg_block >> -(-(space >> ',') >> arg_table_block)
913 ) | arg_table_block; 1102 ) | arg_table_block;
914 1103
915 leading_spaces_error = pl::user(+space_one >> '(' >> space >> Exp >> +(space >> ',' >> space >> Exp) >> space >> ')', [](const item_t& item) {
916 throw ParserError("write invoke arguments in parentheses without leading spaces or just leading spaces without parentheses"sv, item.begin);
917 return false;
918 });
919
920 InvokeArgs = 1104 InvokeArgs =
921 not_(set("-~") | "[]") >> space >> Seperator >> ( 1105 not_(set("-~") | "[]") >> space >> Seperator >> (
922 Exp >> *(space >> ',' >> space >> Exp) >> -(space >> invoke_args_with_table) | 1106 Exp >> *(space >> ',' >> space >> Exp) >> -(space >> invoke_args_with_table) |
923 arg_table_block | 1107 arg_table_block
924 leading_spaces_error
925 ); 1108 );
926 1109
927 ConstValue = (expr("nil") | "true" | "false") >> not_alpha_num; 1110 ConstValue = (expr("nil") | "true" | "false") >> not_alpha_num;
928 1111
929 braces_expression_error = pl::user(true_(), [](const item_t& item) {
930 throw ParserError("syntax error in brace expression"sv, item.begin);
931 return false;
932 });
933
934 brackets_expression_error = pl::user(true_(), [](const item_t& item) {
935 throw ParserError("syntax error in bracket expression"sv, item.begin);
936 return false;
937 });
938
939 slice_expression_error = pl::user(true_(), [](const item_t& item) {
940 throw ParserError("syntax error in slice expression"sv, item.begin);
941 return false;
942 });
943
944 SimpleValue = 1112 SimpleValue =
945 TableLit | ConstValue | If | Switch | Try | With | 1113 TableLit | ConstValue | If | Switch | Try | With |
946 ClassDecl | ForEach | For | While | Do | 1114 ClassDecl | For | While | Repeat | Do |
947 UnaryValue | TblComprehension | Comprehension | 1115 UnaryValue | TblComprehension | Comprehension |
948 FunLit | Num | VarArg; 1116 FunLit | Num | VarArg;
949 1117
@@ -952,63 +1120,59 @@ YueParser::YueParser() {
952 IfLine = IfType >> space >> IfCond; 1120 IfLine = IfType >> space >> IfCond;
953 WhileLine = WhileType >> space >> Exp; 1121 WhileLine = WhileType >> space >> Exp;
954 1122
955 YueLineComment = *(not_(set("\r\n")) >> any_char);
956 yue_line_comment = "--" >> YueLineComment >> and_(stop);
957 MultilineCommentInner = multi_line_content;
958 YueMultilineComment = multi_line_open >> MultilineCommentInner >> multi_line_close;
959 yue_comment = check_indent >> (
960 (
961 YueMultilineComment >>
962 *(set(" \t") | YueMultilineComment) >>
963 -yue_line_comment
964 ) | yue_line_comment
965 ) >> and_(line_break);
966
967 ChainAssign = Seperator >> Exp >> +(space >> '=' >> space >> Exp >> space >> and_('=')) >> space >> Assign; 1123 ChainAssign = Seperator >> Exp >> +(space >> '=' >> space >> Exp >> space >> and_('=')) >> space >> Assign;
968 1124
969 StatementAppendix = (IfLine | WhileLine | CompInner) >> space; 1125 StatementAppendix = (IfLine | WhileLine | CompFor) >> space;
970 Statement = 1126 Statement =
971 Seperator >> 1127 (
972 -( 1128 Import | While | Repeat | For |
973 yue_comment >>
974 *(line_break >> yue_comment) >>
975 line_break >>
976 check_indent_match
977 ) >>
978 space >> (
979 Import | While | Repeat | For | ForEach |
980 Return | Local | Global | Export | Macro | 1129 Return | Local | Global | Export | Macro |
981 MacroInPlace | BreakLoop | Label | Goto | ShortTabAppending | 1130 MacroInPlace | BreakLoop | Label | Goto | ShortTabAppending |
982 LocalAttrib | Backcall | PipeBody | ExpListAssign | ChainAssign | 1131 LocalAttrib | Backcall | PipeBody | ExpListAssign | ChainAssign |
983 StatementAppendix >> empty_block_error 1132 StatementAppendix >> empty_block_error |
984 ) >> 1133 and_(key("else") | key("elseif") | key("when")) >> dangling_clause_error
985 space >> 1134 ) >> space >>
986 -StatementAppendix; 1135 -StatementAppendix;
987 1136
988 StatementSep = white >> (set("('\"") | "[[" | "[="); 1137 StatementSep = white >> (set("('\"") | "[[" | "[=");
989 1138
990 Body = in_block | Statement; 1139 Body = in_block | Statement;
991 1140
992 empty_line_break = 1141 YueLineComment = *(not_(set("\r\n")) >> any_char);
993 check_indent >> (multi_line_comment >> space | comment) >> and_(stop) | 1142 yue_line_comment = "--" >> YueLineComment >> and_(stop);
994 advance >> ensure(multi_line_comment >> space | comment, pop_indent) >> and_(stop) | 1143 YueMultilineComment = multi_line_content;
995 plain_space >> and_(line_break); 1144 yue_multiline_comment = multi_line_open >> YueMultilineComment >> multi_line_close;
1145 comment_line =
1146 yue_multiline_comment >> *(set(" \t") | yue_multiline_comment) >> plain_space >> -yue_line_comment |
1147 yue_line_comment;
1148 YueComment =
1149 check_indent >> comment_line >> and_(stop) |
1150 advance >> ensure(comment_line, pop_indent) >> and_(stop);
1151
1152 EmptyLine = plain_space >> and_(stop);
996 1153
997 indentation_error = pl::user(not_(pipe_operator | eof()), [](const item_t& item) { 1154 indentation_error = pl::user(not_(pipe_operator | eof()), [](const item_t& item) {
998 throw ParserError("unexpected indent"sv, item.begin); 1155 RaiseError("unexpected indent"sv, item);
999 return false; 1156 return false;
1000 }); 1157 });
1001 1158
1002 line = ( 1159 line = *(EmptyLine >> line_break) >> (
1003 check_indent_match >> Statement | 1160 check_indent_match >> space >> Statement |
1004 empty_line_break | 1161 YueComment |
1005 advance_match >> ensure(space >> (indentation_error | Statement), pop_indent) 1162 advance_match >> ensure(space >> (indentation_error | Statement), pop_indent)
1006 ); 1163 );
1007 Block = Seperator >> line >> *(+line_break >> line); 1164 Block = Seperator >> (pl::user(true_(), [](const item_t& item) {
1165 State* st = reinterpret_cast<State*>(item.user_data);
1166 return st->lax;
1167 }) >> lax_line >> *(line_break >> lax_line) | line >> *(line_break >> line));
1008 1168
1009 shebang = "#!" >> *(not_(stop) >> any_char); 1169 shebang = "#!" >> *(not_(stop) >> any_char);
1010 BlockEnd = Block >> white >> stop; 1170 BlockEnd = Block >> plain_white >> stop;
1011 File = -shebang >> -Block >> white >> stop; 1171 File = -shebang >> -Block >> plain_white >> stop;
1172
1173 lax_line = advance_match >> ensure(*(not_(stop) >> any()), pop_indent) |
1174 line >> and_(stop) |
1175 check_indent_match >> *(not_(stop) >> any());
1012} 1176}
1013// clang-format on 1177// clang-format on
1014 1178
@@ -1019,7 +1183,7 @@ bool YueParser::startWith(std::string_view codes, rule& r) {
1019 } 1183 }
1020 try { 1184 try {
1021 if (!codes.empty()) { 1185 if (!codes.empty()) {
1022 converted = std::make_unique<input>(_converter.from_bytes(&codes.front(), &codes.back() + 1)); 1186 converted = std::make_unique<input>(utf8_decode({&codes.front(), &codes.back() + 1}));
1023 } else { 1187 } else {
1024 converted = std::make_unique<input>(); 1188 converted = std::make_unique<input>();
1025 } 1189 }
@@ -1038,24 +1202,25 @@ bool YueParser::startWith(std::string_view codes, rule& r) {
1038 return true; 1202 return true;
1039} 1203}
1040 1204
1041ParseInfo YueParser::parse(std::string_view codes, rule& r) { 1205ParseInfo YueParser::parse(std::string_view codes, rule& r, bool lax) {
1042 ParseInfo res; 1206 ParseInfo res;
1043 if (codes.substr(0, 3) == "\xEF\xBB\xBF"sv) { 1207 if (codes.substr(0, 3) == "\xEF\xBB\xBF"sv) {
1044 codes = codes.substr(3); 1208 codes = codes.substr(3);
1045 } 1209 }
1046 try { 1210 try {
1047 if (!codes.empty()) { 1211 if (!codes.empty()) {
1048 res.codes = std::make_unique<input>(_converter.from_bytes(&codes.front(), &codes.back() + 1)); 1212 res.codes = std::make_unique<input>(utf8_decode({&codes.front(), &codes.back() + 1}));
1049 } else { 1213 } else {
1050 res.codes = std::make_unique<input>(); 1214 res.codes = std::make_unique<input>();
1051 } 1215 }
1052 } catch (const std::range_error&) { 1216 } catch (const std::exception&) {
1053 res.error = {"invalid text encoding"s, 1, 1}; 1217 res.error = {"invalid text encoding"s, 1, 1};
1054 return res; 1218 return res;
1055 } 1219 }
1056 error_list errors; 1220 error_list errors;
1057 try { 1221 try {
1058 State state; 1222 State state;
1223 state.lax = lax;
1059 res.node.set(::yue::parse(*(res.codes), r, errors, &state)); 1224 res.node.set(::yue::parse(*(res.codes), r, errors, &state));
1060 if (state.exportCount > 0) { 1225 if (state.exportCount > 0) {
1061 int index = 0; 1226 int index = 0;
@@ -1093,29 +1258,31 @@ ParseInfo YueParser::parse(std::string_view codes, rule& r) {
1093 return res; 1258 return res;
1094} 1259}
1095 1260
1096ParseInfo YueParser::parse(std::string_view astName, std::string_view codes) { 1261ParseInfo YueParser::parse(std::string_view astName, std::string_view codes, bool lax) {
1097 auto it = _rules.find(astName); 1262 auto it = _rules.find(astName);
1098 if (it != _rules.end()) { 1263 if (it != _rules.end()) {
1099 return parse(codes, *it->second); 1264 return parse(codes, *it->second, lax);
1100 } 1265 }
1101 return {}; 1266 ParseInfo info{};
1267 info.error = ParseInfo::Error{"invalid rule: "s + std::string{astName}, 1, 1};
1268 return info;
1102} 1269}
1103 1270
1104bool YueParser::match(std::string_view astName, std::string_view codes) { 1271bool YueParser::match(std::string_view astName, std::string_view codes) {
1105 auto it = _rules.find(astName); 1272 auto it = _rules.find(astName);
1106 if (it != _rules.end()) { 1273 if (it != _rules.end()) {
1107 auto rEnd = rule(*it->second >> eof()); 1274 auto rEnd = rule(*it->second >> eof());
1108 return parse(codes, rEnd).node; 1275 return parse(codes, rEnd, false).node;
1109 } 1276 }
1110 return false; 1277 return false;
1111} 1278}
1112 1279
1113std::string YueParser::toString(ast_node* node) { 1280std::string YueParser::toString(ast_node* node) {
1114 return _converter.to_bytes(std::wstring(node->m_begin.m_it, node->m_end.m_it)); 1281 return utf8_encode({node->m_begin.m_it, node->m_end.m_it});
1115} 1282}
1116 1283
1117std::string YueParser::toString(input::iterator begin, input::iterator end) { 1284std::string YueParser::toString(input::iterator begin, input::iterator end) {
1118 return _converter.to_bytes(std::wstring(begin, end)); 1285 return utf8_encode({begin, end});
1119} 1286}
1120 1287
1121bool YueParser::hasAST(std::string_view name) const { 1288bool YueParser::hasAST(std::string_view name) const {
@@ -1141,6 +1308,24 @@ void trim(std::string& str) {
1141 str.erase(0, str.find_first_not_of(" \t\r\n")); 1308 str.erase(0, str.find_first_not_of(" \t\r\n"));
1142 str.erase(str.find_last_not_of(" \t\r\n") + 1); 1309 str.erase(str.find_last_not_of(" \t\r\n") + 1);
1143} 1310}
1311
1312std::string toLuaDoubleString(const std::string& input) {
1313 std::string luaStr = "\"";
1314 for (char c : input) {
1315 switch (c) {
1316 case '\"': luaStr += "\\\""; break;
1317 case '\\': luaStr += "\\\\"; break;
1318 case '\n': luaStr += "\\n"; break;
1319 case '\r': luaStr += "\\r"; break;
1320 case '\t': luaStr += "\\t"; break;
1321 default:
1322 luaStr += c;
1323 break;
1324 }
1325 }
1326 luaStr += "\"";
1327 return luaStr;
1328}
1144} // namespace Utils 1329} // namespace Utils
1145 1330
1146std::string ParseInfo::errorMessage(std::string_view msg, int errLine, int errCol, int lineOffset) const { 1331std::string ParseInfo::errorMessage(std::string_view msg, int errLine, int errCol, int lineOffset) const {
@@ -1174,7 +1359,7 @@ std::string ParseInfo::errorMessage(std::string_view msg, int errLine, int errCo
1174 } 1359 }
1175 ++it; 1360 ++it;
1176 } 1361 }
1177 auto line = Converter{}.to_bytes(std::wstring(begin, end)); 1362 auto line = utf8_encode({begin, end});
1178 while (col < static_cast<int>(line.size()) 1363 while (col < static_cast<int>(line.size())
1179 && (line[col] == ' ' || line[col] == '\t')) { 1364 && (line[col] == ' ' || line[col] == '\t')) {
1180 col++; 1365 col++;
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h
index 4488685..acb56d0 100644
--- a/src/yuescript/yue_parser.h
+++ b/src/yuescript/yue_parser.h
@@ -1,4 +1,4 @@
1/* Copyright (c) 2017-2025 Li Jin <dragon-fly@qq.com> 1/* Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com>
2 2
3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 4
@@ -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;
@@ -118,11 +119,13 @@ protected:
118 int expLevel = 0; 119 int expLevel = 0;
119 size_t stringOpen = 0; 120 size_t stringOpen = 0;
120 std::string buffer; 121 std::string buffer;
122 std::optional<bool> useTab;
121 std::stack<int> indents; 123 std::stack<int> indents;
122 std::stack<bool> noDoStack; 124 std::vector<bool> noDoStack;
123 std::stack<bool> noChainBlockStack; 125 std::vector<bool> noChainBlockStack;
124 std::stack<bool> noTableBlockStack; 126 std::vector<bool> noTableBlockStack;
125 std::stack<bool> noForStack; 127 std::vector<bool> noForStack;
128 std::vector<bool> noUntilStack;
126 std::unordered_set<std::string> usedNames; 129 std::unordered_set<std::string> usedNames;
127 }; 130 };
128 131
@@ -132,7 +135,6 @@ protected:
132 } 135 }
133 136
134private: 137private:
135 Converter _converter;
136 std::unordered_map<std::string_view, rule*> _rules; 138 std::unordered_map<std::string_view, rule*> _rules;
137 139
138 template <class T> 140 template <class T>
@@ -147,7 +149,6 @@ private:
147 } 149 }
148 150
149 NONE_AST_RULE(empty_block_error); 151 NONE_AST_RULE(empty_block_error);
150 NONE_AST_RULE(leading_spaces_error);
151 NONE_AST_RULE(indentation_error); 152 NONE_AST_RULE(indentation_error);
152 NONE_AST_RULE(braces_expression_error); 153 NONE_AST_RULE(braces_expression_error);
153 NONE_AST_RULE(brackets_expression_error); 154 NONE_AST_RULE(brackets_expression_error);
@@ -156,12 +157,42 @@ private:
156 NONE_AST_RULE(invalid_interpolation_error); 157 NONE_AST_RULE(invalid_interpolation_error);
157 NONE_AST_RULE(confusing_unary_not_error); 158 NONE_AST_RULE(confusing_unary_not_error);
158 NONE_AST_RULE(table_key_pair_error); 159 NONE_AST_RULE(table_key_pair_error);
159 NONE_AST_RULE(if_assignment_syntax_error); 160 NONE_AST_RULE(assignment_expression_syntax_error);
161 NONE_AST_RULE(unclosed_single_string_error);
162 NONE_AST_RULE(unclosed_double_string_error);
163 NONE_AST_RULE(unclosed_lua_string_error);
164 NONE_AST_RULE(unexpected_comma_error);
165 NONE_AST_RULE(parenthesis_error);
166 NONE_AST_RULE(dangling_clause_error);
167 NONE_AST_RULE(keyword_as_label_error);
168 NONE_AST_RULE(check_vararg_position);
169 NONE_AST_RULE(vararg_position_error);
170 NONE_AST_RULE(invalid_import_syntax_error);
171 NONE_AST_RULE(invalid_import_as_syntax_error);
172 NONE_AST_RULE(expected_expression_error);
173 NONE_AST_RULE(invalid_from_import_error);
174 NONE_AST_RULE(invalid_export_syntax_error);
175 NONE_AST_RULE(invalid_macro_definition_error);
176 NONE_AST_RULE(invalid_global_declaration_error);
177 NONE_AST_RULE(invalid_local_declaration_error);
178 NONE_AST_RULE(invalid_with_syntax_error);
179 NONE_AST_RULE(invalid_try_syntax_error);
180 NONE_AST_RULE(keyword_as_identifier_syntax_error);
181 NONE_AST_RULE(invalid_number_literal_error);
182 NONE_AST_RULE(invalid_import_literal_error);
183 NONE_AST_RULE(expected_indentifier_error);
184
185 NONE_AST_RULE(must_exp);
186 NONE_AST_RULE(must_unary_exp);
187 NONE_AST_RULE(must_variable);
188 NONE_AST_RULE(end_braces_expression);
189 NONE_AST_RULE(end_brackets_expression);
160 190
161 NONE_AST_RULE(inc_exp_level); 191 NONE_AST_RULE(inc_exp_level);
162 NONE_AST_RULE(dec_exp_level); 192 NONE_AST_RULE(dec_exp_level);
163 193
164 NONE_AST_RULE(num_char); 194 NONE_AST_RULE(num_char);
195 NONE_AST_RULE(must_num_char);
165 NONE_AST_RULE(num_char_hex); 196 NONE_AST_RULE(num_char_hex);
166 NONE_AST_RULE(num_lit); 197 NONE_AST_RULE(num_lit);
167 NONE_AST_RULE(num_bin_lit); 198 NONE_AST_RULE(num_bin_lit);
@@ -172,6 +203,7 @@ private:
172 NONE_AST_RULE(line_break); 203 NONE_AST_RULE(line_break);
173 NONE_AST_RULE(any_char); 204 NONE_AST_RULE(any_char);
174 NONE_AST_RULE(white); 205 NONE_AST_RULE(white);
206 NONE_AST_RULE(plain_white);
175 NONE_AST_RULE(stop); 207 NONE_AST_RULE(stop);
176 NONE_AST_RULE(comment); 208 NONE_AST_RULE(comment);
177 NONE_AST_RULE(multi_line_open); 209 NONE_AST_RULE(multi_line_open);
@@ -217,6 +249,8 @@ private:
217 NONE_AST_RULE(enable_for); 249 NONE_AST_RULE(enable_for);
218 NONE_AST_RULE(enable_fun_lit); 250 NONE_AST_RULE(enable_fun_lit);
219 NONE_AST_RULE(disable_fun_lit); 251 NONE_AST_RULE(disable_fun_lit);
252 NONE_AST_RULE(disable_until);
253 NONE_AST_RULE(enable_until);
220 NONE_AST_RULE(switch_else); 254 NONE_AST_RULE(switch_else);
221 NONE_AST_RULE(switch_block); 255 NONE_AST_RULE(switch_block);
222 NONE_AST_RULE(if_else_if); 256 NONE_AST_RULE(if_else_if);
@@ -246,6 +280,8 @@ private:
246 NONE_AST_RULE(fn_arg_def_lit_lines); 280 NONE_AST_RULE(fn_arg_def_lit_lines);
247 NONE_AST_RULE(destruct_def); 281 NONE_AST_RULE(destruct_def);
248 NONE_AST_RULE(macro_args_def); 282 NONE_AST_RULE(macro_args_def);
283 NONE_AST_RULE(var_arg_def);
284 NONE_AST_RULE(outer_var_shadow_def);
249 NONE_AST_RULE(chain_call); 285 NONE_AST_RULE(chain_call);
250 NONE_AST_RULE(chain_call_list); 286 NONE_AST_RULE(chain_call_list);
251 NONE_AST_RULE(chain_index_chain); 287 NONE_AST_RULE(chain_index_chain);
@@ -262,7 +298,6 @@ private:
262 NONE_AST_RULE(table_value); 298 NONE_AST_RULE(table_value);
263 NONE_AST_RULE(table_lit_lines); 299 NONE_AST_RULE(table_lit_lines);
264 NONE_AST_RULE(table_lit_line); 300 NONE_AST_RULE(table_lit_line);
265 NONE_AST_RULE(table_value_list);
266 NONE_AST_RULE(table_block_inner); 301 NONE_AST_RULE(table_block_inner);
267 NONE_AST_RULE(class_line); 302 NONE_AST_RULE(class_line);
268 NONE_AST_RULE(key_value_line); 303 NONE_AST_RULE(key_value_line);
@@ -279,17 +314,17 @@ private:
279 NONE_AST_RULE(expo_exp); 314 NONE_AST_RULE(expo_exp);
280 NONE_AST_RULE(exp_not_tab); 315 NONE_AST_RULE(exp_not_tab);
281 NONE_AST_RULE(local_const_item); 316 NONE_AST_RULE(local_const_item);
282 NONE_AST_RULE(empty_line_break); 317 NONE_AST_RULE(comment_line);
283 NONE_AST_RULE(yue_comment);
284 NONE_AST_RULE(yue_line_comment); 318 NONE_AST_RULE(yue_line_comment);
319 NONE_AST_RULE(yue_multiline_comment);
285 NONE_AST_RULE(line); 320 NONE_AST_RULE(line);
286 NONE_AST_RULE(shebang); 321 NONE_AST_RULE(shebang);
322 NONE_AST_RULE(lax_line);
287 323
288 AST_RULE(Num); 324 AST_RULE(Num);
289 AST_RULE(Name); 325 AST_RULE(Name);
290 AST_RULE(UnicodeName); 326 AST_RULE(UnicodeName);
291 AST_RULE(Variable); 327 AST_RULE(Variable);
292 AST_RULE(LabelName);
293 AST_RULE(LuaKeyword); 328 AST_RULE(LuaKeyword);
294 AST_RULE(Self); 329 AST_RULE(Self);
295 AST_RULE(SelfName); 330 AST_RULE(SelfName);
@@ -298,6 +333,7 @@ private:
298 AST_RULE(SelfItem); 333 AST_RULE(SelfItem);
299 AST_RULE(KeyName); 334 AST_RULE(KeyName);
300 AST_RULE(VarArg); 335 AST_RULE(VarArg);
336 AST_RULE(VarArgDef);
301 AST_RULE(Seperator); 337 AST_RULE(Seperator);
302 AST_RULE(NameList); 338 AST_RULE(NameList);
303 AST_RULE(LocalFlag); 339 AST_RULE(LocalFlag);
@@ -315,6 +351,7 @@ private:
315 AST_RULE(ImportAllMacro); 351 AST_RULE(ImportAllMacro);
316 AST_RULE(ImportTabLit); 352 AST_RULE(ImportTabLit);
317 AST_RULE(ImportAs); 353 AST_RULE(ImportAs);
354 AST_RULE(ImportGlobal);
318 AST_RULE(Import); 355 AST_RULE(Import);
319 AST_RULE(Label); 356 AST_RULE(Label);
320 AST_RULE(Goto); 357 AST_RULE(Goto);
@@ -339,6 +376,7 @@ private:
339 AST_RULE(Repeat); 376 AST_RULE(Repeat);
340 AST_RULE(ForStepValue); 377 AST_RULE(ForStepValue);
341 AST_RULE(For); 378 AST_RULE(For);
379 AST_RULE(ForNum);
342 AST_RULE(ForEach); 380 AST_RULE(ForEach);
343 AST_RULE(Do); 381 AST_RULE(Do);
344 AST_RULE(CatchBlock); 382 AST_RULE(CatchBlock);
@@ -348,8 +386,8 @@ private:
348 AST_RULE(TblComprehension); 386 AST_RULE(TblComprehension);
349 AST_RULE(StarExp); 387 AST_RULE(StarExp);
350 AST_RULE(CompForEach); 388 AST_RULE(CompForEach);
389 AST_RULE(CompForNum);
351 AST_RULE(CompFor); 390 AST_RULE(CompFor);
352 AST_RULE(CompInner);
353 AST_RULE(Assign); 391 AST_RULE(Assign);
354 AST_RULE(UpdateOp); 392 AST_RULE(UpdateOp);
355 AST_RULE(Update); 393 AST_RULE(Update);
@@ -360,6 +398,7 @@ private:
360 AST_RULE(ExpOpValue); 398 AST_RULE(ExpOpValue);
361 AST_RULE(Exp); 399 AST_RULE(Exp);
362 AST_RULE(Callable); 400 AST_RULE(Callable);
401 AST_RULE(ReversedIndex);
363 AST_RULE(ChainValue); 402 AST_RULE(ChainValue);
364 AST_RULE(SimpleTable); 403 AST_RULE(SimpleTable);
365 AST_RULE(SimpleValue); 404 AST_RULE(SimpleValue);
@@ -372,6 +411,11 @@ private:
372 AST_RULE(DoubleStringInner); 411 AST_RULE(DoubleStringInner);
373 AST_RULE(DoubleStringContent); 412 AST_RULE(DoubleStringContent);
374 AST_RULE(DoubleString); 413 AST_RULE(DoubleString);
414 AST_RULE(YAMLIndent);
415 AST_RULE(YAMLLineInner);
416 AST_RULE(YAMLLineContent);
417 AST_RULE(YAMLLine);
418 AST_RULE(YAMLMultiline);
375 AST_RULE(String); 419 AST_RULE(String);
376 AST_RULE(Parens); 420 AST_RULE(Parens);
377 AST_RULE(DotChainItem); 421 AST_RULE(DotChainItem);
@@ -435,8 +479,9 @@ private:
435 AST_RULE(Statement); 479 AST_RULE(Statement);
436 AST_RULE(StatementSep); 480 AST_RULE(StatementSep);
437 AST_RULE(YueLineComment); 481 AST_RULE(YueLineComment);
438 AST_RULE(MultilineCommentInner);
439 AST_RULE(YueMultilineComment); 482 AST_RULE(YueMultilineComment);
483 AST_RULE(YueComment);
484 AST_RULE(EmptyLine);
440 AST_RULE(ChainAssign); 485 AST_RULE(ChainAssign);
441 AST_RULE(Body); 486 AST_RULE(Body);
442 AST_RULE(Block); 487 AST_RULE(Block);
@@ -447,6 +492,7 @@ private:
447namespace Utils { 492namespace Utils {
448void replace(std::string& str, std::string_view from, std::string_view to); 493void replace(std::string& str, std::string_view from, std::string_view to);
449void trim(std::string& str); 494void trim(std::string& str);
495std::string toLuaDoubleString(const std::string& input);
450} // namespace Utils 496} // namespace Utils
451 497
452} // namespace yue 498} // namespace yue
diff --git a/src/yuescript/yuescript.cpp b/src/yuescript/yuescript.cpp
index 7e8e8b7..fd2bf62 100644
--- a/src/yuescript/yuescript.cpp
+++ b/src/yuescript/yuescript.cpp
@@ -1,4 +1,4 @@
1/* Copyright (c) 2017-2025 Li Jin <dragon-fly@qq.com> 1/* Copyright (c) 2017-2026 Li Jin <dragon-fly@qq.com>
2 2
3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 3Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4 4
@@ -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) {
@@ -179,8 +185,13 @@ static int yueformat(lua_State* L) {
179 if (!lua_isnoneornil(L, 2)) { 185 if (!lua_isnoneornil(L, 2)) {
180 tabSize = static_cast<int>(luaL_checkinteger(L, 2)); 186 tabSize = static_cast<int>(luaL_checkinteger(L, 2));
181 } 187 }
188 bool reserveComment = true;
189 if (!lua_isnoneornil(L, 3)) {
190 luaL_checktype(L, 3, LUA_TBOOLEAN);
191 reserveComment = lua_toboolean(L, 3) != 0;
192 }
182 std::string_view codes(input, len); 193 std::string_view codes(input, len);
183 auto info = yue::YueParser::shared().parse<yue::File_t>(codes); 194 auto info = yue::YueParser::shared().parse<yue::File_t>(codes, false);
184 if (info.error) { 195 if (info.error) {
185 const auto& error = info.error.value(); 196 const auto& error = info.error.value();
186 if (!info.codes) { 197 if (!info.codes) {
@@ -200,7 +211,11 @@ static int yueformat(lua_State* L) {
200 } else { 211 } else {
201 formatter.spaceOverTab = false; 212 formatter.spaceOverTab = false;
202 } 213 }
214 formatter.reserveComment = reserveComment;
203 auto result = formatter.toString(info.node.get()); 215 auto result = formatter.toString(info.node.get());
216 if (!formatter.reserveComment) {
217 yue::Utils::replace(result, "\n\n", "\n");
218 }
204 lua_pushlstring(L, result.c_str(), result.size()); 219 lua_pushlstring(L, result.c_str(), result.size());
205 return 1; 220 return 1;
206} 221}
@@ -235,6 +250,7 @@ static int yuecheck(lua_State* L) {
235 } 250 }
236 if (result.globals) { 251 if (result.globals) {
237 for (const auto& global : *result.globals) { 252 for (const auto& global : *result.globals) {
253 if (global.defined) continue;
238 lua_createtable(L, 4, 0); 254 lua_createtable(L, 4, 0);
239 lua_pushliteral(L, "global"); 255 lua_pushliteral(L, "global");
240 lua_rawseti(L, -2, 1); 256 lua_rawseti(L, -2, 1);
@@ -247,7 +263,7 @@ static int yuecheck(lua_State* L) {
247 lua_rawseti(L, -2, ++i); 263 lua_rawseti(L, -2, ++i);
248 } 264 }
249 } 265 }
250 if (result.error) { 266 if (!config.lax && result.error) {
251 lua_pushboolean(L, 0); 267 lua_pushboolean(L, 0);
252 lua_insert(L, -2); 268 lua_insert(L, -2);
253 return 2; 269 return 2;
@@ -282,8 +298,18 @@ static int yuetoast(lua_State* L) {
282 ruleName = {name, nameSize}; 298 ruleName = {name, nameSize};
283 } 299 }
284 } 300 }
301 bool lax = false;
302 if (!lua_isnoneornil(L, 4)) {
303 luaL_checktype(L, 4, LUA_TBOOLEAN);
304 lax = lua_toboolean(L, 4) != 0;
305 }
306 bool reserveComment = false;
307 if (!lua_isnoneornil(L, 5)) {
308 luaL_checktype(L, 5, LUA_TBOOLEAN);
309 reserveComment = lua_toboolean(L, 5) != 0;
310 }
285 auto& yueParser = yue::YueParser::shared(); 311 auto& yueParser = yue::YueParser::shared();
286 auto info = ruleName.empty() ? yueParser.parse<yue::File_t>({input, size}) : yueParser.parse(ruleName, {input, size}); 312 auto info = ruleName.empty() ? yueParser.parse<yue::File_t>({input, size}, lax) : yueParser.parse(ruleName, {input, size}, lax);
287 if (!info.error) { 313 if (!info.error) {
288 lua_createtable(L, 0, 0); 314 lua_createtable(L, 0, 0);
289 int tableIndex = lua_gettop(L); 315 int tableIndex = lua_gettop(L);
@@ -309,13 +335,11 @@ static int yuetoast(lua_State* L) {
309 }; 335 };
310 do_call(info.node); 336 do_call(info.node);
311 yue::YueFormat formatter{}; 337 yue::YueFormat formatter{};
338 formatter.reserveComment = reserveComment;
312 while (!stack.empty()) { 339 while (!stack.empty()) {
313 auto& current = stack.top(); 340 auto& current = stack.top();
314 int continuation = current.continuation; 341 int continuation = current.continuation;
315 auto node = current.node; 342 auto node = current.node;
316 if (auto comment = yue::ast_cast<yue::YueMultilineComment_t>(node)) {
317 node = comment->inner.get();
318 }
319 switch (continuation) { 343 switch (continuation) {
320 case 0: { 344 case 0: {
321 if (!current.children) { 345 if (!current.children) {
@@ -324,6 +348,9 @@ static int yuetoast(lua_State* L) {
324 current.hasSep = true; 348 current.hasSep = true;
325 return false; 349 return false;
326 } 350 }
351 if (!reserveComment && yue::ast_is<yue::YueComment_t, yue::EmptyLine_t>(child)) {
352 return false;
353 }
327 if (!current.children) { 354 if (!current.children) {
328 current.children = std::make_unique<std::vector<yue::ast_node*>>(); 355 current.children = std::make_unique<std::vector<yue::ast_node*>>();
329 } 356 }
diff --git a/win-build/Lua53/Lua53.vcxproj b/win-build/Lua53/Lua53.vcxproj
index 4f17bfc..d0e7fee 100644
--- a/win-build/Lua53/Lua53.vcxproj
+++ b/win-build/Lua53/Lua53.vcxproj
@@ -269,69 +269,69 @@
269 </Link> 269 </Link>
270 </ItemDefinitionGroup> 270 </ItemDefinitionGroup>
271 <ItemGroup> 271 <ItemGroup>
272 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lapi.c" /> 272 <ClCompile Include="lapi.c" />
273 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lauxlib.c" /> 273 <ClCompile Include="lauxlib.c" />
274 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lbaselib.c" /> 274 <ClCompile Include="lbaselib.c" />
275 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lbitlib.c" /> 275 <ClCompile Include="lbitlib.c" />
276 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lcode.c" /> 276 <ClCompile Include="lcode.c" />
277 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lcorolib.c" /> 277 <ClCompile Include="lcorolib.c" />
278 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lctype.c" /> 278 <ClCompile Include="lctype.c" />
279 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\ldblib.c" /> 279 <ClCompile Include="ldblib.c" />
280 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\ldebug.c" /> 280 <ClCompile Include="ldebug.c" />
281 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\ldo.c" /> 281 <ClCompile Include="ldo.c" />
282 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\ldump.c" /> 282 <ClCompile Include="ldump.c" />
283 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lfunc.c" /> 283 <ClCompile Include="lfunc.c" />
284 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lgc.c" /> 284 <ClCompile Include="lgc.c" />
285 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\linit.c" /> 285 <ClCompile Include="linit.c" />
286 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\liolib.c" /> 286 <ClCompile Include="liolib.c" />
287 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\llex.c" /> 287 <ClCompile Include="llex.c" />
288 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lmathlib.c" /> 288 <ClCompile Include="lmathlib.c" />
289 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lmem.c" /> 289 <ClCompile Include="lmem.c" />
290 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\loadlib.c" /> 290 <ClCompile Include="loadlib.c" />
291 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lobject.c" /> 291 <ClCompile Include="lobject.c" />
292 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lopcodes.c" /> 292 <ClCompile Include="lopcodes.c" />
293 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\loslib.c" /> 293 <ClCompile Include="loslib.c" />
294 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lparser.c" /> 294 <ClCompile Include="lparser.c" />
295 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lstate.c" /> 295 <ClCompile Include="lstate.c" />
296 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lstring.c" /> 296 <ClCompile Include="lstring.c" />
297 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lstrlib.c" /> 297 <ClCompile Include="lstrlib.c" />
298 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\ltable.c" /> 298 <ClCompile Include="ltable.c" />
299 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\ltablib.c" /> 299 <ClCompile Include="ltablib.c" />
300 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\ltm.c" /> 300 <ClCompile Include="ltm.c" />
301 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lundump.c" /> 301 <ClCompile Include="lundump.c" />
302 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lutf8lib.c" /> 302 <ClCompile Include="lutf8lib.c" />
303 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lvm.c" /> 303 <ClCompile Include="lvm.c" />
304 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lzio.c" /> 304 <ClCompile Include="lzio.c" />
305 </ItemGroup> 305 </ItemGroup>
306 <ItemGroup> 306 <ItemGroup>
307 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lapi.h" /> 307 <ClInclude Include="lapi.h" />
308 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lauxlib.h" /> 308 <ClInclude Include="lauxlib.h" />
309 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lcode.h" /> 309 <ClInclude Include="lcode.h" />
310 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lctype.h" /> 310 <ClInclude Include="lctype.h" />
311 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\ldebug.h" /> 311 <ClInclude Include="ldebug.h" />
312 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\ldo.h" /> 312 <ClInclude Include="ldo.h" />
313 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lfunc.h" /> 313 <ClInclude Include="lfunc.h" />
314 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lgc.h" /> 314 <ClInclude Include="lgc.h" />
315 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\llex.h" /> 315 <ClInclude Include="llex.h" />
316 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\llimits.h" /> 316 <ClInclude Include="llimits.h" />
317 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lmem.h" /> 317 <ClInclude Include="lmem.h" />
318 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lobject.h" /> 318 <ClInclude Include="lobject.h" />
319 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lopcodes.h" /> 319 <ClInclude Include="lopcodes.h" />
320 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lparser.h" /> 320 <ClInclude Include="lparser.h" />
321 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lprefix.h" /> 321 <ClInclude Include="lprefix.h" />
322 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lstate.h" /> 322 <ClInclude Include="lstate.h" />
323 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lstring.h" /> 323 <ClInclude Include="lstring.h" />
324 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\ltable.h" /> 324 <ClInclude Include="ltable.h" />
325 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\ltm.h" /> 325 <ClInclude Include="ltm.h" />
326 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lua.h" /> 326 <ClInclude Include="lua.h" />
327 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lua.hpp" /> 327 <ClInclude Include="lua.hpp" />
328 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\luaconf.h" /> 328 <ClInclude Include="luaconf.h" />
329 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lualib.h" /> 329 <ClInclude Include="lualib.h" />
330 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lundump.h" /> 330 <ClInclude Include="lundump.h" />
331 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lvm.h" /> 331 <ClInclude Include="lvm.h" />
332 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lzio.h" /> 332 <ClInclude Include="lzio.h" />
333 </ItemGroup> 333 </ItemGroup>
334 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> 334 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
335 <ImportGroup Label="ExtensionTargets"> 335 <ImportGroup Label="ExtensionTargets">
336 </ImportGroup> 336 </ImportGroup>
337</Project> \ No newline at end of file 337</Project>
diff --git a/win-build/Lua53/Lua53.vcxproj.filters b/win-build/Lua53/Lua53.vcxproj.filters
index df8715c..be208ec 100644
--- a/win-build/Lua53/Lua53.vcxproj.filters
+++ b/win-build/Lua53/Lua53.vcxproj.filters
@@ -7,184 +7,184 @@
7 </Filter> 7 </Filter>
8 </ItemGroup> 8 </ItemGroup>
9 <ItemGroup> 9 <ItemGroup>
10 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lapi.c"> 10 <ClCompile Include="lapi.c">
11 <Filter>src</Filter> 11 <Filter>src</Filter>
12 </ClCompile> 12 </ClCompile>
13 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lauxlib.c"> 13 <ClCompile Include="lauxlib.c">
14 <Filter>src</Filter> 14 <Filter>src</Filter>
15 </ClCompile> 15 </ClCompile>
16 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lbaselib.c"> 16 <ClCompile Include="lbaselib.c">
17 <Filter>src</Filter> 17 <Filter>src</Filter>
18 </ClCompile> 18 </ClCompile>
19 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lbitlib.c"> 19 <ClCompile Include="lbitlib.c">
20 <Filter>src</Filter> 20 <Filter>src</Filter>
21 </ClCompile> 21 </ClCompile>
22 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lcode.c"> 22 <ClCompile Include="lcode.c">
23 <Filter>src</Filter> 23 <Filter>src</Filter>
24 </ClCompile> 24 </ClCompile>
25 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lcorolib.c"> 25 <ClCompile Include="lcorolib.c">
26 <Filter>src</Filter> 26 <Filter>src</Filter>
27 </ClCompile> 27 </ClCompile>
28 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lctype.c"> 28 <ClCompile Include="lctype.c">
29 <Filter>src</Filter> 29 <Filter>src</Filter>
30 </ClCompile> 30 </ClCompile>
31 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\ldblib.c"> 31 <ClCompile Include="ldblib.c">
32 <Filter>src</Filter> 32 <Filter>src</Filter>
33 </ClCompile> 33 </ClCompile>
34 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\ldebug.c"> 34 <ClCompile Include="ldebug.c">
35 <Filter>src</Filter> 35 <Filter>src</Filter>
36 </ClCompile> 36 </ClCompile>
37 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\ldo.c"> 37 <ClCompile Include="ldo.c">
38 <Filter>src</Filter> 38 <Filter>src</Filter>
39 </ClCompile> 39 </ClCompile>
40 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\ldump.c"> 40 <ClCompile Include="ldump.c">
41 <Filter>src</Filter> 41 <Filter>src</Filter>
42 </ClCompile> 42 </ClCompile>
43 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lfunc.c"> 43 <ClCompile Include="lfunc.c">
44 <Filter>src</Filter> 44 <Filter>src</Filter>
45 </ClCompile> 45 </ClCompile>
46 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lgc.c"> 46 <ClCompile Include="lgc.c">
47 <Filter>src</Filter> 47 <Filter>src</Filter>
48 </ClCompile> 48 </ClCompile>
49 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\linit.c"> 49 <ClCompile Include="linit.c">
50 <Filter>src</Filter> 50 <Filter>src</Filter>
51 </ClCompile> 51 </ClCompile>
52 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\liolib.c"> 52 <ClCompile Include="liolib.c">
53 <Filter>src</Filter> 53 <Filter>src</Filter>
54 </ClCompile> 54 </ClCompile>
55 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\llex.c"> 55 <ClCompile Include="llex.c">
56 <Filter>src</Filter> 56 <Filter>src</Filter>
57 </ClCompile> 57 </ClCompile>
58 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lmathlib.c"> 58 <ClCompile Include="lmathlib.c">
59 <Filter>src</Filter> 59 <Filter>src</Filter>
60 </ClCompile> 60 </ClCompile>
61 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lmem.c"> 61 <ClCompile Include="lmem.c">
62 <Filter>src</Filter> 62 <Filter>src</Filter>
63 </ClCompile> 63 </ClCompile>
64 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\loadlib.c"> 64 <ClCompile Include="loadlib.c">
65 <Filter>src</Filter> 65 <Filter>src</Filter>
66 </ClCompile> 66 </ClCompile>
67 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lobject.c"> 67 <ClCompile Include="lobject.c">
68 <Filter>src</Filter> 68 <Filter>src</Filter>
69 </ClCompile> 69 </ClCompile>
70 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lopcodes.c"> 70 <ClCompile Include="lopcodes.c">
71 <Filter>src</Filter> 71 <Filter>src</Filter>
72 </ClCompile> 72 </ClCompile>
73 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\loslib.c"> 73 <ClCompile Include="loslib.c">
74 <Filter>src</Filter> 74 <Filter>src</Filter>
75 </ClCompile> 75 </ClCompile>
76 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lparser.c"> 76 <ClCompile Include="lparser.c">
77 <Filter>src</Filter> 77 <Filter>src</Filter>
78 </ClCompile> 78 </ClCompile>
79 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lstate.c"> 79 <ClCompile Include="lstate.c">
80 <Filter>src</Filter> 80 <Filter>src</Filter>
81 </ClCompile> 81 </ClCompile>
82 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lstring.c"> 82 <ClCompile Include="lstring.c">
83 <Filter>src</Filter> 83 <Filter>src</Filter>
84 </ClCompile> 84 </ClCompile>
85 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lstrlib.c"> 85 <ClCompile Include="lstrlib.c">
86 <Filter>src</Filter> 86 <Filter>src</Filter>
87 </ClCompile> 87 </ClCompile>
88 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\ltable.c"> 88 <ClCompile Include="ltable.c">
89 <Filter>src</Filter> 89 <Filter>src</Filter>
90 </ClCompile> 90 </ClCompile>
91 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\ltablib.c"> 91 <ClCompile Include="ltablib.c">
92 <Filter>src</Filter> 92 <Filter>src</Filter>
93 </ClCompile> 93 </ClCompile>
94 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\ltm.c"> 94 <ClCompile Include="ltm.c">
95 <Filter>src</Filter> 95 <Filter>src</Filter>
96 </ClCompile> 96 </ClCompile>
97 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lundump.c"> 97 <ClCompile Include="lundump.c">
98 <Filter>src</Filter> 98 <Filter>src</Filter>
99 </ClCompile> 99 </ClCompile>
100 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lutf8lib.c"> 100 <ClCompile Include="lutf8lib.c">
101 <Filter>src</Filter> 101 <Filter>src</Filter>
102 </ClCompile> 102 </ClCompile>
103 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lvm.c"> 103 <ClCompile Include="lvm.c">
104 <Filter>src</Filter> 104 <Filter>src</Filter>
105 </ClCompile> 105 </ClCompile>
106 <ClCompile Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lzio.c"> 106 <ClCompile Include="lzio.c">
107 <Filter>src</Filter> 107 <Filter>src</Filter>
108 </ClCompile> 108 </ClCompile>
109 </ItemGroup> 109 </ItemGroup>
110 <ItemGroup> 110 <ItemGroup>
111 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lapi.h"> 111 <ClInclude Include="lapi.h">
112 <Filter>src</Filter> 112 <Filter>src</Filter>
113 </ClInclude> 113 </ClInclude>
114 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lauxlib.h"> 114 <ClInclude Include="lauxlib.h">
115 <Filter>src</Filter> 115 <Filter>src</Filter>
116 </ClInclude> 116 </ClInclude>
117 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lcode.h"> 117 <ClInclude Include="lcode.h">
118 <Filter>src</Filter> 118 <Filter>src</Filter>
119 </ClInclude> 119 </ClInclude>
120 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lctype.h"> 120 <ClInclude Include="lctype.h">
121 <Filter>src</Filter> 121 <Filter>src</Filter>
122 </ClInclude> 122 </ClInclude>
123 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\ldebug.h"> 123 <ClInclude Include="ldebug.h">
124 <Filter>src</Filter> 124 <Filter>src</Filter>
125 </ClInclude> 125 </ClInclude>
126 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\ldo.h"> 126 <ClInclude Include="ldo.h">
127 <Filter>src</Filter> 127 <Filter>src</Filter>
128 </ClInclude> 128 </ClInclude>
129 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lfunc.h"> 129 <ClInclude Include="lfunc.h">
130 <Filter>src</Filter> 130 <Filter>src</Filter>
131 </ClInclude> 131 </ClInclude>
132 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lgc.h"> 132 <ClInclude Include="lgc.h">
133 <Filter>src</Filter> 133 <Filter>src</Filter>
134 </ClInclude> 134 </ClInclude>
135 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\llex.h"> 135 <ClInclude Include="llex.h">
136 <Filter>src</Filter> 136 <Filter>src</Filter>
137 </ClInclude> 137 </ClInclude>
138 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\llimits.h"> 138 <ClInclude Include="llimits.h">
139 <Filter>src</Filter> 139 <Filter>src</Filter>
140 </ClInclude> 140 </ClInclude>
141 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lmem.h"> 141 <ClInclude Include="lmem.h">
142 <Filter>src</Filter> 142 <Filter>src</Filter>
143 </ClInclude> 143 </ClInclude>
144 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lobject.h"> 144 <ClInclude Include="lobject.h">
145 <Filter>src</Filter> 145 <Filter>src</Filter>
146 </ClInclude> 146 </ClInclude>
147 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lopcodes.h"> 147 <ClInclude Include="lopcodes.h">
148 <Filter>src</Filter> 148 <Filter>src</Filter>
149 </ClInclude> 149 </ClInclude>
150 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lparser.h"> 150 <ClInclude Include="lparser.h">
151 <Filter>src</Filter> 151 <Filter>src</Filter>
152 </ClInclude> 152 </ClInclude>
153 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lprefix.h"> 153 <ClInclude Include="lprefix.h">
154 <Filter>src</Filter> 154 <Filter>src</Filter>
155 </ClInclude> 155 </ClInclude>
156 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lstate.h"> 156 <ClInclude Include="lstate.h">
157 <Filter>src</Filter> 157 <Filter>src</Filter>
158 </ClInclude> 158 </ClInclude>
159 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lstring.h"> 159 <ClInclude Include="lstring.h">
160 <Filter>src</Filter> 160 <Filter>src</Filter>
161 </ClInclude> 161 </ClInclude>
162 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\ltable.h"> 162 <ClInclude Include="ltable.h">
163 <Filter>src</Filter> 163 <Filter>src</Filter>
164 </ClInclude> 164 </ClInclude>
165 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\ltm.h"> 165 <ClInclude Include="ltm.h">
166 <Filter>src</Filter> 166 <Filter>src</Filter>
167 </ClInclude> 167 </ClInclude>
168 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lua.h"> 168 <ClInclude Include="lua.h">
169 <Filter>src</Filter> 169 <Filter>src</Filter>
170 </ClInclude> 170 </ClInclude>
171 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lua.hpp"> 171 <ClInclude Include="lua.hpp">
172 <Filter>src</Filter> 172 <Filter>src</Filter>
173 </ClInclude> 173 </ClInclude>
174 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\luaconf.h"> 174 <ClInclude Include="luaconf.h">
175 <Filter>src</Filter> 175 <Filter>src</Filter>
176 </ClInclude> 176 </ClInclude>
177 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lualib.h"> 177 <ClInclude Include="lualib.h">
178 <Filter>src</Filter> 178 <Filter>src</Filter>
179 </ClInclude> 179 </ClInclude>
180 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lundump.h"> 180 <ClInclude Include="lundump.h">
181 <Filter>src</Filter> 181 <Filter>src</Filter>
182 </ClInclude> 182 </ClInclude>
183 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lvm.h"> 183 <ClInclude Include="lvm.h">
184 <Filter>src</Filter> 184 <Filter>src</Filter>
185 </ClInclude> 185 </ClInclude>
186 <ClInclude Include="\\Mac\Home\Workspace\Yuescript\win-build\Lua53\lzio.h"> 186 <ClInclude Include="lzio.h">
187 <Filter>src</Filter> 187 <Filter>src</Filter>
188 </ClInclude> 188 </ClInclude>
189 </ItemGroup> 189 </ItemGroup>
190</Project> \ No newline at end of file 190</Project>
diff --git a/win-build/Yuescript/Yuescript.vcxproj b/win-build/Yuescript/Yuescript.vcxproj
index d073e70..9b05567 100644
--- a/win-build/Yuescript/Yuescript.vcxproj
+++ b/win-build/Yuescript/Yuescript.vcxproj
@@ -176,11 +176,11 @@
176 <ClCompile> 176 <ClCompile>
177 <WarningLevel>Level3</WarningLevel> 177 <WarningLevel>Level3</WarningLevel>
178 <SDLCheck>true</SDLCheck> 178 <SDLCheck>true</SDLCheck>
179 <PreprocessorDefinitions>_DEBUG;_CONSOLE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SCL_SECURE_NO_WARNINGS;_ITERATOR_DEBUG_LEVEL=0;%(PreprocessorDefinitions)</PreprocessorDefinitions> 179 <PreprocessorDefinitions>_DEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS;_ITERATOR_DEBUG_LEVEL=0;YUE_UTF8_IMPL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
180 <ConformanceMode>true</ConformanceMode> 180 <ConformanceMode>true</ConformanceMode>
181 <LanguageStandard>stdcpp17</LanguageStandard> 181 <LanguageStandard>stdcpp20</LanguageStandard>
182 <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 182 <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
183 <AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions> 183 <AdditionalOptions>/Zc:__cplusplus /utf-8 %(AdditionalOptions)</AdditionalOptions>
184 </ClCompile> 184 </ClCompile>
185 <Link> 185 <Link>
186 <SubSystem>Console</SubSystem> 186 <SubSystem>Console</SubSystem>
@@ -191,11 +191,11 @@
191 <ClCompile> 191 <ClCompile>
192 <WarningLevel>Level3</WarningLevel> 192 <WarningLevel>Level3</WarningLevel>
193 <SDLCheck>true</SDLCheck> 193 <SDLCheck>true</SDLCheck>
194 <PreprocessorDefinitions>_DEBUG;_CONSOLE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 194 <PreprocessorDefinitions>_DEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS;YUE_UTF8_IMPL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
195 <ConformanceMode>true</ConformanceMode> 195 <ConformanceMode>true</ConformanceMode>
196 <LanguageStandard>stdcpp17</LanguageStandard> 196 <LanguageStandard>stdcpp20</LanguageStandard>
197 <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 197 <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
198 <AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions> 198 <AdditionalOptions>/Zc:__cplusplus /utf-8 %(AdditionalOptions)</AdditionalOptions>
199 </ClCompile> 199 </ClCompile>
200 <Link> 200 <Link>
201 <SubSystem>Console</SubSystem> 201 <SubSystem>Console</SubSystem>
@@ -206,30 +206,32 @@
206 <ClCompile> 206 <ClCompile>
207 <WarningLevel>Level3</WarningLevel> 207 <WarningLevel>Level3</WarningLevel>
208 <SDLCheck>true</SDLCheck> 208 <SDLCheck>true</SDLCheck>
209 <PreprocessorDefinitions>_DEBUG;_CONSOLE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SCL_SECURE_NO_WARNINGS;_ITERATOR_DEBUG_LEVEL=0;%(PreprocessorDefinitions)</PreprocessorDefinitions> 209 <PreprocessorDefinitions>_DEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS;_ITERATOR_DEBUG_LEVEL=0;YUE_UTF8_IMPL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
210 <ConformanceMode>true</ConformanceMode> 210 <ConformanceMode>true</ConformanceMode>
211 <LanguageStandard>stdcpp17</LanguageStandard> 211 <LanguageStandard>stdcpp20</LanguageStandard>
212 <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 212 <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
213 <AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions> 213 <AdditionalOptions>/Zc:__cplusplus /utf-8 %(AdditionalOptions)</AdditionalOptions>
214 </ClCompile> 214 </ClCompile>
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'">
221 <ClCompile> 222 <ClCompile>
222 <WarningLevel>Level3</WarningLevel> 223 <WarningLevel>Level3</WarningLevel>
223 <SDLCheck>true</SDLCheck> 224 <SDLCheck>true</SDLCheck>
224 <PreprocessorDefinitions>_DEBUG;_CONSOLE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 225 <PreprocessorDefinitions>_DEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS;YUE_UTF8_IMPL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
225 <ConformanceMode>true</ConformanceMode> 226 <ConformanceMode>true</ConformanceMode>
226 <LanguageStandard>stdcpp17</LanguageStandard> 227 <LanguageStandard>stdcpp20</LanguageStandard>
227 <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 228 <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
228 <AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions> 229 <AdditionalOptions>/Zc:__cplusplus /utf-8 %(AdditionalOptions)</AdditionalOptions>
229 </ClCompile> 230 </ClCompile>
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'">
@@ -238,11 +240,11 @@
238 <FunctionLevelLinking>true</FunctionLevelLinking> 240 <FunctionLevelLinking>true</FunctionLevelLinking>
239 <IntrinsicFunctions>true</IntrinsicFunctions> 241 <IntrinsicFunctions>true</IntrinsicFunctions>
240 <SDLCheck>true</SDLCheck> 242 <SDLCheck>true</SDLCheck>
241 <PreprocessorDefinitions>NDEBUG;_CONSOLE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 243 <PreprocessorDefinitions>NDEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS;YUE_UTF8_IMPL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
242 <ConformanceMode>true</ConformanceMode> 244 <ConformanceMode>true</ConformanceMode>
243 <LanguageStandard>stdcpp17</LanguageStandard> 245 <LanguageStandard>stdcpp20</LanguageStandard>
244 <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 246 <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
245 <AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions> 247 <AdditionalOptions>/Zc:__cplusplus /utf-8 %(AdditionalOptions)</AdditionalOptions>
246 </ClCompile> 248 </ClCompile>
247 <Link> 249 <Link>
248 <SubSystem>Console</SubSystem> 250 <SubSystem>Console</SubSystem>
@@ -257,11 +259,11 @@
257 <FunctionLevelLinking>true</FunctionLevelLinking> 259 <FunctionLevelLinking>true</FunctionLevelLinking>
258 <IntrinsicFunctions>true</IntrinsicFunctions> 260 <IntrinsicFunctions>true</IntrinsicFunctions>
259 <SDLCheck>true</SDLCheck> 261 <SDLCheck>true</SDLCheck>
260 <PreprocessorDefinitions>NDEBUG;_CONSOLE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 262 <PreprocessorDefinitions>NDEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS;YUE_UTF8_IMPL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
261 <ConformanceMode>true</ConformanceMode> 263 <ConformanceMode>true</ConformanceMode>
262 <LanguageStandard>stdcpp17</LanguageStandard> 264 <LanguageStandard>stdcpp20</LanguageStandard>
263 <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 265 <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
264 <AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions> 266 <AdditionalOptions>/Zc:__cplusplus /utf-8 %(AdditionalOptions)</AdditionalOptions>
265 </ClCompile> 267 </ClCompile>
266 <Link> 268 <Link>
267 <SubSystem>Console</SubSystem> 269 <SubSystem>Console</SubSystem>
@@ -276,17 +278,18 @@
276 <FunctionLevelLinking>true</FunctionLevelLinking> 278 <FunctionLevelLinking>true</FunctionLevelLinking>
277 <IntrinsicFunctions>true</IntrinsicFunctions> 279 <IntrinsicFunctions>true</IntrinsicFunctions>
278 <SDLCheck>true</SDLCheck> 280 <SDLCheck>true</SDLCheck>
279 <PreprocessorDefinitions>NDEBUG;_CONSOLE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 281 <PreprocessorDefinitions>NDEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS;YUE_UTF8_IMPL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
280 <ConformanceMode>true</ConformanceMode> 282 <ConformanceMode>true</ConformanceMode>
281 <LanguageStandard>stdcpp17</LanguageStandard> 283 <LanguageStandard>stdcpp20</LanguageStandard>
282 <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 284 <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
283 <AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions> 285 <AdditionalOptions>/Zc:__cplusplus /utf-8 %(AdditionalOptions)</AdditionalOptions>
284 </ClCompile> 286 </ClCompile>
285 <Link> 287 <Link>
286 <SubSystem>Console</SubSystem> 288 <SubSystem>Console</SubSystem>
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'">
@@ -295,20 +298,22 @@
295 <FunctionLevelLinking>true</FunctionLevelLinking> 298 <FunctionLevelLinking>true</FunctionLevelLinking>
296 <IntrinsicFunctions>true</IntrinsicFunctions> 299 <IntrinsicFunctions>true</IntrinsicFunctions>
297 <SDLCheck>true</SDLCheck> 300 <SDLCheck>true</SDLCheck>
298 <PreprocessorDefinitions>NDEBUG;_CONSOLE;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;_SCL_SECURE_NO_WARNINGS;%(PreprocessorDefinitions)</PreprocessorDefinitions> 301 <PreprocessorDefinitions>NDEBUG;_CONSOLE;_SCL_SECURE_NO_WARNINGS;YUE_UTF8_IMPL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
299 <ConformanceMode>true</ConformanceMode> 302 <ConformanceMode>true</ConformanceMode>
300 <LanguageStandard>stdcpp17</LanguageStandard> 303 <LanguageStandard>stdcpp20</LanguageStandard>
301 <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 304 <AdditionalIncludeDirectories>..\..\src;..\..\src\3rdParty;..\..\src\3rdParty\lua;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
302 <AdditionalOptions>/Zc:__cplusplus %(AdditionalOptions)</AdditionalOptions> 305 <AdditionalOptions>/Zc:__cplusplus /utf-8 %(AdditionalOptions)</AdditionalOptions>
303 </ClCompile> 306 </ClCompile>
304 <Link> 307 <Link>
305 <SubSystem>Console</SubSystem> 308 <SubSystem>Console</SubSystem>
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>
316 <ClCompile Include="..\..\src\3rdParty\colib\ljson.c" />
312 <ClCompile Include="..\..\src\3rdParty\lua\lapi.c" /> 317 <ClCompile Include="..\..\src\3rdParty\lua\lapi.c" />
313 <ClCompile Include="..\..\src\3rdParty\lua\lauxlib.c" /> 318 <ClCompile Include="..\..\src\3rdParty\lua\lauxlib.c" />
314 <ClCompile Include="..\..\src\3rdParty\lua\lbaselib.c" /> 319 <ClCompile Include="..\..\src\3rdParty\lua\lbaselib.c" />
diff --git a/win-build/Yuescript/Yuescript.vcxproj.filters b/win-build/Yuescript/Yuescript.vcxproj.filters
index 122f0b6..73efba3 100644
--- a/win-build/Yuescript/Yuescript.vcxproj.filters
+++ b/win-build/Yuescript/Yuescript.vcxproj.filters
@@ -17,6 +17,9 @@
17 <Filter Include="src\efsw\win"> 17 <Filter Include="src\efsw\win">
18 <UniqueIdentifier>{4b765224-203c-4df9-ba95-c975f75c4cf1}</UniqueIdentifier> 18 <UniqueIdentifier>{4b765224-203c-4df9-ba95-c975f75c4cf1}</UniqueIdentifier>
19 </Filter> 19 </Filter>
20 <Filter Include="src\colib">
21 <UniqueIdentifier>{0f5875b7-722d-4903-8299-eeb462a34086}</UniqueIdentifier>
22 </Filter>
20 </ItemGroup> 23 </ItemGroup>
21 <ItemGroup> 24 <ItemGroup>
22 <ClCompile Include="..\..\src\3rdParty\lua\lapi.c"> 25 <ClCompile Include="..\..\src\3rdParty\lua\lapi.c">
@@ -205,6 +208,9 @@
205 <ClCompile Include="..\..\src\yuescript\yue_ast.cpp"> 208 <ClCompile Include="..\..\src\yuescript\yue_ast.cpp">
206 <Filter>src\yuescript</Filter> 209 <Filter>src\yuescript</Filter>
207 </ClCompile> 210 </ClCompile>
211 <ClCompile Include="..\..\src\3rdParty\colib\ljson.c">
212 <Filter>src\colib</Filter>
213 </ClCompile>
208 </ItemGroup> 214 </ItemGroup>
209 <ItemGroup> 215 <ItemGroup>
210 <ClInclude Include="..\..\src\3rdParty\lua\lapi.h"> 216 <ClInclude Include="..\..\src\3rdParty\lua\lapi.h">
diff --git a/win-build/YuescriptDLL/YuescriptDLL.vcxproj b/win-build/YuescriptDLL/YuescriptDLL.vcxproj
index b418163..1544c3c 100644
--- a/win-build/YuescriptDLL/YuescriptDLL.vcxproj
+++ b/win-build/YuescriptDLL/YuescriptDLL.vcxproj
@@ -176,9 +176,9 @@
176 <ClCompile> 176 <ClCompile>
177 <WarningLevel>Level3</WarningLevel> 177 <WarningLevel>Level3</WarningLevel>
178 <SDLCheck>true</SDLCheck> 178 <SDLCheck>true</SDLCheck>
179 <PreprocessorDefinitions>_DEBUG;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;YUE_BUILD_AS_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> 179 <PreprocessorDefinitions>_DEBUG;UTF_CPP_CPLUSPLUS=202002L;YUE_BUILD_AS_DLL;YUE_UTF8_IMPL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
180 <ConformanceMode>true</ConformanceMode> 180 <ConformanceMode>true</ConformanceMode>
181 <LanguageStandard>stdcpp17</LanguageStandard> 181 <LanguageStandard>stdcpp20</LanguageStandard>
182 <AdditionalIncludeDirectories>..\lua51;..\..\src;..\..\src\3rdParty;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 182 <AdditionalIncludeDirectories>..\lua51;..\..\src;..\..\src\3rdParty;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
183 </ClCompile> 183 </ClCompile>
184 <Link> 184 <Link>
@@ -194,9 +194,9 @@
194 <ClCompile> 194 <ClCompile>
195 <WarningLevel>Level3</WarningLevel> 195 <WarningLevel>Level3</WarningLevel>
196 <SDLCheck>true</SDLCheck> 196 <SDLCheck>true</SDLCheck>
197 <PreprocessorDefinitions>_DEBUG;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;YUE_BUILD_AS_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> 197 <PreprocessorDefinitions>_DEBUG;UTF_CPP_CPLUSPLUS=202002L;YUE_BUILD_AS_DLL;YUE_UTF8_IMPL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
198 <ConformanceMode>true</ConformanceMode> 198 <ConformanceMode>true</ConformanceMode>
199 <LanguageStandard>stdcpp17</LanguageStandard> 199 <LanguageStandard>stdcpp20</LanguageStandard>
200 <AdditionalIncludeDirectories>..\lua53;..\..\src;..\..\src\3rdParty;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 200 <AdditionalIncludeDirectories>..\lua53;..\..\src;..\..\src\3rdParty;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
201 </ClCompile> 201 </ClCompile>
202 <Link> 202 <Link>
@@ -214,9 +214,9 @@
214 <FunctionLevelLinking>true</FunctionLevelLinking> 214 <FunctionLevelLinking>true</FunctionLevelLinking>
215 <IntrinsicFunctions>true</IntrinsicFunctions> 215 <IntrinsicFunctions>true</IntrinsicFunctions>
216 <SDLCheck>true</SDLCheck> 216 <SDLCheck>true</SDLCheck>
217 <PreprocessorDefinitions>NDEBUG;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;YUE_BUILD_AS_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> 217 <PreprocessorDefinitions>NDEBUG;UTF_CPP_CPLUSPLUS=202002L;YUE_BUILD_AS_DLL;YUE_UTF8_IMPL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
218 <ConformanceMode>true</ConformanceMode> 218 <ConformanceMode>true</ConformanceMode>
219 <LanguageStandard>stdcpp17</LanguageStandard> 219 <LanguageStandard>stdcpp20</LanguageStandard>
220 <AdditionalIncludeDirectories>..\lua51;..\..\src;..\..\src\3rdParty;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 220 <AdditionalIncludeDirectories>..\lua51;..\..\src;..\..\src\3rdParty;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
221 </ClCompile> 221 </ClCompile>
222 <Link> 222 <Link>
@@ -236,9 +236,9 @@
236 <FunctionLevelLinking>true</FunctionLevelLinking> 236 <FunctionLevelLinking>true</FunctionLevelLinking>
237 <IntrinsicFunctions>true</IntrinsicFunctions> 237 <IntrinsicFunctions>true</IntrinsicFunctions>
238 <SDLCheck>true</SDLCheck> 238 <SDLCheck>true</SDLCheck>
239 <PreprocessorDefinitions>NDEBUG;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;YUE_BUILD_AS_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> 239 <PreprocessorDefinitions>NDEBUG;UTF_CPP_CPLUSPLUS=202002L;YUE_BUILD_AS_DLL;YUE_UTF8_IMPL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
240 <ConformanceMode>true</ConformanceMode> 240 <ConformanceMode>true</ConformanceMode>
241 <LanguageStandard>stdcpp17</LanguageStandard> 241 <LanguageStandard>stdcpp20</LanguageStandard>
242 <AdditionalIncludeDirectories>..\lua53;..\..\src;..\..\src\3rdParty;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 242 <AdditionalIncludeDirectories>..\lua53;..\..\src;..\..\src\3rdParty;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
243 </ClCompile> 243 </ClCompile>
244 <Link> 244 <Link>
@@ -256,9 +256,9 @@
256 <ClCompile> 256 <ClCompile>
257 <WarningLevel>Level3</WarningLevel> 257 <WarningLevel>Level3</WarningLevel>
258 <SDLCheck>true</SDLCheck> 258 <SDLCheck>true</SDLCheck>
259 <PreprocessorDefinitions>_DEBUG;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;YUE_BUILD_AS_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> 259 <PreprocessorDefinitions>_DEBUG;YUE_BUILD_AS_DLL;YUE_UTF8_IMPL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
260 <ConformanceMode>true</ConformanceMode> 260 <ConformanceMode>true</ConformanceMode>
261 <LanguageStandard>stdcpp17</LanguageStandard> 261 <LanguageStandard>stdcpp20</LanguageStandard>
262 <AdditionalIncludeDirectories>..\lua51;..\..\src;..\..\src\3rdParty;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 262 <AdditionalIncludeDirectories>..\lua51;..\..\src;..\..\src\3rdParty;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
263 </ClCompile> 263 </ClCompile>
264 <Link> 264 <Link>
@@ -274,9 +274,9 @@
274 <ClCompile> 274 <ClCompile>
275 <WarningLevel>Level3</WarningLevel> 275 <WarningLevel>Level3</WarningLevel>
276 <SDLCheck>true</SDLCheck> 276 <SDLCheck>true</SDLCheck>
277 <PreprocessorDefinitions>_DEBUG;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;YUE_BUILD_AS_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> 277 <PreprocessorDefinitions>_DEBUG;UTF_CPP_CPLUSPLUS=202002L;YUE_BUILD_AS_DLL;YUE_UTF8_IMPL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
278 <ConformanceMode>true</ConformanceMode> 278 <ConformanceMode>true</ConformanceMode>
279 <LanguageStandard>stdcpp17</LanguageStandard> 279 <LanguageStandard>stdcpp20</LanguageStandard>
280 <AdditionalIncludeDirectories>..\lua53;..\..\src;..\..\src\3rdParty;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 280 <AdditionalIncludeDirectories>..\lua53;..\..\src;..\..\src\3rdParty;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
281 </ClCompile> 281 </ClCompile>
282 <Link> 282 <Link>
@@ -294,9 +294,9 @@
294 <FunctionLevelLinking>true</FunctionLevelLinking> 294 <FunctionLevelLinking>true</FunctionLevelLinking>
295 <IntrinsicFunctions>true</IntrinsicFunctions> 295 <IntrinsicFunctions>true</IntrinsicFunctions>
296 <SDLCheck>true</SDLCheck> 296 <SDLCheck>true</SDLCheck>
297 <PreprocessorDefinitions>NDEBUG;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;YUE_BUILD_AS_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> 297 <PreprocessorDefinitions>NDEBUG;UTF_CPP_CPLUSPLUS=202002L;YUE_BUILD_AS_DLL;YUE_UTF8_IMPL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
298 <ConformanceMode>true</ConformanceMode> 298 <ConformanceMode>true</ConformanceMode>
299 <LanguageStandard>stdcpp17</LanguageStandard> 299 <LanguageStandard>stdcpp20</LanguageStandard>
300 <AdditionalIncludeDirectories>..\lua51;..\..\src;..\..\src\3rdParty;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 300 <AdditionalIncludeDirectories>..\lua51;..\..\src;..\..\src\3rdParty;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
301 </ClCompile> 301 </ClCompile>
302 <Link> 302 <Link>
@@ -316,9 +316,9 @@
316 <FunctionLevelLinking>true</FunctionLevelLinking> 316 <FunctionLevelLinking>true</FunctionLevelLinking>
317 <IntrinsicFunctions>true</IntrinsicFunctions> 317 <IntrinsicFunctions>true</IntrinsicFunctions>
318 <SDLCheck>true</SDLCheck> 318 <SDLCheck>true</SDLCheck>
319 <PreprocessorDefinitions>NDEBUG;_SILENCE_CXX17_CODECVT_HEADER_DEPRECATION_WARNING;YUE_BUILD_AS_DLL;%(PreprocessorDefinitions)</PreprocessorDefinitions> 319 <PreprocessorDefinitions>NDEBUG;UTF_CPP_CPLUSPLUS=202002L;YUE_BUILD_AS_DLL;YUE_UTF8_IMPL;%(PreprocessorDefinitions)</PreprocessorDefinitions>
320 <ConformanceMode>true</ConformanceMode> 320 <ConformanceMode>true</ConformanceMode>
321 <LanguageStandard>stdcpp17</LanguageStandard> 321 <LanguageStandard>stdcpp20</LanguageStandard>
322 <AdditionalIncludeDirectories>..\lua53;..\..\src;..\..\src\3rdParty;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories> 322 <AdditionalIncludeDirectories>..\lua53;..\..\src;..\..\src\3rdParty;%(AdditionalIncludeDirectories)</AdditionalIncludeDirectories>
323 </ClCompile> 323 </ClCompile>
324 <Link> 324 <Link>
@@ -352,4 +352,4 @@
352 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" /> 352 <Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
353 <ImportGroup Label="ExtensionTargets"> 353 <ImportGroup Label="ExtensionTargets">
354 </ImportGroup> 354 </ImportGroup>
355</Project> \ No newline at end of file 355</Project>