mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-02-18 19:34:27 -05:00
more streamlined code generation for instance-bound methods ... keep the prototype method around, and just bind it in the constructor.
This commit is contained in:
33
lib/nodes.js
33
lib/nodes.js
@@ -895,10 +895,13 @@
|
|||||||
// equivalent syntax tree and compile that, in pieces. You can see the
|
// equivalent syntax tree and compile that, in pieces. You can see the
|
||||||
// constructor, property assignments, and inheritance getting built out below.
|
// constructor, property assignments, and inheritance getting built out below.
|
||||||
ClassNode.prototype.compileNode = function(o) {
|
ClassNode.prototype.compileNode = function(o) {
|
||||||
var _b, _c, _d, _e, access, applied, construct, extension, func, prop, props, pvar, returns, val;
|
var _b, _c, _d, _e, access, applied, className, constScope, construct, extension, func, me, pname, prop, props, pvar, returns, val;
|
||||||
extension = this.parent && new ExtendsNode(this.variable, this.parent);
|
extension = this.parent && new ExtendsNode(this.variable, this.parent);
|
||||||
props = new Expressions();
|
props = new Expressions();
|
||||||
o.top = true;
|
o.top = true;
|
||||||
|
me = null;
|
||||||
|
className = this.variable.compile(o);
|
||||||
|
constScope = null;
|
||||||
if (this.parent) {
|
if (this.parent) {
|
||||||
applied = new ValueNode(this.parent, [new AccessorNode(literal('apply'))]);
|
applied = new ValueNode(this.parent, [new AccessorNode(literal('apply'))]);
|
||||||
constructor = new CodeNode([], new Expressions([new CallNode(applied, [literal('this'), literal('arguments')])]));
|
constructor = new CodeNode([], new Expressions([new CallNode(applied, [literal('this'), literal('arguments')])]));
|
||||||
@@ -912,7 +915,7 @@
|
|||||||
pvar = _e[0];
|
pvar = _e[0];
|
||||||
func = _e[1];
|
func = _e[1];
|
||||||
if (pvar && pvar.base.value === 'constructor' && func instanceof CodeNode) {
|
if (pvar && pvar.base.value === 'constructor' && func instanceof CodeNode) {
|
||||||
func.name = this.variable.compile(o);
|
func.name = className;
|
||||||
func.body.push(new ReturnNode(literal('this')));
|
func.body.push(new ReturnNode(literal('this')));
|
||||||
this.variable = new ValueNode(this.variable);
|
this.variable = new ValueNode(this.variable);
|
||||||
this.variable.namespaced = include(func.name, '.');
|
this.variable.namespaced = include(func.name, '.');
|
||||||
@@ -920,20 +923,28 @@
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
if (func instanceof CodeNode && func.bound) {
|
if (func instanceof CodeNode && func.bound) {
|
||||||
|
func.bound = false;
|
||||||
|
constScope = constScope || new Scope(o.scope, constructor.body, constructor);
|
||||||
|
me = me || constScope.freeVariable();
|
||||||
|
pname = pvar.compile(o);
|
||||||
if (constructor.body.empty()) {
|
if (constructor.body.empty()) {
|
||||||
constructor.body.push(new ReturnNode(literal('this')));
|
constructor.body.push(new ReturnNode(literal('this')));
|
||||||
}
|
}
|
||||||
constructor.body.unshift(new AssignNode(new ValueNode(literal('this'), [new AccessorNode(pvar)]), func));
|
constructor.body.unshift(literal(("this." + (pname) + " = function(){ return " + (className) + ".prototype." + (pname) + ".apply(" + me + ", arguments); }")));
|
||||||
} else {
|
|
||||||
if (pvar) {
|
|
||||||
access = prop.context === 'this' ? pvar.base.properties[0] : new AccessorNode(pvar, 'prototype');
|
|
||||||
val = new ValueNode(this.variable, [access]);
|
|
||||||
prop = new AssignNode(val, func);
|
|
||||||
}
|
|
||||||
props.push(prop);
|
|
||||||
}
|
}
|
||||||
|
if (pvar) {
|
||||||
|
access = prop.context === 'this' ? pvar.base.properties[0] : new AccessorNode(pvar, 'prototype');
|
||||||
|
val = new ValueNode(this.variable, [access]);
|
||||||
|
prop = new AssignNode(val, func);
|
||||||
|
}
|
||||||
|
props.push(prop);
|
||||||
}
|
}
|
||||||
construct = this.idt() + (new AssignNode(this.variable, constructor)).compile(o) + ';\n';
|
if (me) {
|
||||||
|
constructor.body.unshift(literal(("" + me + " = this")));
|
||||||
|
}
|
||||||
|
construct = this.idt() + (new AssignNode(this.variable, constructor)).compile(merge(o, {
|
||||||
|
sharedScope: constScope
|
||||||
|
})) + ';\n';
|
||||||
props = props.empty() ? '' : props.compile(o) + '\n';
|
props = props.empty() ? '' : props.compile(o) + '\n';
|
||||||
extension = extension ? this.idt() + extension.compile(o) + ';\n' : '';
|
extension = extension ? this.idt() + extension.compile(o) + ';\n' : '';
|
||||||
returns = this.returns ? new ReturnNode(this.variable).compile(o) : '';
|
returns = this.returns ? new ReturnNode(this.variable).compile(o) : '';
|
||||||
|
|||||||
@@ -655,9 +655,12 @@ exports.ClassNode: class ClassNode extends BaseNode
|
|||||||
# equivalent syntax tree and compile that, in pieces. You can see the
|
# equivalent syntax tree and compile that, in pieces. You can see the
|
||||||
# constructor, property assignments, and inheritance getting built out below.
|
# constructor, property assignments, and inheritance getting built out below.
|
||||||
compileNode: (o) ->
|
compileNode: (o) ->
|
||||||
extension: @parent and new ExtendsNode(@variable, @parent)
|
extension: @parent and new ExtendsNode(@variable, @parent)
|
||||||
props: new Expressions()
|
props: new Expressions()
|
||||||
o.top: true
|
o.top: true
|
||||||
|
me: null
|
||||||
|
className: @variable.compile o
|
||||||
|
constScope: null
|
||||||
|
|
||||||
if @parent
|
if @parent
|
||||||
applied: new ValueNode(@parent, [new AccessorNode(literal('apply'))])
|
applied: new ValueNode(@parent, [new AccessorNode(literal('apply'))])
|
||||||
@@ -670,23 +673,27 @@ exports.ClassNode: class ClassNode extends BaseNode
|
|||||||
for prop in @properties
|
for prop in @properties
|
||||||
[pvar, func]: [prop.variable, prop.value]
|
[pvar, func]: [prop.variable, prop.value]
|
||||||
if pvar and pvar.base.value is 'constructor' and func instanceof CodeNode
|
if pvar and pvar.base.value is 'constructor' and func instanceof CodeNode
|
||||||
func.name: @variable.compile(o)
|
func.name: className
|
||||||
func.body.push new ReturnNode literal 'this'
|
func.body.push new ReturnNode literal 'this'
|
||||||
@variable: new ValueNode @variable
|
@variable: new ValueNode @variable
|
||||||
@variable.namespaced: include func.name, '.'
|
@variable.namespaced: include func.name, '.'
|
||||||
constructor: func
|
constructor: func
|
||||||
continue
|
continue
|
||||||
if func instanceof CodeNode and func.bound
|
if func instanceof CodeNode and func.bound
|
||||||
|
func.bound: false
|
||||||
|
constScope: or new Scope(o.scope, constructor.body, constructor)
|
||||||
|
me: or constScope.freeVariable()
|
||||||
|
pname: pvar.compile(o)
|
||||||
constructor.body.push new ReturnNode literal 'this' if constructor.body.empty()
|
constructor.body.push new ReturnNode literal 'this' if constructor.body.empty()
|
||||||
constructor.body.unshift new AssignNode(new ValueNode(literal('this'), [new AccessorNode(pvar)]), func)
|
constructor.body.unshift literal "this.${pname} = function(){ return ${className}.prototype.${pname}.apply($me, arguments); }"
|
||||||
else
|
if pvar
|
||||||
if pvar
|
access: if prop.context is 'this' then pvar.base.properties[0] else new AccessorNode(pvar, 'prototype')
|
||||||
access: if prop.context is 'this' then pvar.base.properties[0] else new AccessorNode(pvar, 'prototype')
|
val: new ValueNode(@variable, [access])
|
||||||
val: new ValueNode(@variable, [access])
|
prop: new AssignNode(val, func)
|
||||||
prop: new AssignNode(val, func)
|
props.push prop
|
||||||
props.push prop
|
|
||||||
|
|
||||||
construct: @idt() + (new AssignNode(@variable, constructor)).compile(o) + ';\n'
|
constructor.body.unshift literal "$me = this" if me
|
||||||
|
construct: @idt() + (new AssignNode(@variable, constructor)).compile(merge o, {sharedScope: constScope}) + ';\n'
|
||||||
props: if props.empty() then '' else props.compile(o) + '\n'
|
props: if props.empty() then '' else props.compile(o) + '\n'
|
||||||
extension: if extension then @idt() + extension.compile(o) + ';\n' else ''
|
extension: if extension then @idt() + extension.compile(o) + ';\n' else ''
|
||||||
returns: if @returns then new ReturnNode(@variable).compile(o) else ''
|
returns: if @returns then new ReturnNode(@variable).compile(o) else ''
|
||||||
@@ -815,7 +822,7 @@ exports.CodeNode: class CodeNode extends BaseNode
|
|||||||
# arrow, generates a wrapper that saves the current value of `this` through
|
# arrow, generates a wrapper that saves the current value of `this` through
|
||||||
# a closure.
|
# a closure.
|
||||||
compileNode: (o) ->
|
compileNode: (o) ->
|
||||||
sharedScope: del o, 'sharedScope'
|
sharedScope: del o, 'sharedScope'
|
||||||
top: del o, 'top'
|
top: del o, 'top'
|
||||||
o.scope: sharedScope or new Scope(o.scope, @body, this)
|
o.scope: sharedScope or new Scope(o.scope, @body, this)
|
||||||
o.top: true
|
o.top: true
|
||||||
|
|||||||
Reference in New Issue
Block a user