diff options
author | Li Jin <dragon-fly@qq.com> | 2024-08-09 11:35:27 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2024-08-09 11:35:32 +0800 |
commit | f2b63cb849ea2f7ef571b82e7927cd4abef4414b (patch) | |
tree | c3277a22a76815fa8ec3d7f9909bf950c26e2dc7 | |
parent | b6c86d19d74ac90a2450cf979a92187e691ea5fa (diff) | |
download | yuescript-f2b63cb849ea2f7ef571b82e7927cd4abef4414b.tar.gz yuescript-f2b63cb849ea2f7ef571b82e7927cd4abef4414b.tar.bz2 yuescript-f2b63cb849ea2f7ef571b82e7927cd4abef4414b.zip |
add builtin macro $is_ast().
-rw-r--r-- | spec/inputs/macro.yue | 5 | ||||
-rw-r--r-- | spec/outputs/macro.lua | 2 | ||||
-rw-r--r-- | src/yuescript/parser.cpp | 20 | ||||
-rw-r--r-- | src/yuescript/yue_compiler.cpp | 152 | ||||
-rw-r--r-- | src/yuescript/yue_parser.cpp | 4 | ||||
-rw-r--r-- | src/yuescript/yue_parser.h | 2 |
6 files changed, 111 insertions, 74 deletions
diff --git a/spec/inputs/macro.yue b/spec/inputs/macro.yue index 3d4fb10..d5197da 100644 --- a/spec/inputs/macro.yue +++ b/spec/inputs/macro.yue | |||
@@ -39,9 +39,8 @@ print $WindowFlag( | |||
39 | ) | 39 | ) |
40 | 40 | ||
41 | macro NumAndStr = (num, str) -> | 41 | macro NumAndStr = (num, str) -> |
42 | import "yue" | 42 | unless $is_ast(Num, num) and $is_ast SingleString, str |
43 | unless yue.is_ast("Num", "123") | 43 | error "got unexpected token" |
44 | error "unmatched tokens got" | ||
45 | "[#{num}, #{str}]" | 44 | "[#{num}, #{str}]" |
46 | 45 | ||
47 | print $NumAndStr 123, 'xyz' | 46 | print $NumAndStr 123, 'xyz' |
diff --git a/spec/outputs/macro.lua b/spec/outputs/macro.lua index 4492827..777f754 100644 --- a/spec/outputs/macro.lua +++ b/spec/outputs/macro.lua | |||
@@ -298,7 +298,7 @@ print((setmetatable({ | |||
298 | return 998 | 298 | return 998 |
299 | end | 299 | end |
300 | })) | 300 | })) |
301 | print("current line: " .. tostring(309)) | 301 | print("current line: " .. tostring(308)) |
302 | do | 302 | do |
303 | -- TODO | 303 | -- TODO |
304 | end | 304 | end |
diff --git a/src/yuescript/parser.cpp b/src/yuescript/parser.cpp index 737deca..5e4caa2 100644 --- a/src/yuescript/parser.cpp +++ b/src/yuescript/parser.cpp | |||
@@ -15,9 +15,15 @@ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND | |||
15 | #include <stdexcept> | 15 | #include <stdexcept> |
16 | #include <unordered_map> | 16 | #include <unordered_map> |
17 | #include <unordered_set> | 17 | #include <unordered_set> |
18 | #include <memory> | ||
18 | 19 | ||
19 | #include "yuescript/parser.hpp" | 20 | #include "yuescript/parser.hpp" |
20 | 21 | ||
22 | #define _DEFER(code, line) std::shared_ptr<void> _defer_##line(nullptr, [&](auto) { \ | ||
23 | code; \ | ||
24 | }) | ||
25 | #define DEFER(code) _DEFER(code, __LINE__) | ||
26 | |||
21 | namespace parserlib { | 27 | namespace parserlib { |
22 | 28 | ||
23 | // internal private class that manages access to the public classes' internals. | 29 | // internal private class that manages access to the public classes' internals. |
@@ -907,6 +913,8 @@ _state::_state(_context& con) | |||
907 | bool _context::parse_non_term(rule& r) { | 913 | bool _context::parse_non_term(rule& r) { |
908 | // save the state of the rule | 914 | // save the state of the rule |
909 | rule::_state old_state = r.m_state; | 915 | rule::_state old_state = r.m_state; |
916 | // restore the rule's state | ||
917 | DEFER(r.m_state = old_state); | ||
910 | 918 | ||
911 | // success/failure result | 919 | // success/failure result |
912 | bool ok = false; | 920 | bool ok = false; |
@@ -952,7 +960,6 @@ bool _context::parse_non_term(rule& r) { | |||
952 | 960 | ||
953 | // since the left recursion was resolved successfully, | 961 | // since the left recursion was resolved successfully, |
954 | // return via a non-local exit | 962 | // return via a non-local exit |
955 | r.m_state = old_state; | ||
956 | throw _lr_ok(r.this_ptr()); | 963 | throw _lr_ok(r.this_ptr()); |
957 | } | 964 | } |
958 | } else { | 965 | } else { |
@@ -964,7 +971,6 @@ bool _context::parse_non_term(rule& r) { | |||
964 | if (ex.m_rule == r.this_ptr()) { | 971 | if (ex.m_rule == r.this_ptr()) { |
965 | ok = true; | 972 | ok = true; |
966 | } else { | 973 | } else { |
967 | r.m_state = old_state; | ||
968 | throw; | 974 | throw; |
969 | } | 975 | } |
970 | } | 976 | } |
@@ -994,9 +1000,6 @@ bool _context::parse_non_term(rule& r) { | |||
994 | break; | 1000 | break; |
995 | } | 1001 | } |
996 | 1002 | ||
997 | // restore the rule's state | ||
998 | r.m_state = old_state; | ||
999 | |||
1000 | return ok; | 1003 | return ok; |
1001 | } | 1004 | } |
1002 | 1005 | ||
@@ -1004,6 +1007,8 @@ bool _context::parse_non_term(rule& r) { | |||
1004 | bool _context::parse_term(rule& r) { | 1007 | bool _context::parse_term(rule& r) { |
1005 | // save the state of the rule | 1008 | // save the state of the rule |
1006 | rule::_state old_state = r.m_state; | 1009 | rule::_state old_state = r.m_state; |
1010 | // restore the rule's state | ||
1011 | DEFER(r.m_state = old_state); | ||
1007 | 1012 | ||
1008 | // success/failure result | 1013 | // success/failure result |
1009 | bool ok = false; | 1014 | bool ok = false; |
@@ -1049,7 +1054,6 @@ bool _context::parse_term(rule& r) { | |||
1049 | 1054 | ||
1050 | // since the left recursion was resolved successfully, | 1055 | // since the left recursion was resolved successfully, |
1051 | // return via a non-local exit | 1056 | // return via a non-local exit |
1052 | r.m_state = old_state; | ||
1053 | throw _lr_ok(r.this_ptr()); | 1057 | throw _lr_ok(r.this_ptr()); |
1054 | } | 1058 | } |
1055 | } else { | 1059 | } else { |
@@ -1061,7 +1065,6 @@ bool _context::parse_term(rule& r) { | |||
1061 | if (ex.m_rule == r.this_ptr()) { | 1065 | if (ex.m_rule == r.this_ptr()) { |
1062 | ok = true; | 1066 | ok = true; |
1063 | } else { | 1067 | } else { |
1064 | r.m_state = old_state; | ||
1065 | throw; | 1068 | throw; |
1066 | } | 1069 | } |
1067 | } | 1070 | } |
@@ -1091,9 +1094,6 @@ bool _context::parse_term(rule& r) { | |||
1091 | break; | 1094 | break; |
1092 | } | 1095 | } |
1093 | 1096 | ||
1094 | // restore the rule's state | ||
1095 | r.m_state = old_state; | ||
1096 | |||
1097 | return ok; | 1097 | return ok; |
1098 | } | 1098 | } |
1099 | 1099 | ||
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index a661356..533a666 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp | |||
@@ -55,6 +55,7 @@ namespace yue { | |||
55 | code; \ | 55 | code; \ |
56 | }) | 56 | }) |
57 | #define DEFER(code) _DEFER(code, __LINE__) | 57 | #define DEFER(code) _DEFER(code, __LINE__) |
58 | |||
58 | #define YUEE(msg, node) throw CompileError( \ | 59 | #define YUEE(msg, node) throw CompileError( \ |
59 | "[File] "s + __FILE__ \ | 60 | "[File] "s + __FILE__ \ |
60 | + ",\n[Func] "s + __FUNCTION__ \ | 61 | + ",\n[Func] "s + __FUNCTION__ \ |
@@ -5116,11 +5117,23 @@ private: | |||
5116 | newArgs.emplace_back(_parser.toString(argsDef->varArg)); | 5117 | newArgs.emplace_back(_parser.toString(argsDef->varArg)); |
5117 | } | 5118 | } |
5118 | } | 5119 | } |
5119 | _buf << "("sv << join(newArgs, ","sv) << ")->"sv; | 5120 | std::string macroCodes; |
5120 | _buf << _parser.toString(macroLit->body); | 5121 | { |
5121 | auto macroCodes = clearBuf(); | 5122 | auto funLit = toAst<FunLit_t>("("s + join(newArgs, ","sv) + ")->"s, macroLit); |
5122 | _buf << "=(macro "sv << macroName << ")"; | 5123 | auto block = macroLit->new_ptr<Block_t>(); |
5123 | auto chunkName = clearBuf(); | 5124 | if (auto stmt = macroLit->body->content.as<Statement_t>()) { |
5125 | block->statements.push_back(stmt); | ||
5126 | } else { | ||
5127 | auto blk = macroLit->body->content.to<Block_t>(); | ||
5128 | block->statements.dup(blk->statements); | ||
5129 | } | ||
5130 | block->statements.push_front(toAst<Statement_t>("_ENV=yue:require('yue'),<index>:_G,<newindex>:(k, v)=>_G[k]=v"sv, macroLit)); | ||
5131 | auto body = macroLit->new_ptr<Body_t>(); | ||
5132 | body->content.set(block); | ||
5133 | funLit->body.set(body); | ||
5134 | macroCodes = YueFormat{}.toString(funLit); | ||
5135 | } | ||
5136 | auto chunkName = "=(macro "s + macroName + ')'; | ||
5124 | pushCurrentModule(); // cur | 5137 | pushCurrentModule(); // cur |
5125 | int top = lua_gettop(L) - 1; | 5138 | int top = lua_gettop(L) - 1; |
5126 | DEFER(lua_settop(L, top)); | 5139 | DEFER(lua_settop(L, top)); |
@@ -6200,8 +6213,7 @@ private: | |||
6200 | std::string expandBuiltinMacro(const std::string& name, ast_node* x) { | 6213 | std::string expandBuiltinMacro(const std::string& name, ast_node* x) { |
6201 | if (name == "LINE"sv) { | 6214 | if (name == "LINE"sv) { |
6202 | return std::to_string(x->m_begin.m_line + _config.lineOffset); | 6215 | return std::to_string(x->m_begin.m_line + _config.lineOffset); |
6203 | } | 6216 | } else if (name == "FILE"sv) { |
6204 | if (name == "FILE"sv) { | ||
6205 | auto moduleName = _config.module; | 6217 | auto moduleName = _config.module; |
6206 | Utils::replace(moduleName, "\\"sv, "\\\\"sv); | 6218 | Utils::replace(moduleName, "\\"sv, "\\\\"sv); |
6207 | return moduleName.empty() ? "\"yuescript\""s : '"' + moduleName + '"'; | 6219 | return moduleName.empty() ? "\"yuescript\""s : '"' + moduleName + '"'; |
@@ -6218,66 +6230,86 @@ private: | |||
6218 | if (!code.empty()) return code; | 6230 | if (!code.empty()) return code; |
6219 | throw CompileError("can not resolve macro"sv, x); | 6231 | throw CompileError("can not resolve macro"sv, x); |
6220 | } | 6232 | } |
6233 | str_list argStrs; | ||
6234 | const node_container* args = nullptr; | ||
6235 | { | ||
6236 | if (chainList.size() > 1) { | ||
6237 | auto item = *(++chainList.begin()); | ||
6238 | if (auto invoke = ast_cast<Invoke_t>(item)) { | ||
6239 | args = &invoke->args.objects(); | ||
6240 | } else if (auto invoke = ast_cast<InvokeArgs_t>(item)) { | ||
6241 | args = &invoke->args.objects(); | ||
6242 | } | ||
6243 | } | ||
6244 | if (args) { | ||
6245 | for (auto arg : *args) { | ||
6246 | std::string str; | ||
6247 | bool rawString = false; | ||
6248 | if (auto lstr = ast_cast<LuaString_t>(arg)) { | ||
6249 | str = _parser.toString(lstr->content); | ||
6250 | rawString = true; | ||
6251 | } else { | ||
6252 | BLOCK_START | ||
6253 | auto exp = ast_cast<Exp_t>(arg); | ||
6254 | BREAK_IF(!exp); | ||
6255 | auto value = singleValueFrom(exp); | ||
6256 | BREAK_IF(!value); | ||
6257 | auto lstr = value->get_by_path<String_t, LuaString_t>(); | ||
6258 | BREAK_IF(!lstr); | ||
6259 | str = _parser.toString(lstr->content); | ||
6260 | rawString = true; | ||
6261 | BLOCK_END | ||
6262 | } | ||
6263 | if (!rawString && str.empty()) { | ||
6264 | // check whether arg is reassembled | ||
6265 | // do some workaround for pipe expression | ||
6266 | if (ast_is<Exp_t>(arg)) { | ||
6267 | auto exp = static_cast<Exp_t*>(arg); | ||
6268 | BLOCK_START | ||
6269 | BREAK_IF(!exp->opValues.empty()); | ||
6270 | auto chainValue = exp->get_by_path<UnaryExp_t, Value_t, ChainValue_t>(); | ||
6271 | BREAK_IF(!chainValue); | ||
6272 | BREAK_IF(!isMacroChain(chainValue)); | ||
6273 | str = std::get<1>(expandMacroStr(chainValue)); | ||
6274 | BLOCK_END | ||
6275 | } | ||
6276 | } | ||
6277 | if (!rawString && str.empty()) { | ||
6278 | str = YueFormat{}.toString(arg); | ||
6279 | } | ||
6280 | Utils::trim(str); | ||
6281 | Utils::replace(str, "\r\n"sv, "\n"sv); | ||
6282 | argStrs.push_back(str); | ||
6283 | } | ||
6284 | } | ||
6285 | } | ||
6221 | lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macroName | 6286 | lua_pushlstring(L, macroName.c_str(), macroName.size()); // cur macroName |
6222 | lua_rawget(L, -2); // cur[macroName], cur macroFunc | 6287 | lua_rawget(L, -2); // cur[macroName], cur macroFunc |
6223 | if (lua_isfunction(L, -1) == 0) { | 6288 | if (!lua_isfunction(L, -1)) { |
6224 | auto code = expandBuiltinMacro(macroName, x); | 6289 | auto code = expandBuiltinMacro(macroName, x); |
6225 | if (!code.empty()) return code; | 6290 | if (!code.empty()) return code; |
6226 | throw CompileError("can not resolve macro"sv, x); | 6291 | if (macroName == "is_ast"sv) { |
6292 | if (!argStrs.empty() && args && !args->empty()) { | ||
6293 | if (!_parser.hasAST(argStrs.front())) { | ||
6294 | throw CompileError("invalid AST name"sv, args->front()); | ||
6295 | } else { | ||
6296 | argStrs.front() = '"' + argStrs.front() + '"'; | ||
6297 | } | ||
6298 | } | ||
6299 | lua_pop(L, 1); // cur | ||
6300 | auto res = "yue.is_ast("s + join(argStrs, ","sv) + ')'; | ||
6301 | lua_pushlstring(L, res.c_str(), res.size()); // cur res | ||
6302 | return std::nullopt; | ||
6303 | } else { | ||
6304 | throw CompileError("can not resolve macro"sv, x); | ||
6305 | } | ||
6227 | } // cur macroFunc | 6306 | } // cur macroFunc |
6228 | pushYue("pcall"sv); // cur macroFunc pcall | 6307 | pushYue("pcall"sv); // cur macroFunc pcall |
6229 | lua_insert(L, -2); // cur pcall macroFunc | 6308 | lua_insert(L, -2); // cur pcall macroFunc |
6230 | const node_container* args = nullptr; | 6309 | for (const auto& arg : argStrs) { |
6231 | if (chainList.size() > 1) { | 6310 | lua_pushlstring(L, arg.c_str(), arg.size()); |
6232 | auto item = *(++chainList.begin()); | 6311 | } // cur pcall macroFunc args... |
6233 | if (auto invoke = ast_cast<Invoke_t>(item)) { | 6312 | bool success = lua_pcall(L, static_cast<int>(argStrs.size()), 1, 0) == 0; |
6234 | args = &invoke->args.objects(); | ||
6235 | } else if (auto invoke = ast_cast<InvokeArgs_t>(item)) { | ||
6236 | args = &invoke->args.objects(); | ||
6237 | } | ||
6238 | } | ||
6239 | if (args) { | ||
6240 | for (auto arg : *args) { | ||
6241 | std::string str; | ||
6242 | bool rawString = false; | ||
6243 | if (auto lstr = ast_cast<LuaString_t>(arg)) { | ||
6244 | str = _parser.toString(lstr->content); | ||
6245 | rawString = true; | ||
6246 | } else { | ||
6247 | BLOCK_START | ||
6248 | auto exp = ast_cast<Exp_t>(arg); | ||
6249 | BREAK_IF(!exp); | ||
6250 | auto value = singleValueFrom(exp); | ||
6251 | BREAK_IF(!value); | ||
6252 | auto lstr = value->get_by_path<String_t, LuaString_t>(); | ||
6253 | BREAK_IF(!lstr); | ||
6254 | str = _parser.toString(lstr->content); | ||
6255 | rawString = true; | ||
6256 | BLOCK_END | ||
6257 | } | ||
6258 | if (!rawString && str.empty()) { | ||
6259 | // check whether arg is reassembled | ||
6260 | // do some workaround for pipe expression | ||
6261 | if (ast_is<Exp_t>(arg)) { | ||
6262 | auto exp = static_cast<Exp_t*>(arg); | ||
6263 | BLOCK_START | ||
6264 | BREAK_IF(!exp->opValues.empty()); | ||
6265 | auto chainValue = exp->get_by_path<UnaryExp_t, Value_t, ChainValue_t>(); | ||
6266 | BREAK_IF(!chainValue); | ||
6267 | BREAK_IF(!isMacroChain(chainValue)); | ||
6268 | str = std::get<1>(expandMacroStr(chainValue)); | ||
6269 | BLOCK_END | ||
6270 | } | ||
6271 | } | ||
6272 | if (!rawString && str.empty()) { | ||
6273 | str = YueFormat{}.toString(arg); | ||
6274 | } | ||
6275 | Utils::trim(str); | ||
6276 | Utils::replace(str, "\r\n"sv, "\n"sv); | ||
6277 | lua_pushlstring(L, str.c_str(), str.size()); | ||
6278 | } // cur pcall macroFunc args... | ||
6279 | } | ||
6280 | bool success = lua_pcall(L, (args ? static_cast<int>(args->size()) : 0), 1, 0) == 0; | ||
6281 | if (!success) { // cur err | 6313 | if (!success) { // cur err |
6282 | std::string err = lua_tostring(L, -1); | 6314 | std::string err = lua_tostring(L, -1); |
6283 | throw CompileError("failed to expand macro: "s + err, x); | 6315 | throw CompileError("failed to expand macro: "s + err, x); |
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index 83aba40..e5337b0 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp | |||
@@ -1109,6 +1109,10 @@ std::string YueParser::toString(input::iterator begin, input::iterator end) { | |||
1109 | return _converter.to_bytes(std::wstring(begin, end)); | 1109 | return _converter.to_bytes(std::wstring(begin, end)); |
1110 | } | 1110 | } |
1111 | 1111 | ||
1112 | bool YueParser::hasAST(std::string_view name) const { | ||
1113 | return _rules.find(name) != _rules.end(); | ||
1114 | } | ||
1115 | |||
1112 | YueParser& YueParser::shared() { | 1116 | YueParser& YueParser::shared() { |
1113 | thread_local static YueParser parser; | 1117 | thread_local static YueParser parser; |
1114 | return parser; | 1118 | return parser; |
diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h index 3c50602..971efb3 100644 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h | |||
@@ -96,6 +96,8 @@ public: | |||
96 | std::string toString(ast_node* node); | 96 | std::string toString(ast_node* node); |
97 | std::string toString(input::iterator begin, input::iterator end); | 97 | std::string toString(input::iterator begin, input::iterator end); |
98 | 98 | ||
99 | bool hasAST(std::string_view name) const; | ||
100 | |||
99 | static YueParser& shared(); | 101 | static YueParser& shared(); |
100 | 102 | ||
101 | protected: | 103 | protected: |