aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2025-01-31 01:02:59 +0800
committerLi Jin <dragon-fly@qq.com>2025-01-31 01:02:59 +0800
commitf5c1735262f07f8064575bebec8b593559abe619 (patch)
treec0e3d660e647843c37df451e4028ec5590edb8e2
parentcf91f61990babdd8a80774809e9e860a155e4201 (diff)
downloadyuescript-f5c1735262f07f8064575bebec8b593559abe619.tar.gz
yuescript-f5c1735262f07f8064575bebec8b593559abe619.tar.bz2
yuescript-f5c1735262f07f8064575bebec8b593559abe619.zip
Fixing issue #178.
-rwxr-xr-xdoc/docs/doc/README.md6
-rwxr-xr-xdoc/docs/zh/doc/README.md6
-rw-r--r--spec/inputs/macro.yue9
-rw-r--r--spec/outputs/macro.lua11
-rw-r--r--src/yuescript/yue_ast.cpp3
-rw-r--r--src/yuescript/yue_ast.h6
-rw-r--r--src/yuescript/yue_compiler.cpp86
-rw-r--r--src/yuescript/yue_parser.cpp2
-rw-r--r--src/yuescript/yue_parser.h1
9 files changed, 94 insertions, 36 deletions
diff --git a/doc/docs/doc/README.md b/doc/docs/doc/README.md
index 56d3635..e1ba56e 100755
--- a/doc/docs/doc/README.md
+++ b/doc/docs/doc/README.md
@@ -278,12 +278,11 @@ macro yueFunc = (var) -> "local #{var} = ->"
278$yueFunc funcA 278$yueFunc funcA
279funcA = -> "fail to assign to the Yue defined variable" 279funcA = -> "fail to assign to the Yue defined variable"
280 280
281-- take care and let YueScript know the 281-- YueScript knows the
282-- local variables you declared in Lua code 282-- local variables you declared in Lua code
283macro luaFunc = (var) -> { 283macro luaFunc = (var) -> {
284 code: "local function #{var}() end" 284 code: "local function #{var}() end"
285 type: "lua" 285 type: "lua"
286 locals: {var}
287} 286}
288$luaFunc funcB 287$luaFunc funcB
289funcB = -> "assign to the Lua defined variable" 288funcB = -> "assign to the Lua defined variable"
@@ -307,12 +306,11 @@ macro yueFunc = (var) -> "local #{var} = ->"
307$yueFunc funcA 306$yueFunc funcA
308funcA = -> "fail to assign to the Yue defined variable" 307funcA = -> "fail to assign to the Yue defined variable"
309 308
310-- take care and let YueScript know the 309-- YueScript knows the
311-- local variables you declared in Lua codes 310-- local variables you declared in Lua codes
312macro luaFunc = (var) -> { 311macro luaFunc = (var) -> {
313 code: "local function #{var}() end" 312 code: "local function #{var}() end"
314 type: "lua" 313 type: "lua"
315 locals: {var}
316} 314}
317$luaFunc funcB 315$luaFunc funcB
318funcB = -> "assign to the Lua defined variable" 316funcB = -> "assign to the Lua defined variable"
diff --git a/doc/docs/zh/doc/README.md b/doc/docs/zh/doc/README.md
index 0e5b532..5e28122 100755
--- a/doc/docs/zh/doc/README.md
+++ b/doc/docs/zh/doc/README.md
@@ -277,11 +277,10 @@ macro yueFunc = (var) -> "local #{var} = ->"
277$yueFunc funcA 277$yueFunc funcA
278funcA = -> "无法访问宏生成月之脚本里定义的变量" 278funcA = -> "无法访问宏生成月之脚本里定义的变量"
279 279
280-- 月之脚本知道你在Lua代码中声明的局部变量 280-- 月之脚本知道你在 Lua 代码中声明的局部变量
281macro luaFunc = (var) -> { 281macro luaFunc = (var) -> {
282 code: "local function #{var}() end" 282 code: "local function #{var}() end"
283 type: "lua" 283 type: "lua"
284 locals: {var}
285} 284}
286$luaFunc funcB 285$luaFunc funcB
287funcB = -> "访问宏生成Lua代码里定义的变量" 286funcB = -> "访问宏生成Lua代码里定义的变量"
@@ -305,11 +304,10 @@ macro yueFunc = (var) -> "local #{var} = ->"
305$yueFunc funcA 304$yueFunc funcA
306funcA = -> "无法访问宏生成月之脚本里定义的变量" 305funcA = -> "无法访问宏生成月之脚本里定义的变量"
307 306
308-- 月之脚本知道你在Lua代码中声明的局部变量 307-- 月之脚本知道你在 Lua 代码中声明的局部变量
309macro luaFunc = (var) -> { 308macro luaFunc = (var) -> {
310 code: "local function #{var}() end" 309 code: "local function #{var}() end"
311 type: "lua" 310 type: "lua"
312 locals: {var}
313} 311}
314$luaFunc funcB 312$luaFunc funcB
315funcB = -> "访问宏生成Lua代码里定义的变量" 313funcB = -> "访问宏生成Lua代码里定义的变量"
diff --git a/spec/inputs/macro.yue b/spec/inputs/macro.yue
index 5dafd84..5d5f1a9 100644
--- a/spec/inputs/macro.yue
+++ b/spec/inputs/macro.yue
@@ -340,6 +340,15 @@ _1 = ->
340 print 2 340 print 2
341 print 3 341 print 3
342 342
343do
344 macro foo = -> code: "tb:func(123)", type: "lua"
345 f = ->
346 x = $foo\bar 456
347 $foo!
348 f1 = ->
349 $foo!
350 return
351
343macro implicitReturnMacroIsAllowed = -> "print 'abc'\n123" 352macro implicitReturnMacroIsAllowed = -> "print 'abc'\n123"
344 353
345$implicitReturnMacroIsAllowed 354$implicitReturnMacroIsAllowed
diff --git a/spec/outputs/macro.lua b/spec/outputs/macro.lua
index 83c6a90..7163077 100644
--- a/spec/outputs/macro.lua
+++ b/spec/outputs/macro.lua
@@ -330,6 +330,17 @@ _1 = function()
330 return _accum_0 330 return _accum_0
331end 331end
332do 332do
333 f = function()
334 x = (tb:func(123)):bar(456)
335 return (tb:func(123))
336 end
337 local f1
338 f1 = function()
339tb:func(123)
340 return
341 end
342end
343do
333 print('abc') 344 print('abc')
334 return 123 345 return 123
335end 346end
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 {
167std::string TableAppendingOp_t::to_string(void*) const { 167std::string TableAppendingOp_t::to_string(void*) const {
168 return "[]"s; 168 return "[]"s;
169} 169}
170std::string PlainItem_t::to_string(void *) const {
171 return {};
172}
170std::string GlobalOp_t::to_string(void* ud) const { 173std::string GlobalOp_t::to_string(void* ud) const {
171 auto info = reinterpret_cast<YueFormat*>(ud); 174 auto info = reinterpret_cast<YueFormat*>(ud);
172 return info->convert(this); 175 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)
635AST_LEAF(TableAppendingOp) 635AST_LEAF(TableAppendingOp)
636AST_END(TableAppendingOp) 636AST_END(TableAppendingOp)
637 637
638AST_LEAF(PlainItem)
639AST_END(PlainItem)
640
638AST_NODE(ChainValue) 641AST_NODE(ChainValue)
639 ast_ptr<true, Seperator_t> sep; 642 ast_ptr<true, Seperator_t> sep;
640 ast_sel_list<true, Callable_t, Invoke_t, DotChainItem_t, ColonChainItem_t, Slice_t, Exp_t, String_t, InvokeArgs_t, ExistentialOp_t, TableAppendingOp_t> items; 643 ast_sel_list<true, Callable_t, Invoke_t, DotChainItem_t, ColonChainItem_t, Slice_t, Exp_t, String_t, InvokeArgs_t, ExistentialOp_t, TableAppendingOp_t,
644 /*non-syntax-rule*/ PlainItem_t> items;
641 AST_MEMBER(ChainValue, &sep, &items) 645 AST_MEMBER(ChainValue, &sep, &items)
642AST_END(ChainValue) 646AST_END(ChainValue)
643 647
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
24 24
25extern "C" { 25extern "C" {
26#include "lauxlib.h" 26#include "lauxlib.h"
27#include "lparser.h"
27#include "lua.h" 28#include "lua.h"
28#include "lualib.h" 29#include "lualib.h"
29} // extern "C" 30} // extern "C"
@@ -6272,6 +6273,9 @@ private:
6272 case id<TableAppendingOp_t>(): 6273 case id<TableAppendingOp_t>():
6273 transform_table_appending_op(static_cast<TableAppendingOp_t*>(item), temp); 6274 transform_table_appending_op(static_cast<TableAppendingOp_t*>(item), temp);
6274 break; 6275 break;
6276 case id<PlainItem_t>():
6277 temp.push_back(_parser.toString(item));
6278 break;
6275 default: YUEE("AST node mismatch", item); break; 6279 default: YUEE("AST node mismatch", item); break;
6276 } 6280 }
6277 } 6281 }
@@ -6519,24 +6523,26 @@ private:
6519 throw CompileError("macro table must contain field \"type\" of value \"lua\" or \"text\""sv, x); 6523 throw CompileError("macro table must contain field \"type\" of value \"lua\" or \"text\""sv, x);
6520 } 6524 }
6521 lua_pop(L, 1); // cur tab 6525 lua_pop(L, 1); // cur tab
6522 lua_getfield(L, -1, "locals"); // cur tab locals 6526 if (type == "text"sv) {
6523 if (lua_istable(L, -1) != 0) { 6527 lua_getfield(L, -1, "locals"); // cur tab locals
6524 for (int i = 0; i < static_cast<int>(lua_objlen(L, -1)); i++) { 6528 if (lua_istable(L, -1) != 0) {
6525 lua_rawgeti(L, -1, i + 1); // cur tab locals item 6529 for (int i = 0; i < static_cast<int>(lua_objlen(L, -1)); i++) {
6526 size_t len = 0; 6530 lua_rawgeti(L, -1, i + 1); // cur tab locals item
6527 if (lua_isstring(L, -1) == 0) { 6531 size_t len = 0;
6528 throw CompileError("macro table field \"locals\" must be a table of strings"sv, x); 6532 if (lua_isstring(L, -1) == 0) {
6529 } 6533 throw CompileError("macro table field \"locals\" must be a table of strings"sv, x);
6530 auto name = lua_tolstring(L, -1, &len); 6534 }
6531 if (auto varNode = toAst<Variable_t>({name, len}, x)) { 6535 auto name = lua_tolstring(L, -1, &len);
6532 localVars.push_back(variableToString(varNode)); 6536 if (auto varNode = toAst<Variable_t>({name, len}, x)) {
6533 } else { 6537 localVars.push_back(variableToString(varNode));
6534 throw CompileError("macro table field \"locals\" must contain names for local variables, got \""s + std::string(name, len) + '"', x); 6538 } else {
6539 throw CompileError("macro table field \"locals\" must contain names for local variables, got \""s + std::string(name, len) + '"', x);
6540 }
6541 lua_pop(L, 1); // cur tab locals
6535 } 6542 }
6536 lua_pop(L, 1); // cur tab locals
6537 } 6543 }
6544 lua_pop(L, 1); // cur tab
6538 } 6545 }
6539 lua_pop(L, 1); // cur tab
6540 } else { // cur code 6546 } else { // cur code
6541 codes = lua_tostring(L, -1); 6547 codes = lua_tostring(L, -1);
6542 } 6548 }
@@ -6554,23 +6560,49 @@ private:
6554 bool isBlock = (usage == ExpUsage::Common) && (chainList.size() < 2 || (chainList.size() == 2 && ast_is<Invoke_t, InvokeArgs_t>(chainList.back()))); 6560 bool isBlock = (usage == ExpUsage::Common) && (chainList.size() < 2 || (chainList.size() == 2 && ast_is<Invoke_t, InvokeArgs_t>(chainList.back())));
6555 ParseInfo info; 6561 ParseInfo info;
6556 if (type == "lua"sv) { 6562 if (type == "lua"sv) {
6557 if (!isBlock) {
6558 throw CompileError("lua macro can only be placed where block macro is allowed"sv, x);
6559 }
6560 auto macroChunk = "=(macro "s + _parser.toString(x->name) + ')'; 6563 auto macroChunk = "=(macro "s + _parser.toString(x->name) + ')';
6561 int top = lua_gettop(L); 6564 int top = lua_gettop(L);
6562 DEFER(lua_settop(L, top)); 6565 DEFER(lua_settop(L, top));
6563 if (luaL_loadbuffer(L, codes.c_str(), codes.size(), macroChunk.c_str()) != 0) { 6566 if (isBlock) {
6564 std::string err = lua_tostring(L, -1); 6567 if (luaL_loadbuffer(L, codes.c_str(), codes.size(), macroChunk.c_str()) != 0) {
6565 throw CompileError(err, x); 6568 std::string err = lua_tostring(L, -1);
6566 } 6569 throw CompileError("lua macro is not expanding to valid block\n"s + err, x);
6567 if (!codes.empty()) { 6570 } else {
6568 if (_config.reserveLineNumber) { 6571 Proto* f = ((LClosure*)lua_topointer(L, -1))->p;
6569 codes.insert(0, nll(chainValue).substr(1)); 6572 for (int i = 0; i < f->sizelocvars; i++) {
6573 localVars.push_back(getstr(f->locvars[i].varname));
6574 }
6575 }
6576 if (!codes.empty()) {
6577 if (_config.reserveLineNumber) {
6578 codes.insert(0, nll(chainValue).substr(1));
6579 }
6580 codes.append(nlr(chainValue));
6570 } 6581 }
6571 codes.append(nlr(chainValue)); 6582 return {nullptr, nullptr, std::move(codes), std::move(localVars)};
6583 } else {
6584 auto expCode = "return ("s + codes + ')';
6585 if (luaL_loadbuffer(L, expCode.c_str(), expCode.size(), macroChunk.c_str()) != 0) {
6586 std::string err = lua_tostring(L, -1);
6587 throw CompileError("lua macro is not expanding to valid expression\n"s + err, x);
6588 }
6589 Utils::trim(codes);
6590 codes = '(' + codes + ')';
6591 auto plainItem = toAst<PlainItem_t>(codes, x);
6592 auto newChain = x->new_ptr<ChainValue_t>();
6593 newChain->items.push_back(plainItem);
6594 ast_ptr<false, ast_node> exp;
6595 exp.set(newExp(newChain, x));
6596 if (chainList.size() > 2 || (chainList.size() == 2 && !ast_is<Invoke_t, InvokeArgs_t>(chainList.back()))) {
6597 auto it = chainList.begin();
6598 it++;
6599 if (chainList.size() > 1 && ast_is<Invoke_t, InvokeArgs_t>(*it)) it++;
6600 for (; it != chainList.end(); ++it) {
6601 newChain->items.push_back(*it);
6602 }
6603 }
6604 return {exp, nullptr, Empty, std::move(localVars)};
6572 } 6605 }
6573 return {nullptr, nullptr, std::move(codes), std::move(localVars)};
6574 } else if (type == "text"sv) { 6606 } else if (type == "text"sv) {
6575 if (!isBlock) { 6607 if (!isBlock) {
6576 throw CompileError("text macro can only be placed where block macro is allowed"sv, x); 6608 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() {
653 653
654 ExistentialOp = '?' >> not_('?'); 654 ExistentialOp = '?' >> not_('?');
655 TableAppendingOp = and_('[') >> ("[]" | brackets_expression_error); 655 TableAppendingOp = and_('[') >> ("[]" | brackets_expression_error);
656 PlainItem = +any_char;
657
656 chain_call = ( 658 chain_call = (
657 Callable >> -ExistentialOp >> -chain_items 659 Callable >> -ExistentialOp >> -chain_items
658 ) | ( 660 ) | (
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:
381 AST_RULE(Invoke); 381 AST_RULE(Invoke);
382 AST_RULE(ExistentialOp); 382 AST_RULE(ExistentialOp);
383 AST_RULE(TableAppendingOp); 383 AST_RULE(TableAppendingOp);
384 AST_RULE(PlainItem);
384 AST_RULE(SpreadExp); 385 AST_RULE(SpreadExp);
385 AST_RULE(SpreadListExp); 386 AST_RULE(SpreadListExp);
386 AST_RULE(TableLit); 387 AST_RULE(TableLit);