diff options
| author | Li Jin <dragon-fly@qq.com> | 2024-10-31 16:29:10 +0800 |
|---|---|---|
| committer | Li Jin <dragon-fly@qq.com> | 2024-10-31 16:29:19 +0800 |
| commit | 37c8f0a862a570af707809d530b3284c6ff9229c (patch) | |
| tree | 78de6d4bdfacd30602823cf05b437dd506572247 /src | |
| parent | 3387abbfe072cbfe1ed1e7a3d71668603831591b (diff) | |
| download | yuescript-37c8f0a862a570af707809d530b3284c6ff9229c.tar.gz yuescript-37c8f0a862a570af707809d530b3284c6ff9229c.tar.bz2 yuescript-37c8f0a862a570af707809d530b3284c6ff9229c.zip | |
Fixed issue #175 and #177.
Diffstat (limited to 'src')
| -rw-r--r-- | src/yuescript/yue_compiler.cpp | 162 |
1 files changed, 108 insertions, 54 deletions
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 |
