aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2024-08-05 17:20:00 +0800
committerLi Jin <dragon-fly@qq.com>2024-08-05 17:20:00 +0800
commit94edfbc8c7d62d700dfb59334a0ed3beedd49493 (patch)
treef695cec8b8873d5a6e763ac94bf3c81fb6ba0be9 /src
parentf8cd1220147d606b7e96f88c12fd0f163fb4e1c5 (diff)
downloadyuescript-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.cpp5
-rw-r--r--src/yuescript/yue_ast.h10
-rw-r--r--src/yuescript/yue_compiler.cpp86
-rw-r--r--src/yuescript/yue_parser.cpp3
-rw-r--r--src/yuescript/yue_parser.h1
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}
1365std::string MacroFunc_t::to_string(void* ud) const {
1366 return name->to_string(ud) + invoke->to_string(ud);
1367}
1365std::string Macro_t::to_string(void* ud) const { 1368std::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}
1368std::string MacroInPlace_t::to_string(void* ud) const { 1371std::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)
775AST_END(MacroLit, "macro_lit"sv) 775AST_END(MacroLit, "macro_lit"sv)
776 776
777AST_NODE(MacroFunc)
778 ast_ptr<true, MacroName_t> name;
779 ast_sel<true, Invoke_t, InvokeArgs_t> invoke;
780 AST_MEMBER(MacroFunc, &name, &invoke)
781AST_END(MacroFunc, "macro_func"sv)
782
777AST_NODE(MacroInPlace) 783AST_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
782AST_NODE(Macro) 788AST_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, &macroLit) 791 AST_MEMBER(Macro, &name, &decl)
786AST_END(Macro, "macro"sv) 792AST_END(Macro, "macro"sv)
787 793
788AST_NODE(NameOrDestructure) 794AST_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
78const std::string_view version = "0.23.8"sv; 78const std::string_view version = "0.23.9"sv;
79const std::string_view extension = "yue"sv; 79const std::string_view extension = "yue"sv;
80 80
81class CompileError : public std::logic_error { 81class 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);