aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.github/workflows/macos.yml2
-rw-r--r--.github/workflows/windows.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.md1000
-rwxr-xr-xdoc/docs/zh/README.md2
-rwxr-xr-xdoc/docs/zh/doc/README.md1177
-rw-r--r--makefile63
-rw-r--r--spec/inputs/backcall.yue4
-rw-r--r--spec/inputs/destructure.yue50
-rw-r--r--spec/inputs/funcs.yue33
-rw-r--r--spec/inputs/global.yue6
-rw-r--r--spec/inputs/import.yue12
-rw-r--r--spec/inputs/import_global.yue93
-rw-r--r--spec/inputs/lists.yue190
-rw-r--r--spec/inputs/loops.yue52
-rw-r--r--spec/inputs/macro.yue54
-rw-r--r--spec/inputs/macro_export.yue31
-rw-r--r--spec/inputs/macro_teal.yue13
-rw-r--r--spec/inputs/macro_todo.yue7
-rw-r--r--spec/inputs/props.yue61
-rw-r--r--spec/inputs/string.yue73
-rw-r--r--spec/inputs/switch.yue125
-rw-r--r--spec/inputs/syntax.yue68
-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.yue6
-rw-r--r--spec/inputs/unicode/vararg.yue4
-rw-r--r--spec/inputs/unicode/whitespace.yue10
-rw-r--r--spec/inputs/unicode/with.yue24
-rw-r--r--spec/inputs/vararg.yue48
-rw-r--r--spec/inputs/whitespace.yue10
-rw-r--r--spec/inputs/with.yue42
-rw-r--r--spec/outputs/5.1/import_global.lua131
-rw-r--r--spec/outputs/5.1/literals.lua44
-rw-r--r--spec/outputs/5.1/loops.lua132
-rw-r--r--spec/outputs/5.1/try_catch.lua265
-rw-r--r--spec/outputs/assign.lua6
-rw-r--r--spec/outputs/codes_from_doc.lua1118
-rw-r--r--spec/outputs/codes_from_doc_zh.lua1118
-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/global.lua25
-rw-r--r--spec/outputs/import.lua10
-rw-r--r--spec/outputs/import_global.lua131
-rw-r--r--spec/outputs/lists.lua594
-rw-r--r--spec/outputs/loops.lua132
-rw-r--r--spec/outputs/macro.lua15
-rw-r--r--spec/outputs/props.lua240
-rw-r--r--spec/outputs/string.lua41
-rw-r--r--spec/outputs/switch.lua362
-rw-r--r--spec/outputs/syntax.lua94
-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/loops.lua4
-rw-r--r--spec/outputs/unicode/macro.lua48
-rw-r--r--spec/outputs/unicode/multiline_chain.lua6
-rw-r--r--spec/outputs/unicode/syntax.lua10
-rw-r--r--spec/outputs/unicode/vararg.lua28
-rw-r--r--spec/outputs/unicode/whitespace.lua8
-rw-r--r--spec/outputs/upvalue_func.lua48
-rw-r--r--spec/outputs/vararg.lua100
-rw-r--r--spec/outputs/whitespace.lua8
-rw-r--r--spec/outputs/with.lua62
-rwxr-xr-xsrc/3rdParty/colib/LICENSE21
-rw-r--r--src/3rdParty/colib/ljson.c925
-rw-r--r--src/3rdParty/efsw/FileWatcherGeneric.cpp2
-rwxr-xr-xsrc/3rdParty/utf8cpp.h1277
-rw-r--r--src/yue.cpp47
-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.cpp303
-rw-r--r--src/yuescript/yue_ast.h203
-rw-r--r--src/yuescript/yue_compiler.cpp2621
-rw-r--r--src/yuescript/yue_compiler.h4
-rw-r--r--src/yuescript/yue_parser.cpp713
-rw-r--r--src/yuescript/yue_parser.h90
-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
98 files changed, 13505 insertions, 2172 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/.github/workflows/windows.yml b/.github/workflows/windows.yml
index 2327710..04d08b0 100644
--- a/.github/workflows/windows.yml
+++ b/.github/workflows/windows.yml
@@ -24,6 +24,7 @@ jobs:
24 bin\windows\Win32\Debug\yue.exe spec\inputs\loops.yue -o spec\generated\5.1\loops.lua --target=5.1 24 bin\windows\Win32\Debug\yue.exe spec\inputs\loops.yue -o spec\generated\5.1\loops.lua --target=5.1
25 bin\windows\Win32\Debug\yue.exe spec\inputs\try_catch.yue -o spec\generated\5.1\try_catch.lua --target=5.1 25 bin\windows\Win32\Debug\yue.exe spec\inputs\try_catch.yue -o spec\generated\5.1\try_catch.lua --target=5.1
26 bin\windows\Win32\Debug\yue.exe spec\inputs\attrib.yue -o spec\generated\5.1\attrib.lua --target=5.1 26 bin\windows\Win32\Debug\yue.exe spec\inputs\attrib.yue -o spec\generated\5.1\attrib.lua --target=5.1
27 bin\windows\Win32\Debug\yue.exe spec\inputs\import_global.yue -o spec\generated\5.1\import_global.lua --target=5.1
27 bin\windows\Win32\Debug\yue.exe spec\inputs\test\loops_spec.yue -o spec\generated\5.1\test\loops_spec.lua --target=5.1 28 bin\windows\Win32\Debug\yue.exe spec\inputs\test\loops_spec.yue -o spec\generated\5.1\test\loops_spec.lua --target=5.1
28 bin\windows\Win32\Debug\yue.exe -e spec/inputs/compile_doc.yue spec/generated 29 bin\windows\Win32\Debug\yue.exe -e spec/inputs/compile_doc.yue spec/generated
29 bin\windows\Win32\Debug\yue.exe -e "io.popen('git diff --no-index spec\\outputs spec\\generated')\read('*a') |> ((r)-> r ~= '' and (print(r) or os.exit 1))" 30 bin\windows\Win32\Debug\yue.exe -e "io.popen('git diff --no-index spec\\outputs spec\\generated')\read('*a') |> ((r)-> r ~= '' and (print(r) or os.exit 1))"
@@ -33,6 +34,7 @@ jobs:
33 bin\windows\x64\Debug\yue.exe spec\inputs\loops.yue -o spec\generated\5.1\loops.lua --target=5.1 34 bin\windows\x64\Debug\yue.exe spec\inputs\loops.yue -o spec\generated\5.1\loops.lua --target=5.1
34 bin\windows\x64\Debug\yue.exe spec\inputs\try_catch.yue -o spec\generated\5.1\try_catch.lua --target=5.1 35 bin\windows\x64\Debug\yue.exe spec\inputs\try_catch.yue -o spec\generated\5.1\try_catch.lua --target=5.1
35 bin\windows\x64\Debug\yue.exe spec\inputs\attrib.yue -o spec\generated\5.1\attrib.lua --target=5.1 36 bin\windows\x64\Debug\yue.exe spec\inputs\attrib.yue -o spec\generated\5.1\attrib.lua --target=5.1
37 bin\windows\x64\Debug\yue.exe spec\inputs\import_global.yue -o spec\generated\5.1\import_global.lua --target=5.1
36 bin\windows\x64\Debug\yue.exe spec\inputs\test\loops_spec.yue -o spec\generated\5.1\test\loops_spec.lua --target=5.1 38 bin\windows\x64\Debug\yue.exe spec\inputs\test\loops_spec.yue -o spec\generated\5.1\test\loops_spec.lua --target=5.1
37 bin\windows\x64\Debug\yue.exe -e spec/inputs/compile_doc.yue spec/generated 39 bin\windows\x64\Debug\yue.exe -e spec/inputs/compile_doc.yue spec/generated
38 bin\windows\x64\Debug\yue.exe -e "io.popen('git diff --no-index spec\\outputs spec\\generated')\read('*a') |> ((r)-> r ~= '' and (print(r) or os.exit 1))" 40 bin\windows\x64\Debug\yue.exe -e "io.popen('git diff --no-index spec\\outputs spec\\generated')\read('*a') |> ((r)-> r ~= '' and (print(r) or os.exit 1))"
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 c4518bf..b5051d4 100755
--- a/doc/docs/doc/README.md
+++ b/doc/docs/doc/README.md
@@ -16,19 +16,29 @@ Yue (月) is the name of moon in Chinese and it's pronounced as [jyɛ].
16### An Overview of YueScript 16### An Overview of YueScript
17```moonscript 17```moonscript
18-- import syntax 18-- import syntax
19import "yue" as :p, :to_lua 19import p, to_lua from "yue"
20 20
21-- object literals 21-- object literals
22inventory = 22inventory =
23 equipment: 23 equipment:
24 * "sword" 24 - "sword"
25 * "shield" 25 - "shield"
26 items: 26 items:
27 * name: "potion" 27 - name: "potion"
28 count: 10 28 count: 10
29 * name: "bread" 29 - name: "bread"
30 count: 3 30 count: 3
31 31
32-- list comprehension
33map = (arr, action) ->
34 [action item for item in *arr]
35
36filter = (arr, cond) ->
37 [item for item in *arr when cond item]
38
39reduce = (arr, init, action): init ->
40 init = action init, item for item in *arr
41
32-- pipe operator 42-- pipe operator
33[1, 2, 3] 43[1, 2, 3]
34 |> map (x) -> x * 2 44 |> map (x) -> x * 2
@@ -51,19 +61,29 @@ export 🌛 = "月之脚本"
51<YueDisplay> 61<YueDisplay>
52<pre> 62<pre>
53-- import syntax 63-- import syntax
54import "yue" as :p, :to_lua 64import p, to_lua from "yue"
55 65
56-- object literals 66-- object literals
57inventory = 67inventory =
58 equipment: 68 equipment:
59 * "sword" 69 - "sword"
60 * "shield" 70 - "shield"
61 items: 71 items:
62 * name: "potion" 72 - name: "potion"
63 count: 10 73 count: 10
64 * name: "bread" 74 - name: "bread"
65 count: 3 75 count: 3
66 76
77-- list comprehension
78map = (arr, action) ->
79 [action item for item in *arr]
80
81filter = (arr, cond) ->
82 [item for item in *arr when cond item]
83
84reduce = (arr, init, action): init ->
85 init = action init, item for item in *arr
86
67-- pipe operator 87-- pipe operator
68[1, 2, 3] 88[1, 2, 3]
69 |> map (x) -> x * 2 89 |> map (x) -> x * 2
@@ -132,14 +152,14 @@ export 🌛 = "月之脚本"
132 152
133&emsp;Use YueScript module in Lua: 153&emsp;Use YueScript module in Lua:
134 154
135* **Case 1** 155* **Case 1**
136Require "your_yuescript_entry.yue" in Lua. 156Require "your_yuescript_entry.yue" in Lua.
137```Lua 157```Lua
138require("yue")("your_yuescript_entry") 158require("yue")("your_yuescript_entry")
139``` 159```
140&emsp;And this code still works when you compile "your_yuescript_entry.yue" to "your_yuescript_entry.lua" in the same path. In the rest YueScript files just use the normal **require** or **import**. The code line numbers in error messages will also be handled correctly. 160&emsp;And this code still works when you compile "your_yuescript_entry.yue" to "your_yuescript_entry.lua" in the same path. In the rest YueScript files just use the normal **require** or **import**. The code line numbers in error messages will also be handled correctly.
141 161
142* **Case 2** 162* **Case 2**
143Require YueScript module and rewite message by hand. 163Require YueScript module and rewite message by hand.
144```lua 164```lua
145local yue = require("yue") 165local yue = require("yue")
@@ -151,7 +171,7 @@ end, function(err)
151end) 171end)
152``` 172```
153 173
154* **Case 3** 174* **Case 3**
155Use the YueScript compiler function in Lua. 175Use the YueScript compiler function in Lua.
156```lua 176```lua
157local yue = require("yue") 177local yue = require("yue")
@@ -203,12 +223,12 @@ Usage: yue [options|files|directories] ...
203 Execute without options to enter REPL, type symbol '$' 223 Execute without options to enter REPL, type symbol '$'
204 in a single line to start/stop multi-line mode 224 in a single line to start/stop multi-line mode
205``` 225```
206&emsp;&emsp;Use cases: 226&emsp;&emsp;Use cases:
207&emsp;&emsp;Recursively compile every YueScript file with extension **.yue** under current path: **yue .** 227&emsp;&emsp;Recursively compile every YueScript file with extension **.yue** under current path: **yue .**
208&emsp;&emsp;Compile and save results to a target path: **yue -t /target/path/ .** 228&emsp;&emsp;Compile and save results to a target path: **yue -t /target/path/ .**
209&emsp;&emsp;Compile and reserve debug info: **yue -l .** 229&emsp;&emsp;Compile and reserve debug info: **yue -l .**
210&emsp;&emsp;Compile and generate minified codes: **yue -m .** 230&emsp;&emsp;Compile and generate minified codes: **yue -m .**
211&emsp;&emsp;Execute raw codes: **yue -e 'print 123'** 231&emsp;&emsp;Execute raw codes: **yue -e 'print 123'**
212&emsp;&emsp;Execute a YueScript file: **yue -e main.yue** 232&emsp;&emsp;Execute a YueScript file: **yue -e main.yue**
213 233
214## Macro 234## Macro
@@ -388,16 +408,16 @@ In YueScript, macro functions allow you to generate code at compile time. By nes
388 408
389```moonscript 409```moonscript
390macro Enum = (...) -> 410macro Enum = (...) ->
391 items = {...} 411 items = {...}
392 itemSet = {item, true for item in *items} 412 itemSet = {item, true for item in *items}
393 (item) -> 413 (item) ->
394 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]
395 "\"#{item}\"" 415 "\"#{item}\""
396 416
397macro BodyType = $Enum( 417macro BodyType = $Enum(
398 Static 418 Static
399 Dynamic 419 Dynamic
400 Kinematic 420 Kinematic
401) 421)
402 422
403print "Valid enum type:", $BodyType Static 423print "Valid enum type:", $BodyType Static
@@ -407,16 +427,16 @@ print "Valid enum type:", $BodyType Static
407<YueDisplay> 427<YueDisplay>
408<pre> 428<pre>
409macro Enum = (...) -> 429macro Enum = (...) ->
410 items = {...} 430 items = {...}
411 itemSet = {item, true for item in *items} 431 itemSet = {item, true for item in *items}
412 (item) -> 432 (item) ->
413 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]
414 "\"#{item}\"" 434 "\"#{item}\""
415 435
416macro BodyType = $Enum( 436macro BodyType = $Enum(
417 Static 437 Static
418 Dynamic 438 Dynamic
419 Kinematic 439 Kinematic
420) 440)
421 441
422print "Valid enum type:", $BodyType Static 442print "Valid enum type:", $BodyType Static
@@ -424,6 +444,54 @@ print "Valid enum type:", $BodyType Static
424</pre> 444</pre>
425</YueDisplay> 445</YueDisplay>
426 446
447### Argument Validation
448
449You can declare the expected AST node types in the argument list, and check whether the incoming macro arguments meet the expectations at compile time.
450
451```moonscript
452macro printNumAndStr = (num `Num, str `String) -> |
453 print(
454 #{num}
455 #{str}
456 )
457
458$printNumAndStr 123, "hello"
459```
460<YueDisplay>
461<pre>
462macro printNumAndStr = (num `Num, str `String) -> |
463 print(
464 #{num}
465 #{str}
466 )
467
468$printNumAndStr 123, "hello"
469</pre>
470</YueDisplay>
471
472If you need more flexible argument checking, you can use the built-in `$is_ast` macro function to manually check at the appropriate place.
473
474```moonscript
475macro printNumAndStr = (num, str) ->
476 error "expected Num as first argument" unless $is_ast Num, num
477 error "expected String as second argument" unless $is_ast String, str
478 "print(#{num}, #{str})"
479
480$printNumAndStr 123, "hello"
481```
482<YueDisplay>
483<pre>
484macro printNumAndStr = (num, str) ->
485 error "expected Num as first argument" unless $is_ast Num, num
486 error "expected String as second argument" unless $is_ast String, str
487 "print(#{num}, #{str})"
488
489$printNumAndStr 123, "hello"
490</pre>
491</YueDisplay>
492
493For more details about available AST nodes, please refer to the uppercased definitions in [yue_parser.cpp](https://github.com/IppClub/YueScript/blob/main/src/yuescript/yue_parser.cpp).
494
427## Operator 495## Operator
428 496
429All of Lua's binary and unary operators are available. Additionally **!=** is as an alias for **~=**, and either **\\** or **::** can be used to write a chaining function call like `tb\func!` or `tb::func!`. And Yuescipt offers some other special operators to write more expressive codes. 497All of Lua's binary and unary operators are available. Additionally **!=** is as an alias for **~=**, and either **\\** or **::** can be used to write a chaining function call like `tb\func!` or `tb::func!`. And Yuescipt offers some other special operators to write more expressive codes.
@@ -466,47 +534,47 @@ Note the evaluation behavior of chained comparisons:
466 534
467```moonscript 535```moonscript
468v = (x) -> 536v = (x) ->
469 print x 537 print x
470 x 538 x
471 539
472print v(1) < v(2) <= v(3) 540print v(1) < v(2) <= v(3)
473--[[ 541--[[
474 output: 542 output:
475 2 543 2
476 1 544 1
477 3 545 3
478 true 546 true
479]] 547]]
480 548
481print v(1) > v(2) <= v(3) 549print v(1) > v(2) <= v(3)
482--[[ 550--[[
483 output: 551 output:
484 2 552 2
485 1 553 1
486 false 554 false
487]] 555]]
488``` 556```
489<YueDisplay> 557<YueDisplay>
490<pre> 558<pre>
491v = (x) -> 559v = (x) ->
492 print x 560 print x
493 x 561 x
494 562
495print v(1) < v(2) <= v(3) 563print v(1) < v(2) <= v(3)
496--[[ 564--[[
497 output: 565 output:
498 2 566 2
499 1 567 1
500 3 568 3
501 true 569 true
502]] 570]]
503 571
504print v(1) > v(2) <= v(3) 572print v(1) > v(2) <= v(3)
505--[[ 573--[[
506 output: 574 output:
507 2 575 2
508 1 576 1
509 false 577 false
510]] 578]]
511</pre> 579</pre>
512</YueDisplay> 580</YueDisplay>
@@ -527,19 +595,36 @@ tab[] = "Value"
527</pre> 595</pre>
528</YueDisplay> 596</YueDisplay>
529 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
530### Table Spreading 615### Table Spreading
531 616
532You 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.
533 618
534```moonscript 619```moonscript
535parts = 620parts =
536 * "shoulders" 621 * "shoulders"
537 * "knees" 622 * "knees"
538lyrics = 623lyrics =
539 * "head" 624 * "head"
540 * ...parts 625 * ...parts
541 * "and" 626 * "and"
542 * "toes" 627 * "toes"
543 628
544copy = {...other} 629copy = {...other}
545 630
@@ -550,13 +635,13 @@ merge = {...a, ...b}
550<YueDisplay> 635<YueDisplay>
551<pre> 636<pre>
552parts = 637parts =
553 * "shoulders" 638 * "shoulders"
554 * "knees" 639 * "knees"
555lyrics = 640lyrics =
556 * "head" 641 * "head"
557 * ...parts 642 * ...parts
558 * "and" 643 * "and"
559 * "toes" 644 * "toes"
560 645
561copy = {...other} 646copy = {...other}
562 647
@@ -566,11 +651,28 @@ merge = {...a, ...b}
566</pre> 651</pre>
567</YueDisplay> 652</YueDisplay>
568 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
569### Metatable 671### Metatable
570 672
571The **<>** operator can be used as a shortcut for metatable manipulation. 673The **<>** operator can be used as a shortcut for metatable manipulation.
572 674
573* **Metatable Creation** 675* **Metatable Creation**
574Create normal table with empty bracekets **<>** or metamethod key which is surrounded by **<>**. 676Create normal table with empty bracekets **<>** or metamethod key which is surrounded by **<>**.
575 677
576```moonscript 678```moonscript
@@ -606,7 +708,7 @@ close _ = &lt;close&gt;: -> print "out of scope"
606</pre> 708</pre>
607</YueDisplay> 709</YueDisplay>
608 710
609* **Metatable Accessing** 711* **Metatable Accessing**
610Accessing metatable with **<>** or metamethod name surrounded by **<>** or writing some expression in **<>**. 712Accessing metatable with **<>** or metamethod name surrounded by **<>** or writing some expression in **<>**.
611 713
612```moonscript 714```moonscript
@@ -630,7 +732,7 @@ print tb.item
630</pre> 732</pre>
631</YueDisplay> 733</YueDisplay>
632 734
633* **Metatable Destructure** 735* **Metatable Destructure**
634Destruct metatable with metamethod key surrounded by **<>**. 736Destruct metatable with metamethod key surrounded by **<>**.
635 737
636```moonscript 738```moonscript
@@ -732,34 +834,45 @@ a ??= false
732 834
733### Implicit Object 835### Implicit Object
734 836
735You can write a list of implicit structures that starts with the symbol **\*** inside a table block. If you are creating implicit object, the fields of the object must be with the same indent. 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
736```moonscript 839```moonscript
840-- assignment with implicit object
737list = 841list =
738 * 1 842 * 1
739 * 2 843 * 2
740 * 3 844 * 3
741 845
846-- function call with implicit object
742func 847func
743 * 1 848 * 1
744 * 2 849 * 2
745 * 3 850 * 3
746 851
852-- return with implicit object
853f = ->
854 return
855 * 1
856 * 2
857 * 3
858
859-- table with implicit object
747tb = 860tb =
748 name: "abc" 861 name: "abc"
749 862
750 values: 863 values:
751 * "a" 864 - "a"
752 * "b" 865 - "b"
753 * "c" 866 - "c"
754 867
755 objects: 868 objects:
756 * name: "a" 869 - name: "a"
757 value: 1 870 value: 1
758 func: => @value + 1 871 func: => @value + 1
759 tb: 872 tb:
760 fieldA: 1 873 fieldA: 1
761 874
762 * name: "b" 875 - name: "b"
763 value: 2 876 value: 2
764 func: => @value + 2 877 func: => @value + 2
765 tb: { } 878 tb: { }
@@ -767,32 +880,42 @@ tb =
767``` 880```
768<YueDisplay> 881<YueDisplay>
769<pre> 882<pre>
883-- assignment with implicit object
770list = 884list =
771 * 1 885 * 1
772 * 2 886 * 2
773 * 3 887 * 3
774 888
889-- function call with implicit object
775func 890func
776 * 1 891 * 1
777 * 2 892 * 2
778 * 3 893 * 3
779 894
895-- return with implicit object
896f = ->
897 return
898 * 1
899 * 2
900 * 3
901
902-- table with implicit object
780tb = 903tb =
781 name: "abc" 904 name: "abc"
782 905
783 values: 906 values:
784 * "a" 907 - "a"
785 * "b" 908 - "b"
786 * "c" 909 - "c"
787 910
788 objects: 911 objects:
789 * name: "a" 912 - name: "a"
790 value: 1 913 value: 1
791 func: => @value + 1 914 func: => @value + 1
792 tb: 915 tb:
793 fieldA: 1 916 fieldA: 1
794 917
795 * name: "b" 918 - name: "b"
796 value: 2 919 value: 2
797 func: => @value + 2 920 func: => @value + 2
798 tb: { } 921 tb: { }
@@ -856,11 +979,67 @@ do
856</pre> 979</pre>
857</YueDisplay> 980</YueDisplay>
858 981
982### Import Global
983
984You can import specific globals into local variables with `import`. When importing a chain of global variable accessings, the last field will be assigned to the local variable.
985
986```moonscript
987do
988 import tostring
989 import table.concat
990 print concat ["a", tostring 1]
991```
992<YueDisplay>
993<pre>
994do
995 import tostring
996 import table.concat
997 print concat ["a", tostring 1]
998</pre>
999</YueDisplay>
1000
1001#### Automatic Import
1002
1003You can place `import global` at the top of a block to automatically import all names that have not been explicitly declared or assigned in the current scope as globals. These implicit imports are treated as local consts that reference the corresponding globals at the position of the statement.
1004
1005Names that are explicitly declared as globals in the same scope will not be imported, so you can still assign to them.
1006
1007```moonscript
1008do
1009 import global
1010 print "hello"
1011 math.random 3
1012 -- print = nil -- error: imported globals are const
1013
1014do
1015 -- explicit global variable will not be imported
1016 import global
1017 global FLAG
1018 print FLAG
1019 FLAG = 123
1020```
1021<YueDisplay>
1022<pre>
1023do
1024 import global
1025 print "hello"
1026 math.random 3
1027 -- print = nil -- error: imported globals are const
1028
1029do
1030 -- explicit global variable will not be imported
1031 import global
1032 global FLAG
1033 print FLAG
1034 FLAG = 123
1035</pre>
1036</YueDisplay>
1037
859### Export 1038### Export
860 1039
861The export statement offers a concise way to define modules. 1040The export statement offers a concise way to define modules.
862 1041
863* **Named Export** 1042* **Named Export**
864Named export will define a local variable as well as adding a field in the exported table. 1043Named export will define a local variable as well as adding a field in the exported table.
865 1044
866```moonscript 1045```moonscript
@@ -924,7 +1103,7 @@ export["a-b-c"] = 123
924</pre> 1103</pre>
925</YueDisplay> 1104</YueDisplay>
926 1105
927* **Unnamed Export** 1106* **Unnamed Export**
928Unnamed export will add the target item into the array part of the exported table. 1107Unnamed export will add the target item into the array part of the exported table.
929 1108
930```moonscript 1109```moonscript
@@ -954,7 +1133,7 @@ export with tmp
954</pre> 1133</pre>
955</YueDisplay> 1134</YueDisplay>
956 1135
957* **Default Export** 1136* **Default Export**
958Using the **default** keyword in export statement to replace the exported table with any thing. 1137Using the **default** keyword in export statement to replace the exported table with any thing.
959 1138
960```moonscript 1139```moonscript
@@ -1202,7 +1381,7 @@ If the destructuring statement is complicated, feel free to spread it out over a
1202</pre> 1381</pre>
1203</YueDisplay> 1382</YueDisplay>
1204 1383
1205It’s common to extract values from at table and assign them the local variables that have the same name as the key. In order to avoid repetition we can use the **:** prefix operator: 1384It's common to extract values from at table and assign them the local variables that have the same name as the key. In order to avoid repetition we can use the **:** prefix operator:
1206 1385
1207```moonscript 1386```moonscript
1208{:concat, :insert} = table 1387{:concat, :insert} = table
@@ -1246,6 +1425,52 @@ You can use `_` as placeholder when doing a list destructuring:
1246</pre> 1425</pre>
1247</YueDisplay> 1426</YueDisplay>
1248 1427
1428### Range Destructuring
1429
1430You 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.
1431
1432```moonscript
1433orders = ["first", "second", "third", "fourth", "last"]
1434[first, ...bulk, last] = orders
1435print first -- prints: first
1436print bulk -- prints: {"second", "third", "fourth"}
1437print last -- prints: last
1438```
1439<YueDisplay>
1440<pre>
1441orders = ["first", "second", "third", "fourth", "last"]
1442[first, ...bulk, last] = orders
1443print first -- prints: first
1444print bulk -- prints: {"second", "third", "fourth"}
1445print last -- prints: last
1446</pre>
1447</YueDisplay>
1448
1449The 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:
1450
1451```moonscript
1452-- Capture everything after first element
1453[first, ...rest] = orders
1454
1455-- Capture everything before last element
1456[...start, last] = orders
1457
1458-- Capture things except the middle elements
1459[first, ..._, last] = orders
1460```
1461<YueDisplay>
1462<pre>
1463-- Capture everything after first element
1464[first, ...rest] = orders
1465
1466-- Capture everything before last element
1467[...start, last] = orders
1468
1469-- Capture things except the middle elements
1470[first, ..._, last] = orders
1471</pre>
1472</YueDisplay>
1473
1249### Destructuring In Other Places 1474### Destructuring In Other Places
1250 1475
1251Destructuring can also show up in places where an assignment implicitly takes place. An example of this is a for loop: 1476Destructuring can also show up in places where an assignment implicitly takes place. An example of this is a for loop:
@@ -1363,6 +1588,19 @@ print ok, count, first
1363 1588
1364YueScript is a whitespace significant language. You have to write some code block in the same indent with space **' '** or tab **'\t'** like function body, value list and some control blocks. And expressions containing different whitespaces might mean different things. Tab is treated like 4 space, but it's better not mix the use of spaces and tabs. 1589YueScript is a whitespace significant language. You have to write some code block in the same indent with space **' '** or tab **'\t'** like function body, value list and some control blocks. And expressions containing different whitespaces might mean different things. Tab is treated like 4 space, but it's better not mix the use of spaces and tabs.
1365 1590
1591### Statement Separator
1592
1593A statement normally ends at a line break. You can also use a semicolon `;` to explicitly terminate a statement, which allows writing multiple statements on the same line:
1594
1595```moonscript
1596a = 1; b = 2; print a + b
1597```
1598<YueDisplay>
1599<pre>
1600a = 1; b = 2; print a + b
1601</pre>
1602</YueDisplay>
1603
1366### Multiline Chaining 1604### Multiline Chaining
1367 1605
1368You can write multi-line chaining function calls with a same indent. 1606You can write multi-line chaining function calls with a same indent.
@@ -1475,6 +1713,47 @@ catch err
1475</pre> 1713</pre>
1476</YueDisplay> 1714</YueDisplay>
1477 1715
1716### Try?
1717
1718`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.
1719
1720```moonscript
1721a, b, c = try? func!
1722
1723-- with nil coalescing operator
1724a = (try? func!) ?? "default"
1725
1726-- as function argument
1727f try? func!
1728
1729-- with catch block
1730f try?
1731 print 123
1732 func!
1733catch e
1734 print e
1735 e
1736```
1737<YueDisplay>
1738<pre>
1739a, b, c = try? func!
1740
1741-- with nil coalescing operator
1742a = (try? func!) ?? "default"
1743
1744-- as function argument
1745f try? func!
1746
1747-- with catch block
1748f try?
1749 print 123
1750 func!
1751catch e
1752 print e
1753 e
1754</pre>
1755</YueDisplay>
1756
1478## Attributes 1757## Attributes
1479 1758
1480Syntax support for Lua 5.4 attributes. And you can still use both the `const` and `close` declaration and get constant check and scoped callback working when targeting Lua versions below 5.4. 1759Syntax support for Lua 5.4 attributes. And you can still use both the `const` and `close` declaration and get constant check and scoped callback working when targeting Lua versions below 5.4.
@@ -1503,6 +1782,19 @@ const {:a, :b, c, d} = tb
1503</pre> 1782</pre>
1504</YueDisplay> 1783</YueDisplay>
1505 1784
1785You can also declare a global variable to be `const`.
1786
1787```moonscript
1788global const Constant = 123
1789-- Constant = 1
1790```
1791<YueDisplay>
1792<pre>
1793global const Constant = 123
1794-- Constant = 1
1795</pre>
1796</YueDisplay>
1797
1506## Literals 1798## Literals
1507 1799
1508All of the primitive literals in Lua can be used. This applies to numbers, strings, booleans, and **nil**. 1800All of the primitive literals in Lua can be used. This applies to numbers, strings, booleans, and **nil**.
@@ -1535,12 +1827,73 @@ You can use underscores in a number literal to increase readability.
1535```moonscript 1827```moonscript
1536integer = 1_000_000 1828integer = 1_000_000
1537hex = 0xEF_BB_BF 1829hex = 0xEF_BB_BF
1830binary = 0B10011
1538``` 1831```
1539<YueDisplay> 1832<YueDisplay>
1540 1833
1541<pre> 1834<pre>
1542integer = 1_000_000 1835integer = 1_000_000
1543hex = 0xEF_BB_BF 1836hex = 0xEF_BB_BF
1837binary = 0B10011
1838</pre>
1839</YueDisplay>
1840
1841### YAML Multiline String
1842
1843The `|` prefix introduces a YAML-style multiline string literal:
1844
1845```moonscript
1846str = |
1847 key: value
1848 list:
1849 - item1
1850 - #{expr}
1851```
1852<YueDisplay>
1853<pre>
1854str = |
1855 key: value
1856 list:
1857 - item1
1858 - #{expr}
1859</pre>
1860</YueDisplay>
1861
1862This 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)`.
1863
1864YAML 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.
1865
1866```moonscript
1867fn = ->
1868 str = |
1869 foo:
1870 bar: baz
1871 return str
1872```
1873<YueDisplay>
1874<pre>
1875fn = ->
1876 str = |
1877 foo:
1878 bar: baz
1879 return str
1880</pre>
1881</YueDisplay>
1882
1883Internal indentation is preserved relative to the removed common prefix, allowing clean nested structures.
1884
1885All 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.
1886
1887```moonscript
1888str = |
1889 path: "C:\Program Files\App"
1890 note: 'He said: "#{Hello}!"'
1891```
1892<YueDisplay>
1893<pre>
1894str = |
1895 path: "C:\Program Files\App"
1896 note: 'He said: "#{Hello}!"'
1544</pre> 1897</pre>
1545</YueDisplay> 1898</YueDisplay>
1546 1899
@@ -1861,6 +2214,138 @@ if func 1, 2, 3,
1861</pre> 2214</pre>
1862</YueDisplay> 2215</YueDisplay>
1863 2216
2217### Parameter Destructuring
2218
2219YueScript now supports destructuring function parameters when the argument is an object. Two forms of destructuring table literals are available:
2220
2221* **Curly-brace wrapped literals/object parameters**, allowing optional default values when fields are missing (e.g., `{:a, :b}`, `{a: a1 = 123}`).
2222
2223* **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.
2224
2225```moonscript
2226f1 = (:a, :b, :c) ->
2227 print a, b, c
2228
2229f1 a: 1, b: "2", c: {}
2230
2231f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) ->
2232 print a1, b, c
2233
2234arg1 = {a: 0}
2235f2 arg1, arg2
2236```
2237<YueDisplay>
2238<pre>
2239f1 = (:a, :b, :c) ->
2240 print a, b, c
2241
2242f1 a: 1, b: "2", c: {}
2243
2244f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) ->
2245print a1, b, c
2246
2247arg1 = {a: 0}
2248f2 arg1, arg2
2249</pre>
2250</YueDisplay>
2251
2252### Prefixed Return Expression
2253
2254When 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:
2255
2256```moon
2257findFirstEven = (list): nil ->
2258 for item in *list
2259 if type(item) == "table"
2260 for sub in *item
2261 if sub % 2 == 0
2262 return sub
2263```
2264<YueDisplay>
2265<pre>
2266findFirstEven = (list): nil ->
2267 for item in *list
2268 if type(item) == "table"
2269 for sub in *item
2270 if sub % 2 == 0
2271 return sub
2272</pre>
2273</YueDisplay>
2274
2275This is equivalent to:
2276
2277```moon
2278findFirstEven = (list) ->
2279 for item in *list
2280 if type(item) == "table"
2281 for sub in *item
2282 if sub % 2 == 0
2283 return sub
2284 nil
2285```
2286<YueDisplay>
2287<pre>
2288findFirstEven = (list) ->
2289 for item in *list
2290 if type(item) == "table"
2291 for sub in *item
2292 if sub % 2 == 0
2293 return sub
2294 nil
2295</pre>
2296</YueDisplay>
2297
2298The 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.
2299
2300### Named Varargs
2301
2302You 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).
2303
2304```moonscript
2305f = (...t) ->
2306 print "argument count:", t.n
2307 print "table length:", #t
2308 for i = 1, t.n
2309 print t[i]
2310
2311f 1, 2, 3
2312f "a", "b", "c", "d"
2313f!
2314
2315-- Handling cases with nil values
2316process = (...args) ->
2317 sum = 0
2318 for i = 1, args.n
2319 if args[i] != nil and type(args[i]) == "number"
2320 sum += args[i]
2321 sum
2322
2323process 1, nil, 3, nil, 5
2324```
2325<YueDisplay>
2326<pre>
2327f = (...t) ->
2328 print "argument count:", t.n
2329 print "table length:", #t
2330 for i = 1, t.n
2331 print t[i]
2332
2333f 1, 2, 3
2334f "a", "b", "c", "d"
2335f!
2336
2337-- Handling cases with nil values
2338process = (...args) ->
2339 sum = 0
2340 for i = 1, args.n
2341 if args[i] != nil and type(args[i]) == "number"
2342 sum += args[i]
2343 sum
2344
2345process 1, nil, 3, nil, 5
2346</pre>
2347</YueDisplay>
2348
1864## Backcalls 2349## Backcalls
1865 2350
1866Backcalls are used for unnesting callbacks. They are defined using arrows pointed to the left as the last parameter by default filling in a function call. All the syntax is mostly the same as regular arrow functions except that it is just pointing the other way and the function body does not require indent. 2351Backcalls are used for unnesting callbacks. They are defined using arrows pointed to the left as the last parameter by default filling in a function call. All the syntax is mostly the same as regular arrow functions except that it is just pointing the other way and the function body does not require indent.
@@ -1902,22 +2387,22 @@ x * 2
1902</pre> 2387</pre>
1903</YueDisplay> 2388</YueDisplay>
1904 2389
1905If you wish to have further code after your backcalls, you can set them aside with a do statement. 2390If you wish to have further code after your backcalls, you can set them aside with a do statement. And the parentheses can be omitted with non-fat arrow functions.
1906 2391
1907```moonscript 2392```moonscript
1908result, msg = do 2393result, msg = do
1909 (data) <- readAsync "filename.txt" 2394 data <- readAsync "filename.txt"
1910 print data 2395 print data
1911 (info) <- processAsync data 2396 info <- processAsync data
1912 check info 2397 check info
1913print result, msg 2398print result, msg
1914``` 2399```
1915<YueDisplay> 2400<YueDisplay>
1916<pre> 2401<pre>
1917result, msg = do 2402result, msg = do
1918 (data) <- readAsync "filename.txt" 2403 data <- readAsync "filename.txt"
1919 print data 2404 print data
1920 (info) <- processAsync data 2405 info <- processAsync data
1921 check info 2406 check info
1922print result, msg 2407print result, msg
1923</pre> 2408</pre>
@@ -2115,6 +2600,27 @@ doubled = [item * 2 for item in *items]
2115</pre> 2600</pre>
2116</YueDisplay> 2601</YueDisplay>
2117 2602
2603In list comprehensions, you can also use the spread operator `...` to flatten nested lists, achieving a flat map effect:
2604
2605```moonscript
2606data =
2607 a: [1, 2, 3]
2608 b: [4, 5, 6]
2609
2610flat = [...v for k,v in pairs data]
2611-- flat is now [1, 2, 3, 4, 5, 6]
2612```
2613<YueDisplay>
2614<pre>
2615data =
2616 a: [1, 2, 3]
2617 b: [4, 5, 6]
2618
2619flat = [...v for k,v in pairs data]
2620-- flat is now [1, 2, 3, 4, 5, 6]
2621</pre>
2622</YueDisplay>
2623
2118The for and when clauses can be chained as much as desired. The only requirement is that a comprehension has at least one for clause. 2624The for and when clauses can be chained as much as desired. The only requirement is that a comprehension has at least one for clause.
2119 2625
2120Using multiple for clauses is the same as using nested loops: 2626Using multiple for clauses is the same as using nested loops:
@@ -2248,6 +2754,45 @@ slice = [item for item in *items[,,2]]
2248</pre> 2754</pre>
2249</YueDisplay> 2755</YueDisplay>
2250 2756
2757Both the minimum and maximum bounds can be negative, which means that the bounds are counted from the end of the table.
2758
2759```moonscript
2760-- take the last 4 items
2761slice = [item for item in *items[-4,-1]]
2762```
2763<YueDisplay>
2764<pre>
2765-- take the last 4 items
2766slice = [item for item in *items[-4,-1]]
2767</pre>
2768</YueDisplay>
2769
2770The step size can also be negative, which means that the items are taken in reverse order.
2771
2772```moonscript
2773reverse_slice = [item for item in *items[-1,1,-1]]
2774```
2775<YueDisplay>
2776<pre>
2777reverse_slice = [item for item in *items[-1,1,-1]]
2778</pre>
2779</YueDisplay>
2780
2781#### Slicing Expression
2782
2783Slicing can also be used as an expression. This is useful for getting a sub-list of a table.
2784
2785```moonscript
2786-- take the 2nd and 4th items as a new list
2787sub_list = items[2, 4]
2788```
2789<YueDisplay>
2790<pre>
2791-- take the 2nd and 4th items as a new list
2792sub_list = items[2, 4]
2793</pre>
2794</YueDisplay>
2795
2251## For Loop 2796## For Loop
2252 2797
2253There are two for loop forms, just like in Lua. A numeric one and a generic one: 2798There are two for loop forms, just like in Lua. A numeric one and a generic one:
@@ -2324,6 +2869,23 @@ doubled_evens = for i = 1, 20
2324</pre> 2869</pre>
2325</YueDisplay> 2870</YueDisplay>
2326 2871
2872In addition, for loops support break with a return value, allowing the loop itself to be used as an expression that exits early with a meaningful result.
2873
2874For example, to find the first number greater than 10:
2875
2876```moonscript
2877first_large = for n in *numbers
2878 break n if n > 10
2879```
2880<YueDisplay>
2881<pre>
2882first_large = for n in *numbers
2883 break n if n > 10
2884</pre>
2885</YueDisplay>
2886
2887This break-with-value syntax enables concise and expressive search or early-exit patterns directly within loop expressions.
2888
2327You can also filter values by combining the for loop expression with the continue statement. 2889You can also filter values by combining the for loop expression with the continue statement.
2328 2890
2329For loops at the end of a function body are not accumulated into a table for a return value (Instead the function will return nil). Either an explicit return statement can be used, or the loop can be converted into a list comprehension. 2891For loops at the end of a function body are not accumulated into a table for a return value (Instead the function will return nil). Either an explicit return statement can be used, or the loop can be converted into a list comprehension.
@@ -2345,7 +2907,7 @@ print func_b! -- prints table object
2345</pre> 2907</pre>
2346</YueDisplay> 2908</YueDisplay>
2347 2909
2348This is done to avoid the needless creation of tables for functions that don’t need to return the results of the loop. 2910This is done to avoid the needless creation of tables for functions that don't need to return the results of the loop.
2349 2911
2350## Repeat Loop 2912## Repeat Loop
2351 2913
@@ -2624,28 +3186,26 @@ reader\parse_line! until reader\eof!
2624 3186
2625## Switch 3187## Switch
2626 3188
2627The switch statement is shorthand for writing a series of if statements that check against the same value. Note that the value is only evaluated once. Like if statements, switches can have an else block to handle no matches. Comparison is done with the == operator. 3189The switch statement is shorthand for writing a series of if statements that check against the same value. Note that the value is only evaluated once. Like if statements, switches can have an else block to handle no matches. Comparison is done with the == operator. In switch statement, you can also use assignment expression to store temporary variable value.
2628 3190
2629```moonscript 3191```moonscript
2630name = "Dan" 3192switch name := "Dan"
2631switch name
2632 when "Robert" 3193 when "Robert"
2633 print "You are Robert" 3194 print "You are Robert"
2634 when "Dan", "Daniel" 3195 when "Dan", "Daniel"
2635 print "Your name, it's Dan" 3196 print "Your name, it's Dan"
2636 else 3197 else
2637 print "I don't know about your name" 3198 print "I don't know about you with name #{name}"
2638``` 3199```
2639<YueDisplay> 3200<YueDisplay>
2640<pre> 3201<pre>
2641name = "Dan" 3202switch name := "Dan"
2642switch name
2643 when "Robert" 3203 when "Robert"
2644 print "You are Robert" 3204 print "You are Robert"
2645 when "Dan", "Daniel" 3205 when "Dan", "Daniel"
2646 print "Your name, it's Dan" 3206 print "Your name, it's Dan"
2647 else 3207 else
2648 print "I don't know about your name" 3208 print "I don't know about you with name #{name}"
2649</pre> 3209</pre>
2650</YueDisplay> 3210</YueDisplay>
2651 3211
@@ -2676,7 +3236,7 @@ next_number = switch b
2676</pre> 3236</pre>
2677</YueDisplay> 3237</YueDisplay>
2678 3238
2679We can use the then keyword to write a switch’s when block on a single line. No extra keyword is needed to write the else block on a single line. 3239We can use the then keyword to write a switch's when block on a single line. No extra keyword is needed to write the else block on a single line.
2680 3240
2681```moonscript 3241```moonscript
2682msg = switch math.random(1, 5) 3242msg = switch math.random(1, 5)
@@ -2722,7 +3282,7 @@ else
2722</pre> 3282</pre>
2723</YueDisplay> 3283</YueDisplay>
2724 3284
2725It is worth noting the order of the case comparison expression. The case’s expression is on the left hand side. This can be useful if the case’s expression wants to overwrite how the comparison is done by defining an eq metamethod. 3285It is worth noting the order of the case comparison expression. The case's expression is on the left hand side. This can be useful if the case's expression wants to overwrite how the comparison is done by defining an eq metamethod.
2726 3286
2727### Table Matching 3287### Table Matching
2728 3288
@@ -2782,6 +3342,123 @@ switch item
2782</pre> 3342</pre>
2783</YueDisplay> 3343</YueDisplay>
2784 3344
3345You can also match against array elements, table fields, and even nested structures with array or table literals.
3346
3347Match against array elements.
3348
3349```moonscript
3350switch tb
3351 when [1, 2, 3]
3352 print "1, 2, 3"
3353 when [1, b, 3]
3354 print "1, #{b}, 3"
3355 when [1, 2, b = 3] -- b has a default value
3356 print "1, 2, #{b}"
3357```
3358<YueDisplay>
3359<pre>
3360switch tb
3361 when [1, 2, 3]
3362 print "1, 2, 3"
3363 when [1, b, 3]
3364 print "1, #{b}, 3"
3365 when [1, 2, b = 3] -- b has a default value
3366 print "1, 2, #{b}"
3367</pre>
3368</YueDisplay>
3369
3370Match against table fields with destructuring.
3371
3372```moonscript
3373switch tb
3374 when success: true, :result
3375 print "success", result
3376 when success: false
3377 print "failed", result
3378 else
3379 print "invalid"
3380```
3381<YueDisplay>
3382<pre>
3383switch tb
3384 when success: true, :result
3385 print "success", result
3386 when success: false
3387 print "failed", result
3388 else
3389 print "invalid"
3390</pre>
3391</YueDisplay>
3392
3393Match against nested table structures.
3394
3395```moonscript
3396switch tb
3397 when data: {type: "success", :content}
3398 print "success", content
3399 when data: {type: "error", :content}
3400 print "failed", content
3401 else
3402 print "invalid"
3403```
3404<YueDisplay>
3405<pre>
3406switch tb
3407 when data: {type: "success", :content}
3408 print "success", content
3409 when data: {type: "error", :content}
3410 print "failed", content
3411 else
3412 print "invalid"
3413</pre>
3414</YueDisplay>
3415
3416Match against array of tables.
3417
3418```moonscript
3419switch tb
3420 when [
3421 {a: 1, b: 2}
3422 {a: 3, b: 4}
3423 {a: 5, b: 6}
3424 fourth
3425 ]
3426 print "matched", fourth
3427```
3428<YueDisplay>
3429<pre>
3430switch tb
3431 when [
3432 {a: 1, b: 2}
3433 {a: 3, b: 4}
3434 {a: 5, b: 6}
3435 fourth
3436 ]
3437 print "matched", fourth
3438</pre>
3439</YueDisplay>
3440
3441Match against a list and capture a range of elements.
3442
3443```moonscript
3444segments = ["admin", "users", "logs", "view"]
3445switch segments
3446 when [...groups, resource, action]
3447 print "Group:", groups -- prints: {"admin", "users"}
3448 print "Resource:", resource -- prints: "logs"
3449 print "Action:", action -- prints: "view"
3450```
3451<YueDisplay>
3452<pre>
3453segments = ["admin", "users", "logs", "view"]
3454switch segments
3455 when [...groups, resource, action]
3456 print "Group:", groups -- prints: {"admin", "users"}
3457 print "Resource:", resource -- prints: "logs"
3458 print "Action:", action -- prints: "view"
3459</pre>
3460</YueDisplay>
3461
2785## Object Oriented Programming 3462## Object Oriented Programming
2786 3463
2787In these examples, the generated Lua code may appear overwhelming. It is best to focus on the meaning of the YueScript code at first, then look into the Lua code if you wish to know the implementation details. 3464In these examples, the generated Lua code may appear overwhelming. It is best to focus on the meaning of the YueScript code at first, then look into the Lua code if you wish to know the implementation details.
@@ -2913,7 +3590,7 @@ class BackPack extends Inventory
2913 3590
2914Here we extend our Inventory class, and limit the amount of items it can carry. 3591Here we extend our Inventory class, and limit the amount of items it can carry.
2915 3592
2916In this example, we don’t define a constructor on the subclass, so the parent class' constructor is called when we make a new instance. If we did define a constructor then we can use the super method to call the parent constructor. 3593In this example, we don't define a constructor on the subclass, so the parent class' constructor is called when we make a new instance. If we did define a constructor then we can use the super method to call the parent constructor.
2917 3594
2918Whenever a class inherits from another, it sends a message to the parent class by calling the method __inherited on the parent class if it exists. The function receives two arguments, the class that is being inherited and the child class. 3595Whenever a class inherits from another, it sends a message to the parent class by calling the method __inherited on the parent class if it exists. The function receives two arguments, the class that is being inherited and the child class.
2919 3596
@@ -3000,13 +3677,13 @@ print BackPack.size -- prints 10
3000 3677
3001The class object is what we create when we use a class statement. The class object is stored in a variable of the same name of the class. 3678The class object is what we create when we use a class statement. The class object is stored in a variable of the same name of the class.
3002 3679
3003The class object can be called like a function in order to create new instances. That’s how we created instances of classes in the examples above. 3680The class object can be called like a function in order to create new instances. That's how we created instances of classes in the examples above.
3004 3681
3005A class is made up of two tables. The class table itself, and the base table. The base is used as the metatable for all the instances. All properties listed in the class declaration are placed in the base. 3682A class is made up of two tables. The class table itself, and the base table. The base is used as the metatable for all the instances. All properties listed in the class declaration are placed in the base.
3006 3683
3007The class object’s metatable reads properties from the base if they don’t exist in the class object. This means we can access functions and properties directly from the class. 3684The class object's metatable reads properties from the base if they don't exist in the class object. This means we can access functions and properties directly from the class.
3008 3685
3009It is important to note that assigning to the class object does not assign into the base, so it’s not a valid way to add new methods to instances. Instead the base must explicitly be changed. See the __base field below. 3686It is important to note that assigning to the class object does not assign into the base, so it's not a valid way to add new methods to instances. Instead the base must explicitly be changed. See the __base field below.
3010 3687
3011The class object has a couple special properties: 3688The class object has a couple special properties:
3012 3689
@@ -3079,7 +3756,7 @@ print Counter.count -- prints 2
3079</pre> 3756</pre>
3080</YueDisplay> 3757</YueDisplay>
3081 3758
3082The calling semantics of @@ are similar to @. Calling a @@ name will pass the class in as the first argument using Lua’s colon syntax. 3759The calling semantics of @@ are similar to @. Calling a @@ name will pass the class in as the first argument using Lua's colon syntax.
3083 3760
3084```moonscript 3761```moonscript
3085@@hello 1,2,3,4 3762@@hello 1,2,3,4
@@ -3094,7 +3771,7 @@ The calling semantics of @@ are similar to @. Calling a @@ name will pass the cl
3094 3771
3095In the body of a class declaration, we can have normal expressions in addition to key/value pairs. In this context, self is equal to the class object. 3772In the body of a class declaration, we can have normal expressions in addition to key/value pairs. In this context, self is equal to the class object.
3096 3773
3097Here is an alternative way to create a class variable compared to what’s described above: 3774Here is an alternative way to create a class variable compared to what's described above:
3098 3775
3099```moonscript 3776```moonscript
3100class Things 3777class Things
@@ -3360,19 +4037,19 @@ In this usage, with can be seen as a special form of the K combinator.
3360The expression in the with statement can also be an assignment, if you want to give a name to the expression. 4037The expression in the with statement can also be an assignment, if you want to give a name to the expression.
3361 4038
3362```moonscript 4039```moonscript
3363with str = "Hello" 4040with str := "Hello"
3364 print "original:", str 4041 print "original:", str
3365 print "upper:", \upper! 4042 print "upper:", \upper!
3366``` 4043```
3367<YueDisplay> 4044<YueDisplay>
3368<pre> 4045<pre>
3369with str = "Hello" 4046with str := "Hello"
3370 print "original:", str 4047 print "original:", str
3371 print "upper:", \upper! 4048 print "upper:", \upper!
3372</pre> 4049</pre>
3373</YueDisplay> 4050</YueDisplay>
3374 4051
3375Accessing special keys with `[]` in a `with` statement. 4052You can access special keys with `[]` in a `with` statement.
3376 4053
3377```moonscript 4054```moonscript
3378with tb 4055with tb
@@ -3395,6 +4072,18 @@ with tb
3395</pre> 4072</pre>
3396</YueDisplay> 4073</YueDisplay>
3397 4074
4075`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.
4076
4077```moonscript
4078with? obj
4079 print obj.name
4080```
4081<YueDisplay>
4082<pre>
4083with? obj
4084 print obj.name
4085</pre>
4086</YueDisplay>
3398 4087
3399## Do 4088## Do
3400 4089
@@ -3415,7 +4104,7 @@ print var -- nil here
3415</pre> 4104</pre>
3416</YueDisplay> 4105</YueDisplay>
3417 4106
3418YueScript’s **do** can also be used an expression . Allowing you to combine multiple lines into one. The result of the do expression is the last statement in its body. 4107YueScript's **do** can also be used an expression . Allowing you to combine multiple lines into one. The result of the do expression is the last statement in its body.
3419 4108
3420```moonscript 4109```moonscript
3421counter = do 4110counter = do
@@ -3541,7 +4230,7 @@ print i -- will print 0
3541</pre> 4230</pre>
3542</YueDisplay> 4231</YueDisplay>
3543 4232
3544In my_func, we've overwritten the value of i mistakenly. In this example it is quite obvious, but consider a large, or foreign code base where it isn’t clear what names have already been declared. 4233In my_func, we've overwritten the value of i mistakenly. In this example it is quite obvious, but consider a large, or foreign code base where it isn't clear what names have already been declared.
3545 4234
3546It would be helpful to say which variables from the enclosing scope we intend on change, in order to prevent us from changing others by accident. 4235It would be helpful to say which variables from the enclosing scope we intend on change, in order to prevent us from changing others by accident.
3547 4236
@@ -3657,9 +4346,9 @@ The YueScript compiling function. It compiles the YueScript code to Lua code.
3657**Signature:** 4346**Signature:**
3658```lua 4347```lua
3659to_lua: function(code: string, config?: Config): 4348to_lua: function(code: string, config?: Config):
3660 --[[codes]] string | nil, 4349 --[[codes]] string | nil,
3661 --[[error]] string | nil, 4350 --[[error]] string | nil,
3662 --[[globals]] {{string, integer, integer}} | nil 4351 --[[globals]] {{string, integer, integer}} | nil
3663``` 4352```
3664 4353
3665**Parameters:** 4354**Parameters:**
@@ -3782,8 +4471,8 @@ Loads YueScript code from a string into a function.
3782**Signature:** 4471**Signature:**
3783```lua 4472```lua
3784loadstring: function(input: string, chunkname: string, env: table, config?: Config): 4473loadstring: function(input: string, chunkname: string, env: table, config?: Config):
3785 --[[loaded function]] nil | function(...: any): (any...), 4474 --[[loaded function]] nil | function(...: any): (any...),
3786 --[[error]] string | nil 4475 --[[error]] string | nil
3787``` 4476```
3788 4477
3789**Parameters:** 4478**Parameters:**
@@ -3813,8 +4502,8 @@ Loads YueScript code from a string into a function.
3813**Signature:** 4502**Signature:**
3814```lua 4503```lua
3815loadstring: function(input: string, chunkname: string, config?: Config): 4504loadstring: function(input: string, chunkname: string, config?: Config):
3816 --[[loaded function]] nil | function(...: any): (any...), 4505 --[[loaded function]] nil | function(...: any): (any...),
3817 --[[error]] string | nil 4506 --[[error]] string | nil
3818``` 4507```
3819 4508
3820**Parameters:** 4509**Parameters:**
@@ -3843,8 +4532,8 @@ Loads YueScript code from a string into a function.
3843**Signature:** 4532**Signature:**
3844```lua 4533```lua
3845loadstring: function(input: string, config?: Config): 4534loadstring: function(input: string, config?: Config):
3846 --[[loaded function]] nil | function(...: any): (any...), 4535 --[[loaded function]] nil | function(...: any): (any...),
3847 --[[error]] string | nil 4536 --[[error]] string | nil
3848``` 4537```
3849 4538
3850**Parameters:** 4539**Parameters:**
@@ -3872,8 +4561,8 @@ Loads YueScript code from a file into a function.
3872**Signature:** 4561**Signature:**
3873```lua 4562```lua
3874loadfile: function(filename: string, env: table, config?: Config): 4563loadfile: function(filename: string, env: table, config?: Config):
3875 nil | function(...: any): (any...), 4564 nil | function(...: any): (any...),
3876 string | nil 4565 string | nil
3877``` 4566```
3878 4567
3879**Parameters:** 4568**Parameters:**
@@ -3902,8 +4591,8 @@ Loads YueScript code from a file into a function.
3902**Signature:** 4591**Signature:**
3903```lua 4592```lua
3904loadfile: function(filename: string, config?: Config): 4593loadfile: function(filename: string, config?: Config):
3905 nil | function(...: any): (any...), 4594 nil | function(...: any): (any...),
3906 string | nil 4595 string | nil
3907``` 4596```
3908 4597
3909**Parameters:** 4598**Parameters:**
@@ -4158,9 +4847,9 @@ Converts the code to the AST.
4158 4847
4159**Signature:** 4848**Signature:**
4160```lua 4849```lua
4161to_ast: function(code: string, flattenLevel?: number, astName?: string): 4850to_ast: function(code: string, flattenLevel?: number, astName?: string, reserveComment?: boolean):
4162 --[[AST]] AST | nil, 4851 --[[AST]] AST | nil,
4163 --[[error]] nil | string 4852 --[[error]] nil | string
4164``` 4853```
4165 4854
4166**Parameters:** 4855**Parameters:**
@@ -4170,6 +4859,7 @@ to_ast: function(code: string, flattenLevel?: number, astName?: string):
4170| code | string | The code. | 4859| code | string | The code. |
4171| flattenLevel | integer | [Optional] The flatten level. Higher level means more flattening. Default is 0. Maximum is 2. | 4860| flattenLevel | integer | [Optional] The flatten level. Higher level means more flattening. Default is 0. Maximum is 2. |
4172| astName | string | [Optional] The AST name. Default is "File". | 4861| astName | string | [Optional] The AST name. Default is "File". |
4862| reserveComment | boolean | [Optional] Whether to reserve the original comments. Default is false. |
4173 4863
4174**Returns:** 4864**Returns:**
4175 4865
@@ -4178,6 +4868,33 @@ to_ast: function(code: string, flattenLevel?: number, astName?: string):
4178| AST \| nil | The AST, or nil if the conversion failed. | 4868| AST \| nil | The AST, or nil if the conversion failed. |
4179| string \| nil | The error message, or nil if the conversion succeeded. | 4869| string \| nil | The error message, or nil if the conversion succeeded. |
4180 4870
4871#### format
4872
4873**Type:** Function.
4874
4875**Description:**
4876
4877Formats the YueScript code.
4878
4879**Signature:**
4880```lua
4881format: function(code: string, tabSize?: number, reserveComment?: boolean): string
4882```
4883
4884**Parameters:**
4885
4886| Parameter | Type | Description |
4887| --- | --- | --- |
4888| code | string | The code. |
4889| tabSize | integer | [Optional] The tab size. Default is 4. |
4890| reserveComment | boolean | [Optional] Whether to reserve the original comments. Default is true. |
4891
4892**Returns:**
4893
4894| Return Type | Description |
4895| --- | --- |
4896| string | The formatted code. |
4897
4181#### __call 4898#### __call
4182 4899
4183**Type:** Metamethod. 4900**Type:** Metamethod.
@@ -4249,6 +4966,19 @@ Whether the compiler should reserve the original line number in the compiled cod
4249reserve_line_number: boolean 4966reserve_line_number: boolean
4250``` 4967```
4251 4968
4969#### reserve_comment
4970
4971**Type:** Field.
4972
4973**Description:**
4974
4975Whether the compiler should reserve the original comments in the compiled code.
4976
4977**Signature:**
4978```lua
4979reserve_comment: boolean
4980```
4981
4252#### space_over_tab 4982#### space_over_tab
4253 4983
4254**Type:** Field. 4984**Type:** Field.
@@ -4299,11 +5029,11 @@ The target Lua version enumeration.
4299**Signature:** 5029**Signature:**
4300```lua 5030```lua
4301enum LuaTarget 5031enum LuaTarget
4302 "5.1" 5032 "5.1"
4303 "5.2" 5033 "5.2"
4304 "5.3" 5034 "5.3"
4305 "5.4" 5035 "5.4"
4306 "5.5" 5036 "5.5"
4307end 5037end
4308``` 5038```
4309 5039
@@ -4380,7 +5110,7 @@ simplified: boolean
4380 5110
4381## Licence: MIT 5111## Licence: MIT
4382 5112
4383Copyright (c) 2017-2025 Li Jin \<dragon-fly@qq.com\> 5113Copyright (c) 2017-2026 Li Jin \<dragon-fly@qq.com\>
4384 5114
4385Permission is hereby granted, free of charge, to any person obtaining a copy 5115Permission is hereby granted, free of charge, to any person obtaining a copy
4386of this software and associated documentation files (the "Software"), to deal 5116of 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 754566c..43713fe 100755
--- a/doc/docs/zh/doc/README.md
+++ b/doc/docs/zh/doc/README.md
@@ -9,26 +9,36 @@ 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-- 列表推导
33map = (arr, action) ->
34 [action item for item in *arr]
35
36filter = (arr, cond) ->
37 [item for item in *arr when cond item]
38
39reduce = (arr, init, action): init ->
40 init = action init, item for item in *arr
41
32-- ç®¡é“æ“作符 42-- ç®¡é“æ“作符
33[1, 2, 3] 43[1, 2, 3]
34 |> map (x) -> x * 2 44 |> map (x) -> x * 2
@@ -51,19 +61,29 @@ export 🌛 = "月之脚本"
51<YueDisplay> 61<YueDisplay>
52<pre> 62<pre>
53-- 导入语法 63-- 导入语法
54import "yue" as :p, :to_lua 64import p, to_lua from "yue"
55 65
56-- éšå¼å¯¹è±¡ 66-- éšå¼å¯¹è±¡
57inventory = 67inventory =
58 equipment: 68 equipment:
59 * "sword" 69 - "sword"
60 * "shield" 70 - "shield"
61 items: 71 items:
62 * name: "potion" 72 - name: "potion"
63 count: 10 73 count: 10
64 * name: "bread" 74 - name: "bread"
65 count: 3 75 count: 3
66 76
77-- 列表推导
78map = (arr, action) ->
79 [action item for item in *arr]
80
81filter = (arr, cond) ->
82 [item for item in *arr when cond item]
83
84reduce = (arr, init, action): init ->
85 init = action init, item for item in *arr
86
67-- ç®¡é“æ“作符 87-- ç®¡é“æ“作符
68[1, 2, 3] 88[1, 2, 3]
69 |> map (x) -> x * 2 89 |> map (x) -> x * 2
@@ -89,7 +109,7 @@ export 🌛 = "月之脚本"
89 109
90* **Lua 模å—** 110* **Lua 模å—**
91 111
92&emsp;安装 [luarocks](https://luarocks.org),一个Lua模å—的包管ç†å™¨ã€‚ç„¶åŽä½œä¸ºLua模å—å’Œå¯æ‰§è¡Œæ–‡ä»¶å®‰è£…它: 112&emsp;安装 [luarocks](https://luarocks.org),一个 Lua 模å—的包管ç†å™¨ã€‚ç„¶åŽä½œä¸º Lua 模å—å’Œå¯æ‰§è¡Œæ–‡ä»¶å®‰è£…它:
93 113
94``` 114```
95> luarocks install yuescript 115> luarocks install yuescript
@@ -122,7 +142,7 @@ export 🌛 = "月之脚本"
122 142
123* **下载预编译的二进制程åº** 143* **下载预编译的二进制程åº**
124 144
125&emsp;您å¯ä»¥ä¸‹è½½é¢„编译的二进制程åºï¼ŒåŒ…括兼容ä¸åŒ Lua ç‰ˆæœ¬çš„äºŒè¿›åˆ¶å¯æ‰§è¡Œæ–‡ä»¶å’Œåº“文件。 145&emsp;ä½ å¯ä»¥ä¸‹è½½é¢„编译的二进制程åºï¼ŒåŒ…括兼容ä¸åŒ Lua ç‰ˆæœ¬çš„äºŒè¿›åˆ¶å¯æ‰§è¡Œæ–‡ä»¶å’Œåº“文件。
126 146
127&emsp;在[这里](https://github.com/IppClub/YueScript/releases)下载预编译的二进制程åºã€‚ 147&emsp;在[这里](https://github.com/IppClub/YueScript/releases)下载预编译的二进制程åºã€‚
128 148
@@ -130,16 +150,16 @@ export 🌛 = "月之脚本"
130 150
131### Lua æ¨¡å— 151### Lua 模å—
132 152
133在Lua中使用月之脚本模å—: 153在 Lua 中使用月之脚本模å—:
134 154
135* **用法 1** 155* **用法 1**
136在Lua中引入 "ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶.yue"。 156在 Lua 中引入 "ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶.yue"。
137```Lua 157```Lua
138require("yue")("ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶") 158require("yue")("ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶")
139``` 159```
140当你在åŒä¸€è·¯å¾„下把 "ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶.yue" 编译æˆäº† "ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶.lua" 时,ä»ç„¶å¯ä»¥ä½¿ç”¨è¿™ä¸ªä»£ç åŠ è½½ .lua ä»£ç æ–‡ä»¶ã€‚在其余的月之脚本文件中,åªéœ€æ­£å¸¸ä½¿ç”¨ **require** 或 **import**进行脚本引用å³å¯ã€‚错误消æ¯ä¸­çš„代ç è¡Œå·ä¹Ÿä¼šè¢«æ­£ç¡®å¤„ç†ã€‚ 160当你在åŒä¸€è·¯å¾„下把 "ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶.yue" 编译æˆäº† "ä½ çš„è„šæœ¬å…¥å£æ–‡ä»¶.lua" 时,ä»ç„¶å¯ä»¥ä½¿ç”¨è¿™ä¸ªä»£ç åŠ è½½ .lua ä»£ç æ–‡ä»¶ã€‚在其余的月之脚本文件中,åªéœ€æ­£å¸¸ä½¿ç”¨ **require** 或 **import** 进行脚本引用å³å¯ã€‚错误消æ¯ä¸­çš„代ç è¡Œå·ä¹Ÿä¼šè¢«æ­£ç¡®å¤„ç†ã€‚
141 161
142* **用法 2** 162* **用法 2**
143手动引入月之脚本模å—å¹¶é‡å†™é”™è¯¯æ¶ˆæ¯æ¥å¸®åŠ©è°ƒè¯•ã€‚ 163手动引入月之脚本模å—å¹¶é‡å†™é”™è¯¯æ¶ˆæ¯æ¥å¸®åŠ©è°ƒè¯•ã€‚
144```lua 164```lua
145local yue = require("yue") 165local yue = require("yue")
@@ -151,8 +171,8 @@ end, function(err)
151end) 171end)
152``` 172```
153 173
154* **用法 3** 174* **用法 3**
155在Lua中使用月之脚本编译器功能。 175在 Lua 中使用月之脚本编译器功能。
156```lua 176```lua
157local yue = require("yue") 177local yue = require("yue")
158local codes, err, globals = yue.to_lua([[ 178local codes, err, globals = yue.to_lua([[
@@ -333,7 +353,7 @@ end
333 353
334### å¯¼å‡ºå® 354### 导出å®
335 355
336å®å‡½æ•°å¯ä»¥ä»Žä¸€ä¸ªæ¨¡å—中导出,并在å¦ä¸€ä¸ªæ¨¡å—中导入。您必须将导出的å®å‡½æ•°æ”¾åœ¨ä¸€ä¸ªå•ç‹¬çš„æ–‡ä»¶ä¸­ä½¿ç”¨ï¼Œè€Œä¸”åªæœ‰å®å®šä¹‰ã€å®å¯¼å…¥å’Œå®å±•å¼€å¯ä»¥æ”¾å…¥è¿™ä¸ªå®å¯¼å‡ºæ¨¡å—中。 356å®å‡½æ•°å¯ä»¥ä»Žä¸€ä¸ªæ¨¡å—中导出,并在å¦ä¸€ä¸ªæ¨¡å—中导入。你必须将导出的å®å‡½æ•°æ”¾åœ¨ä¸€ä¸ªå•ç‹¬çš„æ–‡ä»¶ä¸­ä½¿ç”¨ï¼Œè€Œä¸”åªæœ‰å®å®šä¹‰ã€å®å¯¼å…¥å’Œå®å±•å¼€å¯ä»¥æ”¾å…¥è¿™ä¸ªå®å¯¼å‡ºæ¨¡å—中。
337```moonscript 357```moonscript
338-- 文件: utils.yue 358-- 文件: utils.yue
339export macro map = (items, action) -> "[#{action} for _ in *#{items}]" 359export macro map = (items, action) -> "[#{action} for _ in *#{items}]"
@@ -387,16 +407,16 @@ print $LINE -- 获å–当å‰ä»£ç è¡Œæ•°ï¼š2
387 407
388```moonscript 408```moonscript
389macro Enum = (...) -> 409macro Enum = (...) ->
390 items = {...} 410 items = {...}
391 itemSet = {item, true for item in *items} 411 itemSet = {item, true for item in *items}
392 (item) -> 412 (item) ->
393 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]
394 "\"#{item}\"" 414 "\"#{item}\""
395 415
396macro BodyType = $Enum( 416macro BodyType = $Enum(
397 Static 417 Static
398 Dynamic 418 Dynamic
399 Kinematic 419 Kinematic
400) 420)
401 421
402print "有效的枚举类型:", $BodyType Static 422print "有效的枚举类型:", $BodyType Static
@@ -405,16 +425,16 @@ print "有效的枚举类型:", $BodyType Static
405<YueDisplay> 425<YueDisplay>
406<pre> 426<pre>
407macro Enum = (...) -> 427macro Enum = (...) ->
408 items = {...} 428 items = {...}
409 itemSet = {item, true for item in *items} 429 itemSet = {item, true for item in *items}
410 (item) -> 430 (item) ->
411 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]
412 "\"#{item}\"" 432 "\"#{item}\""
413 433
414macro BodyType = $Enum( 434macro BodyType = $Enum(
415 Static 435 Static
416 Dynamic 436 Dynamic
417 Kinematic 437 Kinematic
418) 438)
419 439
420print "有效的枚举类型:", $BodyType Static 440print "有效的枚举类型:", $BodyType Static
@@ -422,9 +442,57 @@ print "有效的枚举类型:", $BodyType Static
422</pre> 442</pre>
423</YueDisplay> 443</YueDisplay>
424 444
445### å®å‚数检查
446
447å¯ä»¥ç›´æŽ¥åœ¨å‚数列表中声明期望的 AST 节点类型,并在编译时检查传入的å®å‚数是å¦ç¬¦åˆé¢„期。
448
449```moonscript
450macro printNumAndStr = (num `Num, str `String) -> |
451 print(
452 #{num}
453 #{str}
454 )
455
456$printNumAndStr 123, "hello"
457```
458<YueDisplay>
459<pre>
460macro printNumAndStr = (num `Num, str `String) -> |
461 print(
462 #{num}
463 #{str}
464 )
465
466$printNumAndStr 123, "hello"
467</pre>
468</YueDisplay>
469
470如果需è¦åšæ›´åŠ çµæ´»çš„傿•°æ£€æŸ¥æ“作,å¯ä»¥ä½¿ç”¨å†…置的 `$is_ast` å®å‡½æ•°åœ¨åˆé€‚çš„ä½ç½®è¿›è¡Œæ‰‹åŠ¨æ£€æŸ¥ã€‚
471
472```moonscript
473macro printNumAndStr = (num, str) ->
474 error "expected Num as first argument" unless $is_ast Num, num
475 error "expected String as second argument" unless $is_ast String, str
476 "print(#{num}, #{str})"
477
478$printNumAndStr 123, "hello"
479```
480<YueDisplay>
481<pre>
482macro printNumAndStr = (num, str) ->
483 error "expected Num as first argument" unless $is_ast Num, num
484 error "expected String as second argument" unless $is_ast String, str
485 "print(#{num}, #{str})"
486
487$printNumAndStr 123, "hello"
488</pre>
489</YueDisplay>
490
491更多关于å¯ç”¨ AST 节点的详细信æ¯ï¼Œè¯·å‚考 [yue_parser.cpp](https://github.com/IppClub/YueScript/blob/main/src/yuescript/yue_parser.cpp) 中大写的规则定义。
492
425## æ“作符 493## æ“作符
426 494
427Lua的所有二元和一元æ“作符在月之脚本中都是å¯ç”¨çš„。此外,**!=** ç¬¦å·æ˜¯ **~=** 的别å,而 **\\** 或 **::** å‡å¯ç”¨äºŽç¼–写链å¼å‡½æ•°è°ƒç”¨ï¼Œå¦‚写作 `tb\func!` 或 `tb::func!`。此外月之脚本还æä¾›äº†ä¸€äº›å…¶ä»–特殊的æ“作符,以编写更具表达力的代ç ã€‚ 495Lua 的所有二元和一元æ“作符在月之脚本中都是å¯ç”¨çš„。此外,**!=** ç¬¦å·æ˜¯ **~=** 的别å,而 **\\** 或 **::** å‡å¯ç”¨äºŽç¼–写链å¼å‡½æ•°è°ƒç”¨ï¼Œå¦‚写作 `tb\func!` 或 `tb::func!`。此外月之脚本还æä¾›äº†ä¸€äº›å…¶ä»–特殊的æ“作符,以编写更具表达力的代ç ã€‚
428 496
429```moonscript 497```moonscript
430tb\func! if tb ~= nil 498tb\func! if tb ~= nil
@@ -439,7 +507,7 @@ tb::func! if tb != nil
439 507
440### 链弿¯”较 508### 链弿¯”较
441 509
442您å¯ä»¥åœ¨æœˆä¹‹è„šæœ¬ä¸­è¿›è¡Œæ¯”è¾ƒè¡¨è¾¾å¼çš„链å¼ä¹¦å†™ï¼š 510ä½ å¯ä»¥åœ¨æœˆä¹‹è„šæœ¬ä¸­è¿›è¡Œæ¯”è¾ƒè¡¨è¾¾å¼çš„链å¼ä¹¦å†™ï¼š
443 511
444```moonscript 512```moonscript
445print 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5 513print 1 < 2 <= 2 < 3 == 3 > 2 >= 1 == 1 < 3 != 5
@@ -464,56 +532,56 @@ print 1 <= a <= 10
464 532
465```moonscript 533```moonscript
466v = (x) -> 534v = (x) ->
467 print x 535 print x
468 x 536 x
469 537
470print v(1) < v(2) <= v(3) 538print v(1) < v(2) <= v(3)
471--[[ 539--[[
472 输出: 540 输出:
473 2 541 2
474 1 542 1
475 3 543 3
476 true 544 true
477]] 545]]
478 546
479print v(1) > v(2) <= v(3) 547print v(1) > v(2) <= v(3)
480--[[ 548--[[
481 输出: 549 输出:
482 2 550 2
483 1 551 1
484 false 552 false
485]] 553]]
486``` 554```
487<YueDisplay> 555<YueDisplay>
488<pre> 556<pre>
489v = (x) -> 557v = (x) ->
490 print x 558 print x
491 x 559 x
492 560
493print v(1) < v(2) <= v(3) 561print v(1) < v(2) <= v(3)
494--[[ 562--[[
495 输出: 563 输出:
496 2 564 2
497 1 565 1
498 3 566 3
499 true 567 true
500]] 568]]
501 569
502print v(1) > v(2) <= v(3) 570print v(1) > v(2) <= v(3)
503--[[ 571--[[
504 输出: 572 输出:
505 2 573 2
506 1 574 1
507 false 575 false
508]] 576]]
509</pre> 577</pre>
510</YueDisplay> 578</YueDisplay>
511 579
512在上é¢çš„例å­é‡Œï¼Œä¸­é—´çš„表达å¼`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` è¿ç®—符æ¥åšè¿žæŽ¥ã€‚
513 581
514### 表追加 582### 表追加
515 583
516**[] =** æ“作符用于å‘Luaè¡¨çš„æœ€åŽæ’入值。 584**[] =** æ“ä½œç¬¦ç”¨äºŽå‘ Lua è¡¨çš„æœ€åŽæ’入值。
517 585
518```moonscript 586```moonscript
519tab = [] 587tab = []
@@ -526,19 +594,36 @@ tab[] = "Value"
526</pre> 594</pre>
527</YueDisplay> 595</YueDisplay>
528 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
529### 表扩展 614### 表扩展
530 615
531您å¯ä»¥ä½¿ç”¨å‰ç½® `...` æ“作符在Lua表中æ’入数组表或哈希表。 616ä½ å¯ä»¥ä½¿ç”¨å‰ç½® `...` æ“作符在 Lua 表中æ’入数组表或哈希表。
532 617
533```moonscript 618```moonscript
534parts = 619parts =
535 * "shoulders" 620 * "shoulders"
536 * "knees" 621 * "knees"
537lyrics = 622lyrics =
538 * "head" 623 * "head"
539 * ...parts 624 * ...parts
540 * "and" 625 * "and"
541 * "toes" 626 * "toes"
542 627
543copy = {...other} 628copy = {...other}
544 629
@@ -549,13 +634,13 @@ merge = {...a, ...b}
549<YueDisplay> 634<YueDisplay>
550<pre> 635<pre>
551parts = 636parts =
552 * "shoulders" 637 * "shoulders"
553 * "knees" 638 * "knees"
554lyrics = 639lyrics =
555 * "head" 640 * "head"
556 * ...parts 641 * ...parts
557 * "and" 642 * "and"
558 * "toes" 643 * "toes"
559 644
560copy = {...other} 645copy = {...other}
561 646
@@ -565,12 +650,29 @@ merge = {...a, ...b}
565</pre> 650</pre>
566</YueDisplay> 651</YueDisplay>
567 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
568### 元表 670### 元表
569 671
570**<>** æ“ä½œç¬¦å¯æä¾›å…ƒè¡¨æ“ä½œçš„å¿«æ·æ–¹å¼ã€‚ 672**<>** æ“ä½œç¬¦å¯æä¾›å…ƒè¡¨æ“ä½œçš„å¿«æ·æ–¹å¼ã€‚
571 673
572* **元表创建** 674* **元表创建**
573ä½¿ç”¨ç©ºæ‹¬å· **<>** 或被 **<>** 包围的元方法键创建普通的Lua表。 675ä½¿ç”¨ç©ºæ‹¬å· **<>** 或被 **<>** 包围的元方法键创建普通的 Lua 表。
574 676
575```moonscript 677```moonscript
576mt = {} 678mt = {}
@@ -605,7 +707,7 @@ close _ = &lt;close&gt;: -> print "超出范围"
605</pre> 707</pre>
606</YueDisplay> 708</YueDisplay>
607 709
608* **元表访问** 710* **元表访问**
609使用 **<>** 或被 **<>** åŒ…å›´çš„å…ƒæ–¹æ³•åæˆ–在 **<>** 中编写æŸäº›è¡¨è¾¾å¼æ¥è®¿é—®å…ƒè¡¨ã€‚ 711使用 **<>** 或被 **<>** åŒ…å›´çš„å…ƒæ–¹æ³•åæˆ–在 **<>** 中编写æŸäº›è¡¨è¾¾å¼æ¥è®¿é—®å…ƒè¡¨ã€‚
610 712
611```moonscript 713```moonscript
@@ -629,7 +731,7 @@ print tb.item
629</pre> 731</pre>
630</YueDisplay> 732</YueDisplay>
631 733
632* **元表解构** 734* **元表解构**
633使用被 **<>** 包围的元方法键解构元表。 735使用被 **<>** 包围的元方法键解构元表。
634 736
635```moonscript 737```moonscript
@@ -680,7 +782,7 @@ with? io.open "test.txt", "w"
680 782
681### ç®¡é“ 783### 管é“
682 784
683与其使用一系列嵌套的函数调用,您还å¯ä»¥è€ƒè™‘使用è¿ç®—符 **|>** æ¥ä¼ é€’值。 785与其使用一系列嵌套的函数调用,你还å¯ä»¥è€ƒè™‘使用è¿ç®—符 **|>** æ¥ä¼ é€’值。
684 786
685```moonscript 787```moonscript
686"你好" |> print 788"你好" |> print
@@ -712,7 +814,7 @@ readFile "example.txt"
712 814
713### 空值åˆå¹¶ 815### 空值åˆå¹¶
714 816
715如果其左æ“ä½œæ•°ä¸æ˜¯**nil**,则nilåˆå¹¶è¿ç®—符 **??** 返回其左æ“作数的值;å¦åˆ™ï¼Œå®ƒå°†è®¡ç®—峿“作数并返回其结果。如果左æ“作数计算结果为éžnil的值,**??** è¿ç®—符将ä¸å†è®¡ç®—其峿“作数。 817如果其左æ“ä½œæ•°ä¸æ˜¯ **nil**,则nilåˆå¹¶è¿ç®—符 **??** 返回其左æ“作数的值;å¦åˆ™ï¼Œå®ƒå°†è®¡ç®—峿“作数并返回其结果。如果左æ“ä½œæ•°è®¡ç®—ç»“æžœä¸ºéž nil 的值,**??** è¿ç®—符将ä¸å†è®¡ç®—其峿“作数。
716```moonscript 818```moonscript
717local a, b, c, d 819local a, b, c, d
718a = b ?? c ?? d 820a = b ?? c ?? d
@@ -731,67 +833,87 @@ a ??= false
731 833
732### éšå¼å¯¹è±¡ 834### éšå¼å¯¹è±¡
733 835
734您å¯ä»¥åœ¨è¡¨æ ¼å—å†…ä½¿ç”¨ç¬¦å· **\*** 开始编写一系列éšå¼ç»“构。如果您正在创建éšå¼å¯¹è±¡ï¼Œå¯¹è±¡çš„字段必须具有相åŒçš„缩进。 836ä½ å¯ä»¥åœ¨è¡¨æ ¼å—å†…ä½¿ç”¨ç¬¦å· **\*** 或是 **-** 开始编写一系列éšå¼ç»“构。如果你正在创建éšå¼å¯¹è±¡ï¼Œå¯¹è±¡çš„字段必须具有相åŒçš„缩进。
837
735```moonscript 838```moonscript
839-- 赋值时使用éšå¼å¯¹è±¡
736list = 840list =
737 * 1 841 * 1
738 * 2 842 * 2
739 * 3 843 * 3
740 844
845-- 函数调用时使用éšå¼å¯¹è±¡
741func 846func
742 * 1 847 * 1
743 * 2 848 * 2
744 * 3 849 * 3
745 850
851-- 返回时使用éšå¼å¯¹è±¡
852f = ->
853 return
854 * 1
855 * 2
856 * 3
857
858-- 表格时使用éšå¼å¯¹è±¡
746tb = 859tb =
747 name: "abc" 860 name: "abc"
748 861
749 values: 862 values:
750 * "a" 863 - "a"
751 * "b" 864 - "b"
752 * "c" 865 - "c"
753 866
754 objects: 867 objects:
755 * name: "a" 868 - name: "a"
756 value: 1 869 value: 1
757 func: => @value + 1 870 func: => @value + 1
758 tb: 871 tb:
759 fieldA: 1 872 fieldA: 1
760 873
761 * name: "b" 874 - name: "b"
762 value: 2 875 value: 2
763 func: => @value + 2 876 func: => @value + 2
764 tb: { } 877 tb: { }
765
766``` 878```
767<YueDisplay> 879<YueDisplay>
768<pre> 880<pre>
881-- 赋值时使用éšå¼å¯¹è±¡
769list = 882list =
770 * 1 883 * 1
771 * 2 884 * 2
772 * 3 885 * 3
773 886
887-- 函数调用时使用éšå¼å¯¹è±¡
774func 888func
775 * 1 889 * 1
776 * 2 890 * 2
777 * 3 891 * 3
778 892
893-- 返回时使用éšå¼å¯¹è±¡
894f = ->
895 return
896 * 1
897 * 2
898 * 3
899
900-- 表格时使用éšå¼å¯¹è±¡
779tb = 901tb =
780 name: "abc" 902 name: "abc"
781 903
782 values: 904 values:
783 * "a" 905 - "a"
784 * "b" 906 - "b"
785 * "c" 907 - "c"
786 908
787 objects: 909 objects:
788 * name: "a" 910 - name: "a"
789 value: 1 911 value: 1
790 func: => @value + 1 912 func: => @value + 1
791 tb: 913 tb:
792 fieldA: 1 914 fieldA: 1
793 915
794 * name: "b" 916 - name: "b"
795 value: 2 917 value: 2
796 func: => @value + 2 918 func: => @value + 2
797 tb: { } 919 tb: { }
@@ -855,11 +977,67 @@ do
855</pre> 977</pre>
856</YueDisplay> 978</YueDisplay>
857 979
980### 导入全局å˜é‡
981
982ä½ å¯ä»¥ä½¿ç”¨ `import` 将指定的全局å˜é‡å¯¼å…¥åˆ°æœ¬åœ°å˜é‡ä¸­ã€‚当导入一系列对全局å˜é‡çš„链å¼è®¿é—®æ—¶ï¼Œæœ€åŽä¸€ä¸ªè®¿é—®çš„字段将被赋值给本地å˜é‡ã€‚
983
984```moonscript
985do
986 import tostring
987 import table.concat
988 print concat ["a", tostring 1]
989```
990<YueDisplay>
991<pre>
992do
993 import tostring
994 import table.concat
995 print concat ["a", tostring 1]
996</pre>
997</YueDisplay>
998
999#### 自动导入
1000
1001在一个代ç å—的顶部写 `import global`,会将当å‰ä½œç”¨åŸŸä¸­å°šæœªæ˜¾å¼å£°æ˜Žæˆ–赋值过的å˜é‡å,自动导入为本地常é‡ï¼Œå¹¶åœ¨è¯¥è¯­å¥çš„ä½ç½®ç»‘定到åŒå的全局å˜é‡ã€‚
1002
1003但是在åŒä¸€ä½œç”¨åŸŸä¸­è¢«æ˜¾å¼å£°æ˜Žä¸ºå…¨å±€çš„å˜é‡ä¸ä¼šè¢«è‡ªåŠ¨å¯¼å…¥ï¼Œå› æ­¤å¯ä»¥ç»§ç»­è¿›è¡Œèµ‹å€¼æ“作。
1004
1005```moonscript
1006do
1007 import global
1008 print "hello"
1009 math.random 3
1010 -- print = nil -- 报错:自动导入的全局å˜é‡ä¸ºå¸¸é‡
1011
1012do
1013 -- 被显å¼å£°æ˜Žä¸ºå…¨å±€çš„å˜é‡ä¸ä¼šè¢«è‡ªåЍ坼入
1014 import global
1015 global FLAG
1016 print FLAG
1017 FLAG = 123
1018```
1019<YueDisplay>
1020<pre>
1021do
1022 import global
1023 print "hello"
1024 math.random 3
1025 -- print = nil -- 报错:自动导入的全局å˜é‡æ˜¯å¸¸é‡
1026
1027do
1028 -- 被显å¼å£°æ˜Žä¸ºå…¨å±€çš„å˜é‡ä¸ä¼šè¢«è‡ªåЍ坼入
1029 import global
1030 global FLAG
1031 print FLAG
1032 FLAG = 123
1033</pre>
1034</YueDisplay>
1035
858### 导出 1036### 导出
859 1037
860å¯¼å‡ºè¯­å¥æä¾›äº†ä¸€ç§ç®€æ´çš„æ–¹å¼æ¥å®šä¹‰å½“å‰çš„æ¨¡å—。 1038å¯¼å‡ºè¯­å¥æä¾›äº†ä¸€ç§ç®€æ´çš„æ–¹å¼æ¥å®šä¹‰å½“å‰çš„æ¨¡å—。
861 1039
862* **命å导出** 1040* **命å导出**
863带命å的导出将定义一个局部å˜é‡ï¼Œå¹¶åœ¨å¯¼å‡ºçš„表中添加一个åŒå的字段。 1041带命å的导出将定义一个局部å˜é‡ï¼Œå¹¶åœ¨å¯¼å‡ºçš„表中添加一个åŒå的字段。
864 1042
865```moonscript 1043```moonscript
@@ -923,7 +1101,7 @@ export["a-b-c"] = 123
923</pre> 1101</pre>
924</YueDisplay> 1102</YueDisplay>
925 1103
926* **未命å导出** 1104* **未命å导出**
927未命å导出会将è¦å¯¼å‡ºçš„目标项目添加到导出表的数组部分。 1105未命å导出会将è¦å¯¼å‡ºçš„目标项目添加到导出表的数组部分。
928 1106
929```moonscript 1107```moonscript
@@ -953,7 +1131,7 @@ export with tmp
953</pre> 1131</pre>
954</YueDisplay> 1132</YueDisplay>
955 1133
956* **默认导出** 1134* **默认导出**
957在导出语å¥ä¸­ä½¿ç”¨ **default** å…³é”®å­—ï¼Œæ¥æ›¿æ¢å¯¼å‡ºçš„表为一个目标的对象。 1135在导出语å¥ä¸­ä½¿ç”¨ **default** å…³é”®å­—ï¼Œæ¥æ›¿æ¢å¯¼å‡ºçš„表为一个目标的对象。
958 1136
959```moonscript 1137```moonscript
@@ -971,7 +1149,7 @@ export default ->
971 1149
972## 赋值 1150## 赋值
973 1151
974月之脚本中定义的å˜é‡æ˜¯åЍæ€ç±»åž‹çš„,并默认为局部å˜é‡ã€‚但你å¯ä»¥é€šè¿‡**local**å’Œ**global**å£°æ˜Žæ¥æ”¹å˜å£°æ˜Žå˜é‡çš„作用范围。 1152月之脚本中定义的å˜é‡æ˜¯åЍæ€ç±»åž‹çš„,并默认为局部å˜é‡ã€‚但你å¯ä»¥é€šè¿‡ **local** å’Œ **global** å£°æ˜Žæ¥æ”¹å˜å£°æ˜Žå˜é‡çš„作用范围。
975 1153
976```moonscript 1154```moonscript
977hello = "world" 1155hello = "world"
@@ -1100,9 +1278,9 @@ do
1100 1278
1101## 解构赋值 1279## 解构赋值
1102 1280
1103解构赋值是一ç§å¿«é€Ÿä»ŽLua表中按å称或基于数组中的ä½ç½®æå–值的方法。 1281解构赋值是一ç§å¿«é€Ÿä»Ž Lua 表中按å称或基于数组中的ä½ç½®æå–值的方法。
1104 1282
1105通常当你看到一个字é¢é‡çš„Lua表,比如{1,2,3},它ä½äºŽèµ‹å€¼çš„å³ä¾§ï¼Œå› ä¸ºå®ƒæ˜¯ä¸€ä¸ªå€¼ã€‚解构赋值语å¥çš„写法就是交æ¢äº†å­—é¢é‡Lua表的角色,并将其放在赋值语å¥çš„左侧。 1283通常当你看到一个字é¢é‡çš„ Lua 表,比如 `{1,2,3}`,它ä½äºŽèµ‹å€¼çš„å³ä¾§ï¼Œå› ä¸ºå®ƒæ˜¯ä¸€ä¸ªå€¼ã€‚解构赋值语å¥çš„写法就是交æ¢äº†å­—é¢é‡ Lua 表的角色,并将其放在赋值语å¥çš„左侧。
1106 1284
1107最好是通过示例æ¥è§£é‡Šã€‚以下是如何从表格中解包å‰ä¸¤ä¸ªå€¼çš„æ–¹æ³•: 1285最好是通过示例æ¥è§£é‡Šã€‚以下是如何从表格中解包å‰ä¸¤ä¸ªå€¼çš„æ–¹æ³•:
1108 1286
@@ -1201,7 +1379,7 @@ print first, second, color
1201</pre> 1379</pre>
1202</YueDisplay> 1380</YueDisplay>
1203 1381
1204有时候我们会需è¦ä»ŽLua表中æå–值并将它们赋给与键åŒå的局部å˜é‡ã€‚为了é¿å…编写é‡å¤ä»£ç ï¼Œæˆ‘们å¯ä»¥ä½¿ç”¨ **:** å‰ç¼€æ“作符: 1382有时候我们会需è¦ä»Ž Lua 表中æå–值并将它们赋给与键åŒå的局部å˜é‡ã€‚为了é¿å…编写é‡å¤ä»£ç ï¼Œæˆ‘们å¯ä»¥ä½¿ç”¨ **:** å‰ç¼€æ“作符:
1205 1383
1206```moonscript 1384```moonscript
1207{:concat, :insert} = table 1385{:concat, :insert} = table
@@ -1223,7 +1401,7 @@ print first, second, color
1223</pre> 1401</pre>
1224</YueDisplay> 1402</YueDisplay>
1225 1403
1226在进行解构时,您å¯ä»¥æŒ‡å®šé»˜è®¤å€¼ï¼Œå¦‚: 1404在进行解构时,你å¯ä»¥æŒ‡å®šé»˜è®¤å€¼ï¼Œå¦‚:
1227 1405
1228```moonscript 1406```moonscript
1229{:name = "nameless", :job = "jobless"} = person 1407{:name = "nameless", :job = "jobless"} = person
@@ -1234,7 +1412,7 @@ print first, second, color
1234</pre> 1412</pre>
1235</YueDisplay> 1413</YueDisplay>
1236 1414
1237在进行列表解构时,您å¯ä»¥ä½¿ç”¨`_`作为å ä½ç¬¦ï¼š 1415在进行列表解构时,你å¯ä»¥ä½¿ç”¨`_`作为å ä½ç¬¦ï¼š
1238 1416
1239```moonscript 1417```moonscript
1240[_, two, _, four] = items 1418[_, two, _, four] = items
@@ -1245,9 +1423,55 @@ print first, second, color
1245</pre> 1423</pre>
1246</YueDisplay> 1424</YueDisplay>
1247 1425
1248### 在其它地方的解构 1426### 范围解构
1249 1427
1250解构也å¯ä»¥å‡ºçŽ°åœ¨å…¶å®ƒéšå¼è¿›è¡Œèµ‹å€¼çš„åœ°æ–¹ã€‚ä¸€ä¸ªä¾‹å­æ˜¯ç”¨åœ¨for循环: 1428ä½ å¯ä»¥ä½¿ç”¨å±•å¼€è¿ç®—符 `...` åœ¨åˆ—è¡¨è§£æž„ä¸­æ¥æ•获一个范围的值到å­åˆ—表中。这在当你想è¦ä»Žåˆ—表的开头和结尾æå–ç‰¹å®šå…ƒç´ ï¼ŒåŒæ—¶æ”¶é›†ä¸­é—´çš„元素时éžå¸¸æœ‰ç”¨ã€‚
1429
1430```moonscript
1431orders = ["first", "second", "third", "fourth", "last"]
1432[first, ...bulk, last] = orders
1433print first -- 打å°: first
1434print bulk -- 打å°: {"second", "third", "fourth"}
1435print last -- 打å°: last
1436```
1437<YueDisplay>
1438<pre>
1439orders = ["first", "second", "third", "fourth", "last"]
1440[first, ...bulk, last] = orders
1441print first -- 打å°: first
1442print bulk -- 打å°: {"second", "third", "fourth"}
1443print last -- 打å°: last
1444</pre>
1445</YueDisplay>
1446
1447展开è¿ç®—符å¯ä»¥ç”¨åœ¨ä¸åŒçš„ä½ç½®æ¥æ•获ä¸åŒçš„范围,并且你å¯ä»¥ä½¿ç”¨ `_` 作为å ä½ç¬¦æ¥è¡¨ç¤ºä½ æƒ³è·³è¿‡å¯¹åº”范围的æ•获:
1448
1449```moonscript
1450-- æ•获第一个元素之åŽçš„æ‰€æœ‰å…ƒç´ 
1451[first, ...rest] = orders
1452
1453-- æ•获最åŽä¸€ä¸ªå…ƒç´ ä¹‹å‰çš„æ‰€æœ‰å…ƒç´ 
1454[...start, last] = orders
1455
1456-- è·³è¿‡ä¸­é—´çš„å…ƒç´ ï¼Œåªæ•获第一个和最åŽä¸€ä¸ªå…ƒç´ 
1457[first, ..._, last] = orders
1458```
1459<YueDisplay>
1460<pre>
1461-- æ•获第一个元素之åŽçš„æ‰€æœ‰å…ƒç´ 
1462[first, ...rest] = orders
1463
1464-- æ•获最åŽä¸€ä¸ªå…ƒç´ ä¹‹å‰çš„æ‰€æœ‰å…ƒç´ 
1465[...start, last] = orders
1466
1467-- è·³è¿‡ä¸­é—´çš„å…ƒç´ ï¼Œåªæ•获第一个和最åŽä¸€ä¸ªå…ƒç´ 
1468[first, ..._, last] = orders
1469</pre>
1470</YueDisplay>
1471
1472### 在其它地方的解构赋值
1473
1474解构赋值也å¯ä»¥å‡ºçŽ°åœ¨å…¶å®ƒéšå¼è¿›è¡Œèµ‹å€¼çš„åœ°æ–¹ã€‚ä¸€ä¸ªä¾‹å­æ˜¯ç”¨åœ¨ for 循环中:
1251 1475
1252```moonscript 1476```moonscript
1253tuples = [ 1477tuples = [
@@ -1270,7 +1494,7 @@ for [left, right] in *tuples
1270</pre> 1494</pre>
1271</YueDisplay> 1495</YueDisplay>
1272 1496
1273æˆ‘ä»¬çŸ¥é“æ•°ç»„表中的æ¯ä¸ªå…ƒç´ éƒ½æ˜¯ä¸€ä¸ªä¸¤é¡¹çš„元组,所以我们å¯ä»¥ç›´æŽ¥åœ¨for语å¥çš„åç§°å­å¥ä¸­ä½¿ç”¨è§£æž„æ¥è§£åŒ…它。 1497æˆ‘ä»¬çŸ¥é“æ•°ç»„表中的æ¯ä¸ªå…ƒç´ éƒ½æ˜¯ä¸€ä¸ªä¸¤é¡¹çš„元组,所以我们å¯ä»¥ç›´æŽ¥åœ¨ for 语å¥çš„åç§°å­å¥ä¸­ä½¿ç”¨è§£æž„æ¥è§£åŒ…它。
1274 1498
1275## If 赋值 1499## If 赋值
1276 1500
@@ -1322,7 +1546,7 @@ print "好的"
1322 1546
1323### While 赋值 1547### While 赋值
1324 1548
1325您å¯ä»¥åœ¨ while å¾ªçŽ¯ä¸­åŒæ ·ä½¿ç”¨èµ‹å€¼æ¥èŽ·å–循环æ¡ä»¶çš„值。 1549ä½ å¯ä»¥åœ¨ while å¾ªçŽ¯ä¸­åŒæ ·ä½¿ç”¨èµ‹å€¼æ¥èŽ·å–循环æ¡ä»¶çš„值。
1326```moonscript 1550```moonscript
1327while byte := stream\read_one! 1551while byte := stream\read_one!
1328 -- 对 byte åšä¸€äº›æ“作 1552 -- 对 byte åšä¸€äº›æ“作
@@ -1338,7 +1562,7 @@ while byte := stream\read_one!
1338 1562
1339## å¯å˜å‚数赋值 1563## å¯å˜å‚数赋值
1340 1564
1341您å¯ä»¥å°†å‡½æ•°è¿”回的结果赋值给一个å¯å˜å‚æ•°ç¬¦å· `...`。然åŽä½¿ç”¨Lua的方å¼è®¿é—®å…¶å†…容。 1565ä½ å¯ä»¥å°†å‡½æ•°è¿”回的结果赋值给一个å¯å˜å‚æ•°ç¬¦å· `...`。然åŽä½¿ç”¨ Lua 的方å¼è®¿é—®å…¶å†…容。
1342```moonscript 1566```moonscript
1343list = [1, 2, 3, 4, 5] 1567list = [1, 2, 3, 4, 5]
1344fn = (ok) -> ok, table.unpack list 1568fn = (ok) -> ok, table.unpack list
@@ -1360,7 +1584,20 @@ print ok, count, first
1360 1584
1361## 空白 1585## 空白
1362 1586
1363æœˆä¹‹è„šæœ¬æ˜¯ä¸€ä¸ªå¯¹ç©ºç™½æ•æ„Ÿçš„语言。您必须在相åŒçš„缩进中使用空格 **' '** 或制表符 **'\t'** æ¥ç¼–写一些代ç å—,如函数体ã€å€¼åˆ—表和一些控制å—。包å«ä¸åŒç©ºç™½çš„表达å¼å¯èƒ½æ„味ç€ä¸åŒçš„事情。制表符被视为4个空格,但最好ä¸è¦æ··åˆä½¿ç”¨ç©ºæ ¼å’Œåˆ¶è¡¨ç¬¦ã€‚ 1587æœˆä¹‹è„šæœ¬æ˜¯ä¸€ä¸ªå¯¹ç©ºç™½æ•æ„Ÿçš„语言。你必须在相åŒçš„缩进中使用空格 **' '** 或制表符 **'\t'** æ¥ç¼–写一些代ç å—,如函数体ã€å€¼åˆ—表和一些控制å—。包å«ä¸åŒç©ºç™½çš„表达å¼å¯èƒ½æ„味ç€ä¸åŒçš„事情。制表符被视为4个空格,但最好ä¸è¦æ··åˆä½¿ç”¨ç©ºæ ¼å’Œåˆ¶è¡¨ç¬¦ã€‚
1588
1589### 语å¥åˆ†éš”符
1590
1591一æ¡è¯­å¥é€šå¸¸ä»¥æ¢è¡Œç»“æŸã€‚你也å¯ä»¥ä½¿ç”¨åˆ†å· `;` 显å¼ç»“æŸä¸€æ¡è¯­å¥ï¼Œä»Žè€Œåœ¨åŒä¸€è¡Œä¸­ç¼–写多æ¡è¯­å¥ï¼š
1592
1593```moonscript
1594a = 1; b = 2; print a + b
1595```
1596<YueDisplay>
1597<pre>
1598a = 1; b = 2; print a + b
1599</pre>
1600</YueDisplay>
1364 1601
1365### 多行链å¼è°ƒç”¨ 1602### 多行链å¼è°ƒç”¨
1366 1603
@@ -1415,7 +1652,7 @@ func --[[端å£]] 3000, --[[ip]] "192.168.1.1"
1415 1652
1416## é”™è¯¯å¤„ç† 1653## 错误处ç†
1417 1654
1418用于统一进行Lua错误处ç†çš„便æ·è¯­æ³•。 1655用于统一进行 Lua 错误处ç†çš„便æ·è¯­æ³•。
1419 1656
1420```moonscript 1657```moonscript
1421try 1658try
@@ -1474,9 +1711,50 @@ catch err
1474</pre> 1711</pre>
1475</YueDisplay> 1712</YueDisplay>
1476 1713
1714### 错误处ç†ç®€åŒ–
1715
1716`try?` 是 `try` 的功能简化语法,它ä¸å†è¿”回 `try` 语å¥çš„布尔状æ€ï¼Œå¹¶åœ¨æˆåŠŸæ—¶ç›´æŽ¥è¿”å›ž `try` 代ç å—的结果,失败时返回 `nil` 值而éžé”™è¯¯å¯¹è±¡ã€‚
1717
1718```moonscript
1719a, b, c = try? func!
1720
1721-- 与空值åˆå¹¶è¿ç®—符一起使用
1722a = (try? func!) ?? "default"
1723
1724-- ä½œä¸ºå‡½æ•°å‚æ•°
1725f try? func!
1726
1727-- 带 catch å—çš„ try!
1728f try?
1729 print 123
1730 func!
1731catch e
1732 print e
1733 e
1734```
1735<YueDisplay>
1736<pre>
1737a, b, c = try? func!
1738
1739-- 与空值åˆå¹¶è¿ç®—符一起使用
1740a = (try? func!) ?? "default"
1741
1742-- ä½œä¸ºå‡½æ•°å‚æ•°
1743f try? func!
1744
1745-- 带 catch å—çš„ try!
1746f try?
1747 print 123
1748 func!
1749catch e
1750 print e
1751 e
1752</pre>
1753</YueDisplay>
1754
1477## 属性 1755## 属性
1478 1756
1479月之脚本现在æä¾›äº†Lua 5.4新增的å«åšå±žæ€§çš„语法支æŒã€‚在月之脚本编译到的Lua目标版本低于5.4时,你ä»ç„¶å¯ä»¥åŒæ—¶ä½¿ç”¨`const`å’Œ`close`çš„å±žæ€§å£°æ˜Žè¯­æ³•ï¼Œå¹¶èŽ·å¾—å¸¸é‡æ£€æŸ¥å’Œä½œç”¨åŸŸå›žè°ƒçš„功能。 1757月之脚本现在æä¾›äº† Lua 5.4 新增的å«åšå±žæ€§çš„语法支æŒã€‚在月之脚本编译到的 Lua 目标版本低于 5.4 时,你ä»ç„¶å¯ä»¥åŒæ—¶ä½¿ç”¨`const` å’Œ `close` çš„å±žæ€§å£°æ˜Žè¯­æ³•ï¼Œå¹¶èŽ·å¾—å¸¸é‡æ£€æŸ¥å’Œä½œç”¨åŸŸå›žè°ƒçš„功能。
1480 1758
1481```moonscript 1759```moonscript
1482const a = 123 1760const a = 123
@@ -1502,11 +1780,24 @@ const {:a, :b, c, d} = tb
1502</pre> 1780</pre>
1503</YueDisplay> 1781</YueDisplay>
1504 1782
1783你也å¯ä»¥å£°æ˜Žå…¨å±€å˜é‡ä¸ºå¸¸é‡ã€‚
1784
1785```moonscript
1786global const Constant = 123
1787-- Constant = 1
1788```
1789<YueDisplay>
1790<pre>
1791global const Constant = 123
1792-- Constant = 1
1793</pre>
1794</YueDisplay>
1795
1505## å­—é¢é‡ 1796## å­—é¢é‡
1506 1797
1507Lua中的所有基本字é¢é‡éƒ½å¯ä»¥åœ¨æœˆä¹‹è„šæœ¬ä¸­ä½¿ç”¨ã€‚åŒ…æ‹¬æ•°å­—ã€å­—符串ã€å¸ƒå°”值和**nil**。 1798Lua 中的所有基本字é¢é‡éƒ½å¯ä»¥åœ¨æœˆä¹‹è„šæœ¬ä¸­ä½¿ç”¨ã€‚åŒ…æ‹¬æ•°å­—ã€å­—符串ã€å¸ƒå°”值和 **nil**。
1508 1799
1509但与Luaä¸åŒçš„æ˜¯ï¼Œå•引å·å’ŒåŒå¼•å·å­—符串内部å…许有æ¢è¡Œï¼š 1800但与 Lua ä¸åŒçš„æ˜¯ï¼Œå•引å·å’ŒåŒå¼•å·å­—符串内部å…许有æ¢è¡Œï¼š
1510 1801
1511```moonscript 1802```moonscript
1512some_string = "这是一个字符串 1803some_string = "这是一个字符串
@@ -1529,17 +1820,78 @@ print "我有#{math.random! * 100}%的把æ¡ã€‚"
1529 1820
1530### æ•°å­—å­—é¢é‡ 1821### æ•°å­—å­—é¢é‡
1531 1822
1532您å¯ä»¥åœ¨æ•°å­—å­—é¢é‡ä¸­ä½¿ç”¨ä¸‹åˆ’线æ¥å¢žåŠ å¯è¯»æ€§ã€‚ 1823ä½ å¯ä»¥åœ¨æ•°å­—å­—é¢é‡ä¸­ä½¿ç”¨ä¸‹åˆ’线æ¥å¢žåŠ å¯è¯»æ€§ã€‚
1533 1824
1534```moonscript 1825```moonscript
1535integer = 1_000_000 1826integer = 1_000_000
1536hex = 0xEF_BB_BF 1827hex = 0xEF_BB_BF
1828binary = 0B10011
1537``` 1829```
1538<YueDisplay> 1830<YueDisplay>
1539 1831
1540<pre> 1832<pre>
1541integer = 1_000_000 1833integer = 1_000_000
1542hex = 0xEF_BB_BF 1834hex = 0xEF_BB_BF
1835binary = 0B10011
1836</pre>
1837</YueDisplay>
1838
1839### YAML 风格字符串
1840
1841使用 `|` å‰ç¼€æ ‡è®°ä¸€ä¸ªå¤šè¡Œ YAML 风格字符串:
1842
1843```moonscript
1844str = |
1845 key: value
1846 list:
1847 - item1
1848 - #{expr}
1849```
1850<YueDisplay>
1851<pre>
1852str = |
1853 key: value
1854 list:
1855 - item1
1856 - #{expr}
1857</pre>
1858</YueDisplay>
1859
1860其效果类似于原生 Lua çš„å¤šè¡Œæ‹¼æŽ¥ï¼Œæ‰€æœ‰æ–‡æœ¬ï¼ˆå«æ¢è¡Œï¼‰å°†è¢«ä¿ç•™ä¸‹æ¥ï¼Œå¹¶æ”¯æŒ `#{...}` 语法,通过 `tostring(expr)` æ’入表达å¼ç»“果。
1861
1862YAML é£Žæ ¼çš„å¤šè¡Œå­—ç¬¦ä¸²ä¼šè‡ªåŠ¨æ£€æµ‹é¦–è¡ŒåŽæœ€å°çš„公共缩进,并从所有行中删除该å‰ç¼€ç©ºç™½å­—符。这让你å¯ä»¥åœ¨ä»£ç ä¸­å¯¹é½æ–‡æœ¬ï¼Œä½†è¾“出字符串ä¸ä¼šå¸¦å¤šä½™ç¼©è¿›ã€‚
1863
1864```moonscript
1865fn = ->
1866 str = |
1867 foo:
1868 bar: baz
1869 return str
1870```
1871<YueDisplay>
1872<pre>
1873fn = ->
1874 str = |
1875 foo:
1876 bar: baz
1877 return str
1878</pre>
1879</YueDisplay>
1880
1881输出字符串中的 foo: 对é½åˆ°è¡Œé¦–,ä¸ä¼šå¸¦æœ‰å‡½æ•°ç¼©è¿›ç©ºæ ¼ã€‚ä¿ç•™å†…部缩进的相对结构,适åˆä¹¦å†™ç»“构化嵌套样å¼çš„内容。
1882
1883支æŒè‡ªåЍ处ç†å­—符中的引å·ã€åæ–œæ ç­‰ç‰¹æ®Šç¬¦å·ï¼Œæ— éœ€æ‰‹åŠ¨è½¬ä¹‰ï¼š
1884
1885```moonscript
1886str = |
1887 path: "C:\Program Files\App"
1888 note: 'He said: "#{Hello}!"'
1889```
1890<YueDisplay>
1891<pre>
1892str = |
1893 path: "C:\Program Files\App"
1894 note: 'He said: "#{Hello}!"'
1543</pre> 1895</pre>
1544</YueDisplay> 1896</YueDisplay>
1545 1897
@@ -1644,7 +1996,7 @@ print "数字的和是", sum 10, 20
1644</pre> 1996</pre>
1645</YueDisplay> 1997</YueDisplay>
1646 1998
1647如果您需è¦åšæ˜¾å¼è¿”回,å¯ä»¥ä½¿ç”¨return关键字: 1999如果你需è¦åšæ˜¾å¼è¿”回,å¯ä»¥ä½¿ç”¨ return 关键字:
1648 2000
1649```moonscript 2001```moonscript
1650sum = (x, y) -> return x + y 2002sum = (x, y) -> return x + y
@@ -1670,7 +2022,7 @@ a, b = mystery 10, 20
1670 2022
1671### 粗箭头 2023### 粗箭头
1672 2024
1673因为在Lua中调用方法时,ç»å¸¸ä¹ æƒ¯å°†å¯¹è±¡ä½œä¸ºç¬¬ä¸€ä¸ªå‚数传入,所以月之脚本æä¾›äº†ä¸€ç§ç‰¹æ®Šçš„语法æ¥åˆ›å»ºè‡ªåŠ¨åŒ…å«self傿•°çš„函数。 2025因为在 Lua 中调用方法时,ç»å¸¸ä¹ æƒ¯å°†å¯¹è±¡ä½œä¸ºç¬¬ä¸€ä¸ªå‚数传入,所以月之脚本æä¾›äº†ä¸€ç§ç‰¹æ®Šçš„语法æ¥åˆ›å»ºè‡ªåŠ¨åŒ…å« self 傿•°çš„函数。
1674 2026
1675```moonscript 2027```moonscript
1676func = (num) => @value + num 2028func = (num) => @value + num
@@ -1683,7 +2035,7 @@ func = (num) => @value + num
1683 2035
1684### 傿•°é»˜è®¤å€¼ 2036### 傿•°é»˜è®¤å€¼
1685 2037
1686å¯ä»¥ä¸ºå‡½æ•°çš„傿•°æä¾›é»˜è®¤å€¼ã€‚å¦‚æžœå‚æ•°çš„值为nilï¼Œåˆ™ç¡®å®šè¯¥å‚æ•°ä¸ºç©ºã€‚任何具有默认值的nil傿•°åœ¨å‡½æ•°ä½“è¿è¡Œä¹‹å‰éƒ½ä¼šè¢«æ›¿æ¢ã€‚ 2038å¯ä»¥ä¸ºå‡½æ•°çš„傿•°æä¾›é»˜è®¤å€¼ã€‚å¦‚æžœå‚æ•°çš„值为 nilï¼Œåˆ™ç¡®å®šè¯¥å‚æ•°ä¸ºç©ºã€‚任何具有默认值的 nil 傿•°åœ¨å‡½æ•°ä½“è¿è¡Œä¹‹å‰éƒ½ä¼šè¢«æ›¿æ¢ã€‚
1687 2039
1688```moonscript 2040```moonscript
1689my_function = (name = "æŸç‰©", height = 100) -> 2041my_function = (name = "æŸç‰©", height = 100) ->
@@ -1755,7 +2107,7 @@ my_func 5, 6, 7,
1755</pre> 2107</pre>
1756</YueDisplay> 2108</YueDisplay>
1757 2109
1758因为Lua表也使用逗å·ä½œä¸ºåˆ†éš”符,这ç§ç¼©è¿›è¯­æ³•有助于让值æˆä¸ºå‚æ•°åˆ—è¡¨çš„ä¸€éƒ¨åˆ†ï¼Œè€Œä¸æ˜¯Lua表的一部分。 2110因为 Lua 表也使用逗å·ä½œä¸ºåˆ†éš”符,这ç§ç¼©è¿›è¯­æ³•有助于让值æˆä¸ºå‚æ•°åˆ—è¡¨çš„ä¸€éƒ¨åˆ†ï¼Œè€Œä¸æ˜¯ Lua 表的一部分。
1759 2111
1760```moonscript 2112```moonscript
1761x = [ 2113x = [
@@ -1822,6 +2174,138 @@ if func 1, 2, 3,
1822</pre> 2174</pre>
1823</YueDisplay> 2175</YueDisplay>
1824 2176
2177### 傿•°è§£æž„
2178
2179月之脚本支æŒåœ¨å‡½æ•°å½¢å‚ä½ç½®å¯¹ä¼ å…¥å¯¹è±¡è¿›è¡Œè§£æž„。适用两类解构表å­é¢é‡ï¼š
2180
2181- 使用 {} 包裹的字é¢é‡/对象形å‚ï¼Œæ”¯æŒæä¾›èŽ·å¾—ç©ºå­—æ®µæ—¶çš„é»˜è®¤å€¼ï¼ˆä¾‹å¦‚ {:a, :b}ã€{a: a1 = 123})。
2182
2183- æ—  {} 包裹ã€ä»¥é”®å€¼/简写键åºåˆ—开头,直至é‡åˆ°å…¶å®ƒè¡¨è¾¾å¼ç»ˆæ­¢ï¼ˆä¾‹å¦‚ :a, b: b1, :c),表示从åŒä¸€ä¸ªå¯¹è±¡ä¸­è§£æž„多个字段。
2184
2185```moonscript
2186f1 = (:a, :b, :c) ->
2187 print a, b, c
2188
2189f1 a: 1, b: "2", c: {}
2190
2191f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) ->
2192 print a1, b, c
2193
2194arg1 = {a: 0}
2195f2 arg1, arg2
2196```
2197<YueDisplay>
2198<pre>
2199f1 = (:a, :b, :c) ->
2200 print a, b, c
2201
2202f1 a: 1, b: "2", c: {}
2203
2204f2 = ({a: a1 = 123, :b = 'abc'}, c = {}) ->
2205 print a1, b, c
2206
2207arg1 = {a: 0}
2208f2 arg1, arg2
2209</pre>
2210</YueDisplay>
2211
2212### å‰ç½®è¿”回表达å¼
2213
2214在深度嵌套的函数体中,为了æå‡è¿”回值的å¯è¯»æ€§åŠç¼–写便利性,我们新增了 “å‰ç½®è¿”回表达å¼â€ 语法。其形å¼å¦‚下:
2215
2216```moon
2217findFirstEven = (list): nil ->
2218 for item in *list
2219 if type(item) == "table"
2220 for sub in *item
2221 if sub % 2 == 0
2222 return sub
2223```
2224<YueDisplay>
2225<pre>
2226findFirstEven = (list): nil ->
2227 for item in *list
2228 if type(item) == "table"
2229 for sub in *item
2230 if sub % 2 == 0
2231 return sub
2232</pre>
2233</YueDisplay>
2234
2235这个写法等价于:
2236
2237```moon
2238findFirstEven = (list) ->
2239 for item in *list
2240 if type(item) == "table"
2241 for sub in *item
2242 if sub % 2 == 0
2243 return sub
2244 nil
2245```
2246<YueDisplay>
2247<pre>
2248findFirstEven = (list) ->
2249 for item in *list
2250 if type(item) == "table"
2251 for sub in *item
2252 if sub % 2 == 0
2253 return sub
2254 nil
2255</pre>
2256</YueDisplay>
2257
2258唯一的区别在于:你å¯ä»¥å°†å‡½æ•°çš„è¿”å›žå€¼è¡¨è¾¾å¼æå‰å†™åœ¨ `->` 或 `=>` å‰ï¼Œç”¨ä»¥æŒ‡ç¤ºè¯¥å‡½æ•°åº”éšå¼è¿”回该表达å¼çš„值。这样å³ä½¿åœ¨å¤šå±‚循环或æ¡ä»¶åˆ¤æ–­çš„场景下,也无需编写尾行悬挂的返回表达å¼ï¼Œé€»è¾‘结构会更加直观清晰。
2259
2260### 命åå˜é•¿å‚æ•°
2261
2262ä½ å¯ä»¥ä½¿ç”¨ `(...t) ->` 语法æ¥å°†å˜é•¿å‚数自动存储到一个命åè¡¨ä¸­ã€‚è¿™ä¸ªè¡¨ä¼šåŒ…å«æ‰€æœ‰ä¼ å…¥çš„傿•°ï¼ˆåŒ…括 `nil` 值),并且会在表的 `n` å­—æ®µä¸­å­˜å‚¨å®žé™…ä¼ å…¥çš„å‚æ•°ä¸ªæ•°ï¼ˆåŒ…括 `nil` 值在内的个数)。
2263
2264```moonscript
2265f = (...t) ->
2266 print "傿•°ä¸ªæ•°:", t.n
2267 print "表长度:", #t
2268 for i = 1, t.n
2269 print t[i]
2270
2271f 1, 2, 3
2272f "a", "b", "c", "d"
2273f!
2274
2275-- 处ç†åŒ…å« nil 的情况
2276process = (...args) ->
2277 sum = 0
2278 for i = 1, args.n
2279 if args[i] != nil and type(args[i]) == "number"
2280 sum += args[i]
2281 sum
2282
2283process 1, nil, 3, nil, 5
2284```
2285<YueDisplay>
2286<pre>
2287f = (...t) ->
2288 print "傿•°ä¸ªæ•°:", t.n
2289 print "表长度:", #t
2290 for i = 1, t.n
2291 print t[i]
2292
2293f 1, 2, 3
2294f "a", "b", "c", "d"
2295f!
2296
2297-- 处ç†åŒ…å« nil 的情况
2298process = (...args) ->
2299 sum = 0
2300 for i = 1, args.n
2301 if args[i] != nil and type(args[i]) == "number"
2302 sum += args[i]
2303 sum
2304
2305process 1, nil, 3, nil, 5
2306</pre>
2307</YueDisplay>
2308
1825## åå‘回调 2309## åå‘回调
1826 2310
1827åå‘回调用于å‡å°‘函数回调的嵌套。它们使用指å‘左侧的箭头,并且默认会被定义为传入åŽç»­å‡½æ•°è°ƒç”¨çš„æœ€åŽä¸€ä¸ªå‚数。它的语法大部分与常规箭头函数相åŒï¼Œåªæ˜¯å®ƒæŒ‡å‘å¦ä¸€æ–¹å‘,并且åŽç»­çš„函数体ä¸éœ€è¦è¿›è¡Œç¼©è¿›ã€‚ 2311åå‘回调用于å‡å°‘函数回调的嵌套。它们使用指å‘左侧的箭头,并且默认会被定义为传入åŽç»­å‡½æ•°è°ƒç”¨çš„æœ€åŽä¸€ä¸ªå‚数。它的语法大部分与常规箭头函数相åŒï¼Œåªæ˜¯å®ƒæŒ‡å‘å¦ä¸€æ–¹å‘,并且åŽç»­çš„函数体ä¸éœ€è¦è¿›è¡Œç¼©è¿›ã€‚
@@ -1850,7 +2334,7 @@ print @value
1850</pre> 2334</pre>
1851</YueDisplay> 2335</YueDisplay>
1852 2336
1853您å¯ä»¥é€šè¿‡ä¸€ä¸ªå ä½ç¬¦æŒ‡å®šå›žè°ƒå‡½æ•°çš„ä¼ å‚ä½ç½®ã€‚ 2337ä½ å¯ä»¥é€šè¿‡ä¸€ä¸ªå ä½ç¬¦æŒ‡å®šå›žè°ƒå‡½æ•°çš„ä¼ å‚ä½ç½®ã€‚
1854 2338
1855```moonscript 2339```moonscript
1856(x) <- map _, [1, 2, 3] 2340(x) <- map _, [1, 2, 3]
@@ -1863,22 +2347,22 @@ x * 2
1863</pre> 2347</pre>
1864</YueDisplay> 2348</YueDisplay>
1865 2349
1866如果您希望在åå‘回调处ç†åŽç»§ç»­ç¼–写更多其它的代ç ï¼Œæ‚¨å¯ä»¥ä½¿ç”¨do语å¥å°†ä¸å½’属åå‘回调的代ç åˆ†å¼€ã€‚ 2350如果你希望在åå‘回调处ç†åŽç»§ç»­ç¼–写更多其它的代ç ï¼Œå¯ä»¥ä½¿ç”¨ do 语å¥å°†ä¸å±žäºŽåå‘回调的代ç åˆ†éš”开。对于éžç²—箭头函数的åå‘回调,回调返回值的括å·ä¹Ÿæ˜¯å¯ä»¥çœç•¥çš„。
1867 2351
1868```moonscript 2352```moonscript
1869result, msg = do 2353result, msg = do
1870 (data) <- readAsync "文件å.txt" 2354 data <- readAsync "文件å.txt"
1871 print data 2355 print data
1872 (info) <- processAsync data 2356 info <- processAsync data
1873 check info 2357 check info
1874print result, msg 2358print result, msg
1875``` 2359```
1876<YueDisplay> 2360<YueDisplay>
1877<pre> 2361<pre>
1878result, msg = do 2362result, msg = do
1879 (data) <- readAsync "文件å.txt" 2363 data <- readAsync "文件å.txt"
1880 print data 2364 print data
1881 (info) <- processAsync data 2365 info <- processAsync data
1882 check info 2366 check info
1883print result, msg 2367print result, msg
1884</pre> 2368</pre>
@@ -1886,7 +2370,7 @@ print result, msg
1886 2370
1887## 表格字é¢é‡ 2371## 表格字é¢é‡
1888 2372
1889å’ŒLua一样,表格å¯ä»¥é€šè¿‡èŠ±æ‹¬å·è¿›è¡Œå®šä¹‰ã€‚ 2373å’Œ Lua 一样,表格å¯ä»¥é€šè¿‡èŠ±æ‹¬å·è¿›è¡Œå®šä¹‰ã€‚
1890 2374
1891```moonscript 2375```moonscript
1892some_values = [1, 2, 3, 4] 2376some_values = [1, 2, 3, 4]
@@ -1969,7 +2453,7 @@ y = type: "ç‹—", legs: 4, tails: 1
1969</pre> 2453</pre>
1970</YueDisplay> 2454</YueDisplay>
1971 2455
1972表格字é¢é‡çš„é”®å¯ä»¥ä½¿ç”¨Lua语言的关键字,而无需转义: 2456表格字é¢é‡çš„é”®å¯ä»¥ä½¿ç”¨ Lua 语言的关键字,而无需转义:
1973 2457
1974```moonscript 2458```moonscript
1975tbl = { 2459tbl = {
@@ -2005,7 +2489,7 @@ print_table :hair, :height
2005</pre> 2489</pre>
2006</YueDisplay> 2490</YueDisplay>
2007 2491
2008如果你希望表中字段的键是æŸä¸ªè¡¨è¾¾å¼çš„结果,那么å¯ä»¥ç”¨ **[ ]** 包裹它,就åƒåœ¨Lua中一样。如果键中有任何特殊字符,也å¯ä»¥ç›´æŽ¥ä½¿ç”¨å­—符串字é¢é‡ä½œä¸ºé”®ï¼Œçœç•¥æ–¹æ‹¬å·ã€‚ 2492如果你希望表中字段的键是æŸä¸ªè¡¨è¾¾å¼çš„结果,那么å¯ä»¥ç”¨ **[ ]** 包裹它,就åƒåœ¨ Lua 中一样。如果键中有任何特殊字符,也å¯ä»¥ç›´æŽ¥ä½¿ç”¨å­—符串字é¢é‡ä½œä¸ºé”®ï¼Œçœç•¥æ–¹æ‹¬å·ã€‚
2009 2493
2010```moonscript 2494```moonscript
2011t = { 2495t = {
@@ -2022,7 +2506,7 @@ t = {
2022</pre> 2506</pre>
2023</YueDisplay> 2507</YueDisplay>
2024 2508
2025Luaçš„è¡¨åŒæ—¶å…·æœ‰æ•°ç»„部分和哈希部分,但有时候你会希望在书写Lua表时,对Luaè¡¨åšæ•°ç»„和哈希ä¸åŒç”¨æ³•的语义区分。然åŽä½ å¯ä»¥ç”¨ **[ ]** è€Œä¸æ˜¯ **{ }** æ¥ç¼–写表示数组的 Lua 表,并且ä¸å…许在数组 Lua 表中写入任何键值对。 2509Lua çš„è¡¨åŒæ—¶å…·æœ‰æ•°ç»„部分和哈希部分,但有时候你会希望在书写 Lua 表时,对 Lua è¡¨åšæ•°ç»„和哈希ä¸åŒç”¨æ³•的语义区分。然åŽä½ å¯ä»¥ç”¨ **[ ]** è€Œä¸æ˜¯ **{ }** æ¥ç¼–写表示数组的 Lua 表,并且ä¸å…许在数组 Lua 表中写入任何键值对。
2026 2510
2027```moonscript 2511```moonscript
2028some_values = [ 1, 2, 3, 4 ] 2512some_values = [ 1, 2, 3, 4 ]
@@ -2037,11 +2521,11 @@ list_with_one_element = [ 1, ]
2037 2521
2038## æŽ¨å¯¼å¼ 2522## 推导å¼
2039 2523
2040推导å¼ä¸ºæˆ‘们æä¾›äº†ä¸€ç§ä¾¿æ·çš„语法,通过éåŽ†çŽ°æœ‰å¯¹è±¡å¹¶å¯¹å…¶å€¼åº”ç”¨è¡¨è¾¾å¼æ¥æž„é€ å‡ºæ–°çš„è¡¨æ ¼ã€‚æœˆä¹‹è„šæœ¬æœ‰ä¸¤ç§æŽ¨å¯¼å¼ï¼šåˆ—表推导å¼å’Œè¡¨æ ¼æŽ¨å¯¼å¼ã€‚它们最终都是产生Lua表格;列表推导å¼å°†å€¼ç´¯ç§¯åˆ°ç±»ä¼¼æ•°ç»„的表格中,而表格推导å¼å…è®¸æ‚¨åœ¨æ¯æ¬¡é历时设置新表格的键和值。 2524推导å¼ä¸ºæˆ‘们æä¾›äº†ä¸€ç§ä¾¿æ·çš„语法,通过éåŽ†çŽ°æœ‰å¯¹è±¡å¹¶å¯¹å…¶å€¼åº”ç”¨è¡¨è¾¾å¼æ¥æž„é€ å‡ºæ–°çš„è¡¨æ ¼ã€‚æœˆä¹‹è„šæœ¬æœ‰ä¸¤ç§æŽ¨å¯¼å¼ï¼šåˆ—表推导å¼å’Œè¡¨æ ¼æŽ¨å¯¼å¼ã€‚它们最终都是产生 Lua 表格;列表推导å¼å°†å€¼ç´¯ç§¯åˆ°ç±»ä¼¼æ•°ç»„的表格中,而表格推导å¼å…è®¸ä½ åœ¨æ¯æ¬¡é历时设置新表格的键和值。
2041 2525
2042### åˆ—è¡¨æŽ¨å¯¼å¼ 2526### 列表推导å¼
2043 2527
2044以下æ“作创建了一个items表的副本,但所有包å«çš„值都翻å€äº†ã€‚ 2528以下æ“作创建了一个 items 表的副本,但所有包å«çš„值都翻å€äº†ã€‚
2045 2529
2046```moonscript 2530```moonscript
2047items = [1, 2, 3, 4] 2531items = [1, 2, 3, 4]
@@ -2054,7 +2538,7 @@ doubled = [item * 2 for i, item in ipairs items]
2054</pre> 2538</pre>
2055</YueDisplay> 2539</YueDisplay>
2056 2540
2057å¯ä»¥ä½¿ç”¨whenå­å¥ç­›é€‰æ–°è¡¨ä¸­åŒ…å«çš„项目: 2541å¯ä»¥ä½¿ç”¨ `when` å­å¥ç­›é€‰æ–°è¡¨ä¸­åŒ…å«çš„项目:
2058 2542
2059```moonscript 2543```moonscript
2060slice = [item for i, item in ipairs items when i > 1 and i < 3] 2544slice = [item for i, item in ipairs items when i > 1 and i < 3]
@@ -2065,7 +2549,7 @@ slice = [item for i, item in ipairs items when i > 1 and i < 3]
2065</pre> 2549</pre>
2066</YueDisplay> 2550</YueDisplay>
2067 2551
2068因为我们常常需è¦è¿­ä»£æ•°å€¼ç´¢å¼•表的值,所以引入了 **\*** æ“作符æ¥åšè¯­æ³•简化。doubled示例å¯ä»¥é‡å†™ä¸ºï¼š 2552因为我们常常需è¦è¿­ä»£æ•°å€¼ç´¢å¼•表的值,所以引入了 **\*** æ“作符æ¥åšè¯­æ³•简化。doubled 示例å¯ä»¥é‡å†™ä¸ºï¼š
2069 2553
2070```moonscript 2554```moonscript
2071doubled = [item * 2 for item in *items] 2555doubled = [item * 2 for item in *items]
@@ -2076,9 +2560,30 @@ doubled = [item * 2 for item in *items]
2076</pre> 2560</pre>
2077</YueDisplay> 2561</YueDisplay>
2078 2562
2079forå’Œwhenå­å¥å¯ä»¥æ ¹æ®éœ€è¦è¿›è¡Œé“¾å¼æ“ä½œã€‚å”¯ä¸€çš„è¦æ±‚是推导å¼ä¸­è‡³å°‘è¦æœ‰ä¸€ä¸ªforå­å¥ã€‚ 2563在列表推导å¼ä¸­ï¼Œä½ è¿˜å¯ä»¥ä½¿ç”¨å±•å¼€æ“作符 `...` æ¥å®žçŽ°å¯¹åˆ—è¡¨åµŒå¥—å±‚çº§è¿›è¡Œæ‰å¹³åŒ–的处ç†ï¼š
2564
2565```moonscript
2566data =
2567 a: [1, 2, 3]
2568 b: [4, 5, 6]
2569
2570flat = [...v for k,v in pairs data]
2571-- flat 现在为 [1, 2, 3, 4, 5, 6]
2572```
2573<YueDisplay>
2574<pre>
2575data =
2576 a: [1, 2, 3]
2577 b: [4, 5, 6]
2578
2579flat = [...v for k,v in pairs data]
2580-- flat 现在为 [1, 2, 3, 4, 5, 6]
2581</pre>
2582</YueDisplay>
2583
2584for å’Œ when å­å¥å¯ä»¥æ ¹æ®éœ€è¦è¿›è¡Œé“¾å¼æ“ä½œã€‚å”¯ä¸€çš„è¦æ±‚是推导å¼ä¸­è‡³å°‘è¦æœ‰ä¸€ä¸ª for å­å¥ã€‚
2080 2585
2081使用多个forå­å¥ä¸Žä½¿ç”¨å¤šé‡å¾ªçŽ¯çš„æ•ˆæžœç›¸åŒï¼š 2586使用多个 for å­å¥ä¸Žä½¿ç”¨å¤šé‡å¾ªçŽ¯çš„æ•ˆæžœç›¸åŒï¼š
2082 2587
2083```moonscript 2588```moonscript
2084x_coords = [4, 5, 6, 7] 2589x_coords = [4, 5, 6, 7]
@@ -2097,7 +2602,7 @@ for y in *y_coords]
2097</pre> 2602</pre>
2098</YueDisplay> 2603</YueDisplay>
2099 2604
2100在推导å¼ä¸­ä¹Ÿå¯ä»¥ä½¿ç”¨ç®€å•的数值for循环: 2605在推导å¼ä¸­ä¹Ÿå¯ä»¥ä½¿ç”¨ç®€å•的数值 for 循环:
2101 2606
2102```moonscript 2607```moonscript
2103evens = [i for i = 1, 100 when i % 2 == 0] 2608evens = [i for i = 1, 100 when i % 2 == 0]
@@ -2112,7 +2617,7 @@ evens = [i for i = 1, 100 when i % 2 == 0]
2112 2617
2113表格推导å¼å’Œåˆ—表推导å¼çš„语法éžå¸¸ç›¸ä¼¼ï¼Œåªæ˜¯è¦ä½¿ç”¨ **{** å’Œ **}** å¹¶ä»Žæ¯æ¬¡è¿­ä»£ä¸­å–两个值。 2618表格推导å¼å’Œåˆ—表推导å¼çš„语法éžå¸¸ç›¸ä¼¼ï¼Œåªæ˜¯è¦ä½¿ç”¨ **{** å’Œ **}** å¹¶ä»Žæ¯æ¬¡è¿­ä»£ä¸­å–两个值。
2114 2619
2115以下示例生æˆäº†è¡¨æ ¼thing的副本: 2620以下示例生æˆäº†è¡¨æ ¼ thing 的副本:
2116 2621
2117```moonscript 2622```moonscript
2118thing = { 2623thing = {
@@ -2174,9 +2679,9 @@ tbl = {unpack tuple for tuple in *tuples}
2174 2679
2175### 切片 2680### 切片
2176 2681
2177当使用 **\*** æ“作符时,月之脚本还æä¾›äº†ä¸€ç§ç‰¹æ®Šçš„语法æ¥é™åˆ¶è¦é历的列表范围。这个语法也相当于在for循环中设置迭代边界和步长。 2682当使用 **\*** æ“作符时,月之脚本还æä¾›äº†ä¸€ç§ç‰¹æ®Šçš„语法æ¥é™åˆ¶è¦é历的列表范围。这个语法也相当于在 for 循环中设置迭代边界和步长。
2178 2683
2179下é¢çš„æ¡ˆä¾‹ä¸­ï¼Œæˆ‘们在切片中设置最å°å’Œæœ€å¤§è¾¹ç•Œï¼Œå–索引在1到5之间(包括1å’Œ5)的所有项目: 2684下é¢çš„æ¡ˆä¾‹ä¸­ï¼Œæˆ‘们在切片中设置最å°å’Œæœ€å¤§è¾¹ç•Œï¼Œå–索引在 1 到 5 之间(包括 1 å’Œ 5)的所有项目:
2180 2685
2181```moonscript 2686```moonscript
2182slice = [item for item in *items[1, 5]] 2687slice = [item for item in *items[1, 5]]
@@ -2198,7 +2703,7 @@ slice = [item for item in *items[2,]]
2198</pre> 2703</pre>
2199</YueDisplay> 2704</YueDisplay>
2200 2705
2201如果çœç•¥äº†æœ€å°è¾¹ç•Œï¼Œä¾¿é»˜è®¤ä¼šè®¾ç½®ä¸º1ã€‚è¿™é‡Œæˆ‘ä»¬åªæä¾›ä¸€ä¸ªæ­¥é•¿ï¼Œå¹¶ç•™ä¸‹å…¶ä»–è¾¹ç•Œä¸ºç©ºã€‚è¿™æ ·ä¼šä½¿å¾—ä»£ç å–出所有奇数索引的项目:(1, 3, 5, …) 2706如果çœç•¥äº†æœ€å°è¾¹ç•Œï¼Œä¾¿é»˜è®¤ä¼šè®¾ç½®ä¸º 1ã€‚è¿™é‡Œæˆ‘ä»¬åªæä¾›ä¸€ä¸ªæ­¥é•¿ï¼Œå¹¶ç•™ä¸‹å…¶ä»–è¾¹ç•Œä¸ºç©ºã€‚è¿™æ ·ä¼šä½¿å¾—ä»£ç å–出所有奇数索引的项目:(1, 3, 5, …)
2202 2707
2203```moonscript 2708```moonscript
2204slice = [item for item in *items[,,2]] 2709slice = [item for item in *items[,,2]]
@@ -2210,9 +2715,48 @@ slice = [item for item in *items[,,2]]
2210</pre> 2715</pre>
2211</YueDisplay> 2716</YueDisplay>
2212 2717
2718最å°å’Œæœ€å¤§è¾¹ç•Œéƒ½å¯ä»¥æ˜¯è´Ÿæ•°ï¼Œä½¿ç”¨è´Ÿæ•°æ„味ç€è¾¹ç•Œæ˜¯ä»Žè¡¨çš„æœ«å°¾å¼€å§‹è®¡ç®—的。
2719
2720```moonscript
2721-- å–æœ€åŽ4个元素
2722slice = [item for item in *items[-4,-1]]
2723```
2724<YueDisplay>
2725<pre>
2726-- å–æœ€åŽ4个元素
2727slice = [item for item in *items[-4,-1]]
2728</pre>
2729</YueDisplay>
2730
2731切片的步长也å¯ä»¥æ˜¯è´Ÿæ•°ï¼Œè¿™æ„味ç€å…ƒç´ ä¼šä»¥ç›¸å的顺åºè¢«å–出。
2732
2733```moonscript
2734reverse_slice = [item for item in *items[-1,1,-1]]
2735```
2736<YueDisplay>
2737<pre>
2738reverse_slice = [item for item in *items[-1,1,-1]]
2739</pre>
2740</YueDisplay>
2741
2742#### 切片表达å¼
2743
2744切片也å¯ä»¥ä½œä¸ºè¡¨è¾¾å¼æ¥ä½¿ç”¨ã€‚å¯ä»¥ç”¨äºŽèŽ·å–一个表包å«çš„å­åˆ—表。
2745
2746```moonscript
2747-- å–第2和第4个元素作为新的列表
2748sub_list = items[2, 4]
2749```
2750<YueDisplay>
2751<pre>
2752-- å–第2和第4个元素作为新的列表
2753sub_list = items[2, 4]
2754</pre>
2755</YueDisplay>
2756
2213## for 循环 2757## for 循环
2214 2758
2215Lua中有两ç§for循环形å¼ï¼Œæ•°å­—型和通用型: 2759Lua ä¸­æœ‰ä¸¤ç§ for 循环形å¼ï¼Œæ•°å­—型和通用型:
2216 2760
2217```moonscript 2761```moonscript
2218for i = 10, 20 2762for i = 10, 20
@@ -2265,7 +2809,7 @@ for j = 1, 10, 3 do print j
2265</pre> 2809</pre>
2266</YueDisplay> 2810</YueDisplay>
2267 2811
2268for循环也å¯ä»¥ç”¨ä½œè¡¨è¾¾å¼ã€‚for循环主体中的最åŽä¸€æ¡è¯­å¥ä¼šè¢«å¼ºåˆ¶è½¬æ¢ä¸ºä¸€ä¸ªè¿”回值的表达å¼ï¼Œå¹¶ä¼šå°†è¡¨è¾¾å¼è®¡ç®—结果的值追加到一个作为结果的数组表中。 2812for 循环也å¯ä»¥ç”¨ä½œè¡¨è¾¾å¼ã€‚for 循环主体中的最åŽä¸€æ¡è¯­å¥ä¼šè¢«å¼ºåˆ¶è½¬æ¢ä¸ºä¸€ä¸ªè¿”回值的表达å¼ï¼Œå¹¶ä¼šå°†è¡¨è¾¾å¼è®¡ç®—结果的值追加到一个作为结果的数组表中。
2269 2813
2270å°†æ¯ä¸ªå¶æ•°åŠ å€ï¼š 2814å°†æ¯ä¸ªå¶æ•°åŠ å€ï¼š
2271 2815
@@ -2286,9 +2830,24 @@ doubled_evens = for i = 1, 20
2286</pre> 2830</pre>
2287</YueDisplay> 2831</YueDisplay>
2288 2832
2289您还å¯ä»¥ç»“åˆfor循环表达å¼ä¸Žcontinueè¯­å¥æ¥è¿‡æ»¤å€¼ã€‚ 2833此外,for 循环还支æŒå¸¦è¿”回值的 break 语å¥ï¼Œè¿™æ ·å¾ªçŽ¯æœ¬èº«å°±å¯ä»¥ä½œä¸ºä¸€ä¸ªè¡¨è¾¾å¼ï¼Œåœ¨æ»¡è¶³æ¡ä»¶æ—¶æå‰é€€å‡ºå¹¶è¿”回有æ„义的结果。
2834
2835例如,查找第一个大于 10 的数字:
2836
2837```moonscript
2838first_large = for n in *numbers
2839 break n if n > 10
2840```
2841<YueDisplay>
2842<pre>
2843first_large = for n in *numbers
2844 break n if n > 10
2845</pre>
2846</YueDisplay>
2847
2848你还å¯ä»¥ç»“åˆ for 循环表达å¼ä¸Ž continue è¯­å¥æ¥è¿‡æ»¤å€¼ã€‚
2290 2849
2291注æ„出现在函数体末尾的for循环,ä¸ä¼šè¢«å½“作是一个表达å¼ï¼Œå¹¶å°†å¾ªçŽ¯ç»“æžœç´¯ç§¯åˆ°ä¸€ä¸ªåˆ—è¡¨ä¸­ä½œä¸ºè¿”å›žå€¼ï¼ˆç›¸å,函数将返回nil)。如果è¦å‡½æ•°æœ«å°¾çš„循环转æ¢ä¸ºåˆ—表表达å¼ï¼Œå¯ä»¥ä½¿ç”¨è¿”回语å¥åŠ for循环表达å¼ã€‚ 2850注æ„出现在函数体末尾的 for 循环,ä¸ä¼šè¢«å½“作是一个表达å¼å¹¶å°†å¾ªçŽ¯ç»“æžœç´¯ç§¯åˆ°ä¸€ä¸ªåˆ—è¡¨ä¸­ä½œä¸ºè¿”å›žå€¼ï¼ˆç›¸å,函数将返回 nil)。如果è¦å‡½æ•°æœ«å°¾çš„循环转æ¢ä¸ºåˆ—表表达å¼ï¼Œå¯ä»¥æ˜¾å¼åœ°ä½¿ç”¨è¿”回语å¥åŠ  for 循环表达å¼ã€‚
2292 2851
2293```moonscript 2852```moonscript
2294func_a = -> for i = 1, 10 do print i 2853func_a = -> for i = 1, 10 do print i
@@ -2311,7 +2870,7 @@ print func_b! -- æ‰“å° table 对象
2311 2870
2312## repeat 循环 2871## repeat 循环
2313 2872
2314repeat循环是从Lua语言中æ¬è¿‡æ¥çš„相似语法: 2873repeat 循环是从 Lua 语言中æ¬è¿‡æ¥çš„相似语法:
2315 2874
2316```moonscript 2875```moonscript
2317i = 10 2876i = 10
@@ -2332,7 +2891,7 @@ until i == 0
2332 2891
2333## while 循环 2892## while 循环
2334 2893
2335在月之脚本中的while循环有四ç§å†™æ³•: 2894在月之脚本中的 while 循环有四ç§å†™æ³•:
2336 2895
2337```moonscript 2896```moonscript
2338i = 10 2897i = 10
@@ -2371,7 +2930,7 @@ until running == false do my_function!
2371</pre> 2930</pre>
2372</YueDisplay> 2931</YueDisplay>
2373 2932
2374åƒfor循环的语法一样,while循环也å¯ä»¥ä½œä¸ºä¸€ä¸ªè¡¨è¾¾å¼ä½¿ç”¨ã€‚为了使函数返回while循环的累积列表值,必须明确使用返回语å¥è¿”回while循环表达å¼ã€‚ 2933åƒ for 循环的语法一样,while 循环也å¯ä»¥ä½œä¸ºä¸€ä¸ªè¡¨è¾¾å¼ä½¿ç”¨ã€‚为了使函数返回 while 循环的累积列表值,必须明确使用返回语å¥è¿”回 while 循环表达å¼ã€‚
2375 2934
2376## ç»§ç»­ 2935## ç»§ç»­
2377 2936
@@ -2489,13 +3048,14 @@ print message -- 打å°: 我很高
2489</pre> 3048</pre>
2490</YueDisplay> 3049</YueDisplay>
2491 3050
2492ifçš„åä¹‰è¯æ˜¯unless(相当于if not,如果 vs 除éžï¼‰ï¼š 3051if çš„åä¹‰è¯æ˜¯ unless(相当于 if not,正如“如果â€å¯¹åº”“除éžâ€ï¼‰ï¼š
2493 3052
2494```moonscript 3053```moonscript
2495unless os.date("%A") == "Monday" 3054unless os.date("%A") == "Monday"
2496 print "ä»Šå¤©ä¸æ˜¯æ˜ŸæœŸä¸€ï¼" 3055 print "ä»Šå¤©ä¸æ˜¯æ˜ŸæœŸä¸€ï¼"
2497``` 3056```
2498<YueDisplay> 3057<YueDisplay>
3058
2499<pre> 3059<pre>
2500unless os.date("%A") == "Monday" 3060unless os.date("%A") == "Monday"
2501 print "ä»Šå¤©ä¸æ˜¯æ˜ŸæœŸä¸€ï¼" 3061 print "ä»Šå¤©ä¸æ˜¯æ˜ŸæœŸä¸€ï¼"
@@ -2513,7 +3073,7 @@ print "你真幸è¿ï¼" unless math.random! > 0.1
2513 3073
2514### èŒƒå›´è¡¨è¾¾å¼ 3074### 范围表达å¼
2515 3075
2516您å¯ä»¥ä½¿ç”¨èŒƒå›´è¡¨è¾¾å¼æ¥ç¼–写进行范围检查的代ç ã€‚ 3076ä½ å¯ä»¥ä½¿ç”¨èŒƒå›´è¡¨è¾¾å¼æ¥ç¼–写进行范围检查的代ç ã€‚
2517 3077
2518```moonscript 3078```moonscript
2519a = 5 3079a = 5
@@ -2547,7 +3107,7 @@ print "你很幸è¿!" unless math.random! > 0.1
2547 3107
2548## 代ç è¡Œä¿®é¥°ç¬¦ 3108## 代ç è¡Œä¿®é¥°ç¬¦
2549 3109
2550为了方便编写代ç ï¼Œå¾ªçŽ¯è¯­å¥å’Œif语å¥å¯ä»¥åº”用于å•行代ç è¯­å¥çš„æœ«å°¾ï¼š 3110为了方便编写代ç ï¼Œå¾ªçŽ¯è¯­å¥å’Œ if 语å¥å¯ä»¥åº”用于å•行代ç è¯­å¥çš„æœ«å°¾ï¼š
2551 3111
2552```moonscript 3112```moonscript
2553print "你好,世界" if name == "Rob" 3113print "你好,世界" if name == "Rob"
@@ -2558,7 +3118,7 @@ print "你好,世界" if name == "Rob"
2558</pre> 3118</pre>
2559</YueDisplay> 3119</YueDisplay>
2560 3120
2561修饰for循环的示例: 3121修饰 for 循环的示例:
2562 3122
2563```moonscript 3123```moonscript
2564print "项目: ", item for item in *items 3124print "项目: ", item for item in *items
@@ -2569,7 +3129,7 @@ print "项目: ", item for item in *items
2569</pre> 3129</pre>
2570</YueDisplay> 3130</YueDisplay>
2571 3131
2572修饰while循环的示例: 3132修饰 while 循环的示例:
2573 3133
2574```moonscript 3134```moonscript
2575game\update! while game\isRunning! 3135game\update! while game\isRunning!
@@ -2586,34 +3146,32 @@ reader\parse_line! until reader\eof!
2586 3146
2587## switch è¯­å¥ 3147## switch 语å¥
2588 3148
2589switchè¯­å¥æ˜¯ä¸ºäº†ç®€åŒ–检查一系列相åŒå€¼çš„if语å¥è€Œæä¾›çš„ç®€å†™è¯­æ³•ã€‚è¦æ³¨æ„用于比较检查的目标值åªä¼šè®¡ç®—一次。和if语å¥ä¸€æ ·ï¼Œswitch语å¥åœ¨æœ€åŽå¯ä»¥æŽ¥ä¸€ä¸ªelse代ç å—æ¥å¤„ç†æ²¡æœ‰åŒ¹é…的情况。在生æˆçš„Lua代ç ä¸­ï¼Œè¿›è¡Œæ¯”较是使用==æ“作符完æˆçš„。 3149switch è¯­å¥æ˜¯ä¸ºäº†ç®€åŒ–检查一系列相åŒå€¼çš„if语å¥è€Œæä¾›çš„ç®€å†™è¯­æ³•ã€‚è¦æ³¨æ„用于比较检查的目标值åªä¼šè®¡ç®—一次。和 if 语å¥ä¸€æ ·ï¼Œswitch 语å¥åœ¨æœ€åŽå¯ä»¥æŽ¥ä¸€ä¸ª else 代ç å—æ¥å¤„ç†æ²¡æœ‰åŒ¹é…的情况。在生æˆçš„ Lua 代ç ä¸­ï¼Œè¿›è¡Œæ¯”较是使用 == æ“作符完æˆçš„。switch 语å¥ä¸­ä¹Ÿå¯ä»¥ä½¿ç”¨èµ‹å€¼è¡¨è¾¾å¼æ¥å‚¨å­˜ä¸´æ—¶å˜é‡å€¼ã€‚
2590 3150
2591```moonscript 3151```moonscript
2592name = "Dan" 3152switch name := "Dan"
2593switch name
2594 when "Robert" 3153 when "Robert"
2595 print "你是Robert" 3154 print "你是Robert"
2596 when "Dan", "Daniel" 3155 when "Dan", "Daniel"
2597 print "ä½ çš„å字是Dan" 3156 print "ä½ çš„å字是Dan"
2598 else 3157 else
2599 print "我ä¸çŸ¥é“ä½ çš„åå­—" 3158 print "我ä¸è®¤è¯†ä½ ï¼Œä½ çš„å字是#{name}"
2600``` 3159```
2601<YueDisplay> 3160<YueDisplay>
2602<pre> 3161<pre>
2603name = "Dan" 3162switch name := "Dan"
2604switch name
2605 when "Robert" 3163 when "Robert"
2606 print "你是Robert" 3164 print "你是Robert"
2607 when "Dan", "Daniel" 3165 when "Dan", "Daniel"
2608 print "ä½ çš„å字是Dan" 3166 print "ä½ çš„å字是Dan"
2609 else 3167 else
2610 print "我ä¸çŸ¥é“ä½ çš„åå­—" 3168 print "我ä¸è®¤è¯†ä½ ï¼Œä½ çš„å字是#{name}"
2611</pre> 3169</pre>
2612</YueDisplay> 3170</YueDisplay>
2613 3171
2614switch语å¥çš„whenå­å¥ä¸­å¯ä»¥é€šè¿‡ä½¿ç”¨é€—å·åˆ†éš”的列表æ¥åŒ¹é…多个值。 3172switch 语å¥çš„ when å­å¥ä¸­å¯ä»¥é€šè¿‡ä½¿ç”¨é€—å·åˆ†éš”的列表æ¥åŒ¹é…多个值。
2615 3173
2616switch语å¥ä¹Ÿå¯ä»¥ä½œä¸ºè¡¨è¾¾å¼ä½¿ç”¨ï¼Œä¸‹é¢æˆ‘们å¯ä»¥å°†switch语å¥è¿”回的结果分é…给一个å˜é‡ï¼š 3174switch 语å¥ä¹Ÿå¯ä»¥ä½œä¸ºè¡¨è¾¾å¼ä½¿ç”¨ï¼Œä¸‹é¢æˆ‘们å¯ä»¥å°† switch 语å¥è¿”回的结果分é…给一个å˜é‡ï¼š
2617 3175
2618```moonscript 3176```moonscript
2619b = 1 3177b = 1
@@ -2638,7 +3196,7 @@ next_number = switch b
2638</pre> 3196</pre>
2639</YueDisplay> 3197</YueDisplay>
2640 3198
2641我们å¯ä»¥ä½¿ç”¨then关键字在whenå­å¥çš„åŒä¸€è¡Œä¸Šç¼–写处ç†ä»£ç ã€‚else代ç å—çš„åŽç»­ä»£ç ä¸­è¦å†™åœ¨åŒä¸€è¡Œä¸Šä¸éœ€è¦é¢å¤–的关键字。 3199我们å¯ä»¥ä½¿ç”¨ then 关键字在 when å­å¥çš„åŒä¸€è¡Œä¸Šç¼–写处ç†ä»£ç ã€‚else 代ç å—çš„åŽç»­ä»£ç ä¸­è¦å†™åœ¨åŒä¸€è¡Œä¸Šä¸éœ€è¦é¢å¤–的关键字。
2642 3200
2643```moonscript 3201```moonscript
2644msg = switch math.random(1, 5) 3202msg = switch math.random(1, 5)
@@ -2655,7 +3213,7 @@ msg = switch math.random(1, 5)
2655</pre> 3213</pre>
2656</YueDisplay> 3214</YueDisplay>
2657 3215
2658如果在编写switchè¯­å¥æ—¶å¸Œæœ›å°‘写一个缩进,那么你å¯ä»¥æŠŠç¬¬ä¸€ä¸ªwhenå­å¥æ”¾åœ¨switch开始语å¥çš„第一行,然åŽåŽç»­çš„å­è¯­å¥å°±éƒ½å¯ä»¥éƒ½å°‘写一个缩进。 3216如果在编写 switch è¯­å¥æ—¶å¸Œæœ›å°‘写一个缩进,那么你å¯ä»¥æŠŠç¬¬ä¸€ä¸ª when å­å¥æ”¾åœ¨ switch 开始语å¥çš„第一行,然åŽåŽç»­çš„å­è¯­å¥å°±éƒ½å¯ä»¥éƒ½å°‘写一个缩进。
2659 3217
2660```moonscript 3218```moonscript
2661switch math.random(1, 5) 3219switch math.random(1, 5)
@@ -2684,11 +3242,11 @@ else
2684</pre> 3242</pre>
2685</YueDisplay> 3243</YueDisplay>
2686 3244
2687值得注æ„的是,在生æˆLuaä»£ç æ—¶ï¼Œæˆ‘们è¦åšæ£€æŸ¥çš„ç›®æ ‡å˜é‡ä¼šæ”¾åœ¨==表达å¼çš„å³ä¾§ã€‚当您希望给whenå­å¥çš„æ¯”较对象定义一个\_\_eq元方法æ¥é‡è½½åˆ¤æ–­é€»è¾‘时,å¯èƒ½ä¼šæœ‰ç”¨ã€‚ 3245值得注æ„çš„æ˜¯ï¼Œåœ¨ç”Ÿæˆ Lua ä»£ç æ—¶ï¼Œæˆ‘们è¦åšæ£€æŸ¥çš„ç›®æ ‡å˜é‡ä¼šæ”¾åœ¨ == 表达å¼çš„å³ä¾§ã€‚当你希望给 when å­å¥çš„æ¯”较对象定义一个 \_\_eq 元方法æ¥é‡è½½åˆ¤æ–­é€»è¾‘时,å¯èƒ½ä¼šæœ‰ç”¨ã€‚
2688 3246
2689### è¡¨æ ¼åŒ¹é… 3247### 表格匹é…
2690 3248
2691在switchçš„whenå­å¥ä¸­ï¼Œå¦‚果期待检查目标是一个表格,且å¯ä»¥é€šè¿‡ç‰¹å®šçš„结构进行解构并获得éžnil值,那么你å¯ä»¥å°è¯•使用表格匹é…的语法。 3249在 switch çš„ when å­å¥ä¸­ï¼Œå¦‚果期待检查目标是一个表格,且å¯ä»¥é€šè¿‡ç‰¹å®šçš„ç»“æž„è¿›è¡Œè§£æž„å¹¶èŽ·å¾—éž nil 值,那么你å¯ä»¥å°è¯•使用表格匹é…的语法。
2692 3250
2693```moonscript 3251```moonscript
2694items = 3252items =
@@ -2744,9 +3302,126 @@ switch item
2744</pre> 3302</pre>
2745</YueDisplay> 3303</YueDisplay>
2746 3304
3305你也å¯ä»¥åŒ¹é…数组元素ã€è¡¨æ ¼å­—段,甚至使用数组或表格字é¢é‡æ¥åŒ¹é…嵌套的结构。
3306
3307åŒ¹é…æ•°ç»„元素。
3308
3309```moonscript
3310switch tb
3311 when [1, 2, 3]
3312 print "1, 2, 3"
3313 when [1, b, 3]
3314 print "1, #{b}, 3"
3315 when [1, 2, b = 3] -- å˜é‡b有默认值
3316 print "1, 2, #{b}"
3317```
3318<YueDisplay>
3319<pre>
3320switch tb
3321 when [1, 2, 3]
3322 print "1, 2, 3"
3323 when [1, b, 3]
3324 print "1, #{b}, 3"
3325 when [1, 2, b = 3] -- å˜é‡b有默认值
3326 print "1, 2, #{b}"
3327</pre>
3328</YueDisplay>
3329
3330匹é…表格字段。
3331
3332```moonscript
3333switch tb
3334 when success: true, :result
3335 print "æˆåŠŸ", result
3336 when success: false
3337 print "失败", result
3338 else
3339 print "无效值"
3340```
3341<YueDisplay>
3342<pre>
3343switch tb
3344 when success: true, :result
3345 print "æˆåŠŸ", result
3346 when success: false
3347 print "失败", result
3348 else
3349 print "无效值"
3350</pre>
3351</YueDisplay>
3352
3353匹é…嵌套的表格结构。
3354
3355```moonscript
3356switch tb
3357 when data: {type: "success", :content}
3358 print "æˆåŠŸ", content
3359 when data: {type: "error", :content}
3360 print "失败", content
3361 else
3362 print "无效值"
3363```
3364<YueDisplay>
3365<pre>
3366switch tb
3367 when data: {type: "success", :content}
3368 print "æˆåŠŸ", content
3369 when data: {type: "error", :content}
3370 print "失败", content
3371 else
3372 print "无效值"
3373</pre>
3374</YueDisplay>
3375
3376匹é…表格数组。
3377
3378```moonscript
3379switch tb
3380 when [
3381 {a: 1, b: 2}
3382 {a: 3, b: 4}
3383 {a: 5, b: 6}
3384 fourth
3385 ]
3386 print "åŒ¹é…æˆåŠŸ", fourth
3387```
3388<YueDisplay>
3389<pre>
3390switch tb
3391 when [
3392 {a: 1, b: 2}
3393 {a: 3, b: 4}
3394 {a: 5, b: 6}
3395 fourth
3396 ]
3397 print "åŒ¹é…æˆåŠŸ", fourth
3398</pre>
3399</YueDisplay>
3400
3401匹é…一个列表并æ•获特定范围内的元素。
3402
3403```moonscript
3404segments = ["admin", "users", "logs", "view"]
3405switch segments
3406 when [...groups, resource, action]
3407 print "Group:", groups -- 打å°: {"admin", "users"}
3408 print "Resource:", resource -- 打å°: "logs"
3409 print "Action:", action -- 打å°: "view"
3410```
3411<YueDisplay>
3412<pre>
3413segments = ["admin", "users", "logs", "view"]
3414switch segments
3415 when [...groups, resource, action]
3416 print "Group:", groups -- 打å°: {"admin", "users"}
3417 print "Resource:", resource -- 打å°: "logs"
3418 print "Action:", action -- 打å°: "view"
3419</pre>
3420</YueDisplay>
3421
2747## é¢å‘对象编程 3422## é¢å‘对象编程
2748 3423
2749在以下的示例中,月之脚本生æˆçš„Lua代ç å¯èƒ½çœ‹èµ·æ¥ä¼šå¾ˆå¤æ‚。所以最好主è¦å…³æ³¨æœˆä¹‹è„šæœ¬ä»£ç å±‚é¢çš„æ„ä¹‰ï¼Œç„¶åŽå¦‚果您想知é“关于é¢å‘å¯¹è±¡åŠŸèƒ½çš„å®žçŽ°ç»†èŠ‚ï¼Œå†æŸ¥çœ‹Lua代ç ã€‚ 3424在以下的示例中,月之脚本生æˆçš„ Lua 代ç å¯èƒ½çœ‹èµ·æ¥ä¼šå¾ˆå¤æ‚。所以最好主è¦å…³æ³¨æœˆä¹‹è„šæœ¬ä»£ç å±‚é¢çš„æ„ä¹‰ï¼Œç„¶åŽå¦‚果你想知é“关于é¢å‘å¯¹è±¡åŠŸèƒ½çš„å®žçŽ°ç»†èŠ‚ï¼Œå†æŸ¥çœ‹ Lua 代ç ã€‚
2750 3425
2751一个简å•的类: 3426一个简å•的类:
2752 3427
@@ -2775,11 +3450,11 @@ class Inventory
2775</pre> 3450</pre>
2776</YueDisplay> 3451</YueDisplay>
2777 3452
2778在月之脚本中采用é¢å‘å¯¹è±¡çš„ç¼–ç¨‹æ–¹å¼æ—¶ï¼Œé€šå¸¸ä¼šä½¿ç”¨ç±»å£°æ˜Žè¯­å¥ç»“åˆLua表格字é¢é‡æ¥åšç±»å®šä¹‰ã€‚这个类的定义包å«äº†å®ƒçš„æ‰€æœ‰æ–¹æ³•和属性。在这ç§ç»“构中,键å为“newâ€çš„æˆå‘˜æ‰®æ¼”äº†ä¸€ä¸ªé‡è¦çš„角色,是作为构造函数æ¥ä½¿ç”¨ã€‚ 3453在月之脚本中采用é¢å‘å¯¹è±¡çš„ç¼–ç¨‹æ–¹å¼æ—¶ï¼Œé€šå¸¸ä¼šä½¿ç”¨ç±»å£°æ˜Žè¯­å¥ç»“åˆ Lua 表格字é¢é‡æ¥åšç±»å®šä¹‰ã€‚这个类的定义包å«äº†å®ƒçš„æ‰€æœ‰æ–¹æ³•和属性。在这ç§ç»“构中,键å为 “new†的æˆå‘˜æ‰®æ¼”了一个é‡è¦çš„角色,是作为构造函数æ¥ä½¿ç”¨ã€‚
2779 3454
2780值得注æ„çš„æ˜¯ï¼Œç±»ä¸­çš„æ–¹æ³•éƒ½é‡‡ç”¨äº†ç²—ç®­å¤´å‡½æ•°è¯­æ³•ã€‚å½“åœ¨ç±»çš„å®žä¾‹ä¸Šè°ƒç”¨æ–¹æ³•æ—¶ï¼Œè¯¥å®žä¾‹ä¼šè‡ªåŠ¨ä½œä¸ºç¬¬ä¸€ä¸ªå‚æ•°è¢«ä¼ å…¥ï¼Œå› æ­¤ç²—箭头函数用于生æˆä¸€ä¸ªå为“selfâ€çš„傿•°ã€‚ 3455值得注æ„çš„æ˜¯ï¼Œç±»ä¸­çš„æ–¹æ³•éƒ½é‡‡ç”¨äº†ç²—ç®­å¤´å‡½æ•°è¯­æ³•ã€‚å½“åœ¨ç±»çš„å®žä¾‹ä¸Šè°ƒç”¨æ–¹æ³•æ—¶ï¼Œè¯¥å®žä¾‹ä¼šè‡ªåŠ¨ä½œä¸ºç¬¬ä¸€ä¸ªå‚æ•°è¢«ä¼ å…¥ï¼Œå› æ­¤ç²—箭头函数用于生æˆä¸€ä¸ªå为 “selfâ€ çš„å‚æ•°ã€‚
2781 3456
2782此外,“@â€å‰ç¼€åœ¨å˜é‡å上起到了简化作用,代表“selfâ€ã€‚例如,`@items` 就等åŒäºŽ `self.items`。 3457此外,“@†å‰ç¼€åœ¨å˜é‡å上起到了简化作用,代表 “selfâ€ã€‚例如,`@items` 就等åŒäºŽ `self.items`。
2783 3458
2784为了创建类的一个新实例,å¯ä»¥å°†ç±»å当作一个函数æ¥è°ƒç”¨ï¼Œè¿™æ ·å°±å¯ä»¥ç”Ÿæˆå¹¶è¿”回一个新的实例。 3459为了创建类的一个新实例,å¯ä»¥å°†ç±»å当作一个函数æ¥è°ƒç”¨ï¼Œè¿™æ ·å°±å¯ä»¥ç”Ÿæˆå¹¶è¿”回一个新的实例。
2785 3460
@@ -2801,7 +3476,7 @@ inv\add_item "pants"
2801 3476
2802需è¦ç‰¹åˆ«æ³¨æ„的是,类的所有属性在其实例之间是共享的。这对于函数类型的æˆå‘˜å±žæ€§é€šå¸¸ä¸ä¼šé€ æˆé—®é¢˜ï¼Œä½†å¯¹äºŽå…¶ä»–类型的属性,å¯èƒ½ä¼šå¯¼è‡´æ„外的结果。 3477需è¦ç‰¹åˆ«æ³¨æ„的是,类的所有属性在其实例之间是共享的。这对于函数类型的æˆå‘˜å±žæ€§é€šå¸¸ä¸ä¼šé€ æˆé—®é¢˜ï¼Œä½†å¯¹äºŽå…¶ä»–类型的属性,å¯èƒ½ä¼šå¯¼è‡´æ„外的结果。
2803 3478
2804例如,在下é¢çš„示例中,clothes属性在所有实例之间共享。因此,对这个属性在一个实例中的修改,将会影å“到其他所有实例。 3479例如,在下é¢çš„示例中,clothes 属性在所有实例之间共享。因此,对这个属性在一个实例中的修改,将会影å“到其他所有实例。
2805 3480
2806```moonscript 3481```moonscript
2807class Person 3482class Person
@@ -2853,7 +3528,7 @@ class Person
2853 3528
2854### 继承 3529### 继承
2855 3530
2856`extends`关键字å¯ä»¥åœ¨ç±»å£°æ˜Žä¸­ä½¿ç”¨ï¼Œä»¥ç»§æ‰¿å¦ä¸€ä¸ªç±»çš„属性和方法。 3531`extends` 关键字å¯ä»¥åœ¨ç±»å£°æ˜Žä¸­ä½¿ç”¨ï¼Œä»¥ç»§æ‰¿å¦ä¸€ä¸ªç±»çš„属性和方法。
2857 3532
2858```moonscript 3533```moonscript
2859class BackPack extends Inventory 3534class BackPack extends Inventory
@@ -2873,11 +3548,11 @@ class BackPack extends Inventory
2873</YueDisplay> 3548</YueDisplay>
2874 3549
2875 3550
2876在这一部分,我们对月之脚本中的`Inventory`类进行了扩展,加入了对å¯ä»¥æºå¸¦ç‰©å“æ•°é‡çš„é™åˆ¶ã€‚ 3551在这一部分,我们对月之脚本中的 `Inventory` 类进行了扩展,加入了对å¯ä»¥æºå¸¦ç‰©å“æ•°é‡çš„é™åˆ¶ã€‚
2877 3552
2878在这个特定的例å­ä¸­ï¼Œå­ç±»å¹¶æ²¡æœ‰å®šä¹‰è‡ªå·±çš„æž„造函数。因此,当创建一个新的实例时,系统会默认调用父类的构造函数。但如果我们在å­ç±»ä¸­å®šä¹‰äº†æž„造函数,我们å¯ä»¥åˆ©ç”¨`super`方法æ¥è°ƒç”¨å¹¶æ‰§è¡Œçˆ¶ç±»çš„æž„造函数。 3553在这个特定的例å­ä¸­ï¼Œå­ç±»å¹¶æ²¡æœ‰å®šä¹‰è‡ªå·±çš„æž„造函数。因此,当创建一个新的实例时,系统会默认调用父类的构造函数。但如果我们在å­ç±»ä¸­å®šä¹‰äº†æž„造函数,我们å¯ä»¥åˆ©ç”¨ `super` 方法æ¥è°ƒç”¨å¹¶æ‰§è¡Œçˆ¶ç±»çš„æž„造函数。
2879 3554
2880此外,当一个类继承自å¦ä¸€ä¸ªç±»æ—¶ï¼Œå®ƒä¼šå°è¯•调用父类上的`__inherited`方法(如果这个方法存在的è¯ï¼‰ï¼Œä»¥æ­¤æ¥å‘父类å‘é€é€šçŸ¥ã€‚这个`__inherited`函数接å—ä¸¤ä¸ªå‚æ•°ï¼šè¢«ç»§æ‰¿çš„父类和继承的å­ç±»ã€‚ 3555此外,当一个类继承自å¦ä¸€ä¸ªç±»æ—¶ï¼Œå®ƒä¼šå°è¯•调用父类上的 `__inherited` 方法(如果这个方法存在的è¯ï¼‰ï¼Œä»¥æ­¤æ¥å‘父类å‘é€é€šçŸ¥ã€‚这个 `__inherited` 函数接å—ä¸¤ä¸ªå‚æ•°ï¼šè¢«ç»§æ‰¿çš„父类和继承的å­ç±»ã€‚
2881 3556
2882```moonscript 3557```moonscript
2883class Shelf 3558class Shelf
@@ -2900,15 +3575,15 @@ class Cupboard extends Shelf
2900 3575
2901### super 关键字 3576### super 关键字
2902 3577
2903`super`是一个特别的关键字,它有两ç§ä¸åŒçš„使用方å¼ï¼šæ—¢å¯ä»¥å½“作一个对象æ¥çœ‹å¾…,也å¯ä»¥åƒè°ƒç”¨å‡½æ•°é‚£æ ·ä½¿ç”¨ã€‚它仅在类的内部使用时具有特殊的功能。 3578`super` 是一个特别的关键字,它有两ç§ä¸åŒçš„使用方å¼ï¼šæ—¢å¯ä»¥å½“作一个对象æ¥çœ‹å¾…,也å¯ä»¥åƒè°ƒç”¨å‡½æ•°é‚£æ ·ä½¿ç”¨ã€‚它仅在类的内部使用时具有特殊的功能。
2904 3579
2905当`super`被作为一个函数调用时,它将调用父类中与之åŒå的函数。此时,当å‰çš„`self`ä¼šè‡ªåŠ¨ä½œä¸ºç¬¬ä¸€ä¸ªå‚æ•°ä¼ é€’ï¼Œæ­£å¦‚ä¸Šé¢æåˆ°çš„ç»§æ‰¿ç¤ºä¾‹æ‰€å±•ç¤ºçš„é‚£æ ·ã€‚ 3580当 `super` 被作为一个函数调用时,它将调用父类中与之åŒå的函数。此时,当å‰çš„ `self` ä¼šè‡ªåŠ¨ä½œä¸ºç¬¬ä¸€ä¸ªå‚æ•°ä¼ é€’ï¼Œæ­£å¦‚ä¸Šé¢æåˆ°çš„ç»§æ‰¿ç¤ºä¾‹æ‰€å±•ç¤ºçš„é‚£æ ·ã€‚
2906 3581
2907在将`super`å½“ä½œæ™®é€šå€¼ä½¿ç”¨æ—¶ï¼Œå®ƒå®žé™…ä¸Šæ˜¯å¯¹çˆ¶ç±»å¯¹è±¡çš„å¼•ç”¨ã€‚é€šè¿‡è¿™ç§æ–¹å¼ï¼Œæˆ‘们å¯ä»¥è®¿é—®çˆ¶ç±»ä¸­å¯èƒ½è¢«å­ç±»è¦†ç›–的值,就åƒè®¿é—®ä»»ä½•普通对象一样。 3582在将 `super` å½“ä½œæ™®é€šå€¼ä½¿ç”¨æ—¶ï¼Œå®ƒå®žé™…ä¸Šæ˜¯å¯¹çˆ¶ç±»å¯¹è±¡çš„å¼•ç”¨ã€‚é€šè¿‡è¿™ç§æ–¹å¼ï¼Œæˆ‘们å¯ä»¥è®¿é—®çˆ¶ç±»ä¸­å¯èƒ½è¢«å­ç±»è¦†ç›–的值,就åƒè®¿é—®ä»»ä½•普通对象一样。
2908 3583
2909此外,当使用`\`æ“作符与`super`一起使用时,`self`将被æ’å…¥ä¸ºç¬¬ä¸€ä¸ªå‚æ•°ï¼Œè€Œä¸æ˜¯ä½¿ç”¨`super`本身的值。而在使用`.`æ“ä½œç¬¦æ¥æ£€ç´¢å‡½æ•°æ—¶ï¼Œåˆ™ä¼šè¿”回父类中的原始函数。 3584此外,当使用 `\` æ“作符与 `super` 一起使用时,`self`将被æ’å…¥ä¸ºç¬¬ä¸€ä¸ªå‚æ•°ï¼Œè€Œä¸æ˜¯ä½¿ç”¨ `super` 本身的值。而在使用`.`æ“ä½œç¬¦æ¥æ£€ç´¢å‡½æ•°æ—¶ï¼Œåˆ™ä¼šè¿”回父类中的原始函数。
2910 3585
2911䏋颿˜¯ä¸€äº›ä½¿ç”¨`super`çš„ä¸åŒæ–¹æ³•的示例: 3586䏋颿˜¯ä¸€äº›ä½¿ç”¨ `super` çš„ä¸åŒæ–¹æ³•的示例:
2912 3587
2913```moonscript 3588```moonscript
2914class MyClass extends ParentClass 3589class MyClass extends ParentClass
@@ -2967,9 +3642,9 @@ print BackPack.size -- æ‰“å° 10
2967 3642
2968如果在类对象的元表中找ä¸åˆ°æŸä¸ªå±žæ€§ï¼Œç³»ç»Ÿä¼šä»ŽåŸºè¡¨ä¸­æ£€ç´¢è¯¥å±žæ€§ã€‚这就æ„å‘³ç€æˆ‘们å¯ä»¥ç›´æŽ¥ä»Žç±»æœ¬èº«è®¿é—®åˆ°å…¶æ–¹æ³•和属性。 3643如果在类对象的元表中找ä¸åˆ°æŸä¸ªå±žæ€§ï¼Œç³»ç»Ÿä¼šä»ŽåŸºè¡¨ä¸­æ£€ç´¢è¯¥å±žæ€§ã€‚这就æ„å‘³ç€æˆ‘们å¯ä»¥ç›´æŽ¥ä»Žç±»æœ¬èº«è®¿é—®åˆ°å…¶æ–¹æ³•和属性。
2969 3644
2970需è¦ç‰¹åˆ«æ³¨æ„的是,对类对象的赋值并ä¸ä¼šå½±å“åˆ°åŸºè¡¨ï¼Œå› æ­¤è¿™ä¸æ˜¯å‘实例添加新方法的正确方å¼ã€‚相å,需è¦ç›´æŽ¥ä¿®æ”¹åŸºè¡¨ã€‚关于这点,å¯ä»¥å‚考下é¢çš„“__baseâ€å­—段。 3645需è¦ç‰¹åˆ«æ³¨æ„的是,对类对象的赋值并ä¸ä¼šå½±å“åˆ°åŸºè¡¨ï¼Œå› æ­¤è¿™ä¸æ˜¯å‘实例添加新方法的正确方å¼ã€‚相å,需è¦ç›´æŽ¥ä¿®æ”¹åŸºè¡¨ã€‚关于这点,å¯ä»¥å‚考下é¢çš„ “__base†字段。
2971 3646
2972此外,类对象包å«å‡ ä¸ªç‰¹æ®Šçš„属性:当类被声明时,类的å称会作为一个字符串存储在类对象的“__nameâ€å­—段中。 3647此外,类对象包å«å‡ ä¸ªç‰¹æ®Šçš„属性:当类被声明时,类的å称会作为一个字符串存储在类对象的 “__name†字段中。
2973 3648
2974```moonscript 3649```moonscript
2975print BackPack.__name -- æ‰“å° Backpack 3650print BackPack.__name -- æ‰“å° Backpack
@@ -3051,7 +3726,7 @@ print Counter.count -- 输出 2
3051 3726
3052### ç±»å£°æ˜Žè¯­å¥ 3727### 类声明语å¥
3053 3728
3054在类声明的主体中,除了键/值对外,我们还å¯ä»¥ç¼–写普通的表达å¼ã€‚在这ç§ç±»å£°æ˜Žä½“中的普通代ç çš„上下文中,selfç­‰äºŽç±»å¯¹è±¡ï¼Œè€Œä¸æ˜¯å®žä¾‹å¯¹è±¡ã€‚ 3729在类声明的主体中,除了键/值对外,我们还å¯ä»¥ç¼–写普通的表达å¼ã€‚在这ç§ç±»å£°æ˜Žä½“中的普通代ç çš„上下文中,self ç­‰äºŽç±»å¯¹è±¡ï¼Œè€Œä¸æ˜¯å®žä¾‹å¯¹è±¡ã€‚
3055 3730
3056以下是创建类å˜é‡çš„å¦ä¸€ç§æ–¹æ³•: 3731以下是创建类å˜é‡çš„å¦ä¸€ç§æ–¹æ³•:
3057 3732
@@ -3091,9 +3766,9 @@ class MoreThings
3091 3766
3092### @ 和 @@ 值 3767### @ 和 @@ 值
3093 3768
3094当@å’Œ@@å‰ç¼€åœ¨ä¸€ä¸ªå字剿—¶ï¼Œå®ƒä»¬åˆ†åˆ«ä»£è¡¨åœ¨selfå’Œself.\_\_class中访问的那个å字。 3769当 @ å’Œ @@ å‰ç¼€åœ¨ä¸€ä¸ªå字剿—¶ï¼Œå®ƒä»¬åˆ†åˆ«ä»£è¡¨åœ¨ self å’Œ self.\_\_class 中访问的那个å字。
3095 3770
3096如果它们å•独使用,它们是selfå’Œself.\_\_class的别å。 3771如果它们å•独使用,它们是 self å’Œ self.\_\_class 的别å。
3097 3772
3098```moonscript 3773```moonscript
3099assert @ == self 3774assert @ == self
@@ -3106,7 +3781,7 @@ assert @@ == self.__class
3106</pre> 3781</pre>
3107</YueDisplay> 3782</YueDisplay>
3108 3783
3109例如,使用@@从实例方法快速创建åŒä¸€ç±»çš„æ–°å®žä¾‹çš„æ–¹æ³•: 3784例如,使用 @@ 从实例方法快速创建åŒä¸€ç±»çš„æ–°å®žä¾‹çš„æ–¹æ³•:
3110 3785
3111```moonscript 3786```moonscript
3112some_instance_method = (...) => @@ ... 3787some_instance_method = (...) => @@ ...
@@ -3184,7 +3859,7 @@ x = class Bucket
3184 3859
3185### 匿åç±» 3860### 匿åç±»
3186 3861
3187声明类时å¯ä»¥çœç•¥å称。如果类的表达å¼ä¸åœ¨èµ‹å€¼è¯­å¥ä¸­ï¼Œ\_\_name属性将为nil。如果出现在赋值语å¥ä¸­ï¼Œèµ‹å€¼æ“作左侧的å称将代替nil。 3862声明类时å¯ä»¥çœç•¥å称。如果类的表达å¼ä¸åœ¨èµ‹å€¼è¯­å¥ä¸­ï¼Œ\_\_name 属性将为 nil。如果出现在赋值语å¥ä¸­ï¼Œèµ‹å€¼æ“作左侧的å称将代替 nil。
3188 3863
3189```moonscript 3864```moonscript
3190BigBucket = class extends Bucket 3865BigBucket = class extends Bucket
@@ -3214,7 +3889,7 @@ x = class
3214 3889
3215### ç±»æ··åˆ 3890### 类混åˆ
3216 3891
3217您å¯ä»¥é€šè¿‡ä½¿ç”¨ `using` 关键字æ¥å®žçŽ°ç±»æ··åˆã€‚è¿™æ„å‘³ç€æ‚¨å¯ä»¥ä»Žä¸€ä¸ªæ™®é€š Lua 表格或已定义的类对象中,å¤åˆ¶å‡½æ•°åˆ°æ‚¨åˆ›å»ºçš„æ–°ç±»ä¸­ã€‚当您使用普通 Lua è¡¨æ ¼è¿›è¡Œç±»æ··åˆæ—¶ï¼Œæ‚¨æœ‰æœºä¼šç”¨è‡ªå·±çš„实现æ¥é‡å†™ç±»çš„索引方法(例如元方法 `__index`ï¼‰ã€‚ç„¶è€Œï¼Œå½“æ‚¨ä»Žä¸€ä¸ªç±»å¯¹è±¡åšæ··åˆæ—¶ï¼Œéœ€è¦æ³¨æ„的是该类对象的元方法将ä¸ä¼šè¢«å¤åˆ¶åˆ°æ–°ç±»ã€‚ 3892ä½ å¯ä»¥é€šè¿‡ä½¿ç”¨ `using` 关键字æ¥å®žçŽ°ç±»æ··åˆã€‚è¿™æ„味ç€ä½ å¯ä»¥ä»Žä¸€ä¸ªæ™®é€š Lua 表格或已定义的类对象中,å¤åˆ¶å‡½æ•°åˆ°ä½ åˆ›å»ºçš„æ–°ç±»ä¸­ã€‚当你使用普通 Lua è¡¨æ ¼è¿›è¡Œç±»æ··åˆæ—¶ï¼Œä½ æœ‰æœºä¼šç”¨è‡ªå·±çš„实现æ¥é‡å†™ç±»çš„索引方法(例如元方法 `__index`ï¼‰ã€‚ç„¶è€Œï¼Œå½“ä½ ä»Žä¸€ä¸ªç±»å¯¹è±¡åšæ··åˆæ—¶ï¼Œéœ€è¦æ³¨æ„的是该类对象的元方法将ä¸ä¼šè¢«å¤åˆ¶åˆ°æ–°ç±»ã€‚
3218 3893
3219```moonscript 3894```moonscript
3220MyIndex = __index: var: 1 3895MyIndex = __index: var: 1
@@ -3255,11 +3930,11 @@ assert y.__class.__parent ~= X -- X 䏿˜¯ Y 的父类
3255 3930
3256## with è¯­å¥ 3931## with 语å¥
3257 3932
3258在编写Luaä»£ç æ—¶ï¼Œæˆ‘们在创建对象åŽçš„å¸¸è§æ“作是立å³è°ƒç”¨è¿™ä¸ªå¯¹è±¡ä¸€ç³»åˆ—æ“作函数并设置一系列属性。 3933在编写 Lua ä»£ç æ—¶ï¼Œæˆ‘们在创建对象åŽçš„å¸¸è§æ“作是立å³è°ƒç”¨è¿™ä¸ªå¯¹è±¡ä¸€ç³»åˆ—æ“作函数并设置一系列属性。
3259 3934
3260这导致在代ç ä¸­å¤šæ¬¡é‡å¤å¼•用对象的å称,增加了ä¸å¿…è¦çš„æ–‡æœ¬å™ªéŸ³ã€‚一个常è§çš„解决方案是在创建对象时,在构造函数传入一个表,该表包å«è¦è¦†ç›–设置的键和值的集åˆã€‚这样åšçš„缺点是该对象的构造函数必须支æŒè¿™ç§åˆå§‹åŒ–å½¢å¼ã€‚ 3935这导致在代ç ä¸­å¤šæ¬¡é‡å¤å¼•用对象的å称,增加了ä¸å¿…è¦çš„æ–‡æœ¬å™ªéŸ³ã€‚一个常è§çš„解决方案是在创建对象时,在构造函数传入一个表,该表包å«è¦è¦†ç›–设置的键和值的集åˆã€‚这样åšçš„缺点是该对象的构造函数必须支æŒè¿™ç§åˆå§‹åŒ–å½¢å¼ã€‚
3261 3936
3262withå—æœ‰åŠ©äºŽç®€åŒ–ç¼–å†™è¿™æ ·çš„ä»£ç ã€‚在withå—内,我们å¯ä»¥ä½¿ç”¨ä»¥.或\开头的特殊语å¥ï¼Œè¿™äº›è¯­å¥ä»£è¡¨æˆ‘们正在使用的对象的æ“作。 3937with å—æœ‰åŠ©äºŽç®€åŒ–ç¼–å†™è¿™æ ·çš„ä»£ç ã€‚在 with å—内,我们å¯ä»¥ä½¿ç”¨ä»¥ . 或 \ 开头的特殊语å¥ï¼Œè¿™äº›è¯­å¥ä»£è¡¨æˆ‘们正在使用的对象的æ“作。
3263 3938
3264例如,我们å¯ä»¥è¿™æ ·å¤„ç†ä¸€ä¸ªæ–°åˆ›å»ºçš„对象: 3939例如,我们å¯ä»¥è¿™æ ·å¤„ç†ä¸€ä¸ªæ–°åˆ›å»ºçš„对象:
3265 3940
@@ -3280,7 +3955,7 @@ with Person!
3280</pre> 3955</pre>
3281</YueDisplay> 3956</YueDisplay>
3282 3957
3283with语å¥ä¹Ÿå¯ä»¥ç”¨ä½œä¸€ä¸ªè¡¨è¾¾å¼ï¼Œå¹¶è¿”回它的代ç å—正在处ç†çš„对象。 3958with 语å¥ä¹Ÿå¯ä»¥ç”¨ä½œä¸€ä¸ªè¡¨è¾¾å¼ï¼Œå¹¶è¿”回它的代ç å—正在处ç†çš„对象。
3284 3959
3285```moonscript 3960```moonscript
3286file = with File "favorite_foods.txt" 3961file = with File "favorite_foods.txt"
@@ -3314,24 +3989,24 @@ me = create_person "Leaf", [dad, mother, sister]
3314</pre> 3989</pre>
3315</YueDisplay> 3990</YueDisplay>
3316 3991
3317在此用法中,withå¯ä»¥è¢«è§†ä¸ºK组åˆå­ï¼ˆk-combinator)的一ç§ç‰¹æ®Šå½¢å¼ã€‚ 3992在此用法中,with å¯ä»¥è¢«è§†ä¸ºK组åˆå­ï¼ˆk-combinator)的一ç§ç‰¹æ®Šå½¢å¼ã€‚
3318 3993
3319如果您想给表达å¼å¦å¤–起一个åç§°çš„è¯ï¼Œwith语å¥ä¸­çš„表达å¼ä¹Ÿå¯ä»¥æ˜¯ä¸€ä¸ªèµ‹å€¼è¯­å¥ã€‚ 3994如果你想给表达å¼å¦å¤–起一个åç§°çš„è¯ï¼Œwith 语å¥ä¸­çš„表达å¼ä¹Ÿå¯ä»¥æ˜¯ä¸€ä¸ªèµ‹å€¼è¯­å¥ã€‚
3320 3995
3321```moonscript 3996```moonscript
3322with str = "你好" 3997with str := "你好"
3323 print "原始:", str 3998 print "原始:", str
3324 print "大写:", \upper! 3999 print "大写:", \upper!
3325``` 4000```
3326<YueDisplay> 4001<YueDisplay>
3327<pre> 4002<pre>
3328with str = "你好" 4003with str := "你好"
3329 print "原始:", str 4004 print "原始:", str
3330 print "大写:", \upper! 4005 print "大写:", \upper!
3331</pre> 4006</pre>
3332</YueDisplay> 4007</YueDisplay>
3333 4008
3334在with语å¥ä¸­å¯ä»¥ä½¿ç”¨`[]`访问特殊键。 4009ä½ å¯ä»¥åœ¨ `with` 语å¥ä¸­ä½¿ç”¨ `[]` 访问特殊键。
3335 4010
3336```moonscript 4011```moonscript
3337with tb 4012with tb
@@ -3354,9 +4029,22 @@ with tb
3354</pre> 4029</pre>
3355</YueDisplay> 4030</YueDisplay>
3356 4031
4032`with?` 是 `with` è¯­æ³•çš„ä¸€ä¸ªå¢žå¼ºç‰ˆæœ¬ï¼Œå¼•å…¥äº†å­˜åœ¨æ€§æ£€æŸ¥ï¼Œç”¨äºŽåœ¨ä¸æ˜¾å¼åˆ¤ç©ºçš„æƒ…况下安全访问å¯èƒ½ä¸º nil 的对象。
4033
4034```moonscript
4035with? obj
4036 print obj.name
4037```
4038<YueDisplay>
4039<pre>
4040with? obj
4041 print obj.name
4042</pre>
4043</YueDisplay>
4044
3357## do è¯­å¥ 4045## do 语å¥
3358 4046
3359å½“ç”¨ä½œè¯­å¥æ—¶ï¼Œdo语å¥çš„作用就åƒåœ¨Lua中差ä¸å¤šã€‚ 4047å½“ç”¨ä½œè¯­å¥æ—¶ï¼Œdo 语å¥çš„作用就åƒåœ¨ Lua 中差ä¸å¤šã€‚
3360 4048
3361```moonscript 4049```moonscript
3362do 4050do
@@ -3373,7 +4061,7 @@ print var -- 这里是nil
3373</pre> 4061</pre>
3374</YueDisplay> 4062</YueDisplay>
3375 4063
3376月之脚本的 **do** 也å¯ä»¥ç”¨ä½œè¡¨è¾¾å¼ã€‚å…许您将多行代ç çš„处ç†åˆå¹¶ä¸ºä¸€ä¸ªè¡¨è¾¾å¼ï¼Œå¹¶å°†do语å¥ä»£ç å—的最åŽä¸€ä¸ªè¯­å¥ä½œä¸ºè¡¨è¾¾å¼è¿”回的结果。 4064月之脚本的 **do** 也å¯ä»¥ç”¨ä½œè¡¨è¾¾å¼ã€‚å…许你将多行代ç çš„处ç†åˆå¹¶ä¸ºä¸€ä¸ªè¡¨è¾¾å¼ï¼Œå¹¶å°† do 语å¥ä»£ç å—的最åŽä¸€ä¸ªè¯­å¥ä½œä¸ºè¡¨è¾¾å¼è¿”回的结果。
3377 4065
3378```moonscript 4066```moonscript
3379counter = do 4067counter = do
@@ -3557,7 +4245,7 @@ print i, k -- 这些已ç»è¢«æ›´æ–°
3557 4245
3558## 月之脚本语言库 4246## 月之脚本语言库
3559 4247
3560使用`require("yue")`æ¥è®¿é—®ã€‚ 4248使用 `require("yue")` æ¥è®¿é—®ã€‚
3561 4249
3562### yue 4250### yue
3563 4251
@@ -3615,9 +4303,9 @@ yue_compiled: {string: string}
3615**ç­¾å:** 4303**ç­¾å:**
3616```lua 4304```lua
3617to_lua: function(code: string, config?: Config): 4305to_lua: function(code: string, config?: Config):
3618 --[[codes]] string | nil, 4306 --[[codes]] string | nil,
3619 --[[error]] string | nil, 4307 --[[error]] string | nil,
3620 --[[globals]] {{string, integer, integer}} | nil 4308 --[[globals]] {{string, integer, integer}} | nil
3621``` 4309```
3622 4310
3623**傿•°ï¼š** 4311**傿•°ï¼š**
@@ -3740,8 +4428,8 @@ remove_loader: function(): boolean
3740**ç­¾å:** 4428**ç­¾å:**
3741```lua 4429```lua
3742loadstring: function(input: string, chunkname: string, env: table, config?: Config): 4430loadstring: function(input: string, chunkname: string, env: table, config?: Config):
3743 --[[loaded function]] nil | function(...: any): (any...), 4431 --[[loaded function]] nil | function(...: any): (any...),
3744 --[[error]] string | nil 4432 --[[error]] string | nil
3745``` 4433```
3746 4434
3747**傿•°ï¼š** 4435**傿•°ï¼š**
@@ -3771,8 +4459,8 @@ loadstring: function(input: string, chunkname: string, env: table, config?: Conf
3771**ç­¾å:** 4459**ç­¾å:**
3772```lua 4460```lua
3773loadstring: function(input: string, chunkname: string, config?: Config): 4461loadstring: function(input: string, chunkname: string, config?: Config):
3774 --[[loaded function]] nil | function(...: any): (any...), 4462 --[[loaded function]] nil | function(...: any): (any...),
3775 --[[error]] string | nil 4463 --[[error]] string | nil
3776``` 4464```
3777 4465
3778**傿•°ï¼š** 4466**傿•°ï¼š**
@@ -3801,8 +4489,8 @@ loadstring: function(input: string, chunkname: string, config?: Config):
3801**ç­¾å:** 4489**ç­¾å:**
3802```lua 4490```lua
3803loadstring: function(input: string, config?: Config): 4491loadstring: function(input: string, config?: Config):
3804 --[[loaded function]] nil | function(...: any): (any...), 4492 --[[loaded function]] nil | function(...: any): (any...),
3805 --[[error]] string | nil 4493 --[[error]] string | nil
3806``` 4494```
3807 4495
3808**傿•°ï¼š** 4496**傿•°ï¼š**
@@ -3830,8 +4518,8 @@ loadstring: function(input: string, config?: Config):
3830**ç­¾å:** 4518**ç­¾å:**
3831```lua 4519```lua
3832loadfile: function(filename: string, env: table, config?: Config): 4520loadfile: function(filename: string, env: table, config?: Config):
3833 nil | function(...: any): (any...), 4521 nil | function(...: any): (any...),
3834 string | nil 4522 string | nil
3835``` 4523```
3836 4524
3837**傿•°ï¼š** 4525**傿•°ï¼š**
@@ -3860,8 +4548,8 @@ loadfile: function(filename: string, env: table, config?: Config):
3860**ç­¾å:** 4548**ç­¾å:**
3861```lua 4549```lua
3862loadfile: function(filename: string, config?: Config): 4550loadfile: function(filename: string, config?: Config):
3863 nil | function(...: any): (any...), 4551 nil | function(...: any): (any...),
3864 string | nil 4552 string | nil
3865``` 4553```
3866 4554
3867**傿•°ï¼š** 4555**傿•°ï¼š**
@@ -4116,9 +4804,9 @@ type AST = {string, integer, integer, any}
4116 4804
4117**ç­¾å:** 4805**ç­¾å:**
4118```lua 4806```lua
4119to_ast: function(code: string, flattenLevel?: number, astName?: string): 4807to_ast: function(code: string, flattenLevel?: number, astName?: string, reserveComment?: boolean):
4120 --[[AST]] AST | nil, 4808 --[[AST]] AST | nil,
4121 --[[error]] nil | string 4809 --[[error]] nil | string
4122``` 4810```
4123 4811
4124**傿•°ï¼š** 4812**傿•°ï¼š**
@@ -4127,6 +4815,42 @@ to_ast: function(code: string, flattenLevel?: number, astName?: string):
4127| --- | --- | --- | 4815| --- | --- | --- |
4128| code | string | 代ç ã€‚ | 4816| code | string | 代ç ã€‚ |
4129| flattenLevel | integer | [å¯é€‰] æ‰å¹³åŒ–级别。级别越高,会消除更多的 AST 结构的嵌套。默认为 0。最大为 2。 | 4817| flattenLevel | integer | [å¯é€‰] æ‰å¹³åŒ–级别。级别越高,会消除更多的 AST 结构的嵌套。默认为 0。最大为 2。 |
4818| astName | string | [å¯é€‰] AST å称。默认为 "File"。 |
4819| reserveComment | boolean | [å¯é€‰] 是å¦ä¿ç•™åŽŸå§‹æ³¨é‡Šã€‚é»˜è®¤ä¸º false。 |
4820
4821**返回值:**
4822
4823| 返回类型 | æè¿° |
4824| --- | --- |
4825| AST \| nil | AST,如果转æ¢å¤±è´¥åˆ™ä¸º nil。 |
4826| string \| nil | 错误消æ¯ï¼Œå¦‚æžœè½¬æ¢æˆåŠŸåˆ™ä¸º nil。 |
4827
4828#### format
4829
4830**类型:** 函数。
4831
4832**æè¿°ï¼š**
4833
4834æ ¼å¼åŒ– YueScript 代ç ã€‚
4835
4836**ç­¾å:**
4837```lua
4838format: function(code: string, tabSize?: number, reserveComment?: boolean): string
4839```
4840
4841**傿•°ï¼š**
4842
4843| 傿•°å | 类型 | æè¿° |
4844| --- | --- | --- |
4845| code | string | 代ç ã€‚ |
4846| tabSize | integer | [å¯é€‰] 制表符大å°ã€‚默认为 4。 |
4847| reserveComment | boolean | [å¯é€‰] 是å¦ä¿ç•™åŽŸå§‹æ³¨é‡Šã€‚é»˜è®¤ä¸º true。 |
4848
4849**返回值:**
4850
4851| 返回类型 | æè¿° |
4852| --- | --- |
4853| string | æ ¼å¼åŒ–åŽçš„代ç ã€‚ |
4130 4854
4131#### __call 4855#### __call
4132 4856
@@ -4199,6 +4923,19 @@ implicit_return_root: boolean
4199reserve_line_number: boolean 4923reserve_line_number: boolean
4200``` 4924```
4201 4925
4926#### reserve_comment
4927
4928**类型:** æˆå‘˜å˜é‡ã€‚
4929
4930**æè¿°ï¼š**
4931
4932编译器是å¦åº”该在编译åŽçš„代ç ä¸­ä¿ç•™åŽŸå§‹æ³¨é‡Šã€‚
4933
4934**ç­¾å:**
4935```lua
4936reserve_comment: boolean
4937```
4938
4202#### space_over_tab 4939#### space_over_tab
4203 4940
4204**类型:** æˆå‘˜å˜é‡ã€‚ 4941**类型:** æˆå‘˜å˜é‡ã€‚
@@ -4249,11 +4986,11 @@ line_offset: integer
4249**ç­¾å:** 4986**ç­¾å:**
4250```lua 4987```lua
4251enum LuaTarget 4988enum LuaTarget
4252 "5.1" 4989 "5.1"
4253 "5.2" 4990 "5.2"
4254 "5.3" 4991 "5.3"
4255 "5.4" 4992 "5.4"
4256 "5.5" 4993 "5.5"
4257end 4994end
4258``` 4995```
4259 4996
@@ -4332,8 +5069,8 @@ simplified: boolean
4332 5069
4333ç‰ˆæƒ (c) 2017-2025 æŽç‘¾ \<dragon-fly@qq.com\> 5070ç‰ˆæƒ (c) 2017-2025 æŽç‘¾ \<dragon-fly@qq.com\>
4334 5071
4335特此å…费授予任何获得本软件副本和相关文档文件(下称“软件â€ï¼‰çš„人ä¸å—é™åˆ¶åœ°å¤„置该软件的æƒåˆ©ï¼ŒåŒ…括ä¸å—é™åˆ¶åœ°ä½¿ç”¨ã€å¤åˆ¶ã€ä¿®æ”¹ã€åˆå¹¶ã€å‘布ã€åˆ†å‘ã€è½¬æŽˆè®¸å¯å’Œ/或出售该软件副本,以åŠå†æŽˆæƒè¢«é…å‘了本软件的人如上的æƒåˆ©ï¼Œé¡»åœ¨ä¸‹åˆ—æ¡ä»¶ä¸‹ï¼š 5072特此å…费授予任何获得本软件副本和相关文档文件(下称“软件â€ï¼‰çš„人ä¸å—é™åˆ¶åœ°å¤„置该软件的æƒåˆ©ï¼ŒåŒ…括ä¸å—é™åˆ¶åœ°ä½¿ç”¨ã€å¤åˆ¶ã€ä¿®æ”¹ã€åˆå¹¶ã€å‘布ã€åˆ†å‘ã€è½¬æŽˆè®¸å¯å’Œ/或出售该软件副本,以åŠå†æŽˆæƒè¢«é…å‘了本软件的人如上的æƒåˆ©ï¼Œé¡»åœ¨ä¸‹åˆ—æ¡ä»¶ä¸‹ï¼š
4336上述版æƒå£°æ˜Žå’Œæœ¬è®¸å¯å£°æ˜Žåº”包å«åœ¨è¯¥è½¯ä»¶çš„æ‰€æœ‰å‰¯æœ¬æˆ–实质æˆåˆ†ä¸­ã€‚ 5073上述版æƒå£°æ˜Žå’Œæœ¬è®¸å¯å£°æ˜Žåº”包å«åœ¨è¯¥è½¯ä»¶çš„æ‰€æœ‰å‰¯æœ¬æˆ–实质æˆåˆ†ä¸­ã€‚
4337æœ¬è½¯ä»¶æ˜¯â€œå¦‚æ­¤â€æä¾›çš„ï¼Œæ²¡æœ‰ä»»ä½•å½¢å¼çš„æ˜Žç¤ºæˆ–暗示的ä¿è¯ï¼ŒåŒ…括但ä¸é™äºŽå¯¹é€‚销性ã€ç‰¹å®šç”¨é€”的适用性和ä¸ä¾µæƒçš„ä¿è¯ã€‚åœ¨ä»»ä½•æƒ…å†µä¸‹ï¼Œä½œè€…æˆ–ç‰ˆæƒæŒæœ‰äººéƒ½ä¸å¯¹ä»»ä½•ç´¢èµ”ã€æŸå®³æˆ–其他责任负责,无论这些追责æ¥è‡ªåˆåŒã€ä¾µæƒæˆ–å…¶å®ƒè¡Œä¸ºä¸­ï¼Œè¿˜æ˜¯äº§ç”ŸäºŽã€æºäºŽæˆ–æœ‰å…³äºŽæœ¬è½¯ä»¶ä»¥åŠæœ¬è½¯ä»¶çš„使用或其它处置。 5074æœ¬è½¯ä»¶æ˜¯â€œå¦‚æ­¤â€æä¾›çš„ï¼Œæ²¡æœ‰ä»»ä½•å½¢å¼çš„æ˜Žç¤ºæˆ–暗示的ä¿è¯ï¼ŒåŒ…括但ä¸é™äºŽå¯¹é€‚销性ã€ç‰¹å®šç”¨é€”的适用性和ä¸ä¾µæƒçš„ä¿è¯ã€‚åœ¨ä»»ä½•æƒ…å†µä¸‹ï¼Œä½œè€…æˆ–ç‰ˆæƒæŒæœ‰äººéƒ½ä¸å¯¹ä»»ä½•ç´¢èµ”ã€æŸå®³æˆ–其他责任负责,无论这些追责æ¥è‡ªåˆåŒã€ä¾µæƒæˆ–å…¶å®ƒè¡Œä¸ºä¸­ï¼Œè¿˜æ˜¯äº§ç”ŸäºŽã€æºäºŽæˆ–æœ‰å…³äºŽæœ¬è½¯ä»¶ä»¥åŠæœ¬è½¯ä»¶çš„使用或其它处置。
4338 5075
4339<CompilerModal /> 5076<CompilerModal />
diff --git a/makefile b/makefile
index d1b074a..047718a 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
@@ -390,8 +435,8 @@ test: debug
390 @./$(BIN_NAME) $(TEST_INPUT)/loops.yue -o $(TEST_OUTPUT)/5.1/loops.lua --target=5.1 435 @./$(BIN_NAME) $(TEST_INPUT)/loops.yue -o $(TEST_OUTPUT)/5.1/loops.lua --target=5.1
391 @./$(BIN_NAME) $(TEST_INPUT)/try_catch.yue -o $(TEST_OUTPUT)/5.1/try_catch.lua --target=5.1 436 @./$(BIN_NAME) $(TEST_INPUT)/try_catch.yue -o $(TEST_OUTPUT)/5.1/try_catch.lua --target=5.1
392 @./$(BIN_NAME) $(TEST_INPUT)/attrib.yue -o $(TEST_OUTPUT)/5.1/attrib.lua --target=5.1 437 @./$(BIN_NAME) $(TEST_INPUT)/attrib.yue -o $(TEST_OUTPUT)/5.1/attrib.lua --target=5.1
438 @./$(BIN_NAME) $(TEST_INPUT)/import_global.yue -o $(TEST_OUTPUT)/5.1/import_global.lua --target=5.1
393 @./$(BIN_NAME) $(TEST_INPUT)/test/loops_spec.yue -o $(TEST_OUTPUT)/5.1/test/loops_spec.lua --target=5.1 439 @./$(BIN_NAME) $(TEST_INPUT)/test/loops_spec.yue -o $(TEST_OUTPUT)/5.1/test/loops_spec.lua --target=5.1
394 @./$(BIN_NAME) $(TEST_INPUT)/literals.yue -o $(TEST_OUTPUT)/5.1/literals.lua --target=5.1
395 @./$(BIN_NAME) -e spec/inputs/compile_doc.yue $(TEST_OUTPUT) 440 @./$(BIN_NAME) -e spec/inputs/compile_doc.yue $(TEST_OUTPUT)
396 @echo -en "Compile time: " 441 @echo -en "Compile time: "
397 @$(END_TIME) 442 @$(END_TIME)
@@ -410,7 +455,7 @@ gen: release
410 @./$(BIN_NAME) $(TEST_INPUT)/loops.yue -o $(GEN_OUTPUT)/5.1/loops.lua --target=5.1 455 @./$(BIN_NAME) $(TEST_INPUT)/loops.yue -o $(GEN_OUTPUT)/5.1/loops.lua --target=5.1
411 @./$(BIN_NAME) $(TEST_INPUT)/try_catch.yue -o $(GEN_OUTPUT)/5.1/try_catch.lua --target=5.1 456 @./$(BIN_NAME) $(TEST_INPUT)/try_catch.yue -o $(GEN_OUTPUT)/5.1/try_catch.lua --target=5.1
412 @./$(BIN_NAME) $(TEST_INPUT)/attrib.yue -o $(GEN_OUTPUT)/5.1/attrib.lua --target=5.1 457 @./$(BIN_NAME) $(TEST_INPUT)/attrib.yue -o $(GEN_OUTPUT)/5.1/attrib.lua --target=5.1
413 @./$(BIN_NAME) $(TEST_INPUT)/literals.yue -o $(GEN_OUTPUT)/5.1/literals.lua --target=5.1 458 @./$(BIN_NAME) $(TEST_INPUT)/import_global.yue -o $(GEN_OUTPUT)/5.1/import_global.lua --target=5.1
414 @./$(BIN_NAME) $(TEST_INPUT)/test/loops_spec.yue -o $(GEN_OUTPUT)/5.1/test/loops_spec.lua --target=5.1 459 @./$(BIN_NAME) $(TEST_INPUT)/test/loops_spec.yue -o $(GEN_OUTPUT)/5.1/test/loops_spec.lua --target=5.1
415 @./$(BIN_NAME) -e spec/inputs/compile_doc.yue $(GEN_OUTPUT) 460 @./$(BIN_NAME) -e spec/inputs/compile_doc.yue $(GEN_OUTPUT)
416 @echo -en "Compile time: " 461 @echo -en "Compile time: "
@@ -442,3 +487,11 @@ $(BUILD_PATH)/%.o: $(SRC_PATH)/%.$(SRC_EXT)
442 $(CMD_PREFIX)$(CXX) $(CXXFLAGS) $(INCLUDES) -MP -MMD -c $< -o $@ 487 $(CMD_PREFIX)$(CXX) $(CXXFLAGS) $(INCLUDES) -MP -MMD -c $< -o $@
443 @echo -en "\t Compile time: " 488 @echo -en "\t Compile time: "
444 @$(END_TIME) 489 @$(END_TIME)
490
491# C source file rules
492$(BUILD_PATH)/%.o: $(SRC_PATH)/%.c
493 @echo "Compiling: $< -> $@"
494 @$(START_TIME)
495 $(CMD_PREFIX)$(CC) $(CFLAGS) $(INCLUDES) -MP -MMD -c $< -o $@
496 @echo -en "\t Compile time: "
497 @$(END_TIME)
diff --git a/spec/inputs/backcall.yue b/spec/inputs/backcall.yue
index 8aadc71..e6b8c21 100644
--- a/spec/inputs/backcall.yue
+++ b/spec/inputs/backcall.yue
@@ -13,9 +13,9 @@ do
13 x > 2 13 x > 2
14 14
15do 15do
16 (data) <- http?.get "ajaxtest" 16 data <- http?.get "ajaxtest"
17 body[".result"]\html data 17 body[".result"]\html data
18 (processed) <- http.post "ajaxprocess", data 18 processed <- http.post "ajaxprocess", data
19 body[".result"]\append processed 19 body[".result"]\append processed
20 <- setTimeout 1000 20 <- setTimeout 1000
21 print "done" 21 print "done"
diff --git a/spec/inputs/destructure.yue b/spec/inputs/destructure.yue
index 674dfe4..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/global.yue b/spec/inputs/global.yue
index ce1cc15..4e3b8aa 100644
--- a/spec/inputs/global.yue
+++ b/spec/inputs/global.yue
@@ -82,3 +82,9 @@ do
82 FooBar = "pascal case" 82 FooBar = "pascal case"
83 FOOBAR = "all uppercase" 83 FOOBAR = "all uppercase"
84 84
85do
86 global const class A
87 global const Flag = 1
88 global const const, x, y = "const", 1, 2
89 global const math, table
90
diff --git a/spec/inputs/import.yue b/spec/inputs/import.yue
index b8ffc24..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/import_global.yue b/spec/inputs/import_global.yue
new file mode 100644
index 0000000..18f0e85
--- /dev/null
+++ b/spec/inputs/import_global.yue
@@ -0,0 +1,93 @@
1
2do
3 import global
4 print "hello"
5 math.random 10
6
7do
8 import global
9 value = 1
10 value += 2
11 print value
12
13do
14 local print = (msg) ->
15 return msg
16 do
17 import global
18 print "local"
19 math.random 1
20
21do
22 import global
23 local tostring = (v) -> "local"
24 tostring "value"
25 print tostring 123
26
27do
28 func = (x, y) ->
29 import global
30 return type x, tostring y, print
31 func 1, 2
32
33do
34 import global
35 try
36 func "hello #{world}"
37 catch err
38 print err
39
40do
41 import global
42 global FLAG
43 print FLAG
44 FLAG = 123
45
46do
47 import global
48 global Foo = 10
49 print Foo
50 Foo += 2
51
52do
53 import global
54 global Bar, Baz
55 Bar = 1
56 Baz = 2
57 print Bar, Baz
58
59do
60 import global
61 global *
62 x = 3434
63 if y then
64 x = 10
65
66do
67 import global
68 global ^
69 foobar = "all #{lowercase}"
70 FooBar = "pascal case"
71 FOOBAR = "all #{Uppercase}"
72
73do
74 import global
75 global const class A
76 global const Flag = 1
77 global const const, x, y = "const", 1, 2
78 global const math, table
79 print math, table
80
81do
82 import global
83 with X
84 \func 1, 2, 3
85 .tag = "abc"
86
87do
88 import global
89
90 f = ->
91 func!
92 try func
93
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 c5b28b3..5df10ca 100644
--- a/spec/inputs/loops.yue
+++ b/spec/inputs/loops.yue
@@ -213,3 +213,55 @@ do
213do 213do
214 until x := func 'a', b do 214 until x := func 'a', b do
215 print "false expected" 215 print "false expected"
216
217do
218 index = for i = 1, #tb
219 break i if tb[i]
220
221 f for i = 1, #tb
222 break i if tb[i]
223
224 f for i = 1, #tb
225 i if tb[i]
226
227 i = 1
228 ids = while tb[i]
229 i += 1
230 i - 1
231
232 i = 1
233 idx = while tb[i]
234 i += 1
235 break i - 1
236
237 f1 = ->
238 i = 1
239 f while tb[i]
240 i += 1
241 i - 1
242
243 i = 1
244 f while tb[i]
245 i += 1
246 break i - 1
247
248 list = for item in *items
249 switch item
250 when type: "A", :value
251 if value > 5
252 item
253
254do
255 repeat print 1 until true
256
257 x = repeat
258 a = func!
259 break a.x
260 until a.v
261
262 items = repeat
263 item = getItem!
264 break unless item
265 item if item.value > 0
266 until false
267
diff --git a/spec/inputs/macro.yue b/spec/inputs/macro.yue
index 5d5f1a9..191f09f 100644
--- a/spec/inputs/macro.yue
+++ b/spec/inputs/macro.yue
@@ -60,6 +60,11 @@ macro NumAndStr = (num, str) ->
60 60
61print $NumAndStr 123, 'xyz' 61print $NumAndStr 123, 'xyz'
62 62
63macro NumAndStr2 = (num`Num, str`SingleString) -> |
64 [#{num}, #{str}]
65
66print $NumAndStr2 456, 'abc'
67
63$asserts item == nil 68$asserts item == nil
64 69
65$myconfig false 70$myconfig false
@@ -100,13 +105,14 @@ macro filter = (items, action)->
100 $showMacro "filter", "[_ for _ in *#{items} when #{action}]" 105 $showMacro "filter", "[_ for _ in *#{items} when #{action}]"
101 106
102macro reduce = (items, def, action)-> 107macro reduce = (items, def, action)->
103 $showMacro "reduce", "if ##{items} == 0 108 $showMacro "reduce", |
104 #{def} 109 if ##{items} == 0
105else 110 #{def}
106 _1 = #{def} 111 else
107 for _2 in *#{items} 112 _1 = #{def}
108 _1 = #{action} 113 for _2 in *#{items}
109 _1" 114 _1 = #{action}
115 _1
110 116
111macro foreach = (items, action)-> 117macro foreach = (items, action)->
112 $showMacro "foreach", "for _ in *#{items} 118 $showMacro "foreach", "for _ in *#{items}
@@ -154,13 +160,15 @@ macro curry = (...)->
154f = $curry x,y,z,do 160f = $curry x,y,z,do
155 print x,y,z 161 print x,y,z
156 162
157macro get_inner = (var)-> "do 163macro get_inner = (var)-> |
158 a = 1 164 do
159 a + 1" 165 a = 1
166 a + 1
160 167
161macro get_inner_hygienic = (var)-> "(-> 168macro get_inner_hygienic = (var)-> |
162 local a = 1 169 (->
163 a + 1)!" 170 local a = 1
171 a + 1)!
164 172
165do 173do
166 a = 8 174 a = 8
@@ -196,6 +204,18 @@ end
196 204
197print x 205print x
198 206
207import "yue"
208macro lua = (code`YAMLMultiline) -> {
209 code: yue.loadstring(code)!
210 type: "lua"
211}
212
213$lua |
214 local function f2(a)
215 return a + 1
216 end
217 x = x + f2(3)
218
199macro def = (fname, ...)-> 219macro def = (fname, ...)->
200 args = {...} 220 args = {...}
201 last = table.remove args 221 last = table.remove args
@@ -317,7 +337,13 @@ $chainC(
317 Destroy! 337 Destroy!
318) 338)
319 339
320macro tb = -> "{'abc', a:123, <call>:=> 998}" 340macro tb = -> |
341 {
342 'abc'
343 a: 123
344 <call>: => 998
345 }
346
321print $tb[1], $tb.a, ($tb)!, $tb! 347print $tb[1], $tb.a, ($tb)!, $tb!
322 348
323print "current line: #{ $LINE }" 349print "current line: #{ $LINE }"
diff --git a/spec/inputs/macro_export.yue b/spec/inputs/macro_export.yue
index cc7d459..22905b5 100644
--- a/spec/inputs/macro_export.yue
+++ b/spec/inputs/macro_export.yue
@@ -8,13 +8,12 @@ export macro config = (debugging = true)->
8 "" 8 ""
9 9
10export macro showMacro = (name, res)-> 10export macro showMacro = (name, res)->
11 if debugMacro then " 11 if debugMacro then |
12do 12 do
13 txt = #{res} 13 txt = #{res}
14 print '[macro ' .. #{name} .. ']' 14 print '[macro #{name}]'
15 print txt 15 print txt
16 txt 16 txt
17"
18 else 17 else
19 res 18 res
20 19
@@ -35,14 +34,16 @@ export macro copy = (src, dst, ...)->
35 src != "_src_" and src != "_dst_" and dst != "_src_" and dst != "_dst_" 34 src != "_src_" and src != "_dst_" and dst != "_src_" and dst != "_dst_"
36 "copy targets can not be _src_ or _dst_" 35 "copy targets can not be _src_ or _dst_"
37 ) 36 )
38 " 37 copyFields = table.concat(
39do 38 ["_dst_.#{field} = _src_.#{field}" for field in *{...}]
40 local _src_, _dst_ 39 "\n\t\t\t"
41 with _dst_ = #{dst} 40 )
42 with _src_ = #{src} 41 |
43#{table.concat for field in *{...} do " 42 do
44 _dst_.#{field} = _src_.#{field} 43 local _src_, _dst_
45"}" 44 with _dst_ := #{dst}
45 with _src_ := #{src}
46 #{copyFields}
46 47
47export macro enum = (...) -> 48export macro enum = (...) ->
48 items = {...} 49 items = {...}
diff --git a/spec/inputs/macro_teal.yue b/spec/inputs/macro_teal.yue
index 0cfd862..e51bcd7 100644
--- a/spec/inputs/macro_teal.yue
+++ b/spec/inputs/macro_teal.yue
@@ -4,11 +4,16 @@ $ ->
4 options.target_extension = "tl" 4 options.target_extension = "tl"
5 package.path ..= ";./spec/lib/?.lua" 5 package.path ..= ";./spec/lib/?.lua"
6 6
7macro to_lua = (code)-> 7macro to_lua = (code)-> |
8 "require('yue').to_lua(#{code}, reserve_line_number:false, same_module:true)" 8 require('yue').to_lua #{code},
9 reserve_line_number: false
10 same_module: true
9 11
10macro trim = (name)-> 12macro trim = (name)-> |
11 "if result := #{name}\\match '[\\'\"](.*)[\\'\"]' then result else #{name}" 13 if result := #{name}\match '[\'"](.*)[\'"]'
14 result
15 else
16 #{name}
12 17
13export macro local = (decl, value = nil)-> 18export macro local = (decl, value = nil)->
14 import "yue" as {options:{:tl_enabled}} 19 import "yue" as {options:{:tl_enabled}}
diff --git a/spec/inputs/macro_todo.yue b/spec/inputs/macro_todo.yue
index 752c9cb..c9c8f77 100644
--- a/spec/inputs/macro_todo.yue
+++ b/spec/inputs/macro_todo.yue
@@ -5,9 +5,6 @@ export macro todoInner = (module, line, msg)->
5 type: "lua" 5 type: "lua"
6 } 6 }
7 7
8export macro todo = (msg)-> 8export macro todo = (msg)-> |
9 if msg 9 $todoInner $FILE, $LINE#{msg and ", #{msg}" or ""}
10 "$todoInner $FILE, $LINE, #{msg}"
11 else
12 "$todoInner $FILE, $LINE"
13 10
diff --git a/spec/inputs/props.yue b/spec/inputs/props.yue
new file mode 100644
index 0000000..bbb7aae
--- /dev/null
+++ b/spec/inputs/props.yue
@@ -0,0 +1,61 @@
1class Props
2 __index: (name): nil =>
3 cls = @.<>
4 if item := cls.__getter?[name] -- access properties
5 return item @
6 elseif item := rawget cls, name -- access member functions
7 return item
8 else
9 c = cls
10 while c := c.<> -- recursive to access base classes
11 if item := c.__getter?[name]
12 cls.__getter ??= {}
13 cls.__getter[name] = item -- cache base properties to class
14 return item @
15 elseif item := rawget c, name
16 rawset cls, name, item -- cache base member to class
17 return item
18
19 __newindex: (name, value) =>
20 cls = @.<>
21 if item := cls.__setter?[name] -- access properties
22 item @, value
23 else
24 c = cls
25 while c := c.<> -- recursive to access base classes
26 if item := c.__setter?[name]
27 cls.__setter ??= {}
28 cls.__setter[name] = item -- cache base property to class
29 item @, value
30 return
31 rawset @, name, value -- assign field to self
32
33 assignReadOnly = -> error "assigning a readonly property"
34
35 prop: (name, props) =>
36 {
37 :get
38 :set = assignReadOnly
39 } = props
40 if getter := rawget @__base, "__getter"
41 getter[name] = get
42 else
43 rawset @__base, "__getter", [name]: get
44 if setter := rawget @__base, "__setter"
45 setter[name] = set
46 else
47 rawset @__base, "__setter", [name]: set
48
49class A extends Props
50 @prop 'x'
51 get: => @_x + 1000
52 set: (v) => @_x = v
53 new: =>
54 @_x = 0
55
56class B extends A
57 @prop 'abc', get: => "hello"
58
59b = B!
60b.x = 999
61print b.x, b.abc
diff --git a/spec/inputs/string.yue b/spec/inputs/string.yue
index f91383e..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 49d47f3..2b0669c 100644
--- a/spec/inputs/switch.yue
+++ b/spec/inputs/switch.yue
@@ -165,5 +165,128 @@ do
165 print item 165 print item
166 when [a = 1, b = "abc"] 166 when [a = 1, b = "abc"]
167 print a, b 167 print a, b
168nil
169 168
169do
170 switch tb
171 when [1, 2, 3]
172 print "1, 2, 3"
173 when [1, b, 3]
174 print "1, #{b}, 3"
175 when [1, 2, b = 3]
176 print "1, 2, #{b}"
177
178do
179 switch tb
180 when success: true, :result
181 print "success", result
182 when success: false
183 print "failed", result
184 else
185 print "invalid"
186
187do
188 switch tb
189 when {type: "success", :content}
190 print "success", content
191 when {type: "error", :content}
192 print "failed", content
193 else
194 print "invalid"
195
196do
197 switch tb
198 when [
199 {a: 1, b: 2}
200 {a: 3, b: 4}
201 {a: 5, b: 6}
202 fourth
203 ]
204 print "matched", fourth
205
206 switch tb
207 when [
208 {c: 1, d: 2}
209 {c: 3, d: 4}
210 {c: 5, d: 6}
211 ]
212 print "OK"
213 when [
214 _
215 _
216 {a: 1, b: 2}
217 {a: 3, b: 4}
218 {a: 5, b: 6}
219 sixth
220 ]
221 print "matched", sixth
222
223do
224 switch v := "hello"
225 when "hello"
226 print "matched hello"
227 else
228 print "not matched"
229 -- output: matched hello
230
231do
232 f = -> "ok"
233 switch val := f!
234 when "ok"
235 print "it's ok"
236 -- output: it's ok
237
238
239do
240 g = -> 42
241 switch result := g!
242 when 1, 2
243 print "small"
244 when 42
245 print "life universe everything"
246 else
247 print "other #{result}"
248 -- output: life universe everything
249
250do
251 check = ->
252 if true
253 "yes"
254 else
255 "no"
256
257 switch x := check!
258 when "yes"
259 print "affirmative"
260 else
261 print "negative"
262 -- output: affirmative
263
264do
265 t = (): tb ->
266 tb = {a: 1}
267 tb.a = 2
268
269 switch data := t!
270 when {a: 2}
271 print "matched"
272 else
273 print "not matched"
274
275do
276 clientData = ["Meta", "CUST_1001", "CHK123"]
277 switch clientData
278 when [...metadata, customerId, checksum]
279 print metadata -- {"Meta"}
280 print customerId -- "CUST_1001"
281 print checksum -- "CHK123"
282
283do
284 handlePath = (segments) ->
285 switch segments
286 when [..._, resource, action]
287 print "Resource:", resource
288 print "Action:", action
289
290 handlePath ["admin", "logs", "view"]
291
292nil
diff --git a/spec/inputs/syntax.yue b/spec/inputs/syntax.yue
index a414d6f..a63f629 100644
--- a/spec/inputs/syntax.yue
+++ b/spec/inputs/syntax.yue
@@ -7,7 +7,7 @@ a, bunch, go, here = another, world, nil, nil
7func arg1, arg2, another, arg3 7func arg1, arg2, another, arg3
8 8
9here, we = () ->, yeah 9here, we = () ->, yeah
10the, different = () -> approach; yeah 10the, different = (() -> approach), yeah
11 11
12dad() 12dad()
13dad(lord) 13dad(lord)
@@ -321,7 +321,7 @@ ajax url,
321 (error) -> 321 (error) ->
322 print error 322 print error
323 323
324-- 324--
325a += 3 - 5 325a += 3 - 5
326a *= 3 + 5 326a *= 3 + 5
327a *= 3 327a *= 3
@@ -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,65 @@ 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
489do
490 -- Simple one-liners
491 x = 1; y = 2
492
493 -- Short related statements
494 i += 1; j += 1
495
496 if condition
497 setup!; run!; cleanup!
498
499 a = 1; b = 2; c = a + b
500 print a; print b; print c
501
502 f = ->
503 a = 1; b = 2; a + b
504
505 a = 1;
506 b = 2;
507
508 success, result = try func!; print result if success
509
510 value = "foo"; print value; value = value .. "bar"; print value
511
512 do
513 if ok then print "ok!"; return 42
514
515 for i=1,3
516 print i; continue
517
518 n = 0
519 while n < 2
520 print "n=", n; n += 1
521
522 obj = {}
523 obj\set 10; obj\get!; print "done"
524
525 with tbl
526 \push 1; print "push"
527
528 a = 5
529 if a > 3
530 print "big"; b = a * 2; print b
531 else
532 print "small"; b = a
533
534 try
535 x = 1; y = 2; print x + y
536 catch err
537 print "error:", err
538
539q = 1 --[[it's q]]; --[[got w]] w = 2; e = 3; print --[[param q]] q, w, e; --[[here]] -- line ends
540
481nil 541nil
482 542
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..939579b 100644
--- a/spec/inputs/unicode/syntax.yue
+++ b/spec/inputs/unicode/syntax.yue
@@ -7,7 +7,7 @@
7函数 傿•°1, 傿•°2, å¦å¤–, 傿•°3 7函数 傿•°1, 傿•°2, å¦å¤–, 傿•°3
8 8
9这里, 我们 = () ->, 是的 9这里, 我们 = () ->, 是的
10这个, ä¸åŒ = () -> 方法; 是的 10这个, ä¸åŒ = (() -> 方法), 是的
11 11
12爸爸() 12爸爸()
13爸爸(主) 13爸爸(主)
@@ -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/whitespace.yue b/spec/inputs/unicode/whitespace.yue
index efe55ce..151789a 100644
--- a/spec/inputs/unicode/whitespace.yue
+++ b/spec/inputs/unicode/whitespace.yue
@@ -97,19 +97,19 @@ v = ->
97 å˜é‡c -- v3 97 å˜é‡c -- v3
98 98
99v1, v2, \ 99v1, v2, \
100 v3 = -> 100 v3 = (->
101 å˜é‡a; \-- 函数结æŸäºŽv1 101 å˜é‡a), \-- 函数结æŸäºŽv1
102 å˜é‡b, \-- v2 102 å˜é‡b, \-- v2
103 å˜é‡c -- v3 103 å˜é‡c -- v3
104 104
105å˜é‡a, å˜é‡b, \ 105å˜é‡a, å˜é‡b, \
106 å˜é‡c, å˜é‡d, \ 106 å˜é‡c, å˜é‡d, \
107å˜é‡e, å˜é‡f = 1, \ 107å˜é‡e, å˜é‡f = 1, \
108 f2 108 (f2
109 :abc; \-- 傿•°2 109 :abc), \-- 傿•°2
110 3, \ 110 3, \
111 4, \ 111 4, \
112 函数5 abc; \-- 傿•°5 112 函数5(abc), \-- 傿•°5
113 6 113 6
114 114
115for å˜é‡a, \-- 解构1 115for å˜é‡a, \-- 解构1
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/whitespace.yue b/spec/inputs/whitespace.yue
index 2655961..e501d3d 100644
--- a/spec/inputs/whitespace.yue
+++ b/spec/inputs/whitespace.yue
@@ -128,19 +128,19 @@ v = ->
128 c -- v3 128 c -- v3
129 129
130v1, v2, \ 130v1, v2, \
131 v3 = -> 131 v3 = (->
132 a; \-- end of function for v1 132 a), \-- end of function for v1
133 b, \-- v2 133 b, \-- v2
134 c -- v3 134 c -- v3
135 135
136a, b, \ 136a, b, \
137 c, d, \ 137 c, d, \
138e, f = 1, \ 138e, f = 1, \
139 f2 139 (f2
140 :abc; \-- arg2 140 :abc), \-- arg2
141 3, \ 141 3, \
142 4, \ 142 4, \
143 f5 abc; \-- arg5 143 f5(abc), \-- arg5
144 6 144 6
145 145
146for a, \-- destruct 1 146for a, \-- destruct 1
diff --git a/spec/inputs/with.yue b/spec/inputs/with.yue
index 19b7be1..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
@@ -152,4 +152,22 @@ do
152 return with {} 152 return with {}
153 return [123] 153 return [123]
154 154
155do
156 f with item
157 if .id > 0
158 break .content
159
160 a = with tb
161 if .v
162 break .a
163
164 a = while true
165 break with? tb
166 break 1
167
168do
169 a = for i = 1, 100
170 with? x := tb[i]
171 break x if .id := 1
172
155nil 173nil
diff --git a/spec/outputs/5.1/import_global.lua b/spec/outputs/5.1/import_global.lua
new file mode 100644
index 0000000..3b8334a
--- /dev/null
+++ b/spec/outputs/5.1/import_global.lua
@@ -0,0 +1,131 @@
1do
2 local print = print
3 local math = math
4 print("hello")
5 math.random(10)
6end
7do
8 local print = print
9 local value = 1
10 value = value + 2
11 print(value)
12end
13do
14 local print
15 print = function(msg)
16 return msg
17 end
18 do
19 local math = math
20 print("local")
21 math.random(1)
22 end
23end
24do
25 local print = print
26 local tostring
27 tostring = function(v)
28 return "local"
29 end
30 tostring("value")
31 print(tostring(123))
32end
33do
34 local func
35 func = function(x, y)
36 local type = type
37 local tostring = tostring
38 local print = print
39 return type(x, tostring(y, print))
40 end
41 func(1, 2)
42end
43do
44 local xpcall = xpcall
45 local func = func
46 local world = world
47 local tostring = tostring
48 local print = print
49 xpcall(function()
50 return func("hello " .. tostring(world))
51 end, function(err)
52 return print(err)
53 end)
54end
55do
56 local print = print
57 print(FLAG)
58 FLAG = 123
59end
60do
61 local print = print
62 Foo = 10
63 print(Foo)
64 Foo = Foo + 2
65end
66do
67 local print = print
68 Bar = 1
69 Baz = 2
70 print(Bar, Baz)
71end
72do
73 local y = y
74 x = 3434
75 if y then
76 x = 10
77 end
78end
79do
80 local lowercase = lowercase
81 local tostring = tostring
82 local Uppercase = Uppercase
83 local foobar = "all " .. tostring(lowercase)
84 FooBar = "pascal case"
85 FOOBAR = "all " .. tostring(Uppercase)
86end
87do
88 local setmetatable = setmetatable
89 local print = print
90 do
91 local _class_0
92 local _base_0 = { }
93 if _base_0.__index == nil then
94 _base_0.__index = _base_0
95 end
96 _class_0 = setmetatable({
97 __init = function() end,
98 __base = _base_0,
99 __name = "A"
100 }, {
101 __index = _base_0,
102 __call = function(cls, ...)
103 local _self_0 = setmetatable({ }, _base_0)
104 cls.__init(_self_0, ...)
105 return _self_0
106 end
107 })
108 _base_0.__class = _class_0
109 A = _class_0
110 end
111 Flag = 1
112 const, x, y = "const", 1, 2
113 print(math, table)
114end
115do
116 local X = X
117 X:func(1, 2, 3)
118 X.tag = "abc"
119end
120local _anon_func_0 = function(func)
121 return func
122end
123do
124 local func = func
125 local pcall = pcall
126 local f
127 f = function()
128 func()
129 return pcall(_anon_func_0, func)
130 end
131end
diff --git a/spec/outputs/5.1/literals.lua b/spec/outputs/5.1/literals.lua
deleted file mode 100644
index 36c705a..0000000
--- a/spec/outputs/5.1/literals.lua
+++ /dev/null
@@ -1,44 +0,0 @@
1local _ = {
2 121,
3 121.2323,
4 121.2323e-1,
5 121.2323e13434,
6 2323E34,
7 0x12323,
8 0xfF2323,
9 0xabcdef,
10 0xABCDEF,
11 0XFBC400,
12 2.7365508487142853e-35,
13 0xABCP321,
14 2.4074124304840448e-35,
15 6.4326233113470805e-94,
16 0.1171875,
17 162.1875,
18 3.1415926535897931,
19 1,
20 8,
21 15,
22 201,
23 .2323,
24 .2323e-1,
25 .2323e13434,
26 1LL,
27 1ULL,
28 9332LL,
29 9332,
30 0x2aLL,
31 0x2aULL,
32 1000000.0000001,
33 1234e5678,
34 1234E-5678,
35 0xDEADBEEF,
36 [[ hello world ]],
37 [=[ hello world ]=],
38 [====[ hello world ]====],
39 "another world",
40 'what world',
41 "\n hello world\n ",
42 'yeah\n what is going on\n here is something cool'
43}
44return nil
diff --git a/spec/outputs/5.1/loops.lua b/spec/outputs/5.1/loops.lua
index 57b19be..e4f2871 100644
--- a/spec/outputs/5.1/loops.lua
+++ b/spec/outputs/5.1/loops.lua
@@ -60,8 +60,8 @@ do
60 local y = hello[_index_0] 60 local y = hello[_index_0]
61 if y % 2 == 0 then 61 if y % 2 == 0 then
62 _accum_0[_len_0] = y 62 _accum_0[_len_0] = y
63 _len_0 = _len_0 + 1
63 end 64 end
64 _len_0 = _len_0 + 1
65 end 65 end
66 x = _accum_0 66 x = _accum_0
67end 67end
@@ -132,13 +132,11 @@ do
132end 132end
133do 133do
134 local _accum_0 = { } 134 local _accum_0 = { }
135 local _len_0 = 1
136 local _list_2 = 3 135 local _list_2 = 3
137 for _index_0 = 1, #_list_2 do 136 for _index_0 = 1, #_list_2 do
138 local thing = _list_2[_index_0] 137 local thing = _list_2[_index_0]
139 y = "hello" 138 y = "hello"
140 break 139 break
141 _len_0 = _len_0 + 1
142 end 140 end
143 x = _accum_0 141 x = _accum_0
144end 142end
@@ -489,3 +487,131 @@ do
489 end 487 end
490 until false 488 until false
491end 489end
490local _anon_func_0 = function(i, tb)
491 local _accum_0 = { }
492 local _len_0 = 1
493 while tb[i] do
494 i = i + 1
495 _accum_0[_len_0] = i - 1
496 _len_0 = _len_0 + 1
497 end
498 return _accum_0
499end
500do
501 local index
502 do
503 local _accum_0
504 for i = 1, #tb do
505 if tb[i] then
506 _accum_0 = i
507 break
508 end
509 end
510 index = _accum_0
511 end
512 f((function()
513 local _accum_0
514 for i = 1, #tb do
515 if tb[i] then
516 _accum_0 = i
517 break
518 end
519 end
520 return _accum_0
521 end)())
522 f((function()
523 local _accum_0 = { }
524 local _len_0 = 1
525 for i = 1, #tb do
526 if tb[i] then
527 _accum_0[_len_0] = i
528 _len_0 = _len_0 + 1
529 end
530 end
531 return _accum_0
532 end)())
533 i = 1
534 local ids
535 do
536 local _accum_0 = { }
537 local _len_0 = 1
538 while tb[i] do
539 i = i + 1
540 _accum_0[_len_0] = i - 1
541 _len_0 = _len_0 + 1
542 end
543 ids = _accum_0
544 end
545 i = 1
546 local idx
547 do
548 local _accum_0
549 while tb[i] do
550 i = i + 1
551 _accum_0 = i - 1
552 break
553 end
554 idx = _accum_0
555 end
556 local f1
557 f1 = function()
558 i = 1
559 return f(_anon_func_0(i, tb))
560 end
561 i = 1
562 f((function()
563 local _accum_0
564 while tb[i] do
565 i = i + 1
566 _accum_0 = i - 1
567 break
568 end
569 return _accum_0
570 end)())
571 local _accum_0 = { }
572 local _len_0 = 1
573 local _list_3 = items
574 for _index_0 = 1, #_list_3 do
575 local item = _list_3[_index_0]
576 local _type_0 = type(item)
577 local _tab_0 = "table" == _type_0 or "userdata" == _type_0
578 if _tab_0 then
579 local value = item.value
580 if "A" == item.type and value ~= nil then
581 if value > 5 then
582 _accum_0[_len_0] = item
583 _len_0 = _len_0 + 1
584 end
585 end
586 end
587 end
588 list = _accum_0
589end
590do
591 repeat
592 print(1)
593 until true
594 do
595 local _accum_0
596 repeat
597 a = func()
598 _accum_0 = a.x
599 break
600 until a.v
601 x = _accum_0
602 end
603 local items
604 local _accum_0 = { }
605 local _len_0 = 1
606 repeat
607 local item = getItem()
608 if not item then
609 break
610 end
611 if item.value > 0 then
612 _accum_0[_len_0] = item
613 _len_0 = _len_0 + 1
614 end
615 until false
616 items = _accum_0
617end
diff --git a/spec/outputs/5.1/try_catch.lua b/spec/outputs/5.1/try_catch.lua
index efd92c6..d2b58bc 100644
--- a/spec/outputs/5.1/try_catch.lua
+++ b/spec/outputs/5.1/try_catch.lua
@@ -22,6 +22,43 @@ end
22local _anon_func_7 = function(a, b, c, tb) 22local _anon_func_7 = function(a, b, c, tb)
23 return tb.f(a, b, c) 23 return tb.f(a, b, c)
24end 24end
25local _anon_func_8 = function(_arg_0, ...)
26 local ok = _arg_0
27 return ...
28end
29local _anon_func_10 = function(_arg_0, ...)
30 local _ok_0 = _arg_0
31 if _ok_0 then
32 return ...
33 end
34end
35local _anon_func_9 = function(func, pcall)
36 return _anon_func_10(pcall(func))
37end
38local _anon_func_12 = function(_arg_0, ...)
39 local _ok_0 = _arg_0
40 if _ok_0 then
41 return ...
42 end
43end
44local _anon_func_11 = function(func, pcall)
45 return _anon_func_12(pcall(func))
46end
47local _anon_func_14 = function(_arg_0, ...)
48 local _ok_0 = _arg_0
49 if _ok_0 then
50 return ...
51 end
52end
53local _anon_func_13 = function(func, print, xpcall)
54 return _anon_func_14(xpcall(function()
55 print(123)
56 return func()
57 end, function(e)
58 print(e)
59 return e
60 end))
61end
25local f 62local f
26f = function() 63f = function()
27 xpcall(function() 64 xpcall(function()
@@ -104,10 +141,236 @@ f = function()
104 do 141 do
105 x(function() 142 x(function()
106 local tb, a, b, c 143 local tb, a, b, c
107 f = function() 144 local f1
145 f1 = function()
108 return pcall(_anon_func_7, a, b, c, tb) 146 return pcall(_anon_func_7, a, b, c, tb)
109 end 147 end
110 end) 148 end)
111 end 149 end
150 do
151 local f1
152 f1 = function()
153 do
154 return _anon_func_8(pcall(function()
155 return func()
156 end))
157 end
158 end
159 end
160 do
161 local func
162 local a, b, c
163 local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(func)
164 if _ok_0 then
165 a, b, c = _ret_0, _ret_1, _ret_2
166 end
167 end
168 do
169 local a, b, c
170 local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function()
171 return func()
172 end)
173 if _ok_0 then
174 a, b, c = _ret_0, _ret_1, _ret_2
175 end
176 end
177 do
178 local a
179 local _exp_0 = (_anon_func_9(func, pcall))
180 if _exp_0 ~= nil then
181 a = _exp_0
182 else
183 a = "default"
184 end
185 end
186 do
187 f(_anon_func_11(func, pcall))
188 end
189 do
190 f(_anon_func_13(func, print, xpcall))
191 end
112 return nil 192 return nil
113end 193end
194local _anon_func_15 = function(a, b, c, tb)
195 return tb.f(a, b, c)
196end
197local _anon_func_16 = function(_arg_0, ...)
198 local ok = _arg_0
199 return ...
200end
201do
202 xpcall(function()
203 return func(1, 2, 3)
204 end, function(err)
205 return print(err)
206 end)
207 xpcall(function()
208 return func(1, 2, 3)
209 end, function(err)
210 return print(err)
211 end)
212 pcall(function()
213 print("trying")
214 return func(1, 2, 3)
215 end)
216 do
217 local success, result = xpcall(function()
218 return func(1, 2, 3)
219 end, function(err)
220 return print(err)
221 end)
222 success, result = pcall(function()
223 return func(1, 2, 3)
224 end)
225 end
226 local tb = { }
227 pcall(function()
228 return tb.func
229 end)
230 pcall(function()
231 return tb.func()
232 end)
233 pcall(function()
234 return tb.func()
235 end)
236 pcall(function()
237 return (tb.func())
238 end)
239 pcall(function()
240 return (tb:func(1, 2, 3))
241 end)
242 pcall(function()
243 return tb.func(1)
244 end)
245 pcall(function()
246 return tb.func(1)
247 end)
248 if (xpcall(function()
249 return func(1)
250 end, function(err)
251 return print(err)
252 end)) then
253 print("OK")
254 end
255 if xpcall(function()
256 return (func(1))
257 end, function(err)
258 return print(err)
259 end) then
260 print("OK")
261 end
262 do
263 do
264 local success, result = pcall(function()
265 return func("abc", 123)
266 end)
267 if success then
268 print(result)
269 end
270 end
271 local success, result = xpcall(function()
272 return func("abc", 123)
273 end, function(err)
274 return print(err)
275 end)
276 success, result = xpcall(function()
277 return func("abc", 123)
278 end, function(err)
279 return print(err)
280 end)
281 if success then
282 print(result)
283 end
284 end
285 do
286 pcall(function()
287 return func(1, 2, 3)
288 end)
289 pcall(function()
290 return func(1, 2, 3)
291 end)
292 end
293 do
294 x(function()
295 local tb, a, b, c
296 local f1
297 f1 = function()
298 return pcall(_anon_func_15, a, b, c, tb)
299 end
300 end)
301 end
302 do
303 local f1
304 f1 = function()
305 do
306 return _anon_func_16(pcall(function()
307 return func()
308 end))
309 end
310 end
311 end
312 do
313 local func
314 local a, b, c
315 local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(func)
316 if _ok_0 then
317 a, b, c = _ret_0, _ret_1, _ret_2
318 end
319 end
320 do
321 local a, b, c
322 local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function()
323 return func()
324 end)
325 if _ok_0 then
326 a, b, c = _ret_0, _ret_1, _ret_2
327 end
328 end
329 do
330 local a
331 local _exp_0 = ((function()
332 return (function(_arg_0, ...)
333 local _ok_0 = _arg_0
334 if _ok_0 then
335 return ...
336 end
337 end)(pcall(function()
338 return func()
339 end))
340 end)())
341 if _exp_0 ~= nil then
342 a = _exp_0
343 else
344 a = "default"
345 end
346 end
347 do
348 f((function()
349 return (function(_arg_0, ...)
350 local _ok_0 = _arg_0
351 if _ok_0 then
352 return ...
353 end
354 end)(pcall(function()
355 return func()
356 end))
357 end)())
358 end
359 do
360 f((function()
361 return (function(_arg_0, ...)
362 local _ok_0 = _arg_0
363 if _ok_0 then
364 return ...
365 end
366 end)(xpcall(function()
367 print(123)
368 return func()
369 end, function(e)
370 print(e)
371 return e
372 end))
373 end)())
374 end
375end
376return nil
diff --git a/spec/outputs/assign.lua b/spec/outputs/assign.lua
index 162c5a8..89c5f8a 100644
--- a/spec/outputs/assign.lua
+++ b/spec/outputs/assign.lua
@@ -43,10 +43,8 @@ do
43 end 43 end
44end 44end
45local _anon_func_0 = function(print) 45local _anon_func_0 = function(print)
46 do 46 print(123)
47 print(123) 47 return { }
48 return { }
49 end
50end 48end
51return _(function() 49return _(function()
52 setmetatable(a, _anon_func_0(print)) 50 setmetatable(a, _anon_func_0(print))
diff --git a/spec/outputs/codes_from_doc.lua b/spec/outputs/codes_from_doc.lua
index f6d5d61..3b0724a 100644
--- a/spec/outputs/codes_from_doc.lua
+++ b/spec/outputs/codes_from_doc.lua
@@ -20,6 +20,38 @@ local inventory = {
20 } 20 }
21 } 21 }
22} 22}
23local map
24map = function(arr, action)
25 local _accum_0 = { }
26 local _len_0 = 1
27 for _index_0 = 1, #arr do
28 local item = arr[_index_0]
29 _accum_0[_len_0] = action(item)
30 _len_0 = _len_0 + 1
31 end
32 return _accum_0
33end
34local filter
35filter = function(arr, cond)
36 local _accum_0 = { }
37 local _len_0 = 1
38 for _index_0 = 1, #arr do
39 local item = arr[_index_0]
40 if cond(item) then
41 _accum_0[_len_0] = item
42 _len_0 = _len_0 + 1
43 end
44 end
45 return _accum_0
46end
47local reduce
48reduce = function(arr, init, action)
49 for _index_0 = 1, #arr do
50 local item = arr[_index_0]
51 init = action(init, item)
52 end
53 return init
54end
23print(reduce(filter(map({ 55print(reduce(filter(map({
24 1, 56 1,
25 2, 57 2,
@@ -41,8 +73,8 @@ local apple = setmetatable({
41if (getmetatable(apple) ~= nil) then 73if (getmetatable(apple) ~= nil) then
42 p(apple.size, apple.color, getmetatable(apple).__index) 74 p(apple.size, apple.color, getmetatable(apple).__index)
43end 75end
44local _ud83c_udf1b = "月之脚本" 76local _u1f31b = "月之脚本"
45_module_0["🌛"] = _ud83c_udf1b 77_module_0["🌛"] = _u1f31b
46return _module_0 78return _module_0
47local area = 6.2831853071796 * 5 79local area = 6.2831853071796 * 5
48print('hello world') 80print('hello world')
@@ -77,6 +109,12 @@ end
77print("yuescript") 109print("yuescript")
78print(3) 110print(3)
79print("Valid enum type:", "Static") 111print("Valid enum type:", "Static")
112do
113 print(123, "hello")
114end
115do
116 print(123, "hello")
117end
80if tb ~= nil then 118if tb ~= nil then
81 tb:func() 119 tb:func()
82end 120end
@@ -109,6 +147,21 @@ print((function()
109end)()) 147end)())
110local tab = { } 148local tab = { }
111tab[#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
112local parts = { 165local parts = {
113 "shoulders", 166 "shoulders",
114 "knees" 167 "knees"
@@ -177,6 +230,18 @@ for _key_0, _value_0 in pairs(b) do
177 end 230 end
178end 231end
179merge = _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
180local mt = { } 245local mt = { }
181local add 246local add
182add = function(self, right) 247add = function(self, right)
@@ -307,6 +372,14 @@ func({
307 2, 372 2,
308 3 373 3
309}) 374})
375local f
376f = function()
377 return {
378 1,
379 2,
380 3
381 }
382end
310local tb = { 383local tb = {
311 name = "abc", 384 name = "abc",
312 values = { 385 values = {
@@ -368,6 +441,25 @@ do
368 local _obj_0 = require("export") 441 local _obj_0 = require("export")
369 one, two, ch = _obj_0[1], _obj_0[2], _obj_0.Something.umm[1] 442 one, two, ch = _obj_0[1], _obj_0[2], _obj_0.Something.umm[1]
370end 443end
444do
445 local tostring <const> = tostring
446 local concat <const> = table.concat
447 print(concat({
448 "a",
449 tostring(1)
450 }))
451end
452do
453 local print <const> = print
454 local math <const> = math
455 print("hello")
456 math.random(3)
457end
458do
459 local print <const> = print
460 print(FLAG)
461 FLAG = 123
462end
371local _module_0 = { } 463local _module_0 = { }
372local a, b, c = 1, 2, 3 464local a, b, c = 1, 2, 3
373_module_0["a"], _module_0["b"], _module_0["c"] = a, b, c 465_module_0["a"], _module_0["b"], _module_0["c"] = a, b, c
@@ -547,6 +639,59 @@ end
547local two, four 639local two, four
548local _obj_0 = items 640local _obj_0 = items
549two, four = _obj_0[2], _obj_0[4] 641two, four = _obj_0[2], _obj_0[4]
642local orders = {
643 "first",
644 "second",
645 "third",
646 "fourth",
647 "last"
648}
649local first, bulk, last = orders[1], (function()
650 local _accum_0 = { }
651 local _len_0 = 1
652 local _max_0 = #orders + -2 + 1
653 for _index_0 = 2, _max_0 do
654 local _item_0 = orders[_index_0]
655 _accum_0[_len_0] = _item_0
656 _len_0 = _len_0 + 1
657 end
658 return _accum_0
659end)(), orders[#orders]
660print(first)
661print(bulk)
662print(last)
663local first, rest
664do
665 local _obj_0 = orders
666 first, rest = _obj_0[1], (function()
667 local _accum_0 = { }
668 local _len_0 = 1
669 local _max_0 = #_obj_0
670 for _index_0 = 2, _max_0 do
671 local _item_0 = _obj_0[_index_0]
672 _accum_0[_len_0] = _item_0
673 _len_0 = _len_0 + 1
674 end
675 return _accum_0
676 end)()
677end
678local start, last
679do
680 local _obj_0 = orders
681 start, last = (function()
682 local _accum_0 = { }
683 local _len_0 = 1
684 local _max_0 = #_obj_0 + -2 + 1
685 for _index_0 = 1, _max_0 do
686 local _item_0 = _obj_0[_index_0]
687 _accum_0[_len_0] = _item_0
688 _len_0 = _len_0 + 1
689 end
690 return _accum_0
691 end)(), _obj_0[#_obj_0]
692end
693local _obj_0 = orders
694first, last = _obj_0[1], _obj_0[#_obj_0]
550local tuples = { 695local tuples = {
551 { 696 {
552 "hello", 697 "hello",
@@ -611,6 +756,9 @@ end
611 local first = select(1, ...) 756 local first = select(1, ...)
612 return print(ok, count, first) 757 return print(ok, count, first)
613end)(fn(true)) 758end)(fn(true))
759local a = 1
760local b = 2
761print(a + b)
614Rx.Observable.fromRange(1, 8):filter(function(x) 762Rx.Observable.fromRange(1, 8):filter(function(x)
615 return x % 2 == 0 763 return x % 2 == 0
616end):concat(Rx.Observable.of('who do we appreciate')):map(function(value) 764end):concat(Rx.Observable.of('who do we appreciate')):map(function(value)
@@ -648,6 +796,56 @@ end)
648if success then 796if success then
649 print(result) 797 print(result)
650end 798end
799local a, b, c
800do
801 local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function()
802 return func()
803 end)
804 if _ok_0 then
805 a, b, c = _ret_0, _ret_1, _ret_2
806 end
807end
808do
809 local _exp_0 = ((function()
810 return (function(_arg_0, ...)
811 local _ok_0 = _arg_0
812 if _ok_0 then
813 return ...
814 end
815 end)(pcall(function()
816 return func()
817 end))
818 end)())
819 if _exp_0 ~= nil then
820 a = _exp_0
821 else
822 a = "default"
823 end
824end
825f((function()
826 return (function(_arg_0, ...)
827 local _ok_0 = _arg_0
828 if _ok_0 then
829 return ...
830 end
831 end)(pcall(function()
832 return func()
833 end))
834end)())
835f((function()
836 return (function(_arg_0, ...)
837 local _ok_0 = _arg_0
838 if _ok_0 then
839 return ...
840 end
841 end)(xpcall(function()
842 print(123)
843 return func()
844 end, function(e)
845 print(e)
846 return e
847 end))
848end)())
651local a <const> = 123 849local a <const> = 123
652local _ <close> = setmetatable({ }, { 850local _ <close> = setmetatable({ }, {
653 __close = function() 851 __close = function()
@@ -657,10 +855,19 @@ local _ <close> = setmetatable({ }, {
657local a, b, c, d 855local a, b, c, d
658local _obj_0 = tb 856local _obj_0 = tb
659a, b, c, d = _obj_0.a, _obj_0.b, _obj_0[1], _obj_0[2] 857a, b, c, d = _obj_0.a, _obj_0.b, _obj_0[1], _obj_0[2]
858Constant = 123
660local some_string = "Here is a string\n that has a line break in it." 859local some_string = "Here is a string\n that has a line break in it."
661print("I am " .. tostring(math.random() * 100) .. "% sure.") 860print("I am " .. tostring(math.random() * 100) .. "% sure.")
662local integer = 1000000 861local integer = 1000000
663local hex = 0xEFBBBF 862local hex = 0xEFBBBF
863local binary = 19
864local str = "key: value\nlist:\n - item1\n - " .. tostring(expr)
865local fn
866fn = function()
867 local str = "foo:\n bar: baz"
868 return str
869end
870local str = "path: \"C:\\Program Files\\App\"\nnote: 'He said: \"" .. tostring(Hello) .. "!\"'"
664local my_function 871local my_function
665my_function = function() end 872my_function = function() end
666my_function() 873my_function()
@@ -755,6 +962,66 @@ if func(1, 2, 3, "hello", "world") then
755 print("hello") 962 print("hello")
756 print("I am inside if") 963 print("I am inside if")
757end 964end
965local f1
966f1 = function(_arg_0)
967 local a, b, c
968 a, b, c = _arg_0.a, _arg_0.b, _arg_0.c
969 return print(a, b, c)
970end
971f1({
972 a = 1,
973 b = "2",
974 c = { }
975})
976local f2
977f2 = function(_arg_0, c)
978 local a1, b
979 a1, b = _arg_0.a, _arg_0.b
980 if a1 == nil then
981 a1 = 123
982 end
983 if b == nil then
984 b = 'abc'
985 end
986 if c == nil then
987 c = { }
988 end
989 return print(a1, b, c)
990end
991local arg1 = {
992 a = 0
993}
994f2(arg1, arg2)
995local f
996f = function(...)
997 local t = {
998 n = select("#", ...),
999 ...
1000 }
1001 print("argument count:", t.n)
1002 print("table length:", #t)
1003 for i = 1, t.n do
1004 print(t[i])
1005 end
1006end
1007f(1, 2, 3)
1008f("a", "b", "c", "d")
1009f()
1010local process
1011process = function(...)
1012 local args = {
1013 n = select("#", ...),
1014 ...
1015 }
1016 local sum = 0
1017 for i = 1, args.n do
1018 if args[i] ~= nil and type(args[i]) == "number" then
1019 sum = sum + args[i]
1020 end
1021 end
1022 return sum
1023end
1024process(1, nil, 3, nil, 5)
758f(function() 1025f(function()
759 return print("hello") 1026 return print("hello")
760end) 1027end)
@@ -880,6 +1147,28 @@ for _index_0 = 1, #_list_0 do
880 _len_0 = _len_0 + 1 1147 _len_0 = _len_0 + 1
881end 1148end
882doubled = _accum_0 1149doubled = _accum_0
1150local data = {
1151 a = {
1152 1,
1153 2,
1154 3
1155 },
1156 b = {
1157 4,
1158 5,
1159 6
1160 }
1161}
1162local flat
1163local _accum_0 = { }
1164for k, v in pairs(data) do
1165 local _len_0 = #_accum_0 + 1
1166 for _index_0 = 1, #v do
1167 local _elm_0 = v[_index_0]
1168 _accum_0[_len_0], _len_0 = _elm_0, _len_0 + 1
1169 end
1170end
1171flat = _accum_0
883local x_coords = { 1172local x_coords = {
884 4, 1173 4,
885 5, 1174 5,
@@ -970,8 +1259,18 @@ local slice
970local _accum_0 = { } 1259local _accum_0 = { }
971local _len_0 = 1 1260local _len_0 = 1
972local _list_0 = items 1261local _list_0 = items
973local _max_0 = 5 1262for _index_0 = 1, 5 do
974for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do 1263 local item = _list_0[_index_0]
1264 _accum_0[_len_0] = item
1265 _len_0 = _len_0 + 1
1266end
1267slice = _accum_0
1268local slice
1269local _accum_0 = { }
1270local _len_0 = 1
1271local _list_0 = items
1272local _max_0 = #_list_0
1273for _index_0 = 2, _max_0 do
975 local item = _list_0[_index_0] 1274 local item = _list_0[_index_0]
976 _accum_0[_len_0] = item 1275 _accum_0[_len_0] = item
977 _len_0 = _len_0 + 1 1276 _len_0 = _len_0 + 1
@@ -981,7 +1280,8 @@ local slice
981local _accum_0 = { } 1280local _accum_0 = { }
982local _len_0 = 1 1281local _len_0 = 1
983local _list_0 = items 1282local _list_0 = items
984for _index_0 = 2, #_list_0 do 1283local _max_0 = #_list_0
1284for _index_0 = 1, _max_0, 2 do
985 local item = _list_0[_index_0] 1285 local item = _list_0[_index_0]
986 _accum_0[_len_0] = item 1286 _accum_0[_len_0] = item
987 _len_0 = _len_0 + 1 1287 _len_0 = _len_0 + 1
@@ -991,12 +1291,35 @@ local slice
991local _accum_0 = { } 1291local _accum_0 = { }
992local _len_0 = 1 1292local _len_0 = 1
993local _list_0 = items 1293local _list_0 = items
994for _index_0 = 1, #_list_0, 2 do 1294local _min_0 = #_list_0 + -4 + 1
1295local _max_0 = #_list_0 + -1 + 1
1296for _index_0 = _min_0, _max_0 do
995 local item = _list_0[_index_0] 1297 local item = _list_0[_index_0]
996 _accum_0[_len_0] = item 1298 _accum_0[_len_0] = item
997 _len_0 = _len_0 + 1 1299 _len_0 = _len_0 + 1
998end 1300end
999slice = _accum_0 1301slice = _accum_0
1302local reverse_slice
1303local _accum_0 = { }
1304local _len_0 = 1
1305local _list_0 = items
1306local _min_0 = #_list_0 + -1 + 1
1307for _index_0 = _min_0, 1, -1 do
1308 local item = _list_0[_index_0]
1309 _accum_0[_len_0] = item
1310 _len_0 = _len_0 + 1
1311end
1312reverse_slice = _accum_0
1313local sub_list
1314local _accum_0 = { }
1315local _len_0 = 1
1316local _list_0 = items
1317for _index_0 = 2, 4 do
1318 local _item_0 = _list_0[_index_0]
1319 _accum_0[_len_0] = _item_0
1320 _len_0 = _len_0 + 1
1321end
1322sub_list = _accum_0
1000for i = 10, 20 do 1323for i = 10, 20 do
1001 print(i) 1324 print(i)
1002end 1325end
@@ -1007,8 +1330,7 @@ for key, value in pairs(object) do
1007 print(key, value) 1330 print(key, value)
1008end 1331end
1009local _list_0 = items 1332local _list_0 = items
1010local _max_0 = 4 1333for _index_0 = 2, 4 do
1011for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do
1012 local item = _list_0[_index_0] 1334 local item = _list_0[_index_0]
1013 print(item) 1335 print(item)
1014end 1336end
@@ -1026,12 +1348,24 @@ local _len_0 = 1
1026for i = 1, 20 do 1348for i = 1, 20 do
1027 if i % 2 == 0 then 1349 if i % 2 == 0 then
1028 _accum_0[_len_0] = i * 2 1350 _accum_0[_len_0] = i * 2
1351 _len_0 = _len_0 + 1
1029 else 1352 else
1030 _accum_0[_len_0] = i 1353 _accum_0[_len_0] = i
1354 _len_0 = _len_0 + 1
1031 end 1355 end
1032 _len_0 = _len_0 + 1
1033end 1356end
1034doubled_evens = _accum_0 1357doubled_evens = _accum_0
1358local first_large
1359local _accum_0
1360local _list_0 = numbers
1361for _index_0 = 1, #_list_0 do
1362 local n = _list_0[_index_0]
1363 if n > 10 then
1364 _accum_0 = n
1365 break
1366 end
1367end
1368first_large = _accum_0
1035local func_a 1369local func_a
1036func_a = function() 1370func_a = function()
1037 for i = 1, 10 do 1371 for i = 1, 10 do
@@ -1180,7 +1514,7 @@ if "Robert" == name then
1180elseif "Dan" == name or "Daniel" == name then 1514elseif "Dan" == name or "Daniel" == name then
1181 print("Your name, it's Dan") 1515 print("Your name, it's Dan")
1182else 1516else
1183 print("I don't know about your name") 1517 print("I don't know about you with name " .. tostring(name))
1184end 1518end
1185local b = 1 1519local b = 1
1186local next_number 1520local next_number
@@ -1280,6 +1614,192 @@ if _tab_0 then
1280 end 1614 end
1281 print("Vec2 " .. tostring(x) .. ", " .. tostring(y)) 1615 print("Vec2 " .. tostring(x) .. ", " .. tostring(y))
1282end 1616end
1617local _exp_0 = tb
1618local _type_0 = type(_exp_0)
1619local _tab_0 = "table" == _type_0 or "userdata" == _type_0
1620local _match_0 = false
1621if _tab_0 then
1622 if 1 == _exp_0[1] and 2 == _exp_0[2] and 3 == _exp_0[3] then
1623 _match_0 = true
1624 print("1, 2, 3")
1625 end
1626end
1627if not _match_0 then
1628 local _match_1 = false
1629 if _tab_0 then
1630 local b = _exp_0[2]
1631 if 1 == _exp_0[1] and b ~= nil and 3 == _exp_0[3] then
1632 _match_1 = true
1633 print("1, " .. tostring(b) .. ", 3")
1634 end
1635 end
1636 if not _match_1 then
1637 if _tab_0 then
1638 local b = _exp_0[3]
1639 if b == nil then
1640 b = 3
1641 end
1642 if 1 == _exp_0[1] and 2 == _exp_0[2] then
1643 print("1, 2, " .. tostring(b))
1644 end
1645 end
1646 end
1647end
1648local _exp_0 = tb
1649local _type_0 = type(_exp_0)
1650local _tab_0 = "table" == _type_0 or "userdata" == _type_0
1651local _match_0 = false
1652if _tab_0 then
1653 local result = _exp_0.result
1654 if true == _exp_0.success and result ~= nil then
1655 _match_0 = true
1656 print("success", result)
1657 end
1658end
1659if not _match_0 then
1660 local _match_1 = false
1661 if _tab_0 then
1662 if false == _exp_0.success then
1663 _match_1 = true
1664 print("failed", result)
1665 end
1666 end
1667 if not _match_1 then
1668 print("invalid")
1669 end
1670end
1671local _exp_0 = tb
1672local _type_0 = type(_exp_0)
1673local _tab_0 = "table" == _type_0 or "userdata" == _type_0
1674local _match_0 = false
1675if _tab_0 then
1676 local content
1677 do
1678 local _obj_0 = _exp_0.data
1679 local _type_1 = type(_obj_0)
1680 if "table" == _type_1 or "userdata" == _type_1 then
1681 content = _obj_0.content
1682 end
1683 end
1684 local _val_0
1685 do
1686 local _obj_0 = _exp_0.data
1687 if _obj_0 ~= nil then
1688 _val_0 = _obj_0.type
1689 end
1690 end
1691 if "success" == _val_0 and content ~= nil then
1692 _match_0 = true
1693 print("success", content)
1694 end
1695end
1696if not _match_0 then
1697 local _match_1 = false
1698 if _tab_0 then
1699 local content
1700 do
1701 local _obj_0 = _exp_0.data
1702 local _type_1 = type(_obj_0)
1703 if "table" == _type_1 or "userdata" == _type_1 then
1704 content = _obj_0.content
1705 end
1706 end
1707 local _val_0
1708 do
1709 local _obj_0 = _exp_0.data
1710 if _obj_0 ~= nil then
1711 _val_0 = _obj_0.type
1712 end
1713 end
1714 if "error" == _val_0 and content ~= nil then
1715 _match_1 = true
1716 print("failed", content)
1717 end
1718 end
1719 if not _match_1 then
1720 print("invalid")
1721 end
1722end
1723local _exp_0 = tb
1724local _type_0 = type(_exp_0)
1725local _tab_0 = "table" == _type_0 or "userdata" == _type_0
1726if _tab_0 then
1727 local fourth = _exp_0[4]
1728 local _val_0
1729 do
1730 local _obj_0 = _exp_0[1]
1731 if _obj_0 ~= nil then
1732 _val_0 = _obj_0.a
1733 end
1734 end
1735 local _val_1
1736 do
1737 local _obj_0 = _exp_0[1]
1738 if _obj_0 ~= nil then
1739 _val_1 = _obj_0.b
1740 end
1741 end
1742 local _val_2
1743 do
1744 local _obj_0 = _exp_0[2]
1745 if _obj_0 ~= nil then
1746 _val_2 = _obj_0.a
1747 end
1748 end
1749 local _val_3
1750 do
1751 local _obj_0 = _exp_0[2]
1752 if _obj_0 ~= nil then
1753 _val_3 = _obj_0.b
1754 end
1755 end
1756 local _val_4
1757 do
1758 local _obj_0 = _exp_0[3]
1759 if _obj_0 ~= nil then
1760 _val_4 = _obj_0.a
1761 end
1762 end
1763 local _val_5
1764 do
1765 local _obj_0 = _exp_0[3]
1766 if _obj_0 ~= nil then
1767 _val_5 = _obj_0.b
1768 end
1769 end
1770 if 1 == _val_0 and 2 == _val_1 and 3 == _val_2 and 4 == _val_3 and 5 == _val_4 and 6 == _val_5 and fourth ~= nil then
1771 print("matched", fourth)
1772 end
1773end
1774local segments = {
1775 "admin",
1776 "users",
1777 "logs",
1778 "view"
1779}
1780local _type_0 = type(segments)
1781local _tab_0 = "table" == _type_0 or "userdata" == _type_0
1782if _tab_0 then
1783 local groups
1784 do
1785 local _accum_0 = { }
1786 local _len_0 = 1
1787 local _max_0 = #segments + -3 + 1
1788 for _index_0 = 1, _max_0 do
1789 local _item_0 = segments[_index_0]
1790 _accum_0[_len_0] = _item_0
1791 _len_0 = _len_0 + 1
1792 end
1793 groups = _accum_0
1794 end
1795 local resource = segments[#segments - 1]
1796 local action = segments[#segments]
1797 if resource ~= nil and action ~= nil then
1798 print("Group:", groups)
1799 print("Resource:", resource)
1800 print("Action:", action)
1801 end
1802end
1283local Inventory 1803local Inventory
1284local _class_0 1804local _class_0
1285local _base_0 = { 1805local _base_0 = {
@@ -1936,6 +2456,10 @@ do
1936 _with_1["key-name"] = value 2456 _with_1["key-name"] = value
1937end 2457end
1938_with_0[#_with_0 + 1] = "abc" 2458_with_0[#_with_0 + 1] = "abc"
2459local _with_0 = obj
2460if _with_0 ~= nil then
2461 print(obj.name)
2462end
1939do 2463do
1940 local var = "hello" 2464 local var = "hello"
1941 print(var) 2465 print(var)
@@ -2026,6 +2550,38 @@ local inventory = {
2026 } 2550 }
2027 } 2551 }
2028} 2552}
2553local map
2554map = function(arr, action)
2555 local _accum_0 = { }
2556 local _len_0 = 1
2557 for _index_0 = 1, #arr do
2558 local item = arr[_index_0]
2559 _accum_0[_len_0] = action(item)
2560 _len_0 = _len_0 + 1
2561 end
2562 return _accum_0
2563end
2564local filter
2565filter = function(arr, cond)
2566 local _accum_0 = { }
2567 local _len_0 = 1
2568 for _index_0 = 1, #arr do
2569 local item = arr[_index_0]
2570 if cond(item) then
2571 _accum_0[_len_0] = item
2572 _len_0 = _len_0 + 1
2573 end
2574 end
2575 return _accum_0
2576end
2577local reduce
2578reduce = function(arr, init, action)
2579 for _index_0 = 1, #arr do
2580 local item = arr[_index_0]
2581 init = action(init, item)
2582 end
2583 return init
2584end
2029print(reduce(filter(map({ 2585print(reduce(filter(map({
2030 1, 2586 1,
2031 2, 2587 2,
@@ -2047,8 +2603,8 @@ local apple = setmetatable({
2047if (getmetatable(apple) ~= nil) then 2603if (getmetatable(apple) ~= nil) then
2048 p(apple.size, apple.color, getmetatable(apple).__index) 2604 p(apple.size, apple.color, getmetatable(apple).__index)
2049end 2605end
2050local _ud83c_udf1b = "月之脚本" 2606local _u1f31b = "月之脚本"
2051_module_0["🌛"] = _ud83c_udf1b 2607_module_0["🌛"] = _u1f31b
2052return _module_0 2608return _module_0
2053local area = 6.2831853071796 * 5 2609local area = 6.2831853071796 * 5
2054print('hello world') 2610print('hello world')
@@ -2083,6 +2639,12 @@ end
2083print("yuescript") 2639print("yuescript")
2084print(3) 2640print(3)
2085print("Valid enum type:", "Static") 2641print("Valid enum type:", "Static")
2642do
2643 print(123, "hello")
2644end
2645do
2646 print(123, "hello")
2647end
2086if tb ~= nil then 2648if tb ~= nil then
2087 tb:func() 2649 tb:func()
2088end 2650end
@@ -2115,6 +2677,21 @@ print((function()
2115end)()) 2677end)())
2116local tab = { } 2678local tab = { }
2117tab[#tab + 1] = "Value" 2679tab[#tab + 1] = "Value"
2680local tbA = {
2681 1,
2682 2,
2683 3
2684}
2685local tbB = {
2686 4,
2687 5,
2688 6
2689}
2690local _len_0 = #tbA + 1
2691for _index_0 = 1, #tbB do
2692 local _elm_0 = tbB[_index_0]
2693 tbA[_len_0], _len_0 = _elm_0, _len_0 + 1
2694end
2118local parts = { 2695local parts = {
2119 "shoulders", 2696 "shoulders",
2120 "knees" 2697 "knees"
@@ -2183,6 +2760,18 @@ for _key_0, _value_0 in pairs(b) do
2183 end 2760 end
2184end 2761end
2185merge = _tab_0 2762merge = _tab_0
2763local last
2764do
2765 local _item_0 = data.items
2766 last = _item_0[#_item_0]
2767end
2768local second_last
2769do
2770 local _item_0 = data.items
2771 second_last = _item_0[#_item_0 - 1]
2772end
2773local _obj_0 = data.items
2774_obj_0[#_obj_0] = 1
2186local mt = { } 2775local mt = { }
2187local add 2776local add
2188add = function(self, right) 2777add = function(self, right)
@@ -2313,6 +2902,14 @@ func({
2313 2, 2902 2,
2314 3 2903 3
2315}) 2904})
2905local f
2906f = function()
2907 return {
2908 1,
2909 2,
2910 3
2911 }
2912end
2316local tb = { 2913local tb = {
2317 name = "abc", 2914 name = "abc",
2318 values = { 2915 values = {
@@ -2374,6 +2971,25 @@ do
2374 local _obj_0 = require("export") 2971 local _obj_0 = require("export")
2375 one, two, ch = _obj_0[1], _obj_0[2], _obj_0.Something.umm[1] 2972 one, two, ch = _obj_0[1], _obj_0[2], _obj_0.Something.umm[1]
2376end 2973end
2974do
2975 local tostring <const> = tostring
2976 local concat <const> = table.concat
2977 print(concat({
2978 "a",
2979 tostring(1)
2980 }))
2981end
2982do
2983 local print <const> = print
2984 local math <const> = math
2985 print("hello")
2986 math.random(3)
2987end
2988do
2989 local print <const> = print
2990 print(FLAG)
2991 FLAG = 123
2992end
2377local _module_0 = { } 2993local _module_0 = { }
2378local a, b, c = 1, 2, 3 2994local a, b, c = 1, 2, 3
2379_module_0["a"], _module_0["b"], _module_0["c"] = a, b, c 2995_module_0["a"], _module_0["b"], _module_0["c"] = a, b, c
@@ -2553,6 +3169,59 @@ end
2553local two, four 3169local two, four
2554local _obj_0 = items 3170local _obj_0 = items
2555two, four = _obj_0[2], _obj_0[4] 3171two, four = _obj_0[2], _obj_0[4]
3172local orders = {
3173 "first",
3174 "second",
3175 "third",
3176 "fourth",
3177 "last"
3178}
3179local first, bulk, last = orders[1], (function()
3180 local _accum_0 = { }
3181 local _len_0 = 1
3182 local _max_0 = #orders + -2 + 1
3183 for _index_0 = 2, _max_0 do
3184 local _item_0 = orders[_index_0]
3185 _accum_0[_len_0] = _item_0
3186 _len_0 = _len_0 + 1
3187 end
3188 return _accum_0
3189end)(), orders[#orders]
3190print(first)
3191print(bulk)
3192print(last)
3193local first, rest
3194do
3195 local _obj_0 = orders
3196 first, rest = _obj_0[1], (function()
3197 local _accum_0 = { }
3198 local _len_0 = 1
3199 local _max_0 = #_obj_0
3200 for _index_0 = 2, _max_0 do
3201 local _item_0 = _obj_0[_index_0]
3202 _accum_0[_len_0] = _item_0
3203 _len_0 = _len_0 + 1
3204 end
3205 return _accum_0
3206 end)()
3207end
3208local start, last
3209do
3210 local _obj_0 = orders
3211 start, last = (function()
3212 local _accum_0 = { }
3213 local _len_0 = 1
3214 local _max_0 = #_obj_0 + -2 + 1
3215 for _index_0 = 1, _max_0 do
3216 local _item_0 = _obj_0[_index_0]
3217 _accum_0[_len_0] = _item_0
3218 _len_0 = _len_0 + 1
3219 end
3220 return _accum_0
3221 end)(), _obj_0[#_obj_0]
3222end
3223local _obj_0 = orders
3224first, last = _obj_0[1], _obj_0[#_obj_0]
2556local tuples = { 3225local tuples = {
2557 { 3226 {
2558 "hello", 3227 "hello",
@@ -2617,6 +3286,9 @@ end
2617 local first = select(1, ...) 3286 local first = select(1, ...)
2618 return print(ok, count, first) 3287 return print(ok, count, first)
2619end)(fn(true)) 3288end)(fn(true))
3289local a = 1
3290local b = 2
3291print(a + b)
2620Rx.Observable.fromRange(1, 8):filter(function(x) 3292Rx.Observable.fromRange(1, 8):filter(function(x)
2621 return x % 2 == 0 3293 return x % 2 == 0
2622end):concat(Rx.Observable.of('who do we appreciate')):map(function(value) 3294end):concat(Rx.Observable.of('who do we appreciate')):map(function(value)
@@ -2654,6 +3326,56 @@ end)
2654if success then 3326if success then
2655 print(result) 3327 print(result)
2656end 3328end
3329local a, b, c
3330do
3331 local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function()
3332 return func()
3333 end)
3334 if _ok_0 then
3335 a, b, c = _ret_0, _ret_1, _ret_2
3336 end
3337end
3338do
3339 local _exp_0 = ((function()
3340 return (function(_arg_0, ...)
3341 local _ok_0 = _arg_0
3342 if _ok_0 then
3343 return ...
3344 end
3345 end)(pcall(function()
3346 return func()
3347 end))
3348 end)())
3349 if _exp_0 ~= nil then
3350 a = _exp_0
3351 else
3352 a = "default"
3353 end
3354end
3355f((function()
3356 return (function(_arg_0, ...)
3357 local _ok_0 = _arg_0
3358 if _ok_0 then
3359 return ...
3360 end
3361 end)(pcall(function()
3362 return func()
3363 end))
3364end)())
3365f((function()
3366 return (function(_arg_0, ...)
3367 local _ok_0 = _arg_0
3368 if _ok_0 then
3369 return ...
3370 end
3371 end)(xpcall(function()
3372 print(123)
3373 return func()
3374 end, function(e)
3375 print(e)
3376 return e
3377 end))
3378end)())
2657local a <const> = 123 3379local a <const> = 123
2658local _ <close> = setmetatable({ }, { 3380local _ <close> = setmetatable({ }, {
2659 __close = function() 3381 __close = function()
@@ -2663,10 +3385,19 @@ local _ <close> = setmetatable({ }, {
2663local a, b, c, d 3385local a, b, c, d
2664local _obj_0 = tb 3386local _obj_0 = tb
2665a, b, c, d = _obj_0.a, _obj_0.b, _obj_0[1], _obj_0[2] 3387a, b, c, d = _obj_0.a, _obj_0.b, _obj_0[1], _obj_0[2]
3388Constant = 123
2666local some_string = "Here is a string\n that has a line break in it." 3389local some_string = "Here is a string\n that has a line break in it."
2667print("I am " .. tostring(math.random() * 100) .. "% sure.") 3390print("I am " .. tostring(math.random() * 100) .. "% sure.")
2668local integer = 1000000 3391local integer = 1000000
2669local hex = 0xEFBBBF 3392local hex = 0xEFBBBF
3393local binary = 19
3394local str = "key: value\nlist:\n - item1\n - " .. tostring(expr)
3395local fn
3396fn = function()
3397 local str = "foo:\n bar: baz"
3398 return str
3399end
3400local str = "path: \"C:\\Program Files\\App\"\nnote: 'He said: \"" .. tostring(Hello) .. "!\"'"
2670local my_function 3401local my_function
2671my_function = function() end 3402my_function = function() end
2672my_function() 3403my_function()
@@ -2761,6 +3492,96 @@ if func(1, 2, 3, "hello", "world") then
2761 print("hello") 3492 print("hello")
2762 print("I am inside if") 3493 print("I am inside if")
2763end 3494end
3495local f1
3496f1 = function(_arg_0)
3497 local a, b, c
3498 a, b, c = _arg_0.a, _arg_0.b, _arg_0.c
3499 return print(a, b, c)
3500end
3501f1({
3502 a = 1,
3503 b = "2",
3504 c = { }
3505})
3506local f2
3507f2 = function(_arg_0, c)
3508 local a1, b
3509 a1, b = _arg_0.a, _arg_0.b
3510 if a1 == nil then
3511 a1 = 123
3512 end
3513 if b == nil then
3514 b = 'abc'
3515 end
3516 if c == nil then
3517 c = { }
3518 end
3519end
3520print(a1, b, c)
3521local arg1 = {
3522 a = 0
3523}
3524f2(arg1, arg2)
3525local findFirstEven
3526findFirstEven = function(list)
3527 for _index_0 = 1, #list do
3528 local item = list[_index_0]
3529 if type(item) == "table" then
3530 for _index_1 = 1, #item do
3531 local sub = item[_index_1]
3532 if sub % 2 == 0 then
3533 return sub
3534 end
3535 end
3536 end
3537 end
3538 return nil
3539end
3540local findFirstEven
3541findFirstEven = function(list)
3542 for _index_0 = 1, #list do
3543 local item = list[_index_0]
3544 if type(item) == "table" then
3545 for _index_1 = 1, #item do
3546 local sub = item[_index_1]
3547 if sub % 2 == 0 then
3548 return sub
3549 end
3550 end
3551 end
3552 end
3553 return nil
3554end
3555local f
3556f = function(...)
3557 local t = {
3558 n = select("#", ...),
3559 ...
3560 }
3561 print("argument count:", t.n)
3562 print("table length:", #t)
3563 for i = 1, t.n do
3564 print(t[i])
3565 end
3566end
3567f(1, 2, 3)
3568f("a", "b", "c", "d")
3569f()
3570local process
3571process = function(...)
3572 local args = {
3573 n = select("#", ...),
3574 ...
3575 }
3576 local sum = 0
3577 for i = 1, args.n do
3578 if args[i] ~= nil and type(args[i]) == "number" then
3579 sum = sum + args[i]
3580 end
3581 end
3582 return sum
3583end
3584process(1, nil, 3, nil, 5)
2764f(function() 3585f(function()
2765 return print("hello") 3586 return print("hello")
2766end) 3587end)
@@ -2886,6 +3707,28 @@ for _index_0 = 1, #_list_0 do
2886 _len_0 = _len_0 + 1 3707 _len_0 = _len_0 + 1
2887end 3708end
2888doubled = _accum_0 3709doubled = _accum_0
3710local data = {
3711 a = {
3712 1,
3713 2,
3714 3
3715 },
3716 b = {
3717 4,
3718 5,
3719 6
3720 }
3721}
3722local flat
3723local _accum_0 = { }
3724for k, v in pairs(data) do
3725 local _len_0 = #_accum_0 + 1
3726 for _index_0 = 1, #v do
3727 local _elm_0 = v[_index_0]
3728 _accum_0[_len_0], _len_0 = _elm_0, _len_0 + 1
3729 end
3730end
3731flat = _accum_0
2889local x_coords = { 3732local x_coords = {
2890 4, 3733 4,
2891 5, 3734 5,
@@ -2976,8 +3819,7 @@ local slice
2976local _accum_0 = { } 3819local _accum_0 = { }
2977local _len_0 = 1 3820local _len_0 = 1
2978local _list_0 = items 3821local _list_0 = items
2979local _max_0 = 5 3822for _index_0 = 1, 5 do
2980for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do
2981 local item = _list_0[_index_0] 3823 local item = _list_0[_index_0]
2982 _accum_0[_len_0] = item 3824 _accum_0[_len_0] = item
2983 _len_0 = _len_0 + 1 3825 _len_0 = _len_0 + 1
@@ -2987,7 +3829,8 @@ local slice
2987local _accum_0 = { } 3829local _accum_0 = { }
2988local _len_0 = 1 3830local _len_0 = 1
2989local _list_0 = items 3831local _list_0 = items
2990for _index_0 = 2, #_list_0 do 3832local _max_0 = #_list_0
3833for _index_0 = 2, _max_0 do
2991 local item = _list_0[_index_0] 3834 local item = _list_0[_index_0]
2992 _accum_0[_len_0] = item 3835 _accum_0[_len_0] = item
2993 _len_0 = _len_0 + 1 3836 _len_0 = _len_0 + 1
@@ -2997,12 +3840,46 @@ local slice
2997local _accum_0 = { } 3840local _accum_0 = { }
2998local _len_0 = 1 3841local _len_0 = 1
2999local _list_0 = items 3842local _list_0 = items
3000for _index_0 = 1, #_list_0, 2 do 3843local _max_0 = #_list_0
3844for _index_0 = 1, _max_0, 2 do
3001 local item = _list_0[_index_0] 3845 local item = _list_0[_index_0]
3002 _accum_0[_len_0] = item 3846 _accum_0[_len_0] = item
3003 _len_0 = _len_0 + 1 3847 _len_0 = _len_0 + 1
3004end 3848end
3005slice = _accum_0 3849slice = _accum_0
3850local slice
3851local _accum_0 = { }
3852local _len_0 = 1
3853local _list_0 = items
3854local _min_0 = #_list_0 + -4 + 1
3855local _max_0 = #_list_0 + -1 + 1
3856for _index_0 = _min_0, _max_0 do
3857 local item = _list_0[_index_0]
3858 _accum_0[_len_0] = item
3859 _len_0 = _len_0 + 1
3860end
3861slice = _accum_0
3862local reverse_slice
3863local _accum_0 = { }
3864local _len_0 = 1
3865local _list_0 = items
3866local _min_0 = #_list_0 + -1 + 1
3867for _index_0 = _min_0, 1, -1 do
3868 local item = _list_0[_index_0]
3869 _accum_0[_len_0] = item
3870 _len_0 = _len_0 + 1
3871end
3872reverse_slice = _accum_0
3873local sub_list
3874local _accum_0 = { }
3875local _len_0 = 1
3876local _list_0 = items
3877for _index_0 = 2, 4 do
3878 local _item_0 = _list_0[_index_0]
3879 _accum_0[_len_0] = _item_0
3880 _len_0 = _len_0 + 1
3881end
3882sub_list = _accum_0
3006for i = 10, 20 do 3883for i = 10, 20 do
3007 print(i) 3884 print(i)
3008end 3885end
@@ -3013,8 +3890,7 @@ for key, value in pairs(object) do
3013 print(key, value) 3890 print(key, value)
3014end 3891end
3015local _list_0 = items 3892local _list_0 = items
3016local _max_0 = 4 3893for _index_0 = 2, 4 do
3017for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do
3018 local item = _list_0[_index_0] 3894 local item = _list_0[_index_0]
3019 print(item) 3895 print(item)
3020end 3896end
@@ -3032,12 +3908,24 @@ local _len_0 = 1
3032for i = 1, 20 do 3908for i = 1, 20 do
3033 if i % 2 == 0 then 3909 if i % 2 == 0 then
3034 _accum_0[_len_0] = i * 2 3910 _accum_0[_len_0] = i * 2
3911 _len_0 = _len_0 + 1
3035 else 3912 else
3036 _accum_0[_len_0] = i 3913 _accum_0[_len_0] = i
3914 _len_0 = _len_0 + 1
3037 end 3915 end
3038 _len_0 = _len_0 + 1
3039end 3916end
3040doubled_evens = _accum_0 3917doubled_evens = _accum_0
3918local first_large
3919local _accum_0
3920local _list_0 = numbers
3921for _index_0 = 1, #_list_0 do
3922 local n = _list_0[_index_0]
3923 if n > 10 then
3924 _accum_0 = n
3925 break
3926 end
3927end
3928first_large = _accum_0
3041local func_a 3929local func_a
3042func_a = function() 3930func_a = function()
3043 for i = 1, 10 do 3931 for i = 1, 10 do
@@ -3186,7 +4074,7 @@ if "Robert" == name then
3186elseif "Dan" == name or "Daniel" == name then 4074elseif "Dan" == name or "Daniel" == name then
3187 print("Your name, it's Dan") 4075 print("Your name, it's Dan")
3188else 4076else
3189 print("I don't know about your name") 4077 print("I don't know about you with name " .. tostring(name))
3190end 4078end
3191local b = 1 4079local b = 1
3192local next_number 4080local next_number
@@ -3286,6 +4174,192 @@ if _tab_0 then
3286 end 4174 end
3287 print("Vec2 " .. tostring(x) .. ", " .. tostring(y)) 4175 print("Vec2 " .. tostring(x) .. ", " .. tostring(y))
3288end 4176end
4177local _exp_0 = tb
4178local _type_0 = type(_exp_0)
4179local _tab_0 = "table" == _type_0 or "userdata" == _type_0
4180local _match_0 = false
4181if _tab_0 then
4182 if 1 == _exp_0[1] and 2 == _exp_0[2] and 3 == _exp_0[3] then
4183 _match_0 = true
4184 print("1, 2, 3")
4185 end
4186end
4187if not _match_0 then
4188 local _match_1 = false
4189 if _tab_0 then
4190 local b = _exp_0[2]
4191 if 1 == _exp_0[1] and b ~= nil and 3 == _exp_0[3] then
4192 _match_1 = true
4193 print("1, " .. tostring(b) .. ", 3")
4194 end
4195 end
4196 if not _match_1 then
4197 if _tab_0 then
4198 local b = _exp_0[3]
4199 if b == nil then
4200 b = 3
4201 end
4202 if 1 == _exp_0[1] and 2 == _exp_0[2] then
4203 print("1, 2, " .. tostring(b))
4204 end
4205 end
4206 end
4207end
4208local _exp_0 = tb
4209local _type_0 = type(_exp_0)
4210local _tab_0 = "table" == _type_0 or "userdata" == _type_0
4211local _match_0 = false
4212if _tab_0 then
4213 local result = _exp_0.result
4214 if true == _exp_0.success and result ~= nil then
4215 _match_0 = true
4216 print("success", result)
4217 end
4218end
4219if not _match_0 then
4220 local _match_1 = false
4221 if _tab_0 then
4222 if false == _exp_0.success then
4223 _match_1 = true
4224 print("failed", result)
4225 end
4226 end
4227 if not _match_1 then
4228 print("invalid")
4229 end
4230end
4231local _exp_0 = tb
4232local _type_0 = type(_exp_0)
4233local _tab_0 = "table" == _type_0 or "userdata" == _type_0
4234local _match_0 = false
4235if _tab_0 then
4236 local content
4237 do
4238 local _obj_0 = _exp_0.data
4239 local _type_1 = type(_obj_0)
4240 if "table" == _type_1 or "userdata" == _type_1 then
4241 content = _obj_0.content
4242 end
4243 end
4244 local _val_0
4245 do
4246 local _obj_0 = _exp_0.data
4247 if _obj_0 ~= nil then
4248 _val_0 = _obj_0.type
4249 end
4250 end
4251 if "success" == _val_0 and content ~= nil then
4252 _match_0 = true
4253 print("success", content)
4254 end
4255end
4256if not _match_0 then
4257 local _match_1 = false
4258 if _tab_0 then
4259 local content
4260 do
4261 local _obj_0 = _exp_0.data
4262 local _type_1 = type(_obj_0)
4263 if "table" == _type_1 or "userdata" == _type_1 then
4264 content = _obj_0.content
4265 end
4266 end
4267 local _val_0
4268 do
4269 local _obj_0 = _exp_0.data
4270 if _obj_0 ~= nil then
4271 _val_0 = _obj_0.type
4272 end
4273 end
4274 if "error" == _val_0 and content ~= nil then
4275 _match_1 = true
4276 print("failed", content)
4277 end
4278 end
4279 if not _match_1 then
4280 print("invalid")
4281 end
4282end
4283local _exp_0 = tb
4284local _type_0 = type(_exp_0)
4285local _tab_0 = "table" == _type_0 or "userdata" == _type_0
4286if _tab_0 then
4287 local fourth = _exp_0[4]
4288 local _val_0
4289 do
4290 local _obj_0 = _exp_0[1]
4291 if _obj_0 ~= nil then
4292 _val_0 = _obj_0.a
4293 end
4294 end
4295 local _val_1
4296 do
4297 local _obj_0 = _exp_0[1]
4298 if _obj_0 ~= nil then
4299 _val_1 = _obj_0.b
4300 end
4301 end
4302 local _val_2
4303 do
4304 local _obj_0 = _exp_0[2]
4305 if _obj_0 ~= nil then
4306 _val_2 = _obj_0.a
4307 end
4308 end
4309 local _val_3
4310 do
4311 local _obj_0 = _exp_0[2]
4312 if _obj_0 ~= nil then
4313 _val_3 = _obj_0.b
4314 end
4315 end
4316 local _val_4
4317 do
4318 local _obj_0 = _exp_0[3]
4319 if _obj_0 ~= nil then
4320 _val_4 = _obj_0.a
4321 end
4322 end
4323 local _val_5
4324 do
4325 local _obj_0 = _exp_0[3]
4326 if _obj_0 ~= nil then
4327 _val_5 = _obj_0.b
4328 end
4329 end
4330 if 1 == _val_0 and 2 == _val_1 and 3 == _val_2 and 4 == _val_3 and 5 == _val_4 and 6 == _val_5 and fourth ~= nil then
4331 print("matched", fourth)
4332 end
4333end
4334local segments = {
4335 "admin",
4336 "users",
4337 "logs",
4338 "view"
4339}
4340local _type_0 = type(segments)
4341local _tab_0 = "table" == _type_0 or "userdata" == _type_0
4342if _tab_0 then
4343 local groups
4344 do
4345 local _accum_0 = { }
4346 local _len_0 = 1
4347 local _max_0 = #segments + -3 + 1
4348 for _index_0 = 1, _max_0 do
4349 local _item_0 = segments[_index_0]
4350 _accum_0[_len_0] = _item_0
4351 _len_0 = _len_0 + 1
4352 end
4353 groups = _accum_0
4354 end
4355 local resource = segments[#segments - 1]
4356 local action = segments[#segments]
4357 if resource ~= nil and action ~= nil then
4358 print("Group:", groups)
4359 print("Resource:", resource)
4360 print("Action:", action)
4361 end
4362end
3289local Inventory 4363local Inventory
3290local _class_0 4364local _class_0
3291local _base_0 = { 4365local _base_0 = {
@@ -3942,6 +5016,10 @@ do
3942 _with_1["key-name"] = value 5016 _with_1["key-name"] = value
3943end 5017end
3944_with_0[#_with_0 + 1] = "abc" 5018_with_0[#_with_0 + 1] = "abc"
5019local _with_0 = obj
5020if _with_0 ~= nil then
5021 print(obj.name)
5022end
3945do 5023do
3946 local var = "hello" 5024 local var = "hello"
3947 print(var) 5025 print(var)
diff --git a/spec/outputs/codes_from_doc_zh.lua b/spec/outputs/codes_from_doc_zh.lua
index acd41a0..89335c9 100644
--- a/spec/outputs/codes_from_doc_zh.lua
+++ b/spec/outputs/codes_from_doc_zh.lua
@@ -20,6 +20,38 @@ local inventory = {
20 } 20 }
21 } 21 }
22} 22}
23local map
24map = function(arr, action)
25 local _accum_0 = { }
26 local _len_0 = 1
27 for _index_0 = 1, #arr do
28 local item = arr[_index_0]
29 _accum_0[_len_0] = action(item)
30 _len_0 = _len_0 + 1
31 end
32 return _accum_0
33end
34local filter
35filter = function(arr, cond)
36 local _accum_0 = { }
37 local _len_0 = 1
38 for _index_0 = 1, #arr do
39 local item = arr[_index_0]
40 if cond(item) then
41 _accum_0[_len_0] = item
42 _len_0 = _len_0 + 1
43 end
44 end
45 return _accum_0
46end
47local reduce
48reduce = function(arr, init, action)
49 for _index_0 = 1, #arr do
50 local item = arr[_index_0]
51 init = action(init, item)
52 end
53 return init
54end
23print(reduce(filter(map({ 55print(reduce(filter(map({
24 1, 56 1,
25 2, 57 2,
@@ -41,8 +73,8 @@ local apple = setmetatable({
41if (getmetatable(apple) ~= nil) then 73if (getmetatable(apple) ~= nil) then
42 p(apple.size, apple.color, getmetatable(apple).__index) 74 p(apple.size, apple.color, getmetatable(apple).__index)
43end 75end
44local _ud83c_udf1b = "月之脚本" 76local _u1f31b = "月之脚本"
45_module_0["🌛"] = _ud83c_udf1b 77_module_0["🌛"] = _u1f31b
46return _module_0 78return _module_0
47local area = 6.2831853071796 * 5 79local area = 6.2831853071796 * 5
48print('你好 世界') 80print('你好 世界')
@@ -77,6 +109,12 @@ end
77print("yuescript") 109print("yuescript")
78print(3) 110print(3)
79print("有效的枚举类型:", "Static") 111print("有效的枚举类型:", "Static")
112do
113 print(123, "hello")
114end
115do
116 print(123, "hello")
117end
80if tb ~= nil then 118if tb ~= nil then
81 tb:func() 119 tb:func()
82end 120end
@@ -109,6 +147,21 @@ print((function()
109end)()) 147end)())
110local tab = { } 148local tab = { }
111tab[#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
112local parts = { 165local parts = {
113 "shoulders", 166 "shoulders",
114 "knees" 167 "knees"
@@ -177,6 +230,18 @@ for _key_0, _value_0 in pairs(b) do
177 end 230 end
178end 231end
179merge = _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
180local mt = { } 245local mt = { }
181local add 246local add
182add = function(self, right) 247add = function(self, right)
@@ -307,6 +372,14 @@ func({
307 2, 372 2,
308 3 373 3
309}) 374})
375local f
376f = function()
377 return {
378 1,
379 2,
380 3
381 }
382end
310local tb = { 383local tb = {
311 name = "abc", 384 name = "abc",
312 values = { 385 values = {
@@ -368,6 +441,25 @@ do
368 local _obj_0 = require("export") 441 local _obj_0 = require("export")
369 one, two, ch = _obj_0[1], _obj_0[2], _obj_0.Something.umm[1] 442 one, two, ch = _obj_0[1], _obj_0[2], _obj_0.Something.umm[1]
370end 443end
444do
445 local tostring <const> = tostring
446 local concat <const> = table.concat
447 print(concat({
448 "a",
449 tostring(1)
450 }))
451end
452do
453 local print <const> = print
454 local math <const> = math
455 print("hello")
456 math.random(3)
457end
458do
459 local print <const> = print
460 print(FLAG)
461 FLAG = 123
462end
371local _module_0 = { } 463local _module_0 = { }
372local a, b, c = 1, 2, 3 464local a, b, c = 1, 2, 3
373_module_0["a"], _module_0["b"], _module_0["c"] = a, b, c 465_module_0["a"], _module_0["b"], _module_0["c"] = a, b, c
@@ -547,6 +639,59 @@ end
547local two, four 639local two, four
548local _obj_0 = items 640local _obj_0 = items
549two, four = _obj_0[2], _obj_0[4] 641two, four = _obj_0[2], _obj_0[4]
642local orders = {
643 "first",
644 "second",
645 "third",
646 "fourth",
647 "last"
648}
649local first, bulk, last = orders[1], (function()
650 local _accum_0 = { }
651 local _len_0 = 1
652 local _max_0 = #orders + -2 + 1
653 for _index_0 = 2, _max_0 do
654 local _item_0 = orders[_index_0]
655 _accum_0[_len_0] = _item_0
656 _len_0 = _len_0 + 1
657 end
658 return _accum_0
659end)(), orders[#orders]
660print(first)
661print(bulk)
662print(last)
663local first, rest
664do
665 local _obj_0 = orders
666 first, rest = _obj_0[1], (function()
667 local _accum_0 = { }
668 local _len_0 = 1
669 local _max_0 = #_obj_0
670 for _index_0 = 2, _max_0 do
671 local _item_0 = _obj_0[_index_0]
672 _accum_0[_len_0] = _item_0
673 _len_0 = _len_0 + 1
674 end
675 return _accum_0
676 end)()
677end
678local start, last
679do
680 local _obj_0 = orders
681 start, last = (function()
682 local _accum_0 = { }
683 local _len_0 = 1
684 local _max_0 = #_obj_0 + -2 + 1
685 for _index_0 = 1, _max_0 do
686 local _item_0 = _obj_0[_index_0]
687 _accum_0[_len_0] = _item_0
688 _len_0 = _len_0 + 1
689 end
690 return _accum_0
691 end)(), _obj_0[#_obj_0]
692end
693local _obj_0 = orders
694first, last = _obj_0[1], _obj_0[#_obj_0]
550local tuples = { 695local tuples = {
551 { 696 {
552 "hello", 697 "hello",
@@ -611,6 +756,9 @@ end
611 local first = select(1, ...) 756 local first = select(1, ...)
612 return print(ok, count, first) 757 return print(ok, count, first)
613end)(fn(true)) 758end)(fn(true))
759local a = 1
760local b = 2
761print(a + b)
614Rx.Observable.fromRange(1, 8):filter(function(x) 762Rx.Observable.fromRange(1, 8):filter(function(x)
615 return x % 2 == 0 763 return x % 2 == 0
616end):concat(Rx.Observable.of('who do we appreciate')):map(function(value) 764end):concat(Rx.Observable.of('who do we appreciate')):map(function(value)
@@ -648,6 +796,56 @@ end)
648if success then 796if success then
649 print(result) 797 print(result)
650end 798end
799local a, b, c
800do
801 local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function()
802 return func()
803 end)
804 if _ok_0 then
805 a, b, c = _ret_0, _ret_1, _ret_2
806 end
807end
808do
809 local _exp_0 = ((function()
810 return (function(_arg_0, ...)
811 local _ok_0 = _arg_0
812 if _ok_0 then
813 return ...
814 end
815 end)(pcall(function()
816 return func()
817 end))
818 end)())
819 if _exp_0 ~= nil then
820 a = _exp_0
821 else
822 a = "default"
823 end
824end
825f((function()
826 return (function(_arg_0, ...)
827 local _ok_0 = _arg_0
828 if _ok_0 then
829 return ...
830 end
831 end)(pcall(function()
832 return func()
833 end))
834end)())
835f((function()
836 return (function(_arg_0, ...)
837 local _ok_0 = _arg_0
838 if _ok_0 then
839 return ...
840 end
841 end)(xpcall(function()
842 print(123)
843 return func()
844 end, function(e)
845 print(e)
846 return e
847 end))
848end)())
651local a <const> = 123 849local a <const> = 123
652local _ <close> = setmetatable({ }, { 850local _ <close> = setmetatable({ }, {
653 __close = function() 851 __close = function()
@@ -657,10 +855,19 @@ local _ <close> = setmetatable({ }, {
657local a, b, c, d 855local a, b, c, d
658local _obj_0 = tb 856local _obj_0 = tb
659a, b, c, d = _obj_0.a, _obj_0.b, _obj_0[1], _obj_0[2] 857a, b, c, d = _obj_0.a, _obj_0.b, _obj_0[1], _obj_0[2]
858Constant = 123
660local some_string = "这是一个字符串\n 并包括一个æ¢è¡Œã€‚" 859local some_string = "这是一个字符串\n 并包括一个æ¢è¡Œã€‚"
661print("我有" .. tostring(math.random() * 100) .. "%的把æ¡ã€‚") 860print("我有" .. tostring(math.random() * 100) .. "%的把æ¡ã€‚")
662local integer = 1000000 861local integer = 1000000
663local hex = 0xEFBBBF 862local hex = 0xEFBBBF
863local binary = 19
864local str = "key: value\nlist:\n - item1\n - " .. tostring(expr)
865local fn
866fn = function()
867 local str = "foo:\n bar: baz"
868 return str
869end
870local str = "path: \"C:\\Program Files\\App\"\nnote: 'He said: \"" .. tostring(Hello) .. "!\"'"
664local my_function 871local my_function
665my_function = function() end 872my_function = function() end
666my_function() 873my_function()
@@ -749,6 +956,66 @@ if func(1, 2, 3, "你好", "世界") then
749 print("hello") 956 print("hello")
750 print("我在if内部") 957 print("我在if内部")
751end 958end
959local f1
960f1 = function(_arg_0)
961 local a, b, c
962 a, b, c = _arg_0.a, _arg_0.b, _arg_0.c
963 return print(a, b, c)
964end
965f1({
966 a = 1,
967 b = "2",
968 c = { }
969})
970local f2
971f2 = function(_arg_0, c)
972 local a1, b
973 a1, b = _arg_0.a, _arg_0.b
974 if a1 == nil then
975 a1 = 123
976 end
977 if b == nil then
978 b = 'abc'
979 end
980 if c == nil then
981 c = { }
982 end
983 return print(a1, b, c)
984end
985local arg1 = {
986 a = 0
987}
988f2(arg1, arg2)
989local f
990f = function(...)
991 local t = {
992 n = select("#", ...),
993 ...
994 }
995 print("傿•°ä¸ªæ•°:", t.n)
996 print("表长度:", #t)
997 for i = 1, t.n do
998 print(t[i])
999 end
1000end
1001f(1, 2, 3)
1002f("a", "b", "c", "d")
1003f()
1004local process
1005process = function(...)
1006 local args = {
1007 n = select("#", ...),
1008 ...
1009 }
1010 local sum = 0
1011 for i = 1, args.n do
1012 if args[i] ~= nil and type(args[i]) == "number" then
1013 sum = sum + args[i]
1014 end
1015 end
1016 return sum
1017end
1018process(1, nil, 3, nil, 5)
752f(function() 1019f(function()
753 return print("hello") 1020 return print("hello")
754end) 1021end)
@@ -874,6 +1141,28 @@ for _index_0 = 1, #_list_0 do
874 _len_0 = _len_0 + 1 1141 _len_0 = _len_0 + 1
875end 1142end
876doubled = _accum_0 1143doubled = _accum_0
1144local data = {
1145 a = {
1146 1,
1147 2,
1148 3
1149 },
1150 b = {
1151 4,
1152 5,
1153 6
1154 }
1155}
1156local flat
1157local _accum_0 = { }
1158for k, v in pairs(data) do
1159 local _len_0 = #_accum_0 + 1
1160 for _index_0 = 1, #v do
1161 local _elm_0 = v[_index_0]
1162 _accum_0[_len_0], _len_0 = _elm_0, _len_0 + 1
1163 end
1164end
1165flat = _accum_0
877local x_coords = { 1166local x_coords = {
878 4, 1167 4,
879 5, 1168 5,
@@ -964,8 +1253,18 @@ local slice
964local _accum_0 = { } 1253local _accum_0 = { }
965local _len_0 = 1 1254local _len_0 = 1
966local _list_0 = items 1255local _list_0 = items
967local _max_0 = 5 1256for _index_0 = 1, 5 do
968for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do 1257 local item = _list_0[_index_0]
1258 _accum_0[_len_0] = item
1259 _len_0 = _len_0 + 1
1260end
1261slice = _accum_0
1262local slice
1263local _accum_0 = { }
1264local _len_0 = 1
1265local _list_0 = items
1266local _max_0 = #_list_0
1267for _index_0 = 2, _max_0 do
969 local item = _list_0[_index_0] 1268 local item = _list_0[_index_0]
970 _accum_0[_len_0] = item 1269 _accum_0[_len_0] = item
971 _len_0 = _len_0 + 1 1270 _len_0 = _len_0 + 1
@@ -975,7 +1274,8 @@ local slice
975local _accum_0 = { } 1274local _accum_0 = { }
976local _len_0 = 1 1275local _len_0 = 1
977local _list_0 = items 1276local _list_0 = items
978for _index_0 = 2, #_list_0 do 1277local _max_0 = #_list_0
1278for _index_0 = 1, _max_0, 2 do
979 local item = _list_0[_index_0] 1279 local item = _list_0[_index_0]
980 _accum_0[_len_0] = item 1280 _accum_0[_len_0] = item
981 _len_0 = _len_0 + 1 1281 _len_0 = _len_0 + 1
@@ -985,12 +1285,35 @@ local slice
985local _accum_0 = { } 1285local _accum_0 = { }
986local _len_0 = 1 1286local _len_0 = 1
987local _list_0 = items 1287local _list_0 = items
988for _index_0 = 1, #_list_0, 2 do 1288local _min_0 = #_list_0 + -4 + 1
1289local _max_0 = #_list_0 + -1 + 1
1290for _index_0 = _min_0, _max_0 do
989 local item = _list_0[_index_0] 1291 local item = _list_0[_index_0]
990 _accum_0[_len_0] = item 1292 _accum_0[_len_0] = item
991 _len_0 = _len_0 + 1 1293 _len_0 = _len_0 + 1
992end 1294end
993slice = _accum_0 1295slice = _accum_0
1296local reverse_slice
1297local _accum_0 = { }
1298local _len_0 = 1
1299local _list_0 = items
1300local _min_0 = #_list_0 + -1 + 1
1301for _index_0 = _min_0, 1, -1 do
1302 local item = _list_0[_index_0]
1303 _accum_0[_len_0] = item
1304 _len_0 = _len_0 + 1
1305end
1306reverse_slice = _accum_0
1307local sub_list
1308local _accum_0 = { }
1309local _len_0 = 1
1310local _list_0 = items
1311for _index_0 = 2, 4 do
1312 local _item_0 = _list_0[_index_0]
1313 _accum_0[_len_0] = _item_0
1314 _len_0 = _len_0 + 1
1315end
1316sub_list = _accum_0
994for i = 10, 20 do 1317for i = 10, 20 do
995 print(i) 1318 print(i)
996end 1319end
@@ -1001,8 +1324,7 @@ for key, value in pairs(object) do
1001 print(key, value) 1324 print(key, value)
1002end 1325end
1003local _list_0 = items 1326local _list_0 = items
1004local _max_0 = 4 1327for _index_0 = 2, 4 do
1005for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do
1006 local item = _list_0[_index_0] 1328 local item = _list_0[_index_0]
1007 print(item) 1329 print(item)
1008end 1330end
@@ -1020,12 +1342,24 @@ local _len_0 = 1
1020for i = 1, 20 do 1342for i = 1, 20 do
1021 if i % 2 == 0 then 1343 if i % 2 == 0 then
1022 _accum_0[_len_0] = i * 2 1344 _accum_0[_len_0] = i * 2
1345 _len_0 = _len_0 + 1
1023 else 1346 else
1024 _accum_0[_len_0] = i 1347 _accum_0[_len_0] = i
1348 _len_0 = _len_0 + 1
1025 end 1349 end
1026 _len_0 = _len_0 + 1
1027end 1350end
1028doubled_evens = _accum_0 1351doubled_evens = _accum_0
1352local first_large
1353local _accum_0
1354local _list_0 = numbers
1355for _index_0 = 1, #_list_0 do
1356 local n = _list_0[_index_0]
1357 if n > 10 then
1358 _accum_0 = n
1359 break
1360 end
1361end
1362first_large = _accum_0
1029local func_a 1363local func_a
1030func_a = function() 1364func_a = function()
1031 for i = 1, 10 do 1365 for i = 1, 10 do
@@ -1174,7 +1508,7 @@ if "Robert" == name then
1174elseif "Dan" == name or "Daniel" == name then 1508elseif "Dan" == name or "Daniel" == name then
1175 print("ä½ çš„å字是Dan") 1509 print("ä½ çš„å字是Dan")
1176else 1510else
1177 print("我ä¸çŸ¥é“ä½ çš„åå­—") 1511 print("我ä¸è®¤è¯†ä½ ï¼Œä½ çš„å字是" .. tostring(name))
1178end 1512end
1179local b = 1 1513local b = 1
1180local next_number 1514local next_number
@@ -1274,6 +1608,192 @@ if _tab_0 then
1274 end 1608 end
1275 print("Vec2 " .. tostring(x) .. ", " .. tostring(y)) 1609 print("Vec2 " .. tostring(x) .. ", " .. tostring(y))
1276end 1610end
1611local _exp_0 = tb
1612local _type_0 = type(_exp_0)
1613local _tab_0 = "table" == _type_0 or "userdata" == _type_0
1614local _match_0 = false
1615if _tab_0 then
1616 if 1 == _exp_0[1] and 2 == _exp_0[2] and 3 == _exp_0[3] then
1617 _match_0 = true
1618 print("1, 2, 3")
1619 end
1620end
1621if not _match_0 then
1622 local _match_1 = false
1623 if _tab_0 then
1624 local b = _exp_0[2]
1625 if 1 == _exp_0[1] and b ~= nil and 3 == _exp_0[3] then
1626 _match_1 = true
1627 print("1, " .. tostring(b) .. ", 3")
1628 end
1629 end
1630 if not _match_1 then
1631 if _tab_0 then
1632 local b = _exp_0[3]
1633 if b == nil then
1634 b = 3
1635 end
1636 if 1 == _exp_0[1] and 2 == _exp_0[2] then
1637 print("1, 2, " .. tostring(b))
1638 end
1639 end
1640 end
1641end
1642local _exp_0 = tb
1643local _type_0 = type(_exp_0)
1644local _tab_0 = "table" == _type_0 or "userdata" == _type_0
1645local _match_0 = false
1646if _tab_0 then
1647 local result = _exp_0.result
1648 if true == _exp_0.success and result ~= nil then
1649 _match_0 = true
1650 print("æˆåŠŸ", result)
1651 end
1652end
1653if not _match_0 then
1654 local _match_1 = false
1655 if _tab_0 then
1656 if false == _exp_0.success then
1657 _match_1 = true
1658 print("失败", result)
1659 end
1660 end
1661 if not _match_1 then
1662 print("无效值")
1663 end
1664end
1665local _exp_0 = tb
1666local _type_0 = type(_exp_0)
1667local _tab_0 = "table" == _type_0 or "userdata" == _type_0
1668local _match_0 = false
1669if _tab_0 then
1670 local content
1671 do
1672 local _obj_0 = _exp_0.data
1673 local _type_1 = type(_obj_0)
1674 if "table" == _type_1 or "userdata" == _type_1 then
1675 content = _obj_0.content
1676 end
1677 end
1678 local _val_0
1679 do
1680 local _obj_0 = _exp_0.data
1681 if _obj_0 ~= nil then
1682 _val_0 = _obj_0.type
1683 end
1684 end
1685 if "success" == _val_0 and content ~= nil then
1686 _match_0 = true
1687 print("æˆåŠŸ", content)
1688 end
1689end
1690if not _match_0 then
1691 local _match_1 = false
1692 if _tab_0 then
1693 local content
1694 do
1695 local _obj_0 = _exp_0.data
1696 local _type_1 = type(_obj_0)
1697 if "table" == _type_1 or "userdata" == _type_1 then
1698 content = _obj_0.content
1699 end
1700 end
1701 local _val_0
1702 do
1703 local _obj_0 = _exp_0.data
1704 if _obj_0 ~= nil then
1705 _val_0 = _obj_0.type
1706 end
1707 end
1708 if "error" == _val_0 and content ~= nil then
1709 _match_1 = true
1710 print("失败", content)
1711 end
1712 end
1713 if not _match_1 then
1714 print("无效值")
1715 end
1716end
1717local _exp_0 = tb
1718local _type_0 = type(_exp_0)
1719local _tab_0 = "table" == _type_0 or "userdata" == _type_0
1720if _tab_0 then
1721 local fourth = _exp_0[4]
1722 local _val_0
1723 do
1724 local _obj_0 = _exp_0[1]
1725 if _obj_0 ~= nil then
1726 _val_0 = _obj_0.a
1727 end
1728 end
1729 local _val_1
1730 do
1731 local _obj_0 = _exp_0[1]
1732 if _obj_0 ~= nil then
1733 _val_1 = _obj_0.b
1734 end
1735 end
1736 local _val_2
1737 do
1738 local _obj_0 = _exp_0[2]
1739 if _obj_0 ~= nil then
1740 _val_2 = _obj_0.a
1741 end
1742 end
1743 local _val_3
1744 do
1745 local _obj_0 = _exp_0[2]
1746 if _obj_0 ~= nil then
1747 _val_3 = _obj_0.b
1748 end
1749 end
1750 local _val_4
1751 do
1752 local _obj_0 = _exp_0[3]
1753 if _obj_0 ~= nil then
1754 _val_4 = _obj_0.a
1755 end
1756 end
1757 local _val_5
1758 do
1759 local _obj_0 = _exp_0[3]
1760 if _obj_0 ~= nil then
1761 _val_5 = _obj_0.b
1762 end
1763 end
1764 if 1 == _val_0 and 2 == _val_1 and 3 == _val_2 and 4 == _val_3 and 5 == _val_4 and 6 == _val_5 and fourth ~= nil then
1765 print("åŒ¹é…æˆåŠŸ", fourth)
1766 end
1767end
1768local segments = {
1769 "admin",
1770 "users",
1771 "logs",
1772 "view"
1773}
1774local _type_0 = type(segments)
1775local _tab_0 = "table" == _type_0 or "userdata" == _type_0
1776if _tab_0 then
1777 local groups
1778 do
1779 local _accum_0 = { }
1780 local _len_0 = 1
1781 local _max_0 = #segments + -3 + 1
1782 for _index_0 = 1, _max_0 do
1783 local _item_0 = segments[_index_0]
1784 _accum_0[_len_0] = _item_0
1785 _len_0 = _len_0 + 1
1786 end
1787 groups = _accum_0
1788 end
1789 local resource = segments[#segments - 1]
1790 local action = segments[#segments]
1791 if resource ~= nil and action ~= nil then
1792 print("Group:", groups)
1793 print("Resource:", resource)
1794 print("Action:", action)
1795 end
1796end
1277local Inventory 1797local Inventory
1278local _class_0 1798local _class_0
1279local _base_0 = { 1799local _base_0 = {
@@ -1930,6 +2450,10 @@ do
1930 _with_1["key-name"] = value 2450 _with_1["key-name"] = value
1931end 2451end
1932_with_0[#_with_0 + 1] = "abc" 2452_with_0[#_with_0 + 1] = "abc"
2453local _with_0 = obj
2454if _with_0 ~= nil then
2455 print(obj.name)
2456end
1933do 2457do
1934 local var = "hello" 2458 local var = "hello"
1935 print(var) 2459 print(var)
@@ -2020,6 +2544,38 @@ local inventory = {
2020 } 2544 }
2021 } 2545 }
2022} 2546}
2547local map
2548map = function(arr, action)
2549 local _accum_0 = { }
2550 local _len_0 = 1
2551 for _index_0 = 1, #arr do
2552 local item = arr[_index_0]
2553 _accum_0[_len_0] = action(item)
2554 _len_0 = _len_0 + 1
2555 end
2556 return _accum_0
2557end
2558local filter
2559filter = function(arr, cond)
2560 local _accum_0 = { }
2561 local _len_0 = 1
2562 for _index_0 = 1, #arr do
2563 local item = arr[_index_0]
2564 if cond(item) then
2565 _accum_0[_len_0] = item
2566 _len_0 = _len_0 + 1
2567 end
2568 end
2569 return _accum_0
2570end
2571local reduce
2572reduce = function(arr, init, action)
2573 for _index_0 = 1, #arr do
2574 local item = arr[_index_0]
2575 init = action(init, item)
2576 end
2577 return init
2578end
2023print(reduce(filter(map({ 2579print(reduce(filter(map({
2024 1, 2580 1,
2025 2, 2581 2,
@@ -2041,8 +2597,8 @@ local apple = setmetatable({
2041if (getmetatable(apple) ~= nil) then 2597if (getmetatable(apple) ~= nil) then
2042 p(apple.size, apple.color, getmetatable(apple).__index) 2598 p(apple.size, apple.color, getmetatable(apple).__index)
2043end 2599end
2044local _ud83c_udf1b = "月之脚本" 2600local _u1f31b = "月之脚本"
2045_module_0["🌛"] = _ud83c_udf1b 2601_module_0["🌛"] = _u1f31b
2046return _module_0 2602return _module_0
2047local area = 6.2831853071796 * 5 2603local area = 6.2831853071796 * 5
2048print('你好 世界') 2604print('你好 世界')
@@ -2077,6 +2633,12 @@ end
2077print("yuescript") 2633print("yuescript")
2078print(3) 2634print(3)
2079print("有效的枚举类型:", "Static") 2635print("有效的枚举类型:", "Static")
2636do
2637 print(123, "hello")
2638end
2639do
2640 print(123, "hello")
2641end
2080if tb ~= nil then 2642if tb ~= nil then
2081 tb:func() 2643 tb:func()
2082end 2644end
@@ -2109,6 +2671,21 @@ print((function()
2109end)()) 2671end)())
2110local tab = { } 2672local tab = { }
2111tab[#tab + 1] = "Value" 2673tab[#tab + 1] = "Value"
2674local tbA = {
2675 1,
2676 2,
2677 3
2678}
2679local tbB = {
2680 4,
2681 5,
2682 6
2683}
2684local _len_0 = #tbA + 1
2685for _index_0 = 1, #tbB do
2686 local _elm_0 = tbB[_index_0]
2687 tbA[_len_0], _len_0 = _elm_0, _len_0 + 1
2688end
2112local parts = { 2689local parts = {
2113 "shoulders", 2690 "shoulders",
2114 "knees" 2691 "knees"
@@ -2177,6 +2754,18 @@ for _key_0, _value_0 in pairs(b) do
2177 end 2754 end
2178end 2755end
2179merge = _tab_0 2756merge = _tab_0
2757local last
2758do
2759 local _item_0 = data.items
2760 last = _item_0[#_item_0]
2761end
2762local second_last
2763do
2764 local _item_0 = data.items
2765 second_last = _item_0[#_item_0 - 1]
2766end
2767local _obj_0 = data.items
2768_obj_0[#_obj_0] = 1
2180local mt = { } 2769local mt = { }
2181local add 2770local add
2182add = function(self, right) 2771add = function(self, right)
@@ -2307,6 +2896,14 @@ func({
2307 2, 2896 2,
2308 3 2897 3
2309}) 2898})
2899local f
2900f = function()
2901 return {
2902 1,
2903 2,
2904 3
2905 }
2906end
2310local tb = { 2907local tb = {
2311 name = "abc", 2908 name = "abc",
2312 values = { 2909 values = {
@@ -2368,6 +2965,25 @@ do
2368 local _obj_0 = require("export") 2965 local _obj_0 = require("export")
2369 one, two, ch = _obj_0[1], _obj_0[2], _obj_0.Something.umm[1] 2966 one, two, ch = _obj_0[1], _obj_0[2], _obj_0.Something.umm[1]
2370end 2967end
2968do
2969 local tostring <const> = tostring
2970 local concat <const> = table.concat
2971 print(concat({
2972 "a",
2973 tostring(1)
2974 }))
2975end
2976do
2977 local print <const> = print
2978 local math <const> = math
2979 print("hello")
2980 math.random(3)
2981end
2982do
2983 local print <const> = print
2984 print(FLAG)
2985 FLAG = 123
2986end
2371local _module_0 = { } 2987local _module_0 = { }
2372local a, b, c = 1, 2, 3 2988local a, b, c = 1, 2, 3
2373_module_0["a"], _module_0["b"], _module_0["c"] = a, b, c 2989_module_0["a"], _module_0["b"], _module_0["c"] = a, b, c
@@ -2547,6 +3163,59 @@ end
2547local two, four 3163local two, four
2548local _obj_0 = items 3164local _obj_0 = items
2549two, four = _obj_0[2], _obj_0[4] 3165two, four = _obj_0[2], _obj_0[4]
3166local orders = {
3167 "first",
3168 "second",
3169 "third",
3170 "fourth",
3171 "last"
3172}
3173local first, bulk, last = orders[1], (function()
3174 local _accum_0 = { }
3175 local _len_0 = 1
3176 local _max_0 = #orders + -2 + 1
3177 for _index_0 = 2, _max_0 do
3178 local _item_0 = orders[_index_0]
3179 _accum_0[_len_0] = _item_0
3180 _len_0 = _len_0 + 1
3181 end
3182 return _accum_0
3183end)(), orders[#orders]
3184print(first)
3185print(bulk)
3186print(last)
3187local first, rest
3188do
3189 local _obj_0 = orders
3190 first, rest = _obj_0[1], (function()
3191 local _accum_0 = { }
3192 local _len_0 = 1
3193 local _max_0 = #_obj_0
3194 for _index_0 = 2, _max_0 do
3195 local _item_0 = _obj_0[_index_0]
3196 _accum_0[_len_0] = _item_0
3197 _len_0 = _len_0 + 1
3198 end
3199 return _accum_0
3200 end)()
3201end
3202local start, last
3203do
3204 local _obj_0 = orders
3205 start, last = (function()
3206 local _accum_0 = { }
3207 local _len_0 = 1
3208 local _max_0 = #_obj_0 + -2 + 1
3209 for _index_0 = 1, _max_0 do
3210 local _item_0 = _obj_0[_index_0]
3211 _accum_0[_len_0] = _item_0
3212 _len_0 = _len_0 + 1
3213 end
3214 return _accum_0
3215 end)(), _obj_0[#_obj_0]
3216end
3217local _obj_0 = orders
3218first, last = _obj_0[1], _obj_0[#_obj_0]
2550local tuples = { 3219local tuples = {
2551 { 3220 {
2552 "hello", 3221 "hello",
@@ -2611,6 +3280,9 @@ end
2611 local first = select(1, ...) 3280 local first = select(1, ...)
2612 return print(ok, count, first) 3281 return print(ok, count, first)
2613end)(fn(true)) 3282end)(fn(true))
3283local a = 1
3284local b = 2
3285print(a + b)
2614Rx.Observable.fromRange(1, 8):filter(function(x) 3286Rx.Observable.fromRange(1, 8):filter(function(x)
2615 return x % 2 == 0 3287 return x % 2 == 0
2616end):concat(Rx.Observable.of('who do we appreciate')):map(function(value) 3288end):concat(Rx.Observable.of('who do we appreciate')):map(function(value)
@@ -2648,6 +3320,56 @@ end)
2648if success then 3320if success then
2649 print(result) 3321 print(result)
2650end 3322end
3323local a, b, c
3324do
3325 local _ok_0, _ret_0, _ret_1, _ret_2 = pcall(function()
3326 return func()
3327 end)
3328 if _ok_0 then
3329 a, b, c = _ret_0, _ret_1, _ret_2
3330 end
3331end
3332do
3333 local _exp_0 = ((function()
3334 return (function(_arg_0, ...)
3335 local _ok_0 = _arg_0
3336 if _ok_0 then
3337 return ...
3338 end
3339 end)(pcall(function()
3340 return func()
3341 end))
3342 end)())
3343 if _exp_0 ~= nil then
3344 a = _exp_0
3345 else
3346 a = "default"
3347 end
3348end
3349f((function()
3350 return (function(_arg_0, ...)
3351 local _ok_0 = _arg_0
3352 if _ok_0 then
3353 return ...
3354 end
3355 end)(pcall(function()
3356 return func()
3357 end))
3358end)())
3359f((function()
3360 return (function(_arg_0, ...)
3361 local _ok_0 = _arg_0
3362 if _ok_0 then
3363 return ...
3364 end
3365 end)(xpcall(function()
3366 print(123)
3367 return func()
3368 end, function(e)
3369 print(e)
3370 return e
3371 end))
3372end)())
2651local a <const> = 123 3373local a <const> = 123
2652local _ <close> = setmetatable({ }, { 3374local _ <close> = setmetatable({ }, {
2653 __close = function() 3375 __close = function()
@@ -2657,10 +3379,19 @@ local _ <close> = setmetatable({ }, {
2657local a, b, c, d 3379local a, b, c, d
2658local _obj_0 = tb 3380local _obj_0 = tb
2659a, b, c, d = _obj_0.a, _obj_0.b, _obj_0[1], _obj_0[2] 3381a, b, c, d = _obj_0.a, _obj_0.b, _obj_0[1], _obj_0[2]
3382Constant = 123
2660local some_string = "这是一个字符串\n 并包括一个æ¢è¡Œã€‚" 3383local some_string = "这是一个字符串\n 并包括一个æ¢è¡Œã€‚"
2661print("我有" .. tostring(math.random() * 100) .. "%的把æ¡ã€‚") 3384print("我有" .. tostring(math.random() * 100) .. "%的把æ¡ã€‚")
2662local integer = 1000000 3385local integer = 1000000
2663local hex = 0xEFBBBF 3386local hex = 0xEFBBBF
3387local binary = 19
3388local str = "key: value\nlist:\n - item1\n - " .. tostring(expr)
3389local fn
3390fn = function()
3391 local str = "foo:\n bar: baz"
3392 return str
3393end
3394local str = "path: \"C:\\Program Files\\App\"\nnote: 'He said: \"" .. tostring(Hello) .. "!\"'"
2664local my_function 3395local my_function
2665my_function = function() end 3396my_function = function() end
2666my_function() 3397my_function()
@@ -2749,6 +3480,96 @@ if func(1, 2, 3, "你好", "世界") then
2749 print("你好") 3480 print("你好")
2750 print("我在if内部") 3481 print("我在if内部")
2751end 3482end
3483local f1
3484f1 = function(_arg_0)
3485 local a, b, c
3486 a, b, c = _arg_0.a, _arg_0.b, _arg_0.c
3487 return print(a, b, c)
3488end
3489f1({
3490 a = 1,
3491 b = "2",
3492 c = { }
3493})
3494local f2
3495f2 = function(_arg_0, c)
3496 local a1, b
3497 a1, b = _arg_0.a, _arg_0.b
3498 if a1 == nil then
3499 a1 = 123
3500 end
3501 if b == nil then
3502 b = 'abc'
3503 end
3504 if c == nil then
3505 c = { }
3506 end
3507 return print(a1, b, c)
3508end
3509local arg1 = {
3510 a = 0
3511}
3512f2(arg1, arg2)
3513local findFirstEven
3514findFirstEven = function(list)
3515 for _index_0 = 1, #list do
3516 local item = list[_index_0]
3517 if type(item) == "table" then
3518 for _index_1 = 1, #item do
3519 local sub = item[_index_1]
3520 if sub % 2 == 0 then
3521 return sub
3522 end
3523 end
3524 end
3525 end
3526 return nil
3527end
3528local findFirstEven
3529findFirstEven = function(list)
3530 for _index_0 = 1, #list do
3531 local item = list[_index_0]
3532 if type(item) == "table" then
3533 for _index_1 = 1, #item do
3534 local sub = item[_index_1]
3535 if sub % 2 == 0 then
3536 return sub
3537 end
3538 end
3539 end
3540 end
3541 return nil
3542end
3543local f
3544f = function(...)
3545 local t = {
3546 n = select("#", ...),
3547 ...
3548 }
3549 print("傿•°ä¸ªæ•°:", t.n)
3550 print("表长度:", #t)
3551 for i = 1, t.n do
3552 print(t[i])
3553 end
3554end
3555f(1, 2, 3)
3556f("a", "b", "c", "d")
3557f()
3558local process
3559process = function(...)
3560 local args = {
3561 n = select("#", ...),
3562 ...
3563 }
3564 local sum = 0
3565 for i = 1, args.n do
3566 if args[i] ~= nil and type(args[i]) == "number" then
3567 sum = sum + args[i]
3568 end
3569 end
3570 return sum
3571end
3572process(1, nil, 3, nil, 5)
2752f(function() 3573f(function()
2753 return print("hello") 3574 return print("hello")
2754end) 3575end)
@@ -2874,6 +3695,28 @@ for _index_0 = 1, #_list_0 do
2874 _len_0 = _len_0 + 1 3695 _len_0 = _len_0 + 1
2875end 3696end
2876doubled = _accum_0 3697doubled = _accum_0
3698local data = {
3699 a = {
3700 1,
3701 2,
3702 3
3703 },
3704 b = {
3705 4,
3706 5,
3707 6
3708 }
3709}
3710local flat
3711local _accum_0 = { }
3712for k, v in pairs(data) do
3713 local _len_0 = #_accum_0 + 1
3714 for _index_0 = 1, #v do
3715 local _elm_0 = v[_index_0]
3716 _accum_0[_len_0], _len_0 = _elm_0, _len_0 + 1
3717 end
3718end
3719flat = _accum_0
2877local x_coords = { 3720local x_coords = {
2878 4, 3721 4,
2879 5, 3722 5,
@@ -2964,8 +3807,7 @@ local slice
2964local _accum_0 = { } 3807local _accum_0 = { }
2965local _len_0 = 1 3808local _len_0 = 1
2966local _list_0 = items 3809local _list_0 = items
2967local _max_0 = 5 3810for _index_0 = 1, 5 do
2968for _index_0 = 1, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do
2969 local item = _list_0[_index_0] 3811 local item = _list_0[_index_0]
2970 _accum_0[_len_0] = item 3812 _accum_0[_len_0] = item
2971 _len_0 = _len_0 + 1 3813 _len_0 = _len_0 + 1
@@ -2975,7 +3817,8 @@ local slice
2975local _accum_0 = { } 3817local _accum_0 = { }
2976local _len_0 = 1 3818local _len_0 = 1
2977local _list_0 = items 3819local _list_0 = items
2978for _index_0 = 2, #_list_0 do 3820local _max_0 = #_list_0
3821for _index_0 = 2, _max_0 do
2979 local item = _list_0[_index_0] 3822 local item = _list_0[_index_0]
2980 _accum_0[_len_0] = item 3823 _accum_0[_len_0] = item
2981 _len_0 = _len_0 + 1 3824 _len_0 = _len_0 + 1
@@ -2985,12 +3828,46 @@ local slice
2985local _accum_0 = { } 3828local _accum_0 = { }
2986local _len_0 = 1 3829local _len_0 = 1
2987local _list_0 = items 3830local _list_0 = items
2988for _index_0 = 1, #_list_0, 2 do 3831local _max_0 = #_list_0
3832for _index_0 = 1, _max_0, 2 do
2989 local item = _list_0[_index_0] 3833 local item = _list_0[_index_0]
2990 _accum_0[_len_0] = item 3834 _accum_0[_len_0] = item
2991 _len_0 = _len_0 + 1 3835 _len_0 = _len_0 + 1
2992end 3836end
2993slice = _accum_0 3837slice = _accum_0
3838local slice
3839local _accum_0 = { }
3840local _len_0 = 1
3841local _list_0 = items
3842local _min_0 = #_list_0 + -4 + 1
3843local _max_0 = #_list_0 + -1 + 1
3844for _index_0 = _min_0, _max_0 do
3845 local item = _list_0[_index_0]
3846 _accum_0[_len_0] = item
3847 _len_0 = _len_0 + 1
3848end
3849slice = _accum_0
3850local reverse_slice
3851local _accum_0 = { }
3852local _len_0 = 1
3853local _list_0 = items
3854local _min_0 = #_list_0 + -1 + 1
3855for _index_0 = _min_0, 1, -1 do
3856 local item = _list_0[_index_0]
3857 _accum_0[_len_0] = item
3858 _len_0 = _len_0 + 1
3859end
3860reverse_slice = _accum_0
3861local sub_list
3862local _accum_0 = { }
3863local _len_0 = 1
3864local _list_0 = items
3865for _index_0 = 2, 4 do
3866 local _item_0 = _list_0[_index_0]
3867 _accum_0[_len_0] = _item_0
3868 _len_0 = _len_0 + 1
3869end
3870sub_list = _accum_0
2994for i = 10, 20 do 3871for i = 10, 20 do
2995 print(i) 3872 print(i)
2996end 3873end
@@ -3001,8 +3878,7 @@ for key, value in pairs(object) do
3001 print(key, value) 3878 print(key, value)
3002end 3879end
3003local _list_0 = items 3880local _list_0 = items
3004local _max_0 = 4 3881for _index_0 = 2, 4 do
3005for _index_0 = 2, _max_0 < 0 and #_list_0 + _max_0 or _max_0 do
3006 local item = _list_0[_index_0] 3882 local item = _list_0[_index_0]
3007 print(item) 3883 print(item)
3008end 3884end
@@ -3020,12 +3896,24 @@ local _len_0 = 1
3020for i = 1, 20 do 3896for i = 1, 20 do
3021 if i % 2 == 0 then 3897 if i % 2 == 0 then
3022 _accum_0[_len_0] = i * 2 3898 _accum_0[_len_0] = i * 2
3899 _len_0 = _len_0 + 1
3023 else 3900 else
3024 _accum_0[_len_0] = i 3901 _accum_0[_len_0] = i
3902 _len_0 = _len_0 + 1
3025 end 3903 end
3026 _len_0 = _len_0 + 1
3027end 3904end
3028doubled_evens = _accum_0 3905doubled_evens = _accum_0
3906local first_large
3907local _accum_0
3908local _list_0 = numbers
3909for _index_0 = 1, #_list_0 do
3910 local n = _list_0[_index_0]
3911 if n > 10 then
3912 _accum_0 = n
3913 break
3914 end
3915end
3916first_large = _accum_0
3029local func_a 3917local func_a
3030func_a = function() 3918func_a = function()
3031 for i = 1, 10 do 3919 for i = 1, 10 do
@@ -3174,7 +4062,7 @@ if "Robert" == name then
3174elseif "Dan" == name or "Daniel" == name then 4062elseif "Dan" == name or "Daniel" == name then
3175 print("ä½ çš„å字是Dan") 4063 print("ä½ çš„å字是Dan")
3176else 4064else
3177 print("我ä¸çŸ¥é“ä½ çš„åå­—") 4065 print("我ä¸è®¤è¯†ä½ ï¼Œä½ çš„å字是" .. tostring(name))
3178end 4066end
3179local b = 1 4067local b = 1
3180local next_number 4068local next_number
@@ -3274,6 +4162,192 @@ if _tab_0 then
3274 end 4162 end
3275 print("Vec2 " .. tostring(x) .. ", " .. tostring(y)) 4163 print("Vec2 " .. tostring(x) .. ", " .. tostring(y))
3276end 4164end
4165local _exp_0 = tb
4166local _type_0 = type(_exp_0)
4167local _tab_0 = "table" == _type_0 or "userdata" == _type_0
4168local _match_0 = false
4169if _tab_0 then
4170 if 1 == _exp_0[1] and 2 == _exp_0[2] and 3 == _exp_0[3] then
4171 _match_0 = true
4172 print("1, 2, 3")
4173 end
4174end
4175if not _match_0 then
4176 local _match_1 = false
4177 if _tab_0 then
4178 local b = _exp_0[2]
4179 if 1 == _exp_0[1] and b ~= nil and 3 == _exp_0[3] then
4180 _match_1 = true
4181 print("1, " .. tostring(b) .. ", 3")
4182 end
4183 end
4184 if not _match_1 then
4185 if _tab_0 then
4186 local b = _exp_0[3]
4187 if b == nil then
4188 b = 3
4189 end
4190 if 1 == _exp_0[1] and 2 == _exp_0[2] then
4191 print("1, 2, " .. tostring(b))
4192 end
4193 end
4194 end
4195end
4196local _exp_0 = tb
4197local _type_0 = type(_exp_0)
4198local _tab_0 = "table" == _type_0 or "userdata" == _type_0
4199local _match_0 = false
4200if _tab_0 then
4201 local result = _exp_0.result
4202 if true == _exp_0.success and result ~= nil then
4203 _match_0 = true
4204 print("æˆåŠŸ", result)
4205 end
4206end
4207if not _match_0 then
4208 local _match_1 = false
4209 if _tab_0 then
4210 if false == _exp_0.success then
4211 _match_1 = true
4212 print("失败", result)
4213 end
4214 end
4215 if not _match_1 then
4216 print("无效值")
4217 end
4218end
4219local _exp_0 = tb
4220local _type_0 = type(_exp_0)
4221local _tab_0 = "table" == _type_0 or "userdata" == _type_0
4222local _match_0 = false
4223if _tab_0 then
4224 local content
4225 do
4226 local _obj_0 = _exp_0.data
4227 local _type_1 = type(_obj_0)
4228 if "table" == _type_1 or "userdata" == _type_1 then
4229 content = _obj_0.content
4230 end
4231 end
4232 local _val_0
4233 do
4234 local _obj_0 = _exp_0.data
4235 if _obj_0 ~= nil then
4236 _val_0 = _obj_0.type
4237 end
4238 end
4239 if "success" == _val_0 and content ~= nil then
4240 _match_0 = true
4241 print("æˆåŠŸ", content)
4242 end
4243end
4244if not _match_0 then
4245 local _match_1 = false
4246 if _tab_0 then
4247 local content
4248 do
4249 local _obj_0 = _exp_0.data
4250 local _type_1 = type(_obj_0)
4251 if "table" == _type_1 or "userdata" == _type_1 then
4252 content = _obj_0.content
4253 end
4254 end
4255 local _val_0
4256 do
4257 local _obj_0 = _exp_0.data
4258 if _obj_0 ~= nil then
4259 _val_0 = _obj_0.type
4260 end
4261 end
4262 if "error" == _val_0 and content ~= nil then
4263 _match_1 = true
4264 print("失败", content)
4265 end
4266 end
4267 if not _match_1 then
4268 print("无效值")
4269 end
4270end
4271local _exp_0 = tb
4272local _type_0 = type(_exp_0)
4273local _tab_0 = "table" == _type_0 or "userdata" == _type_0
4274if _tab_0 then
4275 local fourth = _exp_0[4]
4276 local _val_0
4277 do
4278 local _obj_0 = _exp_0[1]
4279 if _obj_0 ~= nil then
4280 _val_0 = _obj_0.a
4281 end
4282 end
4283 local _val_1
4284 do
4285 local _obj_0 = _exp_0[1]
4286 if _obj_0 ~= nil then
4287 _val_1 = _obj_0.b
4288 end
4289 end
4290 local _val_2
4291 do
4292 local _obj_0 = _exp_0[2]
4293 if _obj_0 ~= nil then
4294 _val_2 = _obj_0.a
4295 end
4296 end
4297 local _val_3
4298 do
4299 local _obj_0 = _exp_0[2]
4300 if _obj_0 ~= nil then
4301 _val_3 = _obj_0.b
4302 end
4303 end
4304 local _val_4
4305 do
4306 local _obj_0 = _exp_0[3]
4307 if _obj_0 ~= nil then
4308 _val_4 = _obj_0.a
4309 end
4310 end
4311 local _val_5
4312 do
4313 local _obj_0 = _exp_0[3]
4314 if _obj_0 ~= nil then
4315 _val_5 = _obj_0.b
4316 end
4317 end
4318 if 1 == _val_0 and 2 == _val_1 and 3 == _val_2 and 4 == _val_3 and 5 == _val_4 and 6 == _val_5 and fourth ~= nil then
4319 print("åŒ¹é…æˆåŠŸ", fourth)
4320 end
4321end
4322local segments = {
4323 "admin",
4324 "users",
4325 "logs",
4326 "view"
4327}
4328local _type_0 = type(segments)
4329local _tab_0 = "table" == _type_0 or "userdata" == _type_0
4330if _tab_0 then
4331 local groups
4332 do
4333 local _accum_0 = { }
4334 local _len_0 = 1
4335 local _max_0 = #segments + -3 + 1
4336 for _index_0 = 1, _max_0 do
4337 local _item_0 = segments[_index_0]
4338 _accum_0[_len_0] = _item_0
4339 _len_0 = _len_0 + 1
4340 end
4341 groups = _accum_0
4342 end
4343 local resource = segments[#segments - 1]
4344 local action = segments[#segments]
4345 if resource ~= nil and action ~= nil then
4346 print("Group:", groups)
4347 print("Resource:", resource)
4348 print("Action:", action)
4349 end
4350end
3277local Inventory 4351local Inventory
3278local _class_0 4352local _class_0
3279local _base_0 = { 4353local _base_0 = {
@@ -3930,6 +5004,10 @@ do
3930 _with_1["key-name"] = value 5004 _with_1["key-name"] = value
3931end 5005end
3932_with_0[#_with_0 + 1] = "abc" 5006_with_0[#_with_0 + 1] = "abc"
5007local _with_0 = obj
5008if _with_0 ~= nil then
5009 print(obj.name)
5010end
3933do 5011do
3934 local var = "hello" 5012 local var = "hello"
3935 print(var) 5013 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/global.lua b/spec/outputs/global.lua
index 54a21a9..3918f85 100644
--- a/spec/outputs/global.lua
+++ b/spec/outputs/global.lua
@@ -93,3 +93,28 @@ do
93 FooBar = "pascal case" 93 FooBar = "pascal case"
94 FOOBAR = "all uppercase" 94 FOOBAR = "all uppercase"
95end 95end
96do
97 do
98 local _class_0
99 local _base_0 = { }
100 if _base_0.__index == nil then
101 _base_0.__index = _base_0
102 end
103 _class_0 = setmetatable({
104 __init = function() end,
105 __base = _base_0,
106 __name = "A"
107 }, {
108 __index = _base_0,
109 __call = function(cls, ...)
110 local _self_0 = setmetatable({ }, _base_0)
111 cls.__init(_self_0, ...)
112 return _self_0
113 end
114 })
115 _base_0.__class = _class_0
116 A = _class_0
117 end
118 Flag = 1
119 const, x, y = "const", 1, 2
120end
diff --git a/spec/outputs/import.lua b/spec/outputs/import.lua
index 83c99e2..7aa130f 100644
--- a/spec/outputs/import.lua
+++ b/spec/outputs/import.lua
@@ -166,3 +166,13 @@ do
166 local _obj_1 = require("m") 166 local _obj_1 = require("m")
167 g, i = _obj_1[1], getmetatable(_obj_1[2]).__close 167 g, i = _obj_1[1], getmetatable(_obj_1[2]).__close
168end 168end
169do
170 local require <const> = require
171 local stringlib <const> = string
172 local format <const> = string.format
173 local io_read <const> = io.read
174 local type
175 type = function() end
176 local tp <const> = _G.type
177 local yue <const> = _G["月"]
178end
diff --git a/spec/outputs/import_global.lua b/spec/outputs/import_global.lua
new file mode 100644
index 0000000..895daf9
--- /dev/null
+++ b/spec/outputs/import_global.lua
@@ -0,0 +1,131 @@
1do
2 local print <const> = print
3 local math <const> = math
4 print("hello")
5 math.random(10)
6end
7do
8 local print <const> = print
9 local value = 1
10 value = value + 2
11 print(value)
12end
13do
14 local print
15 print = function(msg)
16 return msg
17 end
18 do
19 local math <const> = math
20 print("local")
21 math.random(1)
22 end
23end
24do
25 local print <const> = print
26 local tostring
27 tostring = function(v)
28 return "local"
29 end
30 tostring("value")
31 print(tostring(123))
32end
33do
34 local func
35 func = function(x, y)
36 local type <const> = type
37 local tostring <const> = tostring
38 local print <const> = print
39 return type(x, tostring(y, print))
40 end
41 func(1, 2)
42end
43do
44 local xpcall <const> = xpcall
45 local func <const> = func
46 local world <const> = world
47 local tostring <const> = tostring
48 local print <const> = print
49 xpcall(function()
50 return func("hello " .. tostring(world))
51 end, function(err)
52 return print(err)
53 end)
54end
55do
56 local print <const> = print
57 print(FLAG)
58 FLAG = 123
59end
60do
61 local print <const> = print
62 Foo = 10
63 print(Foo)
64 Foo = Foo + 2
65end
66do
67 local print <const> = print
68 Bar = 1
69 Baz = 2
70 print(Bar, Baz)
71end
72do
73 local y <const> = y
74 x = 3434
75 if y then
76 x = 10
77 end
78end
79do
80 local lowercase <const> = lowercase
81 local tostring <const> = tostring
82 local Uppercase <const> = Uppercase
83 local foobar = "all " .. tostring(lowercase)
84 FooBar = "pascal case"
85 FOOBAR = "all " .. tostring(Uppercase)
86end
87do
88 local setmetatable <const> = setmetatable
89 local print <const> = print
90 do
91 local _class_0
92 local _base_0 = { }
93 if _base_0.__index == nil then
94 _base_0.__index = _base_0
95 end
96 _class_0 = setmetatable({
97 __init = function() end,
98 __base = _base_0,
99 __name = "A"
100 }, {
101 __index = _base_0,
102 __call = function(cls, ...)
103 local _self_0 = setmetatable({ }, _base_0)
104 cls.__init(_self_0, ...)
105 return _self_0
106 end
107 })
108 _base_0.__class = _class_0
109 A = _class_0
110 end
111 Flag = 1
112 const, x, y = "const", 1, 2
113 print(math, table)
114end
115do
116 local X <const> = X
117 X:func(1, 2, 3)
118 X.tag = "abc"
119end
120local _anon_func_0 = function(func)
121 return func
122end
123do
124 local func <const> = func
125 local pcall <const> = pcall
126 local f
127 f = function()
128 func()
129 return pcall(_anon_func_0, func)
130 end
131end
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 8624d49..6ab4bbb 100644
--- a/spec/outputs/loops.lua
+++ b/spec/outputs/loops.lua
@@ -60,8 +60,8 @@ do
60 local y = hello[_index_0] 60 local y = hello[_index_0]
61 if y % 2 == 0 then 61 if y % 2 == 0 then
62 _accum_0[_len_0] = y 62 _accum_0[_len_0] = y
63 _len_0 = _len_0 + 1
63 end 64 end
64 _len_0 = _len_0 + 1
65 end 65 end
66 x = _accum_0 66 x = _accum_0
67end 67end
@@ -132,13 +132,11 @@ do
132end 132end
133do 133do
134 local _accum_0 = { } 134 local _accum_0 = { }
135 local _len_0 = 1
136 local _list_2 = 3 135 local _list_2 = 3
137 for _index_0 = 1, #_list_2 do 136 for _index_0 = 1, #_list_2 do
138 local thing = _list_2[_index_0] 137 local thing = _list_2[_index_0]
139 y = "hello" 138 y = "hello"
140 break 139 break
141 _len_0 = _len_0 + 1
142 end 140 end
143 x = _accum_0 141 x = _accum_0
144end 142end
@@ -370,3 +368,131 @@ do
370 end 368 end
371 until false 369 until false
372end 370end
371local _anon_func_0 = function(i, tb)
372 local _accum_0 = { }
373 local _len_0 = 1
374 while tb[i] do
375 i = i + 1
376 _accum_0[_len_0] = i - 1
377 _len_0 = _len_0 + 1
378 end
379 return _accum_0
380end
381do
382 local index
383 do
384 local _accum_0
385 for i = 1, #tb do
386 if tb[i] then
387 _accum_0 = i
388 break
389 end
390 end
391 index = _accum_0
392 end
393 f((function()
394 local _accum_0
395 for i = 1, #tb do
396 if tb[i] then
397 _accum_0 = i
398 break
399 end
400 end
401 return _accum_0
402 end)())
403 f((function()
404 local _accum_0 = { }
405 local _len_0 = 1
406 for i = 1, #tb do
407 if tb[i] then
408 _accum_0[_len_0] = i
409 _len_0 = _len_0 + 1
410 end
411 end
412 return _accum_0
413 end)())
414 i = 1
415 local ids
416 do
417 local _accum_0 = { }
418 local _len_0 = 1
419 while tb[i] do
420 i = i + 1
421 _accum_0[_len_0] = i - 1
422 _len_0 = _len_0 + 1
423 end
424 ids = _accum_0
425 end
426 i = 1
427 local idx
428 do
429 local _accum_0
430 while tb[i] do
431 i = i + 1
432 _accum_0 = i - 1
433 break
434 end
435 idx = _accum_0
436 end
437 local f1
438 f1 = function()
439 i = 1
440 return f(_anon_func_0(i, tb))
441 end
442 i = 1
443 f((function()
444 local _accum_0
445 while tb[i] do
446 i = i + 1
447 _accum_0 = i - 1
448 break
449 end
450 return _accum_0
451 end)())
452 local _accum_0 = { }
453 local _len_0 = 1
454 local _list_3 = items
455 for _index_0 = 1, #_list_3 do
456 local item = _list_3[_index_0]
457 local _type_0 = type(item)
458 local _tab_0 = "table" == _type_0 or "userdata" == _type_0
459 if _tab_0 then
460 local value = item.value
461 if "A" == item.type and value ~= nil then
462 if value > 5 then
463 _accum_0[_len_0] = item
464 _len_0 = _len_0 + 1
465 end
466 end
467 end
468 end
469 list = _accum_0
470end
471do
472 repeat
473 print(1)
474 until true
475 do
476 local _accum_0
477 repeat
478 a = func()
479 _accum_0 = a.x
480 break
481 until a.v
482 x = _accum_0
483 end
484 local items
485 local _accum_0 = { }
486 local _len_0 = 1
487 repeat
488 local item = getItem()
489 if not item then
490 break
491 end
492 if item.value > 0 then
493 _accum_0[_len_0] = item
494 _len_0 = _len_0 + 1
495 end
496 until false
497 items = _accum_0
498end
diff --git a/spec/outputs/macro.lua b/spec/outputs/macro.lua
index 4d31574..89c6e63 100644
--- a/spec/outputs/macro.lua
+++ b/spec/outputs/macro.lua
@@ -26,6 +26,10 @@ print({
26 123, 26 123,
27 'xyz' 27 'xyz'
28}) 28})
29print({
30 456,
31 'abc'
32})
29do 33do
30 assert(item == nil) 34 assert(item == nil)
31end 35end
@@ -213,6 +217,13 @@ function tb:func()
213end 217end
214end 218end
215print(x) 219print(x)
220local yue = require("yue")
221do
222local function f2(a)
223 return a + 1
224end
225x = x + f2(3)
226end
216local sel 227local sel
217sel = function(a, b, c) 228sel = function(a, b, c)
218 if a then 229 if a then
@@ -317,7 +328,7 @@ print((setmetatable({
317 return 998 328 return 998
318 end 329 end
319})) 330}))
320print("current line: " .. tostring(323)) 331print("current line: " .. tostring(349))
321do 332do
322 do 333 do
323-- TODO 334-- TODO
@@ -330,10 +341,8 @@ local _1
330_1 = function() 341_1 = function()
331 print(1) 342 print(1)
332 local _accum_0 = { } 343 local _accum_0 = { }
333 local _len_0 = 1
334 while false do 344 while false do
335 break 345 break
336 _len_0 = _len_0 + 1
337 end 346 end
338 return _accum_0 347 return _accum_0
339end 348end
diff --git a/spec/outputs/props.lua b/spec/outputs/props.lua
new file mode 100644
index 0000000..2c282e0
--- /dev/null
+++ b/spec/outputs/props.lua
@@ -0,0 +1,240 @@
1local Props
2do
3 local _class_0
4 local assignReadOnly
5 local _base_0 = {
6 __index = function(self, name)
7 local cls = getmetatable(self)
8 do
9 local item
10 do
11 local _obj_0 = cls.__getter
12 if _obj_0 ~= nil then
13 item = _obj_0[name]
14 end
15 end
16 if item then
17 return item(self)
18 else
19 item = rawget(cls, name)
20 if item then
21 return item
22 else
23 local c = cls
24 repeat
25 c = getmetatable(c)
26 if c then
27 local _obj_0 = c.__getter
28 if _obj_0 ~= nil then
29 item = _obj_0[name]
30 end
31 if item then
32 if cls.__getter == nil then
33 cls.__getter = { }
34 end
35 cls.__getter[name] = item
36 return item(self)
37 else
38 item = rawget(c, name)
39 if item then
40 rawset(cls, name, item)
41 return item
42 end
43 end
44 else
45 break
46 end
47 until false
48 end
49 end
50 end
51 return nil
52 end,
53 __newindex = function(self, name, value)
54 local cls = getmetatable(self)
55 local item
56 local _obj_0 = cls.__setter
57 if _obj_0 ~= nil then
58 item = _obj_0[name]
59 end
60 if item then
61 return item(self, value)
62 else
63 local c = cls
64 repeat
65 c = getmetatable(c)
66 if c then
67 local _obj_1 = c.__setter
68 if _obj_1 ~= nil then
69 item = _obj_1[name]
70 end
71 if item then
72 if cls.__setter == nil then
73 cls.__setter = { }
74 end
75 cls.__setter[name] = item
76 item(self, value)
77 return
78 end
79 else
80 break
81 end
82 until false
83 return rawset(self, name, value)
84 end
85 end,
86 prop = function(self, name, props)
87 local get, set = props.get, props.set
88 if set == nil then
89 set = assignReadOnly
90 end
91 do
92 local getter = rawget(self.__base, "__getter")
93 if getter then
94 getter[name] = get
95 else
96 rawset(self.__base, "__getter", {
97 [name] = get
98 })
99 end
100 end
101 local setter = rawget(self.__base, "__setter")
102 if setter then
103 setter[name] = set
104 else
105 return rawset(self.__base, "__setter", {
106 [name] = set
107 })
108 end
109 end
110 }
111 if _base_0.__index == nil then
112 _base_0.__index = _base_0
113 end
114 _class_0 = setmetatable({
115 __init = function() end,
116 __base = _base_0,
117 __name = "Props"
118 }, {
119 __index = _base_0,
120 __call = function(cls, ...)
121 local _self_0 = setmetatable({ }, _base_0)
122 cls.__init(_self_0, ...)
123 return _self_0
124 end
125 })
126 _base_0.__class = _class_0
127 local self = _class_0;
128 assignReadOnly = function()
129 return error("assigning a readonly property")
130 end
131 Props = _class_0
132end
133local A
134do
135 local _class_0
136 local _parent_0 = Props
137 local _base_0 = { }
138 for _key_0, _val_0 in pairs(_parent_0.__base) do
139 if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then
140 _base_0[_key_0] = _val_0
141 end
142 end
143 if _base_0.__index == nil then
144 _base_0.__index = _base_0
145 end
146 setmetatable(_base_0, _parent_0.__base)
147 _class_0 = setmetatable({
148 __init = function(self)
149 self._x = 0
150 end,
151 __base = _base_0,
152 __name = "A",
153 __parent = _parent_0
154 }, {
155 __index = function(cls, name)
156 local val = rawget(_base_0, name)
157 if val == nil then
158 local parent = rawget(cls, "__parent")
159 if parent then
160 return parent[name]
161 end
162 else
163 return val
164 end
165 end,
166 __call = function(cls, ...)
167 local _self_0 = setmetatable({ }, _base_0)
168 cls.__init(_self_0, ...)
169 return _self_0
170 end
171 })
172 _base_0.__class = _class_0
173 local self = _class_0;
174 self:prop('x', {
175 get = function(self)
176 return self._x + 1000
177 end,
178 set = function(self, v)
179 self._x = v
180 end
181 })
182 if _parent_0.__inherited then
183 _parent_0.__inherited(_parent_0, _class_0)
184 end
185 A = _class_0
186end
187local B
188do
189 local _class_0
190 local _parent_0 = A
191 local _base_0 = { }
192 for _key_0, _val_0 in pairs(_parent_0.__base) do
193 if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then
194 _base_0[_key_0] = _val_0
195 end
196 end
197 if _base_0.__index == nil then
198 _base_0.__index = _base_0
199 end
200 setmetatable(_base_0, _parent_0.__base)
201 _class_0 = setmetatable({
202 __init = function(self, ...)
203 return _class_0.__parent.__init(self, ...)
204 end,
205 __base = _base_0,
206 __name = "B",
207 __parent = _parent_0
208 }, {
209 __index = function(cls, name)
210 local val = rawget(_base_0, name)
211 if val == nil then
212 local parent = rawget(cls, "__parent")
213 if parent then
214 return parent[name]
215 end
216 else
217 return val
218 end
219 end,
220 __call = function(cls, ...)
221 local _self_0 = setmetatable({ }, _base_0)
222 cls.__init(_self_0, ...)
223 return _self_0
224 end
225 })
226 _base_0.__class = _class_0
227 local self = _class_0;
228 self:prop('abc', {
229 get = function(self)
230 return "hello"
231 end
232 })
233 if _parent_0.__inherited then
234 _parent_0.__inherited(_parent_0, _class_0)
235 end
236 B = _class_0
237end
238local b = B()
239b.x = 999
240return print(b.x, b.abc)
diff --git a/spec/outputs/string.lua b/spec/outputs/string.lua
index febea62..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 e4dedc9..7c1004b 100644
--- a/spec/outputs/switch.lua
+++ b/spec/outputs/switch.lua
@@ -415,4 +415,366 @@ do
415 end 415 end
416 end 416 end
417end 417end
418do
419 local _exp_0 = tb
420 local _type_0 = type(_exp_0)
421 local _tab_0 = "table" == _type_0 or "userdata" == _type_0
422 local _match_0 = false
423 if _tab_0 then
424 if 1 == _exp_0[1] and 2 == _exp_0[2] and 3 == _exp_0[3] then
425 _match_0 = true
426 print("1, 2, 3")
427 end
428 end
429 if not _match_0 then
430 local _match_1 = false
431 if _tab_0 then
432 local b = _exp_0[2]
433 if 1 == _exp_0[1] and b ~= nil and 3 == _exp_0[3] then
434 _match_1 = true
435 print("1, " .. tostring(b) .. ", 3")
436 end
437 end
438 if not _match_1 then
439 if _tab_0 then
440 local b = _exp_0[3]
441 if b == nil then
442 b = 3
443 end
444 if 1 == _exp_0[1] and 2 == _exp_0[2] then
445 print("1, 2, " .. tostring(b))
446 end
447 end
448 end
449 end
450end
451do
452 local _exp_0 = tb
453 local _type_0 = type(_exp_0)
454 local _tab_0 = "table" == _type_0 or "userdata" == _type_0
455 local _match_0 = false
456 if _tab_0 then
457 local result = _exp_0.result
458 if true == _exp_0.success and result ~= nil then
459 _match_0 = true
460 print("success", result)
461 end
462 end
463 if not _match_0 then
464 local _match_1 = false
465 if _tab_0 then
466 if false == _exp_0.success then
467 _match_1 = true
468 print("failed", result)
469 end
470 end
471 if not _match_1 then
472 print("invalid")
473 end
474 end
475end
476do
477 local _exp_0 = tb
478 local _type_0 = type(_exp_0)
479 local _tab_0 = "table" == _type_0 or "userdata" == _type_0
480 local _match_0 = false
481 if _tab_0 then
482 local content = _exp_0.content
483 if "success" == _exp_0.type and content ~= nil then
484 _match_0 = true
485 print("success", content)
486 end
487 end
488 if not _match_0 then
489 local _match_1 = false
490 if _tab_0 then
491 local content = _exp_0.content
492 if "error" == _exp_0.type and content ~= nil then
493 _match_1 = true
494 print("failed", content)
495 end
496 end
497 if not _match_1 then
498 print("invalid")
499 end
500 end
501end
502do
503 do
504 local _exp_0 = tb
505 local _type_0 = type(_exp_0)
506 local _tab_0 = "table" == _type_0 or "userdata" == _type_0
507 if _tab_0 then
508 local fourth = _exp_0[4]
509 local _val_0
510 do
511 local _obj_0 = _exp_0[1]
512 if _obj_0 ~= nil then
513 _val_0 = _obj_0.a
514 end
515 end
516 local _val_1
517 do
518 local _obj_0 = _exp_0[1]
519 if _obj_0 ~= nil then
520 _val_1 = _obj_0.b
521 end
522 end
523 local _val_2
524 do
525 local _obj_0 = _exp_0[2]
526 if _obj_0 ~= nil then
527 _val_2 = _obj_0.a
528 end
529 end
530 local _val_3
531 do
532 local _obj_0 = _exp_0[2]
533 if _obj_0 ~= nil then
534 _val_3 = _obj_0.b
535 end
536 end
537 local _val_4
538 do
539 local _obj_0 = _exp_0[3]
540 if _obj_0 ~= nil then
541 _val_4 = _obj_0.a
542 end
543 end
544 local _val_5
545 do
546 local _obj_0 = _exp_0[3]
547 if _obj_0 ~= nil then
548 _val_5 = _obj_0.b
549 end
550 end
551 if 1 == _val_0 and 2 == _val_1 and 3 == _val_2 and 4 == _val_3 and 5 == _val_4 and 6 == _val_5 and fourth ~= nil then
552 print("matched", fourth)
553 end
554 end
555 end
556 local _exp_0 = tb
557 local _type_0 = type(_exp_0)
558 local _tab_0 = "table" == _type_0 or "userdata" == _type_0
559 local _match_0 = false
560 if _tab_0 then
561 local _val_0
562 do
563 local _obj_0 = _exp_0[1]
564 if _obj_0 ~= nil then
565 _val_0 = _obj_0.c
566 end
567 end
568 local _val_1
569 do
570 local _obj_0 = _exp_0[1]
571 if _obj_0 ~= nil then
572 _val_1 = _obj_0.d
573 end
574 end
575 local _val_2
576 do
577 local _obj_0 = _exp_0[2]
578 if _obj_0 ~= nil then
579 _val_2 = _obj_0.c
580 end
581 end
582 local _val_3
583 do
584 local _obj_0 = _exp_0[2]
585 if _obj_0 ~= nil then
586 _val_3 = _obj_0.d
587 end
588 end
589 local _val_4
590 do
591 local _obj_0 = _exp_0[3]
592 if _obj_0 ~= nil then
593 _val_4 = _obj_0.c
594 end
595 end
596 local _val_5
597 do
598 local _obj_0 = _exp_0[3]
599 if _obj_0 ~= nil then
600 _val_5 = _obj_0.d
601 end
602 end
603 if 1 == _val_0 and 2 == _val_1 and 3 == _val_2 and 4 == _val_3 and 5 == _val_4 and 6 == _val_5 then
604 _match_0 = true
605 print("OK")
606 end
607 end
608 if not _match_0 then
609 if _tab_0 then
610 local sixth = _exp_0[6]
611 local _val_0
612 do
613 local _obj_0 = _exp_0[3]
614 if _obj_0 ~= nil then
615 _val_0 = _obj_0.a
616 end
617 end
618 local _val_1
619 do
620 local _obj_0 = _exp_0[3]
621 if _obj_0 ~= nil then
622 _val_1 = _obj_0.b
623 end
624 end
625 local _val_2
626 do
627 local _obj_0 = _exp_0[4]
628 if _obj_0 ~= nil then
629 _val_2 = _obj_0.a
630 end
631 end
632 local _val_3
633 do
634 local _obj_0 = _exp_0[4]
635 if _obj_0 ~= nil then
636 _val_3 = _obj_0.b
637 end
638 end
639 local _val_4
640 do
641 local _obj_0 = _exp_0[5]
642 if _obj_0 ~= nil then
643 _val_4 = _obj_0.a
644 end
645 end
646 local _val_5
647 do
648 local _obj_0 = _exp_0[5]
649 if _obj_0 ~= nil then
650 _val_5 = _obj_0.b
651 end
652 end
653 if 1 == _val_0 and 2 == _val_1 and 3 == _val_2 and 4 == _val_3 and 5 == _val_4 and 6 == _val_5 and sixth ~= nil then
654 print("matched", sixth)
655 end
656 end
657 end
658end
659do
660 local v = "hello"
661 if "hello" == v then
662 print("matched hello")
663 else
664 print("not matched")
665 end
666end
667do
668 local f
669 f = function()
670 return "ok"
671 end
672 local val = f()
673 if "ok" == val then
674 print("it's ok")
675 end
676end
677do
678 local g
679 g = function()
680 return 42
681 end
682 local result = g()
683 if 1 == result or 2 == result then
684 print("small")
685 elseif 42 == result then
686 print("life universe everything")
687 else
688 print("other " .. tostring(result))
689 end
690end
691do
692 local check
693 check = function()
694 if true then
695 return "yes"
696 else
697 return "no"
698 end
699 end
700 local x = check()
701 if "yes" == x then
702 print("affirmative")
703 else
704 print("negative")
705 end
706end
707do
708 local t
709 t = function()
710 local tb = {
711 a = 1
712 }
713 tb.a = 2
714 return tb
715 end
716 local data = t()
717 local _type_0 = type(data)
718 local _tab_0 = "table" == _type_0 or "userdata" == _type_0
719 local _match_0 = false
720 if _tab_0 then
721 if 2 == data.a then
722 _match_0 = true
723 print("matched")
724 end
725 end
726 if not _match_0 then
727 print("not matched")
728 end
729end
730do
731 local clientData = {
732 "Meta",
733 "CUST_1001",
734 "CHK123"
735 }
736 local _type_0 = type(clientData)
737 local _tab_0 = "table" == _type_0 or "userdata" == _type_0
738 if _tab_0 then
739 local metadata
740 do
741 local _accum_0 = { }
742 local _len_0 = 1
743 local _max_0 = #clientData + -3 + 1
744 for _index_0 = 1, _max_0 do
745 local _item_0 = clientData[_index_0]
746 _accum_0[_len_0] = _item_0
747 _len_0 = _len_0 + 1
748 end
749 metadata = _accum_0
750 end
751 local customerId = clientData[#clientData - 1]
752 local checksum = clientData[#clientData]
753 if customerId ~= nil and checksum ~= nil then
754 print(metadata)
755 print(customerId)
756 print(checksum)
757 end
758 end
759end
760do
761 local handlePath
762 handlePath = function(segments)
763 local _type_0 = type(segments)
764 local _tab_0 = "table" == _type_0 or "userdata" == _type_0
765 if _tab_0 then
766 local resource = segments[#segments - 1]
767 local action = segments[#segments]
768 if resource ~= nil and action ~= nil then
769 print("Resource:", resource)
770 return print("Action:", action)
771 end
772 end
773 end
774 handlePath({
775 "admin",
776 "logs",
777 "view"
778 })
779end
418return nil 780return nil
diff --git a/spec/outputs/syntax.lua b/spec/outputs/syntax.lua
index 040a325..eb4543c 100644
--- a/spec/outputs/syntax.lua
+++ b/spec/outputs/syntax.lua
@@ -5,9 +5,9 @@ func(arg1, arg2, another, arg3)
5local we 5local we
6here, we = function() end, yeah 6here, we = function() end, yeah
7local the, different 7local the, different
8the, different = function() 8the, different = (function()
9 return approach 9 return approach
10end, yeah 10end), yeah
11dad() 11dad()
12dad(lord) 12dad(lord)
13hello(one, two)(); 13hello(one, two)();
@@ -430,4 +430,94 @@ 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
444do
445 x = 1
446 y = 2
447 i = i + 1
448 j = j + 1
449 if condition then
450 setup()
451 run()
452 cleanup()
453 end
454 a = 1
455 local b = 2
456 local c = a + b
457 print(a)
458 print(b)
459 print(c)
460 f = function()
461 a = 1
462 b = 2
463 return a + b
464 end
465 a = 1
466 b = 2
467 local success, result = pcall(function()
468 return func()
469 end)
470 if success then
471 print(result)
472 end
473 local value = "foo"
474 print(value)
475 value = value .. "bar"
476 print(value)
477 do
478 if ok then
479 print("ok!")
480 end
481 return 42
482 end
483 for i = 1, 3 do
484 print(i)
485 goto _continue_0
486 ::_continue_0::
487 end
488 local n = 0
489 while n < 2 do
490 print("n=", n)
491 n = n + 1
492 end
493 local obj = { }
494 obj:set(10)
495 obj:get()
496 print("done")
497 do
498 local _with_0 = tbl
499 _with_0:push(1)
500 print("push")
501 end
502 a = 5
503 if a > 3 then
504 print("big")
505 b = a * 2
506 print(b)
507 else
508 print("small")
509 b = a
510 end
511 xpcall(function()
512 x = 1
513 y = 2
514 return print(x + y)
515 end, function(err)
516 return print("error:", err)
517 end)
518end
519local q = 1
520local w = 2
521local e = 3
522print(q, w, e)
433return nil 523return 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/loops.lua b/spec/outputs/unicode/loops.lua
index 8379993..27bbe2e 100644
--- a/spec/outputs/unicode/loops.lua
+++ b/spec/outputs/unicode/loops.lua
@@ -60,8 +60,8 @@ do
60 local _u53d8_u91cfy = _u4f60_u597d[_index_0] 60 local _u53d8_u91cfy = _u4f60_u597d[_index_0]
61 if _u53d8_u91cfy % 2 == 0 then 61 if _u53d8_u91cfy % 2 == 0 then
62 _accum_0[_len_0] = _u53d8_u91cfy 62 _accum_0[_len_0] = _u53d8_u91cfy
63 _len_0 = _len_0 + 1
63 end 64 end
64 _len_0 = _len_0 + 1
65 end 65 end
66 _u53d8_u91cfx = _accum_0 66 _u53d8_u91cfx = _accum_0
67end 67end
@@ -132,13 +132,11 @@ do
132end 132end
133do 133do
134 local _accum_0 = { } 134 local _accum_0 = { }
135 local _len_0 = 1
136 local _list_2 = 3 135 local _list_2 = 3
137 for _index_0 = 1, #_list_2 do 136 for _index_0 = 1, #_list_2 do
138 local _u4e1c_u897f = _list_2[_index_0] 137 local _u4e1c_u897f = _list_2[_index_0]
139 _u53d8_u91cfy = "你好" 138 _u53d8_u91cfy = "你好"
140 break 139 break
141 _len_0 = _len_0 + 1
142 end 140 end
143 _u53d8_u91cfx = _accum_0 141 _u53d8_u91cfx = _accum_0
144end 142end
diff --git a/spec/outputs/unicode/macro.lua b/spec/outputs/unicode/macro.lua
index b14f571..b4e78cd 100644
--- a/spec/outputs/unicode/macro.lua
+++ b/spec/outputs/unicode/macro.lua
@@ -216,17 +216,15 @@ do
216end 216end
217local _ = require('下划线') 217local _ = require('下划线')
218local _anon_func_0 = function(_) 218local _anon_func_0 = function(_)
219 do 219 local _call_0 = (_({
220 local _call_0 = (_({ 220 1,
221 1, 221 2,
222 2, 222 3,
223 3, 223 4,
224 4, 224 -2,
225 -2, 225 3
226 3 226 }))
227 })) 227 return _call_0["链"](_call_0)
228 return _call_0["链"](_call_0)
229 end
230end 228end
231local _call_0 = ((function() 229local _call_0 = ((function()
232 local _call_0 = ((function() 230 local _call_0 = ((function()
@@ -241,17 +239,15 @@ local _call_0 = ((function()
241end)()) 239end)())
242local _u7ed3_u679ca = _call_0["å–值"](_call_0) 240local _u7ed3_u679ca = _call_0["å–值"](_call_0)
243local _anon_func_1 = function(_) 241local _anon_func_1 = function(_)
244 do 242 local _call_1 = (_({
245 local _call_1 = (_({ 243 1,
246 1, 244 2,
247 2, 245 3,
248 3, 246 4,
249 4, 247 -2,
250 -2, 248 3
251 3 249 }))
252 })) 250 return _call_1["链"](_call_1)
253 return _call_1["链"](_call_1)
254 end
255end 251end
256do 252do
257 local _call_1 = ((function() 253 local _call_1 = ((function()
@@ -270,10 +266,8 @@ do
270 end) 266 end)
271end 267end
272local _anon_func_2 = function(_u539f_u70b9) 268local _anon_func_2 = function(_u539f_u70b9)
273 do 269 local _call_1 = _u539f_u70b9["å˜æ¢"]["根节点"]["游æˆå¯¹è±¡"]
274 local _call_1 = _u539f_u70b9["å˜æ¢"]["根节点"]["游æˆå¯¹è±¡"] 270 return _call_1["父节点"](_call_1)
275 return _call_1["父节点"](_call_1)
276 end
277end 271end
278local _call_1 = ((function() 272local _call_1 = ((function()
279 local _call_1 = ((function() 273 local _call_1 = ((function()
@@ -365,10 +359,8 @@ local _1
365_1 = function() 359_1 = function()
366 _u6253_u5370(1) 360 _u6253_u5370(1)
367 local _accum_0 = { } 361 local _accum_0 = { }
368 local _len_0 = 1
369 while false do 362 while false do
370 break 363 break
371 _len_0 = _len_0 + 1
372 end 364 end
373 return _accum_0 365 return _accum_0
374end 366end
diff --git a/spec/outputs/unicode/multiline_chain.lua b/spec/outputs/unicode/multiline_chain.lua
index c1da13f..61e7057 100644
--- a/spec/outputs/unicode/multiline_chain.lua
+++ b/spec/outputs/unicode/multiline_chain.lua
@@ -59,10 +59,8 @@ _u51fd_u6570 = function()
59 return _accum_0 59 return _accum_0
60end 60end
61local _anon_func_0 = function(_u53d8_u91cfa) 61local _anon_func_0 = function(_u53d8_u91cfa)
62 do 62 local _call_1 = _u53d8_u91cfa
63 local _call_1 = _u53d8_u91cfa 63 return (_call_1["å˜é‡b"](_call_1, 123))["å˜é‡c"]("abc")
64 return (_call_1["å˜é‡b"](_call_1, 123))["å˜é‡c"]("abc")
65 end
66end 64end
67local _u51fd_u65701 65local _u51fd_u65701
68_u51fd_u65701 = function() 66_u51fd_u65701 = function()
diff --git a/spec/outputs/unicode/syntax.lua b/spec/outputs/unicode/syntax.lua
index 1984f40..f5d5d8a 100644
--- a/spec/outputs/unicode/syntax.lua
+++ b/spec/outputs/unicode/syntax.lua
@@ -5,9 +5,9 @@ _u51fd_u6570(_u53c2_u65701, _u53c2_u65702, _u53e6_u5916, _u53c2_u65703)
5local _u6211_u4eec 5local _u6211_u4eec
6_u8fd9_u91cc, _u6211_u4eec = function() end, _u662f_u7684 6_u8fd9_u91cc, _u6211_u4eec = function() end, _u662f_u7684
7local _u8fd9_u4e2a, _u4e0d_u540c 7local _u8fd9_u4e2a, _u4e0d_u540c
8_u8fd9_u4e2a, _u4e0d_u540c = function() 8_u8fd9_u4e2a, _u4e0d_u540c = (function()
9 return _u65b9_u6cd5 9 return _u65b9_u6cd5
10end, _u662f_u7684 10end), _u662f_u7684
11_u7238_u7238() 11_u7238_u7238()
12_u7238_u7238(_u4e3b) 12_u7238_u7238(_u4e3b)
13_u4f60_u597d(_u4e00, _u4e8c)(); 13_u4f60_u597d(_u4e00, _u4e8c)();
@@ -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/unicode/whitespace.lua b/spec/outputs/unicode/whitespace.lua
index d026abb..7a83d9f 100644
--- a/spec/outputs/unicode/whitespace.lua
+++ b/spec/outputs/unicode/whitespace.lua
@@ -82,12 +82,12 @@ v = function()
82 return _u53d8_u91cfa, _u53d8_u91cfb, _u53d8_u91cfc 82 return _u53d8_u91cfa, _u53d8_u91cfb, _u53d8_u91cfc
83end 83end
84local v1, v2, v3 84local v1, v2, v3
85v1, v2, v3 = function() 85v1, v2, v3 = (function()
86 return _u53d8_u91cfa 86 return _u53d8_u91cfa
87end, _u53d8_u91cfb, _u53d8_u91cfc 87end), _u53d8_u91cfb, _u53d8_u91cfc
88local _u53d8_u91cfa, _u53d8_u91cfb, _u53d8_u91cfc, _u53d8_u91cfd, _u53d8_u91cfe, _u53d8_u91cff = 1, f2({ 88local _u53d8_u91cfa, _u53d8_u91cfb, _u53d8_u91cfc, _u53d8_u91cfd, _u53d8_u91cfe, _u53d8_u91cff = 1, (f2({
89 abc = abc 89 abc = abc
90}), 3, 4, _u51fd_u65705(abc), 6 90})), 3, 4, _u51fd_u65705(abc), 6
91for _u53d8_u91cfa, _u53d8_u91cfb, _u53d8_u91cfc in pairs(_u5bf9_u8c61tb) do 91for _u53d8_u91cfa, _u53d8_u91cfb, _u53d8_u91cfc in pairs(_u5bf9_u8c61tb) do
92 _u6253_u5370(_u53d8_u91cfa, _u53d8_u91cfb, _u53d8_u91cfc) 92 _u6253_u5370(_u53d8_u91cfa, _u53d8_u91cfb, _u53d8_u91cfc)
93end 93end
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/whitespace.lua b/spec/outputs/whitespace.lua
index 0251968..864f085 100644
--- a/spec/outputs/whitespace.lua
+++ b/spec/outputs/whitespace.lua
@@ -94,12 +94,12 @@ v = function()
94 return a, b, c 94 return a, b, c
95end 95end
96local v1, v2, v3 96local v1, v2, v3
97v1, v2, v3 = function() 97v1, v2, v3 = (function()
98 return a 98 return a
99end, b, c 99end), b, c
100local a, b, c, d, e, f = 1, f2({ 100local a, b, c, d, e, f = 1, (f2({
101 abc = abc 101 abc = abc
102}), 3, 4, f5(abc), 6 102})), 3, 4, f5(abc), 6
103for a, b, c in pairs(tb) do 103for a, b, c in pairs(tb) do
104 print(a, b, c) 104 print(a, b, c)
105end 105end
diff --git a/spec/outputs/with.lua b/spec/outputs/with.lua
index 1a795c1..530915e 100644
--- a/spec/outputs/with.lua
+++ b/spec/outputs/with.lua
@@ -187,4 +187,66 @@ do
187 return _with_0[123] 187 return _with_0[123]
188 end 188 end
189end 189end
190do
191 f((function()
192 local _with_0 = item
193 do
194 local _accum_0
195 repeat
196 if _with_0.id > 0 then
197 _accum_0 = _with_0.content
198 break
199 end
200 until true
201 _with_0 = _accum_0
202 end
203 return _with_0
204 end)())
205 local a
206 do
207 local _with_0 = tb
208 do
209 local _accum_0
210 repeat
211 if _with_0.v then
212 _accum_0 = _with_0.a
213 break
214 end
215 until true
216 _with_0 = _accum_0
217 end
218 a = _with_0
219 end
220 local _accum_0
221 while true do
222 local _with_0 = tb
223 local _accum_1
224 repeat
225 if _with_0 ~= nil then
226 _accum_1 = 1
227 break
228 end
229 until true
230 _with_0 = _accum_1
231 _accum_0 = _with_0
232 break
233 end
234 a = _accum_0
235end
236do
237 local a
238 local _accum_0
239 for i = 1, 100 do
240 local x = tb[i]
241 if x ~= nil then
242 local _des_0 = 1
243 if _des_0 then
244 x.id = _des_0
245 _accum_0 = x
246 break
247 end
248 end
249 end
250 a = _accum_0
251end
190return nil 252return nil
diff --git a/src/3rdParty/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/efsw/FileWatcherGeneric.cpp b/src/3rdParty/efsw/FileWatcherGeneric.cpp
index 3f3c52e..468d27c 100644
--- a/src/3rdParty/efsw/FileWatcherGeneric.cpp
+++ b/src/3rdParty/efsw/FileWatcherGeneric.cpp
@@ -25,7 +25,7 @@ FileWatcherGeneric::~FileWatcherGeneric() {
25} 25}
26 26
27WatchID FileWatcherGeneric::addWatch( const std::string& directory, FileWatchListener* watcher, 27WatchID FileWatcherGeneric::addWatch( const std::string& directory, FileWatchListener* watcher,
28 bool recursive, const std::vector<WatcherOption>& options ) { 28 bool recursive, const std::vector<WatcherOption>& /*options*/ ) {
29 std::string dir( directory ); 29 std::string dir( directory );
30 30
31 FileSystem::dirAddSlashAtEnd( dir ); 31 FileSystem::dirAddSlashAtEnd( dir );
diff --git a/src/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..2722c55 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) {
@@ -304,7 +341,7 @@ int main(int narg, const char** args) {
304 " -- Read from standard in, print to standard out\n" 341 " -- Read from standard in, print to standard out\n"
305 " (Must be first and only argument)\n\n" 342 " (Must be first and only argument)\n\n"
306 " --target=version Specify the Lua version that codes will be generated to\n" 343 " --target=version Specify the Lua version that codes will be generated to\n"
307 " (version can only be 5.1, 5.2, 5.3 or 5.4)\n" 344 " (version can only be 5.1 to 5.5)\n"
308 " --path=path_str Append an extra Lua search path string to package.path\n\n" 345 " --path=path_str Append an extra Lua search path string to package.path\n\n"
309 " Execute without options to enter REPL, type symbol '$'\n" 346 " Execute without options to enter REPL, type symbol '$'\n"
310 " in a single line to start/stop multi-line mode\n" 347 " in a single line to start/stop multi-line mode\n"
@@ -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 fe6e726..cfd4cc6 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,12 +174,11 @@ 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* ud) const { 180std::string GlobalOp_t::to_string(void*) const {
174 auto info = reinterpret_cast<YueFormat*>(ud); 181 return "*"s;
175 return info->convert(this);
176} 182}
177std::string ExportDefault_t::to_string(void*) const { 183std::string ExportDefault_t::to_string(void*) const {
178 return "default"s; 184 return "default"s;
@@ -188,22 +194,34 @@ std::string ConstValue_t::to_string(void* ud) const {
188std::string NotIn_t::to_string(void*) const { 194std::string NotIn_t::to_string(void*) const {
189 return {}; 195 return {};
190} 196}
197std::string Break_t::to_string(void*) const {
198 return "break"s;
199}
200std::string Continue_t::to_string(void*) const {
201 return "continue"s;
202}
191std::string BreakLoop_t::to_string(void* ud) const { 203std::string BreakLoop_t::to_string(void* ud) const {
192 auto info = reinterpret_cast<YueFormat*>(ud); 204 if (value) {
193 return info->convert(this); 205 return type->to_string(ud) + ' ' + value->to_string(ud);
206 }
207 return type->to_string(ud);
194} 208}
195std::string YueLineComment_t::to_string(void* ud) const { 209std::string YueLineComment_t::to_string(void* ud) const {
196 auto info = reinterpret_cast<YueFormat*>(ud); 210 auto info = reinterpret_cast<YueFormat*>(ud);
197 return "--"s + info->convert(this); 211 return "--"s + info->convert(this);
198} 212}
199std::string MultilineCommentInner_t::to_string(void* ud) const { 213std::string YueMultilineComment_t::to_string(void* ud) const {
200 auto info = reinterpret_cast<YueFormat*>(ud); 214 auto info = reinterpret_cast<YueFormat*>(ud);
201 return info->convert(this); 215 return "--[["s + info->convert(this) + "]]"s;
202} 216}
203std::string Variable_t::to_string(void* ud) const { 217std::string YueComment_t::to_string(void* ud) const {
204 return name->to_string(ud); 218 if (comment) {
219 return comment->to_string(ud);
220 } else {
221 return {};
222 }
205} 223}
206std::string LabelName_t::to_string(void* ud) const { 224std::string Variable_t::to_string(void* ud) const {
207 return name->to_string(ud); 225 return name->to_string(ud);
208} 226}
209std::string LuaKeyword_t::to_string(void* ud) const { 227std::string LuaKeyword_t::to_string(void* ud) const {
@@ -297,6 +315,20 @@ std::string ImportAs_t::to_string(void* ud) const {
297 } 315 }
298 return join(temp, " "s); 316 return join(temp, " "s);
299} 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}
329std::string ImportAllGlobal_t::to_string(void*) const {
330 return "global"s;
331}
300std::string Import_t::to_string(void* ud) const { 332std::string Import_t::to_string(void* ud) const {
301 if (ast_is<FromImport_t>(content)) { 333 if (ast_is<FromImport_t>(content)) {
302 return content->to_string(ud); 334 return content->to_string(ud);
@@ -324,6 +356,12 @@ std::string Backcall_t::to_string(void* ud) const {
324 temp.emplace_back(value->to_string(ud)); 356 temp.emplace_back(value->to_string(ud));
325 return join(temp, " "sv); 357 return join(temp, " "sv);
326} 358}
359std::string SubBackcall_t::to_string(void* ud) const {
360 str_list temp;
361 temp.emplace_back(arrow->to_string(ud));
362 temp.emplace_back(value->to_string(ud));
363 return join(temp, " "sv);
364}
327std::string PipeBody_t::to_string(void* ud) const { 365std::string PipeBody_t::to_string(void* ud) const {
328 auto info = reinterpret_cast<YueFormat*>(ud); 366 auto info = reinterpret_cast<YueFormat*>(ud);
329 str_list temp; 367 str_list temp;
@@ -332,13 +370,6 @@ std::string PipeBody_t::to_string(void* ud) const {
332 } 370 }
333 return join(temp, "\n"sv); 371 return join(temp, "\n"sv);
334} 372}
335std::string ExpListLow_t::to_string(void* ud) const {
336 str_list temp;
337 for (auto exp : exprs.objects()) {
338 temp.emplace_back(exp->to_string(ud));
339 }
340 return join(temp, "; "sv);
341}
342std::string ExpList_t::to_string(void* ud) const { 373std::string ExpList_t::to_string(void* ud) const {
343 str_list temp; 374 str_list temp;
344 for (auto exp : exprs.objects()) { 375 for (auto exp : exprs.objects()) {
@@ -359,8 +390,8 @@ std::string With_t::to_string(void* ud) const {
359 str_list temp{ 390 str_list temp{
360 eop ? "with?"s : "with"s, 391 eop ? "with?"s : "with"s,
361 valueList->to_string(ud)}; 392 valueList->to_string(ud)};
362 if (assigns) { 393 if (assign) {
363 temp.push_back(assigns->to_string(ud)); 394 temp.push_back(':' + assign->to_string(ud));
364 } 395 }
365 if (body.is<Statement_t>()) { 396 if (body.is<Statement_t>()) {
366 return join(temp, " "sv) + " do "s + body->to_string(ud); 397 return join(temp, " "sv) + " do "s + body->to_string(ud);
@@ -406,6 +437,9 @@ std::string SwitchCase_t::to_string(void* ud) const {
406std::string Switch_t::to_string(void* ud) const { 437std::string Switch_t::to_string(void* ud) const {
407 auto info = reinterpret_cast<YueFormat*>(ud); 438 auto info = reinterpret_cast<YueFormat*>(ud);
408 str_list temp{"switch "s + target->to_string(ud)}; 439 str_list temp{"switch "s + target->to_string(ud)};
440 if (assignment) {
441 temp.back().append(assignment->to_string(ud));
442 }
409 info->pushScope(); 443 info->pushScope();
410 for (auto branch : branches.objects()) { 444 for (auto branch : branches.objects()) {
411 temp.emplace_back(info->ind() + branch->to_string(ud)); 445 temp.emplace_back(info->ind() + branch->to_string(ud));
@@ -449,41 +483,75 @@ std::string If_t::to_string(void* ud) const {
449 temp.back() += " then"s; 483 temp.back() += " then"s;
450 } 484 }
451 ++it; 485 ++it;
452 bool condition = true; 486 enum class NType {
487 Cond,
488 Stat,
489 Block
490 };
491 NType lastType = NType::Cond;
453 for (; it != nodes.objects().end(); ++it) { 492 for (; it != nodes.objects().end(); ++it) {
454 auto node = *it; 493 auto node = *it;
455 switch (node->get_id()) { 494 switch (node->get_id()) {
456 case id<IfCond_t>(): 495 case id<IfCond_t>():
457 temp.emplace_back(info->ind() + "elseif "s + node->to_string(ud)); 496 temp.emplace_back(info->ind() + "elseif "s + node->to_string(ud));
458 condition = true; 497 lastType = NType::Cond;
459 break; 498 break;
460 case id<Statement_t>(): { 499 case id<Statement_t>(): {
461 if (condition) { 500 switch (lastType) {
462 temp.back() += " then "s + node->to_string(ud); 501 case NType::Cond:
463 } else { 502 temp.back() += " then "s + node->to_string(ud);
464 temp.emplace_back(info->ind() + "else "s + node->to_string(ud)); 503 break;
504 case NType::Stat:
505 if (temp.back().back() == '\n') {
506 temp.emplace_back(info->ind() + "else "s + node->to_string(ud));
507 } else {
508 temp.back() += " else "s + node->to_string(ud);
509 }
510 break;
511 case NType::Block:
512 temp.emplace_back(info->ind() + "else "s + node->to_string(ud));
513 break;
465 } 514 }
466 condition = false; 515 lastType = NType::Stat;
467 break; 516 break;
468 } 517 }
469 case id<Block_t>(): { 518 case id<Block_t>(): {
470 if (condition) { 519 switch (lastType) {
471 info->pushScope(); 520 case NType::Cond: {
472 temp.emplace_back(node->to_string(ud)); 521 info->pushScope();
473 if (temp.back().empty()) { 522 temp.emplace_back(node->to_string(ud));
474 temp.back() = info->ind() + "--"s; 523 if (temp.back().empty()) {
524 temp.back() = info->ind() + "--"s;
525 }
526 info->popScope();
527 break;
528 }
529 case NType::Stat: {
530 if (temp.back().back() == '\n') {
531 temp.emplace_back(info->ind() + "else"s);
532 } else {
533 temp.back() += " else"s;
534 }
535 info->pushScope();
536 temp.emplace_back(node->to_string(ud));
537 if (temp.back().empty()) {
538 temp.back() = info->ind() + "--"s;
539 }
540 info->popScope();
541 break;
475 } 542 }
476 info->popScope(); 543 case NType::Block: {
477 } else { 544 temp.emplace_back(info->ind() + "else"s);
478 temp.emplace_back(info->ind() + "else"s); 545 info->pushScope();
479 info->pushScope(); 546 temp.emplace_back(node->to_string(ud));
480 temp.emplace_back(node->to_string(ud)); 547 if (temp.back().empty()) {
481 if (temp.back().empty()) { 548 temp.back() = info->ind() + "--"s;
482 temp.back() = info->ind() + "--"s; 549 }
550 info->popScope();
551 break;
483 } 552 }
484 info->popScope();
485 } 553 }
486 condition = false; 554 lastType = NType::Block;
487 break; 555 break;
488 } 556 }
489 } 557 }
@@ -511,10 +579,10 @@ std::string While_t::to_string(void* ud) const {
511} 579}
512std::string Repeat_t::to_string(void* ud) const { 580std::string Repeat_t::to_string(void* ud) const {
513 auto info = reinterpret_cast<YueFormat*>(ud); 581 auto info = reinterpret_cast<YueFormat*>(ud);
514 str_list temp; 582 if (body.is<Statement_t>()) {
515 if (body->content.is<Statement_t>()) { 583 return "repeat "s + body->to_string(ud) + " until "s + condition->to_string(ud);
516 temp.emplace_back("repeat "s + body->to_string(ud));
517 } else { 584 } else {
585 str_list temp;
518 temp.emplace_back("repeat"s); 586 temp.emplace_back("repeat"s);
519 info->pushScope(); 587 info->pushScope();
520 temp.emplace_back(body->to_string(ud)); 588 temp.emplace_back(body->to_string(ud));
@@ -522,14 +590,14 @@ std::string Repeat_t::to_string(void* ud) const {
522 temp.back() = info->ind() + "--"s; 590 temp.back() = info->ind() + "--"s;
523 } 591 }
524 info->popScope(); 592 info->popScope();
593 temp.emplace_back(info->ind() + "until "s + condition->to_string(ud));
594 return join(temp, "\n"sv);
525 } 595 }
526 temp.emplace_back(info->ind() + "until "s + condition->to_string(ud));
527 return join(temp, "\n"sv);
528} 596}
529std::string ForStepValue_t::to_string(void* ud) const { 597std::string ForStepValue_t::to_string(void* ud) const {
530 return value->to_string(ud); 598 return value->to_string(ud);
531} 599}
532std::string For_t::to_string(void* ud) const { 600std::string ForNum_t::to_string(void* ud) const {
533 auto info = reinterpret_cast<YueFormat*>(ud); 601 auto info = reinterpret_cast<YueFormat*>(ud);
534 auto line = "for "s + varName->to_string(ud) + " = "s + startValue->to_string(ud) + ", "s + stopValue->to_string(ud); 602 auto line = "for "s + varName->to_string(ud) + " = "s + startValue->to_string(ud) + ", "s + stopValue->to_string(ud);
535 if (stepValue) { 603 if (stepValue) {
@@ -568,6 +636,9 @@ std::string ForEach_t::to_string(void* ud) const {
568 return line + '\n' + block; 636 return line + '\n' + block;
569 } 637 }
570} 638}
639std::string For_t::to_string(void* ud) const {
640 return forLoop->to_string(ud);
641}
571std::string Do_t::to_string(void* ud) const { 642std::string Do_t::to_string(void* ud) const {
572 auto info = reinterpret_cast<YueFormat*>(ud); 643 auto info = reinterpret_cast<YueFormat*>(ud);
573 if (body->content.is<Statement_t>()) { 644 if (body->content.is<Statement_t>()) {
@@ -596,10 +667,13 @@ std::string CatchBlock_t::to_string(void* ud) const {
596std::string Try_t::to_string(void* ud) const { 667std::string Try_t::to_string(void* ud) const {
597 auto info = reinterpret_cast<YueFormat*>(ud); 668 auto info = reinterpret_cast<YueFormat*>(ud);
598 str_list temp; 669 str_list temp;
670 temp.emplace_back("try"s);
671 if (eop) {
672 temp.back() += eop->to_string(ud);
673 }
599 if (func.is<Exp_t>()) { 674 if (func.is<Exp_t>()) {
600 temp.emplace_back("try "s + func->to_string(ud)); 675 temp.back() += (" "s + func->to_string(ud));
601 } else { 676 } else {
602 temp.emplace_back("try"s);
603 info->pushScope(); 677 info->pushScope();
604 temp.emplace_back(func->to_string(ud)); 678 temp.emplace_back(func->to_string(ud));
605 if (temp.back().empty()) { 679 if (temp.back().empty()) {
@@ -716,7 +790,7 @@ static bool isInBlockExp(ast_node* node, bool last = false) {
716 return false; 790 return false;
717} 791}
718std::string Comprehension_t::to_string(void* ud) const { 792std::string Comprehension_t::to_string(void* ud) const {
719 if (items.size() != 2 || !ast_is<CompInner_t>(items.back())) { 793 if (items.size() != 2 || !ast_is<CompFor_t>(items.back())) {
720 if (items.size() == 1) { 794 if (items.size() == 1) {
721 str_list temp; 795 str_list temp;
722 for (const auto& item : items.objects()) { 796 for (const auto& item : items.objects()) {
@@ -783,14 +857,14 @@ std::string StarExp_t::to_string(void* ud) const {
783std::string CompForEach_t::to_string(void* ud) const { 857std::string CompForEach_t::to_string(void* ud) const {
784 return "for "s + nameList->to_string(ud) + " in "s + loopValue->to_string(ud); 858 return "for "s + nameList->to_string(ud) + " in "s + loopValue->to_string(ud);
785} 859}
786std::string CompFor_t::to_string(void* ud) const { 860std::string CompForNum_t::to_string(void* ud) const {
787 auto line = "for "s + varName->to_string(ud) + " = "s + startValue->to_string(ud) + ", "s + stopValue->to_string(ud); 861 auto line = "for "s + varName->to_string(ud) + " = "s + startValue->to_string(ud) + ", "s + stopValue->to_string(ud);
788 if (stepValue) { 862 if (stepValue) {
789 line += stepValue->to_string(ud); 863 line += stepValue->to_string(ud);
790 } 864 }
791 return line; 865 return line;
792} 866}
793std::string CompInner_t::to_string(void* ud) const { 867std::string CompFor_t::to_string(void* ud) const {
794 str_list temp; 868 str_list temp;
795 for (auto item : items.objects()) { 869 for (auto item : items.objects()) {
796 if (ast_is<Exp_t>(item)) { 870 if (ast_is<Exp_t>(item)) {
@@ -809,7 +883,7 @@ std::string Assign_t::to_string(void* ud) const {
809 for (auto value : values.objects()) { 883 for (auto value : values.objects()) {
810 temp.emplace_back(value->to_string(ud)); 884 temp.emplace_back(value->to_string(ud));
811 } 885 }
812 return "= "s + join(temp, "; "sv); 886 return "= "s + join(temp, ", "sv);
813} 887}
814std::string Update_t::to_string(void* ud) const { 888std::string Update_t::to_string(void* ud) const {
815 return op->to_string(ud) + "= "s + value->to_string(ud); 889 return op->to_string(ud) + "= "s + value->to_string(ud);
@@ -851,6 +925,12 @@ std::string Exp_t::to_string(void* ud) const {
851 } 925 }
852 return join(temp, " "sv); 926 return join(temp, " "sv);
853} 927}
928std::string ReversedIndex_t::to_string(void* ud) const {
929 if (modifier) {
930 return "[# - "s + modifier->to_string(ud) + ']';
931 }
932 return "[#]"s;
933}
854std::string Callable_t::to_string(void* ud) const { 934std::string Callable_t::to_string(void* ud) const {
855 return item->to_string(ud); 935 return item->to_string(ud);
856} 936}
@@ -937,6 +1017,51 @@ std::string DoubleString_t::to_string(void* ud) const {
937 } 1017 }
938 return '"' + join(temp) + '"'; 1018 return '"' + join(temp) + '"';
939} 1019}
1020std::string YAMLIndent_t::to_string(void* ud) const {
1021 auto info = reinterpret_cast<YueFormat*>(ud);
1022 return info->convert(this);
1023}
1024std::string YAMLLineInner_t::to_string(void* ud) const {
1025 auto info = reinterpret_cast<YueFormat*>(ud);
1026 return info->convert(this);
1027}
1028std::string YAMLLineContent_t::to_string(void* ud) const {
1029 if (content.is<Exp_t>()) {
1030 return "#{"s + content->to_string(ud) + '}';
1031 }
1032 return content->to_string(ud);
1033}
1034std::string YAMLLine_t::to_string(void* ud) const {
1035 str_list temp;
1036 for (auto seg : segments.objects()) {
1037 temp.emplace_back(seg->to_string(ud));
1038 }
1039 return join(temp);
1040}
1041std::string YAMLMultiline_t::to_string(void* ud) const {
1042 auto info = reinterpret_cast<YueFormat*>(ud);
1043 int currentIndent = info->indent;
1044 str_list temp;
1045 int lastIndent = -1;
1046 for (auto line_ : lines.objects()) {
1047 auto line = static_cast<YAMLLine_t*>(line_);
1048 auto indent = line->indent->to_string(ud);
1049 int ind = 0;
1050 for (auto c : indent) {
1051 if (c == ' ') ind++;
1052 if (c == '\t') ind += 4;
1053 }
1054 if (lastIndent < ind) {
1055 info->pushScope();
1056 } else if (lastIndent > ind) {
1057 info->popScope();
1058 }
1059 lastIndent = ind;
1060 temp.emplace_back(indent + line->to_string(ud));
1061 }
1062 info->indent = currentIndent;
1063 return "|\n" + join(temp, "\n"sv) + '\n';
1064}
940std::string String_t::to_string(void* ud) const { 1065std::string String_t::to_string(void* ud) const {
941 return str->to_string(ud); 1066 return str->to_string(ud);
942} 1067}
@@ -1125,7 +1250,7 @@ std::string ClassDecl_t::to_string(void* ud) const {
1125 return line; 1250 return line;
1126} 1251}
1127std::string GlobalValues_t::to_string(void* ud) const { 1252std::string GlobalValues_t::to_string(void* ud) const {
1128 auto line = nameList->to_string(ud); 1253 std::string line = nameList->to_string(ud);
1129 if (valueList) { 1254 if (valueList) {
1130 if (valueList.is<TableBlock_t>()) { 1255 if (valueList.is<TableBlock_t>()) {
1131 line += " =\n"s + valueList->to_string(ud); 1256 line += " =\n"s + valueList->to_string(ud);
@@ -1136,7 +1261,7 @@ std::string GlobalValues_t::to_string(void* ud) const {
1136 return line; 1261 return line;
1137} 1262}
1138std::string Global_t::to_string(void* ud) const { 1263std::string Global_t::to_string(void* ud) const {
1139 return "global "s + item->to_string(ud); 1264 return "global "s + (constAttrib ? "const "s : ""s) + item->to_string(ud);
1140} 1265}
1141std::string Export_t::to_string(void* ud) const { 1266std::string Export_t::to_string(void* ud) const {
1142 auto line = "export"s; 1267 auto line = "export"s;
@@ -1235,6 +1360,9 @@ std::string FnArgDef_t::to_string(void* ud) const {
1235 if (op) { 1360 if (op) {
1236 line += op->to_string(ud); 1361 line += op->to_string(ud);
1237 } 1362 }
1363 if (label) {
1364 line += '`' + label->to_string(ud);
1365 }
1238 if (defaultValue) { 1366 if (defaultValue) {
1239 line += " = "s + defaultValue->to_string(ud); 1367 line += " = "s + defaultValue->to_string(ud);
1240 } 1368 }
@@ -1257,6 +1385,9 @@ std::string FnArgDefList_t::to_string(void* ud) const {
1257 } 1385 }
1258 if (varArg) { 1386 if (varArg) {
1259 temp.emplace_back(info->ind() + varArg->to_string(ud)); 1387 temp.emplace_back(info->ind() + varArg->to_string(ud));
1388 if (label) {
1389 temp.back().append('`' + label->to_string(ud));
1390 }
1260 } 1391 }
1261 return join(temp, "\n"sv); 1392 return join(temp, "\n"sv);
1262 } else { 1393 } else {
@@ -1265,6 +1396,9 @@ std::string FnArgDefList_t::to_string(void* ud) const {
1265 } 1396 }
1266 if (varArg) { 1397 if (varArg) {
1267 temp.emplace_back(varArg->to_string(ud)); 1398 temp.emplace_back(varArg->to_string(ud));
1399 if (label) {
1400 temp.back().append('`' + label->to_string(ud));
1401 }
1268 } 1402 }
1269 return join(temp, ", "sv); 1403 return join(temp, ", "sv);
1270 } 1404 }
@@ -1475,37 +1609,17 @@ std::string StatementAppendix_t::to_string(void* ud) const {
1475 return item->to_string(ud); 1609 return item->to_string(ud);
1476} 1610}
1477std::string Statement_t::to_string(void* ud) const { 1611std::string Statement_t::to_string(void* ud) const {
1478 std::string line; 1612 if (appendix) {
1479 if (!comments.empty()) { 1613 return content->to_string(ud) + ' ' + appendix->to_string(ud);
1480 auto info = reinterpret_cast<YueFormat*>(ud);
1481 str_list temp;
1482 for (ast_node* comment : comments.objects()) {
1483 if (comment == comments.front()) {
1484 temp.push_back(comment->to_string(ud));
1485 } else {
1486 temp.push_back(info->ind() + comment->to_string(ud));
1487 }
1488 }
1489 if (appendix) {
1490 temp.push_back(info->ind() + content->to_string(ud) + ' ' + appendix->to_string(ud));
1491 return join(temp, "\n"sv);
1492 } else {
1493 temp.push_back(info->ind() + content->to_string(ud));
1494 return join(temp, "\n"sv);
1495 }
1496 } else { 1614 } else {
1497 if (appendix) { 1615 return content->to_string(ud);
1498 return content->to_string(ud) + ' ' + appendix->to_string(ud);
1499 } else {
1500 return content->to_string(ud);
1501 }
1502 } 1616 }
1503} 1617}
1504std::string StatementSep_t::to_string(void*) const { 1618std::string StatementSep_t::to_string(void*) const {
1505 return {}; 1619 return {};
1506} 1620}
1507std::string YueMultilineComment_t::to_string(void* ud) const { 1621std::string EmptyLine_t::to_string(void*) const {
1508 return "--[["s + inner->to_string(ud) + "]]"s; 1622 return {};
1509} 1623}
1510std::string ChainAssign_t::to_string(void* ud) const { 1624std::string ChainAssign_t::to_string(void* ud) const {
1511 str_list temp; 1625 str_list temp;
@@ -1520,14 +1634,22 @@ std::string Body_t::to_string(void* ud) const {
1520std::string Block_t::to_string(void* ud) const { 1634std::string Block_t::to_string(void* ud) const {
1521 auto info = reinterpret_cast<YueFormat*>(ud); 1635 auto info = reinterpret_cast<YueFormat*>(ud);
1522 str_list temp; 1636 str_list temp;
1523 for (auto stmt_ : statements.objects()) { 1637 for (auto stmt_ : statementOrComments.objects()) {
1524 auto stmt = static_cast<Statement_t*>(stmt_); 1638 if (auto stmt = ast_cast<Statement_t>(stmt_)) {
1525 if (stmt->content.is<PipeBody_t>()) { 1639 if (stmt->content.is<PipeBody_t>()) {
1526 info->pushScope(); 1640 info->pushScope();
1527 temp.emplace_back(stmt->to_string(ud)); 1641 temp.emplace_back(stmt->to_string(ud));
1528 info->popScope(); 1642 info->popScope();
1529 } else { 1643 } else {
1530 temp.emplace_back(info->ind() + stmt->to_string(ud)); 1644 temp.emplace_back(info->ind() + stmt->to_string(ud));
1645 }
1646 } else if (info->reserveComment) {
1647 if (auto comment = ast_cast<YueComment_t>(stmt_)) {
1648 temp.emplace_back(info->ind() + comment->to_string(ud));
1649 } else {
1650 auto empty = ast_to<EmptyLine_t>(stmt_);
1651 temp.emplace_back(empty->to_string(ud));
1652 }
1531 } 1653 }
1532 } 1654 }
1533 return join(temp, "\n"sv); 1655 return join(temp, "\n"sv);
@@ -1546,3 +1668,4 @@ std::string File_t::to_string(void* ud) const {
1546} // namespace yue 1668} // namespace yue
1547 1669
1548} // namespace parserlib 1670} // namespace parserlib
1671
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h
index 5e70645..5043526 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
@@ -50,7 +50,7 @@ std::string_view ast_name() { return {}; }
50// clang-format off 50// clang-format off
51 51
52namespace yue { 52namespace yue {
53class ExpListLow_t; 53class ExpList_t;
54class TableBlock_t; 54class TableBlock_t;
55class SimpleTable_t; 55class SimpleTable_t;
56class TableLit_t; 56class TableLit_t;
@@ -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
@@ -156,7 +156,7 @@ AST_END(NameList)
156 156
157AST_NODE(LocalValues) 157AST_NODE(LocalValues)
158 ast_ptr<true, NameList_t> nameList; 158 ast_ptr<true, NameList_t> nameList;
159 ast_sel<false, TableBlock_t, ExpListLow_t> valueList; 159 ast_sel<false, TableBlock_t, ExpList_t> valueList;
160 AST_MEMBER(LocalValues, &nameList, &valueList) 160 AST_MEMBER(LocalValues, &nameList, &valueList)
161AST_END(LocalValues) 161AST_END(LocalValues)
162 162
@@ -233,18 +233,28 @@ AST_NODE(ImportAs)
233 AST_MEMBER(ImportAs, &literal, &target) 233 AST_MEMBER(ImportAs, &literal, &target)
234AST_END(ImportAs) 234AST_END(ImportAs)
235 235
236AST_LEAF(ImportAllGlobal)
237AST_END(ImportAllGlobal)
238
239AST_NODE(ImportGlobal)
240 ast_ptr<true, Seperator_t> sep;
241 ast_list<true, UnicodeName_t> segs;
242 ast_ptr<false, Variable_t> target;
243 AST_MEMBER(ImportGlobal, &sep, &segs, &target)
244AST_END(ImportGlobal)
245
236AST_NODE(Import) 246AST_NODE(Import)
237 ast_sel<true, ImportAs_t, ImportFrom_t, FromImport_t> content; 247 ast_sel<true, ImportAs_t, ImportFrom_t, FromImport_t, ImportGlobal_t, ImportAllGlobal_t> content;
238 AST_MEMBER(Import, &content) 248 AST_MEMBER(Import, &content)
239AST_END(Import) 249AST_END(Import)
240 250
241AST_NODE(Label) 251AST_NODE(Label)
242 ast_ptr<true, LabelName_t> label; 252 ast_ptr<true, UnicodeName_t> label;
243 AST_MEMBER(Label, &label) 253 AST_MEMBER(Label, &label)
244AST_END(Label) 254AST_END(Label)
245 255
246AST_NODE(Goto) 256AST_NODE(Goto)
247 ast_ptr<true, LabelName_t> label; 257 ast_ptr<true, UnicodeName_t> label;
248 AST_MEMBER(Goto, &label) 258 AST_MEMBER(Goto, &label)
249AST_END(Goto) 259AST_END(Goto)
250 260
@@ -263,31 +273,27 @@ AST_NODE(Backcall)
263 AST_MEMBER(Backcall, &argsDef, &arrow, &value) 273 AST_MEMBER(Backcall, &argsDef, &arrow, &value)
264AST_END(Backcall) 274AST_END(Backcall)
265 275
266AST_NODE(ExpListLow)
267 ast_ptr<true, Seperator_t> sep;
268 ast_list<true, Exp_t> exprs;
269 AST_MEMBER(ExpListLow, &sep, &exprs)
270AST_END(ExpListLow)
271
272AST_NODE(ExpList) 276AST_NODE(ExpList)
273 ast_ptr<true, Seperator_t> sep; 277 ast_ptr<true, Seperator_t> sep;
274 ast_list<true, Exp_t> exprs; 278 ast_list<true, Exp_t> exprs;
275 AST_MEMBER(ExpList, &sep, &exprs) 279 AST_MEMBER(ExpList, &sep, &exprs)
280 bool followStmtProcessed = false;
281 Statement_t* followStmt = nullptr;
276AST_END(ExpList) 282AST_END(ExpList)
277 283
278AST_NODE(Return) 284AST_NODE(Return)
279 bool allowBlockMacroReturn = false; 285 bool allowBlockMacroReturn = false;
280 bool explicitReturn = true; 286 bool explicitReturn = true;
281 ast_sel<false, TableBlock_t, ExpListLow_t> valueList; 287 ast_sel<false, TableBlock_t, ExpList_t> valueList;
282 AST_MEMBER(Return, &valueList) 288 AST_MEMBER(Return, &valueList)
283AST_END(Return) 289AST_END(Return)
284 290
285AST_NODE(With) 291AST_NODE(With)
286 ast_ptr<false, ExistentialOp_t> eop; 292 ast_ptr<false, ExistentialOp_t> eop;
287 ast_ptr<true, ExpList_t> valueList; 293 ast_ptr<true, ExpList_t> valueList;
288 ast_ptr<false, Assign_t> assigns; 294 ast_ptr<false, Assign_t> assign;
289 ast_sel<true, Block_t, Statement_t> body; 295 ast_sel<true, Block_t, Statement_t> body;
290 AST_MEMBER(With, &eop, &valueList, &assigns, &body) 296 AST_MEMBER(With, &eop, &valueList, &assign, &body)
291AST_END(With) 297AST_END(With)
292 298
293AST_NODE(SwitchList) 299AST_NODE(SwitchList)
@@ -302,20 +308,21 @@ AST_NODE(SwitchCase)
302 AST_MEMBER(SwitchCase, &condition, &body) 308 AST_MEMBER(SwitchCase, &condition, &body)
303AST_END(SwitchCase) 309AST_END(SwitchCase)
304 310
311AST_NODE(Assignment)
312 ast_ptr<false, ExpList_t> expList;
313 ast_ptr<true, Assign_t> assign;
314 AST_MEMBER(Assignment, &expList, &assign)
315AST_END(Assignment)
316
305AST_NODE(Switch) 317AST_NODE(Switch)
306 ast_ptr<true, Exp_t> target; 318 ast_ptr<true, Exp_t> target;
319 ast_ptr<false, Assignment_t> assignment;
307 ast_ptr<true, Seperator_t> sep; 320 ast_ptr<true, Seperator_t> sep;
308 ast_list<true, SwitchCase_t> branches; 321 ast_list<true, SwitchCase_t> branches;
309 ast_sel<false, Block_t, Statement_t> lastBranch; 322 ast_sel<false, Block_t, Statement_t> lastBranch;
310 AST_MEMBER(Switch, &target, &sep, &branches, &lastBranch) 323 AST_MEMBER(Switch, &target, &assignment, &sep, &branches, &lastBranch)
311AST_END(Switch) 324AST_END(Switch)
312 325
313AST_NODE(Assignment)
314 ast_ptr<false, ExpList_t> expList;
315 ast_ptr<true, Assign_t> assign;
316 AST_MEMBER(Assignment, &expList, &assign)
317AST_END(Assignment)
318
319AST_NODE(IfCond) 326AST_NODE(IfCond)
320 ast_ptr<true, Exp_t> condition; 327 ast_ptr<true, Exp_t> condition;
321 ast_ptr<false, Assignment_t> assignment; 328 ast_ptr<false, Assignment_t> assignment;
@@ -343,7 +350,7 @@ AST_NODE(While)
343AST_END(While) 350AST_END(While)
344 351
345AST_NODE(Repeat) 352AST_NODE(Repeat)
346 ast_ptr<true, Body_t> body; 353 ast_sel<true, Block_t, Statement_t> body;
347 ast_ptr<true, Exp_t> condition; 354 ast_ptr<true, Exp_t> condition;
348 AST_MEMBER(Repeat, &body, &condition) 355 AST_MEMBER(Repeat, &body, &condition)
349AST_END(Repeat) 356AST_END(Repeat)
@@ -353,14 +360,14 @@ AST_NODE(ForStepValue)
353 AST_MEMBER(ForStepValue, &value) 360 AST_MEMBER(ForStepValue, &value)
354AST_END(ForStepValue) 361AST_END(ForStepValue)
355 362
356AST_NODE(For) 363AST_NODE(ForNum)
357 ast_ptr<true, Variable_t> varName; 364 ast_ptr<true, Variable_t> varName;
358 ast_ptr<true, Exp_t> startValue; 365 ast_ptr<true, Exp_t> startValue;
359 ast_ptr<true, Exp_t> stopValue; 366 ast_ptr<true, Exp_t> stopValue;
360 ast_ptr<false, ForStepValue_t> stepValue; 367 ast_ptr<false, ForStepValue_t> stepValue;
361 ast_sel<true, Block_t, Statement_t> body; 368 ast_sel<true, Block_t, Statement_t> body;
362 AST_MEMBER(For, &varName, &startValue, &stopValue, &stepValue, &body) 369 AST_MEMBER(ForNum, &varName, &startValue, &stopValue, &stepValue, &body)
363AST_END(For) 370AST_END(ForNum)
364 371
365AST_NODE(ForEach) 372AST_NODE(ForEach)
366 ast_ptr<true, AssignableNameList_t> nameList; 373 ast_ptr<true, AssignableNameList_t> nameList;
@@ -369,6 +376,11 @@ AST_NODE(ForEach)
369 AST_MEMBER(ForEach, &nameList, &loopValue, &body) 376 AST_MEMBER(ForEach, &nameList, &loopValue, &body)
370AST_END(ForEach) 377AST_END(ForEach)
371 378
379AST_NODE(For)
380 ast_sel<true, ForEach_t, ForNum_t> forLoop;
381 AST_MEMBER(For, &forLoop)
382AST_END(For)
383
372AST_NODE(Do) 384AST_NODE(Do)
373 ast_ptr<true, Body_t> body; 385 ast_ptr<true, Body_t> body;
374 AST_MEMBER(Do, &body) 386 AST_MEMBER(Do, &body)
@@ -381,14 +393,15 @@ AST_NODE(CatchBlock)
381AST_END(CatchBlock) 393AST_END(CatchBlock)
382 394
383AST_NODE(Try) 395AST_NODE(Try)
396 ast_ptr<false, ExistentialOp_t> eop;
384 ast_sel<true, Block_t, Exp_t> func; 397 ast_sel<true, Block_t, Exp_t> func;
385 ast_ptr<false, CatchBlock_t> catchBlock; 398 ast_ptr<false, CatchBlock_t> catchBlock;
386 AST_MEMBER(Try, &func, &catchBlock) 399 AST_MEMBER(Try, &eop, &func, &catchBlock)
387AST_END(Try) 400AST_END(Try)
388 401
389AST_NODE(Comprehension) 402AST_NODE(Comprehension)
390 ast_ptr<true, Seperator_t> sep; 403 ast_ptr<true, Seperator_t> sep;
391 ast_sel_list<false, NormalDef_t, SpreadListExp_t, CompInner_t, 404 ast_sel_list<false, NormalDef_t, SpreadListExp_t, CompFor_t,
392 /*non-syntax-rule*/ Statement_t> items; 405 /*non-syntax-rule*/ Statement_t> items;
393 AST_MEMBER(Comprehension, &sep, &items) 406 AST_MEMBER(Comprehension, &sep, &items)
394AST_END(Comprehension) 407AST_END(Comprehension)
@@ -401,7 +414,7 @@ AST_END(CompValue)
401AST_NODE(TblComprehension) 414AST_NODE(TblComprehension)
402 ast_ptr<true, Exp_t> key; 415 ast_ptr<true, Exp_t> key;
403 ast_ptr<false, CompValue_t> value; 416 ast_ptr<false, CompValue_t> value;
404 ast_ptr<true, CompInner_t> forLoop; 417 ast_ptr<true, CompFor_t> forLoop;
405 AST_MEMBER(TblComprehension, &key, &value, &forLoop) 418 AST_MEMBER(TblComprehension, &key, &value, &forLoop)
406AST_END(TblComprehension) 419AST_END(TblComprehension)
407 420
@@ -416,23 +429,23 @@ AST_NODE(CompForEach)
416 AST_MEMBER(CompForEach, &nameList, &loopValue) 429 AST_MEMBER(CompForEach, &nameList, &loopValue)
417AST_END(CompForEach) 430AST_END(CompForEach)
418 431
419AST_NODE(CompFor) 432AST_NODE(CompForNum)
420 ast_ptr<true, Variable_t> varName; 433 ast_ptr<true, Variable_t> varName;
421 ast_ptr<true, Exp_t> startValue; 434 ast_ptr<true, Exp_t> startValue;
422 ast_ptr<true, Exp_t> stopValue; 435 ast_ptr<true, Exp_t> stopValue;
423 ast_ptr<false, ForStepValue_t> stepValue; 436 ast_ptr<false, ForStepValue_t> stepValue;
424 AST_MEMBER(CompFor, &varName, &startValue, &stopValue, &stepValue) 437 AST_MEMBER(CompForNum, &varName, &startValue, &stopValue, &stepValue)
425AST_END(CompFor) 438AST_END(CompForNum)
426 439
427AST_NODE(CompInner) 440AST_NODE(CompFor)
428 ast_ptr<true, Seperator_t> sep; 441 ast_ptr<true, Seperator_t> sep;
429 ast_sel_list<true, CompFor_t, CompForEach_t, Exp_t> items; 442 ast_sel_list<true, CompForNum_t, CompForEach_t, Exp_t> items;
430 AST_MEMBER(CompInner, &sep, &items) 443 AST_MEMBER(CompFor, &sep, &items)
431AST_END(CompInner) 444AST_END(CompFor)
432 445
433AST_NODE(Assign) 446AST_NODE(Assign)
434 ast_ptr<true, Seperator_t> sep; 447 ast_ptr<true, Seperator_t> sep;
435 ast_sel_list<true, With_t, If_t, Switch_t, TableBlock_t, Exp_t> values; 448 ast_sel_list<true, With_t, If_t, Switch_t, TableBlock_t, Exp_t, SpreadListExp_t> values;
436 AST_MEMBER(Assign, &sep, &values) 449 AST_MEMBER(Assign, &sep, &values)
437AST_END(Assign) 450AST_END(Assign)
438 451
@@ -547,8 +560,8 @@ AST_NODE(SimpleValue)
547 ast_sel<true, 560 ast_sel<true,
548 TableLit_t, ConstValue_t, 561 TableLit_t, ConstValue_t,
549 If_t, Switch_t, With_t, ClassDecl_t, 562 If_t, Switch_t, With_t, ClassDecl_t,
550 ForEach_t, For_t, While_t, Do_t, Try_t, 563 For_t, While_t, Repeat_t,
551 UnaryValue_t, 564 Do_t, Try_t, UnaryValue_t,
552 TblComprehension_t, Comprehension_t, 565 TblComprehension_t, Comprehension_t,
553 FunLit_t, Num_t, VarArg_t> value; 566 FunLit_t, Num_t, VarArg_t> value;
554 AST_MEMBER(SimpleValue, &value) 567 AST_MEMBER(SimpleValue, &value)
@@ -587,8 +600,31 @@ AST_NODE(DoubleString)
587 AST_MEMBER(DoubleString, &sep, &segments) 600 AST_MEMBER(DoubleString, &sep, &segments)
588AST_END(DoubleString) 601AST_END(DoubleString)
589 602
603AST_LEAF(YAMLIndent)
604AST_END(YAMLIndent)
605
606AST_LEAF(YAMLLineInner)
607AST_END(YAMLLineInner)
608
609AST_NODE(YAMLLineContent)
610 ast_sel<true, YAMLLineInner_t, Exp_t> content;
611 AST_MEMBER(YAMLLineContent, &content)
612AST_END(YAMLLineContent)
613
614AST_NODE(YAMLLine)
615 ast_ptr<true, YAMLIndent_t> indent;
616 ast_list<true, YAMLLineContent_t> segments;
617 AST_MEMBER(YAMLLine, &indent, &segments)
618AST_END(YAMLLine)
619
620AST_NODE(YAMLMultiline)
621 ast_ptr<true, Seperator_t> sep;
622 ast_list<true, YAMLLine_t> lines;
623 AST_MEMBER(YAMLMultiline, &sep, &lines)
624AST_END(YAMLMultiline)
625
590AST_NODE(String) 626AST_NODE(String)
591 ast_sel<true, DoubleString_t, SingleString_t, LuaString_t> str; 627 ast_sel<true, DoubleString_t, SingleString_t, LuaString_t, YAMLMultiline_t> str;
592 AST_MEMBER(String, &str) 628 AST_MEMBER(String, &str)
593AST_END(String) 629AST_END(String)
594 630
@@ -639,9 +675,14 @@ AST_END(TableAppendingOp)
639AST_LEAF(PlainItem) 675AST_LEAF(PlainItem)
640AST_END(PlainItem) 676AST_END(PlainItem)
641 677
678AST_NODE(ReversedIndex)
679 ast_ptr<false, Exp_t> modifier;
680 AST_MEMBER(ReversedIndex, &modifier)
681AST_END(ReversedIndex)
682
642AST_NODE(ChainValue) 683AST_NODE(ChainValue)
643 ast_ptr<true, Seperator_t> sep; 684 ast_ptr<true, Seperator_t> sep;
644 ast_sel_list<true, Callable_t, Invoke_t, DotChainItem_t, ColonChainItem_t, Slice_t, Exp_t, String_t, InvokeArgs_t, ExistentialOp_t, TableAppendingOp_t, 685 ast_sel_list<true, Callable_t, Invoke_t, DotChainItem_t, ColonChainItem_t, Slice_t, Exp_t, String_t, InvokeArgs_t, ExistentialOp_t, TableAppendingOp_t, ReversedIndex_t,
645 /*non-syntax-rule*/ PlainItem_t> items; 686 /*non-syntax-rule*/ PlainItem_t> items;
646 AST_MEMBER(ChainValue, &sep, &items) 687 AST_MEMBER(ChainValue, &sep, &items)
647AST_END(ChainValue) 688AST_END(ChainValue)
@@ -717,7 +758,7 @@ AST_END(ClassDecl)
717 758
718AST_NODE(GlobalValues) 759AST_NODE(GlobalValues)
719 ast_ptr<true, NameList_t> nameList; 760 ast_ptr<true, NameList_t> nameList;
720 ast_sel<false, TableBlock_t, ExpListLow_t> valueList; 761 ast_sel<false, TableBlock_t, ExpList_t> valueList;
721 AST_MEMBER(GlobalValues, &nameList, &valueList) 762 AST_MEMBER(GlobalValues, &nameList, &valueList)
722AST_END(GlobalValues) 763AST_END(GlobalValues)
723 764
@@ -725,8 +766,9 @@ AST_LEAF(GlobalOp)
725AST_END(GlobalOp) 766AST_END(GlobalOp)
726 767
727AST_NODE(Global) 768AST_NODE(Global)
769 ast_ptr<false, ConstAttrib_t> constAttrib;
728 ast_sel<true, ClassDecl_t, GlobalOp_t, GlobalValues_t> item; 770 ast_sel<true, ClassDecl_t, GlobalOp_t, GlobalValues_t> item;
729 AST_MEMBER(Global, &item) 771 AST_MEMBER(Global, &constAttrib, &item)
730AST_END(Global) 772AST_END(Global)
731 773
732AST_LEAF(ExportDefault) 774AST_LEAF(ExportDefault)
@@ -740,17 +782,19 @@ AST_NODE(Export)
740AST_END(Export) 782AST_END(Export)
741 783
742AST_NODE(FnArgDef) 784AST_NODE(FnArgDef)
743 ast_sel<true, Variable_t, SelfItem_t> name; 785 ast_sel<true, Variable_t, SelfItem_t, SimpleTable_t, TableLit_t> name;
744 ast_ptr<false, ExistentialOp_t> op; 786 ast_ptr<false, ExistentialOp_t> op;
787 ast_ptr<false, Name_t> label;
745 ast_ptr<false, Exp_t> defaultValue; 788 ast_ptr<false, Exp_t> defaultValue;
746 AST_MEMBER(FnArgDef, &name, &op, &defaultValue) 789 AST_MEMBER(FnArgDef, &name, &op, &label, &defaultValue)
747AST_END(FnArgDef) 790AST_END(FnArgDef)
748 791
749AST_NODE(FnArgDefList) 792AST_NODE(FnArgDefList)
750 ast_ptr<true, Seperator_t> sep; 793 ast_ptr<true, Seperator_t> sep;
751 ast_list<false, FnArgDef_t> definitions; 794 ast_list<false, FnArgDef_t> definitions;
752 ast_ptr<false, VarArg_t> varArg; 795 ast_ptr<false, VarArgDef_t> varArg;
753 AST_MEMBER(FnArgDefList, &sep, &definitions, &varArg) 796 ast_ptr<false, Name_t> label;
797 AST_MEMBER(FnArgDefList, &sep, &definitions, &varArg, &label)
754AST_END(FnArgDefList) 798AST_END(FnArgDefList)
755 799
756AST_NODE(OuterVarShadow) 800AST_NODE(OuterVarShadow)
@@ -769,7 +813,7 @@ AST_END(FnArrow)
769 813
770AST_NODE(FunLit) 814AST_NODE(FunLit)
771 ast_ptr<false, FnArgsDef_t> argsDef; 815 ast_ptr<false, FnArgsDef_t> argsDef;
772 ast_sel<false, ExpListLow_t, DefaultValue_t> defaultReturn; 816 ast_sel<false, ExpList_t, DefaultValue_t> defaultReturn;
773 ast_ptr<true, FnArrow_t> arrow; 817 ast_ptr<true, FnArrow_t> arrow;
774 ast_ptr<false, Body_t> body; 818 ast_ptr<false, Body_t> body;
775 bool noRecursion = false; 819 bool noRecursion = false;
@@ -806,7 +850,7 @@ AST_NODE(Macro)
806AST_END(Macro) 850AST_END(Macro)
807 851
808AST_NODE(NameOrDestructure) 852AST_NODE(NameOrDestructure)
809 ast_sel<true, Variable_t, TableLit_t, Comprehension_t> item; 853 ast_sel<true, Variable_t, SimpleTable_t, TableLit_t, Comprehension_t> item;
810 AST_MEMBER(NameOrDestructure, &item) 854 AST_MEMBER(NameOrDestructure, &item)
811AST_END(NameOrDestructure) 855AST_END(NameOrDestructure)
812 856
@@ -838,9 +882,15 @@ AST_NODE(UnaryExp)
838 AST_MEMBER(UnaryExp, &ops, &expos, &inExp) 882 AST_MEMBER(UnaryExp, &ops, &expos, &inExp)
839AST_END(UnaryExp) 883AST_END(UnaryExp)
840 884
885AST_NODE(SubBackcall)
886 ast_ptr<true, FnArrowBack_t> arrow;
887 ast_ptr<true, ChainValue_t> value;
888 AST_MEMBER(SubBackcall, &arrow, &value)
889AST_END(SubBackcall)
890
841AST_NODE(ExpListAssign) 891AST_NODE(ExpListAssign)
842 ast_ptr<true, ExpList_t> expList; 892 ast_ptr<true, ExpList_t> expList;
843 ast_sel<false, Update_t, Assign_t> action; 893 ast_sel<false, Update_t, Assign_t, SubBackcall_t> action;
844 AST_MEMBER(ExpListAssign, &expList, &action) 894 AST_MEMBER(ExpListAssign, &expList, &action)
845AST_END(ExpListAssign) 895AST_END(ExpListAssign)
846 896
@@ -856,7 +906,17 @@ AST_NODE(WhileLine)
856 AST_MEMBER(WhileLine, &type, &condition) 906 AST_MEMBER(WhileLine, &type, &condition)
857AST_END(WhileLine) 907AST_END(WhileLine)
858 908
859AST_LEAF(BreakLoop) 909AST_LEAF(Break)
910AST_END(Break)
911
912AST_LEAF(Continue)
913AST_END(Continue)
914
915AST_NODE(BreakLoop)
916 ast_sel<true, Break_t, Continue_t> type;
917 ast_ptr<false, Exp_t> value;
918 AST_MEMBER(BreakLoop, &type, &value)
919 std::string varBWV;
860AST_END(BreakLoop) 920AST_END(BreakLoop)
861 921
862AST_NODE(PipeBody) 922AST_NODE(PipeBody)
@@ -866,7 +926,7 @@ AST_NODE(PipeBody)
866AST_END(PipeBody) 926AST_END(PipeBody)
867 927
868AST_NODE(StatementAppendix) 928AST_NODE(StatementAppendix)
869 ast_sel<true, IfLine_t, WhileLine_t, CompInner_t> item; 929 ast_sel<true, IfLine_t, WhileLine_t, CompFor_t> item;
870 AST_MEMBER(StatementAppendix, &item) 930 AST_MEMBER(StatementAppendix, &item)
871AST_END(StatementAppendix) 931AST_END(StatementAppendix)
872 932
@@ -876,14 +936,17 @@ AST_END(StatementSep)
876AST_LEAF(YueLineComment) 936AST_LEAF(YueLineComment)
877AST_END(YueLineComment) 937AST_END(YueLineComment)
878 938
879AST_LEAF(MultilineCommentInner) 939AST_LEAF(YueMultilineComment)
880AST_END(MultilineCommentInner)
881
882AST_NODE(YueMultilineComment)
883 ast_ptr<true, MultilineCommentInner_t> inner;
884 AST_MEMBER(YueMultilineComment, &inner)
885AST_END(YueMultilineComment) 940AST_END(YueMultilineComment)
886 941
942AST_NODE(YueComment)
943 ast_sel<true, YueLineComment_t, YueMultilineComment_t> comment;
944 AST_MEMBER(YueComment, &comment)
945AST_END(YueComment)
946
947AST_LEAF(EmptyLine)
948AST_END(EmptyLine)
949
887AST_NODE(ChainAssign) 950AST_NODE(ChainAssign)
888 ast_ptr<true, Seperator_t> sep; 951 ast_ptr<true, Seperator_t> sep;
889 ast_list<true, Exp_t> exprs; 952 ast_list<true, Exp_t> exprs;
@@ -892,16 +955,14 @@ AST_NODE(ChainAssign)
892AST_END(ChainAssign) 955AST_END(ChainAssign)
893 956
894AST_NODE(Statement) 957AST_NODE(Statement)
895 ast_ptr<true, Seperator_t> sep;
896 ast_sel_list<false, YueLineComment_t, YueMultilineComment_t> comments;
897 ast_sel<true, 958 ast_sel<true,
898 Import_t, While_t, Repeat_t, For_t, ForEach_t, 959 Import_t, While_t, Repeat_t, For_t,
899 Return_t, Local_t, Global_t, Export_t, Macro_t, MacroInPlace_t, 960 Return_t, Local_t, Global_t, Export_t, Macro_t, MacroInPlace_t,
900 BreakLoop_t, Label_t, Goto_t, ShortTabAppending_t, 961 BreakLoop_t, Label_t, Goto_t, ShortTabAppending_t,
901 Backcall_t, LocalAttrib_t, PipeBody_t, ExpListAssign_t, ChainAssign_t 962 Backcall_t, LocalAttrib_t, PipeBody_t, ExpListAssign_t, ChainAssign_t
902 > content; 963 > content;
903 ast_ptr<false, StatementAppendix_t> appendix; 964 ast_ptr<false, StatementAppendix_t> appendix;
904 AST_MEMBER(Statement, &sep, &comments, &content, &appendix) 965 AST_MEMBER(Statement, &content, &appendix)
905AST_END(Statement) 966AST_END(Statement)
906 967
907AST_NODE(Body) 968AST_NODE(Body)
@@ -911,8 +972,8 @@ AST_END(Body)
911 972
912AST_NODE(Block) 973AST_NODE(Block)
913 ast_ptr<true, Seperator_t> sep; 974 ast_ptr<true, Seperator_t> sep;
914 ast_list<false, Statement_t> statements; 975 ast_sel_list<false, Statement_t, YueComment_t, EmptyLine_t> statementOrComments;
915 AST_MEMBER(Block, &sep, &statements) 976 AST_MEMBER(Block, &sep, &statementOrComments)
916AST_END(Block) 977AST_END(Block)
917 978
918AST_NODE(BlockEnd) 979AST_NODE(BlockEnd)
@@ -931,9 +992,9 @@ struct YueFormat {
931 int indent = 0; 992 int indent = 0;
932 bool spaceOverTab = false; 993 bool spaceOverTab = false;
933 int tabSpaces = 4; 994 int tabSpaces = 4;
995 bool reserveComment = true;
934 std::string toString(ast_node* node); 996 std::string toString(ast_node* node);
935 997
936 Converter converter{};
937 void pushScope(); 998 void pushScope();
938 void popScope(); 999 void popScope();
939 std::string convert(const ast_node* node); 1000 std::string convert(const ast_node* node);
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp
index 590c502..f9b4f18 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.27.5"sv; 81const std::string_view version = "0.32.1"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";
@@ -429,8 +430,18 @@ private:
429 }; 430 };
430 enum class VarType { 431 enum class VarType {
431 Local = 0, 432 Local = 0,
432 Const = 1, 433 LocalConst = 1,
433 Global = 2 434 Global = 2,
435 GlobalConst = 3
436 };
437 struct Scope;
438 struct ImportedGlobal {
439 std::string* globalCodeLine = nullptr;
440 std::unordered_map<std::string, VarType>* vars = nullptr;
441 std::string indent;
442 std::string nl;
443 std::unordered_set<std::string_view> globals;
444 str_list globalList;
434 }; 445 };
435 struct Scope { 446 struct Scope {
436 GlobalMode mode = GlobalMode::None; 447 GlobalMode mode = GlobalMode::None;
@@ -440,8 +451,10 @@ private:
440#endif 451#endif
441 std::unique_ptr<std::unordered_map<std::string, VarType>> vars; 452 std::unique_ptr<std::unordered_map<std::string, VarType>> vars;
442 std::unique_ptr<std::unordered_set<std::string>> allows; 453 std::unique_ptr<std::unordered_set<std::string>> allows;
454 std::unique_ptr<ImportedGlobal> importedGlobal;
443 }; 455 };
444 std::list<Scope> _scopes; 456 std::list<Scope> _scopes;
457 ImportedGlobal* _importedGlobal = nullptr;
445 static const std::string Empty; 458 static const std::string Empty;
446 459
447 enum class MemType { 460 enum class MemType {
@@ -558,7 +571,7 @@ private:
558 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) { 571 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) {
559 auto vars = it->vars.get(); 572 auto vars = it->vars.get();
560 auto vit = vars->find(name); 573 auto vit = vars->find(name);
561 if (vit != vars->end() && vit->second != VarType::Global) { 574 if (vit != vars->end() && (vit->second == VarType::Local || vit->second == VarType::LocalConst)) {
562 local = true; 575 local = true;
563 break; 576 break;
564 } 577 }
@@ -571,7 +584,7 @@ private:
571 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) { 584 for (auto it = _scopes.rbegin(); it != _scopes.rend(); ++it) {
572 auto vars = it->vars.get(); 585 auto vars = it->vars.get();
573 auto vit = vars->find(name); 586 auto vit = vars->find(name);
574 if (vit != vars->end() && vit->second == VarType::Global) { 587 if (vit != vars->end() && (vit->second == VarType::Global || vit->second == VarType::GlobalConst)) {
575 global = true; 588 global = true;
576 break; 589 break;
577 } 590 }
@@ -593,7 +606,7 @@ private:
593 auto vars = it->vars.get(); 606 auto vars = it->vars.get();
594 auto vit = vars->find(name); 607 auto vit = vars->find(name);
595 if (vit != vars->end()) { 608 if (vit != vars->end()) {
596 isConst = (vit->second == VarType::Const); 609 isConst = (vit->second == VarType::LocalConst || vit->second == VarType::GlobalConst);
597 break; 610 break;
598 } 611 }
599 if (checkShadowScopeOnly && it->allows) break; 612 if (checkShadowScopeOnly && it->allows) break;
@@ -874,9 +887,13 @@ private:
874 return false; 887 return false;
875 } 888 }
876 889
877 void markVarConst(const std::string& name) { 890 bool isListComp(Comprehension_t* comp) const {
891 return comp->items.size() == 2 && ast_is<CompFor_t>(comp->items.back());
892 }
893
894 void markVarLocalConst(const std::string& name) {
878 auto& scope = _scopes.back(); 895 auto& scope = _scopes.back();
879 scope.vars->insert_or_assign(name, VarType::Const); 896 scope.vars->insert_or_assign(name, VarType::LocalConst);
880 } 897 }
881 898
882 void markVarShadowed() { 899 void markVarShadowed() {
@@ -895,6 +912,11 @@ private:
895 scope.vars->insert_or_assign(name, VarType::Global); 912 scope.vars->insert_or_assign(name, VarType::Global);
896 } 913 }
897 914
915 void markVarGlobalConst(const std::string& name) {
916 auto& scope = _scopes.back();
917 scope.vars->insert_or_assign(name, VarType::GlobalConst);
918 }
919
898 void addToAllowList(const std::string& name) { 920 void addToAllowList(const std::string& name) {
899 auto& scope = _scopes.back(); 921 auto& scope = _scopes.back();
900 scope.allows->insert(name); 922 scope.allows->insert(name);
@@ -961,7 +983,7 @@ private:
961 } 983 }
962 } 984 }
963 985
964 const std::string nll(ast_node* node) const { 986 const std::string nl(ast_node* node) const {
965 if (_config.reserveLineNumber) { 987 if (_config.reserveLineNumber) {
966 return " -- "s + std::to_string(node->m_begin.m_line + _config.lineOffset) + _newLine; 988 return " -- "s + std::to_string(node->m_begin.m_line + _config.lineOffset) + _newLine;
967 } else { 989 } else {
@@ -969,14 +991,6 @@ private:
969 } 991 }
970 } 992 }
971 993
972 const std::string nlr(ast_node* node) const {
973 if (_config.reserveLineNumber) {
974 return " -- "s + std::to_string(node->m_end.m_line + _config.lineOffset) + _newLine;
975 } else {
976 return _newLine;
977 }
978 }
979
980 void incIndentOffset() { 994 void incIndentOffset() {
981 _indentOffset++; 995 _indentOffset++;
982 } 996 }
@@ -1043,13 +1057,6 @@ private:
1043 } 1057 }
1044 break; 1058 break;
1045 } 1059 }
1046 case id<ExpListLow_t>(): {
1047 auto expList = static_cast<ExpListLow_t*>(item);
1048 if (expList->exprs.size() == 1) {
1049 exp = static_cast<Exp_t*>(expList->exprs.front());
1050 }
1051 break;
1052 }
1053 case id<SwitchList_t>(): { 1060 case id<SwitchList_t>(): {
1054 auto expList = static_cast<SwitchList_t*>(item); 1061 auto expList = static_cast<SwitchList_t*>(item);
1055 if (expList->exprs.size() == 1) { 1062 if (expList->exprs.size() == 1) {
@@ -1078,12 +1085,12 @@ private:
1078 return nullptr; 1085 return nullptr;
1079 } 1086 }
1080 1087
1081 Value_t* singleValueFrom(ast_node* item) const { 1088 Value_t* singleValueFrom(ast_node* item, bool forceUnparened = false) const {
1082 if (auto unary = singleUnaryExpFrom(item)) { 1089 if (auto unary = singleUnaryExpFrom(item)) {
1083 if (unary->ops.empty()) { 1090 if (unary->ops.empty()) {
1084 Value_t* value = static_cast<Value_t*>(unary->expos.back()); 1091 Value_t* value = static_cast<Value_t*>(unary->expos.back());
1085 if (auto chain = ast_cast<ChainValue_t>(value->item); chain && chain->items.size() == 1) { 1092 if (auto chain = ast_cast<ChainValue_t>(value->item); chain && chain->items.size() == 1) {
1086 if (auto parens = chain->get_by_path<Callable_t, Parens_t>(); parens && parens->extra) { 1093 if (auto parens = chain->get_by_path<Callable_t, Parens_t>(); parens && (forceUnparened || parens->extra)) {
1087 if (auto insideValue = singleValueFrom(parens->expr)) { 1094 if (auto insideValue = singleValueFrom(parens->expr)) {
1088 return insideValue; 1095 return insideValue;
1089 } 1096 }
@@ -1143,6 +1150,22 @@ private:
1143 return exp; 1150 return exp;
1144 } 1151 }
1145 1152
1153 ast_ptr<false, Return_t> newReturn(Exp_t* value) {
1154 auto returnNode = value->new_ptr<Return_t>();
1155 returnNode->explicitReturn = false;
1156 auto expList = value->new_ptr<ExpList_t>();
1157 expList->exprs.push_back(value);
1158 returnNode->valueList.set(expList);
1159 return returnNode;
1160 }
1161
1162 ast_ptr<false, Return_t> newReturn(ExpList_t* valueList) {
1163 auto returnNode = valueList->new_ptr<Return_t>();
1164 returnNode->explicitReturn = false;
1165 returnNode->valueList.set(valueList);
1166 return returnNode;
1167 }
1168
1146 SimpleValue_t* simpleSingleValueFrom(ast_node* node) const { 1169 SimpleValue_t* simpleSingleValueFrom(ast_node* node) const {
1147 auto value = singleValueFrom(node); 1170 auto value = singleValueFrom(node);
1148 if (value && value->item.is<SimpleValue_t>()) { 1171 if (value && value->item.is<SimpleValue_t>()) {
@@ -1163,14 +1186,22 @@ private:
1163 return nullptr; 1186 return nullptr;
1164 } 1187 }
1165 1188
1166 Statement_t* lastStatementFrom(const node_container& stmts) const { 1189 Statement_t* lastStatementFrom(const node_container& statementOrComments) const {
1167 if (!stmts.empty()) { 1190 if (!statementOrComments.empty()) {
1168 auto it = stmts.end(); 1191 for (auto it = statementOrComments.rbegin(); it != statementOrComments.rend(); ++it) {
1169 --it; 1192 if (auto stmt = ast_cast<Statement_t>(*it)) {
1170 while (!static_cast<Statement_t*>(*it)->content && it != stmts.begin()) { 1193 return stmt;
1171 --it; 1194 }
1195 }
1196 }
1197 return nullptr;
1198 }
1199
1200 Statement_t* firstStatementFrom(Block_t* block) const {
1201 for (auto stmt_ : block->statementOrComments.objects()) {
1202 if (auto stmt = ast_cast<Statement_t>(stmt_)) {
1203 return stmt;
1172 } 1204 }
1173 return static_cast<Statement_t*>(*it);
1174 } 1205 }
1175 return nullptr; 1206 return nullptr;
1176 } 1207 }
@@ -1179,16 +1210,26 @@ private:
1179 if (auto stmt = body->content.as<Statement_t>()) { 1210 if (auto stmt = body->content.as<Statement_t>()) {
1180 return stmt; 1211 return stmt;
1181 } else { 1212 } else {
1182 const auto& stmts = body->content.to<Block_t>()->statements.objects(); 1213 const auto& stmts = body->content.to<Block_t>()->statementOrComments.objects();
1183 return lastStatementFrom(stmts); 1214 return lastStatementFrom(stmts);
1184 } 1215 }
1185 } 1216 }
1186 1217
1187 Statement_t* lastStatementFrom(Block_t* block) const { 1218 Statement_t* lastStatementFrom(Block_t* block) const {
1188 const auto& stmts = block->statements.objects(); 1219 const auto& stmts = block->statementOrComments.objects();
1189 return lastStatementFrom(stmts); 1220 return lastStatementFrom(stmts);
1190 } 1221 }
1191 1222
1223 int countStatementFrom(Block_t* block) const {
1224 int count = 0;
1225 for (auto stmt_ : block->statementOrComments.objects()) {
1226 if (ast_is<Statement_t>(stmt_)) {
1227 count++;
1228 }
1229 }
1230 return count;
1231 }
1232
1192 Exp_t* lastExpFromAssign(ast_node* action) { 1233 Exp_t* lastExpFromAssign(ast_node* action) {
1193 switch (action->get_id()) { 1234 switch (action->get_id()) {
1194 case id<Update_t>(): { 1235 case id<Update_t>(): {
@@ -1232,7 +1273,7 @@ private:
1232 } 1273 }
1233 case id<Local_t>(): { 1274 case id<Local_t>(): {
1234 if (auto localValues = static_cast<Local_t*>(stmt->content.get())->item.as<LocalValues_t>()) { 1275 if (auto localValues = static_cast<Local_t*>(stmt->content.get())->item.as<LocalValues_t>()) {
1235 if (auto expList = localValues->valueList.as<ExpListLow_t>()) { 1276 if (auto expList = localValues->valueList.as<ExpList_t>()) {
1236 return static_cast<Exp_t*>(expList->exprs.back()); 1277 return static_cast<Exp_t*>(expList->exprs.back());
1237 } 1278 }
1238 } 1279 }
@@ -1240,7 +1281,7 @@ private:
1240 } 1281 }
1241 case id<Global_t>(): { 1282 case id<Global_t>(): {
1242 if (auto globalValues = static_cast<Global_t*>(stmt->content.get())->item.as<GlobalValues_t>()) { 1283 if (auto globalValues = static_cast<Global_t*>(stmt->content.get())->item.as<GlobalValues_t>()) {
1243 if (auto expList = globalValues->valueList.as<ExpListLow_t>()) { 1284 if (auto expList = globalValues->valueList.as<ExpList_t>()) {
1244 return static_cast<Exp_t*>(expList->exprs.back()); 1285 return static_cast<Exp_t*>(expList->exprs.back());
1245 } 1286 }
1246 } 1287 }
@@ -1252,7 +1293,7 @@ private:
1252 1293
1253 template <class T> 1294 template <class T>
1254 ast_ptr<false, T> toAst(std::string_view codes, ast_node* parent) { 1295 ast_ptr<false, T> toAst(std::string_view codes, ast_node* parent) {
1255 auto res = _parser.parse<T>(std::string(codes)); 1296 auto res = _parser.parse<T>(std::string(codes), false);
1256 if (res.error) { 1297 if (res.error) {
1257 throw CompileError(res.error.value().msg, parent); 1298 throw CompileError(res.error.value().msg, parent);
1258 } 1299 }
@@ -1275,6 +1316,8 @@ private:
1275 Common, 1316 Common,
1276 EndWithColon, 1317 EndWithColon,
1277 EndWithEOP, 1318 EndWithEOP,
1319 EndWithSlice,
1320 HasRIndex,
1278 HasEOP, 1321 HasEOP,
1279 HasKeyword, 1322 HasKeyword,
1280 HasUnicode, 1323 HasUnicode,
@@ -1293,6 +1336,9 @@ private:
1293 if (ast_is<ExistentialOp_t>(chainValue->items.back())) { 1336 if (ast_is<ExistentialOp_t>(chainValue->items.back())) {
1294 return ChainType::EndWithEOP; 1337 return ChainType::EndWithEOP;
1295 } 1338 }
1339 if (ast_is<Slice_t>(chainValue->items.back())) {
1340 return ChainType::EndWithSlice;
1341 }
1296 if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) { 1342 if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) {
1297 if (dot->name.is<Metatable_t>()) { 1343 if (dot->name.is<Metatable_t>()) {
1298 return ChainType::Metatable; 1344 return ChainType::Metatable;
@@ -1318,6 +1364,8 @@ private:
1318 } 1364 }
1319 } else if (ast_is<ExistentialOp_t>(item)) { 1365 } else if (ast_is<ExistentialOp_t>(item)) {
1320 return ChainType::HasEOP; 1366 return ChainType::HasEOP;
1367 } else if (ast_is<ReversedIndex_t>(item)) {
1368 return ChainType::HasRIndex;
1321 } 1369 }
1322 } 1370 }
1323 return type; 1371 return type;
@@ -1347,10 +1395,10 @@ private:
1347 std::ostringstream buf; 1395 std::ostringstream buf;
1348 for (auto it = uname->m_begin.m_it; it != uname->m_end.m_it; ++it) { 1396 for (auto it = uname->m_begin.m_it; it != uname->m_end.m_it; ++it) {
1349 auto ch = *it; 1397 auto ch = *it;
1350 if (ch > 255) { 1398 if (ch <= 0x7F && ((ch == '_') || ((ch | 0x20) >= 'a' && (ch | 0x20) <= 'z') || (ch >= '0' && ch <= '9'))) {
1351 buf << "_u"sv << std::hex << static_cast<int>(ch);
1352 } else {
1353 buf << static_cast<char>(ch); 1399 buf << static_cast<char>(ch);
1400 } else {
1401 buf << "_u"sv << std::hex << static_cast<uint32_t>(ch);
1354 } 1402 }
1355 } 1403 }
1356 return buf.str(); 1404 return buf.str();
@@ -1432,6 +1480,7 @@ private:
1432 case id<DotChainItem_t>(): 1480 case id<DotChainItem_t>():
1433 case id<Exp_t>(): 1481 case id<Exp_t>():
1434 case id<TableAppendingOp_t>(): 1482 case id<TableAppendingOp_t>():
1483 case id<ReversedIndex_t>():
1435 return true; 1484 return true;
1436 } 1485 }
1437 } 1486 }
@@ -1449,7 +1498,7 @@ private:
1449 if (simpleValue->value.is<TableLit_t>()) { 1498 if (simpleValue->value.is<TableLit_t>()) {
1450 return true; 1499 return true;
1451 } else if (auto comp = simpleValue->value.as<Comprehension_t>()) { 1500 } else if (auto comp = simpleValue->value.as<Comprehension_t>()) {
1452 if (comp->items.size() != 2 || !ast_is<CompInner_t>(comp->items.back())) { 1501 if (!isListComp(comp)) {
1453 return true; 1502 return true;
1454 } 1503 }
1455 } 1504 }
@@ -1581,16 +1630,26 @@ private:
1581 return !_varArgs.empty() && _varArgs.top().usedVar ? "end)(...)"s : "end)()"s; 1630 return !_varArgs.empty() && _varArgs.top().usedVar ? "end)(...)"s : "end)()"s;
1582 } 1631 }
1583 1632
1633 void markGlobalImported(const std::string& name) {
1634 if (_importedGlobal->globals.find(name) == _importedGlobal->globals.end() && !isSolidDefined(name)) {
1635 const auto& global = _importedGlobal->globalList.emplace_back(name);
1636 _importedGlobal->globals.insert(global);
1637 _importedGlobal->vars->insert_or_assign(name, VarType::LocalConst);
1638 }
1639 }
1640
1584 std::string globalVar(std::string_view var, ast_node* x, AccessType accessType) { 1641 std::string globalVar(std::string_view var, ast_node* x, AccessType accessType) {
1585 std::string str(var); 1642 std::string str(var);
1586 if (_config.lintGlobalVariable) { 1643 if (_importedGlobal) {
1644 markGlobalImported(str);
1645 } else if (_config.lintGlobalVariable) {
1587 if (!isLocal(str)) { 1646 if (!isLocal(str)) {
1588 auto key = str + ':' + std::to_string(x->m_begin.m_line) + ':' + std::to_string(x->m_begin.m_col); 1647 auto key = str + ':' + std::to_string(x->m_begin.m_line) + ':' + std::to_string(x->m_begin.m_col);
1589 if (_globals.find(key) == _globals.end()) { 1648 if (_globals.find(key) == _globals.end()) {
1590 if (accessType == AccessType::Read && _funcLevel > 1) { 1649 if (accessType == AccessType::Read && _funcLevel > 1) {
1591 accessType = AccessType::Capture; 1650 accessType = AccessType::Capture;
1592 } 1651 }
1593 _globals[key] = {str, x->m_begin.m_line, x->m_begin.m_col, accessType}; 1652 _globals[key] = {str, x->m_begin.m_line, x->m_begin.m_col, accessType, isSolidDefined(str)};
1594 } 1653 }
1595 } 1654 }
1596 } 1655 }
@@ -1632,24 +1691,31 @@ private:
1632 return; 1691 return;
1633 } 1692 }
1634 1693
1635 void transformStatement(Statement_t* statement, str_list& out) { 1694 void transformComment(YueComment_t* comment, str_list& out) {
1636 auto x = statement; 1695 if (!_config.reserveComment) {
1637 if (_config.reserveComment && !x->comments.empty()) { 1696 return;
1638 for (ast_node* node : x->comments.objects()) { 1697 }
1639 switch (node->get_id()) { 1698 auto node = comment->comment.get();
1640 case id<YueLineComment_t>(): { 1699 if (!node) {
1641 auto comment = ast_cast<YueLineComment_t>(node); 1700 out.push_back("\n"s);
1642 out.push_back(indent() + "--"s + _parser.toString(comment) + '\n'); 1701 return;
1643 break; 1702 }
1644 } 1703 switch (node->get_id()) {
1645 case id<YueMultilineComment_t>(): { 1704 case id<YueLineComment_t>(): {
1646 auto comment = ast_cast<YueMultilineComment_t>(node); 1705 auto content = static_cast<YueLineComment_t*>(node);
1647 out.push_back(indent() + _parser.toString(comment) + '\n'); 1706 out.push_back(indent() + "--"s + _parser.toString(content) + '\n');
1648 break; 1707 break;
1649 } 1708 }
1650 } 1709 case id<YueMultilineComment_t>(): {
1710 auto content = static_cast<YueMultilineComment_t*>(node);
1711 out.push_back(indent() + "--[["s + _parser.toString(content) + "]]\n"s);
1712 break;
1651 } 1713 }
1652 } 1714 }
1715 }
1716
1717 void transformStatement(Statement_t* statement, str_list& out) {
1718 auto x = statement;
1653 if (statement->appendix) { 1719 if (statement->appendix) {
1654 if (auto assignment = assignmentFrom(statement)) { 1720 if (auto assignment = assignmentFrom(statement)) {
1655 auto preDefine = getPreDefineLine(assignment); 1721 auto preDefine = getPreDefineLine(assignment);
@@ -1713,7 +1779,7 @@ private:
1713 throw CompileError("while-loop line decorator is not supported here"sv, appendix->item.get()); 1779 throw CompileError("while-loop line decorator is not supported here"sv, appendix->item.get());
1714 break; 1780 break;
1715 } 1781 }
1716 case id<CompInner_t>(): { 1782 case id<CompFor_t>(): {
1717 throw CompileError("for-loop line decorator is not supported here"sv, appendix->item.get()); 1783 throw CompileError("for-loop line decorator is not supported here"sv, appendix->item.get());
1718 break; 1784 break;
1719 } 1785 }
@@ -1774,8 +1840,8 @@ private:
1774 statement->content.set(expListAssign); 1840 statement->content.set(expListAssign);
1775 break; 1841 break;
1776 } 1842 }
1777 case id<CompInner_t>(): { 1843 case id<CompFor_t>(): {
1778 auto compInner = appendix->item.to<CompInner_t>(); 1844 auto compInner = appendix->item.to<CompFor_t>();
1779 auto comp = x->new_ptr<Comprehension_t>(); 1845 auto comp = x->new_ptr<Comprehension_t>();
1780 auto stmt = x->new_ptr<Statement_t>(); 1846 auto stmt = x->new_ptr<Statement_t>();
1781 stmt->content.set(statement->content); 1847 stmt->content.set(statement->content);
@@ -1840,11 +1906,12 @@ private:
1840 case id<ForEach_t>(): transformForEach(static_cast<ForEach_t*>(value), out); break; 1906 case id<ForEach_t>(): transformForEach(static_cast<ForEach_t*>(value), out); break;
1841 case id<For_t>(): transformFor(static_cast<For_t*>(value), out); break; 1907 case id<For_t>(): transformFor(static_cast<For_t*>(value), out); break;
1842 case id<While_t>(): transformWhile(static_cast<While_t*>(value), out); break; 1908 case id<While_t>(): transformWhile(static_cast<While_t*>(value), out); break;
1909 case id<Repeat_t>(): transformRepeat(static_cast<Repeat_t*>(value), out); break;
1843 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Common); break; 1910 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Common); break;
1844 case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Common); break; 1911 case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Common); break;
1845 case id<Comprehension_t>(): { 1912 case id<Comprehension_t>(): {
1846 auto comp = static_cast<Comprehension_t*>(value); 1913 auto comp = static_cast<Comprehension_t*>(value);
1847 if (comp->items.size() == 2 && ast_is<CompInner_t>(comp->items.back())) { 1914 if (isListComp(comp)) {
1848 transformCompCommon(comp, out); 1915 transformCompCommon(comp, out);
1849 } else { 1916 } else {
1850 specialSingleValue = false; 1917 specialSingleValue = false;
@@ -1968,7 +2035,7 @@ private:
1968 return indent() + "local "s + join(defs, ", "sv); 2035 return indent() + "local "s + join(defs, ", "sv);
1969 } 2036 }
1970 2037
1971 std::string getDestrucureDefine(ExpListAssign_t* assignment) { 2038 std::string getDestructureDefine(ExpListAssign_t* assignment) {
1972 auto info = extractDestructureInfo(assignment, true, false); 2039 auto info = extractDestructureInfo(assignment, true, false);
1973 if (!info.destructures.empty()) { 2040 if (!info.destructures.empty()) {
1974 str_list defs; 2041 str_list defs;
@@ -1999,8 +2066,31 @@ private:
1999 return clearBuf(); 2066 return clearBuf();
2000 } 2067 }
2001 2068
2069 str_list getArgDestructureList(ExpListAssign_t* assignment) {
2070 str_list defs;
2071 auto info = extractDestructureInfo(assignment, true, false);
2072 if (!info.destructures.empty()) {
2073 for (const auto& des : info.destructures) {
2074 if (std::holds_alternative<Destructure>(des)) {
2075 const auto& destruct = std::get<Destructure>(des);
2076 for (const auto& item : destruct.items) {
2077 if (item.targetVar.empty()) {
2078 throw CompileError("can only destruct argument to variable"sv, item.target);
2079 } else {
2080 defs.push_back(item.targetVar);
2081 }
2082 }
2083 } else {
2084 const auto& assignment = std::get<AssignmentPtr>(des);
2085 YUEE("AST node mismatch", assignment.ptr);
2086 }
2087 }
2088 }
2089 return defs;
2090 }
2091
2002 std::string getPreDefine(ExpListAssign_t* assignment) { 2092 std::string getPreDefine(ExpListAssign_t* assignment) {
2003 auto preDefine = getDestrucureDefine(assignment); 2093 auto preDefine = getDestructureDefine(assignment);
2004 if (preDefine.empty()) { 2094 if (preDefine.empty()) {
2005 preDefine = toLocalDecl(transformAssignDefs(assignment->expList, DefOp::Mark)); 2095 preDefine = toLocalDecl(transformAssignDefs(assignment->expList, DefOp::Mark));
2006 } 2096 }
@@ -2009,7 +2099,7 @@ private:
2009 2099
2010 std::string getPreDefineLine(ExpListAssign_t* assignment) { 2100 std::string getPreDefineLine(ExpListAssign_t* assignment) {
2011 auto preDefine = getPreDefine(assignment); 2101 auto preDefine = getPreDefine(assignment);
2012 if (!preDefine.empty()) preDefine += nll(assignment); 2102 if (!preDefine.empty()) preDefine += nl(assignment);
2013 return preDefine; 2103 return preDefine;
2014 } 2104 }
2015 2105
@@ -2051,13 +2141,16 @@ private:
2051 if (item.targetVar.empty()) { 2141 if (item.targetVar.empty()) {
2052 throw CompileError("can only declare variable as const"sv, item.target); 2142 throw CompileError("can only declare variable as const"sv, item.target);
2053 } 2143 }
2054 markVarConst(item.targetVar); 2144 markVarLocalConst(item.targetVar);
2055 } 2145 }
2056 } 2146 }
2057 } 2147 }
2058 } 2148 }
2059 2149
2060 bool transformAssignment(ExpListAssign_t* assignment, str_list& out, bool optionalDestruct = false) { 2150 bool transformAssignment(ExpListAssign_t* assignment, str_list& out, bool optionalDestruct = false) {
2151 if (assignment->action.is<SubBackcall_t>()) {
2152 YUEE("AST node mismatch", assignment->action);
2153 }
2061 checkAssignable(assignment->expList); 2154 checkAssignable(assignment->expList);
2062 BLOCK_START 2155 BLOCK_START
2063 auto assign = ast_cast<Assign_t>(assignment->action); 2156 auto assign = ast_cast<Assign_t>(assignment->action);
@@ -2162,14 +2255,14 @@ private:
2162 temp.push_back(getPreDefineLine(assignment)); 2255 temp.push_back(getPreDefineLine(assignment));
2163 bool needScope = !currentScope().lastStatement; 2256 bool needScope = !currentScope().lastStatement;
2164 if (needScope) { 2257 if (needScope) {
2165 temp.push_back(indent() + "do"s + nll(assignment)); 2258 temp.push_back(indent() + "do"s + nl(assignment));
2166 pushScope(); 2259 pushScope();
2167 } 2260 }
2168 transformAssignment(preAssignment, temp); 2261 transformAssignment(preAssignment, temp);
2169 transformAssignment(assignment, temp); 2262 transformAssignment(assignment, temp);
2170 if (needScope) { 2263 if (needScope) {
2171 popScope(); 2264 popScope();
2172 temp.push_back(indent() + "end"s + nll(assignment)); 2265 temp.push_back(indent() + "end"s + nl(assignment));
2173 } 2266 }
2174 out.push_back(join(temp)); 2267 out.push_back(join(temp));
2175 return false; 2268 return false;
@@ -2214,7 +2307,8 @@ private:
2214 BREAK_IF(!value); 2307 BREAK_IF(!value);
2215 auto chainValue = value->item.as<ChainValue_t>(); 2308 auto chainValue = value->item.as<ChainValue_t>();
2216 BREAK_IF(!chainValue); 2309 BREAK_IF(!chainValue);
2217 if (auto dot = ast_cast<DotChainItem_t>(chainValue->items.back())) { 2310 auto last = chainValue->items.back();
2311 if (auto dot = ast_cast<DotChainItem_t>(last)) {
2218 BREAK_IF(!dot->name.is<Metatable_t>()); 2312 BREAK_IF(!dot->name.is<Metatable_t>());
2219 str_list temp; 2313 str_list temp;
2220 auto [beforeAssignment, afterAssignment] = splitAssignment(); 2314 auto [beforeAssignment, afterAssignment] = splitAssignment();
@@ -2238,14 +2332,14 @@ private:
2238 throw CompileError("right value missing"sv, values.front()); 2332 throw CompileError("right value missing"sv, values.front());
2239 } 2333 }
2240 transformAssignItem(*vit, args); 2334 transformAssignItem(*vit, args);
2241 _buf << indent() << globalVar("setmetatable"sv, x, AccessType::Read) << '(' << join(args, ", "sv) << ')' << nll(x); 2335 _buf << indent() << globalVar("setmetatable"sv, x, AccessType::Read) << '(' << join(args, ", "sv) << ')' << nl(x);
2242 temp.push_back(clearBuf()); 2336 temp.push_back(clearBuf());
2243 if (!afterAssignment->expList->exprs.empty()) { 2337 if (!afterAssignment->expList->exprs.empty()) {
2244 transformAssignment(afterAssignment, temp); 2338 transformAssignment(afterAssignment, temp);
2245 } 2339 }
2246 out.push_back(join(temp)); 2340 out.push_back(join(temp));
2247 return false; 2341 return false;
2248 } else if (ast_is<TableAppendingOp_t>(chainValue->items.back())) { 2342 } else if (ast_is<TableAppendingOp_t>(last)) {
2249 str_list temp; 2343 str_list temp;
2250 auto [beforeAssignment, afterAssignment] = splitAssignment(); 2344 auto [beforeAssignment, afterAssignment] = splitAssignment();
2251 if (!beforeAssignment->expList->exprs.empty()) { 2345 if (!beforeAssignment->expList->exprs.empty()) {
@@ -2267,7 +2361,7 @@ private:
2267 if (varName.empty() || !isLocal(varName)) { 2361 if (varName.empty() || !isLocal(varName)) {
2268 if (needScope) { 2362 if (needScope) {
2269 extraScoped = true; 2363 extraScoped = true;
2270 temp.push_back(indent() + "do"s + nll(x)); 2364 temp.push_back(indent() + "do"s + nl(x));
2271 pushScope(); 2365 pushScope();
2272 } 2366 }
2273 auto objVar = getUnusedName("_obj_"sv); 2367 auto objVar = getUnusedName("_obj_"sv);
@@ -2279,24 +2373,74 @@ private:
2279 transformAssignment(newAssignment, temp); 2373 transformAssignment(newAssignment, temp);
2280 varName = objVar; 2374 varName = objVar;
2281 } 2375 }
2282 auto newAssignment = x->new_ptr<ExpListAssign_t>(); 2376 if (auto spread = ast_cast<SpreadListExp_t>(*vit)) {
2283 newAssignment->expList.set(toAst<ExpList_t>(varName + "[#"s + varName + "+1]"s, x)); 2377 auto lenVar = getUnusedName("_len_"sv);
2284 auto assign = x->new_ptr<Assign_t>(); 2378 forceAddToScope(lenVar);
2285 if (vit == values.end()) { 2379 temp.push_back(indent() + "local "s + lenVar + " = #"s + varName + " + 1"s + nl(spread));
2286 throw CompileError("right value missing"sv, values.front()); 2380 auto elmVar = getUnusedName("_elm_"sv);
2381 _buf << varName << '[' << lenVar << "],"s << lenVar << "="s << elmVar << ',' << lenVar << "+1 for "s << elmVar << " in *nil"s;
2382 auto stmt = toAst<Statement_t>(clearBuf(), spread);
2383 auto comp = stmt->appendix->item.to<CompFor_t>();
2384 ast_to<CompForEach_t>(comp->items.front())->loopValue.to<StarExp_t>()->value.set(spread->exp);
2385 transformStatement(stmt, temp);
2386 } else {
2387 auto newAssignment = x->new_ptr<ExpListAssign_t>();
2388 newAssignment->expList.set(toAst<ExpList_t>(varName + "[#"s + varName + "+1]"s, x));
2389 auto assign = x->new_ptr<Assign_t>();
2390 if (vit == values.end()) {
2391 throw CompileError("right value missing"sv, values.front());
2392 }
2393 assign->values.push_back(*vit);
2394 newAssignment->action.set(assign);
2395 transformAssignment(newAssignment, temp);
2287 } 2396 }
2288 assign->values.push_back(*vit);
2289 newAssignment->action.set(assign);
2290 transformAssignment(newAssignment, temp);
2291 if (extraScoped) { 2397 if (extraScoped) {
2292 popScope(); 2398 popScope();
2293 temp.push_back(indent() + "end"s + nlr(x)); 2399 temp.push_back(indent() + "end"s + nl(x));
2294 } 2400 }
2295 if (!afterAssignment->expList->exprs.empty()) { 2401 if (!afterAssignment->expList->exprs.empty()) {
2296 transformAssignment(afterAssignment, temp); 2402 transformAssignment(afterAssignment, temp);
2297 } 2403 }
2298 out.push_back(join(temp)); 2404 out.push_back(join(temp));
2299 return false; 2405 return false;
2406 } else if (ast_is<ReversedIndex_t>(last)) {
2407 if (chainValue->items.size() == 1) {
2408 if (_withVars.empty()) {
2409 throw CompileError("short dot/colon syntax must be called within a with block"sv, x);
2410 } else {
2411 break;
2412 }
2413 }
2414 auto tmpChain = chainValue->new_ptr<ChainValue_t>();
2415 tmpChain->items.dup(chainValue->items);
2416 tmpChain->items.pop_back();
2417 auto tmpLeft = newExp(tmpChain, tmpChain);
2418 auto leftVar = singleVariableFrom(tmpLeft, AccessType::Read);
2419 if (!leftVar.empty() && isLocal(leftVar)) {
2420 break;
2421 }
2422 leftVar = getUnusedName("_obj_"sv);
2423 auto tmpAsmt = assignmentFrom(toAst<Exp_t>(leftVar, tmpLeft), tmpLeft, tmpLeft);
2424 str_list temp;
2425 transformAssignment(tmpAsmt, temp);
2426 auto [beforeAssignment, afterAssignment] = splitAssignment();
2427 if (!beforeAssignment->expList->exprs.empty()) {
2428 transformAssignment(beforeAssignment, temp);
2429 }
2430 if (vit == values.end()) {
2431 throw CompileError("right value missing"sv, values.front());
2432 }
2433 auto newChain = chainValue->new_ptr<ChainValue_t>();
2434 newChain->items.push_back(toAst<Callable_t>(leftVar, newChain));
2435 newChain->items.push_back(chainValue->items.back());
2436 auto newLeft = newExp(newChain, newChain);
2437 auto newAsmt = assignmentFrom(newLeft, *vit, newLeft);
2438 transformAssignment(newAsmt, temp);
2439 if (!afterAssignment->expList->exprs.empty()) {
2440 transformAssignment(afterAssignment, temp);
2441 }
2442 out.push_back(join(temp));
2443 return false;
2300 } else { 2444 } else {
2301 break; 2445 break;
2302 } 2446 }
@@ -2320,6 +2464,17 @@ private:
2320 out.back().insert(0, preDefine); 2464 out.back().insert(0, preDefine);
2321 return false; 2465 return false;
2322 } 2466 }
2467 case id<Try_t>(): {
2468 auto tryNode = static_cast<Try_t*>(value);
2469 if (tryNode->eop) {
2470 auto assignList = assignment->expList.get();
2471 std::string preDefine = getPreDefineLine(assignment);
2472 transformTry(tryNode, out, ExpUsage::Assignment, assignList);
2473 out.back().insert(0, preDefine);
2474 return false;
2475 }
2476 break;
2477 }
2323 case id<Switch_t>(): { 2478 case id<Switch_t>(): {
2324 auto switchNode = static_cast<Switch_t*>(value); 2479 auto switchNode = static_cast<Switch_t*>(value);
2325 auto assignList = assignment->expList.get(); 2480 auto assignList = assignment->expList.get();
@@ -2347,7 +2502,7 @@ private:
2347 case id<Comprehension_t>(): { 2502 case id<Comprehension_t>(): {
2348 auto comp = static_cast<Comprehension_t*>(value); 2503 auto comp = static_cast<Comprehension_t*>(value);
2349 auto expList = assignment->expList.get(); 2504 auto expList = assignment->expList.get();
2350 if (comp->items.size() == 2 && ast_is<CompInner_t>(comp->items.back())) { 2505 if (isListComp(comp)) {
2351 std::string preDefine = getPreDefineLine(assignment); 2506 std::string preDefine = getPreDefineLine(assignment);
2352 transformComprehension(comp, out, ExpUsage::Assignment, expList); 2507 transformComprehension(comp, out, ExpUsage::Assignment, expList);
2353 out.back().insert(0, preDefine); 2508 out.back().insert(0, preDefine);
@@ -2391,6 +2546,13 @@ private:
2391 out.back().insert(0, preDefine); 2546 out.back().insert(0, preDefine);
2392 return false; 2547 return false;
2393 } 2548 }
2549 case id<Repeat_t>(): {
2550 auto expList = assignment->expList.get();
2551 std::string preDefine = getPreDefineLine(assignment);
2552 transformRepeatInPlace(static_cast<Repeat_t*>(value), out, expList);
2553 out.back().insert(0, preDefine);
2554 return false;
2555 }
2394 case id<TableLit_t>(): { 2556 case id<TableLit_t>(): {
2395 auto tableLit = static_cast<TableLit_t*>(value); 2557 auto tableLit = static_cast<TableLit_t*>(value);
2396 if (hasSpreadExp(tableLit->values.objects())) { 2558 if (hasSpreadExp(tableLit->values.objects())) {
@@ -2443,12 +2605,14 @@ private:
2443 switch (type) { 2605 switch (type) {
2444 case ChainType::HasEOP: 2606 case ChainType::HasEOP:
2445 case ChainType::EndWithColon: 2607 case ChainType::EndWithColon:
2608 case ChainType::EndWithSlice:
2446 case ChainType::MetaFieldInvocation: { 2609 case ChainType::MetaFieldInvocation: {
2447 std::string preDefine = getPreDefineLine(assignment); 2610 std::string preDefine = getPreDefineLine(assignment);
2448 transformChainValue(chainValue, out, ExpUsage::Assignment, expList, false, optionalDestruct); 2611 transformChainValue(chainValue, out, ExpUsage::Assignment, expList, false, optionalDestruct);
2449 out.back().insert(0, preDefine); 2612 out.back().insert(0, preDefine);
2450 return false; 2613 return false;
2451 } 2614 }
2615 case ChainType::HasRIndex:
2452 case ChainType::HasKeyword: 2616 case ChainType::HasKeyword:
2453 case ChainType::HasUnicode: 2617 case ChainType::HasUnicode:
2454 case ChainType::Macro: 2618 case ChainType::Macro:
@@ -2464,6 +2628,10 @@ private:
2464 auto info = extractDestructureInfo(assignment, false, optionalDestruct); 2628 auto info = extractDestructureInfo(assignment, false, optionalDestruct);
2465 if (info.destructures.empty()) { 2629 if (info.destructures.empty()) {
2466 transformAssignmentCommon(assignment, out); 2630 transformAssignmentCommon(assignment, out);
2631 if (assignment->expList->followStmt) {
2632 transformStatement(assignment->expList->followStmt, out);
2633 assignment->expList->followStmtProcessed = true;
2634 }
2467 return true; 2635 return true;
2468 } else { 2636 } else {
2469 auto x = assignment; 2637 auto x = assignment;
@@ -2499,11 +2667,11 @@ private:
2499 checkConst(def, x); 2667 checkConst(def, x);
2500 addToScope(def); 2668 addToScope(def);
2501 } 2669 }
2502 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nll(x)); 2670 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nl(x));
2503 } 2671 }
2504 if (needScope) { 2672 if (needScope) {
2505 extraScope = true; 2673 extraScope = true;
2506 temp.push_back(indent() + "do"s + nll(x)); 2674 temp.push_back(indent() + "do"s + nl(x));
2507 pushScope(); 2675 pushScope();
2508 } 2676 }
2509 } 2677 }
@@ -2555,13 +2723,13 @@ private:
2555 continue; 2723 continue;
2556 } 2724 }
2557 if (extraScope) { 2725 if (extraScope) {
2558 temp.push_back(indent() + "do"s + nll(x)); 2726 temp.push_back(indent() + "do"s + nl(x));
2559 pushScope(); 2727 pushScope();
2560 } 2728 }
2561 if (!pair.targetVar.empty()) { 2729 if (!pair.targetVar.empty()) {
2562 checkConst(pair.targetVar, x); 2730 checkConst(pair.targetVar, x);
2563 if (addToScope(pair.targetVar)) { 2731 if (addToScope(pair.targetVar)) {
2564 _buf << indent() << "local "sv << pair.targetVar << nll(x); 2732 _buf << indent() << "local "sv << pair.targetVar << nl(x);
2565 temp.push_back(clearBuf()); 2733 temp.push_back(clearBuf());
2566 } 2734 }
2567 } 2735 }
@@ -2571,7 +2739,7 @@ private:
2571 objVar = destruct.valueVar; 2739 objVar = destruct.valueVar;
2572 } else { 2740 } else {
2573 if (needScope) { 2741 if (needScope) {
2574 temp.push_back(indent() + "do"s + nll(x)); 2742 temp.push_back(indent() + "do"s + nl(x));
2575 pushScope(); 2743 pushScope();
2576 } 2744 }
2577 objVar = getUnusedName("_obj_"sv); 2745 objVar = getUnusedName("_obj_"sv);
@@ -2587,7 +2755,7 @@ private:
2587 if (!isLocalValue) { 2755 if (!isLocalValue) {
2588 if (needScope) { 2756 if (needScope) {
2589 popScope(); 2757 popScope();
2590 _buf << indent() << "end"sv << nlr(x); 2758 _buf << indent() << "end"sv << nl(x);
2591 temp.push_back(clearBuf()); 2759 temp.push_back(clearBuf());
2592 } 2760 }
2593 } 2761 }
@@ -2625,9 +2793,9 @@ private:
2625 checkConst(def, x); 2793 checkConst(def, x);
2626 addToScope(def); 2794 addToScope(def);
2627 } 2795 }
2628 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nll(x)); 2796 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nl(x));
2629 } 2797 }
2630 temp.push_back(indent() + "do"s + nll(x)); 2798 temp.push_back(indent() + "do"s + nl(x));
2631 pushScope(); 2799 pushScope();
2632 } 2800 }
2633 } else { 2801 } else {
@@ -2636,11 +2804,11 @@ private:
2636 checkConst(def, x); 2804 checkConst(def, x);
2637 addToScope(def); 2805 addToScope(def);
2638 } 2806 }
2639 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nll(x)); 2807 temp.push_back(indent() + "local "s + join(defs, ", "sv) + nl(x));
2640 } 2808 }
2641 if (needScope) { 2809 if (needScope) {
2642 extraScope = true; 2810 extraScope = true;
2643 temp.push_back(indent() + "do"s + nll(x)); 2811 temp.push_back(indent() + "do"s + nl(x));
2644 pushScope(); 2812 pushScope();
2645 } 2813 }
2646 auto valVar = getUnusedName("_obj_"sv); 2814 auto valVar = getUnusedName("_obj_"sv);
@@ -2655,7 +2823,7 @@ private:
2655 if (destruct.inlineAssignment) { 2823 if (destruct.inlineAssignment) {
2656 if (needScope && !extraScope) { 2824 if (needScope && !extraScope) {
2657 extraScope = true; 2825 extraScope = true;
2658 temp.push_back(indent() + "do"s + nll(x)); 2826 temp.push_back(indent() + "do"s + nl(x));
2659 pushScope(); 2827 pushScope();
2660 } 2828 }
2661 transformAssignment(destruct.inlineAssignment, temp); 2829 transformAssignment(destruct.inlineAssignment, temp);
@@ -2720,17 +2888,21 @@ private:
2720 } 2888 }
2721 if (extraScope) { 2889 if (extraScope) {
2722 popScope(); 2890 popScope();
2723 _buf << indent() << "end"sv << nlr(x); 2891 _buf << indent() << "end"sv << nl(x);
2724 temp.push_back(clearBuf()); 2892 temp.push_back(clearBuf());
2725 } 2893 }
2726 } 2894 }
2727 if (extraScope) { 2895 if (extraScope) {
2728 popScope(); 2896 popScope();
2729 temp.push_back(indent() + "end"s + nlr(x)); 2897 temp.push_back(indent() + "end"s + nl(x));
2730 } 2898 }
2731 out.push_back(join(temp)); 2899 out.push_back(join(temp));
2900 if (assignment->expList->followStmt) {
2901 transformStatement(assignment->expList->followStmt, out);
2902 assignment->expList->followStmtProcessed = true;
2903 }
2904 return false;
2732 } 2905 }
2733 return false;
2734 } 2906 }
2735 2907
2736 void transformAssignItem(ast_node* value, str_list& out) { 2908 void transformAssignItem(ast_node* value, str_list& out) {
@@ -2740,6 +2912,7 @@ private:
2740 case id<Switch_t>(): transformSwitch(static_cast<Switch_t*>(value), out, ExpUsage::Closure); break; 2912 case id<Switch_t>(): transformSwitch(static_cast<Switch_t*>(value), out, ExpUsage::Closure); break;
2741 case id<TableBlock_t>(): transformTableBlock(static_cast<TableBlock_t*>(value), out); break; 2913 case id<TableBlock_t>(): transformTableBlock(static_cast<TableBlock_t*>(value), out); break;
2742 case id<Exp_t>(): transformExp(static_cast<Exp_t*>(value), out, ExpUsage::Closure); break; 2914 case id<Exp_t>(): transformExp(static_cast<Exp_t*>(value), out, ExpUsage::Closure); break;
2915 case id<SpreadListExp_t>(): throw CompileError("can only be used for ranged table append assignments"sv, value); break;
2743 default: YUEE("AST node mismatch", value); break; 2916 default: YUEE("AST node mismatch", value); break;
2744 } 2917 }
2745 } 2918 }
@@ -2754,7 +2927,7 @@ private:
2754 if (auto tbA = item->get_by_path<TableLit_t>()) { 2927 if (auto tbA = item->get_by_path<TableLit_t>()) {
2755 tableItems = &tbA->values.objects(); 2928 tableItems = &tbA->values.objects();
2756 } else if (auto tbB = item->get_by_path<Comprehension_t>()) { 2929 } else if (auto tbB = item->get_by_path<Comprehension_t>()) {
2757 if (tbB->items.size() == 2 && ast_is<CompInner_t>(tbB->items.back())) { 2930 if (isListComp(tbB)) {
2758 throw CompileError("invalid destructure value"sv, tbB); 2931 throw CompileError("invalid destructure value"sv, tbB);
2759 } 2932 }
2760 tableItems = &tbB->items.objects(); 2933 tableItems = &tbB->items.objects();
@@ -2785,7 +2958,7 @@ private:
2785 } 2958 }
2786 case id<Comprehension_t>(): { 2959 case id<Comprehension_t>(): {
2787 auto table = static_cast<Comprehension_t*>(node); 2960 auto table = static_cast<Comprehension_t*>(node);
2788 if (table->items.size() == 2 && ast_is<CompInner_t>(table->items.back())) { 2961 if (isListComp(table)) {
2789 throw CompileError("invalid destructure value"sv, table); 2962 throw CompileError("invalid destructure value"sv, table);
2790 } 2963 }
2791 tableItems = &table->items.objects(); 2964 tableItems = &table->items.objects();
@@ -2796,20 +2969,46 @@ private:
2796 if (!tableItems) throw CompileError("invalid destructure value"sv, node); 2969 if (!tableItems) throw CompileError("invalid destructure value"sv, node);
2797 std::list<DestructItem> pairs; 2970 std::list<DestructItem> pairs;
2798 int index = 0; 2971 int index = 0;
2972 int count = 0;
2973 bool hasSpread = false;
2799 auto subMetaDestruct = node->new_ptr<TableLit_t>(); 2974 auto subMetaDestruct = node->new_ptr<TableLit_t>();
2800 for (auto pair : *tableItems) { 2975 for (auto pair : *tableItems) {
2801 switch (pair->get_id()) { 2976 switch (pair->get_id()) {
2802 case id<Exp_t>(): 2977 case id<Exp_t>():
2803 case id<NormalDef_t>(): { 2978 case id<NormalDef_t>(): {
2979 ++index;
2804 Exp_t* defVal = nullptr; 2980 Exp_t* defVal = nullptr;
2805 if (auto nd = ast_cast<NormalDef_t>(pair)) { 2981 if (auto nd = ast_cast<NormalDef_t>(pair)) {
2806 pair = nd->item.get(); 2982 pair = nd->item.get();
2807 defVal = nd->defVal.get(); 2983 defVal = nd->defVal.get();
2808 } 2984 }
2809 ++index; 2985 bool assignable = false;
2810 if (!varDefOnly && !isAssignable(static_cast<Exp_t*>(pair))) { 2986 try {
2987 assignable = isAssignable(static_cast<Exp_t*>(pair));
2988 } catch (const CompileError& e) {
2989 if (!varDefOnly) throw e;
2990 }
2991 if (!assignable && !varDefOnly) {
2992 if (optional) break;
2811 throw CompileError("can't destructure value"sv, pair); 2993 throw CompileError("can't destructure value"sv, pair);
2812 } 2994 }
2995 ast_ptr<true, ast_node> indexItem;
2996 if (hasSpread) {
2997 int rIndex = count - index;
2998 indexItem.set(toAst<ReversedIndex_t>('#' + (rIndex == 0 ? Empty : "-"s + std::to_string(rIndex)), pair));
2999 } else {
3000 indexItem.set(toAst<Exp_t>(std::to_string(index), pair));
3001 }
3002 if (optional && varDefOnly && !assignable) {
3003 if (defVal) {
3004 throw CompileError("default value is not supported here"sv, defVal);
3005 }
3006 auto exp = static_cast<Exp_t*>(pair);
3007 auto chain = exp->new_ptr<ChainValue_t>();
3008 chain->items.push_back(indexItem);
3009 pairs.push_back({exp, Empty, chain, nullptr});
3010 break;
3011 }
2813 auto value = singleValueFrom(pair); 3012 auto value = singleValueFrom(pair);
2814 auto item = value->item.get(); 3013 auto item = value->item.get();
2815 ast_node* subExp = ast_cast<SimpleTable_t>(item); 3014 ast_node* subExp = ast_cast<SimpleTable_t>(item);
@@ -2820,7 +3019,6 @@ private:
2820 throw CompileError("default value is not supported here"sv, defVal); 3019 throw CompileError("default value is not supported here"sv, defVal);
2821 } 3020 }
2822 } 3021 }
2823 auto indexItem = toAst<Exp_t>(std::to_string(index), value);
2824 for (auto& p : subPairs) { 3022 for (auto& p : subPairs) {
2825 if (sep) p.structure->items.push_front(sep); 3023 if (sep) p.structure->items.push_front(sep);
2826 p.structure->items.push_front(indexItem); 3024 p.structure->items.push_front(indexItem);
@@ -2831,7 +3029,6 @@ private:
2831 auto varName = singleVariableFrom(exp, AccessType::None); 3029 auto varName = singleVariableFrom(exp, AccessType::None);
2832 if (varName == "_"sv) break; 3030 if (varName == "_"sv) break;
2833 auto chain = exp->new_ptr<ChainValue_t>(); 3031 auto chain = exp->new_ptr<ChainValue_t>();
2834 auto indexItem = toAst<Exp_t>(std::to_string(index), exp);
2835 chain->items.push_back(indexItem); 3032 chain->items.push_back(indexItem);
2836 pairs.push_back({exp, 3033 pairs.push_back({exp,
2837 varName, 3034 varName,
@@ -2889,7 +3086,25 @@ private:
2889 } 3086 }
2890 } 3087 }
2891 if (auto exp = np->value.as<Exp_t>()) { 3088 if (auto exp = np->value.as<Exp_t>()) {
2892 if (!varDefOnly && !isAssignable(exp)) throw CompileError("can't do destructure value"sv, exp); 3089 bool assignable = false;
3090 try {
3091 assignable = isAssignable(exp);
3092 } catch (const CompileError& e) {
3093 if (!varDefOnly) throw e;
3094 }
3095 if (!assignable && !varDefOnly) {
3096 if (optional) break;
3097 throw CompileError("can't destructure value"sv, pair);
3098 }
3099 if (optional && varDefOnly && !assignable) {
3100 if (defVal) {
3101 throw CompileError("default value is not supported here"sv, defVal);
3102 }
3103 auto chain = exp->new_ptr<ChainValue_t>();
3104 if (keyIndex) chain->items.push_back(keyIndex);
3105 pairs.push_back({exp, Empty, chain, nullptr});
3106 break;
3107 }
2893 auto item = singleValueFrom(exp)->item.get(); 3108 auto item = singleValueFrom(exp)->item.get();
2894 ast_node* subExp = ast_cast<SimpleTable_t>(item); 3109 ast_node* subExp = ast_cast<SimpleTable_t>(item);
2895 if (subExp || (subExp = item->get_by_path<TableLit_t>()) || (subExp = item->get_by_path<Comprehension_t>())) { 3110 if (subExp || (subExp = item->get_by_path<TableLit_t>()) || (subExp = item->get_by_path<Comprehension_t>())) {
@@ -2938,7 +3153,13 @@ private:
2938 auto tb = static_cast<TableBlockIndent_t*>(pair); 3153 auto tb = static_cast<TableBlockIndent_t*>(pair);
2939 ++index; 3154 ++index;
2940 auto subPairs = destructFromExp(tb, varDefOnly, optional); 3155 auto subPairs = destructFromExp(tb, varDefOnly, optional);
2941 auto indexItem = toAst<Exp_t>(std::to_string(index), tb); 3156 ast_ptr<true, ast_node> indexItem;
3157 if (hasSpread) {
3158 int rIndex = count - index;
3159 indexItem.set(toAst<ReversedIndex_t>('#' + (rIndex == 0 ? Empty : "-"s + std::to_string(rIndex)), tb));
3160 } else {
3161 indexItem.set(toAst<Exp_t>(std::to_string(index), tb));
3162 }
2942 for (auto& p : subPairs) { 3163 for (auto& p : subPairs) {
2943 if (sep) p.structure->items.push_front(sep); 3164 if (sep) p.structure->items.push_front(sep);
2944 p.structure->items.push_front(indexItem); 3165 p.structure->items.push_front(indexItem);
@@ -2995,6 +3216,42 @@ private:
2995 subMetaDestruct->values.push_back(newPairDef); 3216 subMetaDestruct->values.push_back(newPairDef);
2996 break; 3217 break;
2997 } 3218 }
3219 case id<SpreadListExp_t>():
3220 case id<SpreadExp_t>(): {
3221 ++index;
3222 if (hasSpread) {
3223 throw CompileError("duplicated spread expression"sv, pair);
3224 }
3225 hasSpread = true;
3226 for (auto item : *tableItems) {
3227 if (ast_is<
3228 SpreadListExp_t, SpreadExp_t,
3229 TableBlockIndent_t,
3230 Exp_t, NormalDef_t>(item)) {
3231 count++;
3232 }
3233 }
3234 Exp_t* exp = nullptr;
3235 if (auto se = ast_cast<SpreadExp_t>(pair)) {
3236 exp = se->exp.get();
3237 } else {
3238 exp = ast_to<SpreadListExp_t>(pair)->exp.get();
3239 }
3240 auto varName = singleVariableFrom(exp, AccessType::None);
3241 if (varName == "_"sv) break;
3242 int start = index;
3243 int stop = index - count - 1;
3244 auto chain = exp->new_ptr<ChainValue_t>();
3245 auto slice = toAst<Slice_t>(
3246 '[' + (start == 1 ? Empty : std::to_string(start)) + ',' + (stop == -1 ? Empty : std::to_string(stop)) + ']', exp);
3247 chain->items.push_back(slice);
3248 auto nil = toAst<Exp_t>("nil"sv, slice);
3249 pairs.push_back({exp,
3250 varName,
3251 chain,
3252 nil.get()});
3253 break;
3254 }
2998 default: YUEE("AST node mismatch", pair); break; 3255 default: YUEE("AST node mismatch", pair); break;
2999 } 3256 }
3000 } 3257 }
@@ -3072,7 +3329,7 @@ private:
3072 if (auto tab = sVal->value.as<TableLit_t>()) { 3329 if (auto tab = sVal->value.as<TableLit_t>()) {
3073 destructNode = tab; 3330 destructNode = tab;
3074 } else if (auto comp = sVal->value.as<Comprehension_t>()) { 3331 } else if (auto comp = sVal->value.as<Comprehension_t>()) {
3075 if (comp->items.size() != 2 || !ast_is<CompInner_t>(comp->items.back())) { 3332 if (!isListComp(comp)) {
3076 destructNode = comp; 3333 destructNode = comp;
3077 } 3334 }
3078 } 3335 }
@@ -3111,7 +3368,11 @@ private:
3111 break; 3368 break;
3112 default: YUEE("AST node mismatch", destructNode); break; 3369 default: YUEE("AST node mismatch", destructNode); break;
3113 } 3370 }
3114 if (dlist->empty()) throw CompileError("expect items to be destructured"sv, destructNode); 3371 if (dlist->empty()) {
3372 if (!optional) {
3373 throw CompileError("expect items to be destructured"sv, destructNode);
3374 }
3375 }
3115 for (auto item : *dlist) { 3376 for (auto item : *dlist) {
3116 switch (item->get_id()) { 3377 switch (item->get_id()) {
3117 case id<MetaVariablePairDef_t>(): { 3378 case id<MetaVariablePairDef_t>(): {
@@ -3247,7 +3508,9 @@ private:
3247 simpleValue->value.set(tab); 3508 simpleValue->value.set(tab);
3248 auto pairs = destructFromExp(newExp(simpleValue, expr), varDefOnly, optional); 3509 auto pairs = destructFromExp(newExp(simpleValue, expr), varDefOnly, optional);
3249 if (pairs.empty()) { 3510 if (pairs.empty()) {
3250 throw CompileError("expect items to be destructured"sv, tab); 3511 if (!optional) {
3512 throw CompileError("expect items to be destructured"sv, tab);
3513 }
3251 } 3514 }
3252 destruct.items = std::move(pairs); 3515 destruct.items = std::move(pairs);
3253 if (!varDefOnly) { 3516 if (!varDefOnly) {
@@ -3286,7 +3549,7 @@ private:
3286 destruct.valueVar.clear(); 3549 destruct.valueVar.clear();
3287 } 3550 }
3288 } 3551 }
3289 destructs.push_back(destruct); 3552 destructs.push_back(std::move(destruct));
3290 } 3553 }
3291 } 3554 }
3292 } else { 3555 } else {
@@ -3453,7 +3716,7 @@ private:
3453 _buf << defs; 3716 _buf << defs;
3454 else 3717 else
3455 _buf << indent() << left; 3718 _buf << indent() << left;
3456 _buf << " = "sv << left << ' ' << op << ' ' << right << nll(assignment); 3719 _buf << " = "sv << left << ' ' << op << ' ' << right << nl(assignment);
3457 out.push_back(clearBuf()); 3720 out.push_back(clearBuf());
3458 break; 3721 break;
3459 } 3722 }
@@ -3463,7 +3726,7 @@ private:
3463 bool oneLined = defs.size() == expList->exprs.objects().size(); 3726 bool oneLined = defs.size() == expList->exprs.objects().size();
3464 bool nonRecursionFunLit = false; 3727 bool nonRecursionFunLit = false;
3465 for (auto val : assign->values.objects()) { 3728 for (auto val : assign->values.objects()) {
3466 if (auto value = singleValueFrom(val)) { 3729 if (auto value = singleValueFrom(val, true)) {
3467 if (auto spValue = value->item.as<SimpleValue_t>()) { 3730 if (auto spValue = value->item.as<SimpleValue_t>()) {
3468 if (auto funLit = spValue->value.as<FunLit_t>()) { 3731 if (auto funLit = spValue->value.as<FunLit_t>()) {
3469 if (funLit->noRecursion) { 3732 if (funLit->noRecursion) {
@@ -3500,9 +3763,9 @@ private:
3500 transformExpList(expList, temp); 3763 transformExpList(expList, temp);
3501 std::string left = std::move(temp.back()); 3764 std::string left = std::move(temp.back());
3502 temp.pop_back(); 3765 temp.pop_back();
3503 out.push_back(indent() + left + " = "s + join(temp, ", "sv) + nll(assignment)); 3766 out.push_back(indent() + left + " = "s + join(temp, ", "sv) + nl(assignment));
3504 } else { 3767 } else {
3505 out.push_back(preDefine + " = "s + join(temp, ", "sv) + nll(assignment)); 3768 out.push_back(preDefine + " = "s + join(temp, ", "sv) + nl(assignment));
3506 } 3769 }
3507 } else { 3770 } else {
3508 std::string preDefine = toLocalDecl(defs); 3771 std::string preDefine = toLocalDecl(defs);
@@ -3518,7 +3781,7 @@ private:
3518 for (auto value : assign->values.objects()) { 3781 for (auto value : assign->values.objects()) {
3519 transformAssignItem(value, temp); 3782 transformAssignItem(value, temp);
3520 } 3783 }
3521 out.push_back((preDefine.empty() ? Empty : preDefine + nll(assignment)) + indent() + left + " = "s + join(temp, ", "sv) + nll(assignment)); 3784 out.push_back((preDefine.empty() ? Empty : preDefine + nl(assignment)) + indent() + left + " = "s + join(temp, ", "sv) + nl(assignment));
3522 } 3785 }
3523 break; 3786 break;
3524 } 3787 }
@@ -3619,7 +3882,7 @@ private:
3619 if (usage != ExpUsage::Closure) { 3882 if (usage != ExpUsage::Closure) {
3620 if (!currentScope().lastStatement) { 3883 if (!currentScope().lastStatement) {
3621 extraScope = true; 3884 extraScope = true;
3622 temp.push_back(indent() + "do"s + nll(asmt)); 3885 temp.push_back(indent() + "do"s + nl(asmt));
3623 pushScope(); 3886 pushScope();
3624 } 3887 }
3625 } 3888 }
@@ -3652,7 +3915,7 @@ private:
3652 if (usage != ExpUsage::Closure) { 3915 if (usage != ExpUsage::Closure) {
3653 if (!currentScope().lastStatement) { 3916 if (!currentScope().lastStatement) {
3654 extraScope = true; 3917 extraScope = true;
3655 temp.push_back(indent() + "do"s + nll(asmt)); 3918 temp.push_back(indent() + "do"s + nl(asmt));
3656 pushScope(); 3919 pushScope();
3657 } 3920 }
3658 } 3921 }
@@ -3681,12 +3944,12 @@ private:
3681 if (pair != ifCondPairs.front()) { 3944 if (pair != ifCondPairs.front()) {
3682 _buf << "else"sv; 3945 _buf << "else"sv;
3683 } 3946 }
3684 _buf << "if "sv << condStr << " then"sv << nll(condition); 3947 _buf << "if "sv << condStr << " then"sv << nl(condition);
3685 temp.push_back(clearBuf()); 3948 temp.push_back(clearBuf());
3686 } 3949 }
3687 if (pair.second) { 3950 if (pair.second) {
3688 if (!pair.first) { 3951 if (!pair.first) {
3689 temp.push_back(indent() + "else"s + nll(pair.second)); 3952 temp.push_back(indent() + "else"s + nl(pair.second));
3690 } 3953 }
3691 pushScope(); 3954 pushScope();
3692 if (pair == ifCondPairs.front() && extraAssignment) { 3955 if (pair == ifCondPairs.front() && extraAssignment) {
@@ -3696,17 +3959,17 @@ private:
3696 popScope(); 3959 popScope();
3697 } 3960 }
3698 if (!pair.first) { 3961 if (!pair.first) {
3699 temp.push_back(indent() + "end"s + nll(nodes.front())); 3962 temp.push_back(indent() + "end"s + nl(nodes.front()));
3700 break; 3963 break;
3701 } 3964 }
3702 } 3965 }
3703 if (extraScope) { 3966 if (extraScope) {
3704 popScope(); 3967 popScope();
3705 temp.push_back(indent() + "end"s + nlr(nodes.front())); 3968 temp.push_back(indent() + "end"s + nl(nodes.front()));
3706 } 3969 }
3707 if (usage == ExpUsage::Closure) { 3970 if (usage == ExpUsage::Closure) {
3708 popScope(); 3971 popScope();
3709 *funcStart = anonFuncStart() + nll(nodes.front()); 3972 *funcStart = anonFuncStart() + nl(nodes.front());
3710 temp.push_back(indent() + anonFuncEnd()); 3973 temp.push_back(indent() + anonFuncEnd());
3711 popAnonVarArg(); 3974 popAnonVarArg();
3712 popFunctionScope(); 3975 popFunctionScope();
@@ -3727,14 +3990,6 @@ private:
3727 out.push_back(join(temp, ", "sv)); 3990 out.push_back(join(temp, ", "sv));
3728 } 3991 }
3729 3992
3730 void transformExpListLow(ExpListLow_t* expListLow, str_list& out) {
3731 str_list temp;
3732 for (auto exp : expListLow->exprs.objects()) {
3733 transformExp(static_cast<Exp_t*>(exp), temp, ExpUsage::Closure);
3734 }
3735 out.push_back(join(temp, ", "sv));
3736 }
3737
3738 void transform_pipe_exp(const node_container& values, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { 3993 void transform_pipe_exp(const node_container& values, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
3739 if (values.size() == 1 && usage == ExpUsage::Closure) { 3994 if (values.size() == 1 && usage == ExpUsage::Closure) {
3740 transformUnaryExp(static_cast<UnaryExp_t*>(values.front()), out, ExpUsage::Closure); 3995 transformUnaryExp(static_cast<UnaryExp_t*>(values.front()), out, ExpUsage::Closure);
@@ -3801,16 +4056,12 @@ private:
3801 } else { 4056 } else {
3802 transformExp(arg, out, ExpUsage::Closure); 4057 transformExp(arg, out, ExpUsage::Closure);
3803 out.back().insert(0, indent()); 4058 out.back().insert(0, indent());
3804 out.back().append(nlr(x)); 4059 out.back().append(nl(x));
3805 } 4060 }
3806 return; 4061 return;
3807 } 4062 }
3808 case ExpUsage::Return: { 4063 case ExpUsage::Return: {
3809 auto ret = x->new_ptr<Return_t>(); 4064 auto ret = newReturn(arg);
3810 ret->explicitReturn = false;
3811 auto expListLow = x->new_ptr<ExpListLow_t>();
3812 expListLow->exprs.push_back(arg);
3813 ret->valueList.set(expListLow);
3814 transformReturn(ret, out); 4065 transformReturn(ret, out);
3815 return; 4066 return;
3816 } 4067 }
@@ -3925,7 +4176,7 @@ private:
3925 auto stmt = exp->new_ptr<Statement_t>(); 4176 auto stmt = exp->new_ptr<Statement_t>();
3926 stmt->content.set(preDefine); 4177 stmt->content.set(preDefine);
3927 preDefine.set(nullptr); 4178 preDefine.set(nullptr);
3928 block->statements.push_back(stmt); 4179 block->statementOrComments.push_back(stmt);
3929 auto simpleValue = exp->new_ptr<SimpleValue_t>(); 4180 auto simpleValue = exp->new_ptr<SimpleValue_t>();
3930 simpleValue->value.set(ifNode); 4181 simpleValue->value.set(ifNode);
3931 auto explist = exp->new_ptr<ExpList_t>(); 4182 auto explist = exp->new_ptr<ExpList_t>();
@@ -3934,7 +4185,7 @@ private:
3934 expListAssign->expList.set(explist); 4185 expListAssign->expList.set(explist);
3935 stmt = exp->new_ptr<Statement_t>(); 4186 stmt = exp->new_ptr<Statement_t>();
3936 stmt->content.set(expListAssign); 4187 stmt->content.set(expListAssign);
3937 block->statements.push_back(stmt); 4188 block->statementOrComments.push_back(stmt);
3938 nodes->push_back(block); 4189 nodes->push_back(block);
3939 nodes = &ifNode->nodes; 4190 nodes = &ifNode->nodes;
3940 } else { 4191 } else {
@@ -3942,7 +4193,7 @@ private:
3942 auto stmt = exp->new_ptr<Statement_t>(); 4193 auto stmt = exp->new_ptr<Statement_t>();
3943 stmt->content.set(preDefine); 4194 stmt->content.set(preDefine);
3944 preDefine.set(nullptr); 4195 preDefine.set(nullptr);
3945 block->statements.push_back(stmt); 4196 block->statementOrComments.push_back(stmt);
3946 auto simpleValue = exp->new_ptr<SimpleValue_t>(); 4197 auto simpleValue = exp->new_ptr<SimpleValue_t>();
3947 simpleValue->value.set(ifNode); 4198 simpleValue->value.set(ifNode);
3948 auto explist = exp->new_ptr<ExpList_t>(); 4199 auto explist = exp->new_ptr<ExpList_t>();
@@ -3951,7 +4202,7 @@ private:
3951 expListAssign->expList.set(explist); 4202 expListAssign->expList.set(explist);
3952 stmt = exp->new_ptr<Statement_t>(); 4203 stmt = exp->new_ptr<Statement_t>();
3953 stmt->content.set(expListAssign); 4204 stmt->content.set(expListAssign);
3954 block->statements.push_back(stmt); 4205 block->statementOrComments.push_back(stmt);
3955 auto body = exp->new_ptr<Body_t>(); 4206 auto body = exp->new_ptr<Body_t>();
3956 body->content.set(block); 4207 body->content.set(block);
3957 auto doNode = exp->new_ptr<Do_t>(); 4208 auto doNode = exp->new_ptr<Do_t>();
@@ -4035,11 +4286,7 @@ private:
4035 break; 4286 break;
4036 } 4287 }
4037 case ExpUsage::Return: { 4288 case ExpUsage::Return: {
4038 auto expListLow = exp->new_ptr<ExpListLow_t>(); 4289 auto returnNode = newReturn(e);
4039 expListLow->exprs.push_back(e);
4040 auto returnNode = exp->new_ptr<Return_t>();
4041 returnNode->explicitReturn = false;
4042 returnNode->valueList.set(expListLow);
4043 transformReturn(returnNode, out); 4290 transformReturn(returnNode, out);
4044 break; 4291 break;
4045 } 4292 }
@@ -4113,7 +4360,7 @@ private:
4113 auto stmt = x->new_ptr<Statement_t>(); 4360 auto stmt = x->new_ptr<Statement_t>();
4114 stmt->content.set(expListAssign); 4361 stmt->content.set(expListAssign);
4115 auto blk = x->new_ptr<Block_t>(); 4362 auto blk = x->new_ptr<Block_t>();
4116 blk->statements.push_back(stmt); 4363 blk->statementOrComments.push_back(stmt);
4117 newBlock.set(blk); 4364 newBlock.set(blk);
4118 } 4365 }
4119 if (!globals.empty()) { 4366 if (!globals.empty()) {
@@ -4205,15 +4452,21 @@ private:
4205 4452
4206 std::optional<std::pair<std::string, str_list>> upValueFuncFromExp(Exp_t* exp, str_list* ensureArgListInTheEnd, bool blockRewrite) { 4453 std::optional<std::pair<std::string, str_list>> upValueFuncFromExp(Exp_t* exp, str_list* ensureArgListInTheEnd, bool blockRewrite) {
4207 if (checkUpValueFuncAvailable(exp)) { 4454 if (checkUpValueFuncAvailable(exp)) {
4208 auto returnNode = exp->new_ptr<Return_t>();
4209 returnNode->explicitReturn = false;
4210 auto returnList = exp->new_ptr<ExpListLow_t>();
4211 returnList->exprs.push_back(exp);
4212 returnNode->valueList.set(returnList);
4213 auto block = exp->new_ptr<Block_t>(); 4455 auto block = exp->new_ptr<Block_t>();
4456 if (auto sVal = simpleSingleValueFrom(exp)) {
4457 if (auto doNode = sVal->value.as<Do_t>()) {
4458 if (auto blk = doNode->body->content.as<Block_t>()) {
4459 block->statementOrComments.dup(blk->statementOrComments);
4460 } else {
4461 block->statementOrComments.push_back(doNode->body->content.to<Statement_t>());
4462 }
4463 return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, false, blockRewrite);
4464 }
4465 }
4466 auto returnNode = newReturn(exp);
4214 auto stmt = exp->new_ptr<Statement_t>(); 4467 auto stmt = exp->new_ptr<Statement_t>();
4215 stmt->content.set(returnNode); 4468 stmt->content.set(returnNode);
4216 block->statements.push_back(stmt); 4469 block->statementOrComments.push_back(stmt);
4217 return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, false, blockRewrite); 4470 return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, false, blockRewrite);
4218 } 4471 }
4219 return std::nullopt; 4472 return std::nullopt;
@@ -4270,7 +4523,7 @@ private:
4270 bool extraScope = !currentScope().lastStatement; 4523 bool extraScope = !currentScope().lastStatement;
4271 if (forAssignment) { 4524 if (forAssignment) {
4272 if (extraScope) { 4525 if (extraScope) {
4273 temp.push_back(indent() + "do"s + nll(x)); 4526 temp.push_back(indent() + "do"s + nl(x));
4274 pushScope(); 4527 pushScope();
4275 } 4528 }
4276 } 4529 }
@@ -4287,26 +4540,24 @@ private:
4287 return false; 4540 return false;
4288 }; 4541 };
4289 switch (usage) { 4542 switch (usage) {
4290 case ExpUsage::Common: YUEE("AST node mismatch", x); return; 4543 case ExpUsage::Common:
4544 YUEE("AST node mismatch", x);
4545 return;
4291 case ExpUsage::Return: 4546 case ExpUsage::Return:
4292 case ExpUsage::Closure: { 4547 case ExpUsage::Closure: {
4293 prepareValue(); 4548 prepareValue();
4294 _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x); 4549 _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nl(x);
4295 _buf << indent(1) << "return "s << objVar << nll(x); 4550 _buf << indent(1) << "return "s << objVar << nl(x);
4296 _buf << indent() << "else"s << nll(x); 4551 _buf << indent() << "else"s << nl(x);
4297 temp.push_back(clearBuf()); 4552 temp.push_back(clearBuf());
4298 auto ret = x->new_ptr<Return_t>();
4299 ret->explicitReturn = false;
4300 auto retList = x->new_ptr<ExpListLow_t>();
4301 retList->exprs.push_back(exp->nilCoalesed);
4302 ret->valueList.set(retList);
4303 incIndentOffset(); 4553 incIndentOffset();
4554 auto ret = newReturn(exp->nilCoalesed);
4304 transformReturn(ret, temp); 4555 transformReturn(ret, temp);
4305 decIndentOffset(); 4556 decIndentOffset();
4306 temp.push_back(indent() + "end"s + nll(x)); 4557 temp.push_back(indent() + "end"s + nl(x));
4307 if (usage == ExpUsage::Closure) { 4558 if (usage == ExpUsage::Closure) {
4308 popScope(); 4559 popScope();
4309 *funcStart = anonFuncStart() + nll(x); 4560 *funcStart = anonFuncStart() + nl(x);
4310 temp.push_back(indent() + anonFuncEnd()); 4561 temp.push_back(indent() + anonFuncEnd());
4311 popAnonVarArg(); 4562 popAnonVarArg();
4312 popFunctionScope(); 4563 popFunctionScope();
@@ -4323,14 +4574,14 @@ private:
4323 assign->values.push_back(exp); 4574 assign->values.push_back(exp);
4324 temp.push_back(getPreDefineLine(assignment)); 4575 temp.push_back(getPreDefineLine(assignment));
4325 extraScope = prepareValue(true); 4576 extraScope = prepareValue(true);
4326 _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x); 4577 _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nl(x);
4327 temp.push_back(clearBuf()); 4578 temp.push_back(clearBuf());
4328 pushScope(); 4579 pushScope();
4329 assign->values.clear(); 4580 assign->values.clear();
4330 assign->values.push_back(toAst<Exp_t>(objVar, x)); 4581 assign->values.push_back(toAst<Exp_t>(objVar, x));
4331 transformAssignment(assignment, temp); 4582 transformAssignment(assignment, temp);
4332 popScope(); 4583 popScope();
4333 temp.push_back(indent() + "else"s + nll(x)); 4584 temp.push_back(indent() + "else"s + nl(x));
4334 assign->values.clear(); 4585 assign->values.clear();
4335 assign->values.push_back(exp->nilCoalesed); 4586 assign->values.push_back(exp->nilCoalesed);
4336 } else { 4587 } else {
@@ -4338,17 +4589,17 @@ private:
4338 assign->values.push_back(exp->nilCoalesed); 4589 assign->values.push_back(exp->nilCoalesed);
4339 temp.push_back(getPreDefineLine(assignment)); 4590 temp.push_back(getPreDefineLine(assignment));
4340 transformExp(left, temp, ExpUsage::Closure); 4591 transformExp(left, temp, ExpUsage::Closure);
4341 _buf << indent() << "if "sv << temp.back() << " == nil then"sv << nll(x); 4592 _buf << indent() << "if "sv << temp.back() << " == nil then"sv << nl(x);
4342 temp.pop_back(); 4593 temp.pop_back();
4343 temp.push_back(clearBuf()); 4594 temp.push_back(clearBuf());
4344 } 4595 }
4345 pushScope(); 4596 pushScope();
4346 transformAssignment(assignment, temp); 4597 transformAssignment(assignment, temp);
4347 popScope(); 4598 popScope();
4348 temp.push_back(indent() + "end"s + nlr(x)); 4599 temp.push_back(indent() + "end"s + nl(x));
4349 if (extraScope) { 4600 if (extraScope) {
4350 popScope(); 4601 popScope();
4351 temp.push_back(indent() + "end"s + nlr(x)); 4602 temp.push_back(indent() + "end"s + nl(x));
4352 } 4603 }
4353 break; 4604 break;
4354 } 4605 }
@@ -4372,13 +4623,17 @@ private:
4372 switch (item->get_id()) { 4623 switch (item->get_id()) {
4373 case id<Variable_t>(): { 4624 case id<Variable_t>(): {
4374 transformVariable(static_cast<Variable_t*>(item), out); 4625 transformVariable(static_cast<Variable_t*>(item), out);
4375 if (_config.lintGlobalVariable && accessType != AccessType::None && !isLocal(out.back())) { 4626 if (accessType != AccessType::None) {
4376 auto key = out.back() + ':' + std::to_string(item->m_begin.m_line) + ':' + std::to_string(item->m_begin.m_col); 4627 if (_importedGlobal) {
4377 if (_globals.find(key) == _globals.end()) { 4628 markGlobalImported(out.back());
4378 if (accessType == AccessType::Read && _funcLevel > 1) { 4629 } else if (_config.lintGlobalVariable && !isLocal(out.back())) {
4379 accessType = AccessType::Capture; 4630 auto key = out.back() + ':' + std::to_string(item->m_begin.m_line) + ':' + std::to_string(item->m_begin.m_col);
4631 if (_globals.find(key) == _globals.end()) {
4632 if (accessType == AccessType::Read && _funcLevel > 1) {
4633 accessType = AccessType::Capture;
4634 }
4635 _globals[key] = {out.back(), item->m_begin.m_line, item->m_begin.m_col, accessType, isSolidDefined(out.back())};
4380 } 4636 }
4381 _globals[key] = {out.back(), item->m_begin.m_line, item->m_begin.m_col, accessType};
4382 } 4637 }
4383 } 4638 }
4384 break; 4639 break;
@@ -4410,6 +4665,7 @@ private:
4410 case id<ForEach_t>(): transformForEachClosure(static_cast<ForEach_t*>(value), out); break; 4665 case id<ForEach_t>(): transformForEachClosure(static_cast<ForEach_t*>(value), out); break;
4411 case id<For_t>(): transformForClosure(static_cast<For_t*>(value), out); break; 4666 case id<For_t>(): transformForClosure(static_cast<For_t*>(value), out); break;
4412 case id<While_t>(): transformWhileClosure(static_cast<While_t*>(value), out); break; 4667 case id<While_t>(): transformWhileClosure(static_cast<While_t*>(value), out); break;
4668 case id<Repeat_t>(): transformRepeatClosure(static_cast<Repeat_t*>(value), out); break;
4413 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Closure); break; 4669 case id<Do_t>(): transformDo(static_cast<Do_t*>(value), out, ExpUsage::Closure); break;
4414 case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Closure); break; 4670 case id<Try_t>(): transformTry(static_cast<Try_t*>(value), out, ExpUsage::Closure); break;
4415 case id<UnaryValue_t>(): transformUnaryValue(static_cast<UnaryValue_t*>(value), out); break; 4671 case id<UnaryValue_t>(): transformUnaryValue(static_cast<UnaryValue_t*>(value), out); break;
@@ -4446,23 +4702,21 @@ private:
4446 switch (content->get_id()) { 4702 switch (content->get_id()) {
4447 case id<Block_t>(): { 4703 case id<Block_t>(): {
4448 auto block = static_cast<Block_t*>(content); 4704 auto block = static_cast<Block_t*>(content);
4449 newBlock->statements.dup(block->statements); 4705 newBlock->statementOrComments.dup(block->statementOrComments);
4450 break; 4706 break;
4451 } 4707 }
4452 case id<Statement_t>(): { 4708 case id<Statement_t>(): {
4453 newBlock->statements.push_back(content); 4709 newBlock->statementOrComments.push_back(content);
4454 break; 4710 break;
4455 } 4711 }
4456 default: YUEE("AST node mismatch", content); break; 4712 default: YUEE("AST node mismatch", content); break;
4457 } 4713 }
4458 } 4714 }
4459 if (funLit->defaultReturn.is<ExpListLow_t>()) { 4715 if (auto defaultReturn = funLit->defaultReturn.as<ExpList_t>()) {
4460 auto returnNode = newBlock->new_ptr<Return_t>(); 4716 auto returnNode = newReturn(defaultReturn);
4461 returnNode->explicitReturn = false;
4462 returnNode->valueList.set(funLit->defaultReturn);
4463 auto stmt = newBlock->new_ptr<Statement_t>(); 4717 auto stmt = newBlock->new_ptr<Statement_t>();
4464 stmt->content.set(returnNode); 4718 stmt->content.set(returnNode);
4465 newBlock->statements.push_back(stmt); 4719 newBlock->statementOrComments.push_back(stmt);
4466 } 4720 }
4467 transformBlock(newBlock, temp, ExpUsage::Common); 4721 transformBlock(newBlock, temp, ExpUsage::Common);
4468 } else { 4722 } else {
@@ -4484,7 +4738,7 @@ private:
4484 } 4738 }
4485 _buf << args << ')'; 4739 _buf << args << ')';
4486 if (!initArgs.empty() || !bodyCodes.empty()) { 4740 if (!initArgs.empty() || !bodyCodes.empty()) {
4487 _buf << nlr(argsDef) << initArgs << bodyCodes; 4741 _buf << nl(argsDef) << initArgs << bodyCodes;
4488 popScope(); 4742 popScope();
4489 _buf << indent() << "end"sv; 4743 _buf << indent() << "end"sv;
4490 } else { 4744 } else {
@@ -4495,7 +4749,7 @@ private:
4495 auto& bodyCodes = temp.back(); 4749 auto& bodyCodes = temp.back();
4496 _buf << "function("sv << (isFatArrow ? "self"s : Empty) << ')'; 4750 _buf << "function("sv << (isFatArrow ? "self"s : Empty) << ')';
4497 if (!bodyCodes.empty()) { 4751 if (!bodyCodes.empty()) {
4498 _buf << nll(funLit) << bodyCodes; 4752 _buf << nl(funLit) << bodyCodes;
4499 popScope(); 4753 popScope();
4500 _buf << indent() << "end"sv; 4754 _buf << indent() << "end"sv;
4501 } else { 4755 } else {
@@ -4512,7 +4766,7 @@ private:
4512 auto x = body; 4766 auto x = body;
4513 if (auto stmt = body->content.as<Statement_t>()) { 4767 if (auto stmt = body->content.as<Statement_t>()) {
4514 auto block = x->new_ptr<Block_t>(); 4768 auto block = x->new_ptr<Block_t>();
4515 block->statements.push_back(stmt); 4769 block->statementOrComments.push_back(stmt);
4516 transformBlock(block, out, usage, assignList); 4770 transformBlock(block, out, usage, assignList);
4517 } else { 4771 } else {
4518 transformBlock(body->content.to<Block_t>(), out, usage, assignList); 4772 transformBlock(body->content.to<Block_t>(), out, usage, assignList);
@@ -4524,13 +4778,15 @@ private:
4524 out.push_back(Empty); 4778 out.push_back(Empty);
4525 return; 4779 return;
4526 } 4780 }
4527 const auto& nodes = block->statements.objects(); 4781 const auto& nodes = block->statementOrComments.objects();
4782 auto lastStmt = lastStatementFrom(nodes);
4528 LocalMode mode = LocalMode::None; 4783 LocalMode mode = LocalMode::None;
4529 Local_t *any = nullptr, *capital = nullptr; 4784 Local_t *any = nullptr, *capital = nullptr;
4530 for (auto it = nodes.begin(); it != nodes.end(); ++it) { 4785 for (auto it = nodes.begin(); it != nodes.end(); ++it) {
4531 auto node = *it; 4786 auto node = *it;
4532 auto stmt = static_cast<Statement_t*>(node); 4787 auto stmt = ast_cast<Statement_t>(node);
4533 if (!stmt->appendix && stmt->content.is<Return_t>() && stmt != nodes.back()) { 4788 if (!stmt) continue;
4789 if (!stmt->appendix && stmt->content.is<Return_t>() && stmt != lastStmt) {
4534 throw CompileError("'return' statement must be the last line in the block"sv, stmt->content); 4790 throw CompileError("'return' statement must be the last line in the block"sv, stmt->content);
4535 } else if (auto pipeBody = stmt->content.as<PipeBody_t>()) { 4791 } else if (auto pipeBody = stmt->content.as<PipeBody_t>()) {
4536 auto x = stmt; 4792 auto x = stmt;
@@ -4539,6 +4795,16 @@ private:
4539 BREAK_IF(it == nodes.begin()); 4795 BREAK_IF(it == nodes.begin());
4540 auto last = it; 4796 auto last = it;
4541 --last; 4797 --last;
4798 bool found = true;
4799 while (!ast_is<Statement_t>(*last)) {
4800 if (last == nodes.begin()) {
4801 found = false;
4802 break;
4803 } else {
4804 --last;
4805 }
4806 }
4807 BREAK_IF(!found);
4542 auto lst = static_cast<Statement_t*>(*last); 4808 auto lst = static_cast<Statement_t*>(*last);
4543 if (lst->appendix) { 4809 if (lst->appendix) {
4544 throw CompileError("statement decorator must be placed at the end of pipe chain"sv, lst->appendix.get()); 4810 throw CompileError("statement decorator must be placed at the end of pipe chain"sv, lst->appendix.get());
@@ -4556,9 +4822,17 @@ private:
4556 stmt->content.set(nullptr); 4822 stmt->content.set(nullptr);
4557 auto next = it; 4823 auto next = it;
4558 ++next; 4824 ++next;
4825 Statement_t* nextStmt = nullptr;
4826 while (next != nodes.end()) {
4827 nextStmt = ast_cast<Statement_t>(*next);
4828 if (nextStmt) {
4829 break;
4830 }
4831 ++next;
4832 }
4559 BLOCK_START 4833 BLOCK_START
4560 BREAK_IF(next == nodes.end()); 4834 BREAK_IF(!nextStmt);
4561 BREAK_IF(!static_cast<Statement_t*>(*next)->content.as<PipeBody_t>()); 4835 BREAK_IF(!nextStmt->content.as<PipeBody_t>());
4562 throw CompileError("indent mismatch in pipe chain"sv, *next); 4836 throw CompileError("indent mismatch in pipe chain"sv, *next);
4563 BLOCK_END 4837 BLOCK_END
4564 } else if (auto backcall = stmt->content.as<Backcall_t>()) { 4838 } else if (auto backcall = stmt->content.as<Backcall_t>()) {
@@ -4566,7 +4840,7 @@ private:
4566 auto newBlock = x->new_ptr<Block_t>(); 4840 auto newBlock = x->new_ptr<Block_t>();
4567 if (it != nodes.begin()) { 4841 if (it != nodes.begin()) {
4568 for (auto i = nodes.begin(); i != it; ++i) { 4842 for (auto i = nodes.begin(); i != it; ++i) {
4569 newBlock->statements.push_back(*i); 4843 newBlock->statementOrComments.push_back(*i);
4570 } 4844 }
4571 } 4845 }
4572 x = backcall; 4846 x = backcall;
@@ -4577,7 +4851,7 @@ private:
4577 ++next; 4851 ++next;
4578 if (next != nodes.end()) { 4852 if (next != nodes.end()) {
4579 for (auto i = next; i != nodes.end(); ++i) { 4853 for (auto i = next; i != nodes.end(); ++i) {
4580 block->statements.push_back(*i); 4854 block->statementOrComments.push_back(*i);
4581 } 4855 }
4582 } 4856 }
4583 auto body = x->new_ptr<Body_t>(); 4857 auto body = x->new_ptr<Body_t>();
@@ -4629,7 +4903,7 @@ private:
4629 expListAssign->expList.set(expList); 4903 expListAssign->expList.set(expList);
4630 newStmt->content.set(expListAssign); 4904 newStmt->content.set(expListAssign);
4631 newStmt->appendix.set(stmt->appendix); 4905 newStmt->appendix.set(stmt->appendix);
4632 newBlock->statements.push_back(newStmt); 4906 newBlock->statementOrComments.push_back(newStmt);
4633 } 4907 }
4634 transformBlock(newBlock, out, usage, assignList, isRoot); 4908 transformBlock(newBlock, out, usage, assignList, isRoot);
4635 return; 4909 return;
@@ -4656,7 +4930,7 @@ private:
4656 throw CompileError("while-loop line decorator is not supported here"sv, appendix->item.get()); 4930 throw CompileError("while-loop line decorator is not supported here"sv, appendix->item.get());
4657 break; 4931 break;
4658 } 4932 }
4659 case id<CompInner_t>(): { 4933 case id<CompFor_t>(): {
4660 throw CompileError("for-loop line decorator is not supported here"sv, appendix->item.get()); 4934 throw CompileError("for-loop line decorator is not supported here"sv, appendix->item.get());
4661 break; 4935 break;
4662 } 4936 }
@@ -4685,7 +4959,7 @@ private:
4685 auto newBlock = x->new_ptr<Block_t>(); 4959 auto newBlock = x->new_ptr<Block_t>();
4686 if (it != nodes.begin()) { 4960 if (it != nodes.begin()) {
4687 for (auto i = nodes.begin(); i != it; ++i) { 4961 for (auto i = nodes.begin(); i != it; ++i) {
4688 newBlock->statements.push_back(*i); 4962 newBlock->statementOrComments.push_back(*i);
4689 } 4963 }
4690 } 4964 }
4691 x = expListAssign; 4965 x = expListAssign;
@@ -4695,7 +4969,7 @@ private:
4695 ++next; 4969 ++next;
4696 if (next != nodes.end()) { 4970 if (next != nodes.end()) {
4697 for (auto i = next; i != nodes.end(); ++i) { 4971 for (auto i = next; i != nodes.end(); ++i) {
4698 followingBlock->statements.push_back(*i); 4972 followingBlock->statementOrComments.push_back(*i);
4699 } 4973 }
4700 } 4974 }
4701 } 4975 }
@@ -4723,17 +4997,13 @@ private:
4723 newAssignment->action.set(newAssign); 4997 newAssignment->action.set(newAssign);
4724 auto newStatement = x->new_ptr<Statement_t>(); 4998 auto newStatement = x->new_ptr<Statement_t>();
4725 newStatement->content.set(newAssignment); 4999 newStatement->content.set(newAssignment);
4726 followingBlock->statements.push_front(newStatement); 5000 followingBlock->statementOrComments.push_front(newStatement);
4727 } 5001 }
4728 argNames.push_back("..."s); 5002 argNames.push_back("..."s);
4729 auto newBody = x->new_ptr<Body_t>(); 5003 auto newBody = x->new_ptr<Body_t>();
4730 newBody->content.set(followingBlock); 5004 newBody->content.set(followingBlock);
4731 { 5005 {
4732 auto doNode = x->new_ptr<Do_t>(); 5006 if (auto result = upValueFuncFromBlock(followingBlock.get(), &argNames, false, true)) {
4733 doNode->body.set(newBody);
4734 auto simpleValue = x->new_ptr<SimpleValue_t>();
4735 simpleValue->value.set(doNode);
4736 if (auto result = upValueFuncFromExp(newExp(simpleValue, x), &argNames, true)) {
4737 auto [funcName, args] = std::move(*result); 5007 auto [funcName, args] = std::move(*result);
4738 str_list finalArgs; 5008 str_list finalArgs;
4739 for (const auto& arg : args) { 5009 for (const auto& arg : args) {
@@ -4741,9 +5011,14 @@ private:
4741 finalArgs.push_back(arg); 5011 finalArgs.push_back(arg);
4742 } 5012 }
4743 } 5013 }
4744 newBlock->statements.push_back(toAst<Statement_t>(funcName + ' ' + join(finalArgs, ","sv), x)); 5014 auto lastNewStmt = toAst<Statement_t>(funcName + ' ' + (finalArgs.empty() ? "nil"s : join(finalArgs, ","sv)), x);
4745 auto sVal = singleValueFrom(static_cast<Statement_t*>(newBlock->statements.back())->content.to<ExpListAssign_t>()->expList); 5015 newBlock->statementOrComments.push_back(lastNewStmt);
4746 ast_to<InvokeArgs_t>(sVal->item.to<ChainValue_t>()->items.back())->args.dup(newInvoke->args); 5016 auto sVal = singleValueFrom(lastNewStmt->content.to<ExpListAssign_t>()->expList);
5017 auto invokArgs = ast_to<InvokeArgs_t>(sVal->item.to<ChainValue_t>()->items.back());
5018 if (finalArgs.empty()) {
5019 invokArgs->args.clear();
5020 }
5021 invokArgs->args.dup(newInvoke->args);
4747 transformBlock(newBlock, out, usage, assignList, isRoot); 5022 transformBlock(newBlock, out, usage, assignList, isRoot);
4748 return; 5023 return;
4749 } 5024 }
@@ -4768,7 +5043,7 @@ private:
4768 newItemListAssign->expList.set(newItemList); 5043 newItemListAssign->expList.set(newItemList);
4769 auto newItemStatement = x->new_ptr<Statement_t>(); 5044 auto newItemStatement = x->new_ptr<Statement_t>();
4770 newItemStatement->content.set(newItemListAssign); 5045 newItemStatement->content.set(newItemListAssign);
4771 newBlock->statements.push_back(newItemStatement); 5046 newBlock->statementOrComments.push_back(newItemStatement);
4772 transformBlock(newBlock, out, usage, assignList, isRoot); 5047 transformBlock(newBlock, out, usage, assignList, isRoot);
4773 return; 5048 return;
4774 BLOCK_END 5049 BLOCK_END
@@ -4777,11 +5052,11 @@ private:
4777 auto newBlock = x->new_ptr<Block_t>(); 5052 auto newBlock = x->new_ptr<Block_t>();
4778 if (it != nodes.begin()) { 5053 if (it != nodes.begin()) {
4779 for (auto i = nodes.begin(); i != it; ++i) { 5054 for (auto i = nodes.begin(); i != it; ++i) {
4780 newBlock->statements.push_back(*i); 5055 newBlock->statementOrComments.push_back(*i);
4781 } 5056 }
4782 } 5057 }
4783 localAttrib->attrib.set(localAttrib->new_ptr<ConstAttrib_t>()); 5058 localAttrib->attrib.set(localAttrib->new_ptr<ConstAttrib_t>());
4784 newBlock->statements.push_back(*it); 5059 newBlock->statementOrComments.push_back(*it);
4785 x = localAttrib; 5060 x = localAttrib;
4786 auto followingBlock = x->new_ptr<Block_t>(); 5061 auto followingBlock = x->new_ptr<Block_t>();
4787 { 5062 {
@@ -4789,7 +5064,7 @@ private:
4789 ++next; 5064 ++next;
4790 if (next != nodes.end()) { 5065 if (next != nodes.end()) {
4791 for (auto i = next; i != nodes.end(); ++i) { 5066 for (auto i = next; i != nodes.end(); ++i) {
4792 followingBlock->statements.push_back(*i); 5067 followingBlock->statementOrComments.push_back(*i);
4793 } 5068 }
4794 } 5069 }
4795 } 5070 }
@@ -4811,13 +5086,44 @@ private:
4811 auto value = singleValueFrom(pCallExp); 5086 auto value = singleValueFrom(pCallExp);
4812 value->item.to<SimpleValue_t>()->value.to<Try_t>()->func.set(followingBlock); 5087 value->item.to<SimpleValue_t>()->value.to<Try_t>()->func.set(followingBlock);
4813 for (const auto& stmt : getCloses) { 5088 for (const auto& stmt : getCloses) {
4814 newBlock->statements.push_back(toAst<Statement_t>(stmt, x)); 5089 newBlock->statementOrComments.push_back(toAst<Statement_t>(stmt, x));
4815 } 5090 }
4816 newBlock->statements.push_back(pCallStmt); 5091 newBlock->statementOrComments.push_back(pCallStmt);
4817 for (const auto& stmt : doCloses) { 5092 for (const auto& stmt : doCloses) {
4818 newBlock->statements.push_back(toAst<Statement_t>(stmt, x)); 5093 newBlock->statementOrComments.push_back(toAst<Statement_t>(stmt, x));
5094 }
5095 newBlock->statementOrComments.push_back(toAst<Statement_t>("if "s + okVar + " then return ... else error ..."s, x));
5096 transformBlock(newBlock, out, usage, assignList, isRoot);
5097 return;
5098 } else if (auto expListAssign = stmt->content.as<ExpListAssign_t>();
5099 expListAssign && expListAssign->action && expListAssign->action.is<SubBackcall_t>()) {
5100 auto x = *nodes.begin();
5101 auto newBlock = x->new_ptr<Block_t>();
5102 if (it != nodes.begin()) {
5103 for (auto i = nodes.begin(); i != it; ++i) {
5104 newBlock->statementOrComments.push_back(*i);
5105 }
5106 }
5107 auto doBackcall = static_cast<SubBackcall_t*>(expListAssign->action.get());
5108 auto backcall = expListAssign->new_ptr<Backcall_t>();
5109 auto argsDef = backcall->new_ptr<FnArgsDef_t>();
5110 try {
5111 auto defList = toAst<FnArgDefList_t>(YueFormat{}.toString(expListAssign->expList), expListAssign->expList);
5112 argsDef->defList.set(defList);
5113 } catch (const std::exception&) {
5114 throw CompileError("backcall syntax error", backcall);
5115 }
5116 backcall->argsDef.set(argsDef);
5117 backcall->arrow.set(doBackcall->arrow);
5118 backcall->value.set(doBackcall->value);
5119 auto newStmt = backcall->new_ptr<Statement_t>();
5120 newStmt->content.set(backcall);
5121 newStmt->appendix.set(stmt->appendix);
5122 newBlock->statementOrComments.push_back(newStmt);
5123 auto ait = it;
5124 for (auto i = ++ait; i != nodes.end(); ++i) {
5125 newBlock->statementOrComments.push_back(*i);
4819 } 5126 }
4820 newBlock->statements.push_back(toAst<Statement_t>("if "s + okVar + " then return ... else error ..."s, x));
4821 transformBlock(newBlock, out, usage, assignList, isRoot); 5127 transformBlock(newBlock, out, usage, assignList, isRoot);
4822 return; 5128 return;
4823 } 5129 }
@@ -4928,7 +5234,7 @@ private:
4928 } 5234 }
4929 } 5235 }
4930 if (isRoot && !_info.moduleName.empty() && !_info.exportMacro) { 5236 if (isRoot && !_info.moduleName.empty() && !_info.exportMacro) {
4931 block->statements.push_front(toAst<Statement_t>(_info.moduleName + (_info.exportDefault ? "=nil"s : (_info.exportMetatable ? "=<>:{}"s : "={}"s)), block)); 5237 block->statementOrComments.push_front(toAst<Statement_t>(_info.moduleName + (_info.exportDefault ? "=nil"s : (_info.exportMetatable ? "=<>:{}"s : "={}"s)), block));
4932 } 5238 }
4933 switch (usage) { 5239 switch (usage) {
4934 case ExpUsage::Closure: 5240 case ExpUsage::Closure:
@@ -4941,11 +5247,9 @@ private:
4941 auto expList = expListFrom(last); 5247 auto expList = expListFrom(last);
4942 BREAK_IF(!expList); 5248 BREAK_IF(!expList);
4943 BREAK_IF(last->appendix && !last->appendix->item.is<IfLine_t>()); 5249 BREAK_IF(last->appendix && !last->appendix->item.is<IfLine_t>());
4944 auto expListLow = x->new_ptr<ExpListLow_t>();
4945 expListLow->exprs.dup(expList->exprs);
4946 auto returnNode = x->new_ptr<Return_t>(); 5250 auto returnNode = x->new_ptr<Return_t>();
4947 returnNode->explicitReturn = false; 5251 returnNode->explicitReturn = false;
4948 returnNode->valueList.set(expListLow); 5252 returnNode->valueList.set(expList);
4949 returnNode->allowBlockMacroReturn = true; 5253 returnNode->allowBlockMacroReturn = true;
4950 last->content.set(returnNode); 5254 last->content.set(returnNode);
4951 BLOCK_END 5255 BLOCK_END
@@ -4965,7 +5269,7 @@ private:
4965 break; 5269 break;
4966 } 5270 }
4967 } 5271 }
4968 bool lastAssignable = (expListFrom(last) || ast_is<For_t, ForEach_t, While_t>(last->content)); 5272 bool lastAssignable = (expListFrom(last) || ast_is<For_t, While_t>(last->content));
4969 if (lastAssignable) { 5273 if (lastAssignable) {
4970 auto x = last; 5274 auto x = last;
4971 auto newAssignment = x->new_ptr<ExpListAssign_t>(); 5275 auto newAssignment = x->new_ptr<ExpListAssign_t>();
@@ -4990,45 +5294,88 @@ private:
4990 } 5294 }
4991 if (!nodes.empty()) { 5295 if (!nodes.empty()) {
4992 str_list temp; 5296 str_list temp;
5297 auto lastStmt = lastStatementFrom(nodes);
4993 for (auto node : nodes) { 5298 for (auto node : nodes) {
4994 currentScope().lastStatement = (node == nodes.back()) && currentScope().mode == GlobalMode::None; 5299 if (auto comment = ast_cast<YueComment_t>(node)) {
4995 transformStatement(static_cast<Statement_t*>(node), temp); 5300 transformComment(comment, temp);
4996 if (isRoot && !_rootDefs.empty()) { 5301 continue;
4997 auto last = std::move(temp.back()); 5302 }
4998 temp.pop_back(); 5303 if (!ast_is<Statement_t>(node)) {
4999 temp.insert(temp.end(), _rootDefs.begin(), _rootDefs.end()); 5304 continue;
5000 _rootDefs.clear(); 5305 }
5001 temp.push_back(std::move(last)); 5306 auto transformNode = [&]() {
5002 } 5307 currentScope().lastStatement = (node == lastStmt) && currentScope().mode == GlobalMode::None;
5003 if (!temp.empty() && _parser.startWith<StatementSep_t>(temp.back())) { 5308 auto stmt = static_cast<Statement_t*>(node);
5004 auto rit = ++temp.rbegin(); 5309 if (auto importNode = stmt->content.as<Import_t>();
5005 if (rit != temp.rend() && !rit->empty()) { 5310 importNode && importNode->content.is<ImportAllGlobal_t>()) {
5006 auto index = std::string::npos; 5311 if (_importedGlobal) {
5007 if (_config.reserveLineNumber) { 5312 throw CompileError("import global redeclared in same scope"sv, importNode);
5008 index = rit->rfind(" -- "sv);
5009 } else { 5313 } else {
5010 index = rit->find_last_not_of('\n'); 5314 auto& scope = currentScope();
5011 if (index != std::string::npos) index++; 5315 scope.importedGlobal = std::make_unique<ImportedGlobal>();
5012 } 5316 _importedGlobal = scope.importedGlobal.get();
5013 if (index != std::string::npos) { 5317 _importedGlobal->vars = scope.vars.get();
5014 auto ending = rit->substr(0, index); 5318 _importedGlobal->indent = indent();
5015 auto ind = ending.find_last_of(" \t\n"sv); 5319 _importedGlobal->nl = nl(stmt);
5016 if (ind != std::string::npos) { 5320 _importedGlobal->globalCodeLine = &temp.emplace_back();
5017 ending = ending.substr(ind + 1); 5321 }
5322 } else {
5323 transformStatement(stmt, temp);
5324 }
5325 if (isRoot && !_rootDefs.empty()) {
5326 auto last = std::move(temp.back());
5327 temp.pop_back();
5328 temp.insert(temp.end(), _rootDefs.begin(), _rootDefs.end());
5329 _rootDefs.clear();
5330 temp.push_back(std::move(last));
5331 }
5332 if (!temp.empty() && _parser.startWith<StatementSep_t>(temp.back())) {
5333 auto rit = ++temp.rbegin();
5334 if (rit != temp.rend() && !rit->empty()) {
5335 auto index = std::string::npos;
5336 if (_config.reserveLineNumber) {
5337 index = rit->rfind(" -- "sv);
5338 } else {
5339 index = rit->find_last_not_of('\n');
5340 if (index != std::string::npos) index++;
5018 } 5341 }
5019 if (LuaKeywords.find(ending) == LuaKeywords.end()) { 5342 if (index != std::string::npos) {
5020 rit->insert(index, ";"sv); 5343 auto ending = rit->substr(0, index);
5344 auto ind = ending.find_last_of(" \t\n"sv);
5345 if (ind != std::string::npos) {
5346 ending = ending.substr(ind + 1);
5347 }
5348 if (LuaKeywords.find(ending) == LuaKeywords.end()) {
5349 rit->insert(index, ";"sv);
5350 }
5021 } 5351 }
5022 } 5352 }
5023 } 5353 }
5354 };
5355 if (_config.lax) {
5356 try {
5357 transformNode();
5358 } catch (const CompileError&) { }
5359 } else {
5360 transformNode();
5024 } 5361 }
5025 } 5362 }
5363 if (auto importedGlobal = currentScope().importedGlobal.get()) {
5364 int target = getLuaTarget(block);
5365 auto attrib = target >= 504 ? " <const>"s : Empty;
5366 str_list globalCodes;
5367 for (const auto& global : importedGlobal->globalList) {
5368 globalCodes.emplace_back(importedGlobal->indent + "local "s + global + attrib + " = "s + global + importedGlobal->nl);
5369 }
5370 *importedGlobal->globalCodeLine = join(globalCodes);
5371 _importedGlobal = nullptr;
5372 }
5026 out.push_back(join(temp)); 5373 out.push_back(join(temp));
5027 } else { 5374 } else {
5028 out.push_back(Empty); 5375 out.push_back(Empty);
5029 } 5376 }
5030 if (isRoot && !_info.moduleName.empty() && !_info.exportMacro) { 5377 if (isRoot && !_info.moduleName.empty() && !_info.exportMacro) {
5031 out.back().append(indent() + "return "s + _info.moduleName + nlr(block)); 5378 out.back().append(indent() + "return "s + _info.moduleName + nl(block));
5032 } 5379 }
5033 } 5380 }
5034 5381
@@ -5229,18 +5576,29 @@ private:
5229 auto macroLit = macro->decl.to<MacroLit_t>(); 5576 auto macroLit = macro->decl.to<MacroLit_t>();
5230 auto argsDef = macroLit->argsDef.get(); 5577 auto argsDef = macroLit->argsDef.get();
5231 str_list newArgs; 5578 str_list newArgs;
5579 str_list argChecks;
5580 bool hasCheck = false;
5232 if (argsDef) { 5581 if (argsDef) {
5233 for (auto def_ : argsDef->definitions.objects()) { 5582 for (auto def_ : argsDef->definitions.objects()) {
5234 auto def = static_cast<FnArgDef_t*>(def_); 5583 auto def = static_cast<FnArgDef_t*>(def_);
5235 if (def->name.is<SelfItem_t>()) { 5584 if (def->name.is<SelfItem_t>()) {
5236 throw CompileError("self name is not supported for macro function argument"sv, def->name); 5585 throw CompileError("self name is not supported for macro function argument"sv, def->name);
5237 } else { 5586 } else {
5587 if (def->op) throw CompileError("invalid existence checking"sv, def->op);
5588 if (def->label) {
5589 hasCheck = true;
5590 const auto& astName = argChecks.emplace_back(_parser.toString(def->label));
5591 if (!_parser.hasAST(astName)) {
5592 throw CompileError("invalid AST name"sv, def->label);
5593 }
5594 } else {
5595 argChecks.emplace_back();
5596 }
5238 std::string defVal; 5597 std::string defVal;
5239 if (def->defaultValue) { 5598 if (def->defaultValue) {
5240 defVal = _parser.toString(def->defaultValue); 5599 defVal = _parser.toString(def->defaultValue);
5241 Utils::trim(defVal); 5600 Utils::trim(defVal);
5242 defVal.insert(0, "=[==========["sv); 5601 defVal = '=' + Utils::toLuaDoubleString(defVal);
5243 defVal.append("]==========]"sv);
5244 } 5602 }
5245 newArgs.emplace_back(_parser.toString(def->name) + defVal); 5603 newArgs.emplace_back(_parser.toString(def->name) + defVal);
5246 } 5604 }
@@ -5248,6 +5606,14 @@ private:
5248 if (argsDef->varArg) { 5606 if (argsDef->varArg) {
5249 newArgs.emplace_back(_parser.toString(argsDef->varArg)); 5607 newArgs.emplace_back(_parser.toString(argsDef->varArg));
5250 } 5608 }
5609 if (argsDef->label) {
5610 hasCheck = true;
5611 const auto& astName = _parser.toString(argsDef->label);
5612 if (!_parser.hasAST(astName)) {
5613 throw CompileError("invalid AST name"sv, argsDef->label);
5614 }
5615 argChecks.emplace_back("..."s + astName);
5616 }
5251 } 5617 }
5252 std::string macroCodes = "_ENV=require('yue').macro_env\n("s + join(newArgs, ","sv) + ")->"s + _parser.toString(macroLit->body); 5618 std::string macroCodes = "_ENV=require('yue').macro_env\n("s + join(newArgs, ","sv) + ")->"s + _parser.toString(macroLit->body);
5253 auto chunkName = "=(macro "s + macroName + ')'; 5619 auto chunkName = "=(macro "s + macroName + ')';
@@ -5278,6 +5644,24 @@ private:
5278 throw CompileError("failed to generate macro function\n"s + err, macroLit); 5644 throw CompileError("failed to generate macro function\n"s + err, macroLit);
5279 } // cur true macro 5645 } // cur true macro
5280 lua_remove(L, -2); // cur macro 5646 lua_remove(L, -2); // cur macro
5647 if (hasCheck) {
5648 lua_createtable(L, 0, 0); // cur macro checks
5649 int i = 1;
5650 for (const auto& check : argChecks) {
5651 if (check.empty()) {
5652 lua_pushboolean(L, 0);
5653 lua_rawseti(L, -2, i);
5654 } else {
5655 lua_pushlstring(L, check.c_str(), check.size());
5656 lua_rawseti(L, -2, i);
5657 }
5658 i++;
5659 }
5660 lua_createtable(L, 2, 0); // cur macro checks macrotab
5661 lua_insert(L, -3); // cur macrotab macro checks
5662 lua_rawseti(L, -3, 1); // macrotab[1] = checks, cur macrotab macro
5663 lua_rawseti(L, -2, 2); // macrotab[2] = macro, cur macrotab
5664 } // cur macro
5281 if (exporting && _config.exporting && !_config.module.empty()) { 5665 if (exporting && _config.exporting && !_config.module.empty()) {
5282 pushModuleTable(_config.module); // cur macro module 5666 pushModuleTable(_config.module); // cur macro module
5283 lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro module name 5667 lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro module name
@@ -5310,7 +5694,7 @@ private:
5310 if (!target) target = returnNode; 5694 if (!target) target = returnNode;
5311 throw CompileError("explicit return statement is not allowed in this context"sv, target); 5695 throw CompileError("explicit return statement is not allowed in this context"sv, target);
5312 } 5696 }
5313 if (auto valueList = returnNode->valueList.as<ExpListLow_t>()) { 5697 if (auto valueList = returnNode->valueList.as<ExpList_t>()) {
5314 if (valueList->exprs.size() == 1) { 5698 if (valueList->exprs.size() == 1) {
5315 auto exp = static_cast<Exp_t*>(valueList->exprs.back()); 5699 auto exp = static_cast<Exp_t*>(valueList->exprs.back());
5316 if (isPurePipeChain(exp)) { 5700 if (isPurePipeChain(exp)) {
@@ -5352,11 +5736,11 @@ private:
5352 case id<While_t>(): 5736 case id<While_t>():
5353 transformWhileInPlace(static_cast<While_t*>(value), out); 5737 transformWhileInPlace(static_cast<While_t*>(value), out);
5354 return; 5738 return;
5355 case id<For_t>(): 5739 case id<Repeat_t>():
5356 transformForInPlace(static_cast<For_t*>(value), out); 5740 transformRepeatInPlace(static_cast<Repeat_t*>(value), out);
5357 return; 5741 return;
5358 case id<ForEach_t>(): 5742 case id<For_t>():
5359 transformForEachInPlace(static_cast<ForEach_t*>(value), out); 5743 transformForInPlace(static_cast<For_t*>(value), out, nullptr);
5360 return; 5744 return;
5361 case id<If_t>(): 5745 case id<If_t>():
5362 transformIf(static_cast<If_t*>(value), out, ExpUsage::Return); 5746 transformIf(static_cast<If_t*>(value), out, ExpUsage::Return);
@@ -5376,12 +5760,12 @@ private:
5376 } 5760 }
5377 } 5761 }
5378 transformValue(singleValue, out); 5762 transformValue(singleValue, out);
5379 out.back() = indent() + "return "s + out.back() + nlr(returnNode); 5763 out.back() = indent() + "return "s + out.back() + nl(returnNode);
5380 return; 5764 return;
5381 } else { 5765 } else {
5382 str_list temp; 5766 str_list temp;
5383 transformExpListLow(valueList, temp); 5767 transformExpList(valueList, temp);
5384 out.push_back(indent() + "return "s + temp.back() + nlr(returnNode)); 5768 out.push_back(indent() + "return "s + temp.back() + nl(returnNode));
5385 } 5769 }
5386 } else if (auto tableBlock = returnNode->valueList.as<TableBlock_t>()) { 5770 } else if (auto tableBlock = returnNode->valueList.as<TableBlock_t>()) {
5387 const auto& values = tableBlock->values.objects(); 5771 const auto& values = tableBlock->values.objects();
@@ -5389,10 +5773,10 @@ private:
5389 transformSpreadTable(values, out, ExpUsage::Return, nullptr, false); 5773 transformSpreadTable(values, out, ExpUsage::Return, nullptr, false);
5390 } else { 5774 } else {
5391 transformTable(values, out); 5775 transformTable(values, out);
5392 out.back() = indent() + "return "s + out.back() + nlr(returnNode); 5776 out.back() = indent() + "return "s + out.back() + nl(returnNode);
5393 } 5777 }
5394 } else { 5778 } else {
5395 out.push_back(indent() + "return"s + nll(returnNode)); 5779 out.push_back(indent() + "return"s + nl(returnNode));
5396 } 5780 }
5397 } 5781 }
5398 5782
@@ -5423,6 +5807,7 @@ private:
5423 bool checkExistence = false; 5807 bool checkExistence = false;
5424 std::string name; 5808 std::string name;
5425 std::string assignSelf; 5809 std::string assignSelf;
5810 ast_ptr<false, ExpListAssign_t> assignment;
5426 }; 5811 };
5427 std::list<ArgItem> argItems; 5812 std::list<ArgItem> argItems;
5428 str_list temp; 5813 str_list temp;
@@ -5432,7 +5817,11 @@ private:
5432 auto def = static_cast<FnArgDef_t*>(_def); 5817 auto def = static_cast<FnArgDef_t*>(_def);
5433 auto& arg = argItems.emplace_back(); 5818 auto& arg = argItems.emplace_back();
5434 switch (def->name->get_id()) { 5819 switch (def->name->get_id()) {
5435 case id<Variable_t>(): arg.name = variableToString(static_cast<Variable_t*>(def->name.get())); break; 5820 case id<Variable_t>(): {
5821 if (def->op) throw CompileError("invalid existence checking"sv, def->op);
5822 arg.name = variableToString(static_cast<Variable_t*>(def->name.get()));
5823 break;
5824 }
5436 case id<SelfItem_t>(): { 5825 case id<SelfItem_t>(): {
5437 assignSelf = true; 5826 assignSelf = true;
5438 if (def->op) { 5827 if (def->op) {
@@ -5473,6 +5862,22 @@ private:
5473 } 5862 }
5474 break; 5863 break;
5475 } 5864 }
5865 case id<TableLit_t>(): {
5866 arg.name = getUnusedName("_arg_"sv);
5867 auto simpleValue = def->new_ptr<SimpleValue_t>();
5868 simpleValue->value.set(def->name);
5869 auto asmt = assignmentFrom(newExp(simpleValue, def), toAst<Exp_t>(arg.name, def), def);
5870 arg.assignment = asmt;
5871 break;
5872 }
5873 case id<SimpleTable_t>(): {
5874 arg.name = getUnusedName("_arg_"sv);
5875 auto value = def->new_ptr<Value_t>();
5876 value->item.set(def->name);
5877 auto asmt = assignmentFrom(newExp(value, def), toAst<Exp_t>(arg.name, def), def);
5878 arg.assignment = asmt;
5879 break;
5880 }
5476 default: YUEE("AST node mismatch", def->name.get()); break; 5881 default: YUEE("AST node mismatch", def->name.get()); break;
5477 } 5882 }
5478 forceAddToScope(arg.name); 5883 forceAddToScope(arg.name);
@@ -5486,23 +5891,46 @@ private:
5486 assignment->action.set(assign); 5891 assignment->action.set(assign);
5487 transformAssignment(assignment, temp); 5892 transformAssignment(assignment, temp);
5488 popScope(); 5893 popScope();
5489 _buf << indent() << "if "sv << arg.name << " == nil then"sv << nll(def); 5894 _buf << indent() << "if "sv << arg.name << " == nil then"sv << nl(def);
5490 _buf << temp.back(); 5895 _buf << temp.back();
5491 _buf << indent() << "end"sv << nll(def); 5896 _buf << indent() << "end"sv << nl(def);
5492 temp.back() = clearBuf(); 5897 temp.back() = clearBuf();
5493 } 5898 }
5494 if (varNames.empty()) 5899 if (arg.assignment) {
5900 auto names = getArgDestructureList(arg.assignment);
5901 for (const auto& name : names) {
5902 forceAddToScope(name);
5903 }
5904 temp.emplace_back(indent() + "local "s + join(names, ", "sv) + nl(def));
5905 transformAssignment(arg.assignment, temp);
5906 }
5907 if (varNames.empty()) {
5495 varNames = arg.name; 5908 varNames = arg.name;
5496 else 5909 } else {
5497 varNames.append(", "s + arg.name); 5910 varNames.append(", "s + arg.name);
5911 }
5498 } 5912 }
5499 if (argDefList->varArg) { 5913 if (argDefList->varArg) {
5914 std::string varStr;
5915 if (auto varName = argDefList->varArg->name.get()) {
5916 varStr = variableToString(varName);
5917 int target = getLuaTarget(varName);
5918 forceAddToScope(varStr);
5919 if (target < 505) {
5920 temp.push_back(indent() + "local "s + varStr + " = {"s + nl(varName));
5921 temp.push_back(indent(1) + "n = "s + globalVar("select", varName, AccessType::Read) + "(\"#\", ...),"s + nl(varName));
5922 temp.push_back(indent(1) + "..."s + nl(varName));
5923 temp.push_back(indent() + '}' + nl(varName));
5924 varStr.clear();
5925 }
5926 }
5500 auto& arg = argItems.emplace_back(); 5927 auto& arg = argItems.emplace_back();
5501 arg.name = "..."sv; 5928 arg.name = "..."sv;
5502 if (varNames.empty()) 5929 if (varNames.empty()) {
5503 varNames = arg.name; 5930 varNames = arg.name + varStr;
5504 else 5931 } else {
5505 varNames.append(", "s + arg.name); 5932 varNames.append(", "s + arg.name + varStr);
5933 }
5506 _varArgs.top().hasVar = true; 5934 _varArgs.top().hasVar = true;
5507 } 5935 }
5508 if (assignSelf) { 5936 if (assignSelf) {
@@ -5571,6 +5999,45 @@ private:
5571 } 5999 }
5572 } 6000 }
5573 6001
6002 bool transformChainEndWithSlice(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) {
6003 auto x = chainList.front();
6004 if (ast_is<Slice_t>(chainList.back())) {
6005 auto comp = x->new_ptr<Comprehension_t>();
6006 {
6007 auto chainValue = x->new_ptr<ChainValue_t>();
6008 for (auto item : chainList) {
6009 chainValue->items.push_back(item);
6010 }
6011 auto itemVar = getUnusedName("_item_"sv);
6012 auto expCode = YueFormat{}.toString(chainValue);
6013 auto compCode = '[' + itemVar + " for "s + itemVar + " in *"s + expCode + ']';
6014 comp.set(toAst<Comprehension_t>(compCode, x));
6015 }
6016 switch (usage) {
6017 case ExpUsage::Assignment: {
6018 auto simpleValue = x->new_ptr<SimpleValue_t>();
6019 simpleValue->value.set(comp);
6020 auto exp = newExp(simpleValue, x);
6021 auto assignment = x->new_ptr<ExpListAssign_t>();
6022 assignment->expList.set(assignList);
6023 auto assign = x->new_ptr<Assign_t>();
6024 assign->values.push_back(exp);
6025 assignment->action.set(assign);
6026 transformAssignment(assignment, out);
6027 break;
6028 }
6029 case ExpUsage::Return:
6030 transformComprehension(comp, out, ExpUsage::Return);
6031 break;
6032 default:
6033 transformComprehension(comp, out, ExpUsage::Closure);
6034 break;
6035 }
6036 return true;
6037 }
6038 return false;
6039 }
6040
5574 bool transformChainEndWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) { 6041 bool transformChainEndWithEOP(const node_container& chainList, str_list& out, ExpUsage usage, ExpList_t* assignList) {
5575 auto x = chainList.front(); 6042 auto x = chainList.front();
5576 if (ast_is<ExistentialOp_t>(chainList.back())) { 6043 if (ast_is<ExistentialOp_t>(chainList.back())) {
@@ -5605,7 +6072,7 @@ private:
5605 case ExpUsage::Return: 6072 case ExpUsage::Return:
5606 transformParens(parens, out); 6073 transformParens(parens, out);
5607 out.back().insert(0, indent() + "return "s); 6074 out.back().insert(0, indent() + "return "s);
5608 out.back().append(nlr(x)); 6075 out.back().append(nl(x));
5609 break; 6076 break;
5610 default: 6077 default:
5611 transformParens(parens, out); 6078 transformParens(parens, out);
@@ -5676,7 +6143,7 @@ private:
5676 } 6143 }
5677 } 6144 }
5678 if (isScoped) { 6145 if (isScoped) {
5679 temp.push_back(indent() + "do"s + nll(x)); 6146 temp.push_back(indent() + "do"s + nl(x));
5680 pushScope(); 6147 pushScope();
5681 } 6148 }
5682 objVar = getUnusedName("_obj_"sv); 6149 objVar = getUnusedName("_obj_"sv);
@@ -5736,9 +6203,9 @@ private:
5736 _buf << typeVar << "=type "sv << objVar; 6203 _buf << typeVar << "=type "sv << objVar;
5737 auto typeAssign = toAst<ExpListAssign_t>(clearBuf(), partOne); 6204 auto typeAssign = toAst<ExpListAssign_t>(clearBuf(), partOne);
5738 transformAssignment(typeAssign, temp); 6205 transformAssignment(typeAssign, temp);
5739 _buf << indent() << "if \"table\" == " << typeVar << " or \"userdata\" == "sv << typeVar << " then"sv << nll(x); 6206 _buf << indent() << "if \"table\" == " << typeVar << " or \"userdata\" == "sv << typeVar << " then"sv << nl(x);
5740 } else { 6207 } else {
5741 _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nll(x); 6208 _buf << indent() << "if "sv << objVar << " ~= nil then"sv << nl(x);
5742 } 6209 }
5743 temp.push_back(clearBuf()); 6210 temp.push_back(clearBuf());
5744 pushScope(); 6211 pushScope();
@@ -5764,25 +6231,21 @@ private:
5764 case ExpUsage::Return: 6231 case ExpUsage::Return:
5765 case ExpUsage::Closure: { 6232 case ExpUsage::Closure: {
5766 auto exp = newExp(partTwo, x); 6233 auto exp = newExp(partTwo, x);
5767 auto ret = x->new_ptr<Return_t>(); 6234 auto ret = newReturn(exp);
5768 ret->explicitReturn = false;
5769 auto expListLow = x->new_ptr<ExpListLow_t>();
5770 expListLow->exprs.push_back(exp);
5771 ret->valueList.set(expListLow);
5772 transformReturn(ret, temp); 6235 transformReturn(ret, temp);
5773 break; 6236 break;
5774 } 6237 }
5775 } 6238 }
5776 popScope(); 6239 popScope();
5777 temp.push_back(indent() + "end"s + nlr(x)); 6240 temp.push_back(indent() + "end"s + nl(x));
5778 switch (usage) { 6241 switch (usage) {
5779 case ExpUsage::Return: 6242 case ExpUsage::Return:
5780 temp.push_back(indent() + "return nil"s + nlr(x)); 6243 temp.push_back(indent() + "return nil"s + nl(x));
5781 break; 6244 break;
5782 case ExpUsage::Closure: 6245 case ExpUsage::Closure:
5783 temp.push_back(indent() + "return nil"s + nlr(x)); 6246 temp.push_back(indent() + "return nil"s + nl(x));
5784 popScope(); 6247 popScope();
5785 *funcStart = anonFuncStart() + nll(x); 6248 *funcStart = anonFuncStart() + nl(x);
5786 temp.push_back(indent() + anonFuncEnd()); 6249 temp.push_back(indent() + anonFuncEnd());
5787 popAnonVarArg(); 6250 popAnonVarArg();
5788 popFunctionScope(); 6251 popFunctionScope();
@@ -5792,7 +6255,7 @@ private:
5792 } 6255 }
5793 if (isScoped) { 6256 if (isScoped) {
5794 popScope(); 6257 popScope();
5795 temp.push_back(indent() + "end"s + nlr(x)); 6258 temp.push_back(indent() + "end"s + nl(x));
5796 } 6259 }
5797 out.push_back(join(temp)); 6260 out.push_back(join(temp));
5798 return true; 6261 return true;
@@ -5809,7 +6272,7 @@ private:
5809 switch (usage) { 6272 switch (usage) {
5810 case ExpUsage::Assignment: 6273 case ExpUsage::Assignment:
5811 if (isScoped) { 6274 if (isScoped) {
5812 temp.push_back(indent() + "do"s + nll(x)); 6275 temp.push_back(indent() + "do"s + nl(x));
5813 pushScope(); 6276 pushScope();
5814 } 6277 }
5815 break; 6278 break;
@@ -5863,11 +6326,7 @@ private:
5863 switch (usage) { 6326 switch (usage) {
5864 case ExpUsage::Closure: 6327 case ExpUsage::Closure:
5865 case ExpUsage::Return: { 6328 case ExpUsage::Return: {
5866 auto returnNode = x->new_ptr<Return_t>(); 6329 auto returnNode = newReturn(funLit);
5867 returnNode->explicitReturn = false;
5868 auto expListLow = x->new_ptr<ExpListLow_t>();
5869 expListLow->exprs.push_back(funLit);
5870 returnNode->valueList.set(expListLow);
5871 transformReturn(returnNode, temp); 6330 transformReturn(returnNode, temp);
5872 break; 6331 break;
5873 } 6332 }
@@ -5887,12 +6346,12 @@ private:
5887 case ExpUsage::Assignment: 6346 case ExpUsage::Assignment:
5888 if (isScoped) { 6347 if (isScoped) {
5889 popScope(); 6348 popScope();
5890 temp.push_back(indent() + "end"s + nlr(x)); 6349 temp.push_back(indent() + "end"s + nl(x));
5891 } 6350 }
5892 break; 6351 break;
5893 case ExpUsage::Closure: 6352 case ExpUsage::Closure:
5894 popScope(); 6353 popScope();
5895 *funcStart = anonFuncStart() + nll(x); 6354 *funcStart = anonFuncStart() + nl(x);
5896 temp.push_back(indent() + anonFuncEnd()); 6355 temp.push_back(indent() + anonFuncEnd());
5897 popAnonVarArg(); 6356 popAnonVarArg();
5898 popFunctionScope(); 6357 popFunctionScope();
@@ -5968,7 +6427,7 @@ private:
5968 pushScope(); 6427 pushScope();
5969 } else if (usage != ExpUsage::Return) { 6428 } else if (usage != ExpUsage::Return) {
5970 if (isScoped) { 6429 if (isScoped) {
5971 temp.push_back(indent() + "do"s + nll(x)); 6430 temp.push_back(indent() + "do"s + nl(x));
5972 pushScope(); 6431 pushScope();
5973 } 6432 }
5974 } 6433 }
@@ -5998,25 +6457,17 @@ private:
5998 } 6457 }
5999 switch (usage) { 6458 switch (usage) {
6000 case ExpUsage::Closure: { 6459 case ExpUsage::Closure: {
6001 auto returnNode = x->new_ptr<Return_t>(); 6460 auto returnNode = newReturn(newChainExp);
6002 returnNode->explicitReturn = false;
6003 auto values = x->new_ptr<ExpListLow_t>();
6004 values->exprs.push_back(newChainExp);
6005 returnNode->valueList.set(values);
6006 transformReturn(returnNode, temp); 6461 transformReturn(returnNode, temp);
6007 popScope(); 6462 popScope();
6008 *funcStart = anonFuncStart() + nll(x); 6463 *funcStart = anonFuncStart() + nl(x);
6009 temp.push_back(indent() + anonFuncEnd()); 6464 temp.push_back(indent() + anonFuncEnd());
6010 popAnonVarArg(); 6465 popAnonVarArg();
6011 popFunctionScope(); 6466 popFunctionScope();
6012 break; 6467 break;
6013 } 6468 }
6014 case ExpUsage::Return: { 6469 case ExpUsage::Return: {
6015 auto returnNode = x->new_ptr<Return_t>(); 6470 auto returnNode = newReturn(newChainExp);
6016 returnNode->explicitReturn = false;
6017 auto values = x->new_ptr<ExpListLow_t>();
6018 values->exprs.push_back(newChainExp);
6019 returnNode->valueList.set(values);
6020 transformReturn(returnNode, temp); 6471 transformReturn(returnNode, temp);
6021 break; 6472 break;
6022 } 6473 }
@@ -6029,7 +6480,7 @@ private:
6029 transformAssignment(assignment, temp); 6480 transformAssignment(assignment, temp);
6030 if (isScoped) { 6481 if (isScoped) {
6031 popScope(); 6482 popScope();
6032 temp.push_back(indent() + "end"s + nlr(x)); 6483 temp.push_back(indent() + "end"s + nl(x));
6033 } 6484 }
6034 break; 6485 break;
6035 } 6486 }
@@ -6037,7 +6488,7 @@ private:
6037 transformExp(newChainExp, temp, usage); 6488 transformExp(newChainExp, temp, usage);
6038 if (isScoped) { 6489 if (isScoped) {
6039 popScope(); 6490 popScope();
6040 temp.push_back(indent() + "end"s + nlr(x)); 6491 temp.push_back(indent() + "end"s + nl(x));
6041 } 6492 }
6042 break; 6493 break;
6043 } 6494 }
@@ -6088,7 +6539,7 @@ private:
6088 case id<ColonChainItem_t>(): 6539 case id<ColonChainItem_t>():
6089 case id<Exp_t>(): 6540 case id<Exp_t>():
6090 if (_withVars.empty()) { 6541 if (_withVars.empty()) {
6091 throw CompileError("short dot/colon and indexing syntax must be called within a with block"sv, x); 6542 throw CompileError("short dot/colon/indexing syntax must be called within a with block"sv, x);
6092 } else { 6543 } else {
6093 temp.push_back(_withVars.top()); 6544 temp.push_back(_withVars.top());
6094 } 6545 }
@@ -6142,7 +6593,7 @@ private:
6142 assignment->action.set(assign); 6593 assignment->action.set(assign);
6143 auto stmt = x->new_ptr<Statement_t>(); 6594 auto stmt = x->new_ptr<Statement_t>();
6144 stmt->content.set(assignment); 6595 stmt->content.set(assignment);
6145 block->statements.push_back(stmt); 6596 block->statementOrComments.push_back(stmt);
6146 } 6597 }
6147 } 6598 }
6148 ast_ptr<false, Exp_t> nexp; 6599 ast_ptr<false, Exp_t> nexp;
@@ -6188,7 +6639,7 @@ private:
6188 expListAssign->expList.set(expList); 6639 expListAssign->expList.set(expList);
6189 auto stmt = x->new_ptr<Statement_t>(); 6640 auto stmt = x->new_ptr<Statement_t>();
6190 stmt->content.set(expListAssign); 6641 stmt->content.set(expListAssign);
6191 block->statements.push_back(stmt); 6642 block->statementOrComments.push_back(stmt);
6192 } 6643 }
6193 switch (usage) { 6644 switch (usage) {
6194 case ExpUsage::Common: 6645 case ExpUsage::Common:
@@ -6202,7 +6653,7 @@ private:
6202 default: 6653 default:
6203 break; 6654 break;
6204 } 6655 }
6205 if (block->statements.size() == 1) { 6656 if (block->statementOrComments.size() == 1) {
6206 transformExp(nexp, out, usage, assignList); 6657 transformExp(nexp, out, usage, assignList);
6207 } else { 6658 } else {
6208 auto body = x->new_ptr<Body_t>(); 6659 auto body = x->new_ptr<Body_t>();
@@ -6234,6 +6685,120 @@ private:
6234 } 6685 }
6235 return; 6686 return;
6236 } 6687 }
6688 break;
6689 }
6690 case id<ReversedIndex_t>(): {
6691 auto rIndex = static_cast<ReversedIndex_t*>(*it);
6692 auto current = it;
6693 auto prevChain = x->new_ptr<ChainValue_t>();
6694 for (auto i = chainList.begin(); i != current; ++i) {
6695 prevChain->items.push_back(*i);
6696 }
6697 auto var = singleVariableFrom(prevChain, AccessType::None);
6698 if (!var.empty() && isLocal(var)) {
6699 auto indexNode = toAst<Exp_t>('#' + var, rIndex);
6700 if (rIndex->modifier) {
6701 auto opValue = rIndex->new_ptr<ExpOpValue_t>();
6702 opValue->op.set(toAst<BinaryOperator_t>("-"sv, rIndex));
6703 opValue->pipeExprs.dup(rIndex->modifier->pipeExprs);
6704 indexNode->opValues.push_back(opValue);
6705 indexNode->opValues.dup(rIndex->modifier->opValues);
6706 indexNode->nilCoalesed.set(rIndex->modifier->nilCoalesed);
6707 }
6708 prevChain->items.push_back(indexNode);
6709 auto next = current;
6710 ++next;
6711 for (auto i = next; i != chainList.end(); ++i) {
6712 prevChain->items.push_back(*i);
6713 }
6714 if (usage == ExpUsage::Assignment) {
6715 auto assignment = x->new_ptr<ExpListAssign_t>();
6716 assignment->expList.set(assignList);
6717 auto assign = x->new_ptr<Assign_t>();
6718 assign->values.push_back(newExp(prevChain, x));
6719 assignment->action.set(assign);
6720 transformAssignment(assignment, out);
6721 return;
6722 }
6723 transformChainValue(prevChain, out, usage, assignList);
6724 return;
6725 } else {
6726 auto itemVar = getUnusedName("_item_"sv);
6727 auto asmt = assignmentFrom(toAst<Exp_t>(itemVar, x), newExp(prevChain, x), x);
6728 auto stmt1 = x->new_ptr<Statement_t>();
6729 stmt1->content.set(asmt);
6730 auto newChain = x->new_ptr<ChainValue_t>();
6731 newChain->items.push_back(toAst<Callable_t>(itemVar, x));
6732 auto indexNode = toAst<Exp_t>('#' + itemVar, rIndex);
6733 if (rIndex->modifier) {
6734 auto opValue = rIndex->new_ptr<ExpOpValue_t>();
6735 opValue->op.set(toAst<BinaryOperator_t>("-"sv, rIndex));
6736 opValue->pipeExprs.dup(rIndex->modifier->pipeExprs);
6737 indexNode->opValues.push_back(opValue);
6738 indexNode->opValues.dup(rIndex->modifier->opValues);
6739 indexNode->nilCoalesed.set(rIndex->modifier->nilCoalesed);
6740 }
6741 newChain->items.push_back(indexNode);
6742 auto expList = x->new_ptr<ExpList_t>();
6743 expList->exprs.push_back(newExp(newChain, x));
6744 auto expListAssign = x->new_ptr<ExpListAssign_t>();
6745 expListAssign->expList.set(expList);
6746 auto stmt2 = x->new_ptr<Statement_t>();
6747 stmt2->content.set(expListAssign);
6748 auto block = x->new_ptr<Block_t>();
6749 block->statementOrComments.push_back(stmt1);
6750 block->statementOrComments.push_back(stmt2);
6751 auto body = x->new_ptr<Body_t>();
6752 body->content.set(block);
6753 auto doNode = x->new_ptr<Do_t>();
6754 doNode->body.set(body);
6755 if (usage == ExpUsage::Assignment) {
6756 auto next = current;
6757 ++next;
6758 for (auto i = next; i != chainList.end(); ++i) {
6759 newChain->items.push_back(*i);
6760 }
6761 auto assignment = x->new_ptr<ExpListAssign_t>();
6762 assignment->expList.set(assignList);
6763 auto assign = x->new_ptr<Assign_t>();
6764 auto sVal = x->new_ptr<SimpleValue_t>();
6765 sVal->value.set(doNode);
6766 assign->values.push_back(newExp(sVal, x));
6767 assignment->action.set(assign);
6768 transformAssignment(assignment, out);
6769 return;
6770 }
6771 if (usage == ExpUsage::Closure) {
6772 auto next = current;
6773 ++next;
6774 if (next != chainList.end()) {
6775 doNode->new_ptr<ChainValue_t>();
6776 auto dVal = doNode->new_ptr<SimpleValue_t>();
6777 dVal->value.set(doNode);
6778 auto dExp = newExp(dVal, dVal);
6779 auto dParen = dExp->new_ptr<Parens_t>();
6780 dParen->extra = true;
6781 dParen->expr.set(dExp);
6782 auto dCallable = dExp->new_ptr<Callable_t>();
6783 dCallable->item.set(dParen);
6784 auto dChain = doNode->new_ptr<ChainValue_t>();
6785 dChain->items.push_back(dCallable);
6786 for (auto i = next; i != chainList.end(); ++i) {
6787 dChain->items.push_back(*i);
6788 }
6789 transformExp(newExp(dChain, dExp), out, usage);
6790 return;
6791 }
6792 }
6793 auto next = current;
6794 ++next;
6795 for (auto i = next; i != chainList.end(); ++i) {
6796 newChain->items.push_back(*i);
6797 }
6798 transformDo(doNode, out, usage);
6799 return;
6800 }
6801 break;
6237 } 6802 }
6238 } 6803 }
6239 } 6804 }
@@ -6283,10 +6848,10 @@ private:
6283 } 6848 }
6284 switch (usage) { 6849 switch (usage) {
6285 case ExpUsage::Common: 6850 case ExpUsage::Common:
6286 out.push_back(indent() + join(temp) + nll(x)); 6851 out.push_back(indent() + join(temp) + nl(x));
6287 break; 6852 break;
6288 case ExpUsage::Return: 6853 case ExpUsage::Return:
6289 out.push_back(indent() + "return "s + join(temp) + nll(x)); 6854 out.push_back(indent() + "return "s + join(temp) + nl(x));
6290 break; 6855 break;
6291 case ExpUsage::Assignment: YUEE("invalid expression usage", x); break; 6856 case ExpUsage::Assignment: YUEE("invalid expression usage", x); break;
6292 default: 6857 default:
@@ -6418,7 +6983,7 @@ private:
6418 } 6983 }
6419 } 6984 }
6420 } 6985 }
6421 int len = lua_objlen(L, -1); 6986 int len = static_cast<int>(lua_objlen(L, -1));
6422 lua_pushnil(L); // cur nil 6987 lua_pushnil(L); // cur nil
6423 for (int i = len; i >= 1; i--) { 6988 for (int i = len; i >= 1; i--) {
6424 lua_pop(L, 1); // cur 6989 lua_pop(L, 1); // cur
@@ -6430,7 +6995,25 @@ private:
6430 break; 6995 break;
6431 } 6996 }
6432 } 6997 }
6433 if (!lua_isfunction(L, -1)) { 6998 str_list checks;
6999 if (lua_istable(L, -1)) {
7000 lua_rawgeti(L, -1, 1); // cur macrotab checks
7001 int len = static_cast<int>(lua_objlen(L, -1));
7002 for (int i = 1; i <= len; i++) {
7003 lua_rawgeti(L, -1, i);
7004 if (lua_toboolean(L, -1) == 0) {
7005 checks.emplace_back();
7006 } else {
7007 size_t str_len = 0;
7008 auto str = lua_tolstring(L, -1, &str_len);
7009 checks.emplace_back(std::string{str, str_len});
7010 }
7011 lua_pop(L, 1);
7012 }
7013 lua_pop(L, 1);
7014 lua_rawgeti(L, -1, 2); // cur macrotab macroFunc
7015 lua_remove(L, -2); // cur macroFunc
7016 } else if (!lua_isfunction(L, -1)) {
6434 auto code = expandBuiltinMacro(macroName, x); 7017 auto code = expandBuiltinMacro(macroName, x);
6435 if (!code.empty()) return code; 7018 if (!code.empty()) return code;
6436 if (macroName == "is_ast"sv) { 7019 if (macroName == "is_ast"sv) {
@@ -6475,11 +7058,34 @@ private:
6475 } // cur macroFunc 7058 } // cur macroFunc
6476 pushYue("pcall"sv); // cur macroFunc pcall 7059 pushYue("pcall"sv); // cur macroFunc pcall
6477 lua_insert(L, -2); // cur pcall macroFunc 7060 lua_insert(L, -2); // cur pcall macroFunc
6478 if (!lua_checkstack(L, argStrs.size())) { 7061 if (!lua_checkstack(L, static_cast<int>(argStrs.size()))) {
6479 throw CompileError("too much macro params"s, x); 7062 throw CompileError("too much macro params"s, x);
6480 } 7063 }
7064 auto checkIt = checks.begin();
7065 node_container::const_iterator argIt;
7066 if (args) {
7067 argIt = args->begin();
7068 }
6481 for (const auto& arg : argStrs) { 7069 for (const auto& arg : argStrs) {
7070 if (checkIt != checks.end()) {
7071 if (checkIt->empty()) {
7072 ++checkIt;
7073 } else {
7074 if ((*checkIt)[0] == '.') {
7075 auto astName = checkIt->substr(3);
7076 if (!_parser.match(astName, arg)) {
7077 throw CompileError("expecting \""s + astName + "\", AST mismatch"s, *argIt);
7078 }
7079 } else {
7080 if (!_parser.match(*checkIt, arg)) {
7081 throw CompileError("expecting \""s + *checkIt + "\", AST mismatch"s, *argIt);
7082 }
7083 ++checkIt;
7084 }
7085 }
7086 }
6482 lua_pushlstring(L, arg.c_str(), arg.size()); 7087 lua_pushlstring(L, arg.c_str(), arg.size());
7088 ++argIt;
6483 } // cur pcall macroFunc args... 7089 } // cur pcall macroFunc args...
6484 bool success = lua_pcall(L, static_cast<int>(argStrs.size()), 1, 0) == 0; 7090 bool success = lua_pcall(L, static_cast<int>(argStrs.size()), 1, 0) == 0;
6485 if (!success) { // cur err 7091 if (!success) { // cur err
@@ -6571,8 +7177,8 @@ private:
6571 throw CompileError("lua macro is not expanding to valid block\n"s + err, x); 7177 throw CompileError("lua macro is not expanding to valid block\n"s + err, x);
6572 } 7178 }
6573 if (!codes.empty()) { 7179 if (!codes.empty()) {
6574 codes.insert(0, indent() + "do"s + nll(chainValue)); 7180 codes.insert(0, indent() + "do"s + nl(chainValue));
6575 codes.append(_newLine + indent() + "end"s + nlr(chainValue)); 7181 codes.append(_newLine + indent() + "end"s + nl(chainValue));
6576 } 7182 }
6577 return {nullptr, nullptr, std::move(codes), std::move(localVars)}; 7183 return {nullptr, nullptr, std::move(codes), std::move(localVars)};
6578 } else { 7184 } else {
@@ -6609,14 +7215,14 @@ private:
6609 } else { 7215 } else {
6610 if (!codes.empty()) { 7216 if (!codes.empty()) {
6611 if (isBlock) { 7217 if (isBlock) {
6612 info = _parser.parse<BlockEnd_t>(codes); 7218 info = _parser.parse<BlockEnd_t>(codes, false);
6613 if (info.error) { 7219 if (info.error) {
6614 throw CompileError("failed to expand macro as block: "s + info.error.value().msg, x); 7220 throw CompileError("failed to expand macro as block: "s + info.error.value().msg, x);
6615 } 7221 }
6616 } else { 7222 } else {
6617 info = _parser.parse<Exp_t>(codes); 7223 info = _parser.parse<Exp_t>(codes, false);
6618 if (!info.node && allowBlockMacroReturn) { 7224 if (!info.node && allowBlockMacroReturn) {
6619 info = _parser.parse<BlockEnd_t>(codes); 7225 info = _parser.parse<BlockEnd_t>(codes, false);
6620 if (info.error) { 7226 if (info.error) {
6621 throw CompileError("failed to expand macro as expr or block: "s + info.error.value().msg, x); 7227 throw CompileError("failed to expand macro as expr or block: "s + info.error.value().msg, x);
6622 } 7228 }
@@ -6661,7 +7267,7 @@ private:
6661 auto stmt = x->new_ptr<Statement_t>(); 7267 auto stmt = x->new_ptr<Statement_t>();
6662 stmt->content.set(exps); 7268 stmt->content.set(exps);
6663 auto block = x->new_ptr<Block_t>(); 7269 auto block = x->new_ptr<Block_t>();
6664 block->statements.push_back(stmt); 7270 block->statementOrComments.push_back(stmt);
6665 info.node.set(block); 7271 info.node.set(block);
6666 } else { 7272 } else {
6667 info.node.set(exp); 7273 info.node.set(exp);
@@ -6698,7 +7304,7 @@ private:
6698 return; 7304 return;
6699 } 7305 }
6700 if (usage == ExpUsage::Common || (usage == ExpUsage::Return && node.is<Block_t>())) { 7306 if (usage == ExpUsage::Common || (usage == ExpUsage::Return && node.is<Block_t>())) {
6701 if (node.to<Block_t>()->statements.empty()) { 7307 if (node.to<Block_t>()->statementOrComments.empty()) {
6702 out.push_back(Empty); 7308 out.push_back(Empty);
6703 } else { 7309 } else {
6704 auto doBody = node->new_ptr<Body_t>(); 7310 auto doBody = node->new_ptr<Body_t>();
@@ -6720,11 +7326,7 @@ private:
6720 break; 7326 break;
6721 } 7327 }
6722 case ExpUsage::Return: { 7328 case ExpUsage::Return: {
6723 auto expListLow = x->new_ptr<ExpListLow_t>(); 7329 auto returnNode = newReturn(node.to<Exp_t>());
6724 expListLow->exprs.push_back(node);
6725 auto returnNode = x->new_ptr<Return_t>();
6726 returnNode->explicitReturn = false;
6727 returnNode->valueList.set(expListLow);
6728 transformReturn(returnNode, out); 7330 transformReturn(returnNode, out);
6729 break; 7331 break;
6730 } 7332 }
@@ -6752,6 +7354,9 @@ private:
6752 if (transformChainEndWithColonItem(chainList, out, usage, assignList)) { 7354 if (transformChainEndWithColonItem(chainList, out, usage, assignList)) {
6753 return; 7355 return;
6754 } 7356 }
7357 if (transformChainEndWithSlice(chainList, out, usage, assignList)) {
7358 return;
7359 }
6755 transformChainList(chainList, out, usage, assignList); 7360 transformChainList(chainList, out, usage, assignList);
6756 } 7361 }
6757 7362
@@ -6848,7 +7453,7 @@ private:
6848 } 7453 }
6849 } 7454 }
6850 } else if (auto comp = sval->value.as<Comprehension_t>()) { 7455 } else if (auto comp = sval->value.as<Comprehension_t>()) {
6851 if (comp->items.size() != 2 || !ast_is<CompInner_t>(comp->items.back())) { 7456 if (!isListComp(comp)) {
6852 discrete = inExp->new_ptr<ExpList_t>(); 7457 discrete = inExp->new_ptr<ExpList_t>();
6853 for (ast_node* val : comp->items.objects()) { 7458 for (ast_node* val : comp->items.objects()) {
6854 if (auto def = ast_cast<NormalDef_t>(val)) { 7459 if (auto def = ast_cast<NormalDef_t>(val)) {
@@ -6877,7 +7482,7 @@ private:
6877 auto assignment = assignmentFrom(toAst<Exp_t>(checkVar, inExp), newExp(inExp, inExp), inExp); 7482 auto assignment = assignmentFrom(toAst<Exp_t>(checkVar, inExp), newExp(inExp, inExp), inExp);
6878 auto stmt = x->new_ptr<Statement_t>(); 7483 auto stmt = x->new_ptr<Statement_t>();
6879 stmt->content.set(assignment); 7484 stmt->content.set(assignment);
6880 block->statements.push_back(stmt); 7485 block->statementOrComments.push_back(stmt);
6881 } 7486 }
6882 if (varName.empty()) { 7487 if (varName.empty()) {
6883 auto newUnaryExp = x->new_ptr<UnaryExp_t>(); 7488 auto newUnaryExp = x->new_ptr<UnaryExp_t>();
@@ -6889,7 +7494,7 @@ private:
6889 auto assignment = assignmentFrom(assignExp, exp, x); 7494 auto assignment = assignmentFrom(assignExp, exp, x);
6890 auto stmt = x->new_ptr<Statement_t>(); 7495 auto stmt = x->new_ptr<Statement_t>();
6891 stmt->content.set(assignment); 7496 stmt->content.set(assignment);
6892 block->statements.push_back(stmt); 7497 block->statementOrComments.push_back(stmt);
6893 } 7498 }
6894 auto findVar = getUnusedName("_find_"); 7499 auto findVar = getUnusedName("_find_");
6895 auto itemVar = getUnusedName("_item_"); 7500 auto itemVar = getUnusedName("_item_");
@@ -6905,7 +7510,7 @@ private:
6905 } 7510 }
6906 auto blockStr = clearBuf(); 7511 auto blockStr = clearBuf();
6907 auto checkBlock = toAst<Block_t>(blockStr, inExp); 7512 auto checkBlock = toAst<Block_t>(blockStr, inExp);
6908 block->statements.dup(checkBlock->statements); 7513 block->statementOrComments.dup(checkBlock->statementOrComments);
6909 auto body = x->new_ptr<Body_t>(); 7514 auto body = x->new_ptr<Body_t>();
6910 body->content.set(block); 7515 body->content.set(block);
6911 auto doNode = x->new_ptr<Do_t>(); 7516 auto doNode = x->new_ptr<Do_t>();
@@ -6925,16 +7530,16 @@ private:
6925 } else { 7530 } else {
6926 auto arrayCheck = [&](bool exist) { 7531 auto arrayCheck = [&](bool exist) {
6927 auto indexVar = getUnusedName("_index_"); 7532 auto indexVar = getUnusedName("_index_");
6928 _buf << indent() << "for "sv << indexVar << " = 1, #"sv << checkVar << " do"sv << nll(x); 7533 _buf << indent() << "for "sv << indexVar << " = 1, #"sv << checkVar << " do"sv << nl(x);
6929 incIndentOffset(); 7534 incIndentOffset();
6930 _buf << indent() << "if "sv << checkVar << '[' << indexVar << "] == "sv << varName << " then"sv << nll(x); 7535 _buf << indent() << "if "sv << checkVar << '[' << indexVar << "] == "sv << varName << " then"sv << nl(x);
6931 incIndentOffset(); 7536 incIndentOffset();
6932 _buf << indent() << "return "sv << (exist ? "true"sv : "false"sv) << nll(x); 7537 _buf << indent() << "return "sv << (exist ? "true"sv : "false"sv) << nl(x);
6933 decIndentOffset(); 7538 decIndentOffset();
6934 _buf << indent() << "end"sv << nll(x); 7539 _buf << indent() << "end"sv << nl(x);
6935 decIndentOffset(); 7540 decIndentOffset();
6936 _buf << indent() << "end"sv << nll(x); 7541 _buf << indent() << "end"sv << nl(x);
6937 _buf << indent() << "return "sv << (exist ? "false"sv : "true"sv) << nll(x); 7542 _buf << indent() << "return "sv << (exist ? "false"sv : "true"sv) << nl(x);
6938 temp.push_back(clearBuf()); 7543 temp.push_back(clearBuf());
6939 }; 7544 };
6940 bool useShortCheck = (usage == ExpUsage::Closure) && !varName.empty() && !checkVar.empty() && isLocal(checkVar); 7545 bool useShortCheck = (usage == ExpUsage::Closure) && !varName.empty() && !checkVar.empty() && isLocal(checkVar);
@@ -6950,7 +7555,7 @@ private:
6950 pushAnonVarArg(); 7555 pushAnonVarArg();
6951 pushScope(); 7556 pushScope();
6952 arrayCheck(true); 7557 arrayCheck(true);
6953 temp.push_front("(#"s + checkVar + " > 0 and "s + anonFuncStart() + nll(x)); 7558 temp.push_front("(#"s + checkVar + " > 0 and "s + anonFuncStart() + nl(x));
6954 popScope(); 7559 popScope();
6955 temp.push_back(indent() + anonFuncEnd() + ')'); 7560 temp.push_back(indent() + anonFuncEnd() + ')');
6956 if (unary_exp->inExp->not_) { 7561 if (unary_exp->inExp->not_) {
@@ -6987,7 +7592,7 @@ private:
6987 arrayCheck(!unary_exp->inExp->not_); 7592 arrayCheck(!unary_exp->inExp->not_);
6988 } else { 7593 } else {
6989 arrayCheck(!unary_exp->inExp->not_); 7594 arrayCheck(!unary_exp->inExp->not_);
6990 temp.push_front(anonFuncStart() + nll(x)); 7595 temp.push_front(anonFuncStart() + nl(x));
6991 popScope(); 7596 popScope();
6992 temp.push_back(indent() + anonFuncEnd()); 7597 temp.push_back(indent() + anonFuncEnd());
6993 popAnonVarArg(); 7598 popAnonVarArg();
@@ -7027,7 +7632,7 @@ private:
7027 pushScope(); 7632 pushScope();
7028 } else if (usage == ExpUsage::Assignment) { 7633 } else if (usage == ExpUsage::Assignment) {
7029 if (isScoped) { 7634 if (isScoped) {
7030 temp.push_back(indent() + "do"s + nll(x)); 7635 temp.push_back(indent() + "do"s + nl(x));
7031 pushScope(); 7636 pushScope();
7032 } 7637 }
7033 } 7638 }
@@ -7067,10 +7672,10 @@ private:
7067 if (unary_exp->inExp->not_) { 7672 if (unary_exp->inExp->not_) {
7068 _buf << ")"sv; 7673 _buf << ")"sv;
7069 } 7674 }
7070 _buf << nll(x); 7675 _buf << nl(x);
7071 temp.push_back(clearBuf()); 7676 temp.push_back(clearBuf());
7072 if (usage == ExpUsage::Closure) { 7677 if (usage == ExpUsage::Closure) {
7073 temp.push_front(anonFuncStart() + nll(x)); 7678 temp.push_front(anonFuncStart() + nl(x));
7074 popScope(); 7679 popScope();
7075 temp.push_back(indent() + anonFuncEnd()); 7680 temp.push_back(indent() + anonFuncEnd());
7076 out.push_back(join(temp)); 7681 out.push_back(join(temp));
@@ -7079,7 +7684,7 @@ private:
7079 } else if (usage == ExpUsage::Assignment) { 7684 } else if (usage == ExpUsage::Assignment) {
7080 if (isScoped) { 7685 if (isScoped) {
7081 popScope(); 7686 popScope();
7082 temp.push_back(indent() + "end"s + nll(x)); 7687 temp.push_back(indent() + "end"s + nl(x));
7083 } 7688 }
7084 out.push_back(join(temp)); 7689 out.push_back(join(temp));
7085 } else { 7690 } else {
@@ -7113,7 +7718,7 @@ private:
7113 } 7718 }
7114 _buf << ')'; 7719 _buf << ')';
7115 if (usage == ExpUsage::Assignment || usage == ExpUsage::Return) { 7720 if (usage == ExpUsage::Assignment || usage == ExpUsage::Return) {
7116 _buf << nll(discrete); 7721 _buf << nl(discrete);
7117 } 7722 }
7118 out.push_back(clearBuf()); 7723 out.push_back(clearBuf());
7119 } 7724 }
@@ -7153,7 +7758,7 @@ private:
7153 try { 7758 try {
7154 unsigned long long value = std::stoull(binaryPart, nullptr, 2); 7759 unsigned long long value = std::stoull(binaryPart, nullptr, 2);
7155 numStr = std::to_string(value); 7760 numStr = std::to_string(value);
7156 } catch (const std::exception& e) { 7761 } catch (const std::exception&) {
7157 throw CompileError("invalid binary literal"sv, num); 7762 throw CompileError("invalid binary literal"sv, num);
7158 } 7763 }
7159 } else if (getLuaTarget(num) < 502) { 7764 } else if (getLuaTarget(num) < 502) {
@@ -7233,7 +7838,7 @@ private:
7233 forceAddToScope(tableVar); 7838 forceAddToScope(tableVar);
7234 auto it = values.begin(); 7839 auto it = values.begin();
7235 if (ast_is<SpreadExp_t, SpreadListExp_t>(*it)) { 7840 if (ast_is<SpreadExp_t, SpreadListExp_t>(*it)) {
7236 temp.push_back(indent() + "local "s + tableVar + " = { }"s + nll(x)); 7841 temp.push_back(indent() + "local "s + tableVar + " = { }"s + nl(x));
7237 } else { 7842 } else {
7238 auto initialTab = x->new_ptr<TableLit_t>(); 7843 auto initialTab = x->new_ptr<TableLit_t>();
7239 while (it != values.end() && !ast_is<SpreadExp_t, SpreadListExp_t>(*it)) { 7844 while (it != values.end() && !ast_is<SpreadExp_t, SpreadListExp_t>(*it)) {
@@ -7241,7 +7846,7 @@ private:
7241 ++it; 7846 ++it;
7242 } 7847 }
7243 transformTable(initialTab->values.objects(), temp); 7848 transformTable(initialTab->values.objects(), temp);
7244 temp.back() = indent() + "local "s + tableVar + " = "s + temp.back() + nll(*it); 7849 temp.back() = indent() + "local "s + tableVar + " = "s + temp.back() + nl(*it);
7245 } 7850 }
7246 for (; it != values.end(); ++it) { 7851 for (; it != values.end(); ++it) {
7247 auto item = *it; 7852 auto item = *it;
@@ -7261,14 +7866,14 @@ private:
7261 transformAssignment(assignment, temp); 7866 transformAssignment(assignment, temp);
7262 } 7867 }
7263 forceAddToScope(indexVar); 7868 forceAddToScope(indexVar);
7264 temp.push_back(indent() + "local "s + indexVar + " = 1"s + nll(item)); 7869 temp.push_back(indent() + "local "s + indexVar + " = 1"s + nl(item));
7265 _buf << "for "sv << keyVar << ',' << valueVar << " in pairs "sv << objVar 7870 _buf << "for "sv << keyVar << ',' << valueVar << " in pairs "sv << objVar
7266 << "\n\tif "sv << indexVar << "=="sv << keyVar 7871 << "\n\tif "sv << indexVar << "=="sv << keyVar
7267 << "\n\t\t"sv << tableVar << "[]="sv << valueVar 7872 << "\n\t\t"sv << tableVar << "[]="sv << valueVar
7268 << "\n\t\t"sv << indexVar << "+=1"sv 7873 << "\n\t\t"sv << indexVar << "+=1"sv
7269 << "\n\telse "sv << tableVar << '[' << keyVar << "]="sv << valueVar; 7874 << "\n\telse "sv << tableVar << '[' << keyVar << "]="sv << valueVar;
7270 auto forEach = toAst<ForEach_t>(clearBuf(), item); 7875 auto forNode = toAst<For_t>(clearBuf(), item);
7271 transformForEach(forEach, temp); 7876 transformFor(forNode, temp);
7272 break; 7877 break;
7273 } 7878 }
7274 case id<SpreadListExp_t>(): { 7879 case id<SpreadListExp_t>(): {
@@ -7285,12 +7890,12 @@ private:
7285 transformAssignment(assignment, temp); 7890 transformAssignment(assignment, temp);
7286 } 7891 }
7287 forceAddToScope(indexVar); 7892 forceAddToScope(indexVar);
7288 temp.push_back(indent() + "local "s + indexVar + " = #"s + tableVar + " + 1"s + nll(item)); 7893 temp.push_back(indent() + "local "s + indexVar + " = #"s + tableVar + " + 1"s + nl(item));
7289 _buf << "for "sv << valueVar << " in *"sv << objVar 7894 _buf << "for "sv << valueVar << " in *"sv << objVar
7290 << "\n\t"sv << tableVar << '[' << indexVar << "]="sv << valueVar 7895 << "\n\t"sv << tableVar << '[' << indexVar << "]="sv << valueVar
7291 << "\n\t"sv << indexVar << "+=1"sv; 7896 << "\n\t"sv << indexVar << "+=1"sv;
7292 auto forEach = toAst<ForEach_t>(clearBuf(), item); 7897 auto forNode = toAst<For_t>(clearBuf(), item);
7293 transformForEach(forEach, temp); 7898 transformFor(forNode, temp);
7294 break; 7899 break;
7295 } 7900 }
7296 case id<VariablePair_t>(): 7901 case id<VariablePair_t>():
@@ -7468,9 +8073,9 @@ private:
7468 break; 8073 break;
7469 case ExpUsage::Closure: { 8074 case ExpUsage::Closure: {
7470 out.push_back(join(temp)); 8075 out.push_back(join(temp));
7471 out.back().append(indent() + "return "s + tableVar + nlr(x)); 8076 out.back().append(indent() + "return "s + tableVar + nl(x));
7472 popScope(); 8077 popScope();
7473 out.back().insert(0, anonFuncStart() + nll(x)); 8078 out.back().insert(0, anonFuncStart() + nl(x));
7474 out.back().append(indent() + anonFuncEnd()); 8079 out.back().append(indent() + anonFuncEnd());
7475 popAnonVarArg(); 8080 popAnonVarArg();
7476 popFunctionScope(); 8081 popFunctionScope();
@@ -7486,13 +8091,13 @@ private:
7486 if (extraScope) popScope(); 8091 if (extraScope) popScope();
7487 out.push_back(join(temp)); 8092 out.push_back(join(temp));
7488 if (extraScope) { 8093 if (extraScope) {
7489 out.back() = indent() + "do"s + nll(x) + out.back() + indent() + "end"s + nlr(x); 8094 out.back() = indent() + "do"s + nl(x) + out.back() + indent() + "end"s + nl(x);
7490 } 8095 }
7491 break; 8096 break;
7492 } 8097 }
7493 case ExpUsage::Return: 8098 case ExpUsage::Return:
7494 out.push_back(join(temp)); 8099 out.push_back(join(temp));
7495 out.back().append(indent() + "return "s + tableVar + nlr(x)); 8100 out.back().append(indent() + "return "s + tableVar + nl(x));
7496 break; 8101 break;
7497 default: 8102 default:
7498 break; 8103 break;
@@ -7613,11 +8218,11 @@ private:
7613 default: YUEE("AST node mismatch", item); break; 8218 default: YUEE("AST node mismatch", item); break;
7614 } 8219 }
7615 if (!isMetamethod) { 8220 if (!isMetamethod) {
7616 temp.back() = indent() + (value == values.back() ? temp.back() : temp.back() + ',') + nll(value); 8221 temp.back() = indent() + (value == values.back() ? temp.back() : temp.back() + ',') + nl(value);
7617 } 8222 }
7618 } 8223 }
7619 if (metatable->pairs.empty() && !metatableItem) { 8224 if (metatable->pairs.empty() && !metatableItem) {
7620 out.push_back('{' + nll(x) + join(temp)); 8225 out.push_back('{' + nl(x) + join(temp));
7621 decIndentOffset(); 8226 decIndentOffset();
7622 out.back() += (indent() + '}'); 8227 out.back() += (indent() + '}');
7623 } else { 8228 } else {
@@ -7627,7 +8232,7 @@ private:
7627 decIndentOffset(); 8232 decIndentOffset();
7628 tabStr += "{ }"sv; 8233 tabStr += "{ }"sv;
7629 } else { 8234 } else {
7630 tabStr += ('{' + nll(x) + join(temp)); 8235 tabStr += ('{' + nl(x) + join(temp));
7631 decIndentOffset(); 8236 decIndentOffset();
7632 tabStr += (indent() + '}'); 8237 tabStr += (indent() + '}');
7633 } 8238 }
@@ -7671,18 +8276,18 @@ private:
7671 void transformCompCommon(Comprehension_t* comp, str_list& out) { 8276 void transformCompCommon(Comprehension_t* comp, str_list& out) {
7672 str_list temp; 8277 str_list temp;
7673 auto x = comp; 8278 auto x = comp;
7674 auto compInner = static_cast<CompInner_t*>(comp->items.back()); 8279 auto compFor = static_cast<CompFor_t*>(comp->items.back());
7675 for (auto item : compInner->items.objects()) { 8280 for (auto item : compFor->items.objects()) {
7676 switch (item->get_id()) { 8281 switch (item->get_id()) {
7677 case id<CompForEach_t>(): 8282 case id<CompForEach_t>():
7678 transformCompForEach(static_cast<CompForEach_t*>(item), temp); 8283 transformCompForEach(static_cast<CompForEach_t*>(item), temp);
7679 break; 8284 break;
7680 case id<CompFor_t>(): 8285 case id<CompForNum_t>():
7681 transformCompFor(static_cast<CompFor_t*>(item), temp); 8286 transformCompForNum(static_cast<CompForNum_t*>(item), temp);
7682 break; 8287 break;
7683 case id<Exp_t>(): 8288 case id<Exp_t>():
7684 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure); 8289 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure);
7685 temp.back() = indent() + "if "s + temp.back() + " then"s + nll(item); 8290 temp.back() = indent() + "if "s + temp.back() + " then"s + nl(item);
7686 pushScope(); 8291 pushScope();
7687 break; 8292 break;
7688 default: YUEE("AST node mismatch", item); break; 8293 default: YUEE("AST node mismatch", item); break;
@@ -7702,16 +8307,16 @@ private:
7702 auto value = std::move(temp.back()); 8307 auto value = std::move(temp.back());
7703 temp.pop_back(); 8308 temp.pop_back();
7704 _buf << join(temp) << value; 8309 _buf << join(temp) << value;
7705 for (size_t i = 0; i < compInner->items.objects().size(); ++i) { 8310 for (size_t i = 0; i < compFor->items.objects().size(); ++i) {
7706 popScope(); 8311 popScope();
7707 _buf << indent() << "end"sv << nll(comp); 8312 _buf << indent() << "end"sv << nl(comp);
7708 } 8313 }
7709 out.push_back(clearBuf()); 8314 out.push_back(clearBuf());
7710 } 8315 }
7711 8316
7712 void transformComprehension(Comprehension_t* comp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { 8317 void transformComprehension(Comprehension_t* comp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
7713 auto x = comp; 8318 auto x = comp;
7714 if (comp->items.size() != 2 || !ast_is<CompInner_t>(comp->items.back())) { 8319 if (!isListComp(comp)) {
7715 switch (usage) { 8320 switch (usage) {
7716 case ExpUsage::Assignment: { 8321 case ExpUsage::Assignment: {
7717 auto tableLit = x->new_ptr<TableLit_t>(); 8322 auto tableLit = x->new_ptr<TableLit_t>();
@@ -7733,11 +8338,7 @@ private:
7733 auto simpleValue = x->new_ptr<SimpleValue_t>(); 8338 auto simpleValue = x->new_ptr<SimpleValue_t>();
7734 simpleValue->value.set(tableLit); 8339 simpleValue->value.set(tableLit);
7735 auto exp = newExp(simpleValue, x); 8340 auto exp = newExp(simpleValue, x);
7736 auto returnNode = x->new_ptr<Return_t>(); 8341 auto returnNode = newReturn(exp);
7737 returnNode->explicitReturn = false;
7738 auto expList = x->new_ptr<ExpListLow_t>();
7739 expList->exprs.push_back(exp);
7740 returnNode->valueList.set(expList);
7741 transformReturn(returnNode, out); 8342 transformReturn(returnNode, out);
7742 break; 8343 break;
7743 } 8344 }
@@ -7750,9 +8351,16 @@ private:
7750 } 8351 }
7751 return; 8352 return;
7752 } 8353 }
7753 auto def = ast_cast<NormalDef_t>(comp->items.front()); 8354 ast_node* value = nullptr;
7754 if (!def || def->defVal) { 8355 bool isSpread = ast_is<SpreadListExp_t>(comp->items.front());
7755 throw CompileError("invalid comprehension expression", comp->items.front()); 8356 if (isSpread) {
8357 value = comp->items.front();
8358 } else {
8359 auto def = ast_cast<NormalDef_t>(comp->items.front());
8360 if (!def || def->defVal) {
8361 throw CompileError("invalid comprehension expression", comp->items.front());
8362 }
8363 value = def->item.get();
7756 } 8364 }
7757 bool extraScope = false; 8365 bool extraScope = false;
7758 switch (usage) { 8366 switch (usage) {
@@ -7776,31 +8384,33 @@ private:
7776 default: 8384 default:
7777 break; 8385 break;
7778 } 8386 }
7779 auto value = def->item.get(); 8387 auto compFor = static_cast<CompFor_t*>(comp->items.back());
7780 auto compInner = static_cast<CompInner_t*>(comp->items.back());
7781 str_list temp; 8388 str_list temp;
7782 std::string accumVar = getUnusedName("_accum_"sv); 8389 std::string accumVar = getUnusedName("_accum_"sv);
7783 std::string lenVar = getUnusedName("_len_"sv);
7784 addToScope(accumVar); 8390 addToScope(accumVar);
7785 addToScope(lenVar); 8391 std::string lenVar;
7786 for (auto item : compInner->items.objects()) { 8392 if (!isSpread) {
8393 lenVar = getUnusedName("_len_"sv);
8394 addToScope(lenVar);
8395 }
8396 for (auto item : compFor->items.objects()) {
7787 switch (item->get_id()) { 8397 switch (item->get_id()) {
7788 case id<CompForEach_t>(): 8398 case id<CompForEach_t>():
7789 transformCompForEach(static_cast<CompForEach_t*>(item), temp); 8399 transformCompForEach(static_cast<CompForEach_t*>(item), temp);
7790 break; 8400 break;
7791 case id<CompFor_t>(): 8401 case id<CompForNum_t>():
7792 transformCompFor(static_cast<CompFor_t*>(item), temp); 8402 transformCompForNum(static_cast<CompForNum_t*>(item), temp);
7793 break; 8403 break;
7794 case id<Exp_t>(): 8404 case id<Exp_t>():
7795 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure); 8405 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure);
7796 temp.back() = indent() + "if "s + temp.back() + " then"s + nll(item); 8406 temp.back() = indent() + "if "s + temp.back() + " then"s + nl(item);
7797 pushScope(); 8407 pushScope();
7798 break; 8408 break;
7799 default: YUEE("AST node mismatch", item); break; 8409 default: YUEE("AST node mismatch", item); break;
7800 } 8410 }
7801 } 8411 }
7802 { 8412 {
7803 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); 8413 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + (isSpread ? "]"s : lenVar + ']'), x);
7804 auto assign = x->new_ptr<Assign_t>(); 8414 auto assign = x->new_ptr<Assign_t>();
7805 assign->values.push_back(value); 8415 assign->values.push_back(value);
7806 auto assignment = x->new_ptr<ExpListAssign_t>(); 8416 auto assignment = x->new_ptr<ExpListAssign_t>();
@@ -7810,25 +8420,30 @@ private:
7810 } 8420 }
7811 auto assignStr = std::move(temp.back()); 8421 auto assignStr = std::move(temp.back());
7812 temp.pop_back(); 8422 temp.pop_back();
7813 for (size_t i = 0; i < compInner->items.objects().size(); ++i) { 8423 for (size_t i = 0; i < compFor->items.objects().size(); ++i) {
7814 popScope(); 8424 popScope();
7815 } 8425 }
7816 _buf << indent() << "local "sv << accumVar << " = { }"sv << nll(comp); 8426 _buf << indent() << "local "sv << accumVar << " = { }"sv << nl(comp);
7817 _buf << indent() << "local "sv << lenVar << " = 1"sv << nll(comp); 8427 if (isSpread) {
7818 _buf << join(temp); 8428 _buf << join(temp);
7819 _buf << assignStr; 8429 _buf << assignStr;
7820 _buf << indent(int(temp.size())) << lenVar << " = "sv << lenVar << " + 1"sv << nll(comp); 8430 } else {
8431 _buf << indent() << "local "sv << lenVar << " = 1"sv << nl(comp);
8432 _buf << join(temp);
8433 _buf << assignStr;
8434 _buf << indent(int(temp.size())) << lenVar << " = "sv << lenVar << " + 1"sv << nl(comp);
8435 }
7821 for (int ind = int(temp.size()) - 1; ind > -1; --ind) { 8436 for (int ind = int(temp.size()) - 1; ind > -1; --ind) {
7822 _buf << indent(ind) << "end"sv << nll(comp); 8437 _buf << indent(ind) << "end"sv << nl(comp);
7823 } 8438 }
7824 switch (usage) { 8439 switch (usage) {
7825 case ExpUsage::Common: 8440 case ExpUsage::Common:
7826 break; 8441 break;
7827 case ExpUsage::Closure: { 8442 case ExpUsage::Closure: {
7828 out.push_back(clearBuf()); 8443 out.push_back(clearBuf());
7829 out.back().append(indent() + "return "s + accumVar + nlr(comp)); 8444 out.back().append(indent() + "return "s + accumVar + nl(comp));
7830 popScope(); 8445 popScope();
7831 out.back().insert(0, anonFuncStart() + nll(comp)); 8446 out.back().insert(0, anonFuncStart() + nl(comp));
7832 out.back().append(indent() + anonFuncEnd()); 8447 out.back().append(indent() + anonFuncEnd());
7833 popAnonVarArg(); 8448 popAnonVarArg();
7834 popFunctionScope(); 8449 popFunctionScope();
@@ -7845,13 +8460,13 @@ private:
7845 out.back().append(temp.back()); 8460 out.back().append(temp.back());
7846 if (extraScope) { 8461 if (extraScope) {
7847 popScope(); 8462 popScope();
7848 out.back() = indent() + "do"s + nll(comp) + out.back() + indent() + "end"s + nlr(comp); 8463 out.back() = indent() + "do"s + nl(comp) + out.back() + indent() + "end"s + nl(comp);
7849 } 8464 }
7850 break; 8465 break;
7851 } 8466 }
7852 case ExpUsage::Return: 8467 case ExpUsage::Return:
7853 out.push_back(clearBuf()); 8468 out.push_back(clearBuf());
7854 out.back().append(indent() + "return "s + accumVar + nlr(comp)); 8469 out.back().append(indent() + "return "s + accumVar + nl(comp));
7855 break; 8470 break;
7856 default: 8471 default:
7857 break; 8472 break;
@@ -7859,6 +8474,11 @@ private:
7859 } 8474 }
7860 8475
7861 bool transformForEachHead(AssignableNameList_t* nameList, ast_node* loopTarget, str_list& out, bool inClosure) { 8476 bool transformForEachHead(AssignableNameList_t* nameList, ast_node* loopTarget, str_list& out, bool inClosure) {
8477 enum class NumState {
8478 Unknown,
8479 Positive,
8480 Negtive
8481 };
7862 auto x = nameList; 8482 auto x = nameList;
7863 str_list temp; 8483 str_list temp;
7864 str_list vars; 8484 str_list vars;
@@ -7877,13 +8497,8 @@ private:
7877 varConstAfter = vars.back(); 8497 varConstAfter = vars.back();
7878 } 8498 }
7879 break; 8499 break;
7880 case id<TableLit_t>(): { 8500 case id<SimpleTable_t>():
7881 auto desVar = getUnusedName("_des_"sv); 8501 case id<TableLit_t>():
7882 destructPairs.emplace_back(item, toAst<Exp_t>(desVar, x));
7883 vars.push_back(desVar);
7884 varAfter.push_back(desVar);
7885 break;
7886 }
7887 case id<Comprehension_t>(): { 8502 case id<Comprehension_t>(): {
7888 auto desVar = getUnusedName("_des_"sv); 8503 auto desVar = getUnusedName("_des_"sv);
7889 destructPairs.emplace_back(item, toAst<Exp_t>(desVar, x)); 8504 destructPairs.emplace_back(item, toAst<Exp_t>(desVar, x));
@@ -7925,15 +8540,35 @@ private:
7925 for (auto item : chainList) { 8540 for (auto item : chainList) {
7926 chain->items.push_back(item); 8541 chain->items.push_back(item);
7927 } 8542 }
7928 std::string startValue("1"sv); 8543 std::string startValue;
8544 NumState startStatus = NumState::Unknown;
7929 if (auto exp = slice->startValue.as<Exp_t>()) { 8545 if (auto exp = slice->startValue.as<Exp_t>()) {
7930 transformExp(exp, temp, ExpUsage::Closure); 8546 transformExp(exp, temp, ExpUsage::Closure);
8547 if (temp.back().at(0) == '-') {
8548 if (_parser.match<Num_t>(temp.back().substr(1))) {
8549 startStatus = NumState::Negtive;
8550 }
8551 } else {
8552 if (_parser.match<Num_t>(temp.back())) {
8553 startStatus = NumState::Positive;
8554 }
8555 }
7931 startValue = std::move(temp.back()); 8556 startValue = std::move(temp.back());
7932 temp.pop_back(); 8557 temp.pop_back();
7933 } 8558 }
7934 std::string stopValue; 8559 std::string stopValue;
8560 NumState stopStatus = NumState::Unknown;
7935 if (auto exp = slice->stopValue.as<Exp_t>()) { 8561 if (auto exp = slice->stopValue.as<Exp_t>()) {
7936 transformExp(exp, temp, ExpUsage::Closure); 8562 transformExp(exp, temp, ExpUsage::Closure);
8563 if (temp.back().at(0) == '-') {
8564 if (_parser.match<Num_t>(temp.back().substr(1))) {
8565 stopStatus = NumState::Negtive;
8566 }
8567 } else {
8568 if (_parser.match<Num_t>(temp.back())) {
8569 stopStatus = NumState::Positive;
8570 }
8571 }
7937 stopValue = std::move(temp.back()); 8572 stopValue = std::move(temp.back());
7938 temp.pop_back(); 8573 temp.pop_back();
7939 } 8574 }
@@ -7947,38 +8582,94 @@ private:
7947 std::string prefix; 8582 std::string prefix;
7948 if (!inClosure && needScope) { 8583 if (!inClosure && needScope) {
7949 extraScope = true; 8584 extraScope = true;
7950 prefix = indent() + "do"s + nll(x); 8585 prefix = indent() + "do"s + nl(x);
7951 pushScope(); 8586 pushScope();
7952 } 8587 }
7953 listVar = getUnusedName("_list_"sv); 8588 listVar = getUnusedName("_list_"sv);
7954 varBefore.push_back(listVar); 8589 varBefore.push_back(listVar);
7955 transformChainValue(chain, temp, ExpUsage::Closure); 8590 transformChainValue(chain, temp, ExpUsage::Closure);
7956 _buf << prefix << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList); 8591 _buf << prefix << indent() << "local "sv << listVar << " = "sv << temp.back() << nl(nameList);
8592 }
8593 if (startValue.empty()) {
8594 startValue = "1"s;
8595 startStatus = NumState::Positive;
8596 }
8597 std::string minVar;
8598 if (startStatus != NumState::Positive) {
8599 std::string prefix;
8600 if (!extraScope && !inClosure && needScope) {
8601 extraScope = true;
8602 prefix = indent() + "do"s + nl(x);
8603 pushScope();
8604 }
8605 minVar = getUnusedName("_min_"sv);
8606 varBefore.push_back(minVar);
8607 if (startStatus == NumState::Negtive) {
8608 _buf << prefix << indent() << "local "sv << minVar << " = "sv << "#"sv << listVar << " + "sv << startValue << " + 1"sv << nl(nameList);
8609 } else {
8610 _buf << prefix << indent() << "local "sv << minVar << " = "sv << startValue << nl(nameList);
8611 }
8612 }
8613 bool defaultStop = false;
8614 if (stopValue.empty()) {
8615 stopValue = "#"s + listVar;
8616 defaultStop = true;
7957 } 8617 }
7958 std::string maxVar; 8618 std::string maxVar;
7959 if (!stopValue.empty()) { 8619 if (stopStatus != NumState::Positive) {
7960 std::string prefix; 8620 std::string prefix;
7961 if (!extraScope && !inClosure && needScope) { 8621 if (!extraScope && !inClosure && needScope) {
7962 extraScope = true; 8622 extraScope = true;
7963 prefix = indent() + "do"s + nll(x); 8623 prefix = indent() + "do"s + nl(x);
7964 pushScope(); 8624 pushScope();
7965 } 8625 }
7966 maxVar = getUnusedName("_max_"sv); 8626 maxVar = getUnusedName("_max_"sv);
7967 varBefore.push_back(maxVar); 8627 varBefore.push_back(maxVar);
7968 _buf << prefix << indent() << "local "sv << maxVar << " = "sv << stopValue << nll(nameList); 8628 if (stopStatus == NumState::Negtive) {
8629 _buf << indent() << "local "sv << maxVar << " = "sv << "#"sv << listVar << " + "sv << stopValue << " + 1"sv << nl(nameList);
8630 } else {
8631 _buf << prefix << indent() << "local "sv << maxVar << " = "sv << stopValue << nl(nameList);
8632 }
8633 }
8634 if (startStatus == NumState::Unknown) {
8635 _buf << indent() << minVar << " = "sv << minVar << " < 0 and #"sv << listVar << " + "sv << minVar << " + 1 or "sv << minVar << nl(nameList);
8636 }
8637 if (!defaultStop && stopStatus == NumState::Unknown) {
8638 _buf << indent() << maxVar << " = "sv << maxVar << " < 0 and #"sv << listVar << " + "sv << maxVar << " + 1 or "sv << maxVar << nl(nameList);
7969 } 8639 }
7970 _buf << indent() << "for "sv << indexVar << " = "sv; 8640 _buf << indent() << "for "sv << indexVar << " = "sv;
7971 _buf << startValue << ", "sv; 8641 if (startValue.empty()) {
8642 _buf << "1"sv;
8643 } else {
8644 switch (startStatus) {
8645 case NumState::Unknown:
8646 case NumState::Negtive:
8647 _buf << minVar;
8648 break;
8649 case NumState::Positive:
8650 _buf << startValue;
8651 break;
8652 }
8653 }
8654 _buf << ", "sv;
7972 if (stopValue.empty()) { 8655 if (stopValue.empty()) {
7973 _buf << "#"sv << listVar; 8656 _buf << "#"sv << listVar;
7974 } else { 8657 } else {
7975 _buf << maxVar << " < 0 and #"sv << listVar << " + "sv << maxVar << " or "sv << maxVar; 8658 switch (stopStatus) {
8659 case NumState::Unknown:
8660 case NumState::Negtive:
8661 _buf << maxVar;
8662 break;
8663 case NumState::Positive:
8664 _buf << stopValue;
8665 break;
8666 }
7976 } 8667 }
7977 if (!stepValue.empty()) { 8668 if (!stepValue.empty()) {
7978 _buf << ", "sv << stepValue; 8669 _buf << ", "sv << stepValue;
7979 } 8670 }
7980 _buf << " do"sv << nlr(loopTarget); 8671 _buf << " do"sv << nl(loopTarget);
7981 _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nll(nameList); 8672 _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nl(nameList);
7982 out.push_back(clearBuf()); 8673 out.push_back(clearBuf());
7983 BLOCK_END 8674 BLOCK_END
7984 bool newListVal = false; 8675 bool newListVal = false;
@@ -7989,21 +8680,21 @@ private:
7989 } 8680 }
7990 if (!endWithSlice) { 8681 if (!endWithSlice) {
7991 transformExp(star_exp->value, temp, ExpUsage::Closure); 8682 transformExp(star_exp->value, temp, ExpUsage::Closure);
7992 if (newListVal) _buf << indent() << "local "sv << listVar << " = "sv << temp.back() << nll(nameList); 8683 if (newListVal) _buf << indent() << "local "sv << listVar << " = "sv << temp.back() << nl(nameList);
7993 _buf << indent() << "for "sv << indexVar << " = 1, #"sv << listVar << " do"sv << nlr(loopTarget); 8684 _buf << indent() << "for "sv << indexVar << " = 1, #"sv << listVar << " do"sv << nl(loopTarget);
7994 _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nll(nameList); 8685 _buf << indent(1) << "local "sv << join(vars, ", "sv) << " = "sv << listVar << "["sv << indexVar << "]"sv << nl(nameList);
7995 out.push_back(clearBuf()); 8686 out.push_back(clearBuf());
7996 } 8687 }
7997 break; 8688 break;
7998 } 8689 }
7999 case id<Exp_t>(): 8690 case id<Exp_t>():
8000 transformExp(static_cast<Exp_t*>(loopTarget), temp, ExpUsage::Closure); 8691 transformExp(static_cast<Exp_t*>(loopTarget), temp, ExpUsage::Closure);
8001 _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nlr(loopTarget); 8692 _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nl(loopTarget);
8002 out.push_back(clearBuf()); 8693 out.push_back(clearBuf());
8003 break; 8694 break;
8004 case id<ExpList_t>(): 8695 case id<ExpList_t>():
8005 transformExpList(static_cast<ExpList_t*>(loopTarget), temp); 8696 transformExpList(static_cast<ExpList_t*>(loopTarget), temp);
8006 _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nlr(loopTarget); 8697 _buf << indent() << "for "sv << join(vars, ", "sv) << " in "sv << temp.back() << " do"sv << nl(loopTarget);
8007 out.push_back(clearBuf()); 8698 out.push_back(clearBuf());
8008 break; 8699 break;
8009 default: YUEE("AST node mismatch", loopTarget); break; 8700 default: YUEE("AST node mismatch", loopTarget); break;
@@ -8012,15 +8703,22 @@ private:
8012 pushScope(); 8703 pushScope();
8013 for (const auto& var : vars) forceAddToScope(var); 8704 for (const auto& var : vars) forceAddToScope(var);
8014 for (const auto& var : varAfter) addToScope(var); 8705 for (const auto& var : varAfter) addToScope(var);
8015 if (!varConstAfter.empty()) markVarConst(varConstAfter); 8706 if (!varConstAfter.empty()) markVarLocalConst(varConstAfter);
8016 if (!destructPairs.empty()) { 8707 if (!destructPairs.empty()) {
8017 temp.clear(); 8708 temp.clear();
8018 for (auto& pair : destructPairs) { 8709 for (auto& pair : destructPairs) {
8019 auto sValue = x->new_ptr<SimpleValue_t>();
8020 sValue->value.set(pair.first);
8021 auto exp = newExp(sValue, x);
8022 auto expList = x->new_ptr<ExpList_t>(); 8710 auto expList = x->new_ptr<ExpList_t>();
8023 expList->exprs.push_back(exp); 8711 if (ast_is<SimpleTable_t>(pair.first)) {
8712 auto value = x->new_ptr<Value_t>();
8713 value->item.set(pair.first);
8714 auto exp = newExp(value, x);
8715 expList->exprs.push_back(exp);
8716 } else {
8717 auto sValue = x->new_ptr<SimpleValue_t>();
8718 sValue->value.set(pair.first);
8719 auto exp = newExp(sValue, x);
8720 expList->exprs.push_back(exp);
8721 }
8024 auto assign = x->new_ptr<Assign_t>(); 8722 auto assign = x->new_ptr<Assign_t>();
8025 assign->values.push_back(pair.second); 8723 assign->values.push_back(pair.second);
8026 auto assignment = x->new_ptr<ExpListAssign_t>(); 8724 auto assignment = x->new_ptr<ExpListAssign_t>();
@@ -8080,7 +8778,7 @@ private:
8080 out.push_back('(' + join(temp, ", "sv) + ')'); 8778 out.push_back('(' + join(temp, ", "sv) + ')');
8081 } 8779 }
8082 8780
8083 void transformForHead(Variable_t* var, Exp_t* startVal, Exp_t* stopVal, ForStepValue_t* stepVal, str_list& out) { 8781 void transformForNumHead(Variable_t* var, Exp_t* startVal, Exp_t* stopVal, ForStepValue_t* stepVal, str_list& out) {
8084 str_list temp; 8782 str_list temp;
8085 std::string varName = variableToString(var); 8783 std::string varName = variableToString(var);
8086 transformExp(startVal, temp, ExpUsage::Closure); 8784 transformExp(startVal, temp, ExpUsage::Closure);
@@ -8094,37 +8792,70 @@ private:
8094 const auto& start = *it; 8792 const auto& start = *it;
8095 const auto& stop = *(++it); 8793 const auto& stop = *(++it);
8096 const auto& step = *(++it); 8794 const auto& step = *(++it);
8097 _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : ", "s + step) << " do"sv << nll(var); 8795 _buf << indent() << "for "sv << varName << " = "sv << start << ", "sv << stop << (step.empty() ? Empty : ", "s + step) << " do"sv << nl(var);
8098 pushScope(); 8796 pushScope();
8099 forceAddToScope(varName); 8797 forceAddToScope(varName);
8100 markVarConst(varName); 8798 markVarLocalConst(varName);
8101 out.push_back(clearBuf()); 8799 out.push_back(clearBuf());
8102 } 8800 }
8103 8801
8104 void transformForHead(For_t* forNode, str_list& out) { 8802 void transformForNumHead(ForNum_t* forNum, str_list& out) {
8105 transformForHead(forNode->varName, forNode->startValue, forNode->stopValue, forNode->stepValue, out); 8803 transformForNumHead(forNum->varName, forNum->startValue, forNum->stopValue, forNum->stepValue, out);
8106 } 8804 }
8107 8805
8108 void transform_plain_body(ast_node* body, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { 8806 void transform_plain_body(ast_node* bodyOrStmt, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
8109 switch (body->get_id()) { 8807 switch (bodyOrStmt->get_id()) {
8110 case id<Block_t>(): 8808 case id<Block_t>():
8111 transformBlock(static_cast<Block_t*>(body), out, usage, assignList); 8809 transformBlock(static_cast<Block_t*>(bodyOrStmt), out, usage, assignList);
8112 break; 8810 break;
8113 case id<Statement_t>(): { 8811 case id<Statement_t>(): {
8114 auto newBlock = body->new_ptr<Block_t>(); 8812 auto newBlock = bodyOrStmt->new_ptr<Block_t>();
8115 newBlock->statements.push_back(body); 8813 newBlock->statementOrComments.push_back(bodyOrStmt);
8116 transformBlock(newBlock, out, usage, assignList); 8814 transformBlock(newBlock, out, usage, assignList);
8117 break; 8815 break;
8118 } 8816 }
8119 default: YUEE("AST node mismatch", body); break; 8817 default: YUEE("AST node mismatch", bodyOrStmt); break;
8120 } 8818 }
8121 } 8819 }
8122 8820
8123 bool hasContinueStatement(ast_node* body) { 8821 enum class BreakLoopType {
8124 return traversal::Stop == body->traverse([&](ast_node* node) { 8822 None = 0,
8823 Break = 1,
8824 BreakWithValue = 1 << 1,
8825 Continue = 1 << 2
8826 };
8827
8828 bool hasBreak(uint32_t breakLoopType) const {
8829 return (breakLoopType & int(BreakLoopType::Break)) != 0;
8830 }
8831
8832 bool hasBreakWithValue(uint32_t breakLoopType) const {
8833 return (breakLoopType & int(BreakLoopType::BreakWithValue)) != 0;
8834 }
8835
8836 bool hasContinue(uint32_t breakLoopType) const {
8837 return (breakLoopType & int(BreakLoopType::Continue)) != 0;
8838 }
8839
8840 uint32_t getBreakLoopType(ast_node* body, const std::string& varBWV) {
8841 uint32_t type = 0;
8842 body->traverse([&](ast_node* node) {
8125 if (auto stmt = ast_cast<Statement_t>(node)) { 8843 if (auto stmt = ast_cast<Statement_t>(node)) {
8126 if (stmt->content.is<BreakLoop_t>()) { 8844 if (auto breakLoop = stmt->content.as<BreakLoop_t>()) {
8127 return _parser.toString(stmt->content) == "continue"sv ? traversal::Stop : traversal::Return; 8845 if (breakLoop->type.is<Continue_t>()) {
8846 type |= int(BreakLoopType::Continue);
8847 return traversal::Return;
8848 } else {
8849 if (breakLoop->value) {
8850 if (varBWV.empty()) {
8851 throw CompileError("break with a value is not allowed here"sv, breakLoop->value);
8852 }
8853 type |= int(BreakLoopType::BreakWithValue);
8854 breakLoop->varBWV = varBWV;
8855 } else {
8856 type |= int(BreakLoopType::Break);
8857 }
8858 }
8128 } else if (auto expList = expListFrom(stmt)) { 8859 } else if (auto expList = expListFrom(stmt)) {
8129 BLOCK_START 8860 BLOCK_START
8130 auto value = singleValueFrom(expList); 8861 auto value = singleValueFrom(expList);
@@ -8135,40 +8866,30 @@ private:
8135 switch (sVal->get_id()) { 8866 switch (sVal->get_id()) {
8136 case id<With_t>(): { 8867 case id<With_t>(): {
8137 auto withNode = static_cast<With_t*>(sVal); 8868 auto withNode = static_cast<With_t*>(sVal);
8138 if (hasContinueStatement(withNode->body)) { 8869 type |= getBreakLoopType(withNode->body, varBWV);
8139 return traversal::Stop; 8870 return traversal::Return;
8140 }
8141 break;
8142 } 8871 }
8143 case id<Do_t>(): { 8872 case id<Do_t>(): {
8144 auto doNode = static_cast<Do_t*>(sVal); 8873 auto doNode = static_cast<Do_t*>(sVal);
8145 if (hasContinueStatement(doNode->body)) { 8874 type |= getBreakLoopType(doNode->body, varBWV);
8146 return traversal::Stop; 8875 return traversal::Return;
8147 }
8148 break;
8149 } 8876 }
8150 case id<If_t>(): { 8877 case id<If_t>(): {
8151 auto ifNode = static_cast<If_t*>(sVal); 8878 auto ifNode = static_cast<If_t*>(sVal);
8152 for (auto n : ifNode->nodes.objects()) { 8879 for (auto n : ifNode->nodes.objects()) {
8153 if (hasContinueStatement(n)) { 8880 type |= getBreakLoopType(n, varBWV);
8154 return traversal::Stop;
8155 }
8156 } 8881 }
8157 break; 8882 return traversal::Return;
8158 } 8883 }
8159 case id<Switch_t>(): { 8884 case id<Switch_t>(): {
8160 auto switchNode = static_cast<Switch_t*>(sVal); 8885 auto switchNode = static_cast<Switch_t*>(sVal);
8161 for (auto branch : switchNode->branches.objects()) { 8886 for (auto branch : switchNode->branches.objects()) {
8162 if (hasContinueStatement(static_cast<SwitchCase_t*>(branch)->body)) { 8887 type |= getBreakLoopType(static_cast<SwitchCase_t*>(branch)->body, varBWV);
8163 return traversal::Stop;
8164 }
8165 } 8888 }
8166 if (switchNode->lastBranch) { 8889 if (switchNode->lastBranch) {
8167 if (hasContinueStatement(switchNode->lastBranch)) { 8890 type |= getBreakLoopType(switchNode->lastBranch, varBWV);
8168 return traversal::Stop;
8169 }
8170 } 8891 }
8171 break; 8892 return traversal::Return;
8172 } 8893 }
8173 } 8894 }
8174 BLOCK_END 8895 BLOCK_END
@@ -8182,12 +8903,13 @@ private:
8182 } 8903 }
8183 return traversal::Return; 8904 return traversal::Return;
8184 }); 8905 });
8906 return type;
8185 } 8907 }
8186 8908
8187 void addDoToLastLineReturn(ast_node* body) { 8909 void addDoToLastLineReturn(ast_node* body) {
8188 if (auto block = ast_cast<Block_t>(body); block && !block->statements.empty()) { 8910 if (auto block = ast_cast<Block_t>(body); block && !block->statementOrComments.empty()) {
8189 auto last = static_cast<Statement_t*>(block->statements.back()); 8911 auto last = lastStatementFrom(block);
8190 if (last->content.is<Return_t>()) { 8912 if (last && last->content.is<Return_t>()) {
8191 auto doNode = last->new_ptr<Do_t>(); 8913 auto doNode = last->new_ptr<Do_t>();
8192 auto newBody = last->new_ptr<Body_t>(); 8914 auto newBody = last->new_ptr<Body_t>();
8193 auto newStmt = last->new_ptr<Statement_t>(); 8915 auto newStmt = last->new_ptr<Statement_t>();
@@ -8205,30 +8927,30 @@ private:
8205 } 8927 }
8206 } 8928 }
8207 8929
8208 void transformLoopBody(ast_node* body, str_list& out, const std::string& appendContent, ExpUsage usage, ExpList_t* assignList = nullptr) { 8930 void transformLoopBody(ast_node* body, str_list& out, uint32_t breakLoopType, ExpUsage usage, ExpList_t* assignList = nullptr) {
8209 str_list temp; 8931 str_list temp;
8210 bool extraDo = false; 8932 bool extraDo = false;
8211 bool withContinue = hasContinueStatement(body); 8933 bool withContinue = hasContinue(breakLoopType);
8212 int target = getLuaTarget(body); 8934 int target = getLuaTarget(body);
8213 std::string extraLabel; 8935 std::string extraLabel;
8214 if (withContinue) { 8936 if (withContinue) {
8215 if (target < 502) { 8937 if (target < 502) {
8216 if (auto block = ast_cast<Block_t>(body)) { 8938 if (auto block = ast_cast<Block_t>(body)) {
8217 if (!block->statements.empty()) { 8939 if (!block->statementOrComments.empty()) {
8218 auto stmt = static_cast<Statement_t*>(block->statements.back()); 8940 auto stmt = lastStatementFrom(block);
8219 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { 8941 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) {
8220 extraDo = _parser.toString(breakLoop) == "break"sv; 8942 extraDo = breakLoop->type.is<Break_t>();
8221 } 8943 }
8222 } 8944 }
8223 } 8945 }
8224 auto continueVar = getUnusedName("_continue_"sv); 8946 auto continueVar = getUnusedName("_continue_"sv);
8225 addToScope(continueVar); 8947 addToScope(continueVar);
8226 _continueVars.push({continueVar, nullptr}); 8948 _continueVars.push({continueVar, nullptr});
8227 _buf << indent() << "local "sv << continueVar << " = false"sv << nll(body); 8949 _buf << indent() << "local "sv << continueVar << " = false"sv << nl(body);
8228 _buf << indent() << "repeat"sv << nll(body); 8950 _buf << indent() << "repeat"sv << nl(body);
8229 pushScope(); 8951 pushScope();
8230 if (extraDo) { 8952 if (extraDo) {
8231 _buf << indent() << "do"sv << nll(body); 8953 _buf << indent() << "do"sv << nl(body);
8232 pushScope(); 8954 pushScope();
8233 } 8955 }
8234 temp.push_back(clearBuf()); 8956 temp.push_back(clearBuf());
@@ -8248,28 +8970,20 @@ private:
8248 if (target < 502) { 8970 if (target < 502) {
8249 if (extraDo) { 8971 if (extraDo) {
8250 popScope(); 8972 popScope();
8251 _buf << indent() << "end"sv << nll(body); 8973 _buf << indent() << "end"sv << nl(body);
8252 }
8253 if (!appendContent.empty()) {
8254 _buf << indent() << appendContent;
8255 } 8974 }
8256 _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); 8975 _buf << indent() << _continueVars.top().var << " = true"sv << nl(body);
8257 popScope(); 8976 popScope();
8258 _buf << indent() << "until true"sv << nlr(body); 8977 _buf << indent() << "until true"sv << nl(body);
8259 _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nlr(body); 8978 _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nl(body);
8260 _buf << indent(1) << "break"sv << nlr(body); 8979 _buf << indent(1) << "break"sv << nl(body);
8261 _buf << indent() << "end"sv << nlr(body); 8980 _buf << indent() << "end"sv << nl(body);
8262 temp.push_back(clearBuf()); 8981 temp.push_back(clearBuf());
8263 _continueVars.pop(); 8982 _continueVars.pop();
8264 } else { 8983 } else {
8265 if (!appendContent.empty()) {
8266 temp.push_back(indent() + appendContent);
8267 }
8268 temp.push_back(extraLabel); 8984 temp.push_back(extraLabel);
8269 _continueVars.pop(); 8985 _continueVars.pop();
8270 } 8986 }
8271 } else if (!appendContent.empty()) {
8272 temp.back().append(indent() + appendContent);
8273 } 8987 }
8274 out.push_back(join(temp)); 8988 out.push_back(join(temp));
8275 } 8989 }
@@ -8277,8 +8991,9 @@ private:
8277 std::string transformRepeatBody(Repeat_t* repeatNode, str_list& out) { 8991 std::string transformRepeatBody(Repeat_t* repeatNode, str_list& out) {
8278 str_list temp; 8992 str_list temp;
8279 bool extraDo = false; 8993 bool extraDo = false;
8280 auto body = repeatNode->body->content.get(); 8994 auto body = repeatNode->body.get();
8281 bool withContinue = hasContinueStatement(body); 8995 auto breakLoopType = getBreakLoopType(body, Empty);
8996 bool withContinue = hasContinue(breakLoopType);
8282 std::string conditionVar; 8997 std::string conditionVar;
8283 std::string extraLabel; 8998 std::string extraLabel;
8284 ast_ptr<false, ExpListAssign_t> condAssign; 8999 ast_ptr<false, ExpListAssign_t> condAssign;
@@ -8286,10 +9001,10 @@ private:
8286 if (withContinue) { 9001 if (withContinue) {
8287 if (target < 502) { 9002 if (target < 502) {
8288 if (auto block = ast_cast<Block_t>(body)) { 9003 if (auto block = ast_cast<Block_t>(body)) {
8289 if (!block->statements.empty()) { 9004 if (!block->statementOrComments.empty()) {
8290 auto stmt = static_cast<Statement_t*>(block->statements.back()); 9005 auto stmt = lastStatementFrom(block);
8291 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) { 9006 if (auto breakLoop = ast_cast<BreakLoop_t>(stmt->content)) {
8292 extraDo = _parser.toString(breakLoop) == "break"sv; 9007 extraDo = breakLoop->type.is<Break_t>();
8293 } 9008 }
8294 } 9009 }
8295 } 9010 }
@@ -8304,12 +9019,12 @@ private:
8304 assign->values.push_back(repeatNode->condition); 9019 assign->values.push_back(repeatNode->condition);
8305 _continueVars.push({continueVar, assignment.get()}); 9020 _continueVars.push({continueVar, assignment.get()});
8306 } 9021 }
8307 _buf << indent() << "local "sv << conditionVar << " = false"sv << nll(body); 9022 _buf << indent() << "local "sv << conditionVar << " = false"sv << nl(body);
8308 _buf << indent() << "local "sv << continueVar << " = false"sv << nll(body); 9023 _buf << indent() << "local "sv << continueVar << " = false"sv << nl(body);
8309 _buf << indent() << "repeat"sv << nll(body); 9024 _buf << indent() << "repeat"sv << nl(body);
8310 pushScope(); 9025 pushScope();
8311 if (extraDo) { 9026 if (extraDo) {
8312 _buf << indent() << "do"sv << nll(body); 9027 _buf << indent() << "do"sv << nl(body);
8313 pushScope(); 9028 pushScope();
8314 } 9029 }
8315 temp.push_back(clearBuf()); 9030 temp.push_back(clearBuf());
@@ -8330,14 +9045,14 @@ private:
8330 transformAssignment(_continueVars.top().condAssign, temp); 9045 transformAssignment(_continueVars.top().condAssign, temp);
8331 if (extraDo) { 9046 if (extraDo) {
8332 popScope(); 9047 popScope();
8333 _buf << indent() << "end"sv << nll(body); 9048 _buf << indent() << "end"sv << nl(body);
8334 } 9049 }
8335 _buf << indent() << _continueVars.top().var << " = true"sv << nll(body); 9050 _buf << indent() << _continueVars.top().var << " = true"sv << nl(body);
8336 popScope(); 9051 popScope();
8337 _buf << indent() << "until true"sv << nlr(body); 9052 _buf << indent() << "until true"sv << nl(body);
8338 _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nlr(body); 9053 _buf << indent() << "if not "sv << _continueVars.top().var << " then"sv << nl(body);
8339 _buf << indent(1) << "break"sv << nlr(body); 9054 _buf << indent(1) << "break"sv << nl(body);
8340 _buf << indent() << "end"sv << nlr(body); 9055 _buf << indent() << "end"sv << nl(body);
8341 temp.push_back(clearBuf()); 9056 temp.push_back(clearBuf());
8342 _continueVars.pop(); 9057 _continueVars.pop();
8343 } else { 9058 } else {
@@ -8349,34 +9064,48 @@ private:
8349 return conditionVar; 9064 return conditionVar;
8350 } 9065 }
8351 9066
8352 void transformFor(For_t* forNode, str_list& out) { 9067 void transformForNum(ForNum_t* forNum, str_list& out) {
8353 str_list temp; 9068 str_list temp;
8354 transformForHead(forNode, temp); 9069 transformForNumHead(forNum, temp);
8355 transformLoopBody(forNode->body, temp, Empty, ExpUsage::Common); 9070 auto breakLoopType = getBreakLoopType(forNum->body, Empty);
9071 transformLoopBody(forNum->body, temp, breakLoopType, ExpUsage::Common);
8356 popScope(); 9072 popScope();
8357 out.push_back(join(temp) + indent() + "end"s + nlr(forNode)); 9073 out.push_back(join(temp) + indent() + "end"s + nl(forNum));
8358 } 9074 }
8359 9075
8360 std::string transformForInner(For_t* forNode, str_list& out) { 9076 std::string transformForNumInner(ForNum_t* forNum, str_list& out) {
8361 auto x = forNode; 9077 auto x = forNum;
8362 std::string accum = getUnusedName("_accum_"sv); 9078 std::string accum = getUnusedName("_accum_"sv);
8363 addToScope(accum); 9079 addToScope(accum);
8364 std::string len = getUnusedName("_len_"sv); 9080 std::string len = getUnusedName("_len_"sv);
8365 addToScope(len); 9081 addToScope(len);
8366 _buf << indent() << "local "sv << accum << " = { }"sv << nll(forNode); 9082 auto breakLoopType = getBreakLoopType(forNum->body, accum);
8367 _buf << indent() << "local "sv << len << " = 1"sv << nll(forNode); 9083 _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(forNum);
8368 out.push_back(clearBuf()); 9084 out.emplace_back(clearBuf());
8369 transformForHead(forNode, out); 9085 _buf << indent() << "local "sv << len << " = 1"sv << nl(forNum);
8370 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); 9086 auto& lenAssign = out.emplace_back(clearBuf());
8371 auto lenLine = len + " = "s + len + " + 1"s + nlr(forNode->body); 9087 transformForNumHead(forNum, out);
8372 transformLoopBody(forNode->body, out, lenLine, ExpUsage::Assignment, expList); 9088 if (hasBreakWithValue(breakLoopType)) {
9089 lenAssign.clear();
9090 transformLoopBody(forNum->body, out, breakLoopType, ExpUsage::Common);
9091 } else {
9092 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x);
9093 auto followStmt = toAst<Statement_t>(len + "+=1"s, forNum->body);
9094 expList->followStmt = followStmt.get();
9095 transformLoopBody(forNum->body, out, breakLoopType, ExpUsage::Assignment, expList);
9096 if (!expList->followStmtProcessed) {
9097 lenAssign.clear();
9098 }
9099 }
8373 popScope(); 9100 popScope();
8374 out.push_back(indent() + "end"s + nlr(forNode)); 9101 out.push_back(indent() + "end"s + nl(forNum));
8375 return accum; 9102 return accum;
8376 } 9103 }
8377 9104
8378 void transformForClosure(For_t* forNode, str_list& out) { 9105 void transformForNumClosure(ForNum_t* forNum, str_list& out) {
8379 auto simpleValue = forNode->new_ptr<SimpleValue_t>(); 9106 auto forNode = forNum->new_ptr<For_t>();
9107 forNode->forLoop.set(forNum);
9108 auto simpleValue = forNum->new_ptr<SimpleValue_t>();
8380 simpleValue->value.set(forNode); 9109 simpleValue->value.set(forNode);
8381 if (transformAsUpValueFunc(newExp(simpleValue, forNode), out)) { 9110 if (transformAsUpValueFunc(newExp(simpleValue, forNode), out)) {
8382 return; 9111 return;
@@ -8386,26 +9115,26 @@ private:
8386 pushAnonVarArg(); 9115 pushAnonVarArg();
8387 std::string& funcStart = temp.emplace_back(); 9116 std::string& funcStart = temp.emplace_back();
8388 pushScope(); 9117 pushScope();
8389 auto accum = transformForInner(forNode, temp); 9118 auto accum = transformForNumInner(forNum, temp);
8390 temp.push_back(indent() + "return "s + accum + nlr(forNode)); 9119 temp.push_back(indent() + "return "s + accum + nl(forNum));
8391 popScope(); 9120 popScope();
8392 funcStart = anonFuncStart() + nll(forNode); 9121 funcStart = anonFuncStart() + nl(forNum);
8393 temp.push_back(indent() + anonFuncEnd()); 9122 temp.push_back(indent() + anonFuncEnd());
8394 popAnonVarArg(); 9123 popAnonVarArg();
8395 popFunctionScope(); 9124 popFunctionScope();
8396 out.push_back(join(temp)); 9125 out.push_back(join(temp));
8397 } 9126 }
8398 9127
8399 void transformForInPlace(For_t* forNode, str_list& out, ExpList_t* assignExpList = nullptr) { 9128 void transformForNumInPlace(ForNum_t* forNum, str_list& out, ExpList_t* assignExpList) {
8400 auto x = forNode; 9129 auto x = forNum;
8401 str_list temp; 9130 str_list temp;
8402 bool isScoped = !currentScope().lastStatement; 9131 bool isScoped = !currentScope().lastStatement;
8403 if (assignExpList) { 9132 if (assignExpList) {
8404 if (isScoped) { 9133 if (isScoped) {
8405 _buf << indent() << "do"sv << nll(forNode); 9134 _buf << indent() << "do"sv << nl(forNum);
8406 pushScope(); 9135 pushScope();
8407 } 9136 }
8408 auto accum = transformForInner(forNode, temp); 9137 auto accum = transformForNumInner(forNum, temp);
8409 auto assign = x->new_ptr<Assign_t>(); 9138 auto assign = x->new_ptr<Assign_t>();
8410 assign->values.push_back(toAst<Exp_t>(accum, x)); 9139 assign->values.push_back(toAst<Exp_t>(accum, x));
8411 auto assignment = x->new_ptr<ExpListAssign_t>(); 9140 auto assignment = x->new_ptr<ExpListAssign_t>();
@@ -8414,14 +9143,11 @@ private:
8414 transformAssignment(assignment, temp); 9143 transformAssignment(assignment, temp);
8415 if (isScoped) { 9144 if (isScoped) {
8416 popScope(); 9145 popScope();
8417 temp.push_back(indent() + "end"s + nlr(forNode)); 9146 temp.push_back(indent() + "end"s + nl(forNum));
8418 } 9147 }
8419 } else { 9148 } else {
8420 auto accum = transformForInner(forNode, temp); 9149 auto accum = transformForNumInner(forNum, temp);
8421 auto returnNode = x->new_ptr<Return_t>(); 9150 auto returnNode = newReturn(toAst<Exp_t>(accum, forNum));
8422 returnNode->explicitReturn = false;
8423 auto expListLow = toAst<ExpListLow_t>(accum, x);
8424 returnNode->valueList.set(expListLow);
8425 transformReturn(returnNode, temp); 9151 transformReturn(returnNode, temp);
8426 } 9152 }
8427 out.push_back(join(temp)); 9153 out.push_back(join(temp));
@@ -8448,12 +9174,13 @@ private:
8448 void transformForEach(ForEach_t* forEach, str_list& out) { 9174 void transformForEach(ForEach_t* forEach, str_list& out) {
8449 str_list temp; 9175 str_list temp;
8450 bool extraScoped = transformForEachHead(forEach->nameList, forEach->loopValue, temp, false); 9176 bool extraScoped = transformForEachHead(forEach->nameList, forEach->loopValue, temp, false);
8451 transformLoopBody(forEach->body, temp, Empty, ExpUsage::Common); 9177 auto breakLoopType = getBreakLoopType(forEach->body, Empty);
9178 transformLoopBody(forEach->body, temp, breakLoopType, ExpUsage::Common);
8452 popScope(); 9179 popScope();
8453 out.push_back(temp.front() + temp.back() + indent() + "end"s + nlr(forEach)); 9180 out.push_back(temp.front() + temp.back() + indent() + "end"s + nl(forEach));
8454 if (extraScoped) { 9181 if (extraScoped) {
8455 popScope(); 9182 popScope();
8456 out.back().append(indent() + "end"s + nlr(forEach)); 9183 out.back().append(indent() + "end"s + nl(forEach));
8457 } 9184 }
8458 } 9185 }
8459 9186
@@ -8463,22 +9190,35 @@ private:
8463 addToScope(accum); 9190 addToScope(accum);
8464 std::string len = getUnusedName("_len_"sv); 9191 std::string len = getUnusedName("_len_"sv);
8465 addToScope(len); 9192 addToScope(len);
8466 _buf << indent() << "local "sv << accum << " = { }"sv << nll(forEach); 9193 auto breakLoopType = getBreakLoopType(forEach->body, accum);
8467 _buf << indent() << "local "sv << len << " = 1"sv << nll(forEach); 9194 _buf << indent() << "local "sv << accum << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(forEach);
8468 out.push_back(clearBuf()); 9195 out.emplace_back(clearBuf());
9196 _buf << indent() << "local "sv << len << " = 1"sv << nl(forEach);
9197 auto& lenAssign = out.emplace_back(clearBuf());
8469 transformForEachHead(forEach->nameList, forEach->loopValue, out, true); 9198 transformForEachHead(forEach->nameList, forEach->loopValue, out, true);
8470 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x); 9199 if (hasBreakWithValue(breakLoopType)) {
8471 auto lenLine = len + " = "s + len + " + 1"s + nlr(forEach->body); 9200 lenAssign.clear();
8472 transformLoopBody(forEach->body, out, lenLine, ExpUsage::Assignment, expList); 9201 transformLoopBody(forEach->body, out, breakLoopType, ExpUsage::Common);
9202 } else {
9203 auto expList = toAst<ExpList_t>(accum + '[' + len + ']', x);
9204 auto followStmt = toAst<Statement_t>(len + "+=1"s, forEach->body);
9205 expList->followStmt = followStmt.get();
9206 transformLoopBody(forEach->body, out, breakLoopType, ExpUsage::Assignment, expList);
9207 if (!expList->followStmtProcessed) {
9208 lenAssign.clear();
9209 }
9210 }
8473 popScope(); 9211 popScope();
8474 out.push_back(indent() + "end"s + nlr(forEach)); 9212 out.push_back(indent() + "end"s + nl(forEach));
8475 return accum; 9213 return accum;
8476 } 9214 }
8477 9215
8478 void transformForEachClosure(ForEach_t* forEach, str_list& out) { 9216 void transformForEachClosure(ForEach_t* forEach, str_list& out) {
9217 auto forNode = forEach->new_ptr<For_t>();
9218 forNode->forLoop.set(forEach);
8479 auto simpleValue = forEach->new_ptr<SimpleValue_t>(); 9219 auto simpleValue = forEach->new_ptr<SimpleValue_t>();
8480 simpleValue->value.set(forEach); 9220 simpleValue->value.set(forNode);
8481 if (transformAsUpValueFunc(newExp(simpleValue, forEach), out)) { 9221 if (transformAsUpValueFunc(newExp(simpleValue, forNode), out)) {
8482 return; 9222 return;
8483 } 9223 }
8484 str_list temp; 9224 str_list temp;
@@ -8487,22 +9227,22 @@ private:
8487 std::string& funcStart = temp.emplace_back(); 9227 std::string& funcStart = temp.emplace_back();
8488 pushScope(); 9228 pushScope();
8489 auto accum = transformForEachInner(forEach, temp); 9229 auto accum = transformForEachInner(forEach, temp);
8490 temp.push_back(indent() + "return "s + accum + nlr(forEach)); 9230 temp.push_back(indent() + "return "s + accum + nl(forEach));
8491 popScope(); 9231 popScope();
8492 funcStart = anonFuncStart() + nll(forEach); 9232 funcStart = anonFuncStart() + nl(forEach);
8493 temp.push_back(indent() + anonFuncEnd()); 9233 temp.push_back(indent() + anonFuncEnd());
8494 popAnonVarArg(); 9234 popAnonVarArg();
8495 popFunctionScope(); 9235 popFunctionScope();
8496 out.push_back(join(temp)); 9236 out.push_back(join(temp));
8497 } 9237 }
8498 9238
8499 void transformForEachInPlace(ForEach_t* forEach, str_list& out, ExpList_t* assignExpList = nullptr) { 9239 void transformForEachInPlace(ForEach_t* forEach, str_list& out, ExpList_t* assignExpList) {
8500 auto x = forEach; 9240 auto x = forEach;
8501 str_list temp; 9241 str_list temp;
8502 bool isScoped = !currentScope().lastStatement; 9242 bool isScoped = !currentScope().lastStatement;
8503 if (assignExpList) { 9243 if (assignExpList) {
8504 if (isScoped) { 9244 if (isScoped) {
8505 _buf << indent() << "do"sv << nll(forEach); 9245 _buf << indent() << "do"sv << nl(forEach);
8506 pushScope(); 9246 pushScope();
8507 } 9247 }
8508 auto accum = transformForEachInner(forEach, temp); 9248 auto accum = transformForEachInner(forEach, temp);
@@ -8514,19 +9254,58 @@ private:
8514 transformAssignment(assignment, temp); 9254 transformAssignment(assignment, temp);
8515 if (isScoped) { 9255 if (isScoped) {
8516 popScope(); 9256 popScope();
8517 temp.push_back(indent() + "end"s + nlr(forEach)); 9257 temp.push_back(indent() + "end"s + nl(forEach));
8518 } 9258 }
8519 } else { 9259 } else {
8520 auto accum = transformForEachInner(forEach, temp); 9260 auto accum = transformForEachInner(forEach, temp);
8521 auto returnNode = x->new_ptr<Return_t>(); 9261 auto returnNode = newReturn(toAst<Exp_t>(accum, forEach));
8522 returnNode->explicitReturn = false;
8523 auto expListLow = toAst<ExpListLow_t>(accum, x);
8524 returnNode->valueList.set(expListLow);
8525 transformReturn(returnNode, temp); 9262 transformReturn(returnNode, temp);
8526 } 9263 }
8527 out.push_back(join(temp)); 9264 out.push_back(join(temp));
8528 } 9265 }
8529 9266
9267 void transformFor(For_t* forNode, str_list& out) {
9268 switch (forNode->forLoop->get_id()) {
9269 case id<ForNum_t>():
9270 transformForNum(static_cast<ForNum_t*>(forNode->forLoop.get()), out);
9271 break;
9272 case id<ForEach_t>():
9273 transformForEach(static_cast<ForEach_t*>(forNode->forLoop.get()), out);
9274 break;
9275 default:
9276 YUEE("AST node mismatch", forNode->forLoop.get());
9277 break;
9278 }
9279 }
9280
9281 void transformForClosure(For_t* forNode, str_list& out) {
9282 switch (forNode->forLoop->get_id()) {
9283 case id<ForNum_t>():
9284 transformForNumClosure(static_cast<ForNum_t*>(forNode->forLoop.get()), out);
9285 break;
9286 case id<ForEach_t>():
9287 transformForEachClosure(static_cast<ForEach_t*>(forNode->forLoop.get()), out);
9288 break;
9289 default:
9290 YUEE("AST node mismatch", forNode->forLoop.get());
9291 break;
9292 }
9293 }
9294
9295 void transformForInPlace(For_t* forNode, str_list& out, ExpList_t* assignExpList) {
9296 switch (forNode->forLoop->get_id()) {
9297 case id<ForNum_t>():
9298 transformForNumInPlace(static_cast<ForNum_t*>(forNode->forLoop.get()), out, assignExpList);
9299 break;
9300 case id<ForEach_t>():
9301 transformForEachInPlace(static_cast<ForEach_t*>(forNode->forLoop.get()), out, assignExpList);
9302 break;
9303 default:
9304 YUEE("AST node mismatch", forNode->forLoop.get());
9305 break;
9306 }
9307 }
9308
8530 void transform_variable_pair(VariablePair_t* pair, str_list& out) { 9309 void transform_variable_pair(VariablePair_t* pair, str_list& out) {
8531 auto name = _parser.toString(pair->name); 9310 auto name = _parser.toString(pair->name);
8532 if (pair->name->name.is<UnicodeName_t>()) { 9311 if (pair->name->name.is<UnicodeName_t>()) {
@@ -8536,10 +9315,12 @@ private:
8536 } else { 9315 } else {
8537 out.push_back(name + " = "s + name); 9316 out.push_back(name + " = "s + name);
8538 } 9317 }
8539 if (_config.lintGlobalVariable && !isLocal(name)) { 9318 if (_importedGlobal) {
9319 markGlobalImported(name);
9320 } else if (_config.lintGlobalVariable && !isLocal(name)) {
8540 auto key = name + ':' + std::to_string(pair->name->m_begin.m_line) + ':' + std::to_string(pair->name->m_begin.m_col); 9321 auto key = name + ':' + std::to_string(pair->name->m_begin.m_line) + ':' + std::to_string(pair->name->m_begin.m_col);
8541 if (_globals.find(key) != _globals.end()) { 9322 if (_globals.find(key) == _globals.end()) {
8542 _globals[key] = {name, pair->name->m_begin.m_line, pair->name->m_begin.m_col, _funcLevel > 1 ? AccessType::Capture : AccessType::Read}; 9323 _globals[key] = {name, pair->name->m_begin.m_line, pair->name->m_begin.m_col, _funcLevel > 1 ? AccessType::Capture : AccessType::Read, isSolidDefined(name)};
8543 } 9324 }
8544 } 9325 }
8545 } 9326 }
@@ -8653,12 +9434,64 @@ private:
8653 out.push_back(temp.empty() ? "\"\""s : join(temp, " .. "sv)); 9434 out.push_back(temp.empty() ? "\"\""s : join(temp, " .. "sv));
8654 } 9435 }
8655 9436
9437 void transformYAMLMultiline(YAMLMultiline_t* multiline, str_list& out) {
9438 std::optional<std::string> indent;
9439 str_list temp;
9440 for (auto line_ : multiline->lines.objects()) {
9441 auto line = static_cast<YAMLLine_t*>(line_);
9442 auto indentStr = _parser.toString(line->indent);
9443 if (!indent) {
9444 indent = indentStr;
9445 }
9446 if (std::string_view{indentStr.c_str(), indent.value().size()} != indent.value()) {
9447 throw CompileError("inconsistent indent"sv, line);
9448 }
9449 indentStr = indentStr.substr(indent.value().size());
9450 str_list segs;
9451 bool firstSeg = true;
9452 for (auto seg_ : line->segments.objects()) {
9453 auto content = static_cast<YAMLLineContent_t*>(seg_)->content.get();
9454 switch (content->get_id()) {
9455 case id<YAMLLineInner_t>(): {
9456 auto seqStr = _parser.toString(content);
9457 Utils::replace(seqStr, "\\#"sv, "#"sv);
9458 if (firstSeg) {
9459 firstSeg = false;
9460 seqStr.insert(0, indentStr);
9461 }
9462 segs.push_back(Utils::toLuaDoubleString(seqStr));
9463 break;
9464 }
9465 case id<Exp_t>(): {
9466 if (firstSeg) {
9467 firstSeg = false;
9468 if (!indentStr.empty()) {
9469 segs.push_back(Utils::toLuaDoubleString(indentStr));
9470 }
9471 }
9472 transformExp(static_cast<Exp_t*>(content), segs, ExpUsage::Closure);
9473 segs.back() = globalVar("tostring"sv, content, AccessType::Read) + '(' + segs.back() + ')';
9474 break;
9475 }
9476 default: YUEE("AST node mismatch", content); break;
9477 }
9478 }
9479 temp.push_back(join(segs, " .. "sv));
9480 }
9481 auto str = join(temp, " .. '\\n' .. "sv);
9482 Utils::replace(str, "\" .. '\\n' .. \""sv, "\\n"sv);
9483 Utils::replace(str, "\" .. '\\n'"sv, "\\n\""sv);
9484 Utils::replace(str, "'\\n' .. \""sv, "\"\\n"sv);
9485 out.push_back(str);
9486 }
9487
8656 void transformString(String_t* string, str_list& out) { 9488 void transformString(String_t* string, str_list& out) {
8657 auto str = string->str.get(); 9489 auto str = string->str.get();
8658 switch (str->get_id()) { 9490 switch (str->get_id()) {
8659 case id<SingleString_t>(): transformSingleString(static_cast<SingleString_t*>(str), out); break; 9491 case id<SingleString_t>(): transformSingleString(static_cast<SingleString_t*>(str), out); break;
8660 case id<DoubleString_t>(): transformDoubleString(static_cast<DoubleString_t*>(str), out); break; 9492 case id<DoubleString_t>(): transformDoubleString(static_cast<DoubleString_t*>(str), out); break;
8661 case id<LuaString_t>(): transformLuaString(static_cast<LuaString_t*>(str), out); break; 9493 case id<LuaString_t>(): transformLuaString(static_cast<LuaString_t*>(str), out); break;
9494 case id<YAMLMultiline_t>(): transformYAMLMultiline(static_cast<YAMLMultiline_t*>(str), out); break;
8662 default: YUEE("AST node mismatch", str); break; 9495 default: YUEE("AST node mismatch", str); break;
8663 } 9496 }
8664 } 9497 }
@@ -8689,7 +9522,7 @@ private:
8689 pushScope(); 9522 pushScope();
8690 transformClassDecl(classDecl, temp, ExpUsage::Return); 9523 transformClassDecl(classDecl, temp, ExpUsage::Return);
8691 popScope(); 9524 popScope();
8692 funcStart = anonFuncStart() + nll(classDecl); 9525 funcStart = anonFuncStart() + nl(classDecl);
8693 temp.push_back(indent() + anonFuncEnd()); 9526 temp.push_back(indent() + anonFuncEnd());
8694 popAnonVarArg(); 9527 popAnonVarArg();
8695 popFunctionScope(); 9528 popFunctionScope();
@@ -8713,7 +9546,7 @@ private:
8713 bool newDefined = false; 9546 bool newDefined = false;
8714 std::tie(className, newDefined, classTextName) = defineClassVariable(assignable); 9547 std::tie(className, newDefined, classTextName) = defineClassVariable(assignable);
8715 if (newDefined) { 9548 if (newDefined) {
8716 temp.push_back(indent() + "local "s + className + nll(classDecl)); 9549 temp.push_back(indent() + "local "s + className + nl(classDecl));
8717 } 9550 }
8718 if (classTextName.empty()) { 9551 if (classTextName.empty()) {
8719 if (auto chain = ast_cast<AssignableChain_t>(assignable->item)) { 9552 if (auto chain = ast_cast<AssignableChain_t>(assignable->item)) {
@@ -8750,12 +9583,12 @@ private:
8750 } 9583 }
8751 } 9584 }
8752 if (isScoped) { 9585 if (isScoped) {
8753 temp.push_back(indent() + "do"s + nll(classDecl)); 9586 temp.push_back(indent() + "do"s + nl(classDecl));
8754 pushScope(); 9587 pushScope();
8755 } 9588 }
8756 auto classVar = getUnusedName("_class_"sv); 9589 auto classVar = getUnusedName("_class_"sv);
8757 addToScope(classVar); 9590 addToScope(classVar);
8758 temp.push_back(indent() + "local "s + classVar + nll(classDecl)); 9591 temp.push_back(indent() + "local "s + classVar + nl(classDecl));
8759 auto block = classDecl->new_ptr<Block_t>(); 9592 auto block = classDecl->new_ptr<Block_t>();
8760 str_list classConstVars; 9593 str_list classConstVars;
8761 if (body) { 9594 if (body) {
@@ -8764,7 +9597,7 @@ private:
8764 if (auto statement = ast_cast<Statement_t>(item)) { 9597 if (auto statement = ast_cast<Statement_t>(item)) {
8765 ClassDecl_t* clsDecl = nullptr; 9598 ClassDecl_t* clsDecl = nullptr;
8766 if (auto assignment = assignmentFrom(statement)) { 9599 if (auto assignment = assignmentFrom(statement)) {
8767 block->statements.push_back(statement); 9600 block->statementOrComments.push_back(statement);
8768 auto names = transformAssignDefs(assignment->expList.get(), DefOp::Mark); 9601 auto names = transformAssignDefs(assignment->expList.get(), DefOp::Mark);
8769 for (const auto& name : names) { 9602 for (const auto& name : names) {
8770 varDefs.push_back(name.first); 9603 varDefs.push_back(name.first);
@@ -8794,12 +9627,12 @@ private:
8794 clsDecl = value->get_by_path<SimpleValue_t, ClassDecl_t>(); 9627 clsDecl = value->get_by_path<SimpleValue_t, ClassDecl_t>();
8795 BLOCK_END 9628 BLOCK_END
8796 } else if (auto expList = expListFrom(statement)) { 9629 } else if (auto expList = expListFrom(statement)) {
8797 block->statements.push_back(statement); 9630 block->statementOrComments.push_back(statement);
8798 if (auto value = singleValueFrom(expList)) { 9631 if (auto value = singleValueFrom(expList)) {
8799 clsDecl = value->get_by_path<SimpleValue_t, ClassDecl_t>(); 9632 clsDecl = value->get_by_path<SimpleValue_t, ClassDecl_t>();
8800 } 9633 }
8801 } else if (auto local = statement->content.as<Local_t>()) { 9634 } else if (auto local = statement->content.as<Local_t>()) {
8802 block->statements.push_back(statement); 9635 block->statementOrComments.push_back(statement);
8803 if (auto values = local->item.as<LocalValues_t>()) { 9636 if (auto values = local->item.as<LocalValues_t>()) {
8804 for (auto name : values->nameList->names.objects()) { 9637 for (auto name : values->nameList->names.objects()) {
8805 auto varName = variableToString(static_cast<Variable_t*>(name)); 9638 auto varName = variableToString(static_cast<Variable_t*>(name));
@@ -8840,7 +9673,7 @@ private:
8840 auto names = transformAssignDefs(assignment->expList.get(), DefOp::Get); 9673 auto names = transformAssignDefs(assignment->expList.get(), DefOp::Get);
8841 for (const auto& name : names) { 9674 for (const auto& name : names) {
8842 forceAddToScope(name.first); 9675 forceAddToScope(name.first);
8843 markVarConst(name.first); 9676 markVarLocalConst(name.first);
8844 varDefs.push_back(name.first); 9677 varDefs.push_back(name.first);
8845 classConstVars.push_back(name.first); 9678 classConstVars.push_back(name.first);
8846 } 9679 }
@@ -8854,7 +9687,7 @@ private:
8854 for (const auto& item : destruct.items) { 9687 for (const auto& item : destruct.items) {
8855 if (!item.targetVar.empty()) { 9688 if (!item.targetVar.empty()) {
8856 forceAddToScope(item.targetVar); 9689 forceAddToScope(item.targetVar);
8857 markVarConst(item.targetVar); 9690 markVarLocalConst(item.targetVar);
8858 varDefs.push_back(item.targetVar); 9691 varDefs.push_back(item.targetVar);
8859 classConstVars.push_back(item.targetVar); 9692 classConstVars.push_back(item.targetVar);
8860 } 9693 }
@@ -8862,7 +9695,6 @@ private:
8862 } 9695 }
8863 } 9696 }
8864 auto stmt = statement->new_ptr<Statement_t>(); 9697 auto stmt = statement->new_ptr<Statement_t>();
8865 stmt->comments.dup(statement->comments);
8866 auto newAttrib = localAttrib->new_ptr<LocalAttrib_t>(); 9698 auto newAttrib = localAttrib->new_ptr<LocalAttrib_t>();
8867 newAttrib->attrib.set(localAttrib->attrib); 9699 newAttrib->attrib.set(localAttrib->attrib);
8868 newAttrib->leftList.dup(localAttrib->leftList); 9700 newAttrib->leftList.dup(localAttrib->leftList);
@@ -8870,7 +9702,7 @@ private:
8870 newAttrib->forceLocal = false; 9702 newAttrib->forceLocal = false;
8871 stmt->content.set(newAttrib); 9703 stmt->content.set(newAttrib);
8872 stmt->appendix.set(statement->appendix); 9704 stmt->appendix.set(statement->appendix);
8873 block->statements.push_back(stmt); 9705 block->statementOrComments.push_back(stmt);
8874 } else if (statement->content.is<Global_t>()) { 9706 } else if (statement->content.is<Global_t>()) {
8875 throw CompileError("global statement is not allowed here"sv, statement->content); 9707 throw CompileError("global statement is not allowed here"sv, statement->content);
8876 } 9708 }
@@ -8884,7 +9716,7 @@ private:
8884 } 9716 }
8885 } 9717 }
8886 if (!varDefs.empty()) { 9718 if (!varDefs.empty()) {
8887 temp.push_back(indent() + "local "s + join(varDefs, ", "sv) + nll(body)); 9719 temp.push_back(indent() + "local "s + join(varDefs, ", "sv) + nl(body));
8888 } 9720 }
8889 } 9721 }
8890 std::string parent, parentVar; 9722 std::string parent, parentVar;
@@ -8894,7 +9726,7 @@ private:
8894 transformExp(extend, temp, ExpUsage::Closure); 9726 transformExp(extend, temp, ExpUsage::Closure);
8895 parent = std::move(temp.back()); 9727 parent = std::move(temp.back());
8896 temp.pop_back(); 9728 temp.pop_back();
8897 temp.push_back(indent() + "local "s + parentVar + " = "s + parent + nll(classDecl)); 9729 temp.push_back(indent() + "local "s + parentVar + " = "s + parent + nl(classDecl));
8898 } 9730 }
8899 auto baseVar = getUnusedName("_base_"sv); 9731 auto baseVar = getUnusedName("_base_"sv);
8900 addToScope(baseVar); 9732 addToScope(baseVar);
@@ -8913,7 +9745,7 @@ private:
8913 for (; it != members.end(); ++it) { 9745 for (; it != members.end(); ++it) {
8914 auto& member = *it; 9746 auto& member = *it;
8915 if (member.type == MemType::Property) { 9747 if (member.type == MemType::Property) {
8916 statements.push_back(indent() + member.item + nll(content)); 9748 statements.push_back(indent() + member.item + nl(content));
8917 } else { 9749 } else {
8918 member.item = indent(1) + member.item; 9750 member.item = indent(1) + member.item;
8919 } 9751 }
@@ -8925,32 +9757,34 @@ private:
8925 } 9757 }
8926 } 9758 }
8927 for (const auto& classVar : classConstVars) { 9759 for (const auto& classVar : classConstVars) {
8928 auto& scope = _scopes.back(); 9760 forceAddToScope(classVar);
8929 scope.vars->insert_or_assign(classVar, VarType::Local);
8930 } 9761 }
8931 for (auto stmt_ : block->statements.objects()) { 9762 forceAddToScope("self"s);
8932 transformStatement(static_cast<Statement_t*>(stmt_), statements); 9763 for (auto stmt_ : block->statementOrComments.objects()) {
9764 if (auto stmt = ast_cast<Statement_t>(stmt_)) {
9765 transformStatement(stmt, statements);
9766 }
8933 } 9767 }
8934 for (auto& member : members) { 9768 for (auto& member : members) {
8935 switch (member.type) { 9769 switch (member.type) {
8936 case MemType::Common: 9770 case MemType::Common:
8937 commons.push_back((commons.empty() ? Empty : ',' + nll(member.node)) + member.item); 9771 commons.push_back((commons.empty() ? Empty : ',' + nl(member.node)) + member.item);
8938 break; 9772 break;
8939 case MemType::Builtin: 9773 case MemType::Builtin:
8940 builtins.push_back((builtins.empty() ? Empty : ',' + nll(member.node)) + member.item); 9774 builtins.push_back((builtins.empty() ? Empty : ',' + nl(member.node)) + member.item);
8941 break; 9775 break;
8942 default: break; 9776 default: break;
8943 } 9777 }
8944 } 9778 }
8945 if (!commons.empty()) { 9779 if (!commons.empty()) {
8946 temp.back() += '{' + nll(body); 9780 temp.back() += '{' + nl(body);
8947 temp.push_back(join(commons) + nll(body)); 9781 temp.push_back(join(commons) + nl(body));
8948 temp.push_back(indent() + '}' + nll(body)); 9782 temp.push_back(indent() + '}' + nl(body));
8949 } else { 9783 } else {
8950 temp.back() += "{ }"s + nll(body); 9784 temp.back() += "{ }"s + nl(body);
8951 } 9785 }
8952 } else { 9786 } else {
8953 temp.back() += "{ }"s + nll(classDecl); 9787 temp.back() += "{ }"s + nl(classDecl);
8954 } 9788 }
8955 if (classDecl->mixes) { 9789 if (classDecl->mixes) {
8956 auto item = getUnusedName("_item_"sv); 9790 auto item = getUnusedName("_item_"sv);
@@ -8983,72 +9817,72 @@ private:
8983 transformAssignment(assignment, tmp); 9817 transformAssignment(assignment, tmp);
8984 } 9818 }
8985 if (extend) { 9819 if (extend) {
8986 _buf << indent() << "setmetatable("sv << baseVar << ", "sv << parentVar << ".__base)"sv << nll(classDecl); 9820 _buf << indent() << "setmetatable("sv << baseVar << ", "sv << parentVar << ".__base)"sv << nl(classDecl);
8987 } 9821 }
8988 _buf << indent() << classVar << " = "sv << globalVar("setmetatable"sv, classDecl, AccessType::Read) << "({"sv << nll(classDecl); 9822 _buf << indent() << classVar << " = "sv << globalVar("setmetatable"sv, classDecl, AccessType::Read) << "({"sv << nl(classDecl);
8989 if (!builtins.empty()) { 9823 if (!builtins.empty()) {
8990 _buf << join(builtins) << ',' << nll(classDecl); 9824 _buf << join(builtins) << ',' << nl(classDecl);
8991 } else { 9825 } else {
8992 if (extend) { 9826 if (extend) {
8993 _buf << indent(1) << "__init = function(self, ...)"sv << nll(classDecl); 9827 _buf << indent(1) << "__init = function(self, ...)"sv << nl(classDecl);
8994 _buf << indent(2) << "return "sv << classVar << ".__parent.__init(self, ...)"sv << nll(classDecl); 9828 _buf << indent(2) << "return "sv << classVar << ".__parent.__init(self, ...)"sv << nl(classDecl);
8995 _buf << indent(1) << "end,"sv << nll(classDecl); 9829 _buf << indent(1) << "end,"sv << nl(classDecl);
8996 } else { 9830 } else {
8997 _buf << indent(1) << "__init = function() end,"sv << nll(classDecl); 9831 _buf << indent(1) << "__init = function() end,"sv << nl(classDecl);
8998 } 9832 }
8999 } 9833 }
9000 _buf << indent(1) << "__base = "sv << baseVar; 9834 _buf << indent(1) << "__base = "sv << baseVar;
9001 if (!classTextName.empty()) { 9835 if (!classTextName.empty()) {
9002 _buf << ","sv << nll(classDecl); 9836 _buf << ","sv << nl(classDecl);
9003 _buf << indent(1) << "__name = "sv << classTextName; 9837 _buf << indent(1) << "__name = "sv << classTextName;
9004 } 9838 }
9005 if (extend) { 9839 if (extend) {
9006 _buf << ","sv << nll(classDecl); 9840 _buf << ","sv << nl(classDecl);
9007 _buf << indent(1) << "__parent = "sv << parentVar; 9841 _buf << indent(1) << "__parent = "sv << parentVar;
9008 } 9842 }
9009 _buf << nll(classDecl); 9843 _buf << nl(classDecl);
9010 _buf << indent() << "}, {"sv << nll(classDecl); 9844 _buf << indent() << "}, {"sv << nl(classDecl);
9011 if (extend) { 9845 if (extend) {
9012 _buf << indent(1) << "__index = function(cls, name)"sv << nll(classDecl); 9846 _buf << indent(1) << "__index = function(cls, name)"sv << nl(classDecl);
9013 _buf << indent(2) << "local val = rawget("sv << baseVar << ", name)"sv << nll(classDecl); 9847 _buf << indent(2) << "local val = rawget("sv << baseVar << ", name)"sv << nl(classDecl);
9014 _buf << indent(2) << "if val == nil then"sv << nll(classDecl); 9848 _buf << indent(2) << "if val == nil then"sv << nl(classDecl);
9015 _buf << indent(3) << "local parent = rawget(cls, \"__parent\")"sv << nll(classDecl); 9849 _buf << indent(3) << "local parent = rawget(cls, \"__parent\")"sv << nl(classDecl);
9016 _buf << indent(3) << "if parent then"sv << nll(classDecl); 9850 _buf << indent(3) << "if parent then"sv << nl(classDecl);
9017 _buf << indent(4) << "return parent[name]"sv << nll(classDecl); 9851 _buf << indent(4) << "return parent[name]"sv << nl(classDecl);
9018 _buf << indent(3) << "end"sv << nll(classDecl); 9852 _buf << indent(3) << "end"sv << nl(classDecl);
9019 _buf << indent(2) << "else"sv << nll(classDecl); 9853 _buf << indent(2) << "else"sv << nl(classDecl);
9020 _buf << indent(3) << "return val"sv << nll(classDecl); 9854 _buf << indent(3) << "return val"sv << nl(classDecl);
9021 _buf << indent(2) << "end"sv << nll(classDecl); 9855 _buf << indent(2) << "end"sv << nl(classDecl);
9022 _buf << indent(1) << "end,"sv << nll(classDecl); 9856 _buf << indent(1) << "end,"sv << nl(classDecl);
9023 } else { 9857 } else {
9024 _buf << indent(1) << "__index = "sv << baseVar << ","sv << nll(classDecl); 9858 _buf << indent(1) << "__index = "sv << baseVar << ","sv << nl(classDecl);
9025 } 9859 }
9026 _buf << indent(1) << "__call = function(cls, ...)"sv << nll(classDecl); 9860 _buf << indent(1) << "__call = function(cls, ...)"sv << nl(classDecl);
9027 pushScope(); 9861 pushScope();
9028 auto selfVar = getUnusedName("_self_"sv); 9862 auto selfVar = getUnusedName("_self_"sv);
9029 addToScope(selfVar); 9863 addToScope(selfVar);
9030 _buf << indent(1) << "local "sv << selfVar << " = setmetatable({ }, "sv << baseVar << ")"sv << nll(classDecl); 9864 _buf << indent(1) << "local "sv << selfVar << " = setmetatable({ }, "sv << baseVar << ")"sv << nl(classDecl);
9031 _buf << indent(1) << "cls.__init("sv << selfVar << ", ...)"sv << nll(classDecl); 9865 _buf << indent(1) << "cls.__init("sv << selfVar << ", ...)"sv << nl(classDecl);
9032 _buf << indent(1) << "return "sv << selfVar << nll(classDecl); 9866 _buf << indent(1) << "return "sv << selfVar << nl(classDecl);
9033 popScope(); 9867 popScope();
9034 _buf << indent(1) << "end"sv << nll(classDecl); 9868 _buf << indent(1) << "end"sv << nl(classDecl);
9035 _buf << indent() << "})"sv << nll(classDecl); 9869 _buf << indent() << "})"sv << nl(classDecl);
9036 _buf << indent() << baseVar << ".__class = "sv << classVar << nll(classDecl); 9870 _buf << indent() << baseVar << ".__class = "sv << classVar << nl(classDecl);
9037 if (!statements.empty()) { 9871 if (!statements.empty()) {
9038 _buf << indent() << "local self = "sv << classVar << ';' << nll(classDecl); 9872 _buf << indent() << "local self = "sv << classVar << ';' << nl(classDecl);
9039 } 9873 }
9040 _buf << join(statements); 9874 _buf << join(statements);
9041 if (extend) { 9875 if (extend) {
9042 _buf << indent() << "if "sv << parentVar << ".__inherited then"sv << nll(classDecl); 9876 _buf << indent() << "if "sv << parentVar << ".__inherited then"sv << nl(classDecl);
9043 _buf << indent(1) << parentVar << ".__inherited("sv << parentVar << ", "sv << classVar << ")"sv << nll(classDecl); 9877 _buf << indent(1) << parentVar << ".__inherited("sv << parentVar << ", "sv << classVar << ")"sv << nl(classDecl);
9044 _buf << indent() << "end"sv << nll(classDecl); 9878 _buf << indent() << "end"sv << nl(classDecl);
9045 } 9879 }
9046 if (!assignItem.empty()) { 9880 if (!assignItem.empty()) {
9047 _buf << indent() << assignItem << " = "sv << classVar << nll(classDecl); 9881 _buf << indent() << assignItem << " = "sv << classVar << nl(classDecl);
9048 } 9882 }
9049 switch (usage) { 9883 switch (usage) {
9050 case ExpUsage::Return: { 9884 case ExpUsage::Return: {
9051 _buf << indent() << "return "sv << classVar << nlr(classDecl); 9885 _buf << indent() << "return "sv << classVar << nl(classDecl);
9052 break; 9886 break;
9053 } 9887 }
9054 case ExpUsage::Assignment: { 9888 case ExpUsage::Assignment: {
@@ -9060,7 +9894,7 @@ private:
9060 temp.push_back(clearBuf()); 9894 temp.push_back(clearBuf());
9061 if (isScoped) { 9895 if (isScoped) {
9062 popScope(); 9896 popScope();
9063 temp.push_back(indent() + "end"s + nlr(classDecl)); 9897 temp.push_back(indent() + "end"s + nl(classDecl));
9064 } 9898 }
9065 out.push_back(join(temp)); 9899 out.push_back(join(temp));
9066 } 9900 }
@@ -9223,7 +10057,7 @@ private:
9223 pushScope(); 10057 pushScope();
9224 transformWith(with, temp, nullptr, true); 10058 transformWith(with, temp, nullptr, true);
9225 popScope(); 10059 popScope();
9226 funcStart = anonFuncStart() + nll(with); 10060 funcStart = anonFuncStart() + nl(with);
9227 temp.push_back(indent() + anonFuncEnd()); 10061 temp.push_back(indent() + anonFuncEnd());
9228 popAnonVarArg(); 10062 popAnonVarArg();
9229 popFunctionScope(); 10063 popFunctionScope();
@@ -9236,11 +10070,11 @@ private:
9236 std::string withVar; 10070 std::string withVar;
9237 bool needScope = !currentScope().lastStatement && !returnValue; 10071 bool needScope = !currentScope().lastStatement && !returnValue;
9238 bool extraScope = false; 10072 bool extraScope = false;
9239 if (with->assigns) { 10073 if (with->assign) {
9240 auto vars = getAssignVars(with); 10074 auto vars = getAssignVars(with);
9241 if (vars.front().empty() || isDeclaredAsGlobal(vars.front())) { 10075 if (vars.front().empty() || isDeclaredAsGlobal(vars.front())) {
9242 if (with->assigns->values.objects().size() == 1) { 10076 if (with->assign->values.objects().size() == 1) {
9243 auto var = singleVariableFrom(with->assigns->values.objects().front(), AccessType::Read); 10077 auto var = singleVariableFrom(with->assign->values.objects().front(), AccessType::Read);
9244 if (!var.empty() && isLocal(var)) { 10078 if (!var.empty() && isLocal(var)) {
9245 withVar = var; 10079 withVar = var;
9246 } 10080 }
@@ -9250,11 +10084,11 @@ private:
9250 auto assignment = x->new_ptr<ExpListAssign_t>(); 10084 auto assignment = x->new_ptr<ExpListAssign_t>();
9251 assignment->expList.set(toAst<ExpList_t>(withVar, x)); 10085 assignment->expList.set(toAst<ExpList_t>(withVar, x));
9252 auto assign = x->new_ptr<Assign_t>(); 10086 auto assign = x->new_ptr<Assign_t>();
9253 assign->values.push_back(with->assigns->values.objects().front()); 10087 assign->values.push_back(with->assign->values.objects().front());
9254 assignment->action.set(assign); 10088 assignment->action.set(assign);
9255 if (needScope) { 10089 if (needScope) {
9256 extraScope = true; 10090 extraScope = true;
9257 temp.push_back(indent() + "do"s + nll(with)); 10091 temp.push_back(indent() + "do"s + nl(with));
9258 pushScope(); 10092 pushScope();
9259 } 10093 }
9260 transformAssignment(assignment, temp); 10094 transformAssignment(assignment, temp);
@@ -9264,7 +10098,7 @@ private:
9264 auto assign = x->new_ptr<Assign_t>(); 10098 auto assign = x->new_ptr<Assign_t>();
9265 assign->values.push_back(toAst<Exp_t>(withVar, x)); 10099 assign->values.push_back(toAst<Exp_t>(withVar, x));
9266 bool skipFirst = true; 10100 bool skipFirst = true;
9267 for (auto value : with->assigns->values.objects()) { 10101 for (auto value : with->assign->values.objects()) {
9268 if (skipFirst) { 10102 if (skipFirst) {
9269 skipFirst = false; 10103 skipFirst = false;
9270 continue; 10104 continue;
@@ -9277,10 +10111,10 @@ private:
9277 withVar = vars.front(); 10111 withVar = vars.front();
9278 auto assignment = x->new_ptr<ExpListAssign_t>(); 10112 auto assignment = x->new_ptr<ExpListAssign_t>();
9279 assignment->expList.set(with->valueList); 10113 assignment->expList.set(with->valueList);
9280 assignment->action.set(with->assigns); 10114 assignment->action.set(with->assign);
9281 if (needScope) { 10115 if (needScope) {
9282 extraScope = true; 10116 extraScope = true;
9283 temp.push_back(indent() + "do"s + nll(with)); 10117 temp.push_back(indent() + "do"s + nl(with));
9284 pushScope(); 10118 pushScope();
9285 } 10119 }
9286 transformAssignment(assignment, temp); 10120 transformAssignment(assignment, temp);
@@ -9296,7 +10130,7 @@ private:
9296 assignment->action.set(assign); 10130 assignment->action.set(assign);
9297 if (needScope) { 10131 if (needScope) {
9298 extraScope = true; 10132 extraScope = true;
9299 temp.push_back(indent() + "do"s + nll(with)); 10133 temp.push_back(indent() + "do"s + nl(with));
9300 pushScope(); 10134 pushScope();
9301 } 10135 }
9302 transformAssignment(assignment, temp); 10136 transformAssignment(assignment, temp);
@@ -9350,27 +10184,69 @@ private:
9350 }); 10184 });
9351 popScope(); 10185 popScope();
9352 if (extraScope) { 10186 if (extraScope) {
9353 temp.push_back(indent() + "do"s + nll(with)); 10187 temp.push_back(indent() + "do"s + nl(with));
9354 pushScope(); 10188 pushScope();
9355 } 10189 }
9356 } 10190 }
9357 _withVars.push(withVar); 10191 _withVars.push(withVar);
10192 std::string breakWithVar;
10193 if (assignList || returnValue) {
10194 auto breakLoopType = getBreakLoopType(with->body, withVar);
10195 if (hasBreakWithValue(breakLoopType)) {
10196 breakWithVar = withVar;
10197 }
10198 }
9358 if (with->eop) { 10199 if (with->eop) {
9359 auto ifNode = x->new_ptr<If_t>(); 10200 auto ifNode = x->new_ptr<If_t>();
9360 ifNode->type.set(toAst<IfType_t>("if"sv, x)); 10201 ifNode->type.set(toAst<IfType_t>("if"sv, x));
9361 ifNode->nodes.push_back(toAst<IfCond_t>(withVar + "~=nil"s, x)); 10202 ifNode->nodes.push_back(toAst<IfCond_t>(withVar + "~=nil"s, x));
9362 ifNode->nodes.push_back(with->body); 10203 ifNode->nodes.push_back(with->body);
9363 transformIf(ifNode, temp, ExpUsage::Common); 10204 if (breakWithVar.empty()) {
10205 transformIf(ifNode, temp, ExpUsage::Common);
10206 } else {
10207 auto simpleValue = x->new_ptr<SimpleValue_t>();
10208 simpleValue->value.set(ifNode);
10209 auto exp = newExp(simpleValue, x);
10210 auto expList = x->new_ptr<ExpList_t>();
10211 expList->exprs.push_back(exp);
10212 auto expListAssign = x->new_ptr<ExpListAssign_t>();
10213 expListAssign->expList.set(expList);
10214 auto stmt = x->new_ptr<Statement_t>();
10215 stmt->content.set(expListAssign);
10216 auto repeatNode = toAst<Repeat_t>("repeat\n\t--\nuntil true"s, x);
10217 auto block = x->new_ptr<Block_t>();
10218 block->statementOrComments.push_back(stmt);
10219 repeatNode->body.set(block);
10220 auto sVal = x->new_ptr<SimpleValue_t>();
10221 sVal->value.set(repeatNode);
10222 auto asmt = assignmentFrom(toAst<Exp_t>(breakWithVar, x), newExp(sVal, x), x);
10223 transformAssignment(asmt, temp);
10224 }
9364 } else { 10225 } else {
9365 bool transformed = false; 10226 bool transformed = false;
9366 if (!extraScope && assignList) { 10227 if (!breakWithVar.empty()) {
10228 auto repeatNode = toAst<Repeat_t>("repeat\n\t--\nuntil true"s, x);
10229 auto block = x->new_ptr<Block_t>();
10230 if (auto blk = with->body.as<Block_t>()) {
10231 block->statementOrComments.dup(blk->statementOrComments);
10232 } else {
10233 auto stmt = with->body.to<Statement_t>();
10234 block->statementOrComments.push_back(stmt);
10235 }
10236 repeatNode->body.set(block);
10237 auto sVal = x->new_ptr<SimpleValue_t>();
10238 sVal->value.set(repeatNode);
10239 auto asmt = assignmentFrom(toAst<Exp_t>(breakWithVar, x), newExp(sVal, x), x);
10240 transformAssignment(asmt, temp);
10241 transformed = true;
10242 } else if (!extraScope && assignList) {
9367 if (auto block = with->body.as<Block_t>()) { 10243 if (auto block = with->body.as<Block_t>()) {
9368 if (!block->statements.empty()) { 10244 if (!block->statementOrComments.empty()) {
9369 Statement_t* stmt = static_cast<Statement_t*>(block->statements.back()); 10245 Statement_t* stmt = lastStatementFrom(block);
9370 if (stmt->content.is<Return_t>()) { 10246 if (stmt && stmt->content.is<Return_t>()) {
9371 auto newBlock = with->body->new_ptr<Block_t>(); 10247 auto newBlock = with->body->new_ptr<Block_t>();
9372 newBlock->statements.dup(block->statements); 10248 newBlock->statementOrComments.dup(block->statementOrComments);
9373 newBlock->statements.pop_back(); 10249 newBlock->statementOrComments.pop_back();
9374 transform_plain_body(newBlock, temp, ExpUsage::Common); 10250 transform_plain_body(newBlock, temp, ExpUsage::Common);
9375 auto newBody = stmt->new_ptr<Body_t>(); 10251 auto newBody = stmt->new_ptr<Body_t>();
9376 newBody->content.set(stmt); 10252 newBody->content.set(stmt);
@@ -9408,12 +10284,12 @@ private:
9408 if (returnValue) { 10284 if (returnValue) {
9409 auto last = lastStatementFrom(with->body); 10285 auto last = lastStatementFrom(with->body);
9410 if (last && !last->content.is<Return_t>()) { 10286 if (last && !last->content.is<Return_t>()) {
9411 temp.push_back(indent() + "return "s + withVar + nll(with)); 10287 temp.push_back(indent() + "return "s + withVar + nl(with));
9412 } 10288 }
9413 } 10289 }
9414 if (extraScope) { 10290 if (extraScope) {
9415 popScope(); 10291 popScope();
9416 temp.push_back(indent() + "end"s + nll(with)); 10292 temp.push_back(indent() + "end"s + nl(with));
9417 } 10293 }
9418 out.push_back(join(temp)); 10294 out.push_back(join(temp));
9419 } 10295 }
@@ -9428,12 +10304,18 @@ private:
9428 switch (item->get_id()) { 10304 switch (item->get_id()) {
9429 case id<ClassDecl_t>(): { 10305 case id<ClassDecl_t>(): {
9430 auto classDecl = static_cast<ClassDecl_t*>(item); 10306 auto classDecl = static_cast<ClassDecl_t*>(item);
10307 std::string varName;
9431 if (classDecl->name) { 10308 if (classDecl->name) {
9432 if (auto var = classDecl->name->item.as<Variable_t>()) { 10309 if (auto var = classDecl->name->item.as<Variable_t>()) {
9433 addGlobalVar(variableToString(var), classDecl->name->item); 10310 varName = variableToString(var);
10311 addGlobalVar(varName, var);
9434 } 10312 }
9435 } 10313 }
10314 if (varName.empty()) {
10315 throw CompileError("missing name for class", classDecl);
10316 }
9436 transformClassDecl(classDecl, out, ExpUsage::Common); 10317 transformClassDecl(classDecl, out, ExpUsage::Common);
10318 markVarGlobalConst(varName);
9437 break; 10319 break;
9438 } 10320 }
9439 case id<GlobalOp_t>(): 10321 case id<GlobalOp_t>():
@@ -9447,9 +10329,11 @@ private:
9447 auto values = global->item.to<GlobalValues_t>(); 10329 auto values = global->item.to<GlobalValues_t>();
9448 if (values->valueList) { 10330 if (values->valueList) {
9449 auto expList = x->new_ptr<ExpList_t>(); 10331 auto expList = x->new_ptr<ExpList_t>();
10332 str_list varNames;
9450 for (auto name : values->nameList->names.objects()) { 10333 for (auto name : values->nameList->names.objects()) {
9451 auto var = static_cast<Variable_t*>(name); 10334 auto var = static_cast<Variable_t*>(name);
9452 addGlobalVar(variableToString(var), var); 10335 varNames.emplace_back(variableToString(var));
10336 addGlobalVar(varNames.back(), var);
9453 auto callable = x->new_ptr<Callable_t>(); 10337 auto callable = x->new_ptr<Callable_t>();
9454 callable->item.set(name); 10338 callable->item.set(name);
9455 auto chainValue = x->new_ptr<ChainValue_t>(); 10339 auto chainValue = x->new_ptr<ChainValue_t>();
@@ -9460,18 +10344,27 @@ private:
9460 auto assignment = x->new_ptr<ExpListAssign_t>(); 10344 auto assignment = x->new_ptr<ExpListAssign_t>();
9461 assignment->expList.set(expList); 10345 assignment->expList.set(expList);
9462 auto assign = x->new_ptr<Assign_t>(); 10346 auto assign = x->new_ptr<Assign_t>();
9463 if (auto expListLow = values->valueList.as<ExpListLow_t>()) { 10347 if (auto expList = values->valueList.as<ExpList_t>()) {
9464 assign->values.dup(expListLow->exprs); 10348 assign->values.dup(expList->exprs);
9465 } else { 10349 } else {
9466 auto tableBlock = values->valueList.to<TableBlock_t>(); 10350 auto tableBlock = values->valueList.to<TableBlock_t>();
9467 assign->values.push_back(tableBlock); 10351 assign->values.push_back(tableBlock);
9468 } 10352 }
9469 assignment->action.set(assign); 10353 assignment->action.set(assign);
9470 transformAssignment(assignment, out); 10354 transformAssignment(assignment, out);
10355 if (global->constAttrib) {
10356 for (const auto& name : varNames) {
10357 markVarGlobalConst(name);
10358 }
10359 }
9471 } else { 10360 } else {
9472 for (auto name : values->nameList->names.objects()) { 10361 for (auto name : values->nameList->names.objects()) {
9473 auto var = static_cast<Variable_t*>(name); 10362 auto var = static_cast<Variable_t*>(name);
9474 addGlobalVar(variableToString(var), var); 10363 auto varName = variableToString(var);
10364 addGlobalVar(varName, var);
10365 if (global->constAttrib) {
10366 markVarGlobalConst(varName);
10367 }
9475 } 10368 }
9476 } 10369 }
9477 break; 10370 break;
@@ -9608,7 +10501,7 @@ private:
9608 } 10501 }
9609 } 10502 }
9610 if (_info.exportDefault) { 10503 if (_info.exportDefault) {
9611 out.back().append(indent() + _info.moduleName + " = "s + names.back().first + nlr(exportNode)); 10504 out.back().append(indent() + _info.moduleName + " = "s + names.back().first + nl(exportNode));
9612 } else { 10505 } else {
9613 str_list lefts, rights; 10506 str_list lefts, rights;
9614 for (const auto& name : names) { 10507 for (const auto& name : names) {
@@ -9621,7 +10514,7 @@ private:
9621 lefts.push_back(_info.moduleName + "[\""s + realName + "\"]"s); 10514 lefts.push_back(_info.moduleName + "[\""s + realName + "\"]"s);
9622 rights.push_back(name.first); 10515 rights.push_back(name.first);
9623 } 10516 }
9624 out.back().append(indent() + join(lefts, ", "sv) + " = "s + join(rights, ", "sv) + nlr(exportNode)); 10517 out.back().append(indent() + join(lefts, ", "sv) + " = "s + join(rights, ", "sv) + nl(exportNode));
9625 } 10518 }
9626 } 10519 }
9627 } else { 10520 } else {
@@ -9705,12 +10598,12 @@ private:
9705 case id<CompForEach_t>(): 10598 case id<CompForEach_t>():
9706 transformCompForEach(static_cast<CompForEach_t*>(item), temp); 10599 transformCompForEach(static_cast<CompForEach_t*>(item), temp);
9707 break; 10600 break;
9708 case id<CompFor_t>(): 10601 case id<CompForNum_t>():
9709 transformCompFor(static_cast<CompFor_t*>(item), temp); 10602 transformCompForNum(static_cast<CompForNum_t*>(item), temp);
9710 break; 10603 break;
9711 case id<Exp_t>(): 10604 case id<Exp_t>():
9712 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure); 10605 transformExp(static_cast<Exp_t*>(item), temp, ExpUsage::Closure);
9713 temp.back() = indent() + "if "s + temp.back() + " then"s + nll(item); 10606 temp.back() = indent() + "if "s + temp.back() + " then"s + nl(item);
9714 pushScope(); 10607 pushScope();
9715 break; 10608 break;
9716 default: YUEE("AST node mismatch", item); break; 10609 default: YUEE("AST node mismatch", item); break;
@@ -9723,27 +10616,27 @@ private:
9723 for (size_t i = 0; i < compInner->items.objects().size(); ++i) { 10616 for (size_t i = 0; i < compInner->items.objects().size(); ++i) {
9724 popScope(); 10617 popScope();
9725 } 10618 }
9726 _buf << indent() << "local "sv << tbl << " = { }"sv << nll(comp); 10619 _buf << indent() << "local "sv << tbl << " = { }"sv << nl(comp);
9727 _buf << join(temp); 10620 _buf << join(temp);
9728 pushScope(); 10621 pushScope();
9729 if (!comp->value) { 10622 if (!comp->value) {
9730 auto keyVar = getUnusedName("_key_"sv); 10623 auto keyVar = getUnusedName("_key_"sv);
9731 auto valVar = getUnusedName("_val_"sv); 10624 auto valVar = getUnusedName("_val_"sv);
9732 _buf << indent(int(temp.size()) - 1) << "local "sv << keyVar << ", "sv << valVar << " = "sv << kv.front() << nll(comp); 10625 _buf << indent(int(temp.size()) - 1) << "local "sv << keyVar << ", "sv << valVar << " = "sv << kv.front() << nl(comp);
9733 kv.front() = keyVar; 10626 kv.front() = keyVar;
9734 kv.push_back(valVar); 10627 kv.push_back(valVar);
9735 } 10628 }
9736 _buf << indent(int(temp.size()) - 1) << tbl << "["sv << kv.front() << "] = "sv << kv.back() << nll(comp); 10629 _buf << indent(int(temp.size()) - 1) << tbl << "["sv << kv.front() << "] = "sv << kv.back() << nl(comp);
9737 for (int ind = int(temp.size()) - 2; ind > -1; --ind) { 10630 for (int ind = int(temp.size()) - 2; ind > -1; --ind) {
9738 _buf << indent(ind) << "end"sv << nll(comp); 10631 _buf << indent(ind) << "end"sv << nl(comp);
9739 } 10632 }
9740 popScope(); 10633 popScope();
9741 _buf << indent() << "end"sv << nll(comp); 10634 _buf << indent() << "end"sv << nl(comp);
9742 switch (usage) { 10635 switch (usage) {
9743 case ExpUsage::Closure: 10636 case ExpUsage::Closure:
9744 out.push_back(clearBuf() + indent() + "return "s + tbl + nlr(comp)); 10637 out.push_back(clearBuf() + indent() + "return "s + tbl + nl(comp));
9745 popScope(); 10638 popScope();
9746 out.back().insert(0, anonFuncStart() + nll(comp)); 10639 out.back().insert(0, anonFuncStart() + nl(comp));
9747 out.back().append(indent() + anonFuncEnd()); 10640 out.back().append(indent() + anonFuncEnd());
9748 popAnonVarArg(); 10641 popAnonVarArg();
9749 popFunctionScope(); 10642 popFunctionScope();
@@ -9759,21 +10652,21 @@ private:
9759 out.back().append(temp.back()); 10652 out.back().append(temp.back());
9760 if (extraScope) { 10653 if (extraScope) {
9761 popScope(); 10654 popScope();
9762 out.back().insert(0, indent() + "do"s + nll(comp)); 10655 out.back().insert(0, indent() + "do"s + nl(comp));
9763 out.back().append(indent() + "end"s + nlr(comp)); 10656 out.back().append(indent() + "end"s + nl(comp));
9764 } 10657 }
9765 break; 10658 break;
9766 } 10659 }
9767 case ExpUsage::Return: 10660 case ExpUsage::Return:
9768 out.push_back(clearBuf() + indent() + "return "s + tbl + nlr(comp)); 10661 out.push_back(clearBuf() + indent() + "return "s + tbl + nl(comp));
9769 break; 10662 break;
9770 default: 10663 default:
9771 break; 10664 break;
9772 } 10665 }
9773 } 10666 }
9774 10667
9775 void transformCompFor(CompFor_t* comp, str_list& out) { 10668 void transformCompForNum(CompForNum_t* comp, str_list& out) {
9776 transformForHead(comp->varName, comp->startValue, comp->stopValue, comp->stepValue, out); 10669 transformForNumHead(comp->varName, comp->startValue, comp->stopValue, comp->stepValue, out);
9777 } 10670 }
9778 10671
9779 void transformTableBlockIndent(TableBlockIndent_t* table, str_list& out) { 10672 void transformTableBlockIndent(TableBlockIndent_t* table, str_list& out) {
@@ -9803,25 +10696,64 @@ private:
9803 funcStart = &temp.emplace_back(); 10696 funcStart = &temp.emplace_back();
9804 pushScope(); 10697 pushScope();
9805 } else { 10698 } else {
9806 temp.push_back(indent() + "do"s + nll(doNode)); 10699 temp.push_back(indent() + "do"s + nl(doNode));
9807 pushScope(); 10700 pushScope();
9808 } 10701 }
9809 transformBody(doNode->body, temp, usage, assignList); 10702 transformBody(doNode->body, temp, usage, assignList);
9810 if (usage == ExpUsage::Closure) { 10703 if (usage == ExpUsage::Closure) {
9811 popScope(); 10704 popScope();
9812 *funcStart = anonFuncStart() + nll(doNode); 10705 *funcStart = anonFuncStart() + nl(doNode);
9813 temp.push_back(indent() + anonFuncEnd()); 10706 temp.push_back(indent() + anonFuncEnd());
9814 popAnonVarArg(); 10707 popAnonVarArg();
9815 popFunctionScope(); 10708 popFunctionScope();
9816 } else { 10709 } else {
9817 popScope(); 10710 popScope();
9818 temp.push_back(indent() + "end"s + nlr(doNode)); 10711 temp.push_back(indent() + "end"s + nl(doNode));
9819 } 10712 }
9820 out.push_back(join(temp)); 10713 out.push_back(join(temp));
9821 } 10714 }
9822 10715
9823 void transformTry(Try_t* tryNode, str_list& out, ExpUsage usage) { 10716 void transformTry(Try_t* tryNode, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) {
9824 auto x = tryNode; 10717 auto x = tryNode;
10718 if (tryNode->eop && usage == ExpUsage::Assignment) {
10719 str_list rets;
10720 pushScope();
10721 auto okVar = getUnusedName("_ok_"sv);
10722 for (size_t i = 0; i < assignList->exprs.size(); i++) {
10723 auto retVar = getUnusedName("_ret_"sv);
10724 rets.emplace_back(retVar);
10725 addToScope(retVar);
10726 }
10727 popScope();
10728 auto varList = join(rets, ","sv);
10729 auto ifNode = toAst<If_t>("if "s + okVar + ',' + varList + ":=try nil then "s + varList, x);
10730 auto exp = ast_to<IfCond_t>(ifNode->nodes.front())->assignment->assign->values.front();
10731 auto sVal = simpleSingleValueFrom(exp);
10732 auto newTry = sVal->value.to<Try_t>();
10733 newTry->func.set(tryNode->func);
10734 newTry->catchBlock.set(tryNode->catchBlock);
10735 auto assignment = x->new_ptr<ExpListAssign_t>();
10736 assignment->expList.set(assignList);
10737 auto assign = x->new_ptr<Assign_t>();
10738 assign->values.push_back(ifNode);
10739 assignment->action.set(assign);
10740 transformAssignment(assignment, out);
10741 return;
10742 }
10743 if (tryNode->eop && usage != ExpUsage::Common) {
10744 auto okVar = getUnusedName("_ok_"sv);
10745 auto code = "do\n\t"s + okVar + ", ... = try nil\n\t... if "s + okVar;
10746 auto doNode = toAst<Do_t>(code, x);
10747 auto block = doNode->body->content.to<Block_t>();
10748 auto asmt = static_cast<Statement_t*>(block->statementOrComments.front())->content.to<ExpListAssign_t>();
10749 auto assign = asmt->action.to<Assign_t>();
10750 auto sVal = simpleSingleValueFrom(assign->values.back());
10751 auto newTry = sVal->value.to<Try_t>();
10752 newTry->func.set(tryNode->func);
10753 newTry->catchBlock.set(tryNode->catchBlock);
10754 transformDo(doNode, out, usage);
10755 return;
10756 }
9825 ast_ptr<true, Exp_t> errHandler; 10757 ast_ptr<true, Exp_t> errHandler;
9826 if (tryNode->catchBlock) { 10758 if (tryNode->catchBlock) {
9827 auto catchBlock = tryNode->catchBlock.get(); 10759 auto catchBlock = tryNode->catchBlock.get();
@@ -9837,8 +10769,8 @@ private:
9837 tryFunc.set(tryNode->func); 10769 tryFunc.set(tryNode->func);
9838 if (auto tryBlock = tryFunc.as<Block_t>()) { 10770 if (auto tryBlock = tryFunc.as<Block_t>()) {
9839 BLOCK_START 10771 BLOCK_START
9840 BREAK_IF(tryBlock->statements.size() != 1); 10772 BREAK_IF(countStatementFrom(tryBlock) != 1);
9841 auto stmt = static_cast<Statement_t*>(tryBlock->statements.front()); 10773 auto stmt = firstStatementFrom(tryBlock);
9842 auto expListAssign = stmt->content.as<ExpListAssign_t>(); 10774 auto expListAssign = stmt->content.as<ExpListAssign_t>();
9843 BREAK_IF(!expListAssign); 10775 BREAK_IF(!expListAssign);
9844 BREAK_IF(expListAssign->action); 10776 BREAK_IF(expListAssign->action);
@@ -9902,7 +10834,7 @@ private:
9902 auto stmt = x->new_ptr<Statement_t>(); 10834 auto stmt = x->new_ptr<Statement_t>();
9903 stmt->content.set(expListAssign); 10835 stmt->content.set(expListAssign);
9904 auto block = x->new_ptr<Block_t>(); 10836 auto block = x->new_ptr<Block_t>();
9905 block->statements.push_back(stmt); 10837 block->statementOrComments.push_back(stmt);
9906 tryFunc.set(block); 10838 tryFunc.set(block);
9907 } 10839 }
9908 } 10840 }
@@ -9930,7 +10862,7 @@ private:
9930 } 10862 }
9931 if (usage == ExpUsage::Common) { 10863 if (usage == ExpUsage::Common) {
9932 out.back().insert(0, indent()); 10864 out.back().insert(0, indent());
9933 out.back().append(nlr(x)); 10865 out.back().append(nl(x));
9934 } 10866 }
9935 return; 10867 return;
9936 } 10868 }
@@ -9955,7 +10887,7 @@ private:
9955 } 10887 }
9956 if (usage == ExpUsage::Common) { 10888 if (usage == ExpUsage::Common) {
9957 out.back().insert(0, indent()); 10889 out.back().insert(0, indent());
9958 out.back().append(nlr(x)); 10890 out.back().append(nl(x));
9959 } 10891 }
9960 return; 10892 return;
9961 } else if (auto value = singleValueFrom(tryFunc)) { 10893 } else if (auto value = singleValueFrom(tryFunc)) {
@@ -10016,7 +10948,7 @@ private:
10016 } 10948 }
10017 if (usage == ExpUsage::Common) { 10949 if (usage == ExpUsage::Common) {
10018 out.back().insert(0, indent()); 10950 out.back().insert(0, indent());
10019 out.back().append(nlr(x)); 10951 out.back().append(nl(x));
10020 } 10952 }
10021 return; 10953 return;
10022 BLOCK_END 10954 BLOCK_END
@@ -10035,13 +10967,13 @@ private:
10035 } 10967 }
10036 if (usage == ExpUsage::Common) { 10968 if (usage == ExpUsage::Common) {
10037 out.back().insert(0, indent()); 10969 out.back().insert(0, indent());
10038 out.back().append(nlr(x)); 10970 out.back().append(nl(x));
10039 } 10971 }
10040 } 10972 }
10041 10973
10042 void transformImportFrom(ImportFrom_t* importNode, str_list& out) { 10974 void transformImportFrom(ImportFrom_t* importNode, str_list& out) {
10043 str_list temp; 10975 str_list temp;
10044 auto x = importNode; 10976 auto x = importNode->item.get();
10045 auto objVar = singleVariableFrom(importNode->item, AccessType::Read); 10977 auto objVar = singleVariableFrom(importNode->item, AccessType::Read);
10046 ast_ptr<false, ExpListAssign_t> objAssign; 10978 ast_ptr<false, ExpListAssign_t> objAssign;
10047 if (objVar.empty()) { 10979 if (objVar.empty()) {
@@ -10111,11 +11043,11 @@ private:
10111 if (objAssign) { 11043 if (objAssign) {
10112 auto preDef = toLocalDecl(transformAssignDefs(expList, DefOp::Mark)); 11044 auto preDef = toLocalDecl(transformAssignDefs(expList, DefOp::Mark));
10113 if (!preDef.empty()) { 11045 if (!preDef.empty()) {
10114 temp.push_back(preDef + nll(importNode)); 11046 temp.push_back(preDef + nl(importNode));
10115 } 11047 }
10116 if (!currentScope().lastStatement) { 11048 if (!currentScope().lastStatement) {
10117 extraScope = true; 11049 extraScope = true;
10118 temp.push_back(indent() + "do"s + nll(importNode)); 11050 temp.push_back(indent() + "do"s + nl(importNode));
10119 pushScope(); 11051 pushScope();
10120 } 11052 }
10121 transformAssignment(objAssign, temp); 11053 transformAssignment(objAssign, temp);
@@ -10127,13 +11059,13 @@ private:
10127 if (objAssign) { 11059 if (objAssign) {
10128 if (extraScope) { 11060 if (extraScope) {
10129 popScope(); 11061 popScope();
10130 temp.push_back(indent() + "end"s + nlr(importNode)); 11062 temp.push_back(indent() + "end"s + nl(importNode));
10131 } 11063 }
10132 } 11064 }
10133 out.push_back(join(temp)); 11065 out.push_back(join(temp));
10134 auto vars = getAssignVars(assignment); 11066 auto vars = getAssignVars(assignment);
10135 for (const auto& var : vars) { 11067 for (const auto& var : vars) {
10136 markVarConst(var); 11068 markVarLocalConst(var);
10137 } 11069 }
10138 } 11070 }
10139 11071
@@ -10361,12 +11293,36 @@ private:
10361 transformAssignment(assignment, out); 11293 transformAssignment(assignment, out);
10362 if (auto var = ast_cast<Variable_t>(target)) { 11294 if (auto var = ast_cast<Variable_t>(target)) {
10363 auto moduleName = variableToString(var); 11295 auto moduleName = variableToString(var);
10364 markVarConst(moduleName); 11296 markVarLocalConst(moduleName);
10365 } else { 11297 } else {
10366 markDestructureConst(assignment); 11298 markDestructureConst(assignment);
10367 } 11299 }
10368 } 11300 }
10369 11301
11302 void transformImportGlobal(ImportGlobal_t* importNode, str_list& out) {
11303 auto uname = static_cast<UnicodeName_t*>(importNode->segs.front());
11304 auto var = _parser.toString(uname);
11305 auto isNormal = _parser.match<Name_t>(var) && _parser.match<Variable_t>(var);
11306 auto varName = unicodeVariableFrom(uname);
11307 str_list temp;
11308 auto it = ++importNode->segs.objects().begin();
11309 for (; it != importNode->segs.objects().end(); ++it) {
11310 temp.emplace_back(_parser.toString(*it));
11311 }
11312 temp.emplace_front(var);
11313 if (isLocal(varName) || !isNormal) {
11314 temp.emplace_front("_G"s);
11315 }
11316 std::string stmt;
11317 if (importNode->target) {
11318 stmt = "const "s + _parser.toString(importNode->target) + '=' + join(temp, "."sv);
11319 } else {
11320 stmt = "const "s + temp.back() + '=' + join(temp, "."sv);
11321 }
11322 auto localAttrib = toAst<LocalAttrib_t>(stmt, importNode);
11323 transformLocalAttrib(localAttrib, out);
11324 }
11325
10370 void transformImport(Import_t* import, str_list& out) { 11326 void transformImport(Import_t* import, str_list& out) {
10371 auto content = import->content.get(); 11327 auto content = import->content.get();
10372 switch (content->get_id()) { 11328 switch (content->get_id()) {
@@ -10379,6 +11335,9 @@ private:
10379 case id<FromImport_t>(): 11335 case id<FromImport_t>():
10380 transformFromImport(static_cast<FromImport_t*>(content), out); 11336 transformFromImport(static_cast<FromImport_t*>(content), out);
10381 break; 11337 break;
11338 case id<ImportGlobal_t>():
11339 transformImportGlobal(static_cast<ImportGlobal_t*>(content), out);
11340 break;
10382 default: YUEE("AST node mismatch", content); break; 11341 default: YUEE("AST node mismatch", content); break;
10383 } 11342 }
10384 } 11343 }
@@ -10390,7 +11349,7 @@ private:
10390 if (expList) { 11349 if (expList) {
10391 if (!currentScope().lastStatement) { 11350 if (!currentScope().lastStatement) {
10392 extraScope = true; 11351 extraScope = true;
10393 temp.push_back(indent() + "do"s + nll(whileNode)); 11352 temp.push_back(indent() + "do"s + nl(whileNode));
10394 pushScope(); 11353 pushScope();
10395 } 11354 }
10396 } 11355 }
@@ -10398,17 +11357,29 @@ private:
10398 addToScope(accumVar); 11357 addToScope(accumVar);
10399 auto lenVar = getUnusedName("_len_"sv); 11358 auto lenVar = getUnusedName("_len_"sv);
10400 addToScope(lenVar); 11359 addToScope(lenVar);
10401 temp.push_back(indent() + "local "s + accumVar + " = { }"s + nll(whileNode)); 11360 auto breakLoopType = getBreakLoopType(whileNode->body, accumVar);
10402 temp.push_back(indent() + "local "s + lenVar + " = 1"s + nll(whileNode)); 11361 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(whileNode);
11362 temp.emplace_back(clearBuf());
11363 _buf << indent() << "local "s << lenVar << " = 1"s << nl(whileNode);
11364 auto& lenAssign = temp.emplace_back(clearBuf());
10403 bool isUntil = _parser.toString(whileNode->type) == "until"sv; 11365 bool isUntil = _parser.toString(whileNode->type) == "until"sv;
10404 auto condStr = transformCondExp(whileNode->condition, isUntil); 11366 auto condStr = transformCondExp(whileNode->condition, isUntil);
10405 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); 11367 temp.push_back(indent() + "while "s + condStr + " do"s + nl(whileNode));
10406 pushScope(); 11368 pushScope();
10407 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); 11369 if (hasBreakWithValue(breakLoopType)) {
10408 auto lenLine = lenVar + " = "s + lenVar + " + 1"s + nlr(whileNode); 11370 lenAssign.clear();
10409 transformLoopBody(whileNode->body, temp, lenLine, ExpUsage::Assignment, assignLeft); 11371 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common);
11372 } else {
11373 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x);
11374 auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, whileNode);
11375 assignLeft->followStmt = followStmt.get();
11376 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft);
11377 if (!assignLeft->followStmtProcessed) {
11378 lenAssign.clear();
11379 }
11380 }
10410 popScope(); 11381 popScope();
10411 temp.push_back(indent() + "end"s + nlr(whileNode)); 11382 temp.push_back(indent() + "end"s + nl(whileNode));
10412 if (expList) { 11383 if (expList) {
10413 auto assign = x->new_ptr<Assign_t>(); 11384 auto assign = x->new_ptr<Assign_t>();
10414 assign->values.push_back(toAst<Exp_t>(accumVar, x)); 11385 assign->values.push_back(toAst<Exp_t>(accumVar, x));
@@ -10418,10 +11389,10 @@ private:
10418 transformAssignment(assignment, temp); 11389 transformAssignment(assignment, temp);
10419 if (extraScope) popScope(); 11390 if (extraScope) popScope();
10420 } else { 11391 } else {
10421 temp.push_back(indent() + "return "s + accumVar + nlr(whileNode)); 11392 temp.push_back(indent() + "return "s + accumVar + nl(whileNode));
10422 } 11393 }
10423 if (expList && extraScope) { 11394 if (expList && extraScope) {
10424 temp.push_back(indent() + "end"s + nlr(whileNode)); 11395 temp.push_back(indent() + "end"s + nl(whileNode));
10425 } 11396 }
10426 out.push_back(join(temp)); 11397 out.push_back(join(temp));
10427 } 11398 }
@@ -10442,20 +11413,31 @@ private:
10442 addToScope(accumVar); 11413 addToScope(accumVar);
10443 auto lenVar = getUnusedName("_len_"sv); 11414 auto lenVar = getUnusedName("_len_"sv);
10444 addToScope(lenVar); 11415 addToScope(lenVar);
10445 temp.push_back(indent() + "local "s + accumVar + " = { }"s + nll(whileNode)); 11416 auto breakLoopType = getBreakLoopType(whileNode->body, accumVar);
10446 temp.push_back(indent() + "local "s + lenVar + " = 1"s + nll(whileNode)); 11417 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(whileNode);
11418 temp.emplace_back(clearBuf());
11419 auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nl(whileNode));
10447 bool isUntil = _parser.toString(whileNode->type) == "until"sv; 11420 bool isUntil = _parser.toString(whileNode->type) == "until"sv;
10448 auto condStr = transformCondExp(whileNode->condition, isUntil); 11421 auto condStr = transformCondExp(whileNode->condition, isUntil);
10449 temp.push_back(indent() + "while "s + condStr + " do"s + nll(whileNode)); 11422 temp.push_back(indent() + "while "s + condStr + " do"s + nl(whileNode));
10450 pushScope(); 11423 pushScope();
10451 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x); 11424 if (hasBreakWithValue(breakLoopType)) {
10452 auto lenLine = lenVar + " = "s + lenVar + " + 1"s + nlr(whileNode); 11425 lenAssign.clear();
10453 transformLoopBody(whileNode->body, temp, lenLine, ExpUsage::Assignment, assignLeft); 11426 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common);
11427 } else {
11428 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x);
11429 auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, whileNode);
11430 assignLeft->followStmt = followStmt.get();
11431 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft);
11432 if (!assignLeft->followStmtProcessed) {
11433 lenAssign.clear();
11434 }
11435 }
10454 popScope(); 11436 popScope();
10455 temp.push_back(indent() + "end"s + nlr(whileNode)); 11437 temp.push_back(indent() + "end"s + nl(whileNode));
10456 temp.push_back(indent() + "return "s + accumVar + nlr(whileNode)); 11438 temp.push_back(indent() + "return "s + accumVar + nl(whileNode));
10457 popScope(); 11439 popScope();
10458 funcStart = anonFuncStart() + nll(whileNode); 11440 funcStart = anonFuncStart() + nl(whileNode);
10459 temp.push_back(indent() + anonFuncEnd()); 11441 temp.push_back(indent() + anonFuncEnd());
10460 popAnonVarArg(); 11442 popAnonVarArg();
10461 popFunctionScope(); 11443 popFunctionScope();
@@ -10485,9 +11467,7 @@ private:
10485 expListAssign->expList.set(expList); 11467 expListAssign->expList.set(expList);
10486 auto stmt = x->new_ptr<Statement_t>(); 11468 auto stmt = x->new_ptr<Statement_t>();
10487 stmt->content.set(expListAssign); 11469 stmt->content.set(expListAssign);
10488 auto body = x->new_ptr<Body_t>(); 11470 repeat->body.set(stmt);
10489 body->content.set(stmt);
10490 repeat->body.set(body);
10491 transformRepeat(repeat, out); 11471 transformRepeat(repeat, out);
10492 return; 11472 return;
10493 } 11473 }
@@ -10495,14 +11475,115 @@ private:
10495 pushScope(); 11475 pushScope();
10496 bool isUntil = _parser.toString(whileNode->type) == "until"sv; 11476 bool isUntil = _parser.toString(whileNode->type) == "until"sv;
10497 auto condStr = transformCondExp(whileNode->condition, isUntil); 11477 auto condStr = transformCondExp(whileNode->condition, isUntil);
10498 transformLoopBody(whileNode->body, temp, Empty, ExpUsage::Common); 11478 auto breakLoopType = getBreakLoopType(whileNode->body, Empty);
11479 transformLoopBody(whileNode->body, temp, breakLoopType, ExpUsage::Common);
10499 popScope(); 11480 popScope();
10500 _buf << indent() << "while "sv << condStr << " do"sv << nll(whileNode); 11481 _buf << indent() << "while "sv << condStr << " do"sv << nl(whileNode);
10501 _buf << temp.back(); 11482 _buf << temp.back();
10502 _buf << indent() << "end"sv << nlr(whileNode); 11483 _buf << indent() << "end"sv << nl(whileNode);
10503 out.push_back(clearBuf()); 11484 out.push_back(clearBuf());
10504 } 11485 }
10505 11486
11487 void transformRepeatInPlace(Repeat_t* repeatNode, str_list& out, ExpList_t* expList = nullptr) {
11488 auto x = repeatNode;
11489 str_list temp;
11490 bool extraScope = false;
11491 if (expList) {
11492 if (!currentScope().lastStatement) {
11493 extraScope = true;
11494 temp.push_back(indent() + "do"s + nl(repeatNode));
11495 pushScope();
11496 }
11497 }
11498 auto accumVar = getUnusedName("_accum_"sv);
11499 addToScope(accumVar);
11500 auto lenVar = getUnusedName("_len_"sv);
11501 addToScope(lenVar);
11502 auto breakLoopType = getBreakLoopType(repeatNode->body, accumVar);
11503 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(repeatNode);
11504 temp.emplace_back(clearBuf());
11505 _buf << indent() << "local "s << lenVar << " = 1"s << nl(repeatNode);
11506 auto& lenAssign = temp.emplace_back(clearBuf());
11507 auto condStr = transformCondExp(repeatNode->condition, false);
11508 temp.push_back(indent() + "repeat"s + nl(repeatNode));
11509 pushScope();
11510 if (hasBreakWithValue(breakLoopType)) {
11511 lenAssign.clear();
11512 transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Common);
11513 } else {
11514 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x);
11515 auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, repeatNode);
11516 assignLeft->followStmt = followStmt.get();
11517 transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft);
11518 if (!assignLeft->followStmtProcessed) {
11519 lenAssign.clear();
11520 }
11521 }
11522 popScope();
11523 temp.push_back(indent() + "until "s + condStr + nl(repeatNode));
11524 if (expList) {
11525 auto assign = x->new_ptr<Assign_t>();
11526 assign->values.push_back(toAst<Exp_t>(accumVar, x));
11527 auto assignment = x->new_ptr<ExpListAssign_t>();
11528 assignment->expList.set(expList);
11529 assignment->action.set(assign);
11530 transformAssignment(assignment, temp);
11531 if (extraScope) popScope();
11532 } else {
11533 temp.push_back(indent() + "return "s + accumVar + nl(repeatNode));
11534 }
11535 if (expList && extraScope) {
11536 temp.push_back(indent() + "end"s + nl(repeatNode));
11537 }
11538 out.push_back(join(temp));
11539 }
11540
11541 void transformRepeatClosure(Repeat_t* repeatNode, str_list& out) {
11542 auto x = repeatNode;
11543 auto simpleValue = x->new_ptr<SimpleValue_t>();
11544 simpleValue->value.set(repeatNode);
11545 if (transformAsUpValueFunc(newExp(simpleValue, x), out)) {
11546 return;
11547 }
11548 str_list temp;
11549 pushAnonFunctionScope();
11550 pushAnonVarArg();
11551 std::string& funcStart = temp.emplace_back();
11552 pushScope();
11553 auto accumVar = getUnusedName("_accum_"sv);
11554 addToScope(accumVar);
11555 auto lenVar = getUnusedName("_len_"sv);
11556 addToScope(lenVar);
11557 auto breakLoopType = getBreakLoopType(repeatNode->body, accumVar);
11558 _buf << indent() << "local "sv << accumVar << (hasBreakWithValue(breakLoopType) ? ""sv : " = { }"sv) << nl(repeatNode);
11559 temp.emplace_back(clearBuf());
11560 auto& lenAssign = temp.emplace_back(indent() + "local "s + lenVar + " = 1"s + nl(repeatNode));
11561 auto condStr = transformCondExp(repeatNode->condition, false);
11562 temp.push_back(indent() + "repeat"s + nl(repeatNode));
11563 pushScope();
11564 if (hasBreakWithValue(breakLoopType)) {
11565 lenAssign.clear();
11566 transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Common);
11567 } else {
11568 auto assignLeft = toAst<ExpList_t>(accumVar + '[' + lenVar + ']', x);
11569 auto followStmt = toAst<Statement_t>(lenVar + "+=1"s, repeatNode);
11570 assignLeft->followStmt = followStmt.get();
11571 transformLoopBody(repeatNode->body, temp, breakLoopType, ExpUsage::Assignment, assignLeft);
11572 if (!assignLeft->followStmtProcessed) {
11573 lenAssign.clear();
11574 }
11575 }
11576 popScope();
11577 temp.push_back(indent() + "until "s + condStr + nl(repeatNode));
11578 temp.push_back(indent() + "return "s + accumVar + nl(repeatNode));
11579 popScope();
11580 funcStart = anonFuncStart() + nl(repeatNode);
11581 temp.push_back(indent() + anonFuncEnd());
11582 popAnonVarArg();
11583 popFunctionScope();
11584 out.push_back(join(temp));
11585 }
11586
10506 void transformRepeat(Repeat_t* repeat, str_list& out) { 11587 void transformRepeat(Repeat_t* repeat, str_list& out) {
10507 str_list temp; 11588 str_list temp;
10508 pushScope(); 11589 pushScope();
@@ -10513,9 +11594,9 @@ private:
10513 temp.push_back(condVar); 11594 temp.push_back(condVar);
10514 } 11595 }
10515 popScope(); 11596 popScope();
10516 _buf << indent() << "repeat"sv << nll(repeat); 11597 _buf << indent() << "repeat"sv << nl(repeat);
10517 _buf << temp.front(); 11598 _buf << temp.front();
10518 _buf << indent() << "until "sv << temp.back() << nlr(repeat); 11599 _buf << indent() << "until "sv << temp.back() << nl(repeat);
10519 out.push_back(clearBuf()); 11600 out.push_back(clearBuf());
10520 } 11601 }
10521 11602
@@ -10536,12 +11617,28 @@ private:
10536 pushScope(); 11617 pushScope();
10537 } 11618 }
10538 bool extraScope = false; 11619 bool extraScope = false;
11620 if (switchNode->assignment) {
11621 if (needScope) {
11622 extraScope = true;
11623 temp.push_back(indent() + "do"s + nl(x));
11624 pushScope();
11625 }
11626 auto asmt = x->new_ptr<ExpListAssign_t>();
11627 auto expList = x->new_ptr<ExpList_t>();
11628 expList->exprs.push_back(switchNode->target);
11629 if (switchNode->assignment->expList) {
11630 expList->exprs.dup(switchNode->assignment->expList->exprs);
11631 }
11632 asmt->expList.set(expList);
11633 asmt->action.set(switchNode->assignment->assign);
11634 transformAssignment(asmt, temp);
11635 }
10539 auto objVar = singleVariableFrom(switchNode->target, AccessType::Read); 11636 auto objVar = singleVariableFrom(switchNode->target, AccessType::Read);
10540 if (objVar.empty() || !isLocal(objVar)) { 11637 if (objVar.empty() || !isLocal(objVar)) {
10541 if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) { 11638 if (usage == ExpUsage::Common || usage == ExpUsage::Assignment) {
10542 if (needScope) { 11639 if (needScope && !extraScope) {
10543 extraScope = true; 11640 extraScope = true;
10544 temp.push_back(indent() + "do"s + nll(x)); 11641 temp.push_back(indent() + "do"s + nl(x));
10545 pushScope(); 11642 pushScope();
10546 } 11643 }
10547 } 11644 }
@@ -10571,13 +11668,13 @@ private:
10571 } 11668 }
10572 if (tableMatching) { 11669 if (tableMatching) {
10573 if (!firstBranch) { 11670 if (!firstBranch) {
10574 temp.push_back(indent() + "else"s + nll(branch)); 11671 temp.push_back(indent() + "else"s + nl(branch));
10575 pushScope(); 11672 pushScope();
10576 addScope++; 11673 addScope++;
10577 } 11674 }
10578 if (tabCheckVar.empty()) { 11675 if (tabCheckVar.empty()) {
10579 if (!extraScope && needScope) { 11676 if (!extraScope && needScope) {
10580 temp.push_back(indent() + "do"s + nll(branch)); 11677 temp.push_back(indent() + "do"s + nl(branch));
10581 pushScope(); 11678 pushScope();
10582 extraScope = true; 11679 extraScope = true;
10583 } 11680 }
@@ -10585,20 +11682,21 @@ private:
10585 forceAddToScope(typeVar); 11682 forceAddToScope(typeVar);
10586 tabCheckVar = getUnusedName("_tab_"sv); 11683 tabCheckVar = getUnusedName("_tab_"sv);
10587 forceAddToScope(tabCheckVar); 11684 forceAddToScope(tabCheckVar);
10588 temp.push_back(indent() + "local "s + typeVar + " = "s + globalVar("type"sv, branch, AccessType::Read) + '(' + objVar + ')' + nll(branch)); 11685 temp.push_back(indent() + "local "s + typeVar + " = "s + globalVar("type"sv, branch, AccessType::Read) + '(' + objVar + ')' + nl(branch));
10589 temp.push_back(indent() + "local "s + tabCheckVar + " = \"table\" == "s + typeVar + " or \"userdata\" == "s + typeVar + nll(branch)); 11686 temp.push_back(indent() + "local "s + tabCheckVar + " = \"table\" == "s + typeVar + " or \"userdata\" == "s + typeVar + nl(branch));
10590 } 11687 }
10591 std::string matchVar; 11688 std::string matchVar;
10592 bool lastBranch = branches.back() == branch_ && !switchNode->lastBranch; 11689 bool lastBranch = branches.back() == branch_ && !switchNode->lastBranch;
10593 if (!lastBranch) { 11690 if (!lastBranch) {
10594 matchVar = getUnusedName("_match_"sv); 11691 matchVar = getUnusedName("_match_"sv);
10595 forceAddToScope(matchVar); 11692 forceAddToScope(matchVar);
10596 temp.push_back(indent() + "local "s + matchVar + " = false"s + nll(branch)); 11693 temp.push_back(indent() + "local "s + matchVar + " = false"s + nl(branch));
10597 } 11694 }
10598 temp.back().append(indent() + "if "s + tabCheckVar + " then"s + nll(branch)); 11695 temp.back().append(indent() + "if "s + tabCheckVar + " then"s + nl(branch));
10599 pushScope(); 11696 pushScope();
10600 auto assignment = assignmentFrom(static_cast<Exp_t*>(valueList->exprs.front()), toAst<Exp_t>(objVar, branch), branch); 11697 auto chainValue = toAst<ChainValue_t>(objVar, branch);
10601 auto info = extractDestructureInfo(assignment, true, false); 11698 auto assignment = assignmentFrom(static_cast<Exp_t*>(valueList->exprs.front()), newExp(chainValue, branch), branch);
11699 auto info = extractDestructureInfo(assignment, true, true);
10602 transformAssignment(assignment, temp, true); 11700 transformAssignment(assignment, temp, true);
10603 str_list conds; 11701 str_list conds;
10604 for (const auto& des : info.destructures) { 11702 for (const auto& des : info.destructures) {
@@ -10608,27 +11706,50 @@ private:
10608 const auto& destruct = std::get<Destructure>(des); 11706 const auto& destruct = std::get<Destructure>(des);
10609 for (const auto& item : destruct.items) { 11707 for (const auto& item : destruct.items) {
10610 if (!item.defVal) { 11708 if (!item.defVal) {
10611 transformExp(item.target, conds, ExpUsage::Closure); 11709 if (!isAssignable(item.target)) {
10612 conds.back().append(" ~= nil"s); 11710 auto callable = chainValue->items.front();
11711 auto chain = callable->new_ptr<ChainValue_t>();
11712 chain->items.push_back(callable);
11713 chain->items.dup(item.structure->items);
11714 if (specialChainValue(chain) == ChainType::Common) {
11715 transformChainValue(chain, conds, ExpUsage::Closure);
11716 auto vStr = conds.back();
11717 conds.pop_back();
11718 transformExp(item.target, conds, ExpUsage::Closure);
11719 conds.back().append(" == "s);
11720 conds.back().append(vStr);
11721 } else {
11722 auto varName = getUnusedName("_val_"sv);
11723 auto vExp = toAst<Exp_t>(varName, chain);
11724 auto asmt = assignmentFrom(vExp, newExp(chain, chain), chain);
11725 transformAssignment(asmt, temp);
11726 transformExp(item.target, conds, ExpUsage::Closure);
11727 conds.back().append(" == "s);
11728 conds.back().append(varName);
11729 }
11730 } else {
11731 transformExp(item.target, conds, ExpUsage::Closure);
11732 conds.back().append(" ~= nil"s);
11733 }
10613 } 11734 }
10614 } 11735 }
10615 } 11736 }
10616 if (!conds.empty()) { 11737 if (!conds.empty()) {
10617 temp.push_back(indent() + "if "s + join(conds, " and "sv) + " then"s + nll(branch)); 11738 temp.push_back(indent() + "if "s + join(conds, " and "sv) + " then"s + nl(branch));
10618 pushScope(); 11739 pushScope();
10619 } 11740 }
10620 if (!lastBranch) { 11741 if (!lastBranch) {
10621 temp.push_back(indent() + matchVar + " = true"s + nll(branch)); 11742 temp.push_back(indent() + matchVar + " = true"s + nl(branch));
10622 } 11743 }
10623 transform_plain_body(branch->body, temp, usage, assignList); 11744 transform_plain_body(branch->body, temp, usage, assignList);
10624 if (!conds.empty()) { 11745 if (!conds.empty()) {
10625 popScope(); 11746 popScope();
10626 temp.push_back(indent() + "end"s + nll(branch)); 11747 temp.push_back(indent() + "end"s + nl(branch));
10627 } 11748 }
10628 if (!lastBranch) { 11749 if (!lastBranch) {
10629 popScope(); 11750 popScope();
10630 temp.push_back(indent() + "end"s + nll(branch)); 11751 temp.push_back(indent() + "end"s + nl(branch));
10631 temp.push_back(indent() + "if not "s + matchVar + " then"s + nll(branch)); 11752 temp.push_back(indent() + "if not "s + matchVar + " then"s + nl(branch));
10632 pushScope(); 11753 pushScope();
10633 addScope++; 11754 addScope++;
10634 } else { 11755 } else {
@@ -10648,7 +11769,7 @@ private:
10648 } 11769 }
10649 temp.back().append(' ' + tmp.back() + " == "s + (exp == exprs.back() ? objVar : objVar + " or"s)); 11770 temp.back().append(' ' + tmp.back() + " == "s + (exp == exprs.back() ? objVar : objVar + " or"s));
10650 } 11771 }
10651 temp.back().append(" then"s + nll(branch)); 11772 temp.back().append(" then"s + nl(branch));
10652 pushScope(); 11773 pushScope();
10653 transform_plain_body(branch->body, temp, usage, assignList); 11774 transform_plain_body(branch->body, temp, usage, assignList);
10654 popScope(); 11775 popScope();
@@ -10656,7 +11777,7 @@ private:
10656 } 11777 }
10657 if (switchNode->lastBranch) { 11778 if (switchNode->lastBranch) {
10658 if (!firstBranch) { 11779 if (!firstBranch) {
10659 temp.push_back(indent() + "else"s + nll(switchNode->lastBranch)); 11780 temp.push_back(indent() + "else"s + nl(switchNode->lastBranch));
10660 pushScope(); 11781 pushScope();
10661 } else { 11782 } else {
10662 addScope--; 11783 addScope--;
@@ -10666,20 +11787,20 @@ private:
10666 } 11787 }
10667 while (addScope > 0) { 11788 while (addScope > 0) {
10668 addScope--; 11789 addScope--;
10669 temp.push_back(indent() + "end"s + nlr(switchNode)); 11790 temp.push_back(indent() + "end"s + nl(switchNode));
10670 popScope(); 11791 popScope();
10671 } 11792 }
10672 temp.push_back(indent() + "end"s + nlr(switchNode)); 11793 temp.push_back(indent() + "end"s + nl(switchNode));
10673 if (usage == ExpUsage::Closure) { 11794 if (usage == ExpUsage::Closure) {
10674 popFunctionScope(); 11795 popFunctionScope();
10675 popScope(); 11796 popScope();
10676 *funcStart = anonFuncStart() + nll(switchNode); 11797 *funcStart = anonFuncStart() + nl(switchNode);
10677 temp.push_back(indent() + anonFuncEnd()); 11798 temp.push_back(indent() + anonFuncEnd());
10678 popAnonVarArg(); 11799 popAnonVarArg();
10679 } 11800 }
10680 if (extraScope) { 11801 if (extraScope) {
10681 popScope(); 11802 popScope();
10682 temp.push_back(indent() + "end"s + nlr(switchNode)); 11803 temp.push_back(indent() + "end"s + nl(switchNode));
10683 } 11804 }
10684 out.push_back(join(temp)); 11805 out.push_back(join(temp));
10685 } 11806 }
@@ -10698,7 +11819,7 @@ private:
10698 } 11819 }
10699 auto preDefine = toLocalDecl(defs); 11820 auto preDefine = toLocalDecl(defs);
10700 if (!preDefine.empty()) { 11821 if (!preDefine.empty()) {
10701 out.push_back(preDefine + nll(local)); 11822 out.push_back(preDefine + nl(local));
10702 } 11823 }
10703 } 11824 }
10704 } 11825 }
@@ -10727,8 +11848,8 @@ private:
10727 auto assignment = x->new_ptr<ExpListAssign_t>(); 11848 auto assignment = x->new_ptr<ExpListAssign_t>();
10728 assignment->expList.set(expList); 11849 assignment->expList.set(expList);
10729 auto assign = x->new_ptr<Assign_t>(); 11850 auto assign = x->new_ptr<Assign_t>();
10730 if (auto expListLow = values->valueList.as<ExpListLow_t>()) { 11851 if (auto expList = values->valueList.as<ExpList_t>()) {
10731 assign->values.dup(expListLow->exprs); 11852 assign->values.dup(expList->exprs);
10732 } else { 11853 } else {
10733 auto tableBlock = values->valueList.to<TableBlock_t>(); 11854 auto tableBlock = values->valueList.to<TableBlock_t>();
10734 assign->values.push_back(tableBlock); 11855 assign->values.push_back(tableBlock);
@@ -10736,7 +11857,7 @@ private:
10736 assignment->action.set(assign); 11857 assignment->action.set(assign);
10737 bool oneLined = transformAssignment(assignment, temp); 11858 bool oneLined = transformAssignment(assignment, temp);
10738 for (auto val : assign->values.objects()) { 11859 for (auto val : assign->values.objects()) {
10739 if (auto value = singleValueFrom(val)) { 11860 if (auto value = singleValueFrom(val, true)) {
10740 if (auto spValue = value->item.as<SimpleValue_t>()) { 11861 if (auto spValue = value->item.as<SimpleValue_t>()) {
10741 if (auto funLit = spValue->value.as<FunLit_t>()) { 11862 if (auto funLit = spValue->value.as<FunLit_t>()) {
10742 if (!funLit->noRecursion) { 11863 if (!funLit->noRecursion) {
@@ -10903,11 +12024,11 @@ private:
10903 } 12024 }
10904 str_list temp; 12025 str_list temp;
10905 if (localAttrib->forceLocal) { 12026 if (localAttrib->forceLocal) {
10906 temp.push_back(indent() + "local "s + join(vars, ", "sv) + nll(x)); 12027 temp.push_back(indent() + "local "s + join(vars, ", "sv) + nl(x));
10907 } 12028 }
10908 transformAssignment(assignment, temp); 12029 transformAssignment(assignment, temp);
10909 for (const auto& name : vars) { 12030 for (const auto& name : vars) {
10910 markVarConst(name); 12031 markVarLocalConst(name);
10911 } 12032 }
10912 if (localAttrib->attrib.is<CloseAttrib_t>()) { 12033 if (localAttrib->attrib.is<CloseAttrib_t>()) {
10913 str_list leftVars, rightVars; 12034 str_list leftVars, rightVars;
@@ -10949,13 +12070,13 @@ private:
10949 auto rit = items.begin(); 12070 auto rit = items.begin();
10950 str_list tmp; 12071 str_list tmp;
10951 while (lit != vars.end()) { 12072 while (lit != vars.end()) {
10952 tmp.push_back(indent() + "local "s + *lit + (target >= 504 ? " <close> = "s : " = "s) + *rit + nll(x)); 12073 tmp.push_back(indent() + "local "s + *lit + (target >= 504 ? " <close> = "s : " = "s) + *rit + nl(x));
10953 lit++; 12074 lit++;
10954 rit++; 12075 rit++;
10955 } 12076 }
10956 temp.push_back(join(tmp)); 12077 temp.push_back(join(tmp));
10957 } else { 12078 } else {
10958 temp.push_back(indent() + "local "s + join(vars, ", "sv) + " = "s + join(items, ", "sv) + nll(x)); 12079 temp.push_back(indent() + "local "s + join(vars, ", "sv) + " = "s + join(items, ", "sv) + nl(x));
10959 str_list leftVars; 12080 str_list leftVars;
10960 pushScope(); 12081 pushScope();
10961 for (size_t i = 0; i < vars.size(); i++) { 12082 for (size_t i = 0; i < vars.size(); i++) {
@@ -10976,10 +12097,10 @@ private:
10976 for (auto item : assignA->values.objects()) { 12097 for (auto item : assignA->values.objects()) {
10977 transformAssignItem(item, items); 12098 transformAssignItem(item, items);
10978 } 12099 }
10979 temp.push_back(indent() + "local "s + join(leftVars, ", "sv) + " = "s + join(items, ", "sv) + nll(x)); 12100 temp.push_back(indent() + "local "s + join(leftVars, ", "sv) + " = "s + join(items, ", "sv) + nl(x));
10980 } 12101 }
10981 for (const auto& var : vars) { 12102 for (const auto& var : vars) {
10982 markVarConst(var); 12103 markVarLocalConst(var);
10983 } 12104 }
10984 } 12105 }
10985 if (!listB->exprs.empty()) { 12106 if (!listB->exprs.empty()) {
@@ -11001,22 +12122,28 @@ private:
11001 vars.push_back(item.targetVar); 12122 vars.push_back(item.targetVar);
11002 } 12123 }
11003 } 12124 }
11004 temp.push_back(indent() + "local "s + join(vars, ", "sv) + nll(x)); 12125 temp.push_back(indent() + "local "s + join(vars, ", "sv) + nl(x));
11005 transformAssignment(assignment, temp); 12126 transformAssignment(assignment, temp);
11006 for (const auto& name : vars) { 12127 for (const auto& name : vars) {
11007 markVarConst(name); 12128 markVarLocalConst(name);
11008 } 12129 }
11009 } 12130 }
11010 out.push_back(join(temp)); 12131 out.push_back(join(temp));
11011 } 12132 }
11012 12133
11013 void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) { 12134 void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) {
11014 auto keyword = _parser.toString(breakLoop); 12135 auto isBreak = breakLoop->type.is<Break_t>();
12136 auto keyword = isBreak ? "break"s : "continue"s;
11015 if (_enableBreakLoop.empty() || !_enableBreakLoop.top()) { 12137 if (_enableBreakLoop.empty() || !_enableBreakLoop.top()) {
11016 throw CompileError(keyword + " is not inside a loop"s, breakLoop); 12138 throw CompileError(keyword + " is not inside a loop"s, breakLoop);
11017 } 12139 }
11018 if (keyword == "break"sv) { 12140 if (isBreak) {
11019 out.push_back(indent() + keyword + nll(breakLoop)); 12141 if (breakLoop->value) {
12142 auto exp = toAst<Exp_t>(breakLoop->varBWV, breakLoop->value);
12143 auto assignment = assignmentFrom(exp, breakLoop->value, breakLoop);
12144 transformAssignment(assignment, out);
12145 }
12146 out.push_back(indent() + keyword + nl(breakLoop));
11020 return; 12147 return;
11021 } 12148 }
11022 if (_continueVars.empty()) throw CompileError("continue is not inside a loop"sv, breakLoop); 12149 if (_continueVars.empty()) throw CompileError("continue is not inside a loop"sv, breakLoop);
@@ -11029,8 +12156,8 @@ private:
11029 if (!temp.empty()) { 12156 if (!temp.empty()) {
11030 _buf << temp.back(); 12157 _buf << temp.back();
11031 } 12158 }
11032 _buf << indent() << item.var << " = true"sv << nll(breakLoop); 12159 _buf << indent() << item.var << " = true"sv << nl(breakLoop);
11033 _buf << indent() << "break"sv << nll(breakLoop); 12160 _buf << indent() << "break"sv << nl(breakLoop);
11034 out.push_back(clearBuf()); 12161 out.push_back(clearBuf());
11035 } else { 12162 } else {
11036 transformGoto(toAst<Goto_t>("goto "s + item.var, breakLoop), temp); 12163 transformGoto(toAst<Goto_t>("goto "s + item.var, breakLoop), temp);
@@ -11042,7 +12169,7 @@ private:
11042 if (getLuaTarget(label) < 502) { 12169 if (getLuaTarget(label) < 502) {
11043 throw CompileError("label statement is not available when not targeting Lua version 5.2 or higher"sv, label); 12170 throw CompileError("label statement is not available when not targeting Lua version 5.2 or higher"sv, label);
11044 } 12171 }
11045 auto labelStr = unicodeVariableFrom(label->label->name); 12172 auto labelStr = unicodeVariableFrom(label->label);
11046 int currentScope = _gotoScopes.top(); 12173 int currentScope = _gotoScopes.top();
11047 if (static_cast<int>(_labels.size()) <= currentScope) { 12174 if (static_cast<int>(_labels.size()) <= currentScope) {
11048 _labels.resize(currentScope + 1, std::nullopt); 12175 _labels.resize(currentScope + 1, std::nullopt);
@@ -11056,16 +12183,16 @@ private:
11056 throw CompileError("label '"s + labelStr + "' already defined at line "s + std::to_string(it->second.line), label); 12183 throw CompileError("label '"s + labelStr + "' already defined at line "s + std::to_string(it->second.line), label);
11057 } 12184 }
11058 scope[labelStr] = {label->m_begin.m_line, static_cast<int>(_scopes.size())}; 12185 scope[labelStr] = {label->m_begin.m_line, static_cast<int>(_scopes.size())};
11059 out.push_back(indent() + "::"s + labelStr + "::"s + nll(label)); 12186 out.push_back(indent() + "::"s + labelStr + "::"s + nl(label));
11060 } 12187 }
11061 12188
11062 void transformGoto(Goto_t* gotoNode, str_list& out) { 12189 void transformGoto(Goto_t* gotoNode, str_list& out) {
11063 if (getLuaTarget(gotoNode) < 502) { 12190 if (getLuaTarget(gotoNode) < 502) {
11064 throw CompileError("goto statement is not available when not targeting Lua version 5.2 or higher"sv, gotoNode); 12191 throw CompileError("goto statement is not available when not targeting Lua version 5.2 or higher"sv, gotoNode);
11065 } 12192 }
11066 auto labelStr = unicodeVariableFrom(gotoNode->label->name); 12193 auto labelStr = unicodeVariableFrom(gotoNode->label);
11067 gotos.push_back({gotoNode, labelStr, _gotoScopes.top(), static_cast<int>(_scopes.size())}); 12194 gotos.push_back({gotoNode, labelStr, _gotoScopes.top(), static_cast<int>(_scopes.size())});
11068 out.push_back(indent() + "goto "s + labelStr + nll(gotoNode)); 12195 out.push_back(indent() + "goto "s + labelStr + nl(gotoNode));
11069 } 12196 }
11070 12197
11071 void transformShortTabAppending(ShortTabAppending_t* tab, str_list& out) { 12198 void transformShortTabAppending(ShortTabAppending_t* tab, str_list& out) {
@@ -11129,13 +12256,13 @@ private:
11129 temp.push_back(getPreDefineLine(assignment)); 12256 temp.push_back(getPreDefineLine(assignment));
11130 } 12257 }
11131 assignments.push_front(assignmentFrom(newValue, value, value)); 12258 assignments.push_front(assignmentFrom(newValue, value, value));
11132 temp.push_back(indent() + "do"s + nll(x)); 12259 temp.push_back(indent() + "do"s + nl(x));
11133 pushScope(); 12260 pushScope();
11134 for (auto item : assignments.objects()) { 12261 for (auto item : assignments.objects()) {
11135 transformAssignment(static_cast<ExpListAssign_t*>(item), temp); 12262 transformAssignment(static_cast<ExpListAssign_t*>(item), temp);
11136 } 12263 }
11137 popScope(); 12264 popScope();
11138 temp.push_back(indent() + "end"s + nll(x)); 12265 temp.push_back(indent() + "end"s + nl(x));
11139 out.push_back(join(temp)); 12266 out.push_back(join(temp));
11140 } 12267 }
11141}; 12268};
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 77c5901..f564f6a 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
106 invalid_interpolation_error = pl::user(true_(), [](const item_t& item) {
107 throw ParserError("invalid string interpolation"sv, item.begin);
108 return false;
109 });
110
111 confusing_unary_not_error = pl::user(true_(), [](const item_t& item) {
112 throw ParserError("deprecated use for unary operator 'not' to be here"sv, item.begin);
113 return false;
114 });
115
116 table_key_pair_error = pl::user(true_(), [](const item_t& item) {
117 throw ParserError("can not put hash pair in a list"sv, item.begin);
118 return false;
119 });
120 123
121 if_assignment_syntax_error = pl::user(true_(), [](const item_t& item) { 124 empty_block_error = expect_error(
122 throw ParserError("use := for if-assignment expression"sv, item.begin); 125 "expected a valid statement or indented block"sv
123 return false; 126 );
124 }); 127 export_expression_error = expect_error(
128 "invalid export expression"sv
129 );
130 invalid_interpolation_error = expect_error(
131 "invalid string interpolation"sv
132 );
133 confusing_unary_not_error = expect_error(
134 "deprecated use for unary operator 'not' to be here"sv
135 );
136 table_key_pair_error = expect_error(
137 "can not put hash pair in a list"sv
138 );
139 assignment_expression_syntax_error = expect_error(
140 "use := for assignment expression"sv
141 );
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 | ExpList | 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,28 +453,41 @@ 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);
466
467 ImportAllGlobal = key("global");
344 468
345 Import = key("import") >> space >> (ImportAs | ImportFrom) | FromImport; 469 Import = key("import") >> space >> (ImportAllGlobal | ImportGlobal | ImportAs | ImportFrom | invalid_import_syntax_error) | FromImport;
346 470
347 Label = "::" >> LabelName >> "::"; 471 Label = "::" >> (and_(LuaKeyword >> "::") >> keyword_as_label_error | UnicodeName >> "::");
348 472
349 Goto = key("goto") >> space >> LabelName; 473 Goto = key("goto") >> space >> (and_(LuaKeyword >> not_alpha_num) >> keyword_as_label_error | UnicodeName);
350 474
351 ShortTabAppending = "[]" >> space >> Assign; 475 ShortTabAppending = "[]" >> space >> Assign;
352 476
353 BreakLoop = (expr("break") | "continue") >> not_alpha_num; 477 Break = key("break");
478 Continue = key("continue");
479 BreakLoop = (Break >> -(space >> Exp) | Continue) >> not_alpha_num;
354 480
355 Return = key("return") >> -(space >> (TableBlock | ExpListLow)); 481 Return = key("return") >> -(space >> (TableBlock | ExpList));
356 482
357 with_exp = ExpList >> -(space >> Assign); 483 must_exp = Exp | expected_expression_error;
358 484
359 With = key("with") >> -ExistentialOp >> space >> disable_do_chain_arg_table_block_rule(with_exp) >> space >> body_with("do"); 485 with_exp = ExpList >> -(space >> (':' >> Assign | and_('=') >> assignment_expression_syntax_error)) | expected_expression_error;
486
487 With = key("with") >> -ExistentialOp >> space >> (
488 disable_do_chain_arg_table_block_rule(with_exp) >> space >> body_with("do") |
489 invalid_with_syntax_error
490 );
360 SwitchCase = key("when") >> space >> disable_chain_rule(disable_arg_table_block_rule(SwitchList)) >> space >> body_with("then"); 491 SwitchCase = key("when") >> space >> disable_chain_rule(disable_arg_table_block_rule(SwitchList)) >> space >> body_with("then");
361 switch_else = key("else") >> space >> body; 492 switch_else = key("else") >> space >> body;
362 493
@@ -368,9 +499,11 @@ YueParser::YueParser() {
368 499
369 SwitchList = Seperator >> ( 500 SwitchList = Seperator >> (
370 and_(SimpleTable | TableLit) >> Exp | 501 and_(SimpleTable | TableLit) >> Exp |
371 exp_not_tab >> *(space >> ',' >> space >> exp_not_tab) 502 exp_not_tab >> *(space >> ',' >> space >> exp_not_tab) |
503 expected_expression_error
372 ); 504 );
373 Switch = key("switch") >> space >> Exp >> 505 Switch = key("switch") >> space >>
506 must_exp >> -(space >> Assignment) >>
374 space >> Seperator >> ( 507 space >> Seperator >> (
375 SwitchCase >> space >> ( 508 SwitchCase >> space >> (
376 switch_block | 509 switch_block |
@@ -379,45 +512,53 @@ YueParser::YueParser() {
379 +space_break >> advance_match >> space >> SwitchCase >> switch_block >> pop_indent 512 +space_break >> advance_match >> space >> SwitchCase >> switch_block >> pop_indent
380 ); 513 );
381 514
382 Assignment = -(',' >> space >> ExpList >> space) >> (':' >> Assign | and_('=') >> if_assignment_syntax_error); 515 Assignment = -(',' >> space >> ExpList >> space) >> (':' >> Assign | and_('=') >> assignment_expression_syntax_error);
383 IfCond = disable_chain_rule(disable_arg_table_block_rule(Exp >> -(space >> Assignment))); 516 IfCond = disable_chain_rule(disable_arg_table_block_rule(Exp >> -(space >> Assignment))) | expected_expression_error;
384 if_else_if = -(line_break >> *space_break >> check_indent_match) >> space >> key("elseif") >> space >> IfCond >> space >> body_with("then"); 517 if_else_if = -(line_break >> *space_break >> check_indent_match) >> space >> key("elseif") >> space >> IfCond >> space >> body_with("then");
385 if_else = -(line_break >> *space_break >> check_indent_match) >> space >> key("else") >> space >> body; 518 if_else = -(line_break >> *space_break >> check_indent_match) >> space >> key("else") >> space >> body;
386 IfType = (expr("if") | "unless") >> not_alpha_num; 519 IfType = (expr("if") | "unless") >> not_alpha_num;
387 If = IfType >> space >> IfCond >> space >> opt_body_with("then") >> *if_else_if >> -if_else; 520 If = IfType >> space >> IfCond >> space >> opt_body_with("then") >> *if_else_if >> -if_else;
388 521
389 WhileType = (expr("while") | "until") >> not_alpha_num; 522 WhileType = (expr("while") | pl::user("until", [](const item_t& item) {
390 While = WhileType >> space >> disable_do_chain_arg_table_block_rule(Exp >> -(space >> Assignment)) >> space >> opt_body_with("do"); 523 State* st = reinterpret_cast<State*>(item.user_data);
391 Repeat = key("repeat") >> space >> Body >> line_break >> *space_break >> check_indent_match >> space >> key("until") >> space >> Exp; 524 return st->noUntilStack.empty() || !st->noUntilStack.back();
525 })) >> not_alpha_num;
526 While = key(WhileType) >> space >> (disable_do_chain_arg_table_block_rule(Exp >> -(space >> Assignment)) | expected_expression_error) >> space >> opt_body_with("do");
527 Repeat = key("repeat") >> space >> (
528 in_block >> line_break >> *space_break >> check_indent_match |
529 disable_until_rule(Statement)
530 ) >> space >> key("until") >> space >> must_exp;
392 531
393 for_key = pl::user(key("for"), [](const item_t& item) { 532 for_key = pl::user(key("for"), [](const item_t& item) {
394 State* st = reinterpret_cast<State*>(item.user_data); 533 State* st = reinterpret_cast<State*>(item.user_data);
395 return st->noForStack.empty() || !st->noForStack.top(); 534 return st->noForStack.empty() || !st->noForStack.back();
396 }); 535 });
397 ForStepValue = ',' >> space >> Exp; 536 ForStepValue = ',' >> space >> must_exp;
398 for_args = Variable >> space >> '=' >> space >> Exp >> space >> ',' >> space >> Exp >> space >> -ForStepValue; 537 for_args = Variable >> space >> '=' >> space >> must_exp >> space >> ',' >> space >> must_exp >> space >> -ForStepValue;
399 538
400 For = for_key >> space >> disable_do_chain_arg_table_block_rule(for_args) >> space >> opt_body_with("do"); 539 ForNum = disable_do_chain_arg_table_block_rule(for_args) >> space >> opt_body_with("do");
401 540
402 for_in = StarExp | ExpList; 541 for_in = StarExp | ExpList | expected_expression_error;
403 542
404 ForEach = for_key >> space >> AssignableNameList >> space >> key("in") >> space >> 543 ForEach = AssignableNameList >> space >> key("in") >> space >>
405 disable_do_chain_arg_table_block_rule(for_in) >> space >> opt_body_with("do"); 544 disable_do_chain_arg_table_block_rule(for_in) >> space >> opt_body_with("do");
406 545
546 For = for_key >> space >> (ForNum | ForEach);
547
407 Do = pl::user(key("do"), [](const item_t& item) { 548 Do = pl::user(key("do"), [](const item_t& item) {
408 State* st = reinterpret_cast<State*>(item.user_data); 549 State* st = reinterpret_cast<State*>(item.user_data);
409 return st->noDoStack.empty() || !st->noDoStack.top(); 550 return st->noDoStack.empty() || !st->noDoStack.back();
410 }) >> space >> Body; 551 }) >> space >> Body;
411 552
412 disable_do = pl::user(true_(), [](const item_t& item) { 553 disable_do = pl::user(true_(), [](const item_t& item) {
413 State* st = reinterpret_cast<State*>(item.user_data); 554 State* st = reinterpret_cast<State*>(item.user_data);
414 st->noDoStack.push(true); 555 st->noDoStack.push_back(true);
415 return true; 556 return true;
416 }); 557 });
417 558
418 enable_do = pl::user(true_(), [](const item_t& item) { 559 enable_do = pl::user(true_(), [](const item_t& item) {
419 State* st = reinterpret_cast<State*>(item.user_data); 560 State* st = reinterpret_cast<State*>(item.user_data);
420 st->noDoStack.pop(); 561 st->noDoStack.pop_back();
421 return true; 562 return true;
422 }); 563 });
423 564
@@ -435,46 +576,58 @@ YueParser::YueParser() {
435 576
436 disable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) { 577 disable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) {
437 State* st = reinterpret_cast<State*>(item.user_data); 578 State* st = reinterpret_cast<State*>(item.user_data);
438 st->noDoStack.push(true); 579 st->noDoStack.push_back(true);
439 st->noChainBlockStack.push(true); 580 st->noChainBlockStack.push_back(true);
440 st->noTableBlockStack.push(true); 581 st->noTableBlockStack.push_back(true);
441 return true; 582 return true;
442 }); 583 });
443 584
444 enable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) { 585 enable_do_chain_arg_table_block = pl::user(true_(), [](const item_t& item) {
445 State* st = reinterpret_cast<State*>(item.user_data); 586 State* st = reinterpret_cast<State*>(item.user_data);
446 st->noDoStack.pop(); 587 st->noDoStack.pop_back();
447 st->noChainBlockStack.pop(); 588 st->noChainBlockStack.pop_back();
448 st->noTableBlockStack.pop(); 589 st->noTableBlockStack.pop_back();
449 return true; 590 return true;
450 }); 591 });
451 592
452 disable_arg_table_block = pl::user(true_(), [](const item_t& item) { 593 disable_arg_table_block = pl::user(true_(), [](const item_t& item) {
453 State* st = reinterpret_cast<State*>(item.user_data); 594 State* st = reinterpret_cast<State*>(item.user_data);
454 st->noTableBlockStack.push(true); 595 st->noTableBlockStack.push_back(true);
455 return true; 596 return true;
456 }); 597 });
457 598
458 enable_arg_table_block = pl::user(true_(), [](const item_t& item) { 599 enable_arg_table_block = pl::user(true_(), [](const item_t& item) {
459 State* st = reinterpret_cast<State*>(item.user_data); 600 State* st = reinterpret_cast<State*>(item.user_data);
460 st->noTableBlockStack.pop(); 601 st->noTableBlockStack.pop_back();
461 return true; 602 return true;
462 }); 603 });
463 604
464 disable_for = pl::user(true_(), [](const item_t& item) { 605 disable_for = pl::user(true_(), [](const item_t& item) {
465 State* st = reinterpret_cast<State*>(item.user_data); 606 State* st = reinterpret_cast<State*>(item.user_data);
466 st->noForStack.push(true); 607 st->noForStack.push_back(true);
467 return true; 608 return true;
468 }); 609 });
469 610
470 enable_for = pl::user(true_(), [](const item_t& item) { 611 enable_for = pl::user(true_(), [](const item_t& item) {
471 State* st = reinterpret_cast<State*>(item.user_data); 612 State* st = reinterpret_cast<State*>(item.user_data);
472 st->noForStack.pop(); 613 st->noForStack.pop_back();
614 return true;
615 });
616
617 disable_until = pl::user(true_(), [](const item_t& item) {
618 State* st = reinterpret_cast<State*>(item.user_data);
619 st->noUntilStack.push_back(true);
620 return true;
621 });
622
623 enable_until = pl::user(true_(), [](const item_t& item) {
624 State* st = reinterpret_cast<State*>(item.user_data);
625 st->noUntilStack.pop_back();
473 return true; 626 return true;
474 }); 627 });
475 628
476 CatchBlock = line_break >> *space_break >> check_indent_match >> space >> key("catch") >> space >> Variable >> space >> in_block; 629 CatchBlock = line_break >> *space_break >> check_indent_match >> space >> key("catch") >> space >> must_variable >> space >> (in_block | invalid_try_syntax_error);
477 Try = key("try") >> space >> (in_block | Exp) >> -CatchBlock; 630 Try = key("try") >> -ExistentialOp >> space >> (in_block | Exp | invalid_try_syntax_error) >> -CatchBlock;
478 631
479 list_value = 632 list_value =
480 and_( 633 and_(
@@ -496,28 +649,33 @@ YueParser::YueParser() {
496 649
497 list_lit_lines = +space_break >> list_lit_line >> *(-(space >> ',') >> space_break >> list_lit_line) >> -(space >> ','); 650 list_lit_lines = +space_break >> list_lit_line >> *(-(space >> ',') >> space_break >> list_lit_line) >> -(space >> ',');
498 651
652 end_brackets_expression = ']' | brackets_expression_error;
653
499 Comprehension = '[' >> not_('[') >> 654 Comprehension = '[' >> not_('[') >>
500 Seperator >> space >> ( 655 Seperator >> space >> (
501 disable_for_rule(list_value) >> space >> ( 656 disable_for_rule(list_value) >> space >> (
502 CompInner >> space >> ']' | 657 CompFor >> space >> end_brackets_expression |
503 (list_value_list >> -(space >> ',') | space >> ',') >> -list_lit_lines >> white >> ']' 658 (list_value_list >> -(space >> ',') | space >> ',') >> -list_lit_lines >> white >> end_brackets_expression
504 ) | 659 ) |
505 list_lit_lines >> white >> ']' | 660 list_lit_lines >> white >> end_brackets_expression |
506 white >> ']' >> not_(space >> '=') 661 white >> ']' >> not_(space >> '=')
507 ); 662 );
508 663
509 CompValue = ',' >> space >> Exp; 664 end_braces_expression = '}' | braces_expression_error;
510 TblComprehension = and_('{') >> ('{' >> space >> disable_for_rule(Exp >> space >> -(CompValue >> space)) >> CompInner >> space >> '}' | braces_expression_error); 665
666 CompValue = ',' >> space >> must_exp;
667 TblComprehension = '{' >> space >> disable_for_rule(Exp >> space >> -(CompValue >> space)) >> (CompFor | braces_expression_error) >> space >> end_braces_expression;
511 668
512 CompInner = Seperator >> (CompForEach | CompFor) >> *(space >> comp_clause); 669 CompFor = key("for") >> space >> Seperator >> (CompForNum | CompForEach) >> *(space >> comp_clause);
513 StarExp = '*' >> space >> Exp; 670 StarExp = '*' >> space >> must_exp;
514 CompForEach = key("for") >> space >> AssignableNameList >> space >> key("in") >> space >> (StarExp | Exp); 671 CompForEach = AssignableNameList >> space >> key("in") >> space >> (StarExp | must_exp);
515 CompFor = key("for") >> space >> Variable >> space >> '=' >> space >> Exp >> space >> ',' >> space >> Exp >> -ForStepValue; 672 CompForNum = Variable >> space >> '=' >> space >> must_exp >> space >> ',' >> space >> must_exp >> -ForStepValue;
516 comp_clause = CompFor | CompForEach | key("when") >> space >> Exp; 673 comp_clause = key("when") >> space >> must_exp | key("for") >> space >> (CompForNum | CompForEach);
517 674
518 Assign = '=' >> space >> Seperator >> ( 675 Assign = '=' >> space >> Seperator >> (
519 With | If | Switch | TableBlock | 676 With | If | Switch | TableBlock |
520 Exp >> *(space >> set(",;") >> space >> Exp) 677 (SpreadListExp | Exp) >> *(space >> set(",") >> space >> (SpreadListExp | Exp)) |
678 expected_expression_error
521 ); 679 );
522 680
523 UpdateOp = 681 UpdateOp =
@@ -525,7 +683,7 @@ YueParser::YueParser() {
525 ">>" | "<<" | "??" | 683 ">>" | "<<" | "??" |
526 set("+-*/%&|^"); 684 set("+-*/%&|^");
527 685
528 Update = UpdateOp >> '=' >> space >> Exp; 686 Update = UpdateOp >> '=' >> space >> must_exp;
529 687
530 Assignable = AssignableChain | Variable | SelfItem; 688 Assignable = AssignableChain | Variable | SelfItem;
531 689
@@ -546,35 +704,38 @@ YueParser::YueParser() {
546 UnaryExp = *(UnaryOperator >> space) >> expo_exp >> -(space >> In); 704 UnaryExp = *(UnaryOperator >> space) >> expo_exp >> -(space >> In);
547 705
548 pipe_operator = "|>"; 706 pipe_operator = "|>";
549 pipe_value = pipe_operator >> *space_break >> space >> UnaryExp; 707 pipe_value = pipe_operator >> *space_break >> space >> must_unary_exp;
550 pipe_exp = UnaryExp >> *(space >> pipe_value); 708 pipe_exp = UnaryExp >> *(space >> pipe_value);
551 709
552 BinaryOperator = 710 BinaryOperator = (
553 key("or") | 711 key("or") |
554 key("and") | 712 key("and") |
555 "<=" | ">=" | "~=" | "!=" | "==" | 713 "<=" | ">=" | "~=" | "!=" | "==" |
556 ".." | "<<" | ">>" | "//" | 714 ".." | "<<" | ">>" | "//" |
557 set("+-*/%><|&~"); 715 set("+*/%>|&~") |
716 '-' >> not_('>') |
717 '<' >> not_('-')
718 ) >> not_('=');
558 719
559 ExpOpValue = BinaryOperator >> *space_break >> space >> pipe_exp; 720 ExpOpValue = BinaryOperator >> *space_break >> space >> (pipe_exp | expected_expression_error);
560 Exp = Seperator >> pipe_exp >> *(space >> ExpOpValue) >> -(space >> "??" >> space >> Exp); 721 Exp = Seperator >> pipe_exp >> *(space >> ExpOpValue) >> -(space >> "??" >> not_('=') >> *space_break >> space >> must_exp);
561 722
562 disable_chain = pl::user(true_(), [](const item_t& item) { 723 disable_chain = pl::user(true_(), [](const item_t& item) {
563 State* st = reinterpret_cast<State*>(item.user_data); 724 State* st = reinterpret_cast<State*>(item.user_data);
564 st->noChainBlockStack.push(true); 725 st->noChainBlockStack.push_back(true);
565 return true; 726 return true;
566 }); 727 });
567 728
568 enable_chain = pl::user(true_(), [](const item_t& item) { 729 enable_chain = pl::user(true_(), [](const item_t& item) {
569 State* st = reinterpret_cast<State*>(item.user_data); 730 State* st = reinterpret_cast<State*>(item.user_data);
570 st->noChainBlockStack.pop(); 731 st->noChainBlockStack.pop_back();
571 return true; 732 return true;
572 }); 733 });
573 734
574 chain_line = check_indent_match >> space >> (chain_dot_chain | colon_chain) >> -InvokeArgs; 735 chain_line = check_indent_match >> space >> (chain_dot_chain | colon_chain) >> -InvokeArgs;
575 chain_block = pl::user(true_(), [](const item_t& item) { 736 chain_block = pl::user(true_(), [](const item_t& item) {
576 State* st = reinterpret_cast<State*>(item.user_data); 737 State* st = reinterpret_cast<State*>(item.user_data);
577 return st->noChainBlockStack.empty() || !st->noChainBlockStack.top(); 738 return st->noChainBlockStack.empty() || !st->noChainBlockStack.back();
578 }) >> +space_break >> advance_match >> ensure( 739 }) >> +space_break >> advance_match >> ensure(
579 chain_line >> *(+space_break >> chain_line), pop_indent); 740 chain_line >> *(+space_break >> chain_line), pop_indent);
580 ChainValue = 741 ChainValue =
@@ -589,7 +750,7 @@ YueParser::YueParser() {
589 st->expLevel++; 750 st->expLevel++;
590 const int max_exp_level = 100; 751 const int max_exp_level = 100;
591 if (st->expLevel > max_exp_level) { 752 if (st->expLevel > max_exp_level) {
592 throw ParserError("nesting expressions exceeds 100 levels"sv, item.begin); 753 RaiseError("nesting expressions exceeds 100 levels"sv, item);
593 } 754 }
594 return true; 755 return true;
595 }); 756 });
@@ -604,14 +765,22 @@ YueParser::YueParser() {
604 Value = inc_exp_level >> ensure(SimpleValue | SimpleTable | ChainValue | String, dec_exp_level); 765 Value = inc_exp_level >> ensure(SimpleValue | SimpleTable | ChainValue | String, dec_exp_level);
605 766
606 single_string_inner = '\\' >> set("'\\") | not_('\'') >> any_char; 767 single_string_inner = '\\' >> set("'\\") | not_('\'') >> any_char;
607 SingleString = '\'' >> *single_string_inner >> '\''; 768 SingleString = '\'' >> *single_string_inner >> ('\'' | unclosed_single_string_error);
608 769
609 interp = "#{" >> space >> (Exp >> space >> '}' | invalid_interpolation_error); 770 interp = "#{" >> space >> (Exp >> space >> '}' | invalid_interpolation_error);
610 double_string_plain = '\\' >> set("\"\\#") | not_('"') >> any_char; 771 double_string_plain = '\\' >> set("\"\\#") | not_('"') >> any_char;
611 DoubleStringInner = +(not_("#{") >> double_string_plain); 772 DoubleStringInner = +(not_("#{") >> double_string_plain);
612 DoubleStringContent = DoubleStringInner | interp; 773 DoubleStringContent = DoubleStringInner | interp;
613 DoubleString = '"' >> Seperator >> *DoubleStringContent >> '"'; 774 DoubleString = '"' >> Seperator >> *DoubleStringContent >> ('"' | unclosed_double_string_error);
614 String = DoubleString | SingleString | LuaString; 775
776 YAMLIndent = +set(" \t");
777 YAMLLineInner = +('\\' >> set("\"\\#") | not_("#{" | stop) >> any_char);
778 YAMLLineContent = YAMLLineInner | interp;
779 YAMLLine = check_indent_match >> YAMLIndent >> +(YAMLLineContent) |
780 advance_match >> YAMLIndent >> ensure(+YAMLLineContent, pop_indent);
781 YAMLMultiline = '|' >> space >> Seperator >> +(*set(" \t") >> line_break) >> advance_match >> ensure(YAMLLine >> *(+(*set(" \t") >> line_break) >> YAMLLine), pop_indent);
782
783 String = DoubleString | SingleString | LuaString | YAMLMultiline;
615 784
616 lua_string_open = '[' >> *expr('=') >> '['; 785 lua_string_open = '[' >> *expr('=') >> '[';
617 lua_string_close = ']' >> *expr('=') >> ']'; 786 lua_string_close = ']' >> *expr('=') >> ']';
@@ -631,15 +800,15 @@ YueParser::YueParser() {
631 800
632 LuaStringContent = *(not_(LuaStringClose) >> any_char); 801 LuaStringContent = *(not_(LuaStringClose) >> any_char);
633 802
634 LuaString = LuaStringOpen >> -line_break >> LuaStringContent >> LuaStringClose; 803 LuaString = LuaStringOpen >> -line_break >> LuaStringContent >> (LuaStringClose | unclosed_lua_string_error);
635 804
636 Parens = '(' >> *space_break >> space >> Exp >> *space_break >> space >> ')'; 805 Parens = '(' >> (*space_break >> space >> Exp >> *space_break >> space >> ')' | parenthesis_error);
637 Callable = Variable | SelfItem | MacroName | Parens; 806 Callable = Variable | SelfItem | MacroName | Parens;
638 807
639 fn_args_value_list = Exp >> *(space >> ',' >> space >> Exp); 808 fn_args_value_list = Exp >> *(space >> ',' >> space >> Exp);
640 809
641 fn_args_lit_line = ( 810 fn_args_lit_line = (
642 push_indent_match >> (space >> fn_args_value_list >> pop_indent | pop_indent) 811 push_indent_match >> ensure(space >> fn_args_value_list, pop_indent)
643 ) | ( 812 ) | (
644 space 813 space
645 ); 814 );
@@ -649,14 +818,14 @@ YueParser::YueParser() {
649 fn_args = 818 fn_args =
650 '(' >> -(space >> fn_args_value_list >> -(space >> ',')) >> 819 '(' >> -(space >> fn_args_value_list >> -(space >> ',')) >>
651 -fn_args_lit_lines >> 820 -fn_args_lit_lines >>
652 white >> ')' | space >> '!' >> not_('='); 821 white >> -(and_(',') >> unexpected_comma_error) >>')' | space >> '!' >> not_('=');
653 822
654 meta_index = Name | index | String; 823 meta_index = Name | index | String;
655 Metatable = '<' >> space >> '>'; 824 Metatable = '<' >> space >> '>';
656 Metamethod = '<' >> space >> meta_index >> space >> '>'; 825 Metamethod = '<' >> space >> meta_index >> space >> '>';
657 826
658 ExistentialOp = '?' >> not_('?'); 827 ExistentialOp = '?' >> not_('?');
659 TableAppendingOp = and_('[') >> ("[]" | brackets_expression_error); 828 TableAppendingOp = and_('[') >> "[]";
660 PlainItem = +any_char; 829 PlainItem = +any_char;
661 830
662 chain_call = ( 831 chain_call = (
@@ -681,7 +850,8 @@ YueParser::YueParser() {
681 chain_with_colon = +chain_item >> -colon_chain; 850 chain_with_colon = +chain_item >> -colon_chain;
682 chain_items = chain_with_colon | colon_chain; 851 chain_items = chain_with_colon | colon_chain;
683 852
684 index = '[' >> not_('[') >> space >> Exp >> space >> ']'; 853 index = '[' >> not_('[') >> space >> (ReversedIndex >> and_(space >> ']') | Exp) >> space >> ']';
854 ReversedIndex = '#' >> space >> -('-' >> space >> Exp);
685 chain_item = 855 chain_item =
686 Invoke >> -ExistentialOp | 856 Invoke >> -ExistentialOp |
687 DotChainItem >> -ExistentialOp | 857 DotChainItem >> -ExistentialOp |
@@ -720,10 +890,8 @@ YueParser::YueParser() {
720 SpreadExp | 890 SpreadExp |
721 NormalDef; 891 NormalDef;
722 892
723 table_value_list = table_value >> *(space >> ',' >> space >> table_value);
724
725 table_lit_line = ( 893 table_lit_line = (
726 push_indent_match >> (space >> table_value_list >> pop_indent | pop_indent) 894 push_indent_match >> (space >> not_(line_break | '}') >> (table_value | expected_expression_error) >> *(space >> ',' >> space >> table_value) >> pop_indent | pop_indent)
727 ) | ( 895 ) | (
728 space 896 space
729 ); 897 );
@@ -732,13 +900,15 @@ YueParser::YueParser() {
732 900
733 TableLit = 901 TableLit =
734 '{' >> Seperator >> 902 '{' >> Seperator >>
735 -(space >> table_value_list >> -(space >> ',')) >> 903 -(space >> table_value >> *(space >> ',' >> space >> table_value) >> -(space >> ',')) >>
736 -table_lit_lines >> 904 (
737 white >> '}'; 905 table_lit_lines >> white >> end_braces_expression |
906 white >> '}'
907 );
738 908
739 table_block_inner = Seperator >> key_value_line >> *(+space_break >> key_value_line); 909 table_block_inner = Seperator >> key_value_line >> *(+space_break >> key_value_line);
740 TableBlock = +space_break >> advance_match >> ensure(table_block_inner, pop_indent); 910 TableBlock = +space_break >> advance_match >> ensure(table_block_inner, pop_indent);
741 TableBlockIndent = '*' >> Seperator >> disable_arg_table_block_rule( 911 TableBlockIndent = ('*' | '-' >> space_one) >> Seperator >> disable_arg_table_block_rule(
742 space >> key_value_list >> -(space >> ',') >> 912 space >> key_value_list >> -(space >> ',') >>
743 -(+space_break >> advance_match >> space >> ensure(key_value_list >> -(space >> ',') >> *(+space_break >> key_value_line), pop_indent))); 913 -(+space_break >> advance_match >> space >> ensure(key_value_list >> -(space >> ',') >> *(+space_break >> key_value_line), pop_indent)));
744 914
@@ -753,13 +923,18 @@ YueParser::YueParser() {
753 ClassDecl = 923 ClassDecl =
754 key("class") >> not_(':') >> disable_arg_table_block_rule( 924 key("class") >> not_(':') >> disable_arg_table_block_rule(
755 -(space >> Assignable) >> 925 -(space >> Assignable) >>
756 -(space >> key("extends") >> prevent_indent >> space >> ensure(Exp, pop_indent)) >> 926 -(space >> key("extends") >> prevent_indent >> space >> ensure(must_exp, pop_indent)) >>
757 -(space >> key("using") >> prevent_indent >> space >> ensure(ExpList, pop_indent)) 927 -(space >> key("using") >> prevent_indent >> space >> ensure(ExpList | expected_expression_error, pop_indent))
758 ) >> -ClassBlock; 928 ) >> -ClassBlock;
759 929
760 GlobalValues = NameList >> -(space >> '=' >> space >> (TableBlock | ExpListLow)); 930 GlobalValues = NameList >> -(space >> '=' >> space >> (TableBlock | ExpList | expected_expression_error));
761 GlobalOp = expr('*') | '^'; 931 GlobalOp = expr('*') | '^';
762 Global = key("global") >> space >> (ClassDecl | GlobalOp | GlobalValues); 932 Global = key("global") >> space >> (
933 -(ConstAttrib >> space) >> ClassDecl |
934 GlobalOp |
935 -(ConstAttrib >> space) >> GlobalValues |
936 invalid_global_declaration_error
937 );
763 938
764 ExportDefault = key("default"); 939 ExportDefault = key("default");
765 940
@@ -771,10 +946,10 @@ YueParser::YueParser() {
771 pl::user(space >> ExportDefault >> space >> Exp, [](const item_t& item) { 946 pl::user(space >> ExportDefault >> space >> Exp, [](const item_t& item) {
772 State* st = reinterpret_cast<State*>(item.user_data); 947 State* st = reinterpret_cast<State*>(item.user_data);
773 if (st->exportDefault) { 948 if (st->exportDefault) {
774 throw ParserError("export default has already been declared"sv, item.begin); 949 RaiseError("export default has already been declared"sv, item);
775 } 950 }
776 if (st->exportCount > 1) { 951 if (st->exportCount > 1) {
777 throw ParserError("there are items already being exported"sv, item.begin); 952 RaiseError("there are items already being exported"sv, item);
778 } 953 }
779 st->exportDefault = true; 954 st->exportDefault = true;
780 return true; 955 return true;
@@ -782,17 +957,17 @@ YueParser::YueParser() {
782 not_(space >> ExportDefault) >> pl::user(true_(), [](const item_t& item) { 957 not_(space >> ExportDefault) >> pl::user(true_(), [](const item_t& item) {
783 State* st = reinterpret_cast<State*>(item.user_data); 958 State* st = reinterpret_cast<State*>(item.user_data);
784 if (st->exportDefault && st->exportCount > 1) { 959 if (st->exportDefault && st->exportCount > 1) {
785 throw ParserError("can not export any more items when 'export default' is declared"sv, item.begin); 960 RaiseError("can not export any more items when 'export default' is declared"sv, item);
786 } 961 }
787 return true; 962 return true;
788 }) >> ( 963 }) >> (
789 and_(set(".[")) >> ((pl::user(and_('.' >> Metatable), [](const item_t& item) { 964 and_(set(".[")) >> ((pl::user(and_('.' >> Metatable), [](const item_t& item) {
790 State* st = reinterpret_cast<State*>(item.user_data); 965 State* st = reinterpret_cast<State*>(item.user_data);
791 if (st->exportMetatable) { 966 if (st->exportMetatable) {
792 throw ParserError("module metatable duplicated"sv, item.begin); 967 RaiseError("module metatable duplicated"sv, item);
793 } 968 }
794 if (st->exportMetamethod) { 969 if (st->exportMetamethod) {
795 throw ParserError("metatable should be exported before metamethod"sv, item.begin); 970 RaiseError("metatable should be exported before metamethod"sv, item);
796 } 971 }
797 st->exportMetatable = true; 972 st->exportMetatable = true;
798 return true; 973 return true;
@@ -807,8 +982,9 @@ YueParser::YueParser() {
807 State* st = reinterpret_cast<State*>(item.user_data); 982 State* st = reinterpret_cast<State*>(item.user_data);
808 st->exportMacro = true; 983 st->exportMacro = true;
809 return true; 984 return true;
810 }) 985 }) |
811 ) >> not_(space >> StatementAppendix); 986 invalid_export_syntax_error
987 );
812 988
813 VariablePair = ':' >> Variable; 989 VariablePair = ':' >> Variable;
814 990
@@ -817,13 +993,13 @@ YueParser::YueParser() {
817 KeyName | 993 KeyName |
818 '[' >> not_('[') >> space >> Exp >> space >> ']' | 994 '[' >> not_('[') >> space >> Exp >> space >> ']' |
819 String 995 String
820 ) >> ':' >> not_(':') >> space >> 996 ) >> ':' >> not_(':' | '=' >> not_('>')) >> space >>
821 (Exp | TableBlock | +space_break >> space >> Exp); 997 (Exp | TableBlock | +space_break >> space >> Exp | expected_expression_error);
822 998
823 MetaVariablePair = ":<" >> space >> Variable >> space >> '>'; 999 MetaVariablePair = ":<" >> space >> must_variable >> space >> '>';
824 1000
825 MetaNormalPair = '<' >> space >> -meta_index >> space >> ">:" >> space >> 1001 MetaNormalPair = '<' >> space >> -meta_index >> space >> ">:" >> space >>
826 (Exp | TableBlock | +space_break >> space >> Exp); 1002 (Exp | TableBlock | +space_break >> space >> Exp | expected_expression_error);
827 1003
828 destruct_def = -(space >> '=' >> space >> Exp); 1004 destruct_def = -(space >> '=' >> space >> Exp);
829 VariablePairDef = VariablePair >> destruct_def; 1005 VariablePairDef = VariablePair >> destruct_def;
@@ -841,66 +1017,83 @@ YueParser::YueParser() {
841 key_value_line = check_indent_match >> space >> ( 1017 key_value_line = check_indent_match >> space >> (
842 key_value_list >> -(space >> ',') | 1018 key_value_list >> -(space >> ',') |
843 TableBlockIndent | 1019 TableBlockIndent |
844 '*' >> space >> (SpreadExp | Exp | TableBlock) 1020 ('*' | '-' >> space_one) >> space >> (SpreadExp | Exp | TableBlock)
845 ); 1021 );
846 1022
847 fn_arg_def_list = FnArgDef >> *(space >> ',' >> space >> FnArgDef); 1023 fn_arg_def_list = FnArgDef >> *(space >> ',' >> space >> FnArgDef);
848 1024
849 fn_arg_def_lit_line = ( 1025 fn_arg_def_lit_line = (
850 push_indent_match >> (space >> fn_arg_def_list >> pop_indent | pop_indent) 1026 push_indent_match >> ensure(space >> fn_arg_def_list, pop_indent)
851 ) | ( 1027 ) | (
852 space 1028 space
853 ); 1029 );
854 1030
855 fn_arg_def_lit_lines = fn_arg_def_lit_line >> *(-(space >> ',') >> space_break >> fn_arg_def_lit_line); 1031 fn_arg_def_lit_lines = fn_arg_def_lit_line >> *(-(space >> ',') >> space_break >> fn_arg_def_lit_line);
856 1032
857 FnArgDef = (Variable | SelfItem >> -ExistentialOp) >> -(space >> '=' >> space >> Exp); 1033 FnArgDef = (Variable | SelfItem >> -ExistentialOp) >> -(space >> '`' >> space >> Name) >> -(space >> '=' >> space >> Exp) | TableLit | SimpleTable;
858 1034
859 FnArgDefList = Seperator >> ( 1035 check_vararg_position = and_(white >> (')' | key("using"))) | white >> -(',' >> white) >> vararg_position_error;
860 fn_arg_def_lit_lines >> -(-(space >> ',') >> white >> VarArg) | 1036
861 white >> VarArg 1037 var_arg_def = (
862 ); 1038 VarArgDef |
1039 +space_break >> push_indent_match >> ensure(space >> VarArgDef >> -(space >> '`' >> space >> Name), pop_indent)
1040 ) >> check_vararg_position;
1041
1042 FnArgDefList = Seperator >>
1043 -fn_arg_def_list >>
1044 -(-(space >> ',') >> +space_break >> fn_arg_def_lit_lines) >>
1045 -(-(space >> ',') >> space >> var_arg_def);
863 1046
864 OuterVarShadow = key("using") >> space >> (NameList | key("nil")); 1047 OuterVarShadow = key("using") >> space >> (key("nil") | NameList);
865 1048
866 FnArgsDef = '(' >> *space_break >> -FnArgDefList >> -(white >> OuterVarShadow) >> white >> ')'; 1049 outer_var_shadow_def = OuterVarShadow |
1050 +space_break >> push_indent_match >> ensure(space >> OuterVarShadow, pop_indent);
1051
1052 FnArgsDef = '(' >> space >> -FnArgDefList >> -(space >> outer_var_shadow_def) >> white >> -(and_(',') >> unexpected_comma_error) >> ')';
867 FnArrow = expr("->") | "=>"; 1053 FnArrow = expr("->") | "=>";
868 FunLit = pl::user(true_(), [](const item_t& item) { 1054 FunLit = pl::user(true_(), [](const item_t& item) {
869 State* st = reinterpret_cast<State*>(item.user_data); 1055 State* st = reinterpret_cast<State*>(item.user_data);
870 return st->fnArrowAvailable; 1056 return st->fnArrowAvailable;
871 }) >> -(FnArgsDef >> 1057 }) >> -(FnArgsDef >>
872 -(':' >> space >> 1058 -(':' >> space >>
873 disable_fun_lit >> ensure(ExpListLow | DefaultValue, enable_fun_lit) 1059 disable_fun_lit >> ensure(ExpList | DefaultValue, enable_fun_lit)
874 ) 1060 )
875 ) >> space >> FnArrow >> -(space >> Body); 1061 ) >> space >> FnArrow >> -(space >> Body);
876 1062
877 MacroName = '$' >> UnicodeName; 1063 MacroName = '$' >> UnicodeName;
878 macro_args_def = '(' >> white >> -FnArgDefList >> white >> ')'; 1064 macro_args_def = '(' >> space >> -FnArgDefList >> white >> -(and_(',') >> unexpected_comma_error) >> ')';
879 MacroLit = -(macro_args_def >> space) >> "->" >> space >> Body; 1065 MacroLit = -(macro_args_def >> space) >> "->" >> space >> Body;
880 MacroFunc = MacroName >> (Invoke | InvokeArgs); 1066 MacroFunc = MacroName >> (Invoke | InvokeArgs);
881 Macro = key("macro") >> space >> UnicodeName >> space >> '=' >> space >> (MacroLit | MacroFunc); 1067 Macro = key("macro") >> space >> (
1068 UnicodeName >> space >> '=' >> space >> (MacroLit | MacroFunc | invalid_macro_definition_error) |
1069 invalid_macro_definition_error
1070 );
882 MacroInPlace = '$' >> space >> "->" >> space >> Body; 1071 MacroInPlace = '$' >> space >> "->" >> space >> Body;
883 1072
884 NameList = Seperator >> Variable >> *(space >> ',' >> space >> Variable); 1073 must_variable = Variable | and_(LuaKeyword >> not_alpha_num) >> keyword_as_identifier_syntax_error | expected_indentifier_error;
885 NameOrDestructure = Variable | TableLit | Comprehension; 1074
1075 NameList = Seperator >> must_variable >> *(space >> ',' >> space >> must_variable);
1076 NameOrDestructure = Variable | TableLit | Comprehension | SimpleTable | expected_expression_error;
886 AssignableNameList = Seperator >> NameOrDestructure >> *(space >> ',' >> space >> NameOrDestructure); 1077 AssignableNameList = Seperator >> NameOrDestructure >> *(space >> ',' >> space >> NameOrDestructure);
887 1078
888 FnArrowBack = '<' >> set("-="); 1079 FnArrowBack = '<' >> set("-=");
889 Backcall = -(FnArgsDef >> space) >> FnArrowBack >> space >> ChainValue; 1080 Backcall = -(FnArgsDef >> space) >> FnArrowBack >> space >> ChainValue;
1081 SubBackcall = FnArrowBack >> space >> ChainValue;
1082
1083 must_unary_exp = UnaryExp | expected_expression_error;
890 1084
891 PipeBody = Seperator >> 1085 PipeBody = Seperator >>
892 pipe_operator >> space >> UnaryExp >> 1086 pipe_operator >> space >> must_unary_exp >>
893 *(+space_break >> check_indent_match >> space >> pipe_operator >> space >> UnaryExp); 1087 *(+space_break >> check_indent_match >> space >> pipe_operator >> space >> must_unary_exp);
894 1088
895 ExpList = Seperator >> Exp >> *(space >> ',' >> space >> Exp); 1089 ExpList = Seperator >> Exp >> *(space >> ',' >> space >> Exp);
896 ExpListLow = Seperator >> Exp >> *(space >> set(",;") >> space >> Exp);
897 1090
898 arg_line = check_indent_match >> space >> Exp >> *(space >> ',' >> space >> Exp); 1091 arg_line = check_indent_match >> space >> Exp >> *(space >> ',' >> space >> Exp);
899 arg_block = arg_line >> *(space >> ',' >> space_break >> arg_line) >> pop_indent; 1092 arg_block = arg_line >> *(space >> ',' >> space_break >> arg_line) >> pop_indent;
900 1093
901 arg_table_block = pl::user(true_(), [](const item_t& item) { 1094 arg_table_block = pl::user(true_(), [](const item_t& item) {
902 State* st = reinterpret_cast<State*>(item.user_data); 1095 State* st = reinterpret_cast<State*>(item.user_data);
903 return st->noTableBlockStack.empty() || !st->noTableBlockStack.top(); 1096 return st->noTableBlockStack.empty() || !st->noTableBlockStack.back();
904 }) >> TableBlock; 1097 }) >> TableBlock;
905 1098
906 invoke_args_with_table = 1099 invoke_args_with_table =
@@ -909,103 +1102,84 @@ YueParser::YueParser() {
909 space_break >> advance_match >> arg_block >> -(-(space >> ',') >> arg_table_block) 1102 space_break >> advance_match >> arg_block >> -(-(space >> ',') >> arg_table_block)
910 ) | arg_table_block; 1103 ) | arg_table_block;
911 1104
912 leading_spaces_error = pl::user(+space_one >> '(' >> space >> Exp >> +(space >> ',' >> space >> Exp) >> space >> ')', [](const item_t& item) {
913 throw ParserError("write invoke arguments in parentheses without leading spaces or just leading spaces without parentheses"sv, item.begin);
914 return false;
915 });
916
917 InvokeArgs = 1105 InvokeArgs =
918 not_(set("-~") | "[]") >> space >> Seperator >> ( 1106 not_(set("-~") | "[]") >> space >> Seperator >> (
919 Exp >> *(space >> ',' >> space >> Exp) >> -(space >> invoke_args_with_table) | 1107 Exp >> *(space >> ',' >> space >> Exp) >> -(space >> invoke_args_with_table) |
920 arg_table_block | 1108 arg_table_block
921 leading_spaces_error
922 ); 1109 );
923 1110
924 ConstValue = (expr("nil") | "true" | "false") >> not_alpha_num; 1111 ConstValue = (expr("nil") | "true" | "false") >> not_alpha_num;
925 1112
926 braces_expression_error = pl::user(true_(), [](const item_t& item) {
927 throw ParserError("syntax error in brace expression"sv, item.begin);
928 return false;
929 });
930
931 brackets_expression_error = pl::user(true_(), [](const item_t& item) {
932 throw ParserError("syntax error in bracket expression"sv, item.begin);
933 return false;
934 });
935
936 slice_expression_error = pl::user(true_(), [](const item_t& item) {
937 throw ParserError("syntax error in slice expression"sv, item.begin);
938 return false;
939 });
940
941 SimpleValue = 1113 SimpleValue =
942 TableLit | ConstValue | If | Switch | Try | With | 1114 TableLit | ConstValue | If | Switch | Try | With |
943 ClassDecl | ForEach | For | While | Do | 1115 ClassDecl | For | While | Repeat | Do |
944 UnaryValue | TblComprehension | Comprehension | 1116 UnaryValue | TblComprehension | Comprehension |
945 FunLit | Num | VarArg; 1117 FunLit | Num | VarArg;
946 1118
947 ExpListAssign = ExpList >> -(space >> (Update | Assign)) >> not_(space >> '='); 1119 ExpListAssign = ExpList >> -(space >> (Update | Assign | SubBackcall)) >> not_(space >> '=');
948 1120
949 IfLine = IfType >> space >> IfCond; 1121 IfLine = IfType >> space >> IfCond;
950 WhileLine = WhileType >> space >> Exp; 1122 WhileLine = WhileType >> space >> Exp;
951 1123
952 YueLineComment = *(not_(set("\r\n")) >> any_char);
953 yue_line_comment = "--" >> YueLineComment >> and_(stop);
954 MultilineCommentInner = multi_line_content;
955 YueMultilineComment = multi_line_open >> MultilineCommentInner >> multi_line_close;
956 yue_comment = check_indent >> (
957 (
958 YueMultilineComment >>
959 *(set(" \t") | YueMultilineComment) >>
960 -yue_line_comment
961 ) | yue_line_comment
962 ) >> and_(line_break);
963
964 ChainAssign = Seperator >> Exp >> +(space >> '=' >> space >> Exp >> space >> and_('=')) >> space >> Assign; 1124 ChainAssign = Seperator >> Exp >> +(space >> '=' >> space >> Exp >> space >> and_('=')) >> space >> Assign;
965 1125
966 StatementAppendix = (IfLine | WhileLine | CompInner) >> space; 1126 StatementAppendix = IfLine | WhileLine | CompFor;
967 Statement = 1127 Statement = (
968 Seperator >> 1128 (
969 -( 1129 Import | Export | Global | Macro | MacroInPlace | Label
970 yue_comment >> 1130 ) | (
971 *(line_break >> yue_comment) >> 1131 Local | While | Repeat | For | Return |
972 line_break >> 1132 BreakLoop | Goto | ShortTabAppending |
973 check_indent_match
974 ) >>
975 space >> (
976 Import | While | Repeat | For | ForEach |
977 Return | Local | Global | Export | Macro |
978 MacroInPlace | BreakLoop | Label | Goto | ShortTabAppending |
979 LocalAttrib | Backcall | PipeBody | ExpListAssign | ChainAssign | 1133 LocalAttrib | Backcall | PipeBody | ExpListAssign | ChainAssign |
980 StatementAppendix >> empty_block_error 1134 StatementAppendix >> empty_block_error |
981 ) >> 1135 and_(key("else") | key("elseif") | key("when")) >> dangling_clause_error
982 space >> 1136 ) >> space >> -StatementAppendix
983 -StatementAppendix; 1137 ) >> space;
984 1138
985 StatementSep = white >> (set("('\"") | "[[" | "[="); 1139 StatementSep = white >> (set("('\"") | "[[" | "[=");
986 1140
987 Body = in_block | Statement; 1141 Body = in_block | Statement;
988 1142
989 empty_line_break = 1143 YueLineComment = *(not_(set("\r\n")) >> any_char);
990 check_indent >> (multi_line_comment >> space | comment) >> and_(stop) | 1144 yue_line_comment = "--" >> YueLineComment >> and_(stop);
991 advance >> ensure(multi_line_comment >> space | comment, pop_indent) >> and_(stop) | 1145 YueMultilineComment = multi_line_content;
992 plain_space >> and_(line_break); 1146 yue_multiline_comment = multi_line_open >> YueMultilineComment >> multi_line_close;
1147 comment_line =
1148 yue_multiline_comment >> *(set(" \t") | yue_multiline_comment) >> plain_space >> -yue_line_comment |
1149 yue_line_comment;
1150 YueComment =
1151 check_indent >> comment_line >> and_(stop) |
1152 advance >> ensure(comment_line, pop_indent) >> and_(stop);
1153
1154 EmptyLine = plain_space >> and_(stop);
993 1155
994 indentation_error = pl::user(not_(pipe_operator | eof()), [](const item_t& item) { 1156 indentation_error = pl::user(not_(pipe_operator | eof()), [](const item_t& item) {
995 throw ParserError("unexpected indent"sv, item.begin); 1157 RaiseError("unexpected indent"sv, item);
996 return false; 1158 return false;
997 }); 1159 });
998 1160
999 line = ( 1161 is_lax = pl::user(true_(), [](const item_t& item) {
1000 check_indent_match >> Statement | 1162 State* st = reinterpret_cast<State*>(item.user_data);
1001 empty_line_break | 1163 return st->lax;
1164 });
1165
1166 line = *(EmptyLine >> line_break) >> (
1167 check_indent_match >> space >> Statement >> *(';' >> space >> (Statement | not_(';'))) |
1168 YueComment |
1002 advance_match >> ensure(space >> (indentation_error | Statement), pop_indent) 1169 advance_match >> ensure(space >> (indentation_error | Statement), pop_indent)
1003 ); 1170 );
1004 Block = Seperator >> line >> *(+line_break >> line); 1171 Block = Seperator >> (
1172 is_lax >> lax_line >> *(line_break >> lax_line) |
1173 line >> *(line_break >> line)
1174 );
1005 1175
1006 shebang = "#!" >> *(not_(stop) >> any_char); 1176 shebang = "#!" >> *(not_(stop) >> any_char);
1007 BlockEnd = Block >> white >> stop; 1177 BlockEnd = Block >> plain_white >> stop;
1008 File = -shebang >> -Block >> white >> stop; 1178 File = -shebang >> -Block >> plain_white >> stop;
1179
1180 lax_line = advance_match >> ensure(*(not_(stop) >> any()), pop_indent) |
1181 line >> and_(stop) |
1182 check_indent_match >> *(not_(stop) >> any());
1009} 1183}
1010// clang-format on 1184// clang-format on
1011 1185
@@ -1016,7 +1190,7 @@ bool YueParser::startWith(std::string_view codes, rule& r) {
1016 } 1190 }
1017 try { 1191 try {
1018 if (!codes.empty()) { 1192 if (!codes.empty()) {
1019 converted = std::make_unique<input>(_converter.from_bytes(&codes.front(), &codes.back() + 1)); 1193 converted = std::make_unique<input>(utf8_decode({&codes.front(), &codes.back() + 1}));
1020 } else { 1194 } else {
1021 converted = std::make_unique<input>(); 1195 converted = std::make_unique<input>();
1022 } 1196 }
@@ -1035,24 +1209,25 @@ bool YueParser::startWith(std::string_view codes, rule& r) {
1035 return true; 1209 return true;
1036} 1210}
1037 1211
1038ParseInfo YueParser::parse(std::string_view codes, rule& r) { 1212ParseInfo YueParser::parse(std::string_view codes, rule& r, bool lax) {
1039 ParseInfo res; 1213 ParseInfo res;
1040 if (codes.substr(0, 3) == "\xEF\xBB\xBF"sv) { 1214 if (codes.substr(0, 3) == "\xEF\xBB\xBF"sv) {
1041 codes = codes.substr(3); 1215 codes = codes.substr(3);
1042 } 1216 }
1043 try { 1217 try {
1044 if (!codes.empty()) { 1218 if (!codes.empty()) {
1045 res.codes = std::make_unique<input>(_converter.from_bytes(&codes.front(), &codes.back() + 1)); 1219 res.codes = std::make_unique<input>(utf8_decode({&codes.front(), &codes.back() + 1}));
1046 } else { 1220 } else {
1047 res.codes = std::make_unique<input>(); 1221 res.codes = std::make_unique<input>();
1048 } 1222 }
1049 } catch (const std::range_error&) { 1223 } catch (const std::exception&) {
1050 res.error = {"invalid text encoding"s, 1, 1}; 1224 res.error = {"invalid text encoding"s, 1, 1};
1051 return res; 1225 return res;
1052 } 1226 }
1053 error_list errors; 1227 error_list errors;
1054 try { 1228 try {
1055 State state; 1229 State state;
1230 state.lax = lax;
1056 res.node.set(::yue::parse(*(res.codes), r, errors, &state)); 1231 res.node.set(::yue::parse(*(res.codes), r, errors, &state));
1057 if (state.exportCount > 0) { 1232 if (state.exportCount > 0) {
1058 int index = 0; 1233 int index = 0;
@@ -1090,29 +1265,31 @@ ParseInfo YueParser::parse(std::string_view codes, rule& r) {
1090 return res; 1265 return res;
1091} 1266}
1092 1267
1093ParseInfo YueParser::parse(std::string_view astName, std::string_view codes) { 1268ParseInfo YueParser::parse(std::string_view astName, std::string_view codes, bool lax) {
1094 auto it = _rules.find(astName); 1269 auto it = _rules.find(astName);
1095 if (it != _rules.end()) { 1270 if (it != _rules.end()) {
1096 return parse(codes, *it->second); 1271 return parse(codes, *it->second, lax);
1097 } 1272 }
1098 return {}; 1273 ParseInfo info{};
1274 info.error = ParseInfo::Error{"invalid rule: "s + std::string{astName}, 1, 1};
1275 return info;
1099} 1276}
1100 1277
1101bool YueParser::match(std::string_view astName, std::string_view codes) { 1278bool YueParser::match(std::string_view astName, std::string_view codes) {
1102 auto it = _rules.find(astName); 1279 auto it = _rules.find(astName);
1103 if (it != _rules.end()) { 1280 if (it != _rules.end()) {
1104 auto rEnd = rule(*it->second >> eof()); 1281 auto rEnd = rule(*it->second >> eof());
1105 return parse(codes, rEnd).node; 1282 return parse(codes, rEnd, false).node;
1106 } 1283 }
1107 return false; 1284 return false;
1108} 1285}
1109 1286
1110std::string YueParser::toString(ast_node* node) { 1287std::string YueParser::toString(ast_node* node) {
1111 return _converter.to_bytes(std::wstring(node->m_begin.m_it, node->m_end.m_it)); 1288 return utf8_encode({node->m_begin.m_it, node->m_end.m_it});
1112} 1289}
1113 1290
1114std::string YueParser::toString(input::iterator begin, input::iterator end) { 1291std::string YueParser::toString(input::iterator begin, input::iterator end) {
1115 return _converter.to_bytes(std::wstring(begin, end)); 1292 return utf8_encode({begin, end});
1116} 1293}
1117 1294
1118bool YueParser::hasAST(std::string_view name) const { 1295bool YueParser::hasAST(std::string_view name) const {
@@ -1138,6 +1315,24 @@ void trim(std::string& str) {
1138 str.erase(0, str.find_first_not_of(" \t\r\n")); 1315 str.erase(0, str.find_first_not_of(" \t\r\n"));
1139 str.erase(str.find_last_not_of(" \t\r\n") + 1); 1316 str.erase(str.find_last_not_of(" \t\r\n") + 1);
1140} 1317}
1318
1319std::string toLuaDoubleString(const std::string& input) {
1320 std::string luaStr = "\"";
1321 for (char c : input) {
1322 switch (c) {
1323 case '\"': luaStr += "\\\""; break;
1324 case '\\': luaStr += "\\\\"; break;
1325 case '\n': luaStr += "\\n"; break;
1326 case '\r': luaStr += "\\r"; break;
1327 case '\t': luaStr += "\\t"; break;
1328 default:
1329 luaStr += c;
1330 break;
1331 }
1332 }
1333 luaStr += "\"";
1334 return luaStr;
1335}
1141} // namespace Utils 1336} // namespace Utils
1142 1337
1143std::string ParseInfo::errorMessage(std::string_view msg, int errLine, int errCol, int lineOffset) const { 1338std::string ParseInfo::errorMessage(std::string_view msg, int errLine, int errCol, int lineOffset) const {
@@ -1171,7 +1366,7 @@ std::string ParseInfo::errorMessage(std::string_view msg, int errLine, int errCo
1171 } 1366 }
1172 ++it; 1367 ++it;
1173 } 1368 }
1174 auto line = Converter{}.to_bytes(std::wstring(begin, end)); 1369 auto line = utf8_encode({begin, end});
1175 while (col < static_cast<int>(line.size()) 1370 while (col < static_cast<int>(line.size())
1176 && (line[col] == ' ' || line[col] == '\t')) { 1371 && (line[col] == ' ' || line[col] == '\t')) {
1177 col++; 1372 col++;
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h
index 7281ec3..df9f39c 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,18 @@ 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(is_lax);
323 NONE_AST_RULE(lax_line);
287 324
288 AST_RULE(Num); 325 AST_RULE(Num);
289 AST_RULE(Name); 326 AST_RULE(Name);
290 AST_RULE(UnicodeName); 327 AST_RULE(UnicodeName);
291 AST_RULE(Variable); 328 AST_RULE(Variable);
292 AST_RULE(LabelName);
293 AST_RULE(LuaKeyword); 329 AST_RULE(LuaKeyword);
294 AST_RULE(Self); 330 AST_RULE(Self);
295 AST_RULE(SelfName); 331 AST_RULE(SelfName);
@@ -298,6 +334,7 @@ private:
298 AST_RULE(SelfItem); 334 AST_RULE(SelfItem);
299 AST_RULE(KeyName); 335 AST_RULE(KeyName);
300 AST_RULE(VarArg); 336 AST_RULE(VarArg);
337 AST_RULE(VarArgDef);
301 AST_RULE(Seperator); 338 AST_RULE(Seperator);
302 AST_RULE(NameList); 339 AST_RULE(NameList);
303 AST_RULE(LocalFlag); 340 AST_RULE(LocalFlag);
@@ -315,14 +352,16 @@ private:
315 AST_RULE(ImportAllMacro); 352 AST_RULE(ImportAllMacro);
316 AST_RULE(ImportTabLit); 353 AST_RULE(ImportTabLit);
317 AST_RULE(ImportAs); 354 AST_RULE(ImportAs);
355 AST_RULE(ImportGlobal);
356 AST_RULE(ImportAllGlobal);
318 AST_RULE(Import); 357 AST_RULE(Import);
319 AST_RULE(Label); 358 AST_RULE(Label);
320 AST_RULE(Goto); 359 AST_RULE(Goto);
321 AST_RULE(ShortTabAppending); 360 AST_RULE(ShortTabAppending);
322 AST_RULE(FnArrowBack); 361 AST_RULE(FnArrowBack);
323 AST_RULE(Backcall); 362 AST_RULE(Backcall);
363 AST_RULE(SubBackcall);
324 AST_RULE(PipeBody); 364 AST_RULE(PipeBody);
325 AST_RULE(ExpListLow);
326 AST_RULE(ExpList); 365 AST_RULE(ExpList);
327 AST_RULE(Return); 366 AST_RULE(Return);
328 AST_RULE(With); 367 AST_RULE(With);
@@ -338,6 +377,7 @@ private:
338 AST_RULE(Repeat); 377 AST_RULE(Repeat);
339 AST_RULE(ForStepValue); 378 AST_RULE(ForStepValue);
340 AST_RULE(For); 379 AST_RULE(For);
380 AST_RULE(ForNum);
341 AST_RULE(ForEach); 381 AST_RULE(ForEach);
342 AST_RULE(Do); 382 AST_RULE(Do);
343 AST_RULE(CatchBlock); 383 AST_RULE(CatchBlock);
@@ -347,8 +387,8 @@ private:
347 AST_RULE(TblComprehension); 387 AST_RULE(TblComprehension);
348 AST_RULE(StarExp); 388 AST_RULE(StarExp);
349 AST_RULE(CompForEach); 389 AST_RULE(CompForEach);
390 AST_RULE(CompForNum);
350 AST_RULE(CompFor); 391 AST_RULE(CompFor);
351 AST_RULE(CompInner);
352 AST_RULE(Assign); 392 AST_RULE(Assign);
353 AST_RULE(UpdateOp); 393 AST_RULE(UpdateOp);
354 AST_RULE(Update); 394 AST_RULE(Update);
@@ -359,6 +399,7 @@ private:
359 AST_RULE(ExpOpValue); 399 AST_RULE(ExpOpValue);
360 AST_RULE(Exp); 400 AST_RULE(Exp);
361 AST_RULE(Callable); 401 AST_RULE(Callable);
402 AST_RULE(ReversedIndex);
362 AST_RULE(ChainValue); 403 AST_RULE(ChainValue);
363 AST_RULE(SimpleTable); 404 AST_RULE(SimpleTable);
364 AST_RULE(SimpleValue); 405 AST_RULE(SimpleValue);
@@ -371,6 +412,11 @@ private:
371 AST_RULE(DoubleStringInner); 412 AST_RULE(DoubleStringInner);
372 AST_RULE(DoubleStringContent); 413 AST_RULE(DoubleStringContent);
373 AST_RULE(DoubleString); 414 AST_RULE(DoubleString);
415 AST_RULE(YAMLIndent);
416 AST_RULE(YAMLLineInner);
417 AST_RULE(YAMLLineContent);
418 AST_RULE(YAMLLine);
419 AST_RULE(YAMLMultiline);
374 AST_RULE(String); 420 AST_RULE(String);
375 AST_RULE(Parens); 421 AST_RULE(Parens);
376 AST_RULE(DotChainItem); 422 AST_RULE(DotChainItem);
@@ -427,13 +473,16 @@ private:
427 AST_RULE(ExpListAssign); 473 AST_RULE(ExpListAssign);
428 AST_RULE(IfLine); 474 AST_RULE(IfLine);
429 AST_RULE(WhileLine); 475 AST_RULE(WhileLine);
476 AST_RULE(Break);
477 AST_RULE(Continue);
430 AST_RULE(BreakLoop); 478 AST_RULE(BreakLoop);
431 AST_RULE(StatementAppendix); 479 AST_RULE(StatementAppendix);
432 AST_RULE(Statement); 480 AST_RULE(Statement);
433 AST_RULE(StatementSep); 481 AST_RULE(StatementSep);
434 AST_RULE(YueLineComment); 482 AST_RULE(YueLineComment);
435 AST_RULE(MultilineCommentInner);
436 AST_RULE(YueMultilineComment); 483 AST_RULE(YueMultilineComment);
484 AST_RULE(YueComment);
485 AST_RULE(EmptyLine);
437 AST_RULE(ChainAssign); 486 AST_RULE(ChainAssign);
438 AST_RULE(Body); 487 AST_RULE(Body);
439 AST_RULE(Block); 488 AST_RULE(Block);
@@ -444,6 +493,7 @@ private:
444namespace Utils { 493namespace Utils {
445void replace(std::string& str, std::string_view from, std::string_view to); 494void replace(std::string& str, std::string_view from, std::string_view to);
446void trim(std::string& str); 495void trim(std::string& str);
496std::string toLuaDoubleString(const std::string& input);
447} // namespace Utils 497} // namespace Utils
448 498
449} // namespace yue 499} // 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>