diff options
author | Li Jin <dragon-fly@qq.com> | 2023-06-30 18:48:20 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2023-06-30 18:48:20 +0800 |
commit | 85a2da5cbbbbfb27f3b65ac67d083dd2443d223d (patch) | |
tree | 25ab99912ebf9a26f5c11f09518b47509d750b36 | |
parent | ef64f6d54bfc25c35e9d3044e324c9a3da7c2b94 (diff) | |
download | yuescript-85a2da5cbbbbfb27f3b65ac67d083dd2443d223d.tar.gz yuescript-85a2da5cbbbbfb27f3b65ac67d083dd2443d223d.tar.bz2 yuescript-85a2da5cbbbbfb27f3b65ac67d083dd2443d223d.zip |
support list table checking to in-expression for issue #140
-rw-r--r-- | spec/inputs/in_expression.yue | 17 | ||||
-rw-r--r-- | spec/outputs/in_expression.lua | 85 | ||||
-rw-r--r-- | src/yuescript/yue_ast.h | 2 | ||||
-rw-r--r-- | src/yuescript/yue_compiler.cpp | 104 | ||||
-rw-r--r-- | src/yuescript/yue_parser.cpp | 12 |
5 files changed, 212 insertions, 8 deletions
diff --git a/spec/inputs/in_expression.yue b/spec/inputs/in_expression.yue index dacf820..66a8215 100644 --- a/spec/inputs/in_expression.yue +++ b/spec/inputs/in_expression.yue | |||
@@ -24,5 +24,22 @@ switch val | |||
24 | 24 | ||
25 | do return y not in (a, b) | 25 | do return y not in (a, b) |
26 | 26 | ||
27 | do | ||
28 | exist = item in list | ||
29 | check item in list | ||
30 | |||
31 | do | ||
32 | item = get! | ||
33 | exist = item in list | ||
34 | check item in list | ||
35 | |||
36 | do | ||
37 | item = get! | ||
38 | list = {1, 2, 3} | ||
39 | exist = item in list | ||
40 | check item in list | ||
41 | check item in {1, 2, 3} | ||
42 | check item in {[1]: 1, [2]: 2, [3]: 3} | ||
43 | |||
27 | nil | 44 | nil |
28 | 45 | ||
diff --git a/spec/outputs/in_expression.lua b/spec/outputs/in_expression.lua index 8b37a72..41ae87e 100644 --- a/spec/outputs/in_expression.lua +++ b/spec/outputs/in_expression.lua | |||
@@ -38,4 +38,89 @@ do | |||
38 | local _val_0 = y | 38 | local _val_0 = y |
39 | return not (a < _val_0 and _val_0 < b) | 39 | return not (a < _val_0 and _val_0 < b) |
40 | end | 40 | end |
41 | do | ||
42 | local exist | ||
43 | do | ||
44 | local _check_0 = list | ||
45 | local _val_0 = item | ||
46 | local _find_0 = false | ||
47 | for _index_0 = 1, #_check_0 do | ||
48 | local _item_0 = _check_0[_index_0] | ||
49 | if _item_0 == _val_0 then | ||
50 | _find_0 = true | ||
51 | break | ||
52 | end | ||
53 | end | ||
54 | exist = _find_0 | ||
55 | end | ||
56 | check((function() | ||
57 | local _check_0 = list | ||
58 | local _val_0 = item | ||
59 | for _index_0 = 1, #_check_0 do | ||
60 | if _check_0[_index_0] == _val_0 then | ||
61 | return true | ||
62 | end | ||
63 | end | ||
64 | return false | ||
65 | end)()) | ||
66 | end | ||
67 | do | ||
68 | local item = get() | ||
69 | local exist = (function() | ||
70 | local _check_0 = list | ||
71 | for _index_0 = 1, #_check_0 do | ||
72 | if _check_0[_index_0] == item then | ||
73 | return true | ||
74 | end | ||
75 | end | ||
76 | return false | ||
77 | end)() | ||
78 | check((function() | ||
79 | local _check_0 = list | ||
80 | for _index_0 = 1, #_check_0 do | ||
81 | if _check_0[_index_0] == item then | ||
82 | return true | ||
83 | end | ||
84 | end | ||
85 | return false | ||
86 | end)()) | ||
87 | end | ||
88 | do | ||
89 | local item = get() | ||
90 | local list = { | ||
91 | 1, | ||
92 | 2, | ||
93 | 3 | ||
94 | } | ||
95 | local exist = (#list > 0 and (function() | ||
96 | for _index_0 = 1, #list do | ||
97 | if list[_index_0] == item then | ||
98 | return true | ||
99 | end | ||
100 | end | ||
101 | return false | ||
102 | end)()) | ||
103 | check((#list > 0 and (function() | ||
104 | for _index_0 = 1, #list do | ||
105 | if list[_index_0] == item then | ||
106 | return true | ||
107 | end | ||
108 | end | ||
109 | return false | ||
110 | end)())) | ||
111 | check((1 == item or 2 == item or 3 == item)) | ||
112 | check((function() | ||
113 | local _check_0 = { | ||
114 | [1] = 1, | ||
115 | [2] = 2, | ||
116 | [3] = 3 | ||
117 | } | ||
118 | for _index_0 = 1, #_check_0 do | ||
119 | if _check_0[_index_0] == item then | ||
120 | return true | ||
121 | end | ||
122 | end | ||
123 | return false | ||
124 | end)()) | ||
125 | end | ||
41 | return nil | 126 | return nil |
diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index 85a1e52..807d01b 100644 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h | |||
@@ -452,7 +452,7 @@ AST_END(InDiscrete, "in_discrete"sv) | |||
452 | 452 | ||
453 | AST_NODE(In) | 453 | AST_NODE(In) |
454 | ast_ptr<false, NotIn_t> not_; | 454 | ast_ptr<false, NotIn_t> not_; |
455 | ast_sel<true, InRange_t, InDiscrete_t> item; | 455 | ast_sel<true, InRange_t, InDiscrete_t, Exp_t> item; |
456 | AST_MEMBER(In, ¬_, &item) | 456 | AST_MEMBER(In, ¬_, &item) |
457 | AST_END(In, "in"sv) | 457 | AST_END(In, "in"sv) |
458 | 458 | ||
diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index efd0aed..3dc8e19 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp | |||
@@ -72,7 +72,7 @@ static std::unordered_set<std::string> Metamethods = { | |||
72 | "close"s // Lua 5.4 | 72 | "close"s // Lua 5.4 |
73 | }; | 73 | }; |
74 | 74 | ||
75 | const std::string_view version = "0.17.3"sv; | 75 | const std::string_view version = "0.17.4"sv; |
76 | const std::string_view extension = "yue"sv; | 76 | const std::string_view extension = "yue"sv; |
77 | 77 | ||
78 | class CompileError : public std::logic_error { | 78 | class CompileError : public std::logic_error { |
@@ -5385,6 +5385,108 @@ private: | |||
5385 | varName.clear(); | 5385 | varName.clear(); |
5386 | } | 5386 | } |
5387 | } | 5387 | } |
5388 | if (auto inExp = unary_exp->inExp->item.as<Exp_t>()) { | ||
5389 | str_list temp; | ||
5390 | auto checkVar = singleVariableFrom(inExp, false); | ||
5391 | if (usage == ExpUsage::Assignment) { | ||
5392 | auto block = x->new_ptr<Block_t>(); | ||
5393 | if (checkVar.empty() || !isLocal(checkVar)) { | ||
5394 | checkVar = getUnusedName("_check_"sv); | ||
5395 | auto assignment = assignmentFrom(toAst<Exp_t>(checkVar, inExp), inExp, inExp); | ||
5396 | auto stmt = x->new_ptr<Statement_t>(); | ||
5397 | stmt->content.set(assignment); | ||
5398 | block->statements.push_back(stmt); | ||
5399 | } | ||
5400 | if (varName.empty()) { | ||
5401 | auto newUnaryExp = x->new_ptr<UnaryExp_t>(); | ||
5402 | newUnaryExp->ops.dup(unary_exp->ops); | ||
5403 | newUnaryExp->expos.dup(unary_exp->expos); | ||
5404 | auto exp = newExp(newUnaryExp, x); | ||
5405 | varName = getUnusedName("_val_"sv); | ||
5406 | auto assignExp = toAst<Exp_t>(varName, x); | ||
5407 | auto assignment = assignmentFrom(assignExp, exp, x); | ||
5408 | auto stmt = x->new_ptr<Statement_t>(); | ||
5409 | stmt->content.set(assignment); | ||
5410 | block->statements.push_back(stmt); | ||
5411 | } | ||
5412 | auto findVar = getUnusedName("_find_"); | ||
5413 | auto itemVar = getUnusedName("_item_"); | ||
5414 | _buf << findVar << "=false\n"sv; | ||
5415 | _buf << "for "sv << itemVar << " in *"sv << checkVar << '\n'; | ||
5416 | _buf << "\tif "sv << itemVar << "=="sv << varName << '\n'; | ||
5417 | _buf << "\t\t"sv << findVar << "=true\n"sv; | ||
5418 | _buf << "\t\tbreak\n"sv; | ||
5419 | _buf << findVar; | ||
5420 | auto blockStr = clearBuf(); | ||
5421 | auto checkBlock = toAst<Block_t>(blockStr, inExp); | ||
5422 | block->statements.dup(checkBlock->statements); | ||
5423 | auto body = x->new_ptr<Body_t>(); | ||
5424 | body->content.set(block); | ||
5425 | auto doNode = x->new_ptr<Do_t>(); | ||
5426 | doNode->body.set(body); | ||
5427 | auto assign = x->new_ptr<Assign_t>(); | ||
5428 | auto simpleValue = x->new_ptr<SimpleValue_t>(); | ||
5429 | simpleValue->value.set(doNode); | ||
5430 | auto value = x->new_ptr<Value_t>(); | ||
5431 | value->item.set(simpleValue); | ||
5432 | assign->values.push_back(newExp(value, x)); | ||
5433 | auto assignment = x->new_ptr<ExpListAssign_t>(); | ||
5434 | assignment->action.set(assign); | ||
5435 | assignment->expList.set(assignList); | ||
5436 | transformAssignment(assignment, temp); | ||
5437 | out.push_back(join(temp)); | ||
5438 | return; | ||
5439 | } else { | ||
5440 | pushFunctionScope(); | ||
5441 | pushAnonVarArg(); | ||
5442 | pushScope(); | ||
5443 | auto arrayCheck = [&]() { | ||
5444 | auto indexVar = getUnusedName("_index_"); | ||
5445 | _buf << indent() << "for "sv << indexVar << " = 1, #"sv << checkVar << " do"sv << nll(x); | ||
5446 | incIndentOffset(); | ||
5447 | _buf << indent() << "if "sv << checkVar << '[' << indexVar << "] == "sv << varName << " then"sv << nll(x); | ||
5448 | incIndentOffset(); | ||
5449 | _buf << indent() << "return true"sv << nll(x); | ||
5450 | decIndentOffset(); | ||
5451 | _buf << indent() << "end"sv << nll(x); | ||
5452 | decIndentOffset(); | ||
5453 | _buf << indent() << "end"sv << nll(x); | ||
5454 | _buf << indent() << "return false"sv << nll(x); | ||
5455 | temp.push_back(clearBuf()); | ||
5456 | }; | ||
5457 | bool useShortCheck = !varName.empty() && !checkVar.empty() && isLocal(checkVar); | ||
5458 | if (useShortCheck) { | ||
5459 | arrayCheck(); | ||
5460 | temp.push_front("(#"s + checkVar + " > 0 and "s + anonFuncStart() + nll(x)); | ||
5461 | popScope(); | ||
5462 | temp.push_back(indent() + anonFuncEnd() + ')'); | ||
5463 | } else { | ||
5464 | if (checkVar.empty() || !isLocal(checkVar)) { | ||
5465 | checkVar = getUnusedName("_check_"sv); | ||
5466 | auto assignment = assignmentFrom(toAst<Exp_t>(checkVar, inExp), inExp, inExp); | ||
5467 | transformAssignment(assignment, temp); | ||
5468 | } | ||
5469 | if (varName.empty()) { | ||
5470 | auto newUnaryExp = x->new_ptr<UnaryExp_t>(); | ||
5471 | newUnaryExp->ops.dup(unary_exp->ops); | ||
5472 | newUnaryExp->expos.dup(unary_exp->expos); | ||
5473 | auto exp = newExp(newUnaryExp, x); | ||
5474 | varName = getUnusedName("_val_"sv); | ||
5475 | auto assignExp = toAst<Exp_t>(varName, x); | ||
5476 | auto assignment = assignmentFrom(assignExp, exp, x); | ||
5477 | transformAssignment(assignment, temp); | ||
5478 | } | ||
5479 | arrayCheck(); | ||
5480 | temp.push_front(anonFuncStart() + nll(x)); | ||
5481 | popScope(); | ||
5482 | temp.push_back(indent() + anonFuncEnd()); | ||
5483 | } | ||
5484 | popAnonVarArg(); | ||
5485 | popFunctionScope(); | ||
5486 | out.push_back(join(temp)); | ||
5487 | return; | ||
5488 | } | ||
5489 | } | ||
5388 | if (varName.empty()) { | 5490 | if (varName.empty()) { |
5389 | str_list temp; | 5491 | str_list temp; |
5390 | if (usage == ExpUsage::Closure) { | 5492 | if (usage == ExpUsage::Closure) { |
diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index f72407d..294f1e5 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp | |||
@@ -317,18 +317,18 @@ YueParser::YueParser() { | |||
317 | with_exp = ExpList >> -(space >> Assign); | 317 | with_exp = ExpList >> -(space >> Assign); |
318 | 318 | ||
319 | With = key("with") >> -ExistentialOp >> space >> disable_do_chain_arg_table_block_rule(with_exp) >> space >> body_with("do"); | 319 | With = key("with") >> -ExistentialOp >> space >> disable_do_chain_arg_table_block_rule(with_exp) >> space >> body_with("do"); |
320 | SwitchCase = key("when") >> (disable_chain_rule(disable_arg_table_block_rule(SwitchList)) | space >> In) >> space >> body_with("then"); | 320 | SwitchCase = key("when") >> space >> (disable_chain_rule(disable_arg_table_block_rule(SwitchList)) | In) >> space >> body_with("then"); |
321 | switch_else = key("else") >> space >> body; | 321 | switch_else = key("else") >> space >> body; |
322 | 322 | ||
323 | switch_block = | 323 | switch_block = |
324 | *(line_break >> *space_break >> check_indent_match >> space >> SwitchCase) >> | 324 | *(line_break >> *space_break >> check_indent_match >> space >> SwitchCase) >> |
325 | -(line_break >> *space_break >> check_indent_match >> space >> switch_else); | 325 | -(line_break >> *space_break >> check_indent_match >> space >> switch_else); |
326 | 326 | ||
327 | exp_not_tab = not_(SimpleTable | TableLit) >> space >> Exp; | 327 | exp_not_tab = not_(SimpleTable | TableLit) >> Exp; |
328 | 328 | ||
329 | SwitchList = Seperator >> ( | 329 | SwitchList = Seperator >> ( |
330 | and_(SimpleTable | TableLit) >> space >> Exp | | 330 | and_(SimpleTable | TableLit) >> Exp | |
331 | exp_not_tab >> *(space >> ',' >> exp_not_tab) | 331 | exp_not_tab >> *(space >> ',' >> space >> exp_not_tab) |
332 | ); | 332 | ); |
333 | Switch = key("switch") >> space >> Exp >> | 333 | Switch = key("switch") >> space >> Exp >> |
334 | space >> Seperator >> ( | 334 | space >> Seperator >> ( |
@@ -458,8 +458,8 @@ YueParser::YueParser() { | |||
458 | InRangeClose = true_(); | 458 | InRangeClose = true_(); |
459 | NotIn = true_(); | 459 | NotIn = true_(); |
460 | InRange = ('(' >> InRangeOpen | '[' >> InRangeClose) >> space >> Exp >> space >> ',' >> space >> Exp >> space >> (')' >> InRangeOpen | ']' >> InRangeClose); | 460 | InRange = ('(' >> InRangeOpen | '[' >> InRangeClose) >> space >> Exp >> space >> ',' >> space >> Exp >> space >> (')' >> InRangeOpen | ']' >> InRangeClose); |
461 | InDiscrete = '{' >> Seperator >> space >> Exp >> *(space >> ',' >> space >> Exp) >> space >> '}'; | 461 | InDiscrete = '{' >> Seperator >> space >> exp_not_tab >> *(space >> ',' >> space >> exp_not_tab) >> space >> '}'; |
462 | In = -(key("not") >> NotIn >> space) >> key("in") >> space >> (InRange | InDiscrete); | 462 | In = -(key("not") >> NotIn >> space) >> key("in") >> space >> (InRange | InDiscrete | Exp); |
463 | 463 | ||
464 | UnaryOperator = | 464 | UnaryOperator = |
465 | '-' >> not_(set(">=") | space_one) | | 465 | '-' >> not_(set(">=") | space_one) | |