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:
parent
f1972ff336
commit
9a5546c8e9
2 changed files with 77 additions and 56 deletions
68
lib/nodes.js
68
lib/nodes.js
|
@ -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) {
|
||||
|
|
|
@ -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()
|
||||
|
|
Loading…
Add table
Reference in a new issue