From 018b9408f167067c596fc23781bc945edb9f4d89 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Mon, 5 Feb 2024 11:24:41 +0800 Subject: fix in-expression format issue. --- spec/inputs/in_expression.yue | 1 - spec/inputs/unicode/in_expression.yue | 39 +++++ spec/outputs/in_expression.lua | 4 - spec/outputs/unicode/in_expression.lua | 52 ++++++ src/yuescript/yue_ast.cpp | 9 +- src/yuescript/yue_ast.h | 11 +- src/yuescript/yue_compiler.cpp | 291 ++++++++++++++++----------------- src/yuescript/yue_parser.cpp | 5 +- src/yuescript/yue_parser.h | 1 - 9 files changed, 238 insertions(+), 175 deletions(-) diff --git a/spec/inputs/in_expression.yue b/spec/inputs/in_expression.yue index 7ee0816..0b2a87a 100644 --- a/spec/inputs/in_expression.yue +++ b/spec/inputs/in_expression.yue @@ -1,5 +1,4 @@ -a^2 in {1, 2, 3} |> f --a^2 in [1, 2, 3] |> f has = "foo" in { "bar", "foo" } diff --git a/spec/inputs/unicode/in_expression.yue b/spec/inputs/unicode/in_expression.yue index e068cbf..4a87099 100644 --- a/spec/inputs/unicode/in_expression.yue +++ b/spec/inputs/unicode/in_expression.yue @@ -29,5 +29,44 @@ do 检查 -> return 对象x in 数组tb 检查 -> 对象x not in 数组tb +do + 函数1 = -> + 变量a = 2 + 变量a in [ + 1 + 2 + 3 + 4 + ] + 函数2 = -> + 变量a not in [ + 1 + 2 + 3 + 4 + ] + 函数3 = -> + 变量a = 2 + 变量a in { 变量b, 变量c, 变量d + 变量e, 变量f + 变量g + } + 函数4 = -> + 变量a = 2 + 变量b = a in [ 1, 2 + 3, 4 + ] + 函数5 = -> + a变量 = 2 + return a变量 in [ 1, 2 + 3, 4 + ] + 函数6 = -> + b变量 = a变量 not in { + 1 + 2 + 字段x: 3 + } + nil diff --git a/spec/outputs/in_expression.lua b/spec/outputs/in_expression.lua index afcc030..b99be8a 100644 --- a/spec/outputs/in_expression.lua +++ b/spec/outputs/in_expression.lua @@ -2,10 +2,6 @@ f((function() local _val_0 = -a ^ 2 return 1 == _val_0 or 2 == _val_0 or 3 == _val_0 end)()) -f((function() - local _val_0 = -a ^ 2 - return 1 == _val_0 or 2 == _val_0 or 3 == _val_0 -end)()) local has do local _val_0 = "foo" diff --git a/spec/outputs/unicode/in_expression.lua b/spec/outputs/unicode/in_expression.lua index 7c584f3..2f47b1f 100644 --- a/spec/outputs/unicode/in_expression.lua +++ b/spec/outputs/unicode/in_expression.lua @@ -153,4 +153,56 @@ do return true end) end +do + local _u51fd_u65701 + _u51fd_u65701 = function() + local _u53d8_u91cfa = 2 + return (1 == _u53d8_u91cfa or 2 == _u53d8_u91cfa or 3 == _u53d8_u91cfa or 4 == _u53d8_u91cfa) + end + local _u51fd_u65702 + _u51fd_u65702 = function() + local _val_0 = _u53d8_u91cfa + return not (1 == _val_0 or 2 == _val_0 or 3 == _val_0 or 4 == _val_0) + end + local _u51fd_u65703 + _u51fd_u65703 = function() + local _u53d8_u91cfa = 2 + return (_u53d8_u91cfb == _u53d8_u91cfa or _u53d8_u91cfc == _u53d8_u91cfa or _u53d8_u91cfd == _u53d8_u91cfa or _u53d8_u91cfe == _u53d8_u91cfa or _u53d8_u91cff == _u53d8_u91cfa or _u53d8_u91cfg == _u53d8_u91cfa) + end + local _u51fd_u65704 + _u51fd_u65704 = function() + local _u53d8_u91cfa = 2 + local _u53d8_u91cfb + do + local _val_0 = a + _u53d8_u91cfb = 1 == _val_0 or 2 == _val_0 or 3 == _val_0 or 4 == _val_0 + end + end + local _u51fd_u65705 + _u51fd_u65705 = function() + local a_u53d8_u91cf = 2 + return (1 == a_u53d8_u91cf or 2 == a_u53d8_u91cf or 3 == a_u53d8_u91cf or 4 == a_u53d8_u91cf) + end + local _u51fd_u65706 + _u51fd_u65706 = function() + local b_u53d8_u91cf + do + local _check_0 = { + 1, + 2, + ["字段x"] = 3 + } + local _val_0 = a_u53d8_u91cf + 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 + b_u53d8_u91cf = not _find_0 + end + end +end return nil diff --git a/src/yuescript/yue_ast.cpp b/src/yuescript/yue_ast.cpp index c25f42d..faa175d 100644 --- a/src/yuescript/yue_ast.cpp +++ b/src/yuescript/yue_ast.cpp @@ -1405,15 +1405,8 @@ std::string UnaryExp_t::to_string(void* ud) const { } return line; } -std::string InDiscrete_t::to_string(void* ud) const { - str_list temp; - for (auto value : values.objects()) { - temp.emplace_back(value->to_string(ud)); - } - return '[' + join(temp, ", "sv) + (temp.size() == 1 ? ",]"s : "]"s); -} std::string In_t::to_string(void* ud) const { - return (not_ ? "not "s : ""s) + "in "s + item->to_string(ud); + return (not_ ? "not "s : ""s) + "in "s + value->to_string(ud); } std::string ExpListAssign_t::to_string(void* ud) const { if (action) { diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index fc07370..90dce7a 100644 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h @@ -81,6 +81,7 @@ class In_t; class NormalDef_t; class SpreadListExp_t; class Comprehension_t; +class Value_t; } // namespace yue AST_LEAF(Num) @@ -445,16 +446,10 @@ AST_END(UnaryOperator, "unary_op"sv) AST_LEAF(NotIn) AST_END(NotIn, "not_in"sv) -AST_NODE(InDiscrete) - ast_ptr sep; - ast_list values; - AST_MEMBER(InDiscrete, &sep, &values) -AST_END(InDiscrete, "in_discrete"sv) - AST_NODE(In) ast_ptr not_; - ast_sel item; - AST_MEMBER(In, ¬_, &item) + ast_ptr value; + AST_MEMBER(In, ¬_, &value) AST_END(In, "in"sv) AST_NODE(Assignable) diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 3892d72..5cdbfda 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp @@ -1231,7 +1231,7 @@ private: auto unary = static_cast(exp->pipeExprs.back()); BREAK_IF(unary->expos.size() != 1); BREAK_IF(!unary->inExp); - if (unary->inExp->item.is()) { + if (unary->inExp) { return unary; } auto value = static_cast(unary->expos.back()); @@ -5946,62 +5946,146 @@ private: varName.clear(); } } - ast_ptr discrete; - if (auto inExp = unary_exp->inExp->item.as()) { - BLOCK_START - auto value = singleValueFrom(inExp); - BREAK_IF(!value); - auto sval = value->item.as(); - BREAK_IF(!sval); - if (auto table = sval->value.as()) { - discrete = inExp->new_ptr(); - for (ast_node* val : table->values.objects()) { + ast_ptr discrete; + auto inExp = unary_exp->inExp->value.get(); + BLOCK_START + auto sval = inExp->item.as(); + BREAK_IF(!sval); + if (auto table = sval->value.as()) { + discrete = inExp->new_ptr(); + for (ast_node* val : table->values.objects()) { + if (auto def = ast_cast(val)) { + if (def->defVal) { + discrete = nullptr; + break; + } else { + discrete->exprs.push_back(def->item); + } + } else if (ast_is(val)) { + discrete->exprs.push_back(val); + } else { + discrete = nullptr; + break; + } + } + } else if (auto comp = sval->value.as()) { + if (comp->items.size() != 2 || !ast_is(comp->items.back())) { + discrete = inExp->new_ptr(); + for (ast_node* val : comp->items.objects()) { if (auto def = ast_cast(val)) { if (def->defVal) { discrete = nullptr; break; } else { - discrete->values.push_back(def->item); + discrete->exprs.push_back(def->item); } - } else if (ast_is(val)) { - discrete->values.push_back(val); } else { discrete = nullptr; break; } } - } else if (auto comp = sval->value.as()) { - if (comp->items.size() != 2 || !ast_is(comp->items.back())) { - discrete = inExp->new_ptr(); - for (ast_node* val : comp->items.objects()) { - if (auto def = ast_cast(val)) { - if (def->defVal) { - discrete = nullptr; - break; - } else { - discrete->values.push_back(def->item); - } - } else { - discrete = nullptr; - break; - } + } + } + BLOCK_END + BLOCK_START + BREAK_IF(discrete); + 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), newExp(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; + if (unary_exp->inExp->not_) { + _buf << "not "sv << findVar; + } else { + _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 { + auto arrayCheck = [&](bool exist) { + 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 "sv << (exist ? "true"sv : "false"sv) << nll(x); + decIndentOffset(); + _buf << indent() << "end"sv << nll(x); + decIndentOffset(); + _buf << indent() << "end"sv << nll(x); + _buf << indent() << "return "sv << (exist ? "false"sv : "true"sv) << nll(x); + temp.push_back(clearBuf()); + }; + bool useShortCheck = (usage == ExpUsage::Closure) && !varName.empty() && !checkVar.empty() && isLocal(checkVar); + if (useShortCheck) { + if (usage == ExpUsage::Return) { + arrayCheck(!unary_exp->inExp->not_); + } else { + pushFunctionScope(); + pushAnonVarArg(); + pushScope(); + arrayCheck(true); + temp.push_front("(#"s + checkVar + " > 0 and "s + anonFuncStart() + nll(x)); + popScope(); + temp.push_back(indent() + anonFuncEnd() + ')'); + if (unary_exp->inExp->not_) { + temp.front().insert(0, "not "s); } + popAnonVarArg(); + popFunctionScope(); + } + } else { + if (usage == ExpUsage::Closure) { + pushFunctionScope(); + pushAnonVarArg(); + pushScope(); } - } - BLOCK_END - - BLOCK_START - BREAK_IF(discrete); - 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); + auto assignment = assignmentFrom(toAst(checkVar, inExp), newExp(inExp, inExp), inExp); + transformAssignment(assignment, temp); } if (varName.empty()) { auto newUnaryExp = x->new_ptr(); @@ -6011,117 +6095,26 @@ private: 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); + transformAssignment(assignment, temp); } - 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; - if (unary_exp->inExp->not_) { - _buf << "not "sv << findVar; + if (usage == ExpUsage::Return) { + arrayCheck(!unary_exp->inExp->not_); } else { - _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 { - auto arrayCheck = [&](bool exist) { - 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 "sv << (exist ? "true"sv : "false"sv) << nll(x); - decIndentOffset(); - _buf << indent() << "end"sv << nll(x); - decIndentOffset(); - _buf << indent() << "end"sv << nll(x); - _buf << indent() << "return "sv << (exist ? "false"sv : "true"sv) << nll(x); - temp.push_back(clearBuf()); - }; - bool useShortCheck = (usage == ExpUsage::Closure) && !varName.empty() && !checkVar.empty() && isLocal(checkVar); - if (useShortCheck) { - if (usage == ExpUsage::Return) { - arrayCheck(!unary_exp->inExp->not_); - } else { - pushFunctionScope(); - pushAnonVarArg(); - pushScope(); - arrayCheck(true); - temp.push_front("(#"s + checkVar + " > 0 and "s + anonFuncStart() + nll(x)); - popScope(); - temp.push_back(indent() + anonFuncEnd() + ')'); - if (unary_exp->inExp->not_) { - temp.front().insert(0, "not "s); - } - popAnonVarArg(); - popFunctionScope(); - } - } else { - if (usage == ExpUsage::Closure) { - pushFunctionScope(); - pushAnonVarArg(); - pushScope(); - } - 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); - } - if (usage == ExpUsage::Return) { - arrayCheck(!unary_exp->inExp->not_); - } else { - arrayCheck(!unary_exp->inExp->not_); - temp.push_front(anonFuncStart() + nll(x)); - popScope(); - temp.push_back(indent() + anonFuncEnd()); - popAnonVarArg(); - popFunctionScope(); - } + arrayCheck(!unary_exp->inExp->not_); + temp.push_front(anonFuncStart() + nll(x)); + popScope(); + temp.push_back(indent() + anonFuncEnd()); + popAnonVarArg(); + popFunctionScope(); } - out.push_back(join(temp)); - return; } - BLOCK_END - } - if (!discrete) { - discrete = unary_exp->inExp->item.to(); + out.push_back(join(temp)); + return; } - if (usage == ExpUsage::Closure && discrete->values.size() == 1) { + BLOCK_END + if (usage == ExpUsage::Closure && discrete->exprs.size() == 1) { str_list tmp; - transformExp(static_cast(discrete->values.front()), tmp, ExpUsage::Closure); + transformExp(static_cast(discrete->exprs.front()), tmp, ExpUsage::Closure); tmp.push_back(" == "s); auto newUnaryExp = x->new_ptr(); newUnaryExp->ops.dup(unary_exp->ops); @@ -6156,7 +6149,7 @@ private: transformAssignment(assignment, temp); str_list tmp; - for (auto exp : discrete->values.objects()) { + for (auto exp : discrete->exprs.objects()) { transformExp(static_cast(exp), tmp, ExpUsage::Closure); } if (usage == ExpUsage::Assignment) { @@ -6196,7 +6189,7 @@ private: } } else { str_list tmp; - for (auto exp : discrete->values.objects()) { + for (auto exp : discrete->exprs.objects()) { transformExp(static_cast(exp), tmp, ExpUsage::Closure); } if (usage == ExpUsage::Assignment) { diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index 6aa0954..d138979 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp @@ -519,10 +519,7 @@ YueParser::YueParser() { expo_exp = Value >> *(space >> expo_value); NotIn = true_(); - InDiscrete = - '[' >> Seperator >> space >> exp_not_tab >> (+(space >> ',' >> space >> exp_not_tab) | space >> ',') >> space >> ']' | - '{' >> Seperator >> space >> exp_not_tab >> *(space >> ',' >> space >> exp_not_tab | space >> ',') >> space >> '}'; - In = -(key("not") >> NotIn >> space) >> key("in") >> space >> (InDiscrete | and_(key("not")) >> confusing_unary_not_error | Exp); + In = -(key("not") >> NotIn >> space) >> key("in") >> space >> (and_(key("not")) >> confusing_unary_not_error | Value); UnaryOperator = '-' >> not_(set(">=") | space_one) | diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h index 213d33e..39b7cce 100644 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h @@ -402,7 +402,6 @@ private: AST_RULE(UnaryValue); AST_RULE(UnaryExp); AST_RULE(NotIn); - AST_RULE(InDiscrete); AST_RULE(In); AST_RULE(ExpListAssign); AST_RULE(IfLine); -- cgit v1.2.3-55-g6feb