From b9b1cf94e1324e344df6f7204c8d479329c56718 Mon Sep 17 00:00:00 2001 From: Li Jin Date: Tue, 8 Nov 2022 10:20:52 +0800 Subject: fix issue #114. --- spec/inputs/test/class_spec.yue | 13 +++ spec/outputs/class.lua | 55 ++++++++++++ spec/outputs/test/class_spec.lua | 186 ++++++++++++++++++++++++++++++++++++++- src/yuescript/yue_compiler.cpp | 16 +++- src/yuescript/yue_parser.cpp | 18 ++-- src/yuescript/yue_parser.h | 7 +- 6 files changed, 280 insertions(+), 15 deletions(-) diff --git a/spec/inputs/test/class_spec.yue b/spec/inputs/test/class_spec.yue index df8bc96..4f7af7c 100644 --- a/spec/inputs/test/class_spec.yue +++ b/spec/inputs/test/class_spec.yue @@ -293,3 +293,16 @@ describe "class", -> assert.same 1 + 100 + 12, Sub!\value! assert.same 6, OtherSub!\value! + it "should copy metamethod from super", -> + class A + val: 1 + : => "Object #{ @val }" + + class B extends A + val: 2 + + a, b = A!, B! + + assert.same "Object 1", tostring a + assert.same "Object 2", tostring b + diff --git a/spec/outputs/class.lua b/spec/outputs/class.lua index 9a61a67..d13b738 100644 --- a/spec/outputs/class.lua +++ b/spec/outputs/class.lua @@ -65,6 +65,11 @@ do local _class_0 local _parent_0 = Simple local _base_0 = { } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -138,6 +143,11 @@ do return _class_0.__parent.__base.cool(self, 120302) end } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -211,6 +221,11 @@ do return assert(_class_0.__parent == Okay) end } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -311,6 +326,11 @@ do end end } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -551,6 +571,11 @@ do local _class_0 local _parent_0 = Hello.World local _base_0 = { } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -641,6 +666,11 @@ do local _class_0 local _parent_0 = Hello local _base_0 = { } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -682,6 +712,11 @@ do local _class_0 local _parent_0 = World local _base_0 = { } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -828,6 +863,11 @@ do } end } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -871,6 +911,11 @@ do return _class_0.__parent.__base.dang(self) end) } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -910,6 +955,11 @@ do local _class_0 local _parent_0 = Thing local _base_0 = { } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -1051,6 +1101,11 @@ do } end } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end diff --git a/spec/outputs/test/class_spec.lua b/spec/outputs/test/class_spec.lua index b4062e0..e08b5aa 100644 --- a/spec/outputs/test/class_spec.lua +++ b/spec/outputs/test/class_spec.lua @@ -129,6 +129,11 @@ return describe("class", function() local _base_0 = { color = "green" } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -195,6 +200,11 @@ return describe("class", function() local _class_0 local _parent_0 = Base local _base_0 = { } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -416,6 +426,11 @@ return describe("class", function() local _class_0 local _parent_0 = Base local _base_0 = { } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -493,6 +508,11 @@ return describe("class", function() return ("%08d"):format(_class_0.__parent.__base.counter(self)) end } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -568,6 +588,11 @@ return describe("class", function() return _class_0.__parent.counter(self) end } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -638,6 +663,11 @@ return describe("class", function() return _class_0.__parent end } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -720,6 +750,11 @@ return describe("class", function() end end } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -790,6 +825,11 @@ return describe("class", function() local _class_0 local _parent_0 = Thing local _base_0 = { } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -857,6 +897,11 @@ return describe("class", function() local _class_0 local _parent_0 = Thing local _base_0 = { } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -969,6 +1014,11 @@ return describe("class", function() return _class_0.__parent end } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -1050,6 +1100,11 @@ return describe("class", function() return _class_0.__parent.__base.a(self) + 2 end } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -1094,6 +1149,11 @@ return describe("class", function() return _class_0.__parent.__base.a(self) + 3 end } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -1164,6 +1224,11 @@ return describe("class", function() local _class_0 local _parent_0 = One local _base_0 = { } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -1208,6 +1273,11 @@ return describe("class", function() return _class_0.__parent.__base.a(self) + 3 end } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -1252,6 +1322,11 @@ return describe("class", function() return _class_0.__parent.__base.a(self) + 4 end } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -1330,6 +1405,11 @@ return describe("class", function() return _class_0.__parent.__base.doit(self) end } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -1404,6 +1484,11 @@ return describe("class", function() local _class_0 local _parent_0 = One local _base_0 = { } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -1444,6 +1529,11 @@ return describe("class", function() local _class_0 local _parent_0 = Two local _base_0 = { } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -1488,6 +1578,11 @@ return describe("class", function() local _class_0 local _parent_0 = Three local _base_0 = { } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -1529,7 +1624,7 @@ return describe("class", function() end return assert.same(8, Four:a()) end) - return it("super should still work when method wrapped", function() + it("super should still work when method wrapped", function() local add_some add_some = function(opts) return function(self) @@ -1574,6 +1669,11 @@ return describe("class", function() end }) } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -1626,6 +1726,11 @@ return describe("class", function() end end)() } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end if _base_0.__index == nil then _base_0.__index = _base_0 end @@ -1664,5 +1769,84 @@ return describe("class", function() assert.same(1 + 100 + 12, Sub():value()) return assert.same(6, OtherSub():value()) end) + return it("should copy metamethod from super", function() + local A + do + local _class_0 + local _base_0 = { + val = 1, + __tostring = function(self) + return "Object " .. tostring(self.val) + end + } + if _base_0.__index == nil then + _base_0.__index = _base_0 + end + _class_0 = setmetatable({ + __init = function() end, + __base = _base_0, + __name = "A" + }, { + __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 + A = _class_0 + end + local B + do + local _class_0 + local _parent_0 = A + local _base_0 = { + val = 2 + } + for _key_0, _val_0 in pairs(_parent_0.__base) do + if _base_0[_key_0] == nil and _key_0:match("^__") and not (_key_0 == "__index" and _val_0 == _parent_0.__base) then + _base_0[_key_0] = _val_0 + end + end + if _base_0.__index == nil then + _base_0.__index = _base_0 + end + setmetatable(_base_0, _parent_0.__base) + _class_0 = setmetatable({ + __init = function(self, ...) + return _class_0.__parent.__init(self, ...) + end, + __base = _base_0, + __name = "B", + __parent = _parent_0 + }, { + __index = function(cls, name) + local val = rawget(_base_0, name) + if val == nil then + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end + else + return val + end + end, + __call = function(cls, ...) + local _self_0 = setmetatable({ }, _base_0) + cls.__init(_self_0, ...) + return _self_0 + end + }) + _base_0.__class = _class_0 + if _parent_0.__inherited then + _parent_0.__inherited(_parent_0, _class_0) + end + B = _class_0 + end + local a, b = A(), B() + assert.same("Object 1", tostring(a)) + return assert.same("Object 2", tostring(b)) + end) end) end) diff --git a/src/yuescript/yue_compiler.cpp b/src/yuescript/yue_compiler.cpp index e061604..d0f2dbb 100644 --- a/src/yuescript/yue_compiler.cpp +++ b/src/yuescript/yue_compiler.cpp @@ -14,7 +14,6 @@ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLI #include #include #include -#include #include "yuescript/yue_compiler.h" #include "yuescript/yue_parser.h" @@ -60,7 +59,7 @@ namespace yue { typedef std::list str_list; -const std::string_view version = "0.15.8"sv; +const std::string_view version = "0.15.9"sv; const std::string_view extension = "yue"sv; class YueCompilerImpl { @@ -2122,7 +2121,8 @@ private: keyIndex = key; } else if (auto key = np->key.as()) { keyIndex = newExp(key, np->key).get(); - } else throw std::logic_error(_info.errorMessage("unsupported key for destructuring"sv, np)); + } else + throw std::logic_error(_info.errorMessage("unsupported key for destructuring"sv, np)); } if (auto exp = np->value.as()) { if (!isAssignable(exp)) throw std::logic_error(_info.errorMessage("can't do destructure value"sv, exp)); @@ -2211,7 +2211,8 @@ private: chain->items.push_back(newExp(key, dp)); } else if (auto key = dp->key.as()) { chain->items.push_back(key); - } else throw std::logic_error(_info.errorMessage("unsupported key for destructuring"sv, dp)); + } else + throw std::logic_error(_info.errorMessage("unsupported key for destructuring"sv, dp)); } if (auto exp = dp->value.get()) { if (!isAssignable(exp)) throw std::logic_error(_info.errorMessage("can't destructure value"sv, exp)); @@ -6520,6 +6521,13 @@ private: _buf << "\t\t"sv << baseVar << '[' << key << "]="sv << val << " if "sv << baseVar << '[' << key << "]==nil and (not "sv << cls << " or not "sv << key << "\\match \"^__\")"sv; transformBlock(toAst(clearBuf(), x), temp, ExpUsage::Common); } + if (!parentVar.empty()) { + auto key = getUnusedName("_key_"sv); + auto val = getUnusedName("_val_"sv); + _buf << "for "sv << key << ',' << val << " in pairs "sv << parentVar << ".__base"sv << '\n' + << '\t' << baseVar << '[' << key << "]="sv << val << " if "sv << baseVar << '[' << key << "]==nil and "sv << key << "\\match(\"^__\") and not ("sv << key << "==\"__index\" and "sv << val << "=="sv << parentVar << ".__base)"sv; + transformBlock(toAst(clearBuf(), x), temp, ExpUsage::Common); + } transformAssignment(toAst(baseVar + ".__index ?\?= "s + baseVar, classDecl), temp); str_list tmp; if (usage == ExpUsage::Assignment) { diff --git a/src/yuescript/yue_parser.cpp b/src/yuescript/yue_parser.cpp index 4aeb79a..e4de0b5 100644 --- a/src/yuescript/yue_parser.cpp +++ b/src/yuescript/yue_parser.cpp @@ -71,7 +71,7 @@ YueParser::YueParser() { Cut = false_(); Seperator = true_(); - invalid_empty_block = pl::user(true_(), [](const item_t& item) { + empty_block_error = pl::user(true_(), [](const item_t& item) { throw ParserError("must be followed by a statement or an indented block", *item.begin, *item.end); return false; }); @@ -84,9 +84,9 @@ YueParser::YueParser() { #define disable_chain(patt) (DisableChain >> ((patt) >> EnableChain | EnableChain >> Cut)) #define disable_do_chain_arg_table_block(patt) (DisableDoChainArgTableBlock >> ((patt) >> EnableDoChainArgTableBlock | EnableDoChainArgTableBlock >> Cut)) #define disable_arg_table_block(patt) (DisableArgTableBlock >> ((patt) >> EnableArgTableBlock | EnableArgTableBlock >> Cut)) - #define body_with(str) (Space >> (key(str) >> Space >> (InBlock | Statement) | InBlock | invalid_empty_block)) + #define body_with(str) (Space >> (key(str) >> Space >> (InBlock | Statement) | InBlock | empty_block_error)) #define opt_body_with(str) (Space >> (key(str) >> Space >> (InBlock | Statement) | InBlock)) - #define body (Space >> (InBlock | Statement | invalid_empty_block)) + #define body (Space >> (InBlock | Statement | empty_block_error)) Variable = pl::user(Name, [](const item_t& item) { State* st = reinterpret_cast(item.user_data); @@ -630,15 +630,17 @@ YueParser::YueParser() { SpaceBreak >> Advance >> ArgBlock >> -arg_table_block ) | arg_table_block; + leading_spaces_error = pl::user(+space_one >> expr('(') >> Exp >> +(sym(',') >> Exp) >> sym(')'), [](const item_t& item) { + throw ParserError("write invoke arguments in parentheses without leading spaces or leading spaces without parentheses", *item.begin, *item.end); + return false; + }); + InvokeArgs = not_(set("-~")) >> Seperator >> ( (Exp >> *(sym(',') >> Exp) >> -invoke_args_with_table) | arg_table_block | - pl::user(+space_one >> expr('(') >> Exp >> +(sym(',') >> Exp) >> sym(')'), [](const item_t& item) { - throw ParserError("write invoke arguments in parentheses without spaces or space seperated without parentheses", *item.begin, *item.end); - return false; - }) + leading_spaces_error ); const_value = (expr("nil") | expr("true") | expr("false")) >> not_(AlphaNum); @@ -666,7 +668,7 @@ YueParser::YueParser() { Return | Local | Global | Export | Macro | MacroInPlace | BreakLoop | Label | Goto | ShortTabAppending | LocalAttrib | Backcall | PipeBody | ExpListAssign | - statement_appendix >> invalid_empty_block + statement_appendix >> empty_block_error ) >> Space >> -statement_appendix >> -statement_sep; diff --git a/src/yuescript/yue_parser.h b/src/yuescript/yue_parser.h index 461b381..9e2a621 100644 --- a/src/yuescript/yue_parser.h +++ b/src/yuescript/yue_parser.h @@ -48,7 +48,9 @@ public: }; template -struct identity { typedef T type; }; +struct identity { + typedef T type; +}; #define AST_RULE(type) \ rule type; \ @@ -113,7 +115,8 @@ private: return Cut; } - rule invalid_empty_block; + rule empty_block_error; + rule leading_spaces_error; rule num_char; rule num_char_hex; -- cgit v1.2.3-55-g6feb