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
Diffstat (limited to '')
| -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) | |
