diff options
author | Li Jin <dragon-fly@qq.com> | 2024-12-19 11:26:23 +0800 |
---|---|---|
committer | Li Jin <dragon-fly@qq.com> | 2024-12-19 11:30:01 +0800 |
commit | f38c4f94c9ba0499d923e59483d6381b97cce926 (patch) | |
tree | 945fd3658a9018dc2558ddf4f2c95d17e3a80091 | |
parent | 8a3d78c4d5bfe2ba39173e91146025278bf0deb2 (diff) | |
download | yuescript-f38c4f94c9ba0499d923e59483d6381b97cce926.tar.gz yuescript-f38c4f94c9ba0499d923e59483d6381b97cce926.tar.bz2 yuescript-f38c4f94c9ba0499d923e59483d6381b97cce926.zip |
Fixed MoonScript issue # 459.v0.26.1
Supported local/const/close hoist in class body.
-rw-r--r-- | spec/inputs/class.yue | 15 | ||||
-rw-r--r-- | spec/outputs/class.lua | 60 | ||||
-rw-r--r-- | src/yuescript/yue_ast.h | 2 | ||||
-rw-r--r-- | src/yuescript/yue_compiler.cpp | 99 |
4 files changed, 169 insertions, 7 deletions
diff --git a/spec/inputs/class.yue b/spec/inputs/class.yue index 49537c2..3c73ebc 100644 --- a/spec/inputs/class.yue +++ b/spec/inputs/class.yue | |||
@@ -242,4 +242,19 @@ class Foo | |||
242 | :add | 242 | :add |
243 | :<add> | 243 | :<add> |
244 | 244 | ||
245 | do | ||
246 | global xa, xb | ||
247 | class CX | ||
248 | xa = 1 | ||
249 | xb = 1 | ||
250 | new: => | ||
251 | |||
252 | do | ||
253 | class CY | ||
254 | xa = 1 | ||
255 | local xb = 2 | ||
256 | new: => print xa, xb, xc, xd | ||
257 | const xc = 3 | ||
258 | close xd = <close>: => | ||
259 | |||
245 | nil | 260 | nil |
diff --git a/spec/outputs/class.lua b/spec/outputs/class.lua index 442ff4b..aaea33c 100644 --- a/spec/outputs/class.lua +++ b/spec/outputs/class.lua | |||
@@ -1229,4 +1229,64 @@ do | |||
1229 | _base_0.__class = _class_0 | 1229 | _base_0.__class = _class_0 |
1230 | Foo = _class_0 | 1230 | Foo = _class_0 |
1231 | end | 1231 | end |
1232 | do | ||
1233 | local CX | ||
1234 | do | ||
1235 | local _class_0 | ||
1236 | local _base_0 = { } | ||
1237 | if _base_0.__index == nil then | ||
1238 | _base_0.__index = _base_0 | ||
1239 | end | ||
1240 | _class_0 = setmetatable({ | ||
1241 | __init = function(self) end, | ||
1242 | __base = _base_0, | ||
1243 | __name = "CX" | ||
1244 | }, { | ||
1245 | __index = _base_0, | ||
1246 | __call = function(cls, ...) | ||
1247 | local _self_0 = setmetatable({ }, _base_0) | ||
1248 | cls.__init(_self_0, ...) | ||
1249 | return _self_0 | ||
1250 | end | ||
1251 | }) | ||
1252 | _base_0.__class = _class_0 | ||
1253 | local self = _class_0; | ||
1254 | xa = 1 | ||
1255 | xb = 1 | ||
1256 | CX = _class_0 | ||
1257 | end | ||
1258 | end | ||
1259 | do | ||
1260 | local CY | ||
1261 | local _class_0 | ||
1262 | local xa, xb, xc, xd | ||
1263 | local _base_0 = { } | ||
1264 | if _base_0.__index == nil then | ||
1265 | _base_0.__index = _base_0 | ||
1266 | end | ||
1267 | _class_0 = setmetatable({ | ||
1268 | __init = function(self) | ||
1269 | return print(xa, xb, xc, xd) | ||
1270 | end, | ||
1271 | __base = _base_0, | ||
1272 | __name = "CY" | ||
1273 | }, { | ||
1274 | __index = _base_0, | ||
1275 | __call = function(cls, ...) | ||
1276 | local _self_0 = setmetatable({ }, _base_0) | ||
1277 | cls.__init(_self_0, ...) | ||
1278 | return _self_0 | ||
1279 | end | ||
1280 | }) | ||
1281 | _base_0.__class = _class_0 | ||
1282 | local self = _class_0; | ||
1283 | xa = 1 | ||
1284 | xb = 2 | ||
1285 | xc = 3 | ||
1286 | xd = setmetatable({ }, { | ||
1287 | __close = function(self) end | ||
1288 | }) | ||
1289 | local _close_0 <close> = xd | ||
1290 | CY = _class_0 | ||
1291 | end | ||
1232 | return nil | 1292 | return nil |
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 {}; } | |||
52 | namespace yue { | 52 | namespace yue { |
53 | class ExpListLow_t; | 53 | class ExpListLow_t; |
54 | class TableBlock_t; | 54 | class TableBlock_t; |
55 | class Attrib_t; | ||
56 | class SimpleTable_t; | 55 | class SimpleTable_t; |
57 | class TableLit_t; | 56 | class TableLit_t; |
58 | class Assign_t; | 57 | class Assign_t; |
@@ -181,6 +180,7 @@ AST_NODE(LocalAttrib) | |||
181 | ast_ptr<true, Seperator_t> sep; | 180 | ast_ptr<true, Seperator_t> sep; |
182 | ast_sel_list<true, Variable_t, SimpleTable_t, TableLit_t, Comprehension_t> leftList; | 181 | ast_sel_list<true, Variable_t, SimpleTable_t, TableLit_t, Comprehension_t> leftList; |
183 | ast_ptr<true, Assign_t> assign; | 182 | ast_ptr<true, Assign_t> assign; |
183 | bool forceLocal = true; | ||
184 | AST_MEMBER(LocalAttrib, &attrib, &sep, &leftList, &assign) | 184 | AST_MEMBER(LocalAttrib, &attrib, &sep, &leftList, &assign) |
185 | AST_END(LocalAttrib) | 185 | AST_END(LocalAttrib) |
186 | 186 | ||
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<std::string> Metamethods = { | |||
75 | "close"s // Lua 5.4 | 75 | "close"s // Lua 5.4 |
76 | }; | 76 | }; |
77 | 77 | ||
78 | const std::string_view version = "0.26.0"sv; | 78 | const std::string_view version = "0.26.1"sv; |
79 | const std::string_view extension = "yue"sv; | 79 | const std::string_view extension = "yue"sv; |
80 | 80 | ||
81 | class CompileError : public std::logic_error { | 81 | class CompileError : public std::logic_error { |
@@ -8701,12 +8701,15 @@ private: | |||
8701 | auto classVar = getUnusedName("_class_"sv); | 8701 | auto classVar = getUnusedName("_class_"sv); |
8702 | addToScope(classVar); | 8702 | addToScope(classVar); |
8703 | temp.push_back(indent() + "local "s + classVar + nll(classDecl)); | 8703 | temp.push_back(indent() + "local "s + classVar + nll(classDecl)); |
8704 | auto block = classDecl->new_ptr<Block_t>(); | ||
8705 | str_list classConstVars; | ||
8704 | if (body) { | 8706 | if (body) { |
8705 | str_list varDefs; | 8707 | str_list varDefs; |
8706 | for (auto item : body->contents.objects()) { | 8708 | for (auto item : body->contents.objects()) { |
8707 | if (auto statement = ast_cast<Statement_t>(item)) { | 8709 | if (auto statement = ast_cast<Statement_t>(item)) { |
8708 | ClassDecl_t* clsDecl = nullptr; | 8710 | ClassDecl_t* clsDecl = nullptr; |
8709 | if (auto assignment = assignmentFrom(statement)) { | 8711 | if (auto assignment = assignmentFrom(statement)) { |
8712 | block->statements.push_back(statement); | ||
8710 | auto names = transformAssignDefs(assignment->expList.get(), DefOp::Mark); | 8713 | auto names = transformAssignDefs(assignment->expList.get(), DefOp::Mark); |
8711 | for (const auto& name : names) { | 8714 | for (const auto& name : names) { |
8712 | varDefs.push_back(name.first); | 8715 | varDefs.push_back(name.first); |
@@ -8736,9 +8739,85 @@ private: | |||
8736 | clsDecl = value->get_by_path<SimpleValue_t, ClassDecl_t>(); | 8739 | clsDecl = value->get_by_path<SimpleValue_t, ClassDecl_t>(); |
8737 | BLOCK_END | 8740 | BLOCK_END |
8738 | } else if (auto expList = expListFrom(statement)) { | 8741 | } else if (auto expList = expListFrom(statement)) { |
8742 | block->statements.push_back(statement); | ||
8739 | if (auto value = singleValueFrom(expList)) { | 8743 | if (auto value = singleValueFrom(expList)) { |
8740 | clsDecl = value->get_by_path<SimpleValue_t, ClassDecl_t>(); | 8744 | clsDecl = value->get_by_path<SimpleValue_t, ClassDecl_t>(); |
8741 | } | 8745 | } |
8746 | } else if (auto local = statement->content.as<Local_t>()) { | ||
8747 | block->statements.push_back(statement); | ||
8748 | if (auto values = local->item.as<LocalValues_t>()) { | ||
8749 | for (auto name : values->nameList->names.objects()) { | ||
8750 | auto varName = variableToString(static_cast<Variable_t*>(name)); | ||
8751 | forceAddToScope(varName); | ||
8752 | varDefs.push_back(varName); | ||
8753 | } | ||
8754 | } | ||
8755 | } else if (auto localAttrib = statement->content.as<LocalAttrib_t>()) { | ||
8756 | auto explist = localAttrib->new_ptr<ExpList_t>(); | ||
8757 | for (auto item : localAttrib->leftList.objects()) { | ||
8758 | auto value = item->new_ptr<Value_t>(); | ||
8759 | switch (item->get_id()) { | ||
8760 | case id<Variable_t>(): { | ||
8761 | auto callable = item->new_ptr<Callable_t>(); | ||
8762 | callable->item.set(item); | ||
8763 | auto chainValue = item->new_ptr<ChainValue_t>(); | ||
8764 | chainValue->items.push_back(callable); | ||
8765 | value->item.set(chainValue); | ||
8766 | break; | ||
8767 | } | ||
8768 | case id<SimpleTable_t>(): | ||
8769 | value->item.set(item); | ||
8770 | break; | ||
8771 | case id<TableLit_t>(): | ||
8772 | case id<Comprehension_t>(): { | ||
8773 | auto simpleValue = item->new_ptr<SimpleValue_t>(); | ||
8774 | simpleValue->value.set(item); | ||
8775 | value->item.set(simpleValue); | ||
8776 | break; | ||
8777 | } | ||
8778 | default: YUEE("AST node mismatch", item); break; | ||
8779 | } | ||
8780 | explist->exprs.push_back(newExp(value, value)); | ||
8781 | } | ||
8782 | auto assignment = localAttrib->new_ptr<ExpListAssign_t>(); | ||
8783 | assignment->expList.set(explist); | ||
8784 | assignment->action.set(localAttrib->assign); | ||
8785 | auto names = transformAssignDefs(assignment->expList.get(), DefOp::Get); | ||
8786 | for (const auto& name : names) { | ||
8787 | forceAddToScope(name.first); | ||
8788 | markVarConst(name.first); | ||
8789 | varDefs.push_back(name.first); | ||
8790 | classConstVars.push_back(name.first); | ||
8791 | } | ||
8792 | auto info = extractDestructureInfo(assignment, true, false); | ||
8793 | if (!info.destructures.empty()) { | ||
8794 | for (const auto& des : info.destructures) { | ||
8795 | if (std::holds_alternative<AssignmentPtr>(des)) { | ||
8796 | continue; | ||
8797 | } | ||
8798 | const auto& destruct = std::get<Destructure>(des); | ||
8799 | for (const auto& item : destruct.items) { | ||
8800 | if (!item.targetVar.empty()) { | ||
8801 | forceAddToScope(item.targetVar); | ||
8802 | markVarConst(item.targetVar); | ||
8803 | varDefs.push_back(item.targetVar); | ||
8804 | classConstVars.push_back(item.targetVar); | ||
8805 | } | ||
8806 | } | ||
8807 | } | ||
8808 | } | ||
8809 | auto stmt = statement->new_ptr<Statement_t>(); | ||
8810 | stmt->comments.dup(statement->comments); | ||
8811 | auto newAttrib = localAttrib->new_ptr<LocalAttrib_t>(); | ||
8812 | newAttrib->attrib.set(localAttrib->attrib); | ||
8813 | newAttrib->leftList.dup(localAttrib->leftList); | ||
8814 | newAttrib->assign.set(localAttrib->assign); | ||
8815 | newAttrib->forceLocal = false; | ||
8816 | stmt->content.set(newAttrib); | ||
8817 | stmt->appendix.set(statement->appendix); | ||
8818 | block->statements.push_back(stmt); | ||
8819 | } else if (statement->content.is<Global_t>()) { | ||
8820 | throw CompileError("global statement is not allowed here"sv, statement->content); | ||
8742 | } | 8821 | } |
8743 | if (clsDecl) { | 8822 | if (clsDecl) { |
8744 | std::string clsName; | 8823 | std::string clsName; |
@@ -8786,12 +8865,17 @@ private: | |||
8786 | } | 8865 | } |
8787 | break; | 8866 | break; |
8788 | } | 8867 | } |
8789 | case id<Statement_t>(): | 8868 | case id<Statement_t>(): break; |
8790 | transformStatement(static_cast<Statement_t*>(content), statements); | ||
8791 | break; | ||
8792 | default: YUEE("AST node mismatch", content); break; | 8869 | default: YUEE("AST node mismatch", content); break; |
8793 | } | 8870 | } |
8794 | } | 8871 | } |
8872 | for (const auto& classVar : classConstVars) { | ||
8873 | auto& scope = _scopes.back(); | ||
8874 | scope.vars->insert_or_assign(classVar, VarType::Local); | ||
8875 | } | ||
8876 | for (auto stmt_ : block->statements.objects()) { | ||
8877 | transformStatement(static_cast<Statement_t*>(stmt_), statements); | ||
8878 | } | ||
8795 | for (auto& member : members) { | 8879 | for (auto& member : members) { |
8796 | switch (member.type) { | 8880 | switch (member.type) { |
8797 | case MemType::Common: | 8881 | case MemType::Common: |
@@ -10608,6 +10692,7 @@ private: | |||
10608 | 10692 | ||
10609 | void transformLocalAttrib(LocalAttrib_t* localAttrib, str_list& out) { | 10693 | void transformLocalAttrib(LocalAttrib_t* localAttrib, str_list& out) { |
10610 | auto x = localAttrib; | 10694 | auto x = localAttrib; |
10695 | bool forceLocal = localAttrib->forceLocal; | ||
10611 | if (x->leftList.size() < x->assign->values.size()) { | 10696 | if (x->leftList.size() < x->assign->values.size()) { |
10612 | auto num = x->leftList.size(); | 10697 | auto num = x->leftList.size(); |
10613 | if (num > 1) { | 10698 | if (num > 1) { |
@@ -10652,7 +10737,7 @@ private: | |||
10652 | ++i; | 10737 | ++i; |
10653 | if (j != je) ++j; | 10738 | if (j != je) ++j; |
10654 | } | 10739 | } |
10655 | bool checkValuesLater = false; | 10740 | bool checkValuesLater = !forceLocal; |
10656 | for (ast_node* value : assignA->values.objects()) { | 10741 | for (ast_node* value : assignA->values.objects()) { |
10657 | if (ast_is<Exp_t>(value)) { | 10742 | if (ast_is<Exp_t>(value)) { |
10658 | if (auto sVal = singleValueFrom(value)) { | 10743 | if (auto sVal = singleValueFrom(value)) { |
@@ -10744,7 +10829,9 @@ private: | |||
10744 | } | 10829 | } |
10745 | } | 10830 | } |
10746 | str_list temp; | 10831 | str_list temp; |
10747 | temp.push_back(indent() + "local "s + join(vars, ", "sv) + nll(x)); | 10832 | if (localAttrib->forceLocal) { |
10833 | temp.push_back(indent() + "local "s + join(vars, ", "sv) + nll(x)); | ||
10834 | } | ||
10748 | transformAssignment(assignment, temp); | 10835 | transformAssignment(assignment, temp); |
10749 | for (const auto& name : vars) { | 10836 | for (const auto& name : vars) { |
10750 | markVarConst(name); | 10837 | markVarConst(name); |