1
0
Fork 0
mirror of https://github.com/jashkenas/coffeescript.git synced 2022-11-09 12:23:24 -05:00

further refactors to Class

This commit is contained in:
Jeremy Ashkenas 2010-11-13 17:05:54 -05:00
parent f1972ff336
commit 9a5546c8e9
2 changed files with 77 additions and 56 deletions

View file

@ -846,6 +846,19 @@
}
});
};
Class.prototype.addBoundFunctions = function(o) {
var bname, bvar, _i, _len, _ref, _results;
if (this.boundFuncs.length) {
_ref = this.boundFuncs;
_results = [];
for (_i = 0, _len = _ref.length; _i < _len; _i++) {
bvar = _ref[_i];
bname = bvar.compile(o);
_results.push(this.ctor.body.unshift(new Literal("this." + bname + " = " + (utility('bind')) + "(this." + bname + ", this);")));
}
return _results;
}
};
Class.prototype.addProperties = function(node, name) {
var assign, base, func, props, _results;
props = node.base.properties.slice(0);
@ -867,25 +880,20 @@
}
return _results;
};
Class.prototype.compileNode = function(o) {
var bname, bvar, ctor, decl, exps, klass, lname, name, _fn, _i, _len, _len2, _ref, _ref2, _ref3;
ctor = null;
decl = this.determineName();
name = decl || this.name || '_Class';
lname = new Literal(name);
this.setContext(name);
Class.prototype.walkBody = function(name) {
var exps, _fn, _len, _ref;
_ref = exps = this.body.expressions;
_fn = function(node, i) {
if (node instanceof Value && node.isObject(true)) {
return exps[i] = compact(this.addProperties(node, name));
} else if (node instanceof Code) {
if (ctor) {
if (this.ctor) {
throw new Error('cannot define more than one constructor in a class');
}
if (node.bound) {
throw new Error('cannot define a constructor as a bound function');
}
ctor = node;
this.ctor = node;
return exps[i] = null;
} else {
return node.traverseChildren(false, __bind(function(n2) {
@ -907,31 +915,35 @@
node = _ref[i];
_fn.call(this, node, i);
}
this.body.expressions = exps = compact(flatten(exps));
if (!ctor) {
ctor = new Code;
return this.body.expressions = exps = compact(flatten(exps));
};
Class.prototype.ensureConstructor = function(name) {
if (!this.ctor) {
this.ctor = new Code;
if (this.parent) {
ctor.body.push(new Call('super', [new Splat(new Literal('arguments'))]));
this.ctor.body.push(new Call('super', [new Splat(new Literal('arguments'))]));
}
}
ctor.ctor = ctor.name = name;
ctor.klass = null;
ctor.noReturn = true;
this.ctor.ctor = this.ctor.name = name;
this.ctor.klass = null;
return this.ctor.noReturn = true;
};
Class.prototype.compileNode = function(o) {
var decl, klass, lname, name, _ref;
decl = this.determineName();
name = decl || this.name || '_Class';
lname = new Literal(name);
this.setContext(name);
this.walkBody(name);
this.ensureConstructor(name);
if (this.parent) {
exps.unshift(new Extends(lname, this.parent));
}
exps.unshift(ctor);
exps.push(lname);
if (this.boundFuncs.length) {
_ref2 = this.boundFuncs;
for (_i = 0, _len2 = _ref2.length; _i < _len2; _i++) {
bvar = _ref2[_i];
bname = bvar.compile(o);
ctor.body.unshift(new Literal("this." + bname + " = " + (utility('bind')) + "(this." + bname + ", this);"));
}
this.body.expressions.unshift(new Extends(lname, this.parent));
}
this.body.expressions.unshift(this.ctor);
this.body.expressions.push(lname);
this.addBoundFunctions(o);
klass = new Parens(new Call(new Code([], this.body)), true);
if (decl && ((_ref3 = this.variable) != null ? _ref3.isComplex() : void 0)) {
if (decl && ((_ref = this.variable) != null ? _ref.isComplex() : void 0)) {
klass = new Assign(new Value(lname), klass);
}
if (this.variable) {

View file

@ -686,6 +686,14 @@ exports.Class = class Class extends Base
node.klass = name
node.context = name if node.bound
# Ensure that all functions bound to the instance are proxied in the
# constructor.
addBoundFunctions: (o) ->
if @boundFuncs.length
for bvar in @boundFuncs
bname = bvar.compile o
@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) ->
@ -702,26 +710,17 @@ exports.Class = class Class extends Base
func.bound = no
assign
# Instead of generating the JavaScript string directly, we build up the
# equivalent syntax tree and compile that, in pieces. You can see the
# constructor, property assignments, and inheritance getting built out below.
compileNode: (o) ->
ctor = null
decl = @determineName()
name = decl or @name or '_Class'
lname = new Literal name
@setContext name
# Walk the body of the class, looking for prototype properties to be converted.
walkBody: (name) ->
for node, i in exps = @body.expressions
if node instanceof Value and node.isObject(true)
exps[i] = compact @addProperties node, name
else if node instanceof Code
if ctor
if @ctor
throw new Error 'cannot define more than one constructor in a class'
if node.bound
throw new Error 'cannot define a constructor as a bound function'
ctor = node
@ctor = node
exps[i] = null
else
node.traverseChildren false, (n2) =>
@ -730,23 +729,33 @@ exports.Class = class Class extends Base
if expr2 instanceof Value and expr2.isObject(true)
n2.expressions[j] = compact @addProperties expr2, name
n2.expressions = flatten n2.expressions
@body.expressions = exps = compact flatten exps
unless ctor
ctor = new Code
if @parent
ctor.body.push new Call 'super', [new Splat new Literal 'arguments']
ctor.ctor = ctor.name = name
ctor.klass = null
ctor.noReturn = yes
exps.unshift new Extends lname, @parent if @parent
exps.unshift ctor
exps.push lname
if @boundFuncs.length
for bvar in @boundFuncs
bname = bvar.compile o
ctor.body.unshift new Literal "this.#{bname} = #{utility 'bind'}(this.#{bname}, this);"
# Make sure that a constructor is defined for the class, and properly
# configured.
ensureConstructor: (name) ->
if not @ctor
@ctor = new Code
@ctor.body.push new Call 'super', [new Splat new Literal 'arguments'] if @parent
@ctor.ctor = @ctor.name = name
@ctor.klass = null
@ctor.noReturn = yes
# Instead of generating the JavaScript string directly, we build up the
# equivalent syntax tree and compile that, in pieces. You can see the
# constructor, property assignments, and inheritance getting built out below.
compileNode: (o) ->
decl = @determineName()
name = decl or @name or '_Class'
lname = new Literal name
@setContext name
@walkBody name
@ensureConstructor name
@body.expressions.unshift new Extends lname, @parent if @parent
@body.expressions.unshift @ctor
@body.expressions.push lname
@addBoundFunctions o
klass = new Parens new Call(new Code [], @body), true
klass = new Assign new Value(lname), klass if decl and @variable?.isComplex()