aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2024-08-09 11:35:27 +0800
committerLi Jin <dragon-fly@qq.com>2024-08-09 11:35:32 +0800
commitf2b63cb849ea2f7ef571b82e7927cd4abef4414b (patch)
treec3277a22a76815fa8ec3d7f9909bf950c26e2dc7 /src
parentb6c86d19d74ac90a2450cf979a92187e691ea5fa (diff)
downloadyuescript-f2b63cb849ea2f7ef571b82e7927cd4abef4414b.tar.gz
yuescript-f2b63cb849ea2f7ef571b82e7927cd4abef4414b.tar.bz2
yuescript-f2b63cb849ea2f7ef571b82e7927cd4abef4414b.zip
add builtin macro $is_ast().
Diffstat (limited to 'src')
-rw-r--r--src/yuescript/parser.cpp20
-rw-r--r--src/yuescript/yue_compiler.cpp152
-rw-r--r--src/yuescript/yue_parser.cpp4
-rw-r--r--src/yuescript/yue_parser.h2
4 files changed, 108 insertions, 70 deletions
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
21namespace parserlib { 27namespace 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)
907bool _context::parse_non_term(rule& r) { 913bool _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) {
1004bool _context::parse_term(rule& r) { 1007bool _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
1112bool YueParser::hasAST(std::string_view name) const {
1113 return _rules.find(name) != _rules.end();
1114}
1115
1112YueParser& YueParser::shared() { 1116YueParser& 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
101protected: 103protected: