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); |
