aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLi Jin <dragon-fly@qq.com>2023-06-30 18:48:20 +0800
committerLi Jin <dragon-fly@qq.com>2023-06-30 18:48:20 +0800
commit85a2da5cbbbbfb27f3b65ac67d083dd2443d223d (patch)
tree25ab99912ebf9a26f5c11f09518b47509d750b36
parentef64f6d54bfc25c35e9d3044e324c9a3da7c2b94 (diff)
downloadyuescript-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.yue17
-rw-r--r--spec/outputs/in_expression.lua85
-rw-r--r--src/yuescript/yue_ast.h2
-rw-r--r--src/yuescript/yue_compiler.cpp104
-rw-r--r--src/yuescript/yue_parser.cpp12
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
25do return y not in (a, b) 25do return y not in (a, b)
26 26
27do
28 exist = item in list
29 check item in list
30
31do
32 item = get!
33 exist = item in list
34 check item in list
35
36do
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
27nil 44nil
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)
40end 40end
41do
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)())
66end
67do
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)())
87end
88do
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)())
125end
41return nil 126return 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
453AST_NODE(In) 453AST_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, &not_, &item) 456 AST_MEMBER(In, &not_, &item)
457AST_END(In, "in"sv) 457AST_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
75const std::string_view version = "0.17.3"sv; 75const std::string_view version = "0.17.4"sv;
76const std::string_view extension = "yue"sv; 76const std::string_view extension = "yue"sv;
77 77
78class CompileError : public std::logic_error { 78class 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) |