diff --git a/lib/nodes.js b/lib/nodes.js index 296de18223..c00fde5690 100644 --- a/lib/nodes.js +++ b/lib/nodes.js @@ -1032,12 +1032,12 @@ for (_i = 0, _len = _ref2.length; _i < _len; _i++) { bvar = _ref2[_i]; bname = bvar.compile(o); - _results.push(this.ctor.body.unshift(new Literal("this." + bname + " = " + (utility('bind')) + "(this." + bname + ", this);"))); + _results.push(this.ctor.body.unshift(new Literal("this." + bname + " = " + (utility('bind')) + "(this." + bname + ", this)"))); } return _results; } }; - Class.prototype.addProperties = function(node, name) { + Class.prototype.addProperties = function(node, name, o) { var assign, base, exprs, func, props; props = node.base.properties.slice(0); exprs = (function() { @@ -1058,8 +1058,8 @@ if (func instanceof Code) { assign = this.ctor = func; } else { - assign = null; - this.ctor = new Assign(new Value(new Literal(name)), func); + this.externalCtor = o.scope.freeVariable('class'); + assign = new Assign(new Literal(this.externalCtor), func); } } else { if (!assign.variable["this"]) { @@ -1077,7 +1077,7 @@ }).call(this); return compact(exprs); }; - Class.prototype.walkBody = function(name) { + Class.prototype.walkBody = function(name, o) { return this.traverseChildren(false, __bind(function(child) { var exps, i, node, _len, _ref2; if (child instanceof Class) { @@ -1088,7 +1088,7 @@ for (i = 0, _len = _ref2.length; i < _len; i++) { node = _ref2[i]; if (node instanceof Value && node.isObject(true)) { - exps[i] = this.addProperties(node, name); + exps[i] = this.addProperties(node, name, o); } } return child.expressions = exps = flatten(exps); @@ -1099,7 +1099,10 @@ if (!this.ctor) { this.ctor = new Code; if (this.parent) { - this.ctor.body.push(new Call('super', [new Splat(new Literal('arguments'))])); + this.ctor.body.push(new Literal("" + name + ".__super__.constructor.apply(this, arguments)")); + } + if (this.externalCtor) { + this.ctor.body.push(new Literal("return " + this.externalCtor + ".apply(this, arguments)")); } this.body.expressions.unshift(this.ctor); } @@ -1113,7 +1116,7 @@ name = decl || this.name || '_Class'; lname = new Literal(name); this.setContext(name); - this.walkBody(name); + this.walkBody(name, o); this.ensureConstructor(name); if (this.parent) { this.body.expressions.unshift(new Extends(lname, this.parent)); diff --git a/src/nodes.coffee b/src/nodes.coffee index eef02fe306..55755ff812 100644 --- a/src/nodes.coffee +++ b/src/nodes.coffee @@ -816,11 +816,11 @@ exports.Class = class Class extends Base if @boundFuncs.length for bvar in @boundFuncs bname = bvar.compile o - @ctor.body.unshift new Literal "this.#{bname} = #{utility 'bind'}(this.#{bname}, this);" + @ctor.body.unshift new Literal "this.#{bname} = #{utility 'bind'}(this.#{bname}, this)" # Merge the properties from a top-level object as prototypal properties # on the class. - addProperties: (node, name) -> + addProperties: (node, name, o) -> props = node.base.properties.slice 0 exprs = while assign = props.shift() if assign instanceof Assign @@ -835,8 +835,8 @@ exports.Class = class Class extends Base if func instanceof Code assign = @ctor = func else - assign = null - @ctor = new Assign new Value(new Literal name), func + @externalCtor = o.scope.freeVariable 'class' + assign = new Assign new Literal(@externalCtor), func else unless assign.variable.this assign.variable = new Value(new Literal(name), [new Access(base, 'proto')]) @@ -847,13 +847,13 @@ exports.Class = class Class extends Base compact exprs # Walk the body of the class, looking for prototype properties to be converted. - walkBody: (name) -> + walkBody: (name, o) -> @traverseChildren false, (child) => return false if child instanceof Class if child instanceof Block for node, i in exps = child.expressions if node instanceof Value and node.isObject(true) - exps[i] = @addProperties node, name + exps[i] = @addProperties node, name, o child.expressions = exps = flatten exps # Make sure that a constructor is defined for the class, and properly @@ -861,7 +861,8 @@ exports.Class = class Class extends Base ensureConstructor: (name) -> if not @ctor @ctor = new Code - @ctor.body.push new Call 'super', [new Splat new Literal 'arguments'] if @parent + @ctor.body.push new Literal "#{name}.__super__.constructor.apply(this, arguments)" if @parent + @ctor.body.push new Literal "return #{@externalCtor}.apply(this, arguments)" if @externalCtor @body.expressions.unshift @ctor @ctor.ctor = @ctor.name = name @ctor.klass = null @@ -876,7 +877,7 @@ exports.Class = class Class extends Base lname = new Literal name @setContext name - @walkBody name + @walkBody name, o @ensureConstructor name @body.expressions.unshift new Extends lname, @parent if @parent @body.expressions.unshift @ctor unless @ctor instanceof Code diff --git a/test/classes.coffee b/test/classes.coffee index 0c38e8a995..a0ad1f8eff 100644 --- a/test/classes.coffee +++ b/test/classes.coffee @@ -288,10 +288,10 @@ test "classes with value'd constructors", -> class Two constructor: classMaker() - ok (new One).value is 1 - ok (new Two).value is 2 - ok (new One).value is 1 - ok (new Two).value is 2 + eq (new One).value, 1 + eq (new Two).value, 2 + eq (new One).value, 1 + eq (new Two).value, 2 test "exectuable class bodies", -> @@ -451,7 +451,6 @@ test "#1182: external constructors continued", -> class B extends A method: -> constructor: ctor - eq ctor, B ok B::method test "#1313: misplaced __extends", ->