From 11f0b022c49cc0cd7e1b0e44c98153042dcac9b0 Mon Sep 17 00:00:00 2001 From: leaf corcoran Date: Thu, 19 Nov 2015 18:01:22 -0800 Subject: [PATCH] use relative reference to parent class instead of closure --- moonscript/compile.lua | 7 ++-- moonscript/transform.moon | 35 ++++++++++++++++--- spec/class_spec.moon | 71 ++++++++++++++++++++++++++++++++++++--- 3 files changed, 102 insertions(+), 11 deletions(-) diff --git a/moonscript/compile.lua b/moonscript/compile.lua index 98045ce..dad4b79 100644 --- a/moonscript/compile.lua +++ b/moonscript/compile.lua @@ -638,7 +638,7 @@ do __init = function(self, options) self.options = options self.root = self - return _parent_0.__init(self) + return self.__class.__parent.__init(self) end, __base = _base_0, __name = "RootBlock", @@ -647,7 +647,10 @@ do __index = function(cls, name) local val = rawget(_base_0, name) if val == nil then - return _parent_0[name] + local parent = rawget(cls, "__parent") + if parent then + return parent[name] + end else return val end diff --git a/moonscript/transform.moon b/moonscript/transform.moon index 4ad3b66..5db3b5d 100644 --- a/moonscript/transform.moon +++ b/moonscript/transform.moon @@ -612,7 +612,25 @@ Statement = Transformer { class_lookup = build["if"] { cond: { "exp", {"ref", "val"}, "==", "nil" } then: { - parent_cls_name\index"name" + build.assign_one LocalName"parent", build.chain { + base: "rawget" + { + "call", { + {"ref", "cls"} + {"string", '"', "__parent"} + } + } + } + + build.if { + cond: LocalName "parent" + then: { + build.chain { + base: LocalName "parent" + {"index", "name"} + } + } + } } } insert class_lookup, {"else", {"val"}} @@ -660,14 +678,21 @@ Statement = Transformer { @put_name name if name @set "super", (block, chain) -> + relative_parent = { + "chain", + "self" + {"dot", "__class"} + {"dot", "__parent"} + } + if chain chain_tail = { unpack chain, 3 } - new_chain = {"chain", parent_cls_name} - head = chain_tail[1] if head == nil - return parent_cls_name + return relative_parent + + new_chain = relative_parent switch head[1] -- calling super, inject calling name and self into chain @@ -702,7 +727,7 @@ Statement = Transformer { new_chain else - parent_cls_name + relative_parent {"declare_glob", "*"} diff --git a/spec/class_spec.moon b/spec/class_spec.moon index c46b441..7b1dbd6 100644 --- a/spec/class_spec.moon +++ b/spec/class_spec.moon @@ -19,8 +19,7 @@ describe "class", -> instance = Thing! assert.same instance\get_color!, "blue" - - it "should have class property", -> + it "should have base properies from class", -> class Thing color: "blue" get_color: => @color @@ -54,7 +53,6 @@ describe "class", -> assert.same instance.property, "name" assert.same instance.name, "the_thing" - it "should call super method", -> class Base _count: 111 @@ -66,6 +64,18 @@ describe "class", -> instance = Thing! assert.same instance\counter!, "00000111" + it "should call other method from super", -> + class Base + _count: 111 + counter: => + @_count + + class Thing extends Base + other_method: => super\counter! + + instance = Thing! + assert.same instance\other_method!, 111 + it "should get super class", -> class Base class Thing extends Base @@ -102,7 +112,6 @@ describe "class", -> Thing = class assert.same Thing.__name, "Thing" - it "should not expose class properties on instance", -> class Thing @height: 10 @@ -135,3 +144,57 @@ describe "class", -> instance = Thing! instance\go! + it "should have class properies take precedence over base properties", -> + class Thing + @prop: "hello" + prop: "world" + + assert.same "hello", Thing.prop + + it "class properties take precedence in super class over base", -> + class Thing + @prop: "hello" + prop: "world" + + class OtherThing extends Thing + + assert.same "hello", OtherThing.prop + + it "gets value from base in super class", -> + class Thing + prop: "world" + + class OtherThing extends Thing + assert.same "world", OtherThing.prop + + it "should let parent be replaced on class", -> + class A + @prop: "yeah" + cool: => 1234 + plain: => "a" + + class B + @prop: "okay" + cool: => 9999 + plain: => "b" + + class Thing extends A + cool: => + super! + 1 + + get_super: => + super + + instance = Thing! + + assert.same "a", instance\plain! + assert.same 1235, instance\cool! + assert A == instance\get_super!, "expected super to be B" + + Thing.__parent = B + setmetatable Thing.__base, B.__base + + assert.same "b", instance\plain! + assert.same 10000, instance\cool! + assert B == instance\get_super!, "expected super to be B" +