diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/yuescript/yue_ast.cpp | 5 | ||||
| -rw-r--r-- | src/yuescript/yue_ast.h | 10 | ||||
| -rw-r--r-- | src/yuescript/yue_compiler.cpp | 86 | ||||
| -rw-r--r-- | src/yuescript/yue_parser.cpp | 3 | ||||
| -rw-r--r-- | src/yuescript/yue_parser.h | 1 |
5 files changed, 77 insertions, 28 deletions
diff --git a/src/yuescript/yue_ast.cpp b/src/yuescript/yue_ast.cpp index 3a22345..a454908 100644 --- a/src/yuescript/yue_ast.cpp +++ b/src/yuescript/yue_ast.cpp | |||
| @@ -1362,8 +1362,11 @@ std::string MacroLit_t::to_string(void* ud) const { | |||
| 1362 | } | 1362 | } |
| 1363 | return line; | 1363 | return line; |
| 1364 | } | 1364 | } |
| 1365 | std::string MacroFunc_t::to_string(void* ud) const { | ||
| 1366 | return name->to_string(ud) + invoke->to_string(ud); | ||
| 1367 | } | ||
| 1365 | std::string Macro_t::to_string(void* ud) const { | 1368 | std::string Macro_t::to_string(void* ud) const { |
| 1366 | return "macro "s + name->to_string(ud) + " = "s + macroLit->to_string(ud); | 1369 | return "macro "s + name->to_string(ud) + " = "s + decl->to_string(ud); |
| 1367 | } | 1370 | } |
| 1368 | std::string MacroInPlace_t::to_string(void* ud) const { | 1371 | std::string MacroInPlace_t::to_string(void* ud) const { |
| 1369 | auto info = reinterpret_cast<YueFormat*>(ud); | 1372 | auto info = reinterpret_cast<YueFormat*>(ud); |
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index 2ea0a85..b287202 100644 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h | |||
| @@ -774,6 +774,12 @@ AST_NODE(MacroLit) | |||
| 774 | AST_MEMBER(MacroLit, &argsDef, &body) | 774 | AST_MEMBER(MacroLit, &argsDef, &body) |
| 775 | AST_END(MacroLit, "macro_lit"sv) | 775 | AST_END(MacroLit, "macro_lit"sv) |
| 776 | 776 | ||
| 777 | AST_NODE(MacroFunc) | ||
| 778 | ast_ptr<true, MacroName_t> name; | ||
| 779 | ast_sel<true, Invoke_t, InvokeArgs_t> invoke; | ||
| 780 | AST_MEMBER(MacroFunc, &name, &invoke) | ||
| 781 | AST_END(MacroFunc, "macro_func"sv) | ||
| 782 | |||
| 777 | AST_NODE(MacroInPlace) | 783 | AST_NODE(MacroInPlace) |
| 778 | ast_ptr<true, Body_t> body; | 784 | ast_ptr<true, Body_t> body; |
| 779 | AST_MEMBER(MacroInPlace, &body) | 785 | AST_MEMBER(MacroInPlace, &body) |
| @@ -781,8 +787,8 @@ AST_END(MacroInPlace, "macro_in_place"sv) | |||
| 781 | 787 | ||
| 782 | AST_NODE(Macro) | 788 | AST_NODE(Macro) |
| 783 | ast_ptr<true, UnicodeName_t> name; | 789 | ast_ptr<true, UnicodeName_t> name; |
| 784 | ast_ptr<true, MacroLit_t> macroLit; | 790 | ast_sel<true, MacroLit_t, MacroFunc_t> decl; |
| 785 | AST_MEMBER(Macro, &name, ¯oLit) | 791 | AST_MEMBER(Macro, &name, &decl) |
| 786 | AST_END(Macro, "macro"sv) | 792 | AST_END(Macro, "macro"sv) |
| 787 | 793 | ||
| 788 | AST_NODE(NameOrDestructure) | 794 | AST_NODE(NameOrDestructure) |
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 7b34d0e..994ab57 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.23.8"sv; | 78 | const std::string_view version = "0.23.9"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 { |
| @@ -5065,7 +5065,36 @@ private: | |||
| 5065 | throw CompileError("can not define macro outside the root block"sv, macro); | 5065 | throw CompileError("can not define macro outside the root block"sv, macro); |
| 5066 | } | 5066 | } |
| 5067 | auto macroName = _parser.toString(macro->name); | 5067 | auto macroName = _parser.toString(macro->name); |
| 5068 | auto argsDef = macro->macroLit->argsDef.get(); | 5068 | if (auto macroFunc = macro->decl.as<MacroFunc_t>()) { |
| 5069 | auto chainValue = macroFunc->new_ptr<ChainValue_t>(); | ||
| 5070 | auto callable = macroFunc->new_ptr<Callable_t>(); | ||
| 5071 | callable->item.set(macroFunc->name); | ||
| 5072 | chainValue->items.push_back(callable); | ||
| 5073 | chainValue->items.push_back(macroFunc->invoke); | ||
| 5074 | pushCurrentModule(); // cur | ||
| 5075 | int top = lua_gettop(L) - 1; | ||
| 5076 | DEFER(lua_settop(L, top)); | ||
| 5077 | if (auto builtinCode = expandMacroChain(chainValue)) { | ||
| 5078 | throw CompileError("macro generating function must return a function"sv, chainValue); | ||
| 5079 | } // cur res | ||
| 5080 | if (lua_isfunction(L, -1) == 0) { | ||
| 5081 | throw CompileError("macro generating function must return a function"sv, chainValue); | ||
| 5082 | } // cur macro | ||
| 5083 | if (exporting && _config.exporting && !_config.module.empty()) { | ||
| 5084 | pushModuleTable(_config.module); // cur macro module | ||
| 5085 | lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro module name | ||
| 5086 | lua_pushvalue(L, -3); // cur macro module name macro | ||
| 5087 | lua_rawset(L, -3); // cur macro module | ||
| 5088 | lua_pop(L, 1); | ||
| 5089 | } // cur macro | ||
| 5090 | lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macro name | ||
| 5091 | lua_insert(L, -2); // cur name macro | ||
| 5092 | lua_rawset(L, -3); // cur[name] = macro, cur | ||
| 5093 | out.push_back(Empty); | ||
| 5094 | return; | ||
| 5095 | } | ||
| 5096 | auto macroLit = macro->decl.to<MacroLit_t>(); | ||
| 5097 | auto argsDef = macroLit->argsDef.get(); | ||
| 5069 | str_list newArgs; | 5098 | str_list newArgs; |
| 5070 | if (argsDef) { | 5099 | if (argsDef) { |
| 5071 | for (auto def_ : argsDef->definitions.objects()) { | 5100 | for (auto def_ : argsDef->definitions.objects()) { |
| @@ -5088,7 +5117,7 @@ private: | |||
| 5088 | } | 5117 | } |
| 5089 | } | 5118 | } |
| 5090 | _buf << "("sv << join(newArgs, ","sv) << ")->"sv; | 5119 | _buf << "("sv << join(newArgs, ","sv) << ")->"sv; |
| 5091 | _buf << _parser.toString(macro->macroLit->body); | 5120 | _buf << _parser.toString(macroLit->body); |
| 5092 | auto macroCodes = clearBuf(); | 5121 | auto macroCodes = clearBuf(); |
| 5093 | _buf << "=(macro "sv << macroName << ")"; | 5122 | _buf << "=(macro "sv << macroName << ")"; |
| 5094 | auto chunkName = clearBuf(); | 5123 | auto chunkName = clearBuf(); |
| @@ -5101,22 +5130,22 @@ private: | |||
| 5101 | pushOptions(macro->m_begin.m_line - 1); // cur loadstring codes chunk options | 5130 | pushOptions(macro->m_begin.m_line - 1); // cur loadstring codes chunk options |
| 5102 | if (lua_pcall(L, 3, 2, 0) != 0) { // loadstring(codes,chunk,options), cur f err | 5131 | if (lua_pcall(L, 3, 2, 0) != 0) { // loadstring(codes,chunk,options), cur f err |
| 5103 | std::string err = lua_tostring(L, -1); | 5132 | std::string err = lua_tostring(L, -1); |
| 5104 | throw CompileError("failed to load macro codes\n"s + err, macro->macroLit); | 5133 | throw CompileError("failed to load macro codes\n"s + err, macroLit); |
| 5105 | } // cur f err | 5134 | } // cur f err |
| 5106 | if (lua_isnil(L, -2) != 0) { // f == nil, cur f err | 5135 | if (lua_isnil(L, -2) != 0) { // f == nil, cur f err |
| 5107 | std::string err = lua_tostring(L, -1); | 5136 | std::string err = lua_tostring(L, -1); |
| 5108 | throw CompileError("failed to load macro codes, at (macro "s + macroName + "): "s + err, macro->macroLit); | 5137 | throw CompileError("failed to load macro codes, at (macro "s + macroName + "): "s + err, macroLit); |
| 5109 | } | 5138 | } |
| 5110 | lua_pop(L, 1); // cur f | 5139 | lua_pop(L, 1); // cur f |
| 5111 | pushYue("pcall"sv); // cur f pcall | 5140 | pushYue("pcall"sv); // cur f pcall |
| 5112 | lua_insert(L, -2); // cur pcall f | 5141 | lua_insert(L, -2); // cur pcall f |
| 5113 | if (lua_pcall(L, 1, 2, 0) != 0) { // f(), cur success macro | 5142 | if (lua_pcall(L, 1, 2, 0) != 0) { // f(), cur success macro |
| 5114 | std::string err = lua_tostring(L, -1); | 5143 | std::string err = lua_tostring(L, -1); |
| 5115 | throw CompileError("failed to generate macro function\n"s + err, macro->macroLit); | 5144 | throw CompileError("failed to generate macro function\n"s + err, macroLit); |
| 5116 | } // cur success res | 5145 | } // cur success res |
| 5117 | if (lua_toboolean(L, -2) == 0) { | 5146 | if (lua_toboolean(L, -2) == 0) { |
| 5118 | std::string err = lua_tostring(L, -1); | 5147 | std::string err = lua_tostring(L, -1); |
| 5119 | throw CompileError("failed to generate macro function\n"s + err, macro->macroLit); | 5148 | throw CompileError("failed to generate macro function\n"s + err, macroLit); |
| 5120 | } // cur true macro | 5149 | } // cur true macro |
| 5121 | lua_remove(L, -2); // cur macro | 5150 | lua_remove(L, -2); // cur macro |
| 5122 | if (exporting && _config.exporting && !_config.module.empty()) { | 5151 | if (exporting && _config.exporting && !_config.module.empty()) { |
| @@ -6180,23 +6209,20 @@ private: | |||
| 6180 | return Empty; | 6209 | return Empty; |
| 6181 | } | 6210 | } |
| 6182 | 6211 | ||
| 6183 | std::tuple<std::string, std::string, str_list> expandMacroStr(ChainValue_t* chainValue) { | 6212 | std::optional<std::string> expandMacroChain(ChainValue_t* chainValue) { |
| 6184 | const auto& chainList = chainValue->items.objects(); | 6213 | const auto& chainList = chainValue->items.objects(); |
| 6185 | auto x = ast_to<Callable_t>(chainList.front())->item.to<MacroName_t>(); | 6214 | auto x = ast_to<Callable_t>(chainList.front())->item.to<MacroName_t>(); |
| 6186 | auto macroName = _parser.toString(x->name); | 6215 | auto macroName = _parser.toString(x->name); |
| 6187 | if (!_useModule) { | 6216 | if (!_useModule) { |
| 6188 | auto code = expandBuiltinMacro(macroName, x); | 6217 | auto code = expandBuiltinMacro(macroName, x); |
| 6189 | if (!code.empty()) return {Empty, code, {}}; | 6218 | if (!code.empty()) return code; |
| 6190 | throw CompileError("can not resolve macro"sv, x); | 6219 | throw CompileError("can not resolve macro"sv, x); |
| 6191 | } | 6220 | } |
| 6192 | pushCurrentModule(); // cur | ||
| 6193 | int top = lua_gettop(L) - 1; | ||
| 6194 | DEFER(lua_settop(L, top)); | ||
| 6195 | lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macroName | 6221 | lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macroName |
| 6196 | lua_rawget(L, -2); // cur[macroName], cur macroFunc | 6222 | lua_rawget(L, -2); // cur[macroName], cur macroFunc |
| 6197 | if (lua_isfunction(L, -1) == 0) { | 6223 | if (lua_isfunction(L, -1) == 0) { |
| 6198 | auto code = expandBuiltinMacro(macroName, x); | 6224 | auto code = expandBuiltinMacro(macroName, x); |
| 6199 | if (!code.empty()) return {Empty, code, {}}; | 6225 | if (!code.empty()) return code; |
| 6200 | throw CompileError("can not resolve macro"sv, x); | 6226 | throw CompileError("can not resolve macro"sv, x); |
| 6201 | } // cur macroFunc | 6227 | } // cur macroFunc |
| 6202 | pushYue("pcall"sv); // cur macroFunc pcall | 6228 | pushYue("pcall"sv); // cur macroFunc pcall |
| @@ -6261,32 +6287,44 @@ private: | |||
| 6261 | throw CompileError("failed to expand macro: "s + err, x); | 6287 | throw CompileError("failed to expand macro: "s + err, x); |
| 6262 | } | 6288 | } |
| 6263 | lua_remove(L, -2); // cur res | 6289 | lua_remove(L, -2); // cur res |
| 6290 | return std::nullopt; | ||
| 6291 | } | ||
| 6292 | |||
| 6293 | std::tuple<std::string, std::string, str_list> expandMacroStr(ChainValue_t* chainValue) { | ||
| 6294 | auto x = chainValue->items.front(); | ||
| 6295 | pushCurrentModule(); // cur | ||
| 6296 | int top = lua_gettop(L) - 1; | ||
| 6297 | DEFER(lua_settop(L, top)); | ||
| 6298 | auto builtinCode = expandMacroChain(chainValue); | ||
| 6299 | if (builtinCode) { | ||
| 6300 | return {Empty, builtinCode.value(), {}}; | ||
| 6301 | } // cur res | ||
| 6264 | if (lua_isstring(L, -1) == 0 && lua_istable(L, -1) == 0) { | 6302 | if (lua_isstring(L, -1) == 0 && lua_istable(L, -1) == 0) { |
| 6265 | throw CompileError("macro function must return string or table"sv, x); | 6303 | throw CompileError("macro function must return a string or a table"sv, x); |
| 6266 | } // cur res | 6304 | } // cur res |
| 6267 | std::string codes; | 6305 | std::string codes; |
| 6268 | std::string type; | 6306 | std::string type; |
| 6269 | str_list localVars; | 6307 | str_list localVars; |
| 6270 | if (lua_istable(L, -1) != 0) { | 6308 | if (lua_istable(L, -1) != 0) { // cur tab |
| 6271 | lua_getfield(L, -1, "code"); // cur res code | 6309 | lua_getfield(L, -1, "code"); // cur tab code |
| 6272 | if (lua_isstring(L, -1) != 0) { | 6310 | if (lua_isstring(L, -1) != 0) { |
| 6273 | codes = lua_tostring(L, -1); | 6311 | codes = lua_tostring(L, -1); |
| 6274 | } else { | 6312 | } else { |
| 6275 | throw CompileError("macro table must contain field \"code\" of string"sv, x); | 6313 | throw CompileError("macro table must contain field \"code\" of string"sv, x); |
| 6276 | } | 6314 | } |
| 6277 | lua_pop(L, 1); // cur res | 6315 | lua_pop(L, 1); // cur tab |
| 6278 | lua_getfield(L, -1, "type"); // cur res type | 6316 | lua_getfield(L, -1, "type"); // cur tab type |
| 6279 | if (lua_isstring(L, -1) != 0) { | 6317 | if (lua_isstring(L, -1) != 0) { |
| 6280 | type = lua_tostring(L, -1); | 6318 | type = lua_tostring(L, -1); |
| 6281 | } | 6319 | } |
| 6282 | if (type != "lua"sv && type != "text"sv) { | 6320 | if (type != "lua"sv && type != "text"sv) { |
| 6283 | throw CompileError("macro table must contain field \"type\" of value \"lua\" or \"text\""sv, x); | 6321 | throw CompileError("macro table must contain field \"type\" of value \"lua\" or \"text\""sv, x); |
| 6284 | } | 6322 | } |
| 6285 | lua_pop(L, 1); // cur res | 6323 | lua_pop(L, 1); // cur tab |
| 6286 | lua_getfield(L, -1, "locals"); // cur res locals | 6324 | lua_getfield(L, -1, "locals"); // cur tab locals |
| 6287 | if (lua_istable(L, -1) != 0) { | 6325 | if (lua_istable(L, -1) != 0) { |
| 6288 | for (int i = 0; i < static_cast<int>(lua_objlen(L, -1)); i++) { | 6326 | for (int i = 0; i < static_cast<int>(lua_objlen(L, -1)); i++) { |
| 6289 | lua_rawgeti(L, -1, i + 1); // cur res locals item | 6327 | lua_rawgeti(L, -1, i + 1); // cur tab locals item |
| 6290 | size_t len = 0; | 6328 | size_t len = 0; |
| 6291 | if (lua_isstring(L, -1) == 0) { | 6329 | if (lua_isstring(L, -1) == 0) { |
| 6292 | throw CompileError("macro table field \"locals\" must be a table of strings"sv, x); | 6330 | throw CompileError("macro table field \"locals\" must be a table of strings"sv, x); |
| @@ -6297,11 +6335,11 @@ private: | |||
| 6297 | } else { | 6335 | } else { |
| 6298 | throw CompileError("macro table field \"locals\" must contain names for local variables, got \""s + std::string(name, len) + '"', x); | 6336 | throw CompileError("macro table field \"locals\" must contain names for local variables, got \""s + std::string(name, len) + '"', x); |
| 6299 | } | 6337 | } |
| 6300 | lua_pop(L, 1); | 6338 | lua_pop(L, 1); // cur tab locals |
| 6301 | } | 6339 | } |
| 6302 | } | 6340 | } |
| 6303 | lua_pop(L, 1); // cur res | 6341 | lua_pop(L, 1); // cur tab |
| 6304 | } else { | 6342 | } else { // cur code |
| 6305 | codes = lua_tostring(L, -1); | 6343 | codes = lua_tostring(L, -1); |
| 6306 | } | 6344 | } |
| 6307 | Utils::trim(codes); | 6345 | Utils::trim(codes); |
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index 3ffaf18..986f67a 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp | |||
| @@ -870,7 +870,8 @@ YueParser::YueParser() { | |||
| 870 | MacroName = '$' >> UnicodeName; | 870 | MacroName = '$' >> UnicodeName; |
| 871 | macro_args_def = '(' >> white >> -FnArgDefList >> white >> ')'; | 871 | macro_args_def = '(' >> white >> -FnArgDefList >> white >> ')'; |
| 872 | MacroLit = -(macro_args_def >> space) >> "->" >> space >> Body; | 872 | MacroLit = -(macro_args_def >> space) >> "->" >> space >> Body; |
| 873 | Macro = key("macro") >> space >> UnicodeName >> space >> '=' >> space >> MacroLit; | 873 | MacroFunc = MacroName >> (Invoke | InvokeArgs); |
| 874 | Macro = key("macro") >> space >> UnicodeName >> space >> '=' >> space >> (MacroLit | MacroFunc); | ||
| 874 | MacroInPlace = '$' >> space >> "->" >> space >> Body; | 875 | MacroInPlace = '$' >> space >> "->" >> space >> Body; |
| 875 | 876 | ||
| 876 | NameList = Seperator >> Variable >> *(space >> ',' >> space >> Variable); | 877 | NameList = Seperator >> Variable >> *(space >> ',' >> space >> Variable); |
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h index 05aa9e6..6623653 100644 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h | |||
| @@ -396,6 +396,7 @@ private: | |||
| 396 | AST_RULE(FunLit); | 396 | AST_RULE(FunLit); |
| 397 | AST_RULE(MacroName); | 397 | AST_RULE(MacroName); |
| 398 | AST_RULE(MacroLit); | 398 | AST_RULE(MacroLit); |
| 399 | AST_RULE(MacroFunc); | ||
| 399 | AST_RULE(Macro); | 400 | AST_RULE(Macro); |
| 400 | AST_RULE(MacroInPlace); | 401 | AST_RULE(MacroInPlace); |
| 401 | AST_RULE(NameOrDestructure); | 402 | AST_RULE(NameOrDestructure); |
