diff options
author | Li Jin <dragon-fly@qq.com> | 2022-06-12 00:16:35 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2022-06-12 00:16:35 +0800 |
commit | 1fa4049fc55986af8615ea836a60ac8cae255ad6 (patch) | |
tree | ba2e35613b32ca3bd46f6d6ff932de2a457328ea | |
parent | 4350d4b094c2c7202b7ad79d15187c1402bd13eb (diff) | |
download | yuescript-1fa4049fc55986af8615ea836a60ac8cae255ad6.tar.gz yuescript-1fa4049fc55986af8615ea836a60ac8cae255ad6.tar.bz2 yuescript-1fa4049fc55986af8615ea836a60ac8cae255ad6.zip |
fix issue #105.
-rw-r--r-- | spec/inputs/with.yue | 14 | ||||
-rw-r--r-- | spec/outputs/with.lua | 26 | ||||
-rwxr-xr-x | src/yuescript/yue_ast.h | 9 | ||||
-rwxr-xr-x | src/yuescript/yue_compiler.cpp | 31 | ||||
-rwxr-xr-x | src/yuescript/yue_parser.cpp | 23 | ||||
-rwxr-xr-x | 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 | |||
@@ -123,6 +123,20 @@ do | |||
123 | y = .end.of.function | 123 | y = .end.of.function |
124 | 124 | ||
125 | do | 125 | do |
126 | with tb | ||
127 | [1] = [2]?\func! | ||
128 | ["%a-b-c%"] = 123 | ||
129 | [ [[x y z]]] = [var] | ||
130 | print [ [3]] | ||
131 | with [4] | ||
132 | [1] = 1 | ||
133 | [] = "abc" | ||
134 | [] = | ||
135 | type: "hello" | ||
136 | * name: "xyz" | ||
137 | value: 998 | ||
138 | |||
139 | do | ||
126 | global mask | 140 | global mask |
127 | with? mask = SolidRect width: w, height: h, color: 0x66000000 | 141 | with? mask = SolidRect width: w, height: h, color: 0x66000000 |
128 | .touchEnabled = true | 142 | .touchEnabled = true |
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 | |||
@@ -165,6 +165,32 @@ do | |||
165 | end | 165 | end |
166 | do | 166 | do |
167 | do | 167 | do |
168 | local _with_0 = tb | ||
169 | do | ||
170 | local _obj_0 = _with_0[2] | ||
171 | if _obj_0 ~= nil then | ||
172 | _with_0[1] = _obj_0:func() | ||
173 | end | ||
174 | end | ||
175 | _with_0["%a-b-c%"] = 123 | ||
176 | _with_0[ [[x y z]]] = _with_0[var] | ||
177 | print(_with_0[_with_0[3]]) | ||
178 | do | ||
179 | local _with_1 = _with_0[4] | ||
180 | _with_1[1] = 1 | ||
181 | end | ||
182 | _with_0[#_with_0 + 1] = "abc" | ||
183 | _with_0[#_with_0 + 1] = { | ||
184 | type = "hello", | ||
185 | { | ||
186 | name = "xyz", | ||
187 | value = 998 | ||
188 | } | ||
189 | } | ||
190 | end | ||
191 | end | ||
192 | do | ||
193 | do | ||
168 | local _with_0 = SolidRect({ | 194 | local _with_0 = SolidRect({ |
169 | width = w, | 195 | width = w, |
170 | height = h, | 196 | height = h, |
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) | |||
197 | AST_MEMBER(Goto, &label) | 197 | AST_MEMBER(Goto, &label) |
198 | AST_END(Goto, "goto"sv) | 198 | AST_END(Goto, "goto"sv) |
199 | 199 | ||
200 | AST_NODE(ShortTabAppending) | ||
201 | ast_ptr<true, Assign_t> assign; | ||
202 | AST_MEMBER(ShortTabAppending, &assign) | ||
203 | AST_END(ShortTabAppending, "short_table_appending"sv) | ||
204 | |||
200 | class FnArgsDef_t; | 205 | class FnArgsDef_t; |
201 | 206 | ||
202 | AST_LEAF(fn_arrow_back) | 207 | AST_LEAF(fn_arrow_back) |
@@ -804,8 +809,8 @@ AST_END(statement_sep, "statement_sep"sv) | |||
804 | AST_NODE(Statement) | 809 | AST_NODE(Statement) |
805 | ast_sel<true, Import_t, While_t, Repeat_t, For_t, ForEach_t, | 810 | ast_sel<true, Import_t, While_t, Repeat_t, For_t, ForEach_t, |
806 | Return_t, Local_t, Global_t, Export_t, Macro_t, MacroInPlace_t, | 811 | Return_t, Local_t, Global_t, Export_t, Macro_t, MacroInPlace_t, |
807 | BreakLoop_t, Label_t, Goto_t, Backcall_t, LocalAttrib_t, | 812 | BreakLoop_t, Label_t, Goto_t, ShortTabAppending_t, |
808 | PipeBody_t, ExpListAssign_t> content; | 813 | Backcall_t, LocalAttrib_t, PipeBody_t, ExpListAssign_t> content; |
809 | ast_ptr<false, statement_appendix_t> appendix; | 814 | ast_ptr<false, statement_appendix_t> appendix; |
810 | ast_ptr<false, statement_sep_t> needSep; | 815 | ast_ptr<false, statement_sep_t> needSep; |
811 | AST_MEMBER(Statement, &content, &appendix, &needSep) | 816 | 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; | |||
56 | 56 | ||
57 | typedef std::list<std::string> str_list; | 57 | typedef std::list<std::string> str_list; |
58 | 58 | ||
59 | const std::string_view version = "0.11.0"sv; | 59 | const std::string_view version = "0.11.1"sv; |
60 | const std::string_view extension = "yue"sv; | 60 | const std::string_view extension = "yue"sv; |
61 | 61 | ||
62 | class YueCompilerImpl { | 62 | class YueCompilerImpl { |
@@ -806,8 +806,10 @@ private: | |||
806 | case id<SelfName_t>(): | 806 | case id<SelfName_t>(): |
807 | return true; | 807 | return true; |
808 | } | 808 | } |
809 | } else if (firstItem->getId() == id<DotChainItem_t>()) { | 809 | } else switch (firstItem->getId()) { |
810 | return true; | 810 | case id<DotChainItem_t>(): |
811 | case id<Exp_t>(): | ||
812 | return true; | ||
811 | } | 813 | } |
812 | } else { | 814 | } else { |
813 | if (std::find_if(chainItems.begin(), chainItems.end(), [](ast_node* node) { | 815 | if (std::find_if(chainItems.begin(), chainItems.end(), [](ast_node* node) { |
@@ -1055,6 +1057,7 @@ private: | |||
1055 | case id<BreakLoop_t>(): transformBreakLoop(static_cast<BreakLoop_t*>(content), out); break; | 1057 | case id<BreakLoop_t>(): transformBreakLoop(static_cast<BreakLoop_t*>(content), out); break; |
1056 | case id<Label_t>(): transformLabel(static_cast<Label_t*>(content), out); break; | 1058 | case id<Label_t>(): transformLabel(static_cast<Label_t*>(content), out); break; |
1057 | case id<Goto_t>(): transformGoto(static_cast<Goto_t*>(content), out); break; | 1059 | case id<Goto_t>(): transformGoto(static_cast<Goto_t*>(content), out); break; |
1060 | case id<ShortTabAppending_t>(): transformShortTabAppending(static_cast<ShortTabAppending_t*>(content), out); break; | ||
1058 | case id<LocalAttrib_t>(): transformLocalAttrib(static_cast<LocalAttrib_t*>(content), out); break; | 1061 | case id<LocalAttrib_t>(): transformLocalAttrib(static_cast<LocalAttrib_t*>(content), out); break; |
1059 | case id<PipeBody_t>(): throw std::logic_error(_info.errorMessage("pipe chain must be following a value"sv, x)); break; | 1062 | case id<PipeBody_t>(): throw std::logic_error(_info.errorMessage("pipe chain must be following a value"sv, x)); break; |
1060 | case id<ExpListAssign_t>(): { | 1063 | case id<ExpListAssign_t>(): { |
@@ -1278,6 +1281,13 @@ private: | |||
1278 | temp.push_back(clearBuf()); | 1281 | temp.push_back(clearBuf()); |
1279 | } else if (ast_is<table_appending_op_t>(chainValue->items.back())) { | 1282 | } else if (ast_is<table_appending_op_t>(chainValue->items.back())) { |
1280 | chainValue->items.pop_back(); | 1283 | chainValue->items.pop_back(); |
1284 | if (chainValue->items.empty()) { | ||
1285 | if (_withVars.empty()) { | ||
1286 | throw std::logic_error(_info.errorMessage("short table appending must be called within a with block"sv, x)); | ||
1287 | } else { | ||
1288 | chainValue->items.push_back(toAst<Callable_t>(_withVars.top(), chainValue)); | ||
1289 | } | ||
1290 | } | ||
1281 | auto varName = singleVariableFrom(chainValue); | 1291 | auto varName = singleVariableFrom(chainValue); |
1282 | bool isScoped = false; | 1292 | bool isScoped = false; |
1283 | if (varName.empty() || !isLocal(varName)) { | 1293 | if (varName.empty() || !isLocal(varName)) { |
@@ -3797,6 +3807,7 @@ private: | |||
3797 | switch (chainList.front()->getId()) { | 3807 | switch (chainList.front()->getId()) { |
3798 | case id<DotChainItem_t>(): | 3808 | case id<DotChainItem_t>(): |
3799 | case id<ColonChainItem_t>(): | 3809 | case id<ColonChainItem_t>(): |
3810 | case id<Exp_t>(): | ||
3800 | if (_withVars.empty()) { | 3811 | if (_withVars.empty()) { |
3801 | throw std::logic_error(_info.errorMessage("short dot/colon syntax must be called within a with block"sv, chainList.front())); | 3812 | throw std::logic_error(_info.errorMessage("short dot/colon syntax must be called within a with block"sv, chainList.front())); |
3802 | } else { | 3813 | } else { |
@@ -3943,8 +3954,9 @@ private: | |||
3943 | switch (x->getId()) { | 3954 | switch (x->getId()) { |
3944 | case id<DotChainItem_t>(): | 3955 | case id<DotChainItem_t>(): |
3945 | case id<ColonChainItem_t>(): | 3956 | case id<ColonChainItem_t>(): |
3957 | case id<Exp_t>(): | ||
3946 | if (_withVars.empty()) { | 3958 | if (_withVars.empty()) { |
3947 | throw std::logic_error(_info.errorMessage("short dot/colon syntax must be called within a with block"sv, x)); | 3959 | throw std::logic_error(_info.errorMessage("short dot/colon and indexing syntax must be called within a with block"sv, x)); |
3948 | } else { | 3960 | } else { |
3949 | temp.push_back(_withVars.top()); | 3961 | temp.push_back(_withVars.top()); |
3950 | } | 3962 | } |
@@ -4440,7 +4452,7 @@ private: | |||
4440 | void transformChainValue(ChainValue_t* chainValue, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr, bool allowBlockMacroReturn = false) { | 4452 | void transformChainValue(ChainValue_t* chainValue, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr, bool allowBlockMacroReturn = false) { |
4441 | if (isMacroChain(chainValue)) { | 4453 | if (isMacroChain(chainValue)) { |
4442 | #ifndef YUE_NO_MACRO | 4454 | #ifndef YUE_NO_MACRO |
4443 | ast_ptr<false,ast_node> node; | 4455 | ast_ptr<false, ast_node> node; |
4444 | std::unique_ptr<input> codes; | 4456 | std::unique_ptr<input> codes; |
4445 | std::string luaCodes; | 4457 | std::string luaCodes; |
4446 | str_list localVars; | 4458 | str_list localVars; |
@@ -7181,6 +7193,15 @@ private: | |||
7181 | void transformGoto(Goto_t* gotoNode, str_list& out) { | 7193 | void transformGoto(Goto_t* gotoNode, str_list& out) { |
7182 | out.push_back(indent() + "goto "s + _parser.toString(gotoNode->label) + nll(gotoNode)); | 7194 | out.push_back(indent() + "goto "s + _parser.toString(gotoNode->label) + nll(gotoNode)); |
7183 | } | 7195 | } |
7196 | |||
7197 | void transformShortTabAppending(ShortTabAppending_t* tab, str_list& out) { | ||
7198 | if (_withVars.empty()) { | ||
7199 | throw std::logic_error(_info.errorMessage("short table appending syntax must be called within a with block"sv, tab)); | ||
7200 | } | ||
7201 | auto assignment = toAst<ExpListAssign_t>(_withVars.top() + "[]=nil"s, tab); | ||
7202 | assignment->action.set(tab->assign); | ||
7203 | transformAssignment(assignment, out); | ||
7204 | } | ||
7184 | }; | 7205 | }; |
7185 | 7206 | ||
7186 | const std::string YueCompilerImpl::Empty; | 7207 | 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() { | |||
216 | 216 | ||
217 | Goto = key("goto") >> Space >> LabelName; | 217 | Goto = key("goto") >> Space >> LabelName; |
218 | 218 | ||
219 | ShortTabAppending = expr("[]") >> Assign; | ||
220 | |||
219 | BreakLoop = (expr("break") | expr("continue")) >> not_(AlphaNum); | 221 | BreakLoop = (expr("break") | expr("continue")) >> not_(AlphaNum); |
220 | 222 | ||
221 | Return = key("return") >> -(TableBlock | ExpListLow); | 223 | Return = key("return") >> -(TableBlock | ExpListLow); |
@@ -335,7 +337,7 @@ YueParser::YueParser() { | |||
335 | 337 | ||
336 | Update = Space >> update_op >> expr("=") >> Exp; | 338 | Update = Space >> update_op >> expr("=") >> Exp; |
337 | 339 | ||
338 | Assignable = AssignableChain | Space >> Variable | Space >> SelfName; | 340 | Assignable = Space >> (AssignableChain | Variable | SelfName); |
339 | 341 | ||
340 | unary_value = unary_operator >> *(Space >> unary_operator) >> Value; | 342 | unary_value = unary_operator >> *(Space >> unary_operator) >> Value; |
341 | 343 | ||
@@ -382,16 +384,16 @@ YueParser::YueParser() { | |||
382 | return true; | 384 | return true; |
383 | }); | 385 | }); |
384 | 386 | ||
385 | chain_line = CheckIndent >> (chain_item | Space >> (chain_dot_chain | ColonChain)) >> -InvokeArgs; | 387 | chain_line = CheckIndent >> Space >> (chain_dot_chain | ColonChain) >> -InvokeArgs; |
386 | chain_block = pl::user(true_(), [](const item_t& item) { | 388 | chain_block = pl::user(true_(), [](const item_t& item) { |
387 | State* st = reinterpret_cast<State*>(item.user_data); | 389 | State* st = reinterpret_cast<State*>(item.user_data); |
388 | return st->noChainBlockStack.empty() || !st->noChainBlockStack.top(); | 390 | return st->noChainBlockStack.empty() || !st->noChainBlockStack.top(); |
389 | }) >> +SpaceBreak >> Advance >> ensure( | 391 | }) >> +SpaceBreak >> Advance >> ensure( |
390 | chain_line >> *(+SpaceBreak >> chain_line), PopIndent); | 392 | chain_line >> *(+SpaceBreak >> chain_line), PopIndent); |
391 | ChainValue = Seperator >> (Chain | Callable) >> -existential_op >> -(InvokeArgs | chain_block) >> -table_appending_op; | 393 | ChainValue = Space >> Seperator >> (Chain | Callable) >> -existential_op >> -(InvokeArgs | chain_block) >> -table_appending_op; |
392 | 394 | ||
393 | simple_table = Seperator >> KeyValue >> *(sym(',') >> KeyValue); | 395 | simple_table = Seperator >> KeyValue >> *(sym(',') >> KeyValue); |
394 | Value = SimpleValue | simple_table | ChainValue | String; | 396 | Value = SimpleValue | simple_table | ChainValue | Space >> String; |
395 | 397 | ||
396 | single_string_inner = expr("\\'") | "\\\\" | not_(expr('\'')) >> Any; | 398 | single_string_inner = expr("\\'") | "\\\\" | not_(expr('\'')) >> Any; |
397 | SingleString = symx('\'') >> *single_string_inner >> symx('\''); | 399 | SingleString = symx('\'') >> *single_string_inner >> symx('\''); |
@@ -400,7 +402,7 @@ YueParser::YueParser() { | |||
400 | double_string_inner = +(not_(interp) >> double_string_plain); | 402 | double_string_inner = +(not_(interp) >> double_string_plain); |
401 | double_string_content = double_string_inner | interp; | 403 | double_string_content = double_string_inner | interp; |
402 | DoubleString = symx('"') >> Seperator >> *double_string_content >> symx('"'); | 404 | DoubleString = symx('"') >> Seperator >> *double_string_content >> symx('"'); |
403 | String = Space >> (DoubleString | SingleString | LuaString); | 405 | String = DoubleString | SingleString | LuaString; |
404 | 406 | ||
405 | lua_string_open = '[' >> *expr('=') >> '['; | 407 | lua_string_open = '[' >> *expr('=') >> '['; |
406 | lua_string_close = ']' >> *expr('=') >> ']'; | 408 | lua_string_close = ']' >> *expr('=') >> ']'; |
@@ -423,7 +425,7 @@ YueParser::YueParser() { | |||
423 | LuaString = LuaStringOpen >> -Break >> LuaStringContent >> LuaStringClose; | 425 | LuaString = LuaStringOpen >> -Break >> LuaStringContent >> LuaStringClose; |
424 | 426 | ||
425 | Parens = symx('(') >> *SpaceBreak >> Exp >> *SpaceBreak >> sym(')'); | 427 | Parens = symx('(') >> *SpaceBreak >> Exp >> *SpaceBreak >> sym(')'); |
426 | Callable = Space >> (Variable | SelfName | MacroName | VarArg | Parens); | 428 | Callable = Variable | SelfName | MacroName | VarArg | Parens; |
427 | FnArgsExpList = Exp >> *((Break | sym(',')) >> White >> Exp); | 429 | FnArgsExpList = Exp >> *((Break | sym(',')) >> White >> Exp); |
428 | 430 | ||
429 | FnArgs = (symx('(') >> *SpaceBreak >> -FnArgsExpList >> *SpaceBreak >> sym(')')) | | 431 | FnArgs = (symx('(') >> *SpaceBreak >> -FnArgsExpList >> *SpaceBreak >> sym(')')) | |
@@ -435,11 +437,10 @@ YueParser::YueParser() { | |||
435 | existential_op = expr('?') >> not_(expr('?')); | 437 | existential_op = expr('?') >> not_(expr('?')); |
436 | table_appending_op = expr("[]"); | 438 | table_appending_op = expr("[]"); |
437 | chain_call = (Callable | String) >> -existential_op >> ChainItems; | 439 | chain_call = (Callable | String) >> -existential_op >> ChainItems; |
438 | chain_item = and_(set(".\\")) >> ChainItems; | 440 | chain_index_chain = Index >> -existential_op >> -ChainItems; |
439 | chain_dot_chain = DotChainItem >> -existential_op >> -ChainItems; | 441 | chain_dot_chain = DotChainItem >> -existential_op >> -ChainItems; |
440 | 442 | ||
441 | Chain = chain_call | chain_item | | 443 | Chain = chain_call | chain_dot_chain | ColonChain | chain_index_chain; |
442 | Space >> (chain_dot_chain | ColonChain); | ||
443 | 444 | ||
444 | AssignableChain = Seperator >> Chain; | 445 | AssignableChain = Seperator >> Chain; |
445 | 446 | ||
@@ -631,8 +632,8 @@ YueParser::YueParser() { | |||
631 | Statement = Space >> ( | 632 | Statement = Space >> ( |
632 | Import | While | Repeat | For | ForEach | | 633 | Import | While | Repeat | For | ForEach | |
633 | Return | Local | Global | Export | Macro | | 634 | Return | Local | Global | Export | Macro | |
634 | MacroInPlace | BreakLoop | Label | Goto | LocalAttrib | | 635 | MacroInPlace | BreakLoop | Label | Goto | ShortTabAppending | |
635 | Backcall | PipeBody | ExpListAssign | 636 | LocalAttrib | Backcall | PipeBody | ExpListAssign |
636 | ) >> Space >> | 637 | ) >> Space >> |
637 | -statement_appendix >> -statement_sep; | 638 | -statement_appendix >> -statement_sep; |
638 | 639 | ||
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: | |||
158 | rule FnArgs; | 158 | rule FnArgs; |
159 | rule macro_args_def; | 159 | rule macro_args_def; |
160 | rule chain_call; | 160 | rule chain_call; |
161 | rule chain_item; | 161 | rule chain_index_chain; |
162 | rule ChainItems; | 162 | rule ChainItems; |
163 | rule chain_dot_chain; | 163 | rule chain_dot_chain; |
164 | rule ColonChain; | 164 | rule ColonChain; |
@@ -220,6 +220,7 @@ private: | |||
220 | AST_RULE(Import) | 220 | AST_RULE(Import) |
221 | AST_RULE(Label) | 221 | AST_RULE(Label) |
222 | AST_RULE(Goto) | 222 | AST_RULE(Goto) |
223 | AST_RULE(ShortTabAppending) | ||
223 | AST_RULE(fn_arrow_back) | 224 | AST_RULE(fn_arrow_back) |
224 | AST_RULE(Backcall) | 225 | AST_RULE(Backcall) |
225 | AST_RULE(PipeBody) | 226 | AST_RULE(PipeBody) |