From 1fa4049fc55986af8615ea836a60ac8cae255ad6 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Sun, 12 Jun 2022 00:16:35 +0800 Subject: fix issue #105. --- spec/inputs/with.yue | 14 ++++++++++++++ spec/outputs/with.lua | 26 ++++++++++++++++++++++++++ src/yuescript/yue_ast.h | 9 +++++++-- src/yuescript/yue_compiler.cpp | 31 ++++++++++++++++++++++++++----- src/yuescript/yue_parser.cpp | 23 ++++++++++++----------- src/yuescript/yue_parser.h | 3 ++- 6 files changed, 87 insertions(+), 19 deletions(-) diff --git a/spec/inputs/with.yue b/spec/inputs/with.yue index fe140ac..6f3e3ba 100644 --- a/spec/inputs/with.yue +++ b/spec/inputs/with.yue @@ -122,6 +122,20 @@ do .if "yes" y = .end.of.function +do + with tb + [1] = [2]?\func! + ["%a-b-c%"] = 123 + [ [[x y z]]] = [var] + print [ [3]] + with [4] + [1] = 1 + [] = "abc" + [] = + type: "hello" + * name: "xyz" + value: 998 + do global mask with? mask = SolidRect width: w, height: h, color: 0x66000000 diff --git a/spec/outputs/with.lua b/spec/outputs/with.lua index f172b01..9dcaca3 100644 --- a/spec/outputs/with.lua +++ b/spec/outputs/with.lua @@ -163,6 +163,32 @@ do local y = _with_0["end"].of["function"] end end +do + do + local _with_0 = tb + do + local _obj_0 = _with_0[2] + if _obj_0 ~= nil then + _with_0[1] = _obj_0:func() + end + end + _with_0["%a-b-c%"] = 123 + _with_0[ [[x y z]]] = _with_0[var] + print(_with_0[_with_0[3]]) + do + local _with_1 = _with_0[4] + _with_1[1] = 1 + end + _with_0[#_with_0 + 1] = "abc" + _with_0[#_with_0 + 1] = { + type = "hello", + { + name = "xyz", + value = 998 + } + } + end +end do do local _with_0 = SolidRect({ diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index 38e97ad..571c18e 100755 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h @@ -197,6 +197,11 @@ AST_NODE(Goto) AST_MEMBER(Goto, &label) AST_END(Goto, "goto"sv) +AST_NODE(ShortTabAppending) + ast_ptr assign; + AST_MEMBER(ShortTabAppending, &assign) +AST_END(ShortTabAppending, "short_table_appending"sv) + class FnArgsDef_t; AST_LEAF(fn_arrow_back) @@ -804,8 +809,8 @@ AST_END(statement_sep, "statement_sep"sv) AST_NODE(Statement) ast_sel content; + BreakLoop_t, Label_t, Goto_t, ShortTabAppending_t, + Backcall_t, LocalAttrib_t, PipeBody_t, ExpListAssign_t> content; ast_ptr appendix; ast_ptr needSep; AST_MEMBER(Statement, &content, &appendix, &needSep) diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index d270455..8535b43 100755 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp @@ -56,7 +56,7 @@ using namespace parserlib; typedef std::list str_list; -const std::string_view version = "0.11.0"sv; +const std::string_view version = "0.11.1"sv; const std::string_view extension = "yue"sv; class YueCompilerImpl { @@ -806,8 +806,10 @@ private: case id(): return true; } - } else if (firstItem->getId() == id()) { - return true; + } else switch (firstItem->getId()) { + case id(): + case id(): + return true; } } else { if (std::find_if(chainItems.begin(), chainItems.end(), [](ast_node* node) { @@ -1055,6 +1057,7 @@ private: case id(): transformBreakLoop(static_cast(content), out); break; case id(): transformLabel(static_cast(content), out); break; case id(): transformGoto(static_cast(content), out); break; + case id(): transformShortTabAppending(static_cast(content), out); break; case id(): transformLocalAttrib(static_cast(content), out); break; case id(): throw std::logic_error(_info.errorMessage("pipe chain must be following a value"sv, x)); break; case id(): { @@ -1278,6 +1281,13 @@ private: temp.push_back(clearBuf()); } else if (ast_is(chainValue->items.back())) { chainValue->items.pop_back(); + if (chainValue->items.empty()) { + if (_withVars.empty()) { + throw std::logic_error(_info.errorMessage("short table appending must be called within a with block"sv, x)); + } else { + chainValue->items.push_back(toAst(_withVars.top(), chainValue)); + } + } auto varName = singleVariableFrom(chainValue); bool isScoped = false; if (varName.empty() || !isLocal(varName)) { @@ -3797,6 +3807,7 @@ private: switch (chainList.front()->getId()) { case id(): case id(): + case id(): if (_withVars.empty()) { throw std::logic_error(_info.errorMessage("short dot/colon syntax must be called within a with block"sv, chainList.front())); } else { @@ -3943,8 +3954,9 @@ private: switch (x->getId()) { case id(): case id(): + case id(): if (_withVars.empty()) { - throw std::logic_error(_info.errorMessage("short dot/colon syntax must be called within a with block"sv, x)); + throw std::logic_error(_info.errorMessage("short dot/colon and indexing syntax must be called within a with block"sv, x)); } else { temp.push_back(_withVars.top()); } @@ -4440,7 +4452,7 @@ private: void transformChainValue(ChainValue_t* chainValue, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr, bool allowBlockMacroReturn = false) { if (isMacroChain(chainValue)) { #ifndef YUE_NO_MACRO - ast_ptr node; + ast_ptr node; std::unique_ptr codes; std::string luaCodes; str_list localVars; @@ -7181,6 +7193,15 @@ private: void transformGoto(Goto_t* gotoNode, str_list& out) { out.push_back(indent() + "goto "s + _parser.toString(gotoNode->label) + nll(gotoNode)); } + + void transformShortTabAppending(ShortTabAppending_t* tab, str_list& out) { + if (_withVars.empty()) { + throw std::logic_error(_info.errorMessage("short table appending syntax must be called within a with block"sv, tab)); + } + auto assignment = toAst(_withVars.top() + "[]=nil"s, tab); + assignment->action.set(tab->assign); + transformAssignment(assignment, out); + } }; const std::string YueCompilerImpl::Empty; diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index 54dd174..5c42963 100755 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp @@ -216,6 +216,8 @@ YueParser::YueParser() { Goto = key("goto") >> Space >> LabelName; + ShortTabAppending = expr("[]") >> Assign; + BreakLoop = (expr("break") | expr("continue")) >> not_(AlphaNum); Return = key("return") >> -(TableBlock | ExpListLow); @@ -335,7 +337,7 @@ YueParser::YueParser() { Update = Space >> update_op >> expr("=") >> Exp; - Assignable = AssignableChain | Space >> Variable | Space >> SelfName; + Assignable = Space >> (AssignableChain | Variable | SelfName); unary_value = unary_operator >> *(Space >> unary_operator) >> Value; @@ -382,16 +384,16 @@ YueParser::YueParser() { return true; }); - chain_line = CheckIndent >> (chain_item | Space >> (chain_dot_chain | ColonChain)) >> -InvokeArgs; + chain_line = CheckIndent >> Space >> (chain_dot_chain | ColonChain) >> -InvokeArgs; chain_block = pl::user(true_(), [](const item_t& item) { State* st = reinterpret_cast(item.user_data); return st->noChainBlockStack.empty() || !st->noChainBlockStack.top(); }) >> +SpaceBreak >> Advance >> ensure( chain_line >> *(+SpaceBreak >> chain_line), PopIndent); - ChainValue = Seperator >> (Chain | Callable) >> -existential_op >> -(InvokeArgs | chain_block) >> -table_appending_op; + ChainValue = Space >> Seperator >> (Chain | Callable) >> -existential_op >> -(InvokeArgs | chain_block) >> -table_appending_op; simple_table = Seperator >> KeyValue >> *(sym(',') >> KeyValue); - Value = SimpleValue | simple_table | ChainValue | String; + Value = SimpleValue | simple_table | ChainValue | Space >> String; single_string_inner = expr("\\'") | "\\\\" | not_(expr('\'')) >> Any; SingleString = symx('\'') >> *single_string_inner >> symx('\''); @@ -400,7 +402,7 @@ YueParser::YueParser() { double_string_inner = +(not_(interp) >> double_string_plain); double_string_content = double_string_inner | interp; DoubleString = symx('"') >> Seperator >> *double_string_content >> symx('"'); - String = Space >> (DoubleString | SingleString | LuaString); + String = DoubleString | SingleString | LuaString; lua_string_open = '[' >> *expr('=') >> '['; lua_string_close = ']' >> *expr('=') >> ']'; @@ -423,7 +425,7 @@ YueParser::YueParser() { LuaString = LuaStringOpen >> -Break >> LuaStringContent >> LuaStringClose; Parens = symx('(') >> *SpaceBreak >> Exp >> *SpaceBreak >> sym(')'); - Callable = Space >> (Variable | SelfName | MacroName | VarArg | Parens); + Callable = Variable | SelfName | MacroName | VarArg | Parens; FnArgsExpList = Exp >> *((Break | sym(',')) >> White >> Exp); FnArgs = (symx('(') >> *SpaceBreak >> -FnArgsExpList >> *SpaceBreak >> sym(')')) | @@ -435,11 +437,10 @@ YueParser::YueParser() { existential_op = expr('?') >> not_(expr('?')); table_appending_op = expr("[]"); chain_call = (Callable | String) >> -existential_op >> ChainItems; - chain_item = and_(set(".\\")) >> ChainItems; + chain_index_chain = Index >> -existential_op >> -ChainItems; chain_dot_chain = DotChainItem >> -existential_op >> -ChainItems; - Chain = chain_call | chain_item | - Space >> (chain_dot_chain | ColonChain); + Chain = chain_call | chain_dot_chain | ColonChain | chain_index_chain; AssignableChain = Seperator >> Chain; @@ -631,8 +632,8 @@ YueParser::YueParser() { Statement = Space >> ( Import | While | Repeat | For | ForEach | Return | Local | Global | Export | Macro | - MacroInPlace | BreakLoop | Label | Goto | LocalAttrib | - Backcall | PipeBody | ExpListAssign + MacroInPlace | BreakLoop | Label | Goto | ShortTabAppending | + LocalAttrib | Backcall | PipeBody | ExpListAssign ) >> Space >> -statement_appendix >> -statement_sep; diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h index 159bbca..1532adf 100755 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h @@ -158,7 +158,7 @@ private: rule FnArgs; rule macro_args_def; rule chain_call; - rule chain_item; + rule chain_index_chain; rule ChainItems; rule chain_dot_chain; rule ColonChain; @@ -220,6 +220,7 @@ private: AST_RULE(Import) AST_RULE(Label) AST_RULE(Goto) + AST_RULE(ShortTabAppending) AST_RULE(fn_arrow_back) AST_RULE(Backcall) AST_RULE(PipeBody) -- cgit v1.2.3-55-g6feb