diff options
author | Li Jin <dragon-fly@qq.com> | 2024-08-05 17:20:00 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2024-08-05 17:20:00 +0800 |
commit | 94edfbc8c7d62d700dfb59334a0ed3beedd49493 (patch) | |
tree | f695cec8b8873d5a6e763ac94bf3c81fb6ba0be9 /src | |
parent | f8cd1220147d606b7e96f88c12fd0f163fb4e1c5 (diff) | |
download | yuescript-94edfbc8c7d62d700dfb59334a0ed3beedd49493.tar.gz yuescript-94edfbc8c7d62d700dfb59334a0ed3beedd49493.tar.bz2 yuescript-94edfbc8c7d62d700dfb59334a0ed3beedd49493.zip |
add macros generating macros feature.v0.23.9
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); |