aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2022-07-24 22:13:08 +0800
committerLi Jin <dragon-fly@qq.com>2022-07-24 22:13:08 +0800
commit303834e1b1e6cd9cae64b66c2ae44dcd7185238f (patch)
tree519f6a1debcc5791d35e06dc5cbb1ce22f9cfd31
parenteb367126bf3a4f5b0e51ccef93b7c7136bea170e (diff)
downloadyuescript-303834e1b1e6cd9cae64b66c2ae44dcd7185238f.tar.gz
yuescript-303834e1b1e6cd9cae64b66c2ae44dcd7185238f.tar.bz2
yuescript-303834e1b1e6cd9cae64b66c2ae44dcd7185238f.zip
add option --target=5.1 to generate Lua 5.1 compatible codes. add const destructure. make import item const by default.
-rw-r--r--makefile4
-rw-r--r--spec/inputs/destructure.yue5
-rw-r--r--spec/inputs/export.yue4
-rw-r--r--spec/inputs/import.yue2
-rw-r--r--spec/inputs/macro.yue2
-rw-r--r--spec/inputs/metatable.yue2
-rw-r--r--spec/inputs/syntax.yue10
-rw-r--r--spec/inputs/tables.yue8
-rw-r--r--spec/inputs/with.yue2
-rw-r--r--spec/outputs/destructure.lua25
-rw-r--r--spec/outputs/export.lua10
-rw-r--r--spec/outputs/import.lua2
-rw-r--r--spec/outputs/macro.lua3
-rw-r--r--spec/outputs/metatable.lua1
-rw-r--r--spec/outputs/syntax.lua10
-rw-r--r--spec/outputs/tables.lua8
-rw-r--r--spec/outputs/with.lua2
-rw-r--r--src/yue.cpp39
-rwxr-xr-xsrc/yuescript/yue_ast.h24
-rwxr-xr-xsrc/yuescript/yue_compiler.cpp232
-rwxr-xr-xsrc/yuescript/yue_parser.cpp42
-rwxr-xr-xsrc/yuescript/yue_parser.h8
-rw-r--r--src/yuescript/yuescript.cpp10
23 files changed, 321 insertions, 134 deletions
diff --git a/makefile b/makefile
index bf5298a..913d70b 100644
--- a/makefile
+++ b/makefile
@@ -266,7 +266,7 @@ test: release
266 @mkdir -p $(TEST_OUTPUT) 266 @mkdir -p $(TEST_OUTPUT)
267 @echo "Compiling Yuescript codes..." 267 @echo "Compiling Yuescript codes..."
268 @$(START_TIME) 268 @$(START_TIME)
269 @./$(BIN_NAME) $(TEST_INPUT) -t $(TEST_OUTPUT) -tl_enabled 269 @./$(BIN_NAME) $(TEST_INPUT) -t $(TEST_OUTPUT) --tl_enabled
270 @./$(BIN_NAME) $(TEST_INPUT)/teal-lang.yue -o $(TEST_OUTPUT)/teal-lang.lua 270 @./$(BIN_NAME) $(TEST_INPUT)/teal-lang.yue -o $(TEST_OUTPUT)/teal-lang.lua
271 @echo -en "Compile time: " 271 @echo -en "Compile time: "
272 @$(END_TIME) 272 @$(END_TIME)
@@ -279,7 +279,7 @@ test: release
279gen: release 279gen: release
280 @echo "Compiling Yuescript codes..." 280 @echo "Compiling Yuescript codes..."
281 @$(START_TIME) 281 @$(START_TIME)
282 @./$(BIN_NAME) $(TEST_INPUT) -t $(GEN_OUTPUT) -tl_enabled 282 @./$(BIN_NAME) $(TEST_INPUT) -t $(GEN_OUTPUT) --tl_enabled
283 @./$(BIN_NAME) $(TEST_INPUT)/teal-lang.yue -o $(GEN_OUTPUT)/teal-lang.lua 283 @./$(BIN_NAME) $(TEST_INPUT)/teal-lang.yue -o $(GEN_OUTPUT)/teal-lang.lua
284 @echo -en "Compile time: " 284 @echo -en "Compile time: "
285 @$(END_TIME) 285 @$(END_TIME)
diff --git a/spec/inputs/destructure.yue b/spec/inputs/destructure.yue
index 3007adf..24282c0 100644
--- a/spec/inputs/destructure.yue
+++ b/spec/inputs/destructure.yue
@@ -11,7 +11,7 @@ do
11 11
12 {:a,:b,:c,:d} = yeah 12 {:a,:b,:c,:d} = yeah
13 13
14 {a} = one, two 14 {a}, b = one, two
15 {b}, c = one 15 {b}, c = one
16 {d}, e = one, two 16 {d}, e = one, two
17 17
@@ -184,3 +184,6 @@ do
184do 184do
185 {x: a.b = 1, y: a.c = 2} = x.x.x 185 {x: a.b = 1, y: a.c = 2} = x.x.x
186 186
187do
188 const :width, :height = View.size
189 const {:x = 0.0, :y = 0.0} = point
diff --git a/spec/inputs/export.yue b/spec/inputs/export.yue
index 9113508..15ffbcb 100644
--- a/spec/inputs/export.yue
+++ b/spec/inputs/export.yue
@@ -55,7 +55,7 @@ f switch a
55f [i for i = 1,10] 55f [i for i = 1,10]
56f for i = 1,10 do i 56f for i = 1,10 do i
57f {k,v for k,v in pairs tb} 57f {k,v for k,v in pairs tb}
58f for k,v in pairs tb do k,v 58f for k,v in pairs tb do {k,v}
59f while a do true 59f while a do true
60f with a 60f with a
61 .b = 123 61 .b = 123
@@ -70,7 +70,7 @@ _ = "#{switch a
70_ = "#{[i for i = 1,10]}" 70_ = "#{[i for i = 1,10]}"
71_ = "#{for i = 1,10 do i}" 71_ = "#{for i = 1,10 do i}"
72_ = "#{{k,v for k,v in pairs tb}}" 72_ = "#{{k,v for k,v in pairs tb}}"
73_ = "#{for k,v in pairs tb do k,v}" 73_ = "#{for k,v in pairs tb do {k,v}}"
74_ = "#{while a do true}" 74_ = "#{while a do true}"
75_ = "#{with a 75_ = "#{with a
76 .b = 123}" 76 .b = 123}"
diff --git a/spec/inputs/import.yue b/spec/inputs/import.yue
index 8e82a01..e206d04 100644
--- a/spec/inputs/import.yue
+++ b/spec/inputs/import.yue
@@ -70,7 +70,7 @@ do
70 70
71do 71do
72 import "m" as {a#: b} 72 import "m" as {a#: b}
73 import "m" as {e: f, a#: b} 73 import "m" as {e: f, a#: c}
74 import "m" as {c: d} 74 import "m" as {c: d}
75 import "m" as {g, {h#: i}} 75 import "m" as {g, {h#: i}}
76 76
diff --git a/spec/inputs/macro.yue b/spec/inputs/macro.yue
index 7bbb06d..3c89c1c 100644
--- a/spec/inputs/macro.yue
+++ b/spec/inputs/macro.yue
@@ -279,7 +279,7 @@ do
279 279
280macro skip = -> "while false do break" 280macro skip = -> "while false do break"
281 281
282_ = -> 282_1 = ->
283 print 1 283 print 1
284 <- $skip 284 <- $skip
285 print 2 285 print 2
diff --git a/spec/inputs/metatable.yue b/spec/inputs/metatable.yue
index ed68a17..7e9b4f2 100644
--- a/spec/inputs/metatable.yue
+++ b/spec/inputs/metatable.yue
@@ -23,7 +23,7 @@ do
23 = 123, a.b.c, func! 23 = 123, a.b.c, func!
24 24
25x.abc, a.b.# = 123, {} 25x.abc, a.b.# = 123, {}
26func!.# = mt, extra 26func!.# = mt --, extra
27a, b.c.#, d, e = 1, mt, "abc" 27a, b.c.#, d, e = 1, mt, "abc"
28 28
29is_same = a.#.__index == a.index# 29is_same = a.#.__index == a.index#
diff --git a/spec/inputs/syntax.yue b/spec/inputs/syntax.yue
index f212bec..d18bd0e 100644
--- a/spec/inputs/syntax.yue
+++ b/spec/inputs/syntax.yue
@@ -71,10 +71,10 @@ _ = something[======[hey]======] * 2
71_ = something[ [======[hey]======] ] * 2 71_ = something[ [======[hey]======] ] * 2
72 72
73 73
74_ = something'else', 2 74_, _ = something'else', 2
75_ = something"else", 2 75_, _ = something"else", 2
76_ = something[[else]], 2 76_, _ = something[[else]], 2
77_ = something[ [[else]] ], 2 77_, _ = something[ [[else]] ], 2
78 78
79something 'else', 2 79something 'else', 2
80something "else", 2 80something "else", 2
@@ -157,7 +157,7 @@ y = #"hello"
157 157
158x = #{#{},#{1},#{1,2}} 158x = #{#{},#{1},#{1,2}}
159 159
160_ = hello, world 160_, _ = hello, world
161 161
162something\hello(what) a,b 162something\hello(what) a,b
163something\hello what 163something\hello what
diff --git a/spec/inputs/tables.yue b/spec/inputs/tables.yue
index e1b9e1d..0b5af46 100644
--- a/spec/inputs/tables.yue
+++ b/spec/inputs/tables.yue
@@ -152,12 +152,12 @@ k = { "hello": 'world', "hat": "zat" }
152please "hello": "world" 152please "hello": "world"
153k = "hello": "world", "one": "zone" 153k = "hello": "world", "one": "zone"
154 154
155f = "one", "two": three, "four" 155f1, f2, f3 = "one", "two": three, "four"
156f = "two": three, "four" 156f1, f2 = "two": three, "four"
157f = { "one", "two": three, "four" } 157f1 = { "one", "two": three, "four" }
158 158
159 159
160j = "one", "two": three, "four": five, 6, 7 160j1, j2, j3, j4 = "one", "two": three, "four": five, 6, 7
161 161
162heroine = 162heroine =
163 name: "Christina" 163 name: "Christina"
diff --git a/spec/inputs/with.yue b/spec/inputs/with.yue
index 6f3e3ba..5da0980 100644
--- a/spec/inputs/with.yue
+++ b/spec/inputs/with.yue
@@ -45,7 +45,7 @@ do
45-- 45--
46 46
47do 47do
48 with a, b -- b is lost 48 with a -- only one value allowed
49 print .world 49 print .world
50 50
51 mod = with _M = {} 51 mod = with _M = {}
diff --git a/spec/outputs/destructure.lua b/spec/outputs/destructure.lua
index 2fe4ba9..59ee358 100644
--- a/spec/outputs/destructure.lua
+++ b/spec/outputs/destructure.lua
@@ -26,7 +26,7 @@ do
26 local _obj_0 = yeah 26 local _obj_0 = yeah
27 a, b, c, d = _obj_0.a, _obj_0.b, _obj_0.c, _obj_0.d 27 a, b, c, d = _obj_0.a, _obj_0.b, _obj_0.c, _obj_0.d
28 end 28 end
29 local _ = two 29 b = two
30 a = one[1] 30 a = one[1]
31 c = nil 31 c = nil
32 b = one[1] 32 b = one[1]
@@ -56,7 +56,10 @@ do
56 end 56 end
57 do 57 do
58 a = tbl 58 a = tbl
59 b, c = _.b, _.c 59 do
60 local _obj_0 = _
61 b, c = _obj_0.b, _obj_0.c
62 end
60 end 63 end
61 do 64 do
62 b = _ 65 b = _
@@ -386,3 +389,21 @@ do
386 a.c = _tmp_1 389 a.c = _tmp_1
387 end 390 end
388end 391end
392do
393 local width, height
394 do
395 local _obj_0 = View.size
396 width, height = _obj_0.width, _obj_0.height
397 end
398 local x, y
399 do
400 local _obj_0 = point
401 x, y = _obj_0.x, _obj_0.y
402 if x == nil then
403 x = 0.0
404 end
405 if y == nil then
406 y = 0.0
407 end
408 end
409end
diff --git a/spec/outputs/export.lua b/spec/outputs/export.lua
index 84e5424..962f18c 100644
--- a/spec/outputs/export.lua
+++ b/spec/outputs/export.lua
@@ -134,7 +134,10 @@ f((function()
134 local _accum_0 = { } 134 local _accum_0 = { }
135 local _len_0 = 1 135 local _len_0 = 1
136 for k, v in pairs(tb) do 136 for k, v in pairs(tb) do
137 _accum_0[_len_0] = k, v 137 _accum_0[_len_0] = {
138 k,
139 v
140 }
138 _len_0 = _len_0 + 1 141 _len_0 = _len_0 + 1
139 end 142 end
140 return _accum_0 143 return _accum_0
@@ -232,7 +235,10 @@ _ = tostring((function()
232 local _accum_0 = { } 235 local _accum_0 = { }
233 local _len_0 = 1 236 local _len_0 = 1
234 for k, v in pairs(tb) do 237 for k, v in pairs(tb) do
235 _accum_0[_len_0] = k, v 238 _accum_0[_len_0] = {
239 k,
240 v
241 }
236 _len_0 = _len_0 + 1 242 _len_0 = _len_0 + 1
237 end 243 end
238 return _accum_0 244 return _accum_0
diff --git a/spec/outputs/import.lua b/spec/outputs/import.lua
index 65e703f..6979e47 100644
--- a/spec/outputs/import.lua
+++ b/spec/outputs/import.lua
@@ -94,7 +94,7 @@ do
94 b = getmetatable(require("m")).__a 94 b = getmetatable(require("m")).__a
95 local _obj_0 = require("m") 95 local _obj_0 = require("m")
96 local f = _obj_0.e 96 local f = _obj_0.e
97 b = getmetatable(_obj_0).__a 97 c = getmetatable(_obj_0).__a
98 local d = require("m").c 98 local d = require("m").c
99 local g, i 99 local g, i
100 do 100 do
diff --git a/spec/outputs/macro.lua b/spec/outputs/macro.lua
index c19b2d7..fbc1d48 100644
--- a/spec/outputs/macro.lua
+++ b/spec/outputs/macro.lua
@@ -282,7 +282,8 @@ print("current line: " .. tostring(268));
282do 282do
283 print(1) 283 print(1)
284end 284end
285_ = function() 285local _1
286_1 = function()
286 print(1) 287 print(1)
287 local _accum_0 = { } 288 local _accum_0 = { }
288 local _len_0 = 1 289 local _len_0 = 1
diff --git a/spec/outputs/metatable.lua b/spec/outputs/metatable.lua
index 935202c..2d72e1d 100644
--- a/spec/outputs/metatable.lua
+++ b/spec/outputs/metatable.lua
@@ -65,7 +65,6 @@ end
65setmetatable(a.b, { }) 65setmetatable(a.b, { })
66x.abc = 123 66x.abc = 123
67setmetatable(func(), mt) 67setmetatable(func(), mt)
68local _ = extra
69setmetatable(b.c, mt) 68setmetatable(b.c, mt)
70a, d, e = 1, "abc" 69a, d, e = 1, "abc"
71local is_same = getmetatable(a).__index == getmetatable(a).__index 70local is_same = getmetatable(a).__index == getmetatable(a).__index
diff --git a/spec/outputs/syntax.lua b/spec/outputs/syntax.lua
index 24b78c6..a4cb8e2 100644
--- a/spec/outputs/syntax.lua
+++ b/spec/outputs/syntax.lua
@@ -56,10 +56,10 @@ something("else")
56_ = something([[hey]]) * 2 56_ = something([[hey]]) * 2
57_ = something([======[hey]======]) * 2 57_ = something([======[hey]======]) * 2
58_ = something[ [======[hey]======]] * 2 58_ = something[ [======[hey]======]] * 2
59_ = something('else'), 2 59_, _ = something('else'), 2
60_ = something("else"), 2 60_, _ = something("else"), 2
61_ = something([[else]]), 2 61_, _ = something([[else]]), 2
62_ = something[ [[else]]], 2 62_, _ = something[ [[else]]], 2
63something('else', 2) 63something('else', 2)
64something("else", 2) 64something("else", 2)
65something([[else]], 2) 65something([[else]], 2)
@@ -165,7 +165,7 @@ x = #{
165 2 165 2
166 } 166 }
167} 167}
168_ = hello, world 168_, _ = hello, world
169something:hello(what)(a, b) 169something:hello(what)(a, b)
170something:hello(what) 170something:hello(what)
171something.hello:world(a, b) 171something.hello:world(a, b)
diff --git a/spec/outputs/tables.lua b/spec/outputs/tables.lua
index 1d28a43..e9df1c4 100644
--- a/spec/outputs/tables.lua
+++ b/spec/outputs/tables.lua
@@ -187,18 +187,18 @@ k = {
187 ["hello"] = "world", 187 ["hello"] = "world",
188 ["one"] = "zone" 188 ["one"] = "zone"
189} 189}
190local f = "one", { 190local f1, f2, f3 = "one", {
191 ["two"] = three 191 ["two"] = three
192}, "four" 192}, "four"
193f = { 193f1, f2 = {
194 ["two"] = three 194 ["two"] = three
195}, "four" 195}, "four"
196f = { 196f1 = {
197 "one", 197 "one",
198 ["two"] = three, 198 ["two"] = three,
199 "four" 199 "four"
200} 200}
201local j = "one", { 201local j1, j2, j3, j4 = "one", {
202 ["two"] = three, 202 ["two"] = three,
203 ["four"] = five 203 ["four"] = five
204}, 6, 7 204}, 6, 7
diff --git a/spec/outputs/with.lua b/spec/outputs/with.lua
index 9dcaca3..304d26e 100644
--- a/spec/outputs/with.lua
+++ b/spec/outputs/with.lua
@@ -54,7 +54,7 @@ do
54end 54end
55do 55do
56 do 56 do
57 local _with_0 = a, b 57 local _with_0 = a
58 print(_with_0.world) 58 print(_with_0.world)
59 end 59 end
60 local mod 60 local mod
diff --git a/src/yue.cpp b/src/yue.cpp
index 3e30c70..cb27db8 100644
--- a/src/yue.cpp
+++ b/src/yue.cpp
@@ -21,6 +21,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
21#include <string_view> 21#include <string_view>
22#include <memory> 22#include <memory>
23using namespace std::string_view_literals; 23using namespace std::string_view_literals;
24using namespace std::string_literals;
24#include "ghc/fs_std.hpp" 25#include "ghc/fs_std.hpp"
25#include "linenoise.hpp" 26#include "linenoise.hpp"
26 27
@@ -91,10 +92,10 @@ static const char luaminifyCodes[] =
91 92
92static void pushLuaminify(lua_State* L) { 93static void pushLuaminify(lua_State* L) {
93 if (luaL_loadbuffer(L, luaminifyCodes, sizeof(luaminifyCodes) / sizeof(luaminifyCodes[0]) - 1, "=(luaminify)") != 0) { 94 if (luaL_loadbuffer(L, luaminifyCodes, sizeof(luaminifyCodes) / sizeof(luaminifyCodes[0]) - 1, "=(luaminify)") != 0) {
94 std::string err = std::string("failed to load luaminify module.\n") + lua_tostring(L, -1); 95 std::string err = "failed to load luaminify module.\n"s + lua_tostring(L, -1);
95 luaL_error(L, err.c_str()); 96 luaL_error(L, err.c_str());
96 } else if (lua_pcall(L, 0, 1, 0) != 0) { 97 } else if (lua_pcall(L, 0, 1, 0) != 0) {
97 std::string err = std::string("failed to init luaminify module.\n") + lua_tostring(L, -1); 98 std::string err = "failed to init luaminify module.\n"s + lua_tostring(L, -1);
98 luaL_error(L, err.c_str()); 99 luaL_error(L, err.c_str());
99 } 100 }
100} 101}
@@ -209,7 +210,7 @@ int main(int narg, const char** args) {
209 DEFER(lua_settop(L, top)); 210 DEFER(lua_settop(L, top));
210 pushYue(L, "loadstring"sv); 211 pushYue(L, "loadstring"sv);
211 lua_pushlstring(L, codes.c_str(), codes.size()); 212 lua_pushlstring(L, codes.c_str(), codes.size());
212 lua_pushstring(L, (std::string("=(repl ") + std::to_string(count) + ')').c_str()); 213 lua_pushstring(L, ("=(repl "s + std::to_string(count) + ')').c_str());
213 pushOptions(L, -1); 214 pushOptions(L, -1);
214 const std::string_view Err = "\033[35m"sv, Val = "\033[33m"sv, Stop = "\033[0m\n"sv; 215 const std::string_view Err = "\033[35m"sv, Val = "\033[33m"sv, Stop = "\033[0m\n"sv;
215 if (lua_pcall(L, 3, 2, 0) != 0) { 216 if (lua_pcall(L, 3, 2, 0) != 0) {
@@ -218,7 +219,7 @@ int main(int narg, const char** args) {
218 } 219 }
219 if (lua_isnil(L, -2) != 0) { 220 if (lua_isnil(L, -2) != 0) {
220 std::string err = lua_tostring(L, -1); 221 std::string err = lua_tostring(L, -1);
221 auto modName = std::string("(repl "sv) + std::to_string(count) + "):"; 222 auto modName = "(repl "s + std::to_string(count) + "):"s;
222 if (err.substr(0, modName.size()) == modName) { 223 if (err.substr(0, modName.size()) == modName) {
223 err = err.substr(modName.size()); 224 err = err.substr(modName.size());
224 } 225 }
@@ -409,8 +410,8 @@ int main(int narg, const char** args) {
409 std::cout << help; 410 std::cout << help;
410 return 1; 411 return 1;
411 } 412 }
412 } else if (arg.size() > 1 && arg.substr(0, 1) == "-"sv && arg.substr(1, 1) != "-"sv) { 413 } else if (arg.size() > 2 && arg.substr(0, 2) == "--"sv && arg.substr(2, 1) != "-"sv) {
413 auto argStr = arg.substr(1); 414 auto argStr = arg.substr(2);
414 yue::Utils::trim(argStr); 415 yue::Utils::trim(argStr);
415 size_t idx = argStr.find('='); 416 size_t idx = argStr.find('=');
416 if (idx != std::string::npos) { 417 if (idx != std::string::npos) {
@@ -420,7 +421,7 @@ int main(int narg, const char** args) {
420 yue::Utils::trim(value); 421 yue::Utils::trim(value);
421 config.options[key] = value; 422 config.options[key] = value;
422 } else { 423 } else {
423 config.options[argStr] = ""; 424 config.options[argStr] = std::string();
424 } 425 }
425 } else { 426 } else {
426 if (fs::is_directory(arg)) { 427 if (fs::is_directory(arg)) {
@@ -459,7 +460,13 @@ int main(int narg, const char** args) {
459 auto conf = config; 460 auto conf = config;
460 conf.module = file.first; 461 conf.module = file.first;
461 if (!workPath.empty()) { 462 if (!workPath.empty()) {
462 conf.options["path"] = (fs::path(workPath) / "?.lua").string(); 463 auto it = conf.options.find("path");
464 if (it != conf.options.end()) {
465 it->second += ';';
466 it->second += (fs::path(workPath) / "?.lua"sv).string();
467 } else {
468 conf.options["path"] = (fs::path(workPath) / "?.lua"sv).string();
469 }
463 } 470 }
464 if (dumpCompileTime) { 471 if (dumpCompileTime) {
465 auto start = std::chrono::high_resolution_clock::now(); 472 auto start = std::chrono::high_resolution_clock::now();
@@ -499,7 +506,7 @@ int main(int narg, const char** args) {
499 } else { 506 } else {
500 std::string targetExtension("lua"sv); 507 std::string targetExtension("lua"sv);
501 if (result.options) { 508 if (result.options) {
502 auto it = result.options->find("target_extension"); 509 auto it = result.options->find("target_extension"s);
503 if (it != result.options->end()) { 510 if (it != result.options->end()) {
504 targetExtension = it->second; 511 targetExtension = it->second;
505 } 512 }
@@ -519,19 +526,19 @@ int main(int narg, const char** args) {
519 fs::create_directories(targetFile.parent_path()); 526 fs::create_directories(targetFile.parent_path());
520 } 527 }
521 if (result.codes.empty()) { 528 if (result.codes.empty()) {
522 return std::tuple{0, targetFile.string(), std::string("Built "sv) + file.first + '\n'}; 529 return std::tuple{0, targetFile.string(), "Built "s + file.first + '\n'};
523 } 530 }
524 std::ofstream output(targetFile, std::ios::trunc | std::ios::out); 531 std::ofstream output(targetFile, std::ios::trunc | std::ios::out);
525 if (output) { 532 if (output) {
526 const auto& codes = result.codes; 533 const auto& codes = result.codes;
527 if (config.reserveLineNumber) { 534 if (config.reserveLineNumber) {
528 auto head = std::string("-- [yue]: "sv) + file.first + '\n'; 535 auto head = "-- [yue]: "s + file.first + '\n';
529 output.write(head.c_str(), head.size()); 536 output.write(head.c_str(), head.size());
530 } 537 }
531 output.write(codes.c_str(), codes.size()); 538 output.write(codes.c_str(), codes.size());
532 return std::tuple{0, targetFile.string(), std::string("Built "sv) + file.first + '\n'}; 539 return std::tuple{0, targetFile.string(), "Built "s + file.first + '\n'};
533 } else { 540 } else {
534 return std::tuple{1, std::string(), std::string("Failed to write file: "sv) + targetFile.string() + '\n'}; 541 return std::tuple{1, std::string(), "Failed to write file: "s + targetFile.string() + '\n'};
535 } 542 }
536 } 543 }
537 } else { 544 } else {
@@ -541,7 +548,7 @@ int main(int narg, const char** args) {
541 return std::tuple{1, std::string(), buf.str()}; 548 return std::tuple{1, std::string(), buf.str()};
542 } 549 }
543 } else { 550 } else {
544 return std::tuple{1, std::string(), std::string("Failed to read file: "sv) + file.first + ".\n"}; 551 return std::tuple{1, std::string(), "Failed to read file: "s + file.first + ".\n"};
545 } 552 }
546 }); 553 });
547 results.push_back(std::move(task)); 554 results.push_back(std::move(task));
@@ -588,7 +595,7 @@ int main(int narg, const char** args) {
588 if (lua_pcall(L, 1, 1, 0) != 0) { 595 if (lua_pcall(L, 1, 1, 0) != 0) {
589 ret = 2; 596 ret = 2;
590 std::string err = lua_tostring(L, -1); 597 std::string err = lua_tostring(L, -1);
591 errs.push_back(std::string("Failed to minify: "sv) + file + '\n' + err + '\n'); 598 errs.push_back("Failed to minify: "s + file + '\n' + err + '\n');
592 } else { 599 } else {
593 size_t size = 0; 600 size_t size = 0;
594 const char* minifiedCodes = lua_tolstring(L, -1, &size); 601 const char* minifiedCodes = lua_tolstring(L, -1, &size);
@@ -603,7 +610,7 @@ int main(int narg, const char** args) {
603 } 610 }
604 } else { 611 } else {
605 ret = 2; 612 ret = 2;
606 errs.push_back(std::string("Failed to minify: "sv) + file + '\n'); 613 errs.push_back("Failed to minify: "s + file + '\n');
607 } 614 }
608 } else { 615 } else {
609 std::cout << msg; 616 std::cout << msg;
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h
index 05ac5ef..620dfcc 100755
--- a/src/yuescript/yue_ast.h
+++ b/src/yuescript/yue_ast.h
@@ -118,16 +118,22 @@ AST_NODE(Local)
118 AST_MEMBER(Local, &item) 118 AST_MEMBER(Local, &item)
119AST_END(Local, "local"sv) 119AST_END(Local, "local"sv)
120 120
121class Assign_t; 121AST_LEAF(const_attrib)
122AST_END(const_attrib, "const"sv)
123
124AST_LEAF(close_attrib)
125AST_END(close_attrib, "close"sv)
122 126
123AST_LEAF(Attrib) 127class simple_table_t;
124AST_END(Attrib, "attrib"sv) 128class TableLit_t;
129class Assign_t;
125 130
126AST_NODE(LocalAttrib) 131AST_NODE(LocalAttrib)
127 ast_ptr<true, Attrib_t> attrib; 132 ast_sel<true, const_attrib_t, close_attrib_t> attrib;
128 ast_ptr<true, NameList_t> nameList; 133 ast_ptr<true, Seperator_t> sep;
134 ast_sel_list<true, Variable_t, simple_table_t, TableLit_t> leftList;
129 ast_ptr<true, Assign_t> assign; 135 ast_ptr<true, Assign_t> assign;
130 AST_MEMBER(LocalAttrib, &attrib, &nameList, &assign) 136 AST_MEMBER(LocalAttrib, &attrib, &sep, &leftList, &assign)
131AST_END(LocalAttrib, "local_attrib"sv) 137AST_END(LocalAttrib, "local_attrib"sv)
132 138
133AST_NODE(colon_import_name) 139AST_NODE(colon_import_name)
@@ -135,9 +141,6 @@ AST_NODE(colon_import_name)
135 AST_MEMBER(colon_import_name, &name) 141 AST_MEMBER(colon_import_name, &name)
136AST_END(colon_import_name, "colon_import_name"sv) 142AST_END(colon_import_name, "colon_import_name"sv)
137 143
138class Exp_t;
139class TableLit_t;
140
141AST_LEAF(import_literal_inner) 144AST_LEAF(import_literal_inner)
142AST_END(import_literal_inner, "import_literal_inner"sv) 145AST_END(import_literal_inner, "import_literal_inner"sv)
143 146
@@ -147,6 +150,8 @@ AST_NODE(ImportLiteral)
147 AST_MEMBER(ImportLiteral, &sep, &inners) 150 AST_MEMBER(ImportLiteral, &sep, &inners)
148AST_END(ImportLiteral, "import_literal"sv) 151AST_END(ImportLiteral, "import_literal"sv)
149 152
153class Exp_t;
154
150AST_NODE(ImportFrom) 155AST_NODE(ImportFrom)
151 ast_ptr<true, Seperator_t> sep; 156 ast_ptr<true, Seperator_t> sep;
152 ast_sel_list<true, colon_import_name_t, Variable_t> names; 157 ast_sel_list<true, colon_import_name_t, Variable_t> names;
@@ -499,7 +504,6 @@ class String_t;
499class const_value_t; 504class const_value_t;
500class ClassDecl_t; 505class ClassDecl_t;
501class unary_value_t; 506class unary_value_t;
502class TableLit_t;
503class FunLit_t; 507class FunLit_t;
504 508
505AST_NODE(SimpleValue) 509AST_NODE(SimpleValue)
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp
index 7bbf5e9..0d027a0 100755
--- a/src/yuescript/yue_compiler.cpp
+++ b/src/yuescript/yue_compiler.cpp
@@ -13,6 +13,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
13#include <vector> 13#include <vector>
14#include <memory> 14#include <memory>
15#include <set> 15#include <set>
16#include <optional>
16 17
17#include "yuescript/yue_parser.h" 18#include "yuescript/yue_parser.h"
18#include "yuescript/yue_compiler.h" 19#include "yuescript/yue_compiler.h"
@@ -37,9 +38,6 @@ extern "C" {
37#endif // YUE_NO_MACRO 38#endif // YUE_NO_MACRO
38 39
39namespace yue { 40namespace yue {
40using namespace std::string_view_literals;
41using namespace std::string_literals;
42using namespace parserlib;
43 41
44#define BLOCK_START do { 42#define BLOCK_START do {
45#define BLOCK_END } while (false); 43#define BLOCK_END } while (false);
@@ -56,7 +54,7 @@ using namespace parserlib;
56 54
57typedef std::list<std::string> str_list; 55typedef std::list<std::string> str_list;
58 56
59const std::string_view version = "0.13.6"sv; 57const std::string_view version = "0.14.0"sv;
60const std::string_view extension = "yue"sv; 58const std::string_view extension = "yue"sv;
61 59
62class YueCompilerImpl { 60class YueCompilerImpl {
@@ -1266,8 +1264,8 @@ private:
1266 1264
1267 std::string getDestrucureDefine(ExpListAssign_t* assignment) { 1265 std::string getDestrucureDefine(ExpListAssign_t* assignment) {
1268 auto info = extractDestructureInfo(assignment, true, false); 1266 auto info = extractDestructureInfo(assignment, true, false);
1269 if (!info.first.empty()) { 1267 if (!info.destructures.empty()) {
1270 for (const auto& destruct : info.first) { 1268 for (const auto& destruct : info.destructures) {
1271 str_list defs; 1269 str_list defs;
1272 for (const auto& item : destruct.items) { 1270 for (const auto& item : destruct.items) {
1273 if (!item.targetVar.empty()) { 1271 if (!item.targetVar.empty()) {
@@ -1319,11 +1317,30 @@ private:
1319 return assignment; 1317 return assignment;
1320 } 1318 }
1321 1319
1320 void markDestructureConst(ExpListAssign_t* assignment) {
1321 auto info = extractDestructureInfo(assignment, true, false);
1322 for (auto& destruct : info.destructures) {
1323 for (auto& item : destruct.items) {
1324 if (item.targetVar.empty()) {
1325 throw std::logic_error(_info.errorMessage("can only declare variable as const"sv, item.target));
1326 }
1327 markVarConst(item.targetVar);
1328 }
1329 }
1330 }
1331
1322 void transformAssignment(ExpListAssign_t* assignment, str_list& out, bool optionalDestruct = false) { 1332 void transformAssignment(ExpListAssign_t* assignment, str_list& out, bool optionalDestruct = false) {
1323 checkAssignable(assignment->expList); 1333 checkAssignable(assignment->expList);
1324 BLOCK_START 1334 BLOCK_START
1325 auto assign = ast_cast<Assign_t>(assignment->action); 1335 auto assign = ast_cast<Assign_t>(assignment->action);
1326 BREAK_IF(!assign); 1336 BREAK_IF(!assign);
1337 if (assignment->expList->exprs.size() < assign->values.size()) {
1338 auto num = assignment->expList->exprs.size();
1339 _buf << "no more than "sv << num << " right value"sv;
1340 if (num > 1) _buf << 's';
1341 _buf << " required"sv;
1342 throw std::logic_error(_info.errorMessage(clearBuf(), assign->values.front()));
1343 }
1327 auto x = assignment; 1344 auto x = assignment;
1328 const auto& exprs = assignment->expList->exprs.objects(); 1345 const auto& exprs = assignment->expList->exprs.objects();
1329 const auto& values = assign->values.objects(); 1346 const auto& values = assign->values.objects();
@@ -1554,15 +1571,15 @@ private:
1554 } 1571 }
1555 BLOCK_END 1572 BLOCK_END
1556 auto info = extractDestructureInfo(assignment, false, optionalDestruct); 1573 auto info = extractDestructureInfo(assignment, false, optionalDestruct);
1557 if (info.first.empty()) { 1574 if (info.destructures.empty()) {
1558 transformAssignmentCommon(assignment, out); 1575 transformAssignmentCommon(assignment, out);
1559 } else { 1576 } else {
1560 str_list temp; 1577 str_list temp;
1561 if (info.second) { 1578 if (info.assignment) {
1562 transformAssignmentCommon(info.second, temp); 1579 transformAssignmentCommon(info.assignment, temp);
1563 } 1580 }
1564 auto x = assignment; 1581 auto x = assignment;
1565 for (auto& destruct : info.first) { 1582 for (auto& destruct : info.destructures) {
1566 std::list<std::pair<ast_ptr<true, Exp_t>, ast_ptr<true, Exp_t>>> leftPairs; 1583 std::list<std::pair<ast_ptr<true, Exp_t>, ast_ptr<true, Exp_t>>> leftPairs;
1567 bool extraScope = false; 1584 bool extraScope = false;
1568 if (destruct.items.size() == 1) { 1585 if (destruct.items.size() == 1) {
@@ -2030,24 +2047,22 @@ private:
2030 return pairs; 2047 return pairs;
2031 } 2048 }
2032 2049
2033 std::pair<std::list<Destructure>, ast_ptr<false, ExpListAssign_t>> 2050 struct DestructureInfo {
2034 extractDestructureInfo(ExpListAssign_t* assignment, bool varDefOnly, bool optional) { 2051 std::list<Destructure> destructures;
2052 ast_ptr<false, ExpListAssign_t> assignment;
2053 };
2054
2055 DestructureInfo extractDestructureInfo(ExpListAssign_t* assignment, bool varDefOnly, bool optional) {
2035 auto x = assignment; 2056 auto x = assignment;
2036 std::list<Destructure> destructs; 2057 std::list<Destructure> destructs;
2037 if (!assignment->action.is<Assign_t>()) return {destructs, nullptr}; 2058 if (!assignment->action.is<Assign_t>()) return {destructs, nullptr};
2038 auto exprs = assignment->expList->exprs.objects(); 2059 auto exprs = assignment->expList->exprs.objects();
2039 auto values = assignment->action.to<Assign_t>()->values.objects(); 2060 auto values = assignment->action.to<Assign_t>()->values.objects();
2040 size_t size = std::max(exprs.size(), values.size()); 2061 size_t size = std::max(exprs.size(), values.size());
2041 ast_list<false, ast_node> cache; 2062 ast_ptr<false, Exp_t> nil;
2042 if (exprs.size() < size) {
2043 auto var = toAst<Exp_t>("_"sv, x);
2044 cache.push_back(var);
2045 while (exprs.size() < size) exprs.emplace_back(var);
2046 }
2047 ast_ptr<false, Exp_t> nullNode;
2048 if (values.size() < size) { 2063 if (values.size() < size) {
2049 nullNode = toAst<Exp_t>("nil"sv, x); 2064 nil = toAst<Exp_t>("nil"sv, x);
2050 while (values.size() < size) values.emplace_back(nullNode); 2065 while (values.size() < size) values.emplace_back(nil);
2051 } 2066 }
2052 using iter = node_container::iterator; 2067 using iter = node_container::iterator;
2053 std::vector<std::pair<iter, iter>> destructPairs; 2068 std::vector<std::pair<iter, iter>> destructPairs;
@@ -2059,11 +2074,11 @@ private:
2059 auto value = singleValueFrom(expr); 2074 auto value = singleValueFrom(expr);
2060 ast_node* destructNode = value->getByPath<SimpleValue_t, TableLit_t>(); 2075 ast_node* destructNode = value->getByPath<SimpleValue_t, TableLit_t>();
2061 if (destructNode || (destructNode = value->item.as<simple_table_t>())) { 2076 if (destructNode || (destructNode = value->item.as<simple_table_t>())) {
2062 if (*j != nullNode) { 2077 if (*j != nil) {
2063 if (auto ssVal = simpleSingleValueFrom(*j)) { 2078 if (auto ssVal = simpleSingleValueFrom(*j)) {
2064 switch (ssVal->value->getId()) { 2079 switch (ssVal->value->getId()) {
2065 case id<const_value_t>(): 2080 case id<const_value_t>():
2066 throw std::logic_error(_info.errorMessage("can not destructure a const value"sv, ssVal->value)); 2081 throw std::logic_error(_info.errorMessage("can not destructure a constant"sv, ssVal->value));
2067 break; 2082 break;
2068 case id<Num_t>(): 2083 case id<Num_t>():
2069 throw std::logic_error(_info.errorMessage("can not destructure a number"sv, ssVal->value)); 2084 throw std::logic_error(_info.errorMessage("can not destructure a number"sv, ssVal->value));
@@ -2074,7 +2089,7 @@ private:
2074 } 2089 }
2075 } 2090 }
2076 } else { 2091 } else {
2077 throw std::logic_error(_info.errorMessage("can not destructure a nil value"sv, destructNode)); 2092 throw std::logic_error(_info.errorMessage("an explicit destructure target required"sv, destructNode));
2078 } 2093 }
2079 destructPairs.push_back({i, j}); 2094 destructPairs.push_back({i, j});
2080 auto subDestruct = destructNode->new_ptr<TableLit_t>(); 2095 auto subDestruct = destructNode->new_ptr<TableLit_t>();
@@ -2173,7 +2188,7 @@ private:
2173 } 2188 }
2174 destruct.items = std::move(pairs); 2189 destruct.items = std::move(pairs);
2175 if (!varDefOnly) { 2190 if (!varDefOnly) {
2176 if (*j == nullNode) { 2191 if (*j == nil) {
2177 for (auto& item : destruct.items) { 2192 for (auto& item : destruct.items) {
2178 item.structure.clear(); 2193 item.structure.clear();
2179 } 2194 }
@@ -3104,8 +3119,8 @@ private:
3104 } 3119 }
3105 } 3120 }
3106 auto info = extractDestructureInfo(assignment, true, false); 3121 auto info = extractDestructureInfo(assignment, true, false);
3107 if (!info.first.empty()) { 3122 if (!info.destructures.empty()) {
3108 for (const auto& destruct : info.first) 3123 for (const auto& destruct : info.destructures)
3109 for (const auto& item : destruct.items) 3124 for (const auto& item : destruct.items)
3110 if (!item.targetVar.empty()) { 3125 if (!item.targetVar.empty()) {
3111 if (std::isupper(item.targetVar[0]) && capital) { capital->decls.push_back(item.targetVar); 3126 if (std::isupper(item.targetVar[0]) && capital) { capital->decls.push_back(item.targetVar);
@@ -3114,8 +3129,8 @@ private:
3114 } 3129 }
3115 } 3130 }
3116 } 3131 }
3117 if (info.second) { 3132 if (info.assignment) {
3118 auto defs = transformAssignDefs(info.second->expList, DefOp::Get); 3133 auto defs = transformAssignDefs(info.assignment->expList, DefOp::Get);
3119 for (const auto& def : defs) { 3134 for (const auto& def : defs) {
3120 if (std::isupper(def[0]) && capital) { capital->decls.push_back(def); 3135 if (std::isupper(def[0]) && capital) { capital->decls.push_back(def);
3121 } else if (any) { 3136 } else if (any) {
@@ -3236,6 +3251,49 @@ private:
3236 } 3251 }
3237 } 3252 }
3238 3253
3254 std::optional<std::string> getOption(std::string_view key) {
3255#ifndef YUE_NO_MACRO
3256 if (L) {
3257 int top = lua_gettop(L);
3258 DEFER(lua_settop(L, top));
3259 pushYue("options"sv); // options
3260 lua_pushlstring(L, &key.front(), key.size());
3261 lua_gettable(L, -2);
3262 if (lua_isstring(L, -1) != 0) {
3263 size_t size = 0;
3264 const char* str = lua_tolstring(L, -1, &size);
3265 return std::string(str, size);
3266 }
3267 }
3268#endif // YUE_NO_MACRO
3269 auto it = _config.options.find(std::string(key));
3270 if (it != _config.options.end()) {
3271 return it->second;
3272 }
3273 return std::nullopt;
3274 }
3275
3276 int getLuaTarget(ast_node* x) {
3277 if (auto target = getOption("target")) {
3278 if (target.value() == "5.1"sv) {
3279 return 501;
3280 } else if (target.value() == "5.2"sv) {
3281 return 502;
3282 } else if (target.value() == "5.3"sv) {
3283 return 503;
3284 } else if (target.value() == "5.4"sv) {
3285 return 504;
3286 } else {
3287 throw std::logic_error(_info.errorMessage("get invalid Lua target \""s + target.value() + "\", should be 5.1, 5.2, 5.3 or 5.4"s, x));
3288 }
3289 }
3290#ifndef YUE_NO_MACRO
3291 return LUA_VERSION_NUM;
3292#else
3293 return 504;
3294#endif // YUE_NO_MACRO
3295 }
3296
3239#ifndef YUE_NO_MACRO 3297#ifndef YUE_NO_MACRO
3240 void passOptions() { 3298 void passOptions() {
3241 if (!_config.options.empty()) { 3299 if (!_config.options.empty()) {
@@ -5898,8 +5956,8 @@ private:
5898 auto names = transformAssignDefs(assignment->expList.get(), DefOp::Mark); 5956 auto names = transformAssignDefs(assignment->expList.get(), DefOp::Mark);
5899 varDefs.insert(varDefs.end(), names.begin(), names.end()); 5957 varDefs.insert(varDefs.end(), names.begin(), names.end());
5900 auto info = extractDestructureInfo(assignment, true, false); 5958 auto info = extractDestructureInfo(assignment, true, false);
5901 if (!info.first.empty()) { 5959 if (!info.destructures.empty()) {
5902 for (const auto& destruct : info.first) 5960 for (const auto& destruct : info.destructures)
5903 for (const auto& item : destruct.items) 5961 for (const auto& item : destruct.items)
5904 if (!item.targetVar.empty() && addToScope(item.targetVar)) 5962 if (!item.targetVar.empty() && addToScope(item.targetVar))
5905 varDefs.push_back(item.targetVar); 5963 varDefs.push_back(item.targetVar);
@@ -6329,8 +6387,8 @@ private:
6329 return traversal::Stop; 6387 return traversal::Stop;
6330 } 6388 }
6331 auto info = extractDestructureInfo(assignment, true, false); 6389 auto info = extractDestructureInfo(assignment, true, false);
6332 if (!info.first.empty()) { 6390 if (!info.destructures.empty()) {
6333 for (const auto& destruct : info.first) 6391 for (const auto& destruct : info.destructures)
6334 for (const auto& item : destruct.items) 6392 for (const auto& item : destruct.items)
6335 if (!item.targetVar.empty() && !isDefined(item.targetVar)) 6393 if (!item.targetVar.empty() && !isDefined(item.targetVar))
6336 return traversal::Stop; 6394 return traversal::Stop;
@@ -6481,8 +6539,8 @@ private:
6481 transformAssignment(assignment, out); 6539 transformAssignment(assignment, out);
6482 str_list names = transformAssignDefs(expList, DefOp::Get); 6540 str_list names = transformAssignDefs(expList, DefOp::Get);
6483 auto info = extractDestructureInfo(assignment, true, false); 6541 auto info = extractDestructureInfo(assignment, true, false);
6484 if (!info.first.empty()) { 6542 if (!info.destructures.empty()) {
6485 for (const auto& destruct : info.first) 6543 for (const auto& destruct : info.destructures)
6486 for (const auto& item : destruct.items) 6544 for (const auto& item : destruct.items)
6487 if (!item.targetVar.empty()) 6545 if (!item.targetVar.empty())
6488 names.push_back(item.targetVar); 6546 names.push_back(item.targetVar);
@@ -6848,6 +6906,7 @@ private:
6848 temp.push_back(indent() + "end"s + nlr(import)); 6906 temp.push_back(indent() + "end"s + nlr(import));
6849 } 6907 }
6850 out.push_back(join(temp)); 6908 out.push_back(join(temp));
6909 markDestructureConst(assignment);
6851 } 6910 }
6852 6911
6853 std::string moduleNameFrom(ImportLiteral_t* literal) { 6912 std::string moduleNameFrom(ImportLiteral_t* literal) {
@@ -7013,6 +7072,12 @@ private:
7013 assignment->expList.set(assignList); 7072 assignment->expList.set(assignList);
7014 assignment->action.set(assign); 7073 assignment->action.set(assign);
7015 transformAssignment(assignment, out); 7074 transformAssignment(assignment, out);
7075 if (auto var = ast_cast<Variable_t>(target)) {
7076 auto moduleName = _parser.toString(var);
7077 markVarConst(moduleName);
7078 } else {
7079 markDestructureConst(assignment);
7080 }
7016 } 7081 }
7017 7082
7018 void transformImport(Import_t* import, str_list& out) { 7083 void transformImport(Import_t* import, str_list& out) {
@@ -7191,7 +7256,7 @@ private:
7191 auto info = extractDestructureInfo(assignment, true, false); 7256 auto info = extractDestructureInfo(assignment, true, false);
7192 transformAssignment(assignment, temp, true); 7257 transformAssignment(assignment, temp, true);
7193 str_list conds; 7258 str_list conds;
7194 for (const auto& destruct : info.first) { 7259 for (const auto& destruct : info.destructures) {
7195 for (const auto& item : destruct.items) { 7260 for (const auto& item : destruct.items) {
7196 if (!item.defVal) { 7261 if (!item.defVal) {
7197 transformExp(item.target, conds, ExpUsage::Closure); 7262 transformExp(item.target, conds, ExpUsage::Closure);
@@ -7334,23 +7399,84 @@ private:
7334 7399
7335 void transformLocalAttrib(LocalAttrib_t* localAttrib, str_list& out) { 7400 void transformLocalAttrib(LocalAttrib_t* localAttrib, str_list& out) {
7336 auto x = localAttrib; 7401 auto x = localAttrib;
7337 auto attrib = _parser.toString(localAttrib->attrib); 7402 if (x->leftList.size() < x->assign->values.size()) {
7338 str_list vars; 7403 throw std::logic_error(_info.errorMessage("number of right values should not be greater than left values"sv, x->assign->values.front()));
7339 for (auto name : localAttrib->nameList->names.objects()) { 7404 }
7340 auto var = _parser.toString(name); 7405 auto listA = x->new_ptr<NameList_t>();
7341 forceAddToScope(var); 7406 auto assignA = x->new_ptr<Assign_t>();
7342 vars.push_back(var); 7407 auto listB = x->new_ptr<ExpList_t>();
7408 auto assignB = x->new_ptr<Assign_t>();
7409 auto i = x->leftList.objects().begin();
7410 auto ie = x->leftList.objects().end();
7411 auto j = x->assign->values.objects().begin();
7412 auto je = x->assign->values.objects().end();
7413 while (i != ie) {
7414 if (ast_is<Variable_t>(*i)) {
7415 listA->names.push_back(*i);
7416 if (j != je) assignA->values.push_back(*j);
7417 } else {
7418 auto item = *i;
7419 auto value = item->new_ptr<Value_t>();
7420 switch (item->getId()) {
7421 case id<simple_table_t>():
7422 value->item.set(item);
7423 break;
7424 case id<TableLit_t>(): {
7425 auto simpleValue = item->new_ptr<SimpleValue_t>();
7426 simpleValue->value.set(item);
7427 value->item.set(simpleValue);
7428 break;
7429 }
7430 default: YUEE("AST node mismatch", item); break;
7431 }
7432 auto exp = newExp(value, item);
7433 listB->exprs.push_back(exp);
7434 if (j != je) assignB->values.push_back(*j);
7435 }
7436 ++i;
7437 if (j != je) ++j;
7343 } 7438 }
7344 attrib = " <"s + attrib + '>'; 7439 if (!listA->names.empty()) {
7345 for (auto& var : vars) { 7440 str_list vars;
7346 markVarConst(var); 7441 for (auto name : listA->names.objects()) {
7347 var.append(attrib); 7442 auto var = _parser.toString(name);
7443 forceAddToScope(var);
7444 vars.push_back(var);
7445 }
7446 if (getLuaTarget(x) >= 504) {
7447 std::string attrib;
7448 if (localAttrib->attrib.is<const_attrib_t>()) {
7449 attrib = " <const>"s;
7450 } else if (localAttrib->attrib.is<close_attrib_t>()) {
7451 attrib = " <close>"s;
7452 } else {
7453 YUEE("AST node mismatch", localAttrib->attrib);
7454 }
7455 for (auto& var : vars) {
7456 markVarConst(var);
7457 var.append(attrib);
7458 }
7459 } else {
7460 if (localAttrib->attrib.is<close_attrib_t>()) {
7461 throw std::logic_error(_info.errorMessage("close attribute is not available when not targeting Lua 5.4 or higher version"sv, x));
7462 }
7463 for (auto& var : vars) {
7464 markVarConst(var);
7465 }
7466 }
7467 str_list temp;
7468 for (auto item : assignA->values.objects()) {
7469 transformAssignItem(item, temp);
7470 }
7471 out.push_back(indent() + "local "s + join(vars, ", "sv) + " = "s + join(temp, ", "sv) + nll(x));
7348 } 7472 }
7349 str_list temp; 7473 if (!listB->exprs.empty()) {
7350 for (auto item : localAttrib->assign->values.objects()) { 7474 auto assignment = x->new_ptr<ExpListAssign_t>();
7351 transformAssignItem(item, temp); 7475 assignment->expList.set(listB);
7476 assignment->action.set(assignB);
7477 transformAssignment(assignment, out);
7478 markDestructureConst(assignment);
7352 } 7479 }
7353 out.push_back(indent() + "local "s + join(vars, ", "sv) + " = "s + join(temp, ", "sv) + nll(x));
7354 } 7480 }
7355 7481
7356 void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) { 7482 void transformBreakLoop(BreakLoop_t* breakLoop, str_list& out) {
@@ -7372,10 +7498,16 @@ private:
7372 } 7498 }
7373 7499
7374 void transformLabel(Label_t* label, str_list& out) { 7500 void transformLabel(Label_t* label, str_list& out) {
7501 if (getLuaTarget(label) < 502) {
7502 throw std::logic_error(_info.errorMessage("label statement is not available when not targeting Lua 5.2 or higher version"sv, label));
7503 }
7375 out.push_back(indent() + "::"s + _parser.toString(label->label) + "::"s + nll(label)); 7504 out.push_back(indent() + "::"s + _parser.toString(label->label) + "::"s + nll(label));
7376 } 7505 }
7377 7506
7378 void transformGoto(Goto_t* gotoNode, str_list& out) { 7507 void transformGoto(Goto_t* gotoNode, str_list& out) {
7508 if (getLuaTarget(gotoNode) < 502) {
7509 throw std::logic_error(_info.errorMessage("goto statement is not available when not targeting Lua 5.2 or higher version"sv, gotoNode));
7510 }
7379 out.push_back(indent() + "goto "s + _parser.toString(gotoNode->label) + nll(gotoNode)); 7511 out.push_back(indent() + "goto "s + _parser.toString(gotoNode->label) + nll(gotoNode));
7380 } 7512 }
7381 7513
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp
index 66043d3..94ce550 100755
--- a/src/yuescript/yue_parser.cpp
+++ b/src/yuescript/yue_parser.cpp
@@ -11,25 +11,24 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
11namespace pl = parserlib; 11namespace pl = parserlib;
12 12
13namespace yue { 13namespace yue {
14using namespace std::string_view_literals;
15 14
16std::unordered_set<std::string> LuaKeywords = { 15std::unordered_set<std::string> LuaKeywords = {
17 "and", "break", "do", "else", "elseif", 16 "and"s, "break"s, "do"s, "else"s, "elseif"s,
18 "end", "false", "for", "function", "goto", 17 "end"s, "false"s, "for"s, "function"s, "goto"s,
19 "if", "in", "local", "nil", "not", 18 "if"s, "in"s, "local"s, "nil"s, "not"s,
20 "or", "repeat", "return", "then", "true", 19 "or"s, "repeat"s, "return"s, "then"s, "true"s,
21 "until", "while" 20 "until"s, "while"s
22}; 21};
23 22
24std::unordered_set<std::string> Keywords = { 23std::unordered_set<std::string> Keywords = {
25 "and", "break", "do", "else", "elseif", 24 "and"s, "break"s, "do"s, "else"s, "elseif"s,
26 "end", "false", "for", "function", "goto", 25 "end"s, "false"s, "for"s, "function"s, "goto"s,
27 "if", "in", "local", "nil", "not", 26 "if"s, "in"s, "local"s, "nil"s, "not"s,
28 "or", "repeat", "return", "then", "true", 27 "or"s, "repeat"s, "return"s, "then"s, "true"s,
29 "until", "while", // Lua keywords 28 "until"s, "while"s, // Lua keywords
30 "as", "class", "continue", "export", "extends", 29 "as"s, "class"s, "continue"s, "export"s, "extends"s,
31 "from", "global", "import", "macro", "switch", 30 "from"s, "global"s, "import"s, "macro"s, "switch"s,
32 "try", "unless", "using", "when", "with" // Yue keywords 31 "try"s, "unless"s, "using"s, "when"s, "with"s // Yue keywords
33}; 32};
34 33
35YueParser::YueParser() { 34YueParser::YueParser() {
@@ -86,7 +85,7 @@ YueParser::YueParser() {
86 if (isValid) { 85 if (isValid) {
87 if (st->buffer == st->moduleName) { 86 if (st->buffer == st->moduleName) {
88 st->moduleFix++; 87 st->moduleFix++;
89 st->moduleName = std::string("_module_"sv) + std::to_string(st->moduleFix); 88 st->moduleName = "_module_"s + std::to_string(st->moduleFix);
90 } 89 }
91 } 90 }
92 st->buffer.clear(); 91 st->buffer.clear();
@@ -179,10 +178,15 @@ YueParser::YueParser() {
179 178
180 local_flag = expr('*') | expr('^'); 179 local_flag = expr('*') | expr('^');
181 local_values = NameList >> -(sym('=') >> (TableBlock | ExpListLow)); 180 local_values = NameList >> -(sym('=') >> (TableBlock | ExpListLow));
182 Attrib = (expr("const") | expr("close")) >> not_(AlphaNum);
183 Local = key("local") >> (Space >> local_flag | local_values); 181 Local = key("local") >> (Space >> local_flag | local_values);
184 182
185 LocalAttrib = Attrib >> NameList >> Assign; 183 const_attrib = key("const");
184 close_attrib = key("close");
185 local_const_item = (Space >> Variable | simple_table | TableLit);
186 LocalAttrib = (
187 const_attrib >> Seperator >> local_const_item >> *(sym(',') >> local_const_item) |
188 close_attrib >> Seperator >> Space >> Variable >> *(sym(',') >> Space >> Variable)
189 ) >> Assign;
186 190
187 colon_import_name = sym('\\') >> Space >> Variable; 191 colon_import_name = sym('\\') >> Space >> Variable;
188 ImportName = colon_import_name | Space >> Variable; 192 ImportName = colon_import_name | Space >> Variable;
@@ -754,6 +758,10 @@ std::string ParseInfo::errorMessage(std::string_view msg, const input_range* loc
754 ++it; 758 ++it;
755 } 759 }
756 auto line = Converter{}.to_bytes(std::wstring(begin, end)); 760 auto line = Converter{}.to_bytes(std::wstring(begin, end));
761 while (col < static_cast<int>(line.size())
762 && (line[col] == ' ' || line[col] == '\t')) {
763 col++;
764 }
757 Utils::replace(line, "\t"sv, " "sv); 765 Utils::replace(line, "\t"sv, " "sv);
758 std::ostringstream buf; 766 std::ostringstream buf;
759 buf << loc->m_begin.m_line << ": "sv << msg << 767 buf << loc->m_begin.m_line << ": "sv << msg <<
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h
index b71a67c..b363ad7 100755
--- a/src/yuescript/yue_parser.h
+++ b/src/yuescript/yue_parser.h
@@ -21,6 +21,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
21#include "yuescript/yue_ast.h" 21#include "yuescript/yue_ast.h"
22 22
23namespace yue { 23namespace yue {
24using namespace std::string_view_literals;
25using namespace std::string_literals;
24using namespace parserlib; 26using namespace parserlib;
25 27
26struct ParseInfo { 28struct ParseInfo {
@@ -77,7 +79,7 @@ protected:
77 int exportCount = 0; 79 int exportCount = 0;
78 int moduleFix = 0; 80 int moduleFix = 0;
79 size_t stringOpen = 0; 81 size_t stringOpen = 0;
80 std::string moduleName = "_module_0"; 82 std::string moduleName = "_module_0"s;
81 std::string buffer; 83 std::string buffer;
82 std::stack<int> indents; 84 std::stack<int> indents;
83 std::stack<bool> noDoStack; 85 std::stack<bool> noDoStack;
@@ -189,6 +191,7 @@ private:
189 rule expo_value; 191 rule expo_value;
190 rule expo_exp; 192 rule expo_exp;
191 rule exp_not_tab; 193 rule exp_not_tab;
194 rule local_const_item;
192 rule empty_line_stop; 195 rule empty_line_stop;
193 rule Line; 196 rule Line;
194 rule Shebang; 197 rule Shebang;
@@ -209,8 +212,9 @@ private:
209 AST_RULE(NameList) 212 AST_RULE(NameList)
210 AST_RULE(local_flag) 213 AST_RULE(local_flag)
211 AST_RULE(local_values) 214 AST_RULE(local_values)
212 AST_RULE(Attrib)
213 AST_RULE(Local) 215 AST_RULE(Local)
216 AST_RULE(const_attrib)
217 AST_RULE(close_attrib)
214 AST_RULE(LocalAttrib); 218 AST_RULE(LocalAttrib);
215 AST_RULE(colon_import_name) 219 AST_RULE(colon_import_name)
216 AST_RULE(import_literal_inner) 220 AST_RULE(import_literal_inner)
diff --git a/src/yuescript/yuescript.cpp b/src/yuescript/yuescript.cpp
index 2e96f16..98e214f 100644
--- a/src/yuescript/yuescript.cpp
+++ b/src/yuescript/yuescript.cpp
@@ -9,6 +9,8 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI
9#include "yuescript/yue_compiler.h" 9#include "yuescript/yue_compiler.h"
10#include "yuescript/yue_parser.h" 10#include "yuescript/yue_parser.h"
11 11
12using namespace std::string_literals;
13
12#if defined(YUE_BUILD_AS_DLL) 14#if defined(YUE_BUILD_AS_DLL)
13#define YUE_API __declspec(dllexport) 15#define YUE_API __declspec(dllexport)
14#else 16#else
@@ -25,12 +27,12 @@ static const char yuescriptCodes[] =
25 27
26static void init_yuescript(lua_State* L) { 28static void init_yuescript(lua_State* L) {
27 if (luaL_loadbuffer(L, yuescriptCodes, sizeof(yuescriptCodes) / sizeof(yuescriptCodes[0]) - 1, "=(yuescript)") != 0) { 29 if (luaL_loadbuffer(L, yuescriptCodes, sizeof(yuescriptCodes) / sizeof(yuescriptCodes[0]) - 1, "=(yuescript)") != 0) {
28 std::string err = std::string("failed to load yuescript module.\n") + lua_tostring(L, -1); 30 std::string err = "failed to load yuescript module.\n"s + lua_tostring(L, -1);
29 luaL_error(L, err.c_str()); 31 luaL_error(L, err.c_str());
30 } else { 32 } else {
31 lua_insert(L, -2); 33 lua_insert(L, -2);
32 if (lua_pcall(L, 1, 0, 0) != 0) { 34 if (lua_pcall(L, 1, 0, 0) != 0) {
33 std::string err = std::string("failed to init yuescript module.\n") + lua_tostring(L, -1); 35 std::string err = "failed to init yuescript module.\n"s + lua_tostring(L, -1);
34 luaL_error(L, err.c_str()); 36 luaL_error(L, err.c_str());
35 } 37 }
36 } 38 }
@@ -41,10 +43,10 @@ static const char stpCodes[] =
41 43
42static int init_stacktraceplus(lua_State* L) { 44static int init_stacktraceplus(lua_State* L) {
43 if (luaL_loadbuffer(L, stpCodes, sizeof(stpCodes) / sizeof(stpCodes[0]) - 1, "=(stacktraceplus)") != 0) { 45 if (luaL_loadbuffer(L, stpCodes, sizeof(stpCodes) / sizeof(stpCodes[0]) - 1, "=(stacktraceplus)") != 0) {
44 std::string err = std::string("failed to load stacktraceplus module.\n") + lua_tostring(L, -1); 46 std::string err = "failed to load stacktraceplus module.\n"s + lua_tostring(L, -1);
45 luaL_error(L, err.c_str()); 47 luaL_error(L, err.c_str());
46 } else if (lua_pcall(L, 0, 1, 0) != 0) { 48 } else if (lua_pcall(L, 0, 1, 0) != 0) {
47 std::string err = std::string("failed to init stacktraceplus module.\n") + lua_tostring(L, -1); 49 std::string err = "failed to init stacktraceplus module.\n"s + lua_tostring(L, -1);
48 luaL_error(L, err.c_str()); 50 luaL_error(L, err.c_str());
49 } 51 }
50 return 1; 52 return 1;