Skip to content

Commit

Permalink
Fixed MoonScript issue # 459.
Browse files Browse the repository at this point in the history
Supported local/const/close hoist in class body.
  • Loading branch information
pigpigyyy committed Dec 19, 2024
1 parent 8a3d78c commit f38c4f9
Show file tree
Hide file tree
Showing 4 changed files with 169 additions and 7 deletions.
15 changes: 15 additions & 0 deletions spec/inputs/class.yue
Original file line number Diff line number Diff line change
Expand Up @@ -242,4 +242,19 @@ class Foo
:add
:<add>

do
global xa, xb
class CX
xa = 1
xb = 1
new: =>

do
class CY
xa = 1
local xb = 2
new: => print xa, xb, xc, xd
const xc = 3
close xd = <close>: =>

nil
60 changes: 60 additions & 0 deletions spec/outputs/class.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1229,4 +1229,64 @@ do
_base_0.__class = _class_0
Foo = _class_0
end
do
local CX
do
local _class_0
local _base_0 = { }
if _base_0.__index == nil then
_base_0.__index = _base_0
end
_class_0 = setmetatable({
__init = function(self) end,
__base = _base_0,
__name = "CX"
}, {
__index = _base_0,
__call = function(cls, ...)
local _self_0 = setmetatable({ }, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
local self = _class_0;
xa = 1
xb = 1
CX = _class_0
end
end
do
local CY
local _class_0
local xa, xb, xc, xd
local _base_0 = { }
if _base_0.__index == nil then
_base_0.__index = _base_0
end
_class_0 = setmetatable({
__init = function(self)
return print(xa, xb, xc, xd)
end,
__base = _base_0,
__name = "CY"
}, {
__index = _base_0,
__call = function(cls, ...)
local _self_0 = setmetatable({ }, _base_0)
cls.__init(_self_0, ...)
return _self_0
end
})
_base_0.__class = _class_0
local self = _class_0;
xa = 1
xb = 2
xc = 3
xd = setmetatable({ }, {
__close = function(self) end
})
local _close_0 <close> = xd
CY = _class_0
end
return nil
2 changes: 1 addition & 1 deletion src/yuescript/yue_ast.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -181,6 +180,7 @@ AST_NODE(LocalAttrib)
ast_ptr<true, Seperator_t> sep;
ast_sel_list<true, Variable_t, SimpleTable_t, TableLit_t, Comprehension_t> leftList;
ast_ptr<true, Assign_t> assign;
bool forceLocal = true;
AST_MEMBER(LocalAttrib, &attrib, &sep, &leftList, &assign)
AST_END(LocalAttrib)

Expand Down
99 changes: 93 additions & 6 deletions src/yuescript/yue_compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -75,7 +75,7 @@ static std::unordered_set<std::string> 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 {
Expand Down Expand Up @@ -8701,12 +8701,15 @@ class YueCompilerImpl {
auto classVar = getUnusedName("_class_"sv);
addToScope(classVar);
temp.push_back(indent() + "local "s + classVar + nll(classDecl));
auto block = classDecl->new_ptr<Block_t>();
str_list classConstVars;
if (body) {
str_list varDefs;
for (auto item : body->contents.objects()) {
if (auto statement = ast_cast<Statement_t>(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);
Expand Down Expand Up @@ -8736,9 +8739,85 @@ class YueCompilerImpl {
clsDecl = value->get_by_path<SimpleValue_t, ClassDecl_t>();
BLOCK_END
} else if (auto expList = expListFrom(statement)) {
block->statements.push_back(statement);
if (auto value = singleValueFrom(expList)) {
clsDecl = value->get_by_path<SimpleValue_t, ClassDecl_t>();
}
} else if (auto local = statement->content.as<Local_t>()) {
block->statements.push_back(statement);
if (auto values = local->item.as<LocalValues_t>()) {
for (auto name : values->nameList->names.objects()) {
auto varName = variableToString(static_cast<Variable_t*>(name));
forceAddToScope(varName);
varDefs.push_back(varName);
}
}
} else if (auto localAttrib = statement->content.as<LocalAttrib_t>()) {
auto explist = localAttrib->new_ptr<ExpList_t>();
for (auto item : localAttrib->leftList.objects()) {
auto value = item->new_ptr<Value_t>();
switch (item->get_id()) {
case id<Variable_t>(): {
auto callable = item->new_ptr<Callable_t>();
callable->item.set(item);
auto chainValue = item->new_ptr<ChainValue_t>();
chainValue->items.push_back(callable);
value->item.set(chainValue);
break;
}
case id<SimpleTable_t>():
value->item.set(item);
break;
case id<TableLit_t>():
case id<Comprehension_t>(): {
auto simpleValue = item->new_ptr<SimpleValue_t>();
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<ExpListAssign_t>();
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<AssignmentPtr>(des)) {
continue;
}
const auto& destruct = std::get<Destructure>(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<Statement_t>();
stmt->comments.dup(statement->comments);
auto newAttrib = localAttrib->new_ptr<LocalAttrib_t>();
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<Global_t>()) {
throw CompileError("global statement is not allowed here"sv, statement->content);
}
if (clsDecl) {
std::string clsName;
Expand Down Expand Up @@ -8786,12 +8865,17 @@ class YueCompilerImpl {
}
break;
}
case id<Statement_t>():
transformStatement(static_cast<Statement_t*>(content), statements);
break;
case id<Statement_t>(): 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<Statement_t*>(stmt_), statements);
}
for (auto& member : members) {
switch (member.type) {
case MemType::Common:
Expand Down Expand Up @@ -10608,6 +10692,7 @@ class YueCompilerImpl {

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) {
Expand Down Expand Up @@ -10652,7 +10737,7 @@ class YueCompilerImpl {
++i;
if (j != je) ++j;
}
bool checkValuesLater = false;
bool checkValuesLater = !forceLocal;
for (ast_node* value : assignA->values.objects()) {
if (ast_is<Exp_t>(value)) {
if (auto sVal = singleValueFrom(value)) {
Expand Down Expand Up @@ -10744,7 +10829,9 @@ class YueCompilerImpl {
}
}
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);
Expand Down

0 comments on commit f38c4f9

Please sign in to comment.