Fixing external constructors / order of execution for once and for all ... knock on wood.

This commit is contained in:
Jeremy Ashkenas
2011-05-10 09:24:20 -04:00
parent f4b8e19c7f
commit 6d6e07604e
3 changed files with 24 additions and 21 deletions

View File

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

View File

@@ -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

View File

@@ -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", ->