diff options
-rw-r--r-- | spec/inputs/macro.yue | 15 | ||||
-rw-r--r-- | spec/outputs/macro.lua | 15 | ||||
-rw-r--r-- | src/yuescript/yue_compiler.cpp | 162 |
3 files changed, 137 insertions, 55 deletions
diff --git a/spec/inputs/macro.yue b/spec/inputs/macro.yue index d5197da..5dafd84 100644 --- a/spec/inputs/macro.yue +++ b/spec/inputs/macro.yue | |||
@@ -5,6 +5,21 @@ import "macro_export" as { | |||
5 | 5 | ||
6 | import "macro_todo" as $ | 6 | import "macro_todo" as $ |
7 | 7 | ||
8 | macro not_leak = -> "leak" | ||
9 | do | ||
10 | macro x = -> 123 | ||
11 | print $x | ||
12 | do | ||
13 | macro x = -> math.pi * 2 | ||
14 | print $x | ||
15 | macro x = -> 456 | ||
16 | print $x | ||
17 | |||
18 | import "macro_todo" as $todo: $not_leak | ||
19 | $not_leak "todo in a do block" | ||
20 | |||
21 | $not_leak!! | ||
22 | |||
8 | macro WindowFlag = $enum( | 23 | macro WindowFlag = $enum( |
9 | NoNav | 24 | NoNav |
10 | NoDecoration | 25 | NoDecoration |
diff --git a/spec/outputs/macro.lua b/spec/outputs/macro.lua index 777f754..83c6a90 100644 --- a/spec/outputs/macro.lua +++ b/spec/outputs/macro.lua | |||
@@ -1,3 +1,16 @@ | |||
1 | do | ||
2 | print(123) | ||
3 | do | ||
4 | print(6.2831853071796) | ||
5 | end | ||
6 | print(456) | ||
7 | do | ||
8 | -- TODO: "todo in a do block" | ||
9 | end | ||
10 | end | ||
11 | do | ||
12 | (leak)() | ||
13 | end | ||
1 | print("AlwaysAutoResize") | 14 | print("AlwaysAutoResize") |
2 | print({ | 15 | print({ |
3 | "NoNav", | 16 | "NoNav", |
@@ -298,7 +311,7 @@ print((setmetatable({ | |||
298 | return 998 | 311 | return 998 |
299 | end | 312 | end |
300 | })) | 313 | })) |
301 | print("current line: " .. tostring(308)) | 314 | print("current line: " .. tostring(323)) |
302 | do | 315 | do |
303 | -- TODO | 316 | -- TODO |
304 | end | 317 | end |
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 77a4967..240e3b5 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp | |||
@@ -75,7 +75,7 @@ static std::unordered_set<std::string> Metamethods = { | |||
75 | "close"s // Lua 5.4 | 75 | "close"s // Lua 5.4 |
76 | }; | 76 | }; |
77 | 77 | ||
78 | const std::string_view version = "0.25.6"sv; | 78 | const std::string_view version = "0.26.0"sv; |
79 | const std::string_view extension = "yue"sv; | 79 | const std::string_view extension = "yue"sv; |
80 | 80 | ||
81 | class CompileError : public std::logic_error { | 81 | class CompileError : public std::logic_error { |
@@ -432,6 +432,9 @@ private: | |||
432 | struct Scope { | 432 | struct Scope { |
433 | GlobalMode mode = GlobalMode::None; | 433 | GlobalMode mode = GlobalMode::None; |
434 | bool lastStatement = false; | 434 | bool lastStatement = false; |
435 | #ifndef YUE_NO_MACRO | ||
436 | bool macroScope = false; | ||
437 | #endif | ||
435 | std::unique_ptr<std::unordered_map<std::string, VarType>> vars; | 438 | std::unique_ptr<std::unordered_map<std::string, VarType>> vars; |
436 | std::unique_ptr<std::unordered_set<std::string>> allows; | 439 | std::unique_ptr<std::unordered_set<std::string>> allows; |
437 | std::unique_ptr<std::unordered_set<std::string>> globals; | 440 | std::unique_ptr<std::unordered_set<std::string>> globals; |
@@ -472,12 +475,39 @@ private: | |||
472 | Closure | 475 | Closure |
473 | }; | 476 | }; |
474 | 477 | ||
478 | #ifndef YUE_NO_MACRO | ||
479 | void pushMacro(int moduleIndex) { | ||
480 | int len = static_cast<int>(lua_objlen(L, moduleIndex)); // len = #cur | ||
481 | if (currentScope().macroScope) { | ||
482 | lua_rawgeti(L, moduleIndex, len); // cur[len], tb | ||
483 | } else { | ||
484 | currentScope().macroScope = true; | ||
485 | lua_newtable(L); // tb | ||
486 | lua_pushvalue(L, -1); // tb tb | ||
487 | lua_rawseti(L, moduleIndex, len + 1); // cur[len + 1] = tb, tb | ||
488 | } | ||
489 | } | ||
490 | |||
491 | void popMacro() { | ||
492 | pushCurrentModule(); // cur | ||
493 | int len = static_cast<int>(lua_objlen(L, -1)); // len = #cur, cur | ||
494 | lua_pushnil(L); // cur nil | ||
495 | lua_rawseti(L, -2, len); // cur[len] = nil, cur | ||
496 | lua_pop(L, 1); | ||
497 | } | ||
498 | #endif // YUE_NO_MACRO | ||
499 | |||
475 | void pushScope() { | 500 | void pushScope() { |
476 | _scopes.emplace_back(); | 501 | _scopes.emplace_back(); |
477 | _scopes.back().vars = std::make_unique<std::unordered_map<std::string, VarType>>(); | 502 | _scopes.back().vars = std::make_unique<std::unordered_map<std::string, VarType>>(); |
478 | } | 503 | } |
479 | 504 | ||
480 | void popScope() { | 505 | void popScope() { |
506 | #ifndef YUE_NO_MACRO | ||
507 | if (_scopes.back().macroScope) { | ||
508 | popMacro(); | ||
509 | } | ||
510 | #endif // YUE_NO_MACRO | ||
481 | _scopes.pop_back(); | 511 | _scopes.pop_back(); |
482 | } | 512 | } |
483 | 513 | ||
@@ -4092,7 +4122,11 @@ private: | |||
4092 | } | 4122 | } |
4093 | YueConfig config; | 4123 | YueConfig config; |
4094 | config.lintGlobalVariable = true; | 4124 | config.lintGlobalVariable = true; |
4095 | auto result = YueCompiler{L, _luaOpen, true}.compile(codes, config); | 4125 | #ifndef YUE_NO_MACRO |
4126 | auto result = YueCompiler{L, _luaOpen, false}.compile(codes, config); | ||
4127 | #else | ||
4128 | auto result = YueCompiler{}.compile(codes, config); | ||
4129 | #endif // YUE_NO_MACRO | ||
4096 | if (result.error) { | 4130 | if (result.error) { |
4097 | YUEE("failed to compile dues to Yue formatter", x); | 4131 | YUEE("failed to compile dues to Yue formatter", x); |
4098 | } | 4132 | } |
@@ -5058,9 +5092,9 @@ private: | |||
5058 | void pushCurrentModule() { | 5092 | void pushCurrentModule() { |
5059 | if (_useModule) { | 5093 | if (_useModule) { |
5060 | lua_pushliteral(L, YUE_MODULES); // YUE_MODULES | 5094 | lua_pushliteral(L, YUE_MODULES); // YUE_MODULES |
5061 | lua_rawget(L, LUA_REGISTRYINDEX); // reg[YUE_MODULES], tb | 5095 | lua_rawget(L, LUA_REGISTRYINDEX); // reg[YUE_MODULES], mods |
5062 | int idx = static_cast<int>(lua_objlen(L, -1)); // idx = #tb, tb | 5096 | int idx = static_cast<int>(lua_objlen(L, -1)); // idx = #mods, mods |
5063 | lua_rawgeti(L, -1, idx); // tb[idx], tb cur | 5097 | lua_rawgeti(L, -1, idx); // mods[idx], mods cur |
5064 | lua_remove(L, -2); // cur | 5098 | lua_remove(L, -2); // cur |
5065 | return; | 5099 | return; |
5066 | } | 5100 | } |
@@ -5085,18 +5119,20 @@ private: | |||
5085 | _stateOwner = true; | 5119 | _stateOwner = true; |
5086 | } | 5120 | } |
5087 | lua_pushliteral(L, YUE_MODULES); // YUE_MODULES | 5121 | lua_pushliteral(L, YUE_MODULES); // YUE_MODULES |
5088 | lua_rawget(L, LUA_REGISTRYINDEX); // reg[YUE_MODULES], tb | 5122 | lua_rawget(L, LUA_REGISTRYINDEX); // reg[YUE_MODULES], mods |
5089 | if (lua_isnil(L, -1) != 0) { // tb == nil | 5123 | if (lua_isnil(L, -1) != 0) { // mods == nil |
5090 | lua_pop(L, 1); | 5124 | lua_pop(L, 1); |
5091 | lua_newtable(L); // tb | 5125 | lua_newtable(L); // mods |
5092 | lua_pushliteral(L, YUE_MODULES); // tb YUE_MODULES | 5126 | lua_pushliteral(L, YUE_MODULES); // mods YUE_MODULES |
5093 | lua_pushvalue(L, -2); // tb YUE_MODULE tb | 5127 | lua_pushvalue(L, -2); // mods YUE_MODULE mods |
5094 | lua_rawset(L, LUA_REGISTRYINDEX); // reg[YUE_MODULES] = tb, tb | 5128 | lua_rawset(L, LUA_REGISTRYINDEX); // reg[YUE_MODULES] = mods, mods |
5095 | } // tb | 5129 | } // tb |
5096 | int idx = static_cast<int>(lua_objlen(L, -1)); // idx = #tb, tb | 5130 | int idx = static_cast<int>(lua_objlen(L, -1)); // idx = #mods, mods |
5097 | lua_newtable(L); // tb cur | 5131 | lua_newtable(L); // mods cur |
5098 | lua_pushvalue(L, -1); // tb cur cur | 5132 | lua_newtable(L); // mods cur scope |
5099 | lua_rawseti(L, -3, idx + 1); // tb[idx + 1] = cur, tb cur | 5133 | lua_rawseti(L, -2, 1); // cur[1] = scope, mods cur |
5134 | lua_pushvalue(L, -1); // mods cur cur | ||
5135 | lua_rawseti(L, -3, idx + 1); // mods[idx + 1] = cur, mods cur | ||
5100 | lua_remove(L, -2); // cur | 5136 | lua_remove(L, -2); // cur |
5101 | } | 5137 | } |
5102 | 5138 | ||
@@ -5158,9 +5194,6 @@ private: | |||
5158 | } | 5194 | } |
5159 | 5195 | ||
5160 | void transformMacro(Macro_t* macro, str_list& out, bool exporting) { | 5196 | void transformMacro(Macro_t* macro, str_list& out, bool exporting) { |
5161 | if (_scopes.size() > 1) { | ||
5162 | throw CompileError("can not define macro outside the root block"sv, macro); | ||
5163 | } | ||
5164 | auto macroName = _parser.toString(macro->name); | 5197 | auto macroName = _parser.toString(macro->name); |
5165 | if (auto macroFunc = macro->decl.as<MacroFunc_t>()) { | 5198 | if (auto macroFunc = macro->decl.as<MacroFunc_t>()) { |
5166 | auto chainValue = macroFunc->new_ptr<ChainValue_t>(); | 5199 | auto chainValue = macroFunc->new_ptr<ChainValue_t>(); |
@@ -5184,9 +5217,12 @@ private: | |||
5184 | lua_rawset(L, -3); // cur macro module | 5217 | lua_rawset(L, -3); // cur macro module |
5185 | lua_pop(L, 1); | 5218 | lua_pop(L, 1); |
5186 | } // cur macro | 5219 | } // cur macro |
5187 | lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro name | 5220 | int moduleIndex = lua_gettop(L) - 1; |
5188 | lua_insert(L, -2); // cur name macro | 5221 | pushMacro(moduleIndex); // cur macro scope |
5189 | lua_rawset(L, -3); // cur[name] = macro, cur | 5222 | lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro scope name |
5223 | lua_insert(L, -3); // cur name macro scope | ||
5224 | lua_insert(L, -3); // cur scope name macro | ||
5225 | lua_rawset(L, -3); // scope[name] = macro, cur scope | ||
5190 | out.push_back(Empty); | 5226 | out.push_back(Empty); |
5191 | return; | 5227 | return; |
5192 | } | 5228 | } |
@@ -5249,9 +5285,12 @@ private: | |||
5249 | lua_rawset(L, -3); // cur macro module | 5285 | lua_rawset(L, -3); // cur macro module |
5250 | lua_pop(L, 1); | 5286 | lua_pop(L, 1); |
5251 | } // cur macro | 5287 | } // cur macro |
5252 | lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro name | 5288 | int moduleIndex = lua_gettop(L) - 1; |
5253 | lua_insert(L, -2); // cur name macro | 5289 | pushMacro(moduleIndex); // cur macro scope |
5254 | lua_rawset(L, -3); // cur[name] = macro, cur | 5290 | lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro scope name |
5291 | lua_insert(L, -3); // cur name macro scope | ||
5292 | lua_insert(L, -3); // cur scope name macro | ||
5293 | lua_rawset(L, -3); // scope[name] = macro, cur scope | ||
5255 | out.push_back(Empty); | 5294 | out.push_back(Empty); |
5256 | } | 5295 | } |
5257 | #else | 5296 | #else |
@@ -6373,8 +6412,18 @@ private: | |||
6373 | } | 6412 | } |
6374 | } | 6413 | } |
6375 | } | 6414 | } |
6376 | lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macroName | 6415 | int len = lua_objlen(L, -1); |
6377 | lua_rawget(L, -2); // cur[macroName], cur macroFunc | 6416 | lua_pushnil(L); // cur nil |
6417 | for (int i = len; i >= 1; i--) { | ||
6418 | lua_pop(L, 1); // cur | ||
6419 | lua_rawgeti(L, -1, i); // cur[i], cur scope | ||
6420 | lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur scope macroName | ||
6421 | lua_rawget(L, -2); // scope[macroName], cur scope macroFunc | ||
6422 | lua_remove(L, -2); // cur macroFunc | ||
6423 | if (!lua_isnil(L, -1)) { | ||
6424 | break; | ||
6425 | } | ||
6426 | } | ||
6378 | if (!lua_isfunction(L, -1)) { | 6427 | if (!lua_isfunction(L, -1)) { |
6379 | auto code = expandBuiltinMacro(macroName, x); | 6428 | auto code = expandBuiltinMacro(macroName, x); |
6380 | if (!code.empty()) return code; | 6429 | if (!code.empty()) return code; |
@@ -7763,13 +7812,13 @@ private: | |||
7763 | bool extraScope = false; | 7812 | bool extraScope = false; |
7764 | bool needScope = !currentScope().lastStatement; | 7813 | bool needScope = !currentScope().lastStatement; |
7765 | std::list<std::pair<ast_node*, ast_ptr<false, ast_node>>> destructPairs; | 7814 | std::list<std::pair<ast_node*, ast_ptr<false, ast_node>>> destructPairs; |
7766 | for (auto _item : nameList->items.objects()) { | 7815 | for (auto item_ : nameList->items.objects()) { |
7767 | auto item = static_cast<NameOrDestructure_t*>(_item)->item.get(); | 7816 | auto item = static_cast<NameOrDestructure_t*>(item_)->item.get(); |
7768 | switch (item->get_id()) { | 7817 | switch (item->get_id()) { |
7769 | case id<Variable_t>(): | 7818 | case id<Variable_t>(): |
7770 | transformVariable(static_cast<Variable_t*>(item), vars); | 7819 | transformVariable(static_cast<Variable_t*>(item), vars); |
7771 | varAfter.push_back(vars.back()); | 7820 | varAfter.push_back(vars.back()); |
7772 | if (_item == nameList->items.objects().front()) { | 7821 | if (getLuaTarget(x) >= 505 && item_ == nameList->items.objects().front()) { |
7773 | varConstAfter = vars.back(); | 7822 | varConstAfter = vars.back(); |
7774 | } | 7823 | } |
7775 | break; | 7824 | break; |
@@ -10027,39 +10076,44 @@ private: | |||
10027 | pushCurrentModule(); // cur | 10076 | pushCurrentModule(); // cur |
10028 | int top = lua_gettop(L) - 1; // Lua state may be setup by pushCurrentModule() | 10077 | int top = lua_gettop(L) - 1; // Lua state may be setup by pushCurrentModule() |
10029 | DEFER(lua_settop(L, top)); | 10078 | DEFER(lua_settop(L, top)); |
10030 | pushYue("find_modulepath"sv); // cur find_modulepath | 10079 | pushMacro(lua_gettop(L)); // cur scope |
10031 | lua_pushlstring(L, moduleName.c_str(), moduleName.size()); // cur find_modulepath moduleName | 10080 | pushYue("find_modulepath"sv); // cur scope find_modulepath |
10032 | if (lua_pcall(L, 1, 2, 0) != 0) { | 10081 | lua_pushlstring(L, moduleName.c_str(), moduleName.size()); // cur scope find_modulepath moduleName |
10082 | if (lua_pcall(L, 1, 2, 0) != 0) { // find_modulepath(moduleName), cur scope result searchItems | ||
10033 | std::string err = lua_tostring(L, -1); | 10083 | std::string err = lua_tostring(L, -1); |
10034 | throw CompileError("failed to resolve module path\n"s + err, x); | 10084 | throw CompileError("failed to resolve module path\n"s + err, x); |
10035 | } | 10085 | } |
10036 | if (lua_isnil(L, -2) != 0) { | 10086 | if (lua_isnil(L, -2) != 0) { // result != nil |
10037 | str_list files; | 10087 | str_list files; |
10038 | if (lua_istable(L, -1) != 0) { | 10088 | if (lua_istable(L, -1) != 0) { // searchItems is table, |
10039 | int size = static_cast<int>(lua_objlen(L, -1)); | 10089 | int size = static_cast<int>(lua_objlen(L, -1)); |
10040 | for (int i = 0; i < size; i++) { | 10090 | for (int i = 0; i < size; i++) { |
10041 | lua_rawgeti(L, -1, i + 1); | 10091 | lua_rawgeti(L, -1, i + 1); // cur scope result searchItems item |
10042 | files.push_back("no file \""s + lua_tostring(L, -1) + "\""s); | 10092 | files.push_back("no file \""s + lua_tostring(L, -1) + "\""s); |
10043 | lua_pop(L, 1); | 10093 | lua_pop(L, 1); // cur scope result searchItems |
10044 | } | 10094 | } |
10045 | } | 10095 | } |
10046 | throw CompileError("module '"s + moduleName + "\' not found:\n\t"s + join(files, "\n\t"sv), x); | 10096 | throw CompileError("module '"s + moduleName + "\' not found:\n\t"s + join(files, "\n\t"sv), x); |
10047 | } | 10097 | } |
10048 | lua_pop(L, 1); | 10098 | lua_pop(L, 1); // cur scope result |
10049 | std::string moduleFullName = lua_tostring(L, -1); | 10099 | std::string moduleFullName = lua_tostring(L, -1); |
10050 | lua_pop(L, 1); // cur | 10100 | lua_pop(L, 1); // cur scope |
10051 | if (!isModuleLoaded(moduleFullName)) { | 10101 | if (!isModuleLoaded(moduleFullName)) { |
10052 | pushYue("read_file"sv); // cur read_file | 10102 | pushYue("read_file"sv); // cur scope read_file |
10053 | lua_pushlstring(L, moduleFullName.c_str(), moduleFullName.size()); // cur load_text moduleFullName | 10103 | lua_pushlstring(L, moduleFullName.c_str(), moduleFullName.size()); // cur scope load_text moduleFullName |
10054 | if (lua_pcall(L, 1, 1, 0) != 0) { | 10104 | if (lua_pcall(L, 1, 1, 0) != 0) { |
10055 | std::string err = lua_tostring(L, -1); | 10105 | std::string err = lua_tostring(L, -1); |
10056 | throw CompileError("failed to read module file\n"s + err, x); | 10106 | throw CompileError("failed to read module file\n"s + err, x); |
10057 | } // cur text | 10107 | } // cur scope text |
10058 | if (lua_isnil(L, -1) != 0) { | 10108 | if (lua_isnil(L, -1) != 0) { |
10059 | throw CompileError("failed to get module text"sv, x); | 10109 | throw CompileError("failed to get module text"sv, x); |
10060 | } // cur text | 10110 | } // cur scope text |
10061 | std::string text = lua_tostring(L, -1); | 10111 | std::string text = lua_tostring(L, -1); |
10062 | auto compiler = YueCompilerImpl(L, _luaOpen, false); | 10112 | #ifndef YUE_NO_MACRO |
10113 | auto compiler = YueCompiler{L, _luaOpen, false}; | ||
10114 | #else | ||
10115 | auto compiler = YueCompiler{}; | ||
10116 | #endif // YUE_NO_MACRO | ||
10063 | YueConfig config; | 10117 | YueConfig config; |
10064 | config.lineOffset = 0; | 10118 | config.lineOffset = 0; |
10065 | config.lintGlobalVariable = false; | 10119 | config.lintGlobalVariable = false; |
@@ -10071,28 +10125,28 @@ private: | |||
10071 | if (result.error) { | 10125 | if (result.error) { |
10072 | throw CompileError("failed to compile module '"s + moduleName + "\': "s + result.error.value().msg, x); | 10126 | throw CompileError("failed to compile module '"s + moduleName + "\': "s + result.error.value().msg, x); |
10073 | } | 10127 | } |
10074 | lua_pop(L, 1); // cur | 10128 | lua_pop(L, 1); // cur scope |
10075 | } | 10129 | } |
10076 | pushModuleTable(moduleFullName); // cur mod | 10130 | pushModuleTable(moduleFullName); // cur scope mod |
10077 | if (importAllMacro) { | 10131 | if (importAllMacro) { |
10078 | lua_pushnil(L); // cur mod startKey | 10132 | lua_pushnil(L); // cur scope mod startKey |
10079 | while (lua_next(L, -2) != 0) { // cur mod key value | 10133 | while (lua_next(L, -2) != 0) { // cur scope mod key value |
10080 | const char* key = lua_tostring(L, -2); | 10134 | const char* key = lua_tostring(L, -2); |
10081 | auto it = std::find_if(macroPairs.begin(), macroPairs.end(), [&](const auto& item) { | 10135 | auto it = std::find_if(macroPairs.begin(), macroPairs.end(), [&](const auto& item) { |
10082 | return key == item.first; | 10136 | return key == item.first; |
10083 | }); | 10137 | }); |
10084 | if (it == macroPairs.end()) { | 10138 | if (it == macroPairs.end()) { |
10085 | lua_pushvalue(L, -2); // cur mod key value key | 10139 | lua_pushvalue(L, -2); // cur scope mod key value key |
10086 | lua_insert(L, -2); // cur mod key key value | 10140 | lua_insert(L, -2); // cur scope mod key key value |
10087 | lua_rawset(L, -5); // cur[key] = value, cur mod key | 10141 | lua_rawset(L, -5); // scope[key] = value, cur scope mod key |
10088 | } else { | 10142 | } else { |
10089 | lua_pop(L, 1); // cur mod key | 10143 | lua_pop(L, 1); // cur scope mod key |
10090 | } | 10144 | } |
10091 | } | 10145 | } // cur scope mod |
10092 | } | 10146 | } |
10093 | for (const auto& pair : macroPairs) { | 10147 | for (const auto& pair : macroPairs) { |
10094 | lua_getfield(L, -1, pair.first.c_str()); // mod[first], cur mod val | 10148 | lua_getfield(L, -1, pair.first.c_str()); // mod[first], cur scope mod val |
10095 | lua_setfield(L, -3, pair.second.c_str()); // cur[second] = val, cur mod | 10149 | lua_setfield(L, -3, pair.second.c_str()); // scope[second] = val, cur scope mod |
10096 | } | 10150 | } |
10097 | } | 10151 | } |
10098 | #else // YUE_NO_MACRO | 10152 | #else // YUE_NO_MACRO |