diff options
author | Li Jin <dragon-fly@qq.com> | 2025-01-31 01:02:59 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2025-01-31 01:02:59 +0800 |
commit | f5c1735262f07f8064575bebec8b593559abe619 (patch) | |
tree | c0e3d660e647843c37df451e4028ec5590edb8e2 | |
parent | cf91f61990babdd8a80774809e9e860a155e4201 (diff) | |
download | yuescript-f5c1735262f07f8064575bebec8b593559abe619.tar.gz yuescript-f5c1735262f07f8064575bebec8b593559abe619.tar.bz2 yuescript-f5c1735262f07f8064575bebec8b593559abe619.zip |
Fixing issue #178.
-rwxr-xr-x | doc/docs/doc/README.md | 6 | ||||
-rwxr-xr-x | doc/docs/zh/doc/README.md | 6 | ||||
-rw-r--r-- | spec/inputs/macro.yue | 9 | ||||
-rw-r--r-- | spec/outputs/macro.lua | 11 | ||||
-rw-r--r-- | src/yuescript/yue_ast.cpp | 3 | ||||
-rw-r--r-- | src/yuescript/yue_ast.h | 6 | ||||
-rw-r--r-- | src/yuescript/yue_compiler.cpp | 86 | ||||
-rw-r--r-- | src/yuescript/yue_parser.cpp | 2 | ||||
-rw-r--r-- | src/yuescript/yue_parser.h | 1 |
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 |
279 | funcA = -> "fail to assign to the Yue defined variable" | 279 | funcA = -> "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 |
283 | macro luaFunc = (var) -> { | 283 | macro 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 |
289 | funcB = -> "assign to the Lua defined variable" | 288 | funcB = -> "assign to the Lua defined variable" |
@@ -307,12 +306,11 @@ macro yueFunc = (var) -> "local #{var} = ->" | |||
307 | $yueFunc funcA | 306 | $yueFunc funcA |
308 | funcA = -> "fail to assign to the Yue defined variable" | 307 | funcA = -> "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 |
312 | macro luaFunc = (var) -> { | 311 | macro 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 |
318 | funcB = -> "assign to the Lua defined variable" | 316 | funcB = -> "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 |
278 | funcA = -> "无法访问宏生成月之脚本里定义的变量" | 278 | funcA = -> "无法访问宏生成月之脚本里定义的变量" |
279 | 279 | ||
280 | -- 让月之脚本知道你在Lua代码中声明的局部变量 | 280 | -- 月之脚本会知道你在 Lua 代码中声明的局部变量 |
281 | macro luaFunc = (var) -> { | 281 | macro 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 |
287 | funcB = -> "访问宏生成Lua代码里定义的变量" | 286 | funcB = -> "访问宏生成Lua代码里定义的变量" |
@@ -305,11 +304,10 @@ macro yueFunc = (var) -> "local #{var} = ->" | |||
305 | $yueFunc funcA | 304 | $yueFunc funcA |
306 | funcA = -> "无法访问宏生成月之脚本里定义的变量" | 305 | funcA = -> "无法访问宏生成月之脚本里定义的变量" |
307 | 306 | ||
308 | -- 让月之脚本知道你在Lua代码中声明的局部变量 | 307 | -- 月之脚本会知道你在 Lua 代码中声明的局部变量 |
309 | macro luaFunc = (var) -> { | 308 | macro 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 |
315 | funcB = -> "访问宏生成Lua代码里定义的变量" | 313 | funcB = -> "访问宏生成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 | ||
343 | do | ||
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 | |||
343 | macro implicitReturnMacroIsAllowed = -> "print 'abc'\n123" | 352 | macro 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 |
331 | end | 331 | end |
332 | do | 332 | do |
333 | f = function() | ||
334 | x = (tb:func(123)):bar(456) | ||
335 | return (tb:func(123)) | ||
336 | end | ||
337 | local f1 | ||
338 | f1 = function() | ||
339 | tb:func(123) | ||
340 | return | ||
341 | end | ||
342 | end | ||
343 | do | ||
333 | print('abc') | 344 | print('abc') |
334 | return 123 | 345 | return 123 |
335 | end | 346 | end |
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 { | |||
167 | std::string TableAppendingOp_t::to_string(void*) const { | 167 | std::string TableAppendingOp_t::to_string(void*) const { |
168 | return "[]"s; | 168 | return "[]"s; |
169 | } | 169 | } |
170 | std::string PlainItem_t::to_string(void *) const { | ||
171 | return {}; | ||
172 | } | ||
170 | std::string GlobalOp_t::to_string(void* ud) const { | 173 | std::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) | |||
635 | AST_LEAF(TableAppendingOp) | 635 | AST_LEAF(TableAppendingOp) |
636 | AST_END(TableAppendingOp) | 636 | AST_END(TableAppendingOp) |
637 | 637 | ||
638 | AST_LEAF(PlainItem) | ||
639 | AST_END(PlainItem) | ||
640 | |||
638 | AST_NODE(ChainValue) | 641 | AST_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) |
642 | AST_END(ChainValue) | 646 | AST_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 | ||
25 | extern "C" { | 25 | extern "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); |