From f38c4f94c9ba0499d923e59483d6381b97cce926 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Thu, 19 Dec 2024 11:26:23 +0800 Subject: Fixed MoonScript issue # 459. Supported local/const/close hoist in class body. --- src/yuescript/yue_ast.h | 2 +- src/yuescript/yue_compiler.cpp | 99 +++++++++++++++++++++++++++++++++++++++--- 2 files changed, 94 insertions(+), 7 deletions(-) (limited to 'src') diff --git a/src/yuescript/yue_ast.h b/src/yuescript/yue_ast.h index 92d67ac..033fe30 100644 --- a/src/yuescript/yue_ast.h +++ b/src/yuescript/yue_ast.h @@ -52,7 +52,6 @@ std::string_view ast_name() { return {}; } namespace yue { class ExpListLow_t; class TableBlock_t; -class Attrib_t; class SimpleTable_t; class TableLit_t; class Assign_t; @@ -181,6 +180,7 @@ AST_NODE(LocalAttrib) ast_ptr sep; ast_sel_list leftList; ast_ptr assign; + bool forceLocal = true; AST_MEMBER(LocalAttrib, &attrib, &sep, &leftList, &assign) AST_END(LocalAttrib) diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index 240e3b5..0b5a8c1 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp @@ -75,7 +75,7 @@ static std::unordered_set Metamethods = { "close"s // Lua 5.4 }; -const std::string_view version = "0.26.0"sv; +const std::string_view version = "0.26.1"sv; const std::string_view extension = "yue"sv; class CompileError : public std::logic_error { @@ -8701,12 +8701,15 @@ private: auto classVar = getUnusedName("_class_"sv); addToScope(classVar); temp.push_back(indent() + "local "s + classVar + nll(classDecl)); + auto block = classDecl->new_ptr(); + str_list classConstVars; if (body) { str_list varDefs; for (auto item : body->contents.objects()) { if (auto statement = ast_cast(item)) { ClassDecl_t* clsDecl = nullptr; if (auto assignment = assignmentFrom(statement)) { + block->statements.push_back(statement); auto names = transformAssignDefs(assignment->expList.get(), DefOp::Mark); for (const auto& name : names) { varDefs.push_back(name.first); @@ -8736,9 +8739,85 @@ private: clsDecl = value->get_by_path(); BLOCK_END } else if (auto expList = expListFrom(statement)) { + block->statements.push_back(statement); if (auto value = singleValueFrom(expList)) { clsDecl = value->get_by_path(); } + } else if (auto local = statement->content.as()) { + block->statements.push_back(statement); + if (auto values = local->item.as()) { + for (auto name : values->nameList->names.objects()) { + auto varName = variableToString(static_cast(name)); + forceAddToScope(varName); + varDefs.push_back(varName); + } + } + } else if (auto localAttrib = statement->content.as()) { + auto explist = localAttrib->new_ptr(); + for (auto item : localAttrib->leftList.objects()) { + auto value = item->new_ptr(); + switch (item->get_id()) { + case id(): { + auto callable = item->new_ptr(); + callable->item.set(item); + auto chainValue = item->new_ptr(); + chainValue->items.push_back(callable); + value->item.set(chainValue); + break; + } + case id(): + value->item.set(item); + break; + case id(): + case id(): { + auto simpleValue = item->new_ptr(); + simpleValue->value.set(item); + value->item.set(simpleValue); + break; + } + default: YUEE("AST node mismatch", item); break; + } + explist->exprs.push_back(newExp(value, value)); + } + auto assignment = localAttrib->new_ptr(); + assignment->expList.set(explist); + assignment->action.set(localAttrib->assign); + auto names = transformAssignDefs(assignment->expList.get(), DefOp::Get); + for (const auto& name : names) { + forceAddToScope(name.first); + markVarConst(name.first); + varDefs.push_back(name.first); + classConstVars.push_back(name.first); + } + auto info = extractDestructureInfo(assignment, true, false); + if (!info.destructures.empty()) { + for (const auto& des : info.destructures) { + if (std::holds_alternative(des)) { + continue; + } + const auto& destruct = std::get(des); + for (const auto& item : destruct.items) { + if (!item.targetVar.empty()) { + forceAddToScope(item.targetVar); + markVarConst(item.targetVar); + varDefs.push_back(item.targetVar); + classConstVars.push_back(item.targetVar); + } + } + } + } + auto stmt = statement->new_ptr(); + stmt->comments.dup(statement->comments); + auto newAttrib = localAttrib->new_ptr(); + newAttrib->attrib.set(localAttrib->attrib); + newAttrib->leftList.dup(localAttrib->leftList); + newAttrib->assign.set(localAttrib->assign); + newAttrib->forceLocal = false; + stmt->content.set(newAttrib); + stmt->appendix.set(statement->appendix); + block->statements.push_back(stmt); + } else if (statement->content.is()) { + throw CompileError("global statement is not allowed here"sv, statement->content); } if (clsDecl) { std::string clsName; @@ -8786,12 +8865,17 @@ private: } break; } - case id(): - transformStatement(static_cast(content), statements); - break; + case id(): break; default: YUEE("AST node mismatch", content); break; } } + for (const auto& classVar : classConstVars) { + auto& scope = _scopes.back(); + scope.vars->insert_or_assign(classVar, VarType::Local); + } + for (auto stmt_ : block->statements.objects()) { + transformStatement(static_cast(stmt_), statements); + } for (auto& member : members) { switch (member.type) { case MemType::Common: @@ -10608,6 +10692,7 @@ private: void transformLocalAttrib(LocalAttrib_t* localAttrib, str_list& out) { auto x = localAttrib; + bool forceLocal = localAttrib->forceLocal; if (x->leftList.size() < x->assign->values.size()) { auto num = x->leftList.size(); if (num > 1) { @@ -10652,7 +10737,7 @@ private: ++i; if (j != je) ++j; } - bool checkValuesLater = false; + bool checkValuesLater = !forceLocal; for (ast_node* value : assignA->values.objects()) { if (ast_is(value)) { if (auto sVal = singleValueFrom(value)) { @@ -10744,7 +10829,9 @@ private: } } str_list temp; - temp.push_back(indent() + "local "s + join(vars, ", "sv) + nll(x)); + if (localAttrib->forceLocal) { + temp.push_back(indent() + "local "s + join(vars, ", "sv) + nll(x)); + } transformAssignment(assignment, temp); for (const auto& name : vars) { markVarConst(name); -- cgit v1.2.3-55-g6feb