From 3fe498781dea9ef2ea46b864506fdac7a86b7c67 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Fri, 17 May 2024 16:44:44 +0800 Subject: [PATCH] update Yuescript. [skip CI] --- Source/3rdParty/yuescript/yue_compiler.cpp | 326 ++++++++++++++++++++- 1 file changed, 310 insertions(+), 16 deletions(-) diff --git a/Source/3rdParty/yuescript/yue_compiler.cpp b/Source/3rdParty/yuescript/yue_compiler.cpp index c2050318f..7f6a04248 100644 --- a/Source/3rdParty/yuescript/yue_compiler.cpp +++ b/Source/3rdParty/yuescript/yue_compiler.cpp @@ -75,7 +75,7 @@ static std::unordered_set Metamethods = { "close"s // Lua 5.4 }; -const std::string_view version = "0.23.4"sv; +const std::string_view version = "0.23.6"sv; const std::string_view extension = "yue"sv; class CompileError : public std::logic_error { @@ -577,6 +577,273 @@ class YueCompilerImpl { } } + bool isConstTableItem(ast_node* item) { + switch (item->get_id()) { + case id(): { + auto pair = static_cast(item); + if (pair->defVal) return false; + return isConstTableItem(pair->pair); + } + case id(): { + auto pair = static_cast(item); + if (pair->defVal) return false; + return isConstTableItem(pair->pair); + } + case id(): { + auto pair = static_cast(item); + if (pair->defVal) return false; + return isConstTableItem(pair->pair); + } + case id(): { + auto pair = static_cast(item); + if (pair->defVal) return false; + return isConstTableItem(pair->pair); + } + case id(): { + auto pair = static_cast(item); + if (pair->defVal) return false; + return isConstTableItem(pair->item); + } + case id(): { + auto pair = static_cast(item); + return isConstExp(pair); + } + case id(): { + auto pair = static_cast(item); + return isLocal(variableToString(pair->name)); + } + case id(): { + auto pair = static_cast(item); + if (auto exp = pair->key.as()) { + if (!isConstExp(exp)) { + return false; + } + } + if (auto exp = pair->value.as()) { + if (!isConstExp(exp)) { + return false; + } + } else if (auto tbBlock = pair->value.as()) { + if (!isConstTable(tbBlock)) { + return false; + } + } else { + return false; + } + return true; + } + case id(): { + auto pair = static_cast(item); + return isConstTable(pair); + } + case id(): { + auto pair = static_cast(item); + return isConstTable(pair); + break; + } + case id(): { + auto pair = static_cast(item); + return isLocal(variableToString(pair->name)); + } + case id(): { + auto pair = static_cast(item); + if (auto str = pair->key.as()) { + if (!ast_is(str)) { + return false; + } + } else if (auto exp = pair->key.as()) { + if (!isConstExp(exp)) { + return false; + } + } else if (pair->key.is()) { + return true; + } else { + return false; + } + if (auto exp = pair->value.as()) { + if (!isConstExp(exp)) { + return false; + } + } else if (auto tbBlock = pair->value.as()) { + if (!isConstTable(tbBlock)) { + return false; + } + } else { + return false; + } + return true; + } + } + return false; + } + + bool isConstTable(TableLit_t* tableLit) { + for (auto value : tableLit->values.objects()) { + if (!isConstTableItem(value)) { + return false; + } + } + return true; + } + + bool isConstTable(TableBlock_t* tableBlock) { + for (auto value : tableBlock->values.objects()) { + if (!isConstTableItem(value)) { + return false; + } + } + return true; + } + + bool isConstTable(SimpleTable_t* stable) { + for (auto value : stable->pairs.objects()) { + if (!isConstTableItem(value)) { + return false; + } + } + return true; + } + + bool isConstTable(TableBlockIndent_t* table) { + for (auto value : table->values.objects()) { + if (!isConstTableItem(value)) { + return false; + } + } + return true; + } + + bool isConstChainValue(ChainValue_t* value) { + auto var = singleVariableFrom(value, AccessType::None); + return isLocal(var); + } + + bool isConstUnaryValue(UnaryValue_t* value) { + if (value->ops.size() > 1) { + return false; + } + auto unaryStr = _parser.toString(value->ops.front()); + if (unaryStr == "-"sv) { + return value->value->item->get_by_path(); + } else if (unaryStr == "#"sv) { + return false; + } else if (unaryStr == "not"sv) { + return isConstValue(value->value); + } + return false; + } + + bool isConstNum(Value_t* value) { + return value->get_by_path(); + } + + bool isConstUnaryExp(UnaryExp_t* value) { + if (value->inExp) return false; + if (value->ops.size() == 0) { + if (value->expos.size() == 1) { + return isConstValue(static_cast(value->expos.front())); + } + for (auto expo : value->expos.objects()) { + if (!isConstNum(static_cast(expo))) { + return false; + } + } + return true; + } + if (value->ops.size() > 1) { + return false; + } + auto unaryStr = _parser.toString(value->ops.front()); + if (unaryStr == "-"sv) { + for (auto expo : value->expos.objects()) { + if (!isConstNum(static_cast(expo))) { + return false; + } + } + return true; + } else if (unaryStr == "#"sv) { + return false; + } else if (unaryStr == "not"sv) { + if (value->expos.size() == 1) { + return isConstValue(static_cast(value->expos.front())); + } + for (auto expo : value->expos.objects()) { + if (!isConstNum(static_cast(expo))) { + return false; + } + } + return true; + } + return false; + } + + bool isConstValue(Value_t* value) { + if (auto strNode = value->item.as()) { + switch (strNode->str->get_id()) { + case id(): + case id(): + return true; + case id(): + return false; + default: + YUEE("AST node mismatch", strNode->str); + return false; + } + } else if (auto chainValue = value->item.as()) { + return isConstChainValue(chainValue); + } else if (auto simpleValue = value->item.as()) { + if (ast_is(simpleValue->value.get())) { + return true; + } else if (auto uValue = simpleValue->value.as()) { + return isConstUnaryValue(uValue); + } else if (auto comp = simpleValue->value.as()) { + for (auto item : comp->items.objects()) { + if (auto ndef = ast_cast(item)) { + if (ndef->defVal) { + return false; + } + if (!isConstExp(ndef->item)) { + return false; + } + } else { + return false; + } + } + return true; + } else if (auto tableLit = simpleValue->value.as()) { + return isConstTable(tableLit); + } else { + return false; + } + } else if (auto simpleTable = value->item.as()) { + return isConstTable(simpleTable); + } + return false; + } + + bool isConstUnaryExps(const ast_list& list) { + if (list.size() > 1) { + return false; + } + if (!isConstUnaryExp(static_cast(list.front()))) { + return false; + } + return true; + } + + bool isConstExp(Exp_t* exp) { + if (exp->nilCoalesed) { + return false; + } + if (!isConstUnaryExps(exp->pipeExprs)) { + return false; + } + if (exp->opValues.empty()) { + return true; + } + return false; + } + void markVarConst(const std::string& name) { auto& scope = _scopes.back(); scope.vars->insert_or_assign(name, VarType::Const); @@ -3691,7 +3958,7 @@ class YueCompilerImpl { }) != traversal::Stop; } - std::optional> getUpValueFuncFromBlock(Block_t* block, str_list* ensureArgListInTheEnd) { + std::optional> getUpValueFuncFromBlock(Block_t* block, str_list* ensureArgListInTheEnd, bool noGlobalVarPassing) { if (_funcLevel <= 1) return std::nullopt; auto result = block->traverse([&](ast_node* node) { switch (node->get_id()) { @@ -3754,6 +4021,9 @@ class YueCompilerImpl { } else if (std::find(args.begin(), args.end(), global.name) == args.end()) { args.push_back(global.name); } + if (noGlobalVarPassing && !isLocal(global.name)) { + return std::nullopt; + } } } } @@ -3809,9 +4079,9 @@ class YueCompilerImpl { } - std::optional> upValueFuncFrom(Block_t* block, str_list* ensureArgListInTheEnd = nullptr) { + std::optional> upValueFuncFrom(Block_t* block, str_list* ensureArgListInTheEnd = nullptr, bool noGlobalVarPassing = false) { if (checkUpValueFuncAvailable(block)) { - return getUpValueFuncFromBlock(block, ensureArgListInTheEnd); + return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, noGlobalVarPassing); } return std::nullopt; } @@ -3826,7 +4096,7 @@ class YueCompilerImpl { auto stmt = exp->new_ptr(); stmt->content.set(returnNode); block->statements.push_back(stmt); - return getUpValueFuncFromBlock(block, ensureArgListInTheEnd); + return getUpValueFuncFromBlock(block, ensureArgListInTheEnd, false); } return std::nullopt; } @@ -9135,23 +9405,47 @@ class YueCompilerImpl { BREAK_IF(var.empty()); tryFunc.set(expListAssign->expList->exprs.front()); BLOCK_END - } else { - auto tryExp = tryFunc.as(); - bool needWrap = singleVariableFrom(tryExp, AccessType::None).empty(); + } + if (auto tryExp = tryFunc.as()) { + bool wrapped = true; BLOCK_START auto value = singleValueFrom(tryExp); BREAK_IF(!value); auto chainValue = value->item.as(); BREAK_IF(!chainValue); BREAK_IF(!isChainValueCall(chainValue)); - auto tmpChain = chainValue->new_ptr(); - tmpChain->items.dup(chainValue->items); - tmpChain->items.pop_back(); - auto var = singleVariableFrom(tmpChain, AccessType::None); - BREAK_IF(var.empty()); - needWrap = false; + auto chainCaller = chainValue->new_ptr(); + chainCaller->items.dup(chainValue->items); + chainCaller->items.pop_back(); + BREAK_IF(!isConstChainValue(chainCaller)); + _ast_list* args = nullptr; + if (auto invoke = ast_cast(chainValue->items.back())) { + args = &invoke->args; + } else { + args = &(ast_to(chainValue->items.back())->args); + } + wrapped = false; + for (auto arg : args->objects()) { + switch (arg->get_id()) { + case id(): + if (isConstExp(static_cast(arg))) continue; + break; + case id(): + case id(): + continue; + case id(): + break; + case id(): + if (isConstTable(static_cast(arg))) continue; + break; + case id(): + if (isConstTable(static_cast(arg))) continue; + break; + } + wrapped = true; + } BLOCK_END - if (needWrap) { + if (wrapped) { auto expList = x->new_ptr(); expList->exprs.push_back(tryFunc); auto expListAssign = x->new_ptr(); @@ -9165,7 +9459,7 @@ class YueCompilerImpl { } if (auto tryBlock = tryFunc.as()) { if (getLuaTarget(tryBlock) >= 502 || !errHandler) { - if (auto result = upValueFuncFrom(tryBlock)) { + if (auto result = upValueFuncFrom(tryBlock, nullptr, true)) { auto [funcName, args] = std::move(*result); if (errHandler) { auto xpcall = toAst("xpcall()", x);