diff --git a/Assets/Script/Game/Touch the Sky/init.yue b/Assets/Script/Game/Touch the Sky/init.yue index c1f0df0da..71f2fad89 100755 --- a/Assets/Script/Game/Touch the Sky/init.yue +++ b/Assets/Script/Game/Touch the Sky/init.yue @@ -213,7 +213,7 @@ addHeartUI = -> loseHeart = -> heart = heart - 1 heartNode\removeAllChildren! - heartSprite = if heart in [0, 3] + heartSprite = if 0 <= heart <= 3 Sprite "Image/heart_#{math.tointeger heart}.png" else Sprite "Image/heart_0.png" diff --git a/Assets/Script/Lib/UI/View/Shape/CIrcle.d.tl b/Assets/Script/Lib/UI/View/Shape/Circle.d.tl similarity index 100% rename from Assets/Script/Lib/UI/View/Shape/CIrcle.d.tl rename to Assets/Script/Lib/UI/View/Shape/Circle.d.tl diff --git a/Assets/Script/Lib/YarnRunner.yue b/Assets/Script/Lib/YarnRunner.yue index cfa6f07f4..ce2ef8279 100644 --- a/Assets/Script/Lib/YarnRunner.yue +++ b/Assets/Script/Lib/YarnRunner.yue @@ -96,7 +96,7 @@ export default class YarnRunner unless @option return "Error", "there is no option to choose" :title, :branches = @option - if choice not in [1, #branches] + if not (1 <= choice <= #branches) return "Error", "choice #{choice} is out of range" optionBranch = branches[choice] @option = nil diff --git a/Source/3rdParty/yuescript/yue_ast.cpp b/Source/3rdParty/yuescript/yue_ast.cpp index ed34274b4..6126f7140 100644 --- a/Source/3rdParty/yuescript/yue_ast.cpp +++ b/Source/3rdParty/yuescript/yue_ast.cpp @@ -182,12 +182,6 @@ std::string ConstValue_t::to_string(void* ud) const { auto info = reinterpret_cast(ud); return info->convert(this); } -std::string InRangeOpen_t::to_string(void*) const { - return {}; -} -std::string InRangeClose_t::to_string(void*) const { - return {}; -} std::string NotIn_t::to_string(void*) const { return {}; } @@ -569,8 +563,18 @@ std::string Try_t::to_string(void* ud) const { return join(temp, "\n"sv); } std::string Comprehension_t::to_string(void* ud) const { - auto valueStr = value->to_string(ud); - return '[' + (valueStr[0] == '[' ? " "s : ""s) + valueStr + ' ' + forLoop->to_string(ud) + ']'; + str_list temp; + for (const auto& item : items.objects()) { + temp.push_back(item->to_string(ud)); + } + if (temp.size() > 0) { + temp.front().insert(0, temp.front()[0] == '[' ? " "s : ""s); + } + if (items.size() != 2 || !ast_is(items.back())) { + return '[' + join(temp, ", "sv) + ']'; + } else { + return '[' + join(temp, " "sv) + ']'; + } } std::string CompValue_t::to_string(void* ud) const { return value->to_string(ud); @@ -830,6 +834,9 @@ std::string Invoke_t::to_string(void* ud) const { std::string SpreadExp_t::to_string(void* ud) const { return "..."s + exp->to_string(ud); } +std::string SpreadListExp_t::to_string(void* ud) const { + return "..."s + exp->to_string(ud); +} std::string TableLit_t::to_string(void* ud) const { auto info = reinterpret_cast(ud); if (values.empty()) { @@ -1168,10 +1175,6 @@ std::string UnaryExp_t::to_string(void* ud) const { } return line; } -std::string InRange_t::to_string(void* ud) const { - auto valueStr = openValue->to_string(ud); - return (open.is() ? "("s : "["s + (valueStr[0] == '[' ? " "s : ""s)) + valueStr + ", "s + closeValue->to_string(ud) + (close.is() ? ')' : ']'); -} std::string InDiscrete_t::to_string(void* ud) const { str_list temp; for (auto value : values.objects()) { diff --git a/Source/3rdParty/yuescript/yue_ast.h b/Source/3rdParty/yuescript/yue_ast.h index a02f54886..2136849c6 100644 --- a/Source/3rdParty/yuescript/yue_ast.h +++ b/Source/3rdParty/yuescript/yue_ast.h @@ -78,6 +78,8 @@ class InvokeArgs_t; class TableBlockIndent_t; class Macro_t; class In_t; +class NormalDef_t; +class SpreadListExp_t; } // namespace yue AST_LEAF(Num) @@ -286,7 +288,7 @@ AST_NODE(SwitchList) AST_END(SwitchList, "switch_list"sv) AST_NODE(SwitchCase) - ast_sel condition; + ast_ptr condition; ast_sel body; AST_MEMBER(SwitchCase, &condition, &body) AST_END(SwitchCase, "switch_case"sv) @@ -374,9 +376,10 @@ AST_NODE(Try) AST_END(Try, "try"sv) AST_NODE(Comprehension) - ast_sel value; - ast_ptr forLoop; - AST_MEMBER(Comprehension, &value, &forLoop) + ast_ptr sep; + ast_sel_list items; + AST_MEMBER(Comprehension, &sep, &items) AST_END(Comprehension, "comp"sv) AST_NODE(CompValue) @@ -437,23 +440,9 @@ AST_END(BinaryOperator, "binary_op"sv) AST_LEAF(UnaryOperator) AST_END(UnaryOperator, "unary_op"sv) -AST_LEAF(InRangeOpen) -AST_END(InRangeOpen, "in_range_open"sv) - -AST_LEAF(InRangeClose) -AST_END(InRangeClose, "in_range_close"sv) - AST_LEAF(NotIn) AST_END(NotIn, "not_in"sv) -AST_NODE(InRange) - ast_sel open; - ast_ptr openValue; - ast_ptr closeValue; - ast_sel close; - AST_MEMBER(InRange, &open, &openValue, &closeValue, &close) -AST_END(InRange, "in_range"sv) - AST_NODE(InDiscrete) ast_ptr sep; ast_list values; @@ -462,7 +451,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) @@ -666,6 +655,11 @@ AST_NODE(SpreadExp) AST_MEMBER(SpreadExp, &exp) AST_END(SpreadExp, "spread_exp"sv) +AST_NODE(SpreadListExp) + ast_ptr exp; + AST_MEMBER(SpreadListExp, &exp) +AST_END(SpreadListExp, "spread_list_exp"sv) + AST_NODE(TableLit) ast_ptr sep; ast_sel_list values; + /*non-syntax-rule*/ TableBlockIndent_t, SpreadListExp_t> values; AST_MEMBER(TableLit, &sep, &values) AST_END(TableLit, "table_lit"sv) diff --git a/Source/3rdParty/yuescript/yue_compiler.cpp b/Source/3rdParty/yuescript/yue_compiler.cpp index 5b9770dcc..d32d9c199 100644 --- a/Source/3rdParty/yuescript/yue_compiler.cpp +++ b/Source/3rdParty/yuescript/yue_compiler.cpp @@ -15,6 +15,7 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include +#include #include "yuescript/yue_compiler.h" #include "yuescript/yue_parser.h" @@ -74,7 +75,7 @@ static std::unordered_set Metamethods = { "close"s // Lua 5.4 }; -const std::string_view version = "0.19.6"sv; +const std::string_view version = "0.20.0"sv; const std::string_view extension = "yue"sv; class CompileError : public std::logic_error { @@ -1148,6 +1149,10 @@ class YueCompilerImpl { auto simpleValue = static_cast(item); if (simpleValue->value.is()) { return true; + } else if (auto comp = simpleValue->value.as()) { + if (comp->items.size() != 2 || !ast_is(comp->items.back())) { + return true; + } } return false; } @@ -1195,6 +1200,28 @@ class YueCompilerImpl { return false; } + bool isConditionChainingOperator(const std::string& op) { + return op == "=="sv || op == "~="sv || op == "!="sv || + op == "<"sv || op == "<="sv || op == ">"sv || op == ">="sv; + } + + bool isConditionChaining(Exp_t* exp) { + int conditionChaining = 0; + for (const auto& opValue_ : exp->opValues.objects()) { + auto opValue = static_cast(opValue_); + auto op = _parser.toString(opValue->op); + if (isConditionChainingOperator(op)) { + conditionChaining++; + if (conditionChaining > 1) { + return true; + } + } else { + conditionChaining = 0; + } + } + return false; + } + UnaryExp_t* unaryGeneratingAnonFunc(Exp_t* exp) { if (!exp) return nullptr; BLOCK_START @@ -1440,10 +1467,10 @@ class YueCompilerImpl { case id(): { auto compInner = appendix->item.to(); auto comp = x->new_ptr(); - comp->forLoop.set(compInner); auto stmt = x->new_ptr(); stmt->content.set(statement->content); - comp->value.set(stmt); + comp->items.push_back(stmt); + comp->items.push_back(compInner); auto simpleValue = x->new_ptr(); simpleValue->value.set(comp); auto exp = newExp(simpleValue, x); @@ -2032,6 +2059,10 @@ class YueCompilerImpl { transformUnaryExp(unary, out, ExpUsage::Assignment, expList); out.back().insert(0, preDefine); return; + } else if (isConditionChaining(exp)) { + auto expList = assignment->expList.get(); + transformExp(exp, out, ExpUsage::Assignment, expList); + return; } auto singleVal = singleValueFrom(exp); BREAK_IF(!singleVal); @@ -2320,12 +2351,15 @@ class YueCompilerImpl { case id(): { auto item = singleValueFrom(node)->item.get(); if (!item) throw CompileError("invalid destructure value"sv, node); - auto tbA = item->get_by_path(); - if (tbA) { + if (auto tbA = item->get_by_path()) { tableItems = &tbA->values.objects(); - } else { - auto tbB = ast_cast(item); - if (tbB) tableItems = &tbB->pairs.objects(); + } else if (auto tbB = item->get_by_path()) { + if (tbB->items.size() == 2 && ast_is(tbB->items.back())) { + throw CompileError("invalid destructure value"sv, tbB); + } + tableItems = &tbB->items.objects(); + } else if (auto tbC = ast_cast(item)) { + tableItems = &tbC->pairs.objects(); } break; } @@ -2340,15 +2374,23 @@ class YueCompilerImpl { break; } case id(): { - auto table = ast_cast(node); + auto table = static_cast(node); tableItems = &table->values.objects(); break; } case id(): { - auto table = ast_cast(node); + auto table = static_cast(node); tableItems = &table->pairs.objects(); break; } + case id(): { + auto table = static_cast(node); + if (table->items.size() == 2 && ast_is(table->items.back())) { + throw CompileError("invalid destructure value"sv, table); + } + tableItems = &table->items.objects(); + break; + } default: YUEE("AST node mismatch", node); break; } if (!tableItems) throw CompileError("invalid destructure value"sv, node); @@ -2370,8 +2412,9 @@ class YueCompilerImpl { } auto value = singleValueFrom(pair); auto item = value->item.get(); - if (ast_is(item) || item->get_by_path()) { - auto subPairs = destructFromExp(pair, varDefOnly, optional); + ast_node* subExp = ast_cast(item); + if (subExp || (subExp = item->get_by_path()) || (subExp = item->get_by_path())) { + auto subPairs = destructFromExp(subExp, varDefOnly, optional); if (!subPairs.empty()) { if (defVal) { throw CompileError("default value is not supported here"sv, defVal); @@ -2448,8 +2491,9 @@ class YueCompilerImpl { if (auto exp = np->value.as()) { if (!varDefOnly && !isAssignable(exp)) throw CompileError("can't do destructure value"sv, exp); auto item = singleValueFrom(exp)->item.get(); - if (ast_is(item) || item->get_by_path()) { - auto subPairs = destructFromExp(exp, varDefOnly, optional); + ast_node* subExp = ast_cast(item); + if (subExp || (subExp = item->get_by_path()) || (subExp = item->get_by_path())) { + auto subPairs = destructFromExp(subExp, varDefOnly, optional); if (!subPairs.empty()) { if (defVal) { throw CompileError("default value is not supported here"sv, defVal); @@ -2602,8 +2646,19 @@ class YueCompilerImpl { if (!value) { throw CompileError("invalid destructure"sv, expr); } - ast_node* destructNode = value->get_by_path(); - if (destructNode || (destructNode = value->item.as())) { + ast_node* destructNode = value->item.as(); + if (!destructNode) { + if (auto sVal = value->item.as()) { + if (auto tab = sVal->value.as()) { + destructNode = tab; + } else if (auto comp = sVal->value.as()) { + if (comp->items.size() != 2 || !ast_is(comp->items.back())) { + destructNode = comp; + } + } + } + } + if (destructNode) { if (*j != nil) { if (auto ssVal = simpleSingleValueFrom(*j)) { switch (ssVal->value->get_id()) { @@ -2630,6 +2685,9 @@ class YueCompilerImpl { case id(): dlist = &static_cast(destructNode)->pairs.objects(); break; + case id(): + dlist = &static_cast(destructNode)->items.objects(); + break; default: YUEE("AST node mismatch", destructNode); break; } if (dlist->empty()) throw CompileError("expect items to be destructured"sv, destructNode); @@ -3300,27 +3358,173 @@ class YueCompilerImpl { transform_pipe_exp(exp->pipeExprs.objects(), out, usage, assignList); return; } - if (usage != ExpUsage::Closure) { - YUEE("invalid expression usage", exp); - } if (exp->nilCoalesed) { + if (usage != ExpUsage::Closure) { + YUEE("invalid expression usage", exp); + } transformNilCoalesedExp(exp, out, ExpUsage::Closure); return; } str_list temp; - transform_pipe_exp(exp->pipeExprs.objects(), temp, ExpUsage::Closure); + std::list*>> chains; + chains.emplace_back(std::string(), &exp->pipeExprs); + int conditionChainCount = 0; + str_list evalLines; + auto checkChains = [&]() { + std::optional result; + if (conditionChainCount > 1) { + bool needWrapping = false; + str_list conds; + str_list preDefines; + std::list>> stack; + for (const auto& item : chains) { + if (!item.first.empty()) { + stack.push_back(item.first); + } + auto node = item.second->front(); + bool checkEvalOnce = item != chains.front() && item != chains.back(); + if (checkEvalOnce) { + std::string varName; + if (item.second->size() == 1) { + if (auto unary = singleUnaryExpFrom(node)) { + if (auto value = singleValueFrom(unary)) { + varName = singleVariableFrom(value, true); + } + if (varName.empty()) { + if (auto sval = static_cast(unary->expos.front())->item.as()) { + if (ast_is(sval->value)) { + auto condExp = unary->new_ptr(); + condExp->pipeExprs.dup(*item.second); + stack.push_back(condExp); + goto reduce; + } + } + } + } + } + if (varName.empty() || !isLocal(varName)) { + varName = getUnusedName("_cond_"sv); + auto condExp = node->new_ptr(); + condExp->pipeExprs.dup(*item.second); + auto varExp = toAst(varName, node); + auto assignment = assignmentFrom(varExp, condExp, node); + if (!needWrapping) { + needWrapping = true; + if (usage == ExpUsage::Closure) { + pushFunctionScope(); + pushAnonVarArg(); + pushScope(); + } else if (usage == ExpUsage::Assignment) { + pushScope(); + } + } + transformAssignment(assignment, preDefines); + stack.push_back(varExp); + goto reduce; + } + } + { + auto condExp = node->new_ptr(); + condExp->pipeExprs.dup(*item.second); + stack.push_back(condExp); + } + reduce: + if (stack.size() == 3) { + str_list tmp; + auto one = std::get>(stack.front()).get(); + transformExp(one, tmp, ExpUsage::Closure); + stack.pop_front(); + auto two = std::get(stack.front()); + tmp.push_back(two); + stack.pop_front(); + auto three = std::get>(stack.front()).get(); + transformExp(three, tmp, ExpUsage::Closure); + conds.push_back(join(tmp, " "sv)); + } + } + auto condStr = join(conds, " and "sv); + if (needWrapping && usage == ExpUsage::Closure) { + str_list closureLines{anonFuncStart() + nll(exp)}; + closureLines.insert(closureLines.end(), preDefines.begin(), preDefines.end()); + closureLines.push_back(indent() + "return "s + condStr + nll(exp)); + popScope(); + closureLines.push_back(indent() + anonFuncEnd()); + temp.push_back(join(closureLines)); + popAnonVarArg(); + popFunctionScope(); + } else { + temp.push_back(condStr); + if (!preDefines.empty()) { + evalLines.insert(evalLines.end(), preDefines.begin(), preDefines.end()); + if (usage == ExpUsage::Assignment) { + popScope(); + } + } + } + } else { + for (const auto& item : chains) { + if (!item.first.empty()) { + temp.push_back(item.first); + } + transform_pipe_exp(item.second->objects(), temp, ExpUsage::Closure); + } + } + conditionChainCount = 0; + chains.clear(); + }; + str_list preDefines; for (auto _opValue : exp->opValues.objects()) { auto opValue = static_cast(_opValue); transformBinaryOperator(opValue->op, temp); - transform_pipe_exp(opValue->pipeExprs.objects(), temp, ExpUsage::Closure); + auto op = temp.back(); + temp.pop_back(); + if (isConditionChainingOperator(op)) { + conditionChainCount++; + chains.emplace_back(op, &opValue->pipeExprs); + } else { + checkChains(); + temp.push_back(op); + transform_pipe_exp(opValue->pipeExprs.objects(), temp, ExpUsage::Closure); + } + } + checkChains(); + auto condStr = join(temp, " "sv); + switch (usage) { + case ExpUsage::Closure: { + out.push_back(condStr); + break; + } + case ExpUsage::Assignment: { + auto assignment = exp->new_ptr(); + assignment->expList.set(assignList); + auto assign = exp->new_ptr(); + assign->values.push_back(toAst(condStr, exp)); + assignment->action.set(assign); + if (evalLines.empty()) { + transformAssignment(assignment, out); + } else { + evalLines.push_front(indent() + "do"s + nll(exp)); + evalLines.push_front(getPreDefineLine(assignment)); + pushScope(); + transformAssignment(assignment, evalLines); + popScope(); + evalLines.push_back(indent() + "end"s + nlr(exp)); + out.push_back(join(evalLines)); + } + break; + } + case ExpUsage::Return: { + evalLines.push_back(indent() + "return "s + condStr + nll(exp)); + out.push_back(join(evalLines)); + break; + } + default: YUEE("invalid expression usage", exp); break; } - out.push_back(join(temp, " "sv)); } void transformNilCoalesedExp(Exp_t* exp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr, bool nilBranchOnly = false) { auto x = exp; str_list temp; - std::string prefix; auto left = exp->new_ptr(); if (exp->opValues.empty()) { left->pipeExprs.dup(exp->pipeExprs); @@ -3328,20 +3532,16 @@ class YueCompilerImpl { if (usage != ExpUsage::Closure) { YUEE("invalid expression usage", exp); } - transform_pipe_exp(exp->pipeExprs.objects(), temp, ExpUsage::Closure); - auto last = exp->opValues.objects().back(); - for (auto _opValue : exp->opValues.objects()) { - auto opValue = static_cast(_opValue); - transformBinaryOperator(opValue->op, temp); - if (opValue == last) { - left->pipeExprs.dup(opValue->pipeExprs); - } else { - transform_pipe_exp(opValue->pipeExprs.objects(), temp, ExpUsage::Closure); - } - } - prefix = join(temp, " "sv) + ' '; - temp.clear(); - temp.push_back(prefix); + auto last = static_cast(exp->opValues.back()); + left->pipeExprs.dup(last->pipeExprs); + + auto startExp = x->new_ptr(); + startExp->pipeExprs.dup(exp->pipeExprs); + startExp->opValues.dup(exp->opValues); + startExp->opValues.pop_back(); + transformExp(startExp, temp, ExpUsage::Closure); + transformBinaryOperator(last->op, temp); + temp.back() = " "s + temp.back() + " "s; } std::string* funcStart = nullptr; if (usage == ExpUsage::Closure) { @@ -4303,6 +4503,9 @@ class YueCompilerImpl { } else if (auto unary = unaryGeneratingAnonFunc(exp)) { transformUnaryExp(unary, out, ExpUsage::Return); return; + } else if (isConditionChaining(exp)) { + transformExp(exp, out, ExpUsage::Return); + return; } } if (auto singleValue = singleValueFrom(valueList)) { @@ -5791,6 +5994,24 @@ class YueCompilerImpl { return; } } + auto discrete = unary_exp->inExp->item.to(); + if (usage == ExpUsage::Closure && discrete->values.size() == 1) { + str_list tmp; + transformExp(static_cast(discrete->values.front()), tmp, ExpUsage::Closure); + tmp.push_back(" == "s); + auto newUnaryExp = x->new_ptr(); + newUnaryExp->ops.dup(unary_exp->ops); + newUnaryExp->expos.dup(unary_exp->expos); + transformUnaryExp(newUnaryExp, tmp, ExpUsage::Closure); + tmp.push_back(")"s); + if (unary_exp->inExp->not_) { + tmp.push_front("not ("s); + } else { + tmp.push_front("("s); + } + out.push_back(join(tmp)); + return; + } if (varName.empty()) { str_list temp; if (usage == ExpUsage::Closure) { @@ -5809,54 +6030,32 @@ class YueCompilerImpl { auto assignExp = toAst(newVar, x); auto assignment = assignmentFrom(assignExp, exp, x); transformAssignment(assignment, temp); - if (auto range = unary_exp->inExp->item.as()) { - str_list tmp; - transformExp(range->openValue, tmp, ExpUsage::Closure); - transformExp(range->closeValue, tmp, ExpUsage::Closure); - if (usage == ExpUsage::Assignment) { - str_list tmpList; - transformExp(static_cast(assignList->exprs.front()), tmpList, ExpUsage::Closure); - _buf << indent() << tmpList.back() << " = "sv; - } else { - _buf << indent() << "return "sv; - } - if (unary_exp->inExp->not_) { - _buf << "not ("sv; - } - _buf << tmp.front() << (range->open.is() ? " < "sv : " <= "sv) << newVar << " and "sv << newVar << (range->close.is() ? " < "sv : " <= "sv) << tmp.back(); - if (unary_exp->inExp->not_) { - _buf << ")"sv; - } - _buf << nll(x); - temp.push_back(clearBuf()); + + str_list tmp; + for (auto exp : discrete->values.objects()) { + transformExp(static_cast(exp), tmp, ExpUsage::Closure); + } + if (usage == ExpUsage::Assignment) { + str_list tmpList; + transformExp(static_cast(assignList->exprs.front()), tmpList, ExpUsage::Closure); + _buf << indent() << tmpList.back() << " = "sv; } else { - auto discrete = unary_exp->inExp->item.to(); - str_list tmp; - for (auto exp : discrete->values.objects()) { - transformExp(static_cast(exp), tmp, ExpUsage::Closure); - } - if (usage == ExpUsage::Assignment) { - str_list tmpList; - transformExp(static_cast(assignList->exprs.front()), tmpList, ExpUsage::Closure); - _buf << indent() << tmpList.back() << " = "sv; - } else { - _buf << indent() << "return "sv; - } - if (unary_exp->inExp->not_) { - _buf << "not ("sv; - } - for (const auto& exp : tmp) { - _buf << exp << " == "sv << newVar; - if (exp != tmp.back()) { - _buf << " or "sv; - } - } - if (unary_exp->inExp->not_) { - _buf << ")"sv; + _buf << indent() << "return "sv; + } + if (unary_exp->inExp->not_) { + _buf << "not ("sv; + } + for (const auto& exp : tmp) { + _buf << exp << " == "sv << newVar; + if (exp != tmp.back()) { + _buf << " or "sv; } - _buf << nll(x); - temp.push_back(clearBuf()); } + if (unary_exp->inExp->not_) { + _buf << ")"sv; + } + _buf << nll(x); + temp.push_back(clearBuf()); if (usage == ExpUsage::Closure) { temp.push_front(anonFuncStart() + nll(x)); popScope(); @@ -5872,35 +6071,22 @@ class YueCompilerImpl { out.push_back(join(temp)); } } else { - if (auto range = unary_exp->inExp->item.as()) { - str_list tmp; - transformExp(range->openValue, tmp, ExpUsage::Closure); - transformExp(range->closeValue, tmp, ExpUsage::Closure); - if (unary_exp->inExp->not_) { - _buf << "not "sv; - } - _buf << '(' << tmp.front() << (range->open.is() ? " < "sv : " <= "sv) << varName << " and "sv << varName << (range->close.is() ? " < "sv : " <= "sv) << tmp.back(); - _buf << ')'; - out.push_back(clearBuf()); - } else { - auto discrete = unary_exp->inExp->item.to(); - str_list tmp; - for (auto exp : discrete->values.objects()) { - transformExp(static_cast(exp), tmp, ExpUsage::Closure); - } - if (unary_exp->inExp->not_) { - _buf << "not "sv; - } - _buf << '('; - for (const auto& exp : tmp) { - _buf << exp << " == "sv << varName; - if (exp != tmp.back()) { - _buf << " or "sv; - } + str_list tmp; + for (auto exp : discrete->values.objects()) { + transformExp(static_cast(exp), tmp, ExpUsage::Closure); + } + if (unary_exp->inExp->not_) { + _buf << "not "sv; + } + _buf << '('; + for (const auto& exp : tmp) { + _buf << exp << " == "sv << varName; + if (exp != tmp.back()) { + _buf << " or "sv; } - _buf << ')'; - out.push_back(clearBuf()); } + _buf << ')'; + out.push_back(clearBuf()); } return; } @@ -5945,7 +6131,7 @@ class YueCompilerImpl { bool hasSpreadExp(const node_container& items) { for (auto item : items) { - if (ast_is(item)) return true; + if (ast_is(item)) return true; } return false; } @@ -5968,11 +6154,11 @@ class YueCompilerImpl { std::string tableVar = getUnusedName("_tab_"sv); forceAddToScope(tableVar); auto it = values.begin(); - if (ast_is(*it)) { + if (ast_is(*it)) { temp.push_back(indent() + "local "s + tableVar + " = { }"s + nll(x)); } else { auto initialTab = x->new_ptr(); - while (it != values.end() && !ast_is(*it)) { + while (it != values.end() && !ast_is(*it)) { initialTab->values.push_back(*it); ++it; } @@ -6007,6 +6193,28 @@ class YueCompilerImpl { transformForEach(forEach, temp); break; } + case id(): { + auto spread = static_cast(item); + std::string indexVar = getUnusedName("_idx_"sv); + std::string valueVar = getUnusedName("_value_"sv); + auto objVar = singleVariableFrom(spread->exp, true); + if (objVar.empty()) { + objVar = getUnusedName("_obj_"); + auto assignment = toAst(objVar + "=nil"s, item); + auto assign = assignment->action.to(); + assign->values.clear(); + assign->values.push_back(spread->exp); + transformAssignment(assignment, temp); + } + forceAddToScope(indexVar); + temp.push_back(indent() + "local "s + indexVar + " = #"s + tableVar + " + 1"s + nll(item)); + _buf << "for "sv << valueVar << " in *"sv << objVar + << "\n\t"sv << tableVar << '[' << indexVar << "]="sv << valueVar + << "\n\t"sv << indexVar << "+=1"sv; + auto forEach = toAst(clearBuf(), item); + transformForEach(forEach, temp); + break; + } case id(): case id(): { if (auto pair = ast_cast(item)) { @@ -6374,7 +6582,7 @@ class YueCompilerImpl { void transformCompCommon(Comprehension_t* comp, str_list& out) { str_list temp; auto x = comp; - auto compInner = comp->forLoop.get(); + auto compInner = static_cast(comp->items.back()); for (auto item : compInner->items.objects()) { switch (item->get_id()) { case id(): @@ -6391,9 +6599,9 @@ class YueCompilerImpl { default: YUEE("AST node mismatch", item); break; } } - if (auto stmt = comp->value.as()) { + if (auto stmt = ast_cast(comp->items.front())) { transformStatement(stmt, temp); - } else if (auto exp = comp->value.as()) { + } else if (auto exp = ast_cast(comp->items.front())) { auto expList = x->new_ptr(); expList->exprs.push_back(exp); auto expListAssign = x->new_ptr(); @@ -6414,6 +6622,48 @@ class YueCompilerImpl { void transformComprehension(Comprehension_t* comp, str_list& out, ExpUsage usage, ExpList_t* assignList = nullptr) { auto x = comp; + if (comp->items.size() != 2 || !ast_is(comp->items.back())) { + auto tableLit = x->new_ptr(); + tableLit->values.dup(comp->items); + switch (usage) { + case ExpUsage::Assignment: { + auto simpleValue = x->new_ptr(); + simpleValue->value.set(tableLit); + auto exp = newExp(simpleValue, x); + auto assignment = x->new_ptr(); + assignment->expList.set(assignList); + auto assign = x->new_ptr(); + assign->values.push_back(exp); + assignment->action.set(assign); + transformAssignment(assignment, out); + break; + } + case ExpUsage::Return: { + auto simpleValue = x->new_ptr(); + simpleValue->value.set(tableLit); + auto exp = newExp(simpleValue, x); + auto returnNode = x->new_ptr(); + auto expList = x->new_ptr(); + expList->exprs.push_back(exp); + returnNode->valueList.set(expList); + transformReturn(returnNode, out); + break; + } + case ExpUsage::Closure: + transformTableLit(tableLit, out); + break; + default: + YUEE("invalid comprehension usage", comp); + break; + } + return; + } + auto def = ast_cast(comp->items.front()); + if (!def || def->defVal) { + throw CompileError("invalid comprehension expression", comp->items.front()); + } + auto value = def->item.get(); + auto compInner = static_cast(comp->items.back()); switch (usage) { case ExpUsage::Closure: pushFunctionScope(); @@ -6431,7 +6681,6 @@ class YueCompilerImpl { std::string lenVar = getUnusedName("_len_"sv); addToScope(accumVar); addToScope(lenVar); - auto compInner = comp->forLoop.get(); for (auto item : compInner->items.objects()) { switch (item->get_id()) { case id(): @@ -6451,7 +6700,7 @@ class YueCompilerImpl { { auto assignLeft = toAst(accumVar + '[' + lenVar + ']', x); auto assign = x->new_ptr(); - assign->values.push_back(comp->value); + assign->values.push_back(value); auto assignment = x->new_ptr(); assignment->expList.set(assignLeft); assignment->action.set(assign); @@ -8830,19 +9079,7 @@ class YueCompilerImpl { std::string tabCheckVar; for (auto branch_ : branches) { auto branch = static_cast(branch_); - if (auto inExp = branch->condition.as()) { - auto unary = branch->new_ptr(); - unary->expos.push_back(toAst(objVar, branch)); - unary->inExp.set(inExp); - transformUnaryExp(unary, temp, ExpUsage::Closure); - temp.back() = indent() + (firstBranch ? "if "s : "elseif "s) + temp.back() + " then"s + nll(branch); - pushScope(); - transform_plain_body(branch->body, temp, usage, assignList); - popScope(); - firstBranch = false; - continue; - } - auto valueList = branch->condition.to(); + auto valueList = static_cast(branch->condition.get()); if (auto value = singleValueFrom(valueList); value && (value->item.is() || value->get_by_path())) { if (!firstBranch) { diff --git a/Source/3rdParty/yuescript/yue_parser.cpp b/Source/3rdParty/yuescript/yue_parser.cpp index c8180982b..8ceee9a91 100644 --- a/Source/3rdParty/yuescript/yue_parser.cpp +++ b/Source/3rdParty/yuescript/yue_parser.cpp @@ -109,6 +109,11 @@ YueParser::YueParser() { return false; }); + table_key_pair_error = pl::user(true_(), [](const item_t& item) { + throw ParserError("can not put hash pair in a list"sv, item.begin); + return false; + }); + #define ensure(patt, finally) ((patt) >> (finally) | (finally) >> cut) #define key(str) (expr(str) >> not_alpha_num) @@ -342,7 +347,7 @@ 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") >> space >> (disable_chain_rule(disable_arg_table_block_rule(SwitchList)) | In) >> space >> body_with("then"); + SwitchCase = key("when") >> space >> disable_chain_rule(disable_arg_table_block_rule(SwitchList)) >> space >> body_with("then"); switch_else = key("else") >> space >> body; switch_block = @@ -449,7 +454,37 @@ YueParser::YueParser() { CatchBlock = line_break >> *space_break >> check_indent_match >> space >> key("catch") >> space >> Variable >> space >> in_block; Try = key("try") >> space >> (in_block | Exp) >> -CatchBlock; - Comprehension = '[' >> not_('[') >> space >> disable_for_rule(Exp) >> space >> CompInner >> space >> ']'; + list_value = + and_( + VariablePairDef | + NormalPairDef | + MetaVariablePairDef | + MetaNormalPairDef + ) >> table_key_pair_error | + SpreadListExp | + NormalDef; + + list_value_list = +(space >> ',' >> space >> list_value); + + list_lit_line = ( + push_indent_match >> (space >> list_value >> -list_value_list >> pop_indent | pop_indent) + ) | ( + space + ); + + list_lit_lines = space_break >> list_lit_line >> *(-(space >> ',') >> space_break >> list_lit_line) >> -(space >> ','); + + Comprehension = '[' >> not_('[') >> + Seperator >> space >> ( + disable_for_rule(list_value) >> space >> ( + CompInner >> space >> ']' | + (list_value_list >> -(space >> ',') | space >> ',') >> -list_lit_lines >> white >> ']' + ) | + list_lit_lines >> white >> ']' | + white >> ']' >> not_(space >> '=') + ); + + (space >> disable_for_rule(Exp) >> space >> CompInner >> space >> ']'); CompValue = ',' >> space >> Exp; TblComprehension = and_('{') >> ('{' >> space >> disable_for_rule(Exp >> space >> -(CompValue >> space)) >> CompInner >> space >> '}' | braces_expression_error); @@ -479,12 +514,11 @@ YueParser::YueParser() { expo_value = exponential_operator >> *space_break >> space >> Value; expo_exp = Value >> *(space >> expo_value); - InRangeOpen = true_(); - InRangeClose = true_(); NotIn = true_(); - InRange = ('(' >> InRangeOpen | '[' >> InRangeClose) >> space >> Exp >> space >> ',' >> space >> Exp >> space >> (')' >> InRangeOpen | ']' >> InRangeClose); - InDiscrete = '{' >> Seperator >> space >> exp_not_tab >> *(space >> ',' >> space >> exp_not_tab) >> space >> '}'; - In = -(key("not") >> NotIn >> space) >> key("in") >> space >> (InRange | InDiscrete | and_(key("not")) >> confusing_unary_not_error | Exp); + InDiscrete = + '[' >> Seperator >> space >> exp_not_tab >> (+(space >> ',' >> space >> exp_not_tab) | space >> ',') >> space >> ']' | + '{' >> Seperator >> space >> exp_not_tab >> *(space >> ',' >> space >> exp_not_tab) >> space >> '}'; + In = -(key("not") >> NotIn >> space) >> key("in") >> space >> (InDiscrete | and_(key("not")) >> confusing_unary_not_error | Exp); UnaryOperator = '-' >> not_(set(">=") | space_one) | @@ -635,7 +669,7 @@ YueParser::YueParser() { space >> ',' >> space >> (Exp | DefaultValue) >> space >> (',' >> space >> Exp | DefaultValue) >> - space >> ']'; + space >> (']' | slice_expression_error); Invoke = Seperator >> ( fn_args | @@ -646,6 +680,7 @@ YueParser::YueParser() { ); SpreadExp = "..." >> space >> Exp; + SpreadListExp = "..." >> space >> Exp; table_value = VariablePairDef | @@ -667,8 +702,7 @@ YueParser::YueParser() { TableLit = space >> '{' >> Seperator >> - -(space >> table_value_list) >> - -(space >> ',') >> + -(space >> table_value_list >> -(space >> ',')) >> -table_lit_lines >> white >> '}'; @@ -834,7 +868,7 @@ YueParser::YueParser() { }); InvokeArgs = - not_(set("-~")) >> space >> Seperator >> ( + not_(set("-~") | "[]") >> space >> Seperator >> ( Exp >> *(space >> ',' >> space >> Exp) >> -(space >> invoke_args_with_table) | arg_table_block | leading_spaces_error @@ -852,6 +886,11 @@ YueParser::YueParser() { return false; }); + slice_expression_error = pl::user(true_(), [](const item_t& item) { + throw ParserError("syntax error in slice expression"sv, item.begin); + return false; + }); + SimpleValue = TableLit | ConstValue | If | Switch | Try | With | ClassDecl | ForEach | For | While | Do | diff --git a/Source/3rdParty/yuescript/yue_parser.h b/Source/3rdParty/yuescript/yue_parser.h index 7864300d7..8156ae227 100644 --- a/Source/3rdParty/yuescript/yue_parser.h +++ b/Source/3rdParty/yuescript/yue_parser.h @@ -136,9 +136,11 @@ class YueParser { NONE_AST_RULE(indentation_error); NONE_AST_RULE(braces_expression_error); NONE_AST_RULE(brackets_expression_error); + NONE_AST_RULE(slice_expression_error); NONE_AST_RULE(export_expression_error); NONE_AST_RULE(invalid_interpolation_error); NONE_AST_RULE(confusing_unary_not_error); + NONE_AST_RULE(table_key_pair_error); NONE_AST_RULE(inc_exp_level); NONE_AST_RULE(dec_exp_level); @@ -202,6 +204,10 @@ class YueParser { NONE_AST_RULE(for_key); NONE_AST_RULE(for_args); NONE_AST_RULE(for_in); + NONE_AST_RULE(list_value); + NONE_AST_RULE(list_value_list); + NONE_AST_RULE(list_lit_line); + NONE_AST_RULE(list_lit_lines); NONE_AST_RULE(comp_clause); NONE_AST_RULE(chain); NONE_AST_RULE(chain_list); @@ -352,6 +358,7 @@ class YueParser { AST_RULE(ExistentialOp); AST_RULE(TableAppendingOp); AST_RULE(SpreadExp); + AST_RULE(SpreadListExp); AST_RULE(TableLit); AST_RULE(TableBlock); AST_RULE(TableBlockIndent); @@ -388,10 +395,7 @@ class YueParser { AST_RULE(ConstValue); AST_RULE(UnaryValue); AST_RULE(UnaryExp); - AST_RULE(InRangeOpen); - AST_RULE(InRangeClose); AST_RULE(NotIn); - AST_RULE(InRange); AST_RULE(InDiscrete); AST_RULE(In); AST_RULE(ExpListAssign);