From f5c1735262f07f8064575bebec8b593559abe619 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Fri, 31 Jan 2025 01:02:59 +0800 Subject: Fixing issue #178. --- src/yuescript/yue_ast.cpp | 3 ++ src/yuescript/yue_ast.h | 6 ++- src/yuescript/yue_compiler.cpp | 86 +++++++++++++++++++++++++++++------------- src/yuescript/yue_parser.cpp | 2 + src/yuescript/yue_parser.h | 1 + 5 files changed, 70 insertions(+), 28 deletions(-) (limited to 'src') diff --git a/src/yuescript/yue_ast.cpp b/src/yuescript/yue_ast.cpp index 3dac699..fe6e726 100644 --- a/src/yuescript/yue_ast.cpp +++ b/src/yuescript/yue_ast.cpp @@ -167,6 +167,9 @@ std::string ExistentialOp_t::to_string(void*) const { std::string TableAppendingOp_t::to_string(void*) const { return "[]"s; } +std::string PlainItem_t::to_string(void *) const { + return {}; +} std::string GlobalOp_t::to_string(void* ud) const { auto info = reinterpret_cast(ud); return info->convert(this); diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index 139f4b3..e670126 100644 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h @@ -635,9 +635,13 @@ AST_END(ExistentialOp) AST_LEAF(TableAppendingOp) AST_END(TableAppendingOp) +AST_LEAF(PlainItem) +AST_END(PlainItem) + AST_NODE(ChainValue) ast_ptr sep; - ast_sel_list items; + ast_sel_list items; AST_MEMBER(ChainValue, &sep, &items) AST_END(ChainValue) diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 369f7e8..446414d 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp @@ -24,6 +24,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI extern "C" { #include "lauxlib.h" +#include "lparser.h" #include "lua.h" #include "lualib.h" } // extern "C" @@ -6272,6 +6273,9 @@ private: case id(): transform_table_appending_op(static_cast(item), temp); break; + case id(): + temp.push_back(_parser.toString(item)); + break; default: YUEE("AST node mismatch", item); break; } } @@ -6519,24 +6523,26 @@ private: throw CompileError("macro table must contain field \"type\" of value \"lua\" or \"text\""sv, x); } lua_pop(L, 1); // cur tab - lua_getfield(L, -1, "locals"); // cur tab locals - if (lua_istable(L, -1) != 0) { - for (int i = 0; i < static_cast(lua_objlen(L, -1)); i++) { - lua_rawgeti(L, -1, i + 1); // cur tab locals item - size_t len = 0; - if (lua_isstring(L, -1) == 0) { - throw CompileError("macro table field \"locals\" must be a table of strings"sv, x); - } - auto name = lua_tolstring(L, -1, &len); - if (auto varNode = toAst({name, len}, x)) { - localVars.push_back(variableToString(varNode)); - } else { - throw CompileError("macro table field \"locals\" must contain names for local variables, got \""s + std::string(name, len) + '"', x); + if (type == "text"sv) { + lua_getfield(L, -1, "locals"); // cur tab locals + if (lua_istable(L, -1) != 0) { + for (int i = 0; i < static_cast(lua_objlen(L, -1)); i++) { + lua_rawgeti(L, -1, i + 1); // cur tab locals item + size_t len = 0; + if (lua_isstring(L, -1) == 0) { + throw CompileError("macro table field \"locals\" must be a table of strings"sv, x); + } + auto name = lua_tolstring(L, -1, &len); + if (auto varNode = toAst({name, len}, x)) { + localVars.push_back(variableToString(varNode)); + } else { + throw CompileError("macro table field \"locals\" must contain names for local variables, got \""s + std::string(name, len) + '"', x); + } + lua_pop(L, 1); // cur tab locals } - lua_pop(L, 1); // cur tab locals } + lua_pop(L, 1); // cur tab } - lua_pop(L, 1); // cur tab } else { // cur code codes = lua_tostring(L, -1); } @@ -6554,23 +6560,49 @@ private: bool isBlock = (usage == ExpUsage::Common) && (chainList.size() < 2 || (chainList.size() == 2 && ast_is(chainList.back()))); ParseInfo info; if (type == "lua"sv) { - if (!isBlock) { - throw CompileError("lua macro can only be placed where block macro is allowed"sv, x); - } auto macroChunk = "=(macro "s + _parser.toString(x->name) + ')'; int top = lua_gettop(L); DEFER(lua_settop(L, top)); - if (luaL_loadbuffer(L, codes.c_str(), codes.size(), macroChunk.c_str()) != 0) { - std::string err = lua_tostring(L, -1); - throw CompileError(err, x); - } - if (!codes.empty()) { - if (_config.reserveLineNumber) { - codes.insert(0, nll(chainValue).substr(1)); + if (isBlock) { + if (luaL_loadbuffer(L, codes.c_str(), codes.size(), macroChunk.c_str()) != 0) { + std::string err = lua_tostring(L, -1); + throw CompileError("lua macro is not expanding to valid block\n"s + err, x); + } else { + Proto* f = ((LClosure*)lua_topointer(L, -1))->p; + for (int i = 0; i < f->sizelocvars; i++) { + localVars.push_back(getstr(f->locvars[i].varname)); + } + } + if (!codes.empty()) { + if (_config.reserveLineNumber) { + codes.insert(0, nll(chainValue).substr(1)); + } + codes.append(nlr(chainValue)); } - codes.append(nlr(chainValue)); + return {nullptr, nullptr, std::move(codes), std::move(localVars)}; + } else { + auto expCode = "return ("s + codes + ')'; + if (luaL_loadbuffer(L, expCode.c_str(), expCode.size(), macroChunk.c_str()) != 0) { + std::string err = lua_tostring(L, -1); + throw CompileError("lua macro is not expanding to valid expression\n"s + err, x); + } + Utils::trim(codes); + codes = '(' + codes + ')'; + auto plainItem = toAst(codes, x); + auto newChain = x->new_ptr(); + newChain->items.push_back(plainItem); + ast_ptr exp; + exp.set(newExp(newChain, x)); + if (chainList.size() > 2 || (chainList.size() == 2 && !ast_is(chainList.back()))) { + auto it = chainList.begin(); + it++; + if (chainList.size() > 1 && ast_is(*it)) it++; + for (; it != chainList.end(); ++it) { + newChain->items.push_back(*it); + } + } + return {exp, nullptr, Empty, std::move(localVars)}; } - return {nullptr, nullptr, std::move(codes), std::move(localVars)}; } else if (type == "text"sv) { if (!isBlock) { throw CompileError("text macro can only be placed where block macro is allowed"sv, x); diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index ef242ea..5993ed5 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp @@ -653,6 +653,8 @@ YueParser::YueParser() { ExistentialOp = '?' >> not_('?'); TableAppendingOp = and_('[') >> ("[]" | brackets_expression_error); + PlainItem = +any_char; + chain_call = ( Callable >> -ExistentialOp >> -chain_items ) | ( diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h index f18cc1b..02292e1 100644 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h @@ -381,6 +381,7 @@ private: AST_RULE(Invoke); AST_RULE(ExistentialOp); AST_RULE(TableAppendingOp); + AST_RULE(PlainItem); AST_RULE(SpreadExp); AST_RULE(SpreadListExp); AST_RULE(TableLit); -- cgit v1.2.3-55-g6feb