From 85a2da5cbbbbfb27f3b65ac67d083dd2443d223d Mon Sep 17 00:00:00 2001 From: Li Jin Date: Fri, 30 Jun 2023 18:48:20 +0800 Subject: support list table checking to in-expression for issue #140 --- spec/inputs/in_expression.yue | 17 +++++++ spec/outputs/in_expression.lua | 85 +++++++++++++++++++++++++++++++++ src/yuescript/yue_ast.h | 2 +- src/yuescript/yue_compiler.cpp | 104 ++++++++++++++++++++++++++++++++++++++++- 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 do return y not in (a, b) +do + exist = item in list + check item in list + +do + item = get! + exist = item in list + check item in list + +do + item = get! + list = {1, 2, 3} + exist = item in list + check item in list + check item in {1, 2, 3} + check item in {[1]: 1, [2]: 2, [3]: 3} + nil 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 local _val_0 = y return not (a < _val_0 and _val_0 < b) end +do + local exist + do + local _check_0 = list + local _val_0 = item + local _find_0 = false + for _index_0 = 1, #_check_0 do + local _item_0 = _check_0[_index_0] + if _item_0 == _val_0 then + _find_0 = true + break + end + end + exist = _find_0 + end + check((function() + local _check_0 = list + local _val_0 = item + for _index_0 = 1, #_check_0 do + if _check_0[_index_0] == _val_0 then + return true + end + end + return false + end)()) +end +do + local item = get() + local exist = (function() + local _check_0 = list + for _index_0 = 1, #_check_0 do + if _check_0[_index_0] == item then + return true + end + end + return false + end)() + check((function() + local _check_0 = list + for _index_0 = 1, #_check_0 do + if _check_0[_index_0] == item then + return true + end + end + return false + end)()) +end +do + local item = get() + local list = { + 1, + 2, + 3 + } + local exist = (#list > 0 and (function() + for _index_0 = 1, #list do + if list[_index_0] == item then + return true + end + end + return false + end)()) + check((#list > 0 and (function() + for _index_0 = 1, #list do + if list[_index_0] == item then + return true + end + end + return false + end)())) + check((1 == item or 2 == item or 3 == item)) + check((function() + local _check_0 = { + [1] = 1, + [2] = 2, + [3] = 3 + } + for _index_0 = 1, #_check_0 do + if _check_0[_index_0] == item then + return true + end + end + return false + end)()) +end 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) AST_NODE(In) ast_ptr not_; - ast_sel item; + ast_sel item; AST_MEMBER(In, ¬_, &item) AST_END(In, "in"sv) 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 Metamethods = { "close"s // Lua 5.4 }; -const std::string_view version = "0.17.3"sv; +const std::string_view version = "0.17.4"sv; const std::string_view extension = "yue"sv; class CompileError : public std::logic_error { @@ -5385,6 +5385,108 @@ private: varName.clear(); } } + if (auto inExp = unary_exp->inExp->item.as()) { + str_list temp; + auto checkVar = singleVariableFrom(inExp, false); + if (usage == ExpUsage::Assignment) { + auto block = x->new_ptr(); + if (checkVar.empty() || !isLocal(checkVar)) { + checkVar = getUnusedName("_check_"sv); + auto assignment = assignmentFrom(toAst(checkVar, inExp), inExp, inExp); + auto stmt = x->new_ptr(); + stmt->content.set(assignment); + block->statements.push_back(stmt); + } + if (varName.empty()) { + auto newUnaryExp = x->new_ptr(); + newUnaryExp->ops.dup(unary_exp->ops); + newUnaryExp->expos.dup(unary_exp->expos); + auto exp = newExp(newUnaryExp, x); + varName = getUnusedName("_val_"sv); + auto assignExp = toAst(varName, x); + auto assignment = assignmentFrom(assignExp, exp, x); + auto stmt = x->new_ptr(); + stmt->content.set(assignment); + block->statements.push_back(stmt); + } + auto findVar = getUnusedName("_find_"); + auto itemVar = getUnusedName("_item_"); + _buf << findVar << "=false\n"sv; + _buf << "for "sv << itemVar << " in *"sv << checkVar << '\n'; + _buf << "\tif "sv << itemVar << "=="sv << varName << '\n'; + _buf << "\t\t"sv << findVar << "=true\n"sv; + _buf << "\t\tbreak\n"sv; + _buf << findVar; + auto blockStr = clearBuf(); + auto checkBlock = toAst(blockStr, inExp); + block->statements.dup(checkBlock->statements); + auto body = x->new_ptr(); + body->content.set(block); + auto doNode = x->new_ptr(); + doNode->body.set(body); + auto assign = x->new_ptr(); + auto simpleValue = x->new_ptr(); + simpleValue->value.set(doNode); + auto value = x->new_ptr(); + value->item.set(simpleValue); + assign->values.push_back(newExp(value, x)); + auto assignment = x->new_ptr(); + assignment->action.set(assign); + assignment->expList.set(assignList); + transformAssignment(assignment, temp); + out.push_back(join(temp)); + return; + } else { + pushFunctionScope(); + pushAnonVarArg(); + pushScope(); + auto arrayCheck = [&]() { + auto indexVar = getUnusedName("_index_"); + _buf << indent() << "for "sv << indexVar << " = 1, #"sv << checkVar << " do"sv << nll(x); + incIndentOffset(); + _buf << indent() << "if "sv << checkVar << '[' << indexVar << "] == "sv << varName << " then"sv << nll(x); + incIndentOffset(); + _buf << indent() << "return true"sv << nll(x); + decIndentOffset(); + _buf << indent() << "end"sv << nll(x); + decIndentOffset(); + _buf << indent() << "end"sv << nll(x); + _buf << indent() << "return false"sv << nll(x); + temp.push_back(clearBuf()); + }; + bool useShortCheck = !varName.empty() && !checkVar.empty() && isLocal(checkVar); + if (useShortCheck) { + arrayCheck(); + temp.push_front("(#"s + checkVar + " > 0 and "s + anonFuncStart() + nll(x)); + popScope(); + temp.push_back(indent() + anonFuncEnd() + ')'); + } else { + if (checkVar.empty() || !isLocal(checkVar)) { + checkVar = getUnusedName("_check_"sv); + auto assignment = assignmentFrom(toAst(checkVar, inExp), inExp, inExp); + transformAssignment(assignment, temp); + } + if (varName.empty()) { + auto newUnaryExp = x->new_ptr(); + newUnaryExp->ops.dup(unary_exp->ops); + newUnaryExp->expos.dup(unary_exp->expos); + auto exp = newExp(newUnaryExp, x); + varName = getUnusedName("_val_"sv); + auto assignExp = toAst(varName, x); + auto assignment = assignmentFrom(assignExp, exp, x); + transformAssignment(assignment, temp); + } + arrayCheck(); + temp.push_front(anonFuncStart() + nll(x)); + popScope(); + temp.push_back(indent() + anonFuncEnd()); + } + popAnonVarArg(); + popFunctionScope(); + out.push_back(join(temp)); + return; + } + } if (varName.empty()) { str_list temp; 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() { with_exp = ExpList >> -(space >> Assign); With = key("with") >> -ExistentialOp >> space >> disable_do_chain_arg_table_block_rule(with_exp) >> space >> body_with("do"); - SwitchCase = key("when") >> (disable_chain_rule(disable_arg_table_block_rule(SwitchList)) | space >> In) >> space >> body_with("then"); + SwitchCase = key("when") >> space >> (disable_chain_rule(disable_arg_table_block_rule(SwitchList)) | In) >> space >> body_with("then"); switch_else = key("else") >> space >> body; switch_block = *(line_break >> *space_break >> check_indent_match >> space >> SwitchCase) >> -(line_break >> *space_break >> check_indent_match >> space >> switch_else); - exp_not_tab = not_(SimpleTable | TableLit) >> space >> Exp; + exp_not_tab = not_(SimpleTable | TableLit) >> Exp; SwitchList = Seperator >> ( - and_(SimpleTable | TableLit) >> space >> Exp | - exp_not_tab >> *(space >> ',' >> exp_not_tab) + and_(SimpleTable | TableLit) >> Exp | + exp_not_tab >> *(space >> ',' >> space >> exp_not_tab) ); Switch = key("switch") >> space >> Exp >> space >> Seperator >> ( @@ -458,8 +458,8 @@ YueParser::YueParser() { InRangeClose = true_(); NotIn = true_(); InRange = ('(' >> InRangeOpen | '[' >> InRangeClose) >> space >> Exp >> space >> ',' >> space >> Exp >> space >> (')' >> InRangeOpen | ']' >> InRangeClose); - InDiscrete = '{' >> Seperator >> space >> Exp >> *(space >> ',' >> space >> Exp) >> space >> '}'; - In = -(key("not") >> NotIn >> space) >> key("in") >> space >> (InRange | InDiscrete); + InDiscrete = '{' >> Seperator >> space >> exp_not_tab >> *(space >> ',' >> space >> exp_not_tab) >> space >> '}'; + In = -(key("not") >> NotIn >> space) >> key("in") >> space >> (InRange | InDiscrete | Exp); UnaryOperator = '-' >> not_(set(">=") | space_one) | -- cgit v1.2.3-55-g6feb