mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-01-15 01:38:13 -05:00
waypoint: part way through refactoring Class
This commit is contained in:
118
lib/nodes.js
118
lib/nodes.js
@@ -7,6 +7,8 @@
|
||||
for (var key in parent) if (__hasProp.call(parent, key)) child[key] = parent[key];
|
||||
child.__super__ = parent.prototype;
|
||||
return child;
|
||||
}, __bind = function(func, context) {
|
||||
return function() { return func.apply(context, arguments); };
|
||||
};
|
||||
Scope = require('./scope').Scope;
|
||||
_ref = require('./helpers'), compact = _ref.compact, flatten = _ref.flatten, extend = _ref.extend, merge = _ref.merge, del = _ref.del, starts = _ref.starts, ends = _ref.ends, last = _ref.last;
|
||||
@@ -820,19 +822,20 @@
|
||||
this.variable = _arg;
|
||||
this.parent = _arg2;
|
||||
this.body = _arg3 != null ? _arg3 : new Expressions;
|
||||
this.boundFuncs = [];
|
||||
}
|
||||
__extends(Class, Base);
|
||||
Class.prototype.children = ['variable', 'parent', 'body'];
|
||||
Class.prototype.compileNode = function(o) {
|
||||
var bname, boundFuncs, bvar, convert, ctor, decl, exps, i, klass, lname, name, node, others, tail, _fn, _i, _j, _len, _len2, _len3, _ref, _ref2;
|
||||
ctor = null;
|
||||
if (this.variable) {
|
||||
decl = (tail = last(this.variable.properties)) ? tail instanceof Accessor && tail.name.value : this.variable.base.value;
|
||||
decl && (decl = IDENTIFIER.test(decl) && decl);
|
||||
Class.prototype.determineName = function() {
|
||||
var decl, tail;
|
||||
if (!this.variable) {
|
||||
return null;
|
||||
}
|
||||
name = decl || this.name || '_Class';
|
||||
lname = new Literal(name);
|
||||
this.body.traverseChildren(false, function(node) {
|
||||
decl = (tail = last(this.variable.properties)) ? tail instanceof Accessor && tail.name.value : this.variable.base.value;
|
||||
return decl && (decl = IDENTIFIER.test(decl) && decl);
|
||||
};
|
||||
Class.prototype.setContext = function(name) {
|
||||
return this.body.traverseChildren(false, function(node) {
|
||||
if (node instanceof Literal && node.value === 'this') {
|
||||
return node.value = name;
|
||||
} else if (node instanceof Code) {
|
||||
@@ -842,34 +845,39 @@
|
||||
}
|
||||
}
|
||||
});
|
||||
convert = function(node) {
|
||||
var assign, base, func, props, _results;
|
||||
props = node.base.properties.slice(0);
|
||||
_results = [];
|
||||
while (assign = props.shift()) {
|
||||
if (assign instanceof Assign) {
|
||||
base = assign.variable.base;
|
||||
delete assign.context;
|
||||
func = assign.value;
|
||||
if (!assign.variable["this"]) {
|
||||
assign.variable = new Value(lname, [new Accessor(base, 'proto')]);
|
||||
}
|
||||
if (func instanceof Code && func.bound) {
|
||||
boundFuncs.push(base);
|
||||
func.bound = false;
|
||||
}
|
||||
};
|
||||
Class.prototype.addProperties = function(node, name) {
|
||||
var assign, base, func, props, _results;
|
||||
props = node.base.properties.slice(0);
|
||||
_results = [];
|
||||
while (assign = props.shift()) {
|
||||
if (assign instanceof Assign) {
|
||||
base = assign.variable.base;
|
||||
delete assign.context;
|
||||
func = assign.value;
|
||||
if (!assign.variable["this"]) {
|
||||
assign.variable = new Value(new Literal(name), [new Accessor(base, 'proto')]);
|
||||
}
|
||||
if (func instanceof Code && func.bound) {
|
||||
this.boundFuncs.push(base);
|
||||
func.bound = false;
|
||||
}
|
||||
_results.push(assign);
|
||||
}
|
||||
return _results;
|
||||
};
|
||||
boundFuncs = [];
|
||||
others = [];
|
||||
_results.push(assign);
|
||||
}
|
||||
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);
|
||||
_ref = exps = this.body.expressions;
|
||||
for (i = 0, _len = _ref.length; i < _len; i++) {
|
||||
node = _ref[i];
|
||||
_fn = function(node, i) {
|
||||
if (node instanceof Value && node.isObject(true)) {
|
||||
exps[i] = compact(convert(node));
|
||||
return exps[i] = compact(this.addProperties(node, name));
|
||||
} else if (node instanceof Code) {
|
||||
if (ctor) {
|
||||
throw new Error('cannot define more than one constructor in a class');
|
||||
@@ -878,29 +886,26 @@
|
||||
throw new Error('cannot define a constructor as a bound function');
|
||||
}
|
||||
ctor = node;
|
||||
exps[i] = null;
|
||||
return exps[i] = null;
|
||||
} else {
|
||||
others.push(node);
|
||||
}
|
||||
}
|
||||
_fn = function(other) {
|
||||
return other.traverseChildren(false, function(n2) {
|
||||
var expr2, j, _len, _ref;
|
||||
if (n2 instanceof Expressions) {
|
||||
_ref = n2.expressions;
|
||||
for (j = 0, _len = _ref.length; j < _len; j++) {
|
||||
expr2 = _ref[j];
|
||||
if (expr2 instanceof Value && expr2.isObject(true)) {
|
||||
n2.expressions[j] = compact(convert(expr2));
|
||||
return node.traverseChildren(false, __bind(function(n2) {
|
||||
var expr2, j, _len, _ref;
|
||||
if (n2 instanceof Expressions) {
|
||||
_ref = n2.expressions;
|
||||
for (j = 0, _len = _ref.length; j < _len; j++) {
|
||||
expr2 = _ref[j];
|
||||
if (expr2 instanceof Value && expr2.isObject(true)) {
|
||||
n2.expressions[j] = compact(this.addProperties(expr2, name));
|
||||
}
|
||||
}
|
||||
return n2.expressions = flatten(n2.expressions);
|
||||
}
|
||||
return n2.expressions = flatten(n2.expressions);
|
||||
}
|
||||
});
|
||||
}, this));
|
||||
}
|
||||
};
|
||||
for (_i = 0, _len2 = others.length; _i < _len2; _i++) {
|
||||
other = others[_i];
|
||||
_fn(other);
|
||||
for (i = 0, _len = _ref.length; i < _len; i++) {
|
||||
node = _ref[i];
|
||||
_fn.call(this, node, i);
|
||||
}
|
||||
this.body.expressions = exps = compact(flatten(exps));
|
||||
if (!ctor) {
|
||||
@@ -917,15 +922,16 @@
|
||||
}
|
||||
exps.unshift(ctor);
|
||||
exps.push(lname);
|
||||
if (boundFuncs.length) {
|
||||
for (_j = 0, _len3 = boundFuncs.length; _j < _len3; _j++) {
|
||||
bvar = boundFuncs[_j];
|
||||
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);"));
|
||||
}
|
||||
}
|
||||
klass = new Parens(new Call(new Code([], this.body)), true);
|
||||
if (decl && ((_ref2 = this.variable) != null ? _ref2.isComplex() : void 0)) {
|
||||
if (decl && ((_ref3 = this.variable) != null ? _ref3.isComplex() : void 0)) {
|
||||
klass = new Assign(new Value(lname), klass);
|
||||
}
|
||||
if (this.variable) {
|
||||
|
||||
@@ -665,22 +665,20 @@ exports.Class = class Class extends Base
|
||||
# Initialize a **Class** with its name, an optional superclass, and a
|
||||
# list of prototype property assignments.
|
||||
(@variable, @parent, @body = new Expressions) ->
|
||||
@boundFuncs = []
|
||||
|
||||
# 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
|
||||
# Figure out the appropriate name for the constructor function of this class.
|
||||
determineName: ->
|
||||
return null unless @variable
|
||||
decl = if tail = last @variable.properties
|
||||
tail instanceof Accessor and tail.name.value
|
||||
else
|
||||
@variable.base.value
|
||||
decl and= IDENTIFIER.test(decl) and decl
|
||||
|
||||
if @variable
|
||||
decl = if tail = last @variable.properties
|
||||
tail instanceof Accessor and tail.name.value
|
||||
else
|
||||
@variable.base.value
|
||||
decl and= IDENTIFIER.test(decl) and decl
|
||||
|
||||
name = decl or @name or '_Class'
|
||||
lname = new Literal name
|
||||
# For all `this`-references and bound functions in the class definition,
|
||||
# `this` is the Class being constructed.
|
||||
setContext: (name) ->
|
||||
@body.traverseChildren false, (node) ->
|
||||
if node instanceof Literal and node.value is 'this'
|
||||
node.value = name
|
||||
@@ -688,25 +686,36 @@ exports.Class = class Class extends Base
|
||||
node.klass = name
|
||||
node.context = name if node.bound
|
||||
|
||||
convert = (node) ->
|
||||
props = node.base.properties.slice 0
|
||||
while assign = props.shift()
|
||||
if assign instanceof Assign
|
||||
base = assign.variable.base
|
||||
delete assign.context
|
||||
func = assign.value
|
||||
unless assign.variable.this
|
||||
assign.variable = new Value(lname, [new Accessor(base, 'proto')])
|
||||
if func instanceof Code and func.bound
|
||||
boundFuncs.push base
|
||||
func.bound = no
|
||||
assign
|
||||
# Merge the properties from a top-level object as prototypal properties
|
||||
# on the class.
|
||||
addProperties: (node, name) ->
|
||||
props = node.base.properties.slice 0
|
||||
while assign = props.shift()
|
||||
if assign instanceof Assign
|
||||
base = assign.variable.base
|
||||
delete assign.context
|
||||
func = assign.value
|
||||
unless assign.variable.this
|
||||
assign.variable = new Value(new Literal(name), [new Accessor(base, 'proto')])
|
||||
if func instanceof Code and func.bound
|
||||
@boundFuncs.push 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
|
||||
|
||||
boundFuncs = []
|
||||
others = []
|
||||
for node, i in exps = @body.expressions
|
||||
if node instanceof Value and node.isObject(true)
|
||||
exps[i] = compact convert node
|
||||
exps[i] = compact @addProperties node, name
|
||||
else if node instanceof Code
|
||||
if ctor
|
||||
throw new Error 'cannot define more than one constructor in a class'
|
||||
@@ -715,16 +724,12 @@ exports.Class = class Class extends Base
|
||||
ctor = node
|
||||
exps[i] = null
|
||||
else
|
||||
others.push node
|
||||
|
||||
# TODO: refactor
|
||||
for other in others
|
||||
other.traverseChildren false, (n2) ->
|
||||
if n2 instanceof Expressions
|
||||
for expr2, j in n2.expressions
|
||||
if expr2 instanceof Value and expr2.isObject(true)
|
||||
n2.expressions[j] = compact convert expr2
|
||||
n2.expressions = flatten n2.expressions
|
||||
node.traverseChildren false, (n2) =>
|
||||
if n2 instanceof Expressions
|
||||
for expr2, j in n2.expressions
|
||||
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
|
||||
@@ -738,8 +743,8 @@ exports.Class = class Class extends Base
|
||||
exps.unshift ctor
|
||||
exps.push lname
|
||||
|
||||
if boundFuncs.length
|
||||
for bvar in boundFuncs
|
||||
if @boundFuncs.length
|
||||
for bvar in @boundFuncs
|
||||
bname = bvar.compile o
|
||||
ctor.body.unshift new Literal "this.#{bname} = #{utility 'bind'}(this.#{bname}, this);"
|
||||
|
||||
|
||||
Reference in New Issue
Block a user