mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
Adopting coco-style efficient bound functions for the common case ... but not for class/prototypes.
This commit is contained in:
parent
52dd348289
commit
981db17b8f
3 changed files with 48 additions and 21 deletions
|
@ -1,6 +1,6 @@
|
||||||
(function() {
|
(function() {
|
||||||
var Access, Arr, Assign, Base, Block, Call, Class, Closure, Code, Comment, Existence, Extends, For, IDENTIFIER, IDENTIFIER_STR, IS_STRING, If, In, Index, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, Literal, METHOD_DEF, NEGATE, NO, Obj, Op, Param, Parens, RESERVED, Range, Return, SIMPLENUM, Scope, Slice, Splat, Switch, TAB, THIS, Throw, Try, UTILITIES, Value, While, YES, compact, del, ends, extend, flatten, last, merge, multident, starts, unfoldSoak, utility, _ref;
|
var Access, Arr, Assign, Base, Block, Call, Class, Closure, Code, Comment, Existence, Extends, For, IDENTIFIER, IDENTIFIER_STR, IS_STRING, If, In, Index, LEVEL_ACCESS, LEVEL_COND, LEVEL_LIST, LEVEL_OP, LEVEL_PAREN, LEVEL_TOP, Literal, METHOD_DEF, NEGATE, NO, Obj, Op, Param, Parens, RESERVED, Range, Return, SIMPLENUM, Scope, Slice, Splat, Switch, TAB, THIS, Throw, Try, UTILITIES, Value, While, YES, compact, del, ends, extend, flatten, last, merge, multident, starts, unfoldSoak, utility, _ref;
|
||||||
var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; }, __bind = function(fn, me){ return function(){ return fn.apply(me, arguments); }; }, __indexOf = Array.prototype.indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (__hasProp.call(this, i) && this[i] === item) return i; } return -1; };
|
var __hasProp = Object.prototype.hasOwnProperty, __extends = function(child, parent) { for (var key in parent) { if (__hasProp.call(parent, key)) child[key] = parent[key]; } function ctor() { this.constructor = child; } ctor.prototype = parent.prototype; child.prototype = new ctor; child.__super__ = parent.prototype; return child; }, __indexOf = Array.prototype.indexOf || function(item) { for (var i = 0, l = this.length; i < l; i++) { if (__hasProp.call(this, i) && this[i] === item) return i; } return -1; };
|
||||||
|
|
||||||
Scope = require('./scope').Scope;
|
Scope = require('./scope').Scope;
|
||||||
|
|
||||||
|
@ -397,8 +397,8 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
Literal.prototype.compileNode = function(o) {
|
Literal.prototype.compileNode = function(o) {
|
||||||
var code, _ref2;
|
var code, _ref2, _ref3;
|
||||||
code = this.isUndefined ? o.level >= LEVEL_ACCESS ? '(void 0)' : 'void 0' : this.value.reserved && ((_ref2 = "" + this.value) !== 'eval' && _ref2 !== 'arguments') ? "\"" + this.value + "\"" : this.value;
|
code = this.isUndefined ? o.level >= LEVEL_ACCESS ? '(void 0)' : 'void 0' : this.value === 'this' ? ((_ref2 = o.scope.method) != null ? _ref2.bound : void 0) ? o.scope.method.context : this.value : this.value.reserved && ((_ref3 = "" + this.value) !== 'eval' && _ref3 !== 'arguments') ? "\"" + this.value + "\"" : this.value;
|
||||||
if (this.isStatement()) {
|
if (this.isStatement()) {
|
||||||
return "" + this.tab + code + ";";
|
return "" + this.tab + code + ";";
|
||||||
} else {
|
} else {
|
||||||
|
@ -563,20 +563,21 @@
|
||||||
|
|
||||||
Value.prototype.unfoldSoak = function(o) {
|
Value.prototype.unfoldSoak = function(o) {
|
||||||
var result;
|
var result;
|
||||||
|
var _this = this;
|
||||||
if (this.unfoldedSoak != null) return this.unfoldedSoak;
|
if (this.unfoldedSoak != null) return this.unfoldedSoak;
|
||||||
result = __bind(function() {
|
result = (function() {
|
||||||
var fst, i, ifn, prop, ref, snd, _len, _ref2;
|
var fst, i, ifn, prop, ref, snd, _len, _ref2;
|
||||||
if (ifn = this.base.unfoldSoak(o)) {
|
if (ifn = _this.base.unfoldSoak(o)) {
|
||||||
Array.prototype.push.apply(ifn.body.properties, this.properties);
|
Array.prototype.push.apply(ifn.body.properties, _this.properties);
|
||||||
return ifn;
|
return ifn;
|
||||||
}
|
}
|
||||||
_ref2 = this.properties;
|
_ref2 = _this.properties;
|
||||||
for (i = 0, _len = _ref2.length; i < _len; i++) {
|
for (i = 0, _len = _ref2.length; i < _len; i++) {
|
||||||
prop = _ref2[i];
|
prop = _ref2[i];
|
||||||
if (!prop.soak) continue;
|
if (!prop.soak) continue;
|
||||||
prop.soak = false;
|
prop.soak = false;
|
||||||
fst = new Value(this.base, this.properties.slice(0, i));
|
fst = new Value(_this.base, _this.properties.slice(0, i));
|
||||||
snd = new Value(this.base, this.properties.slice(i));
|
snd = new Value(_this.base, _this.properties.slice(i));
|
||||||
if (fst.isComplex()) {
|
if (fst.isComplex()) {
|
||||||
ref = new Literal(o.scope.freeVariable('ref'));
|
ref = new Literal(o.scope.freeVariable('ref'));
|
||||||
fst = new Parens(new Assign(ref, fst));
|
fst = new Parens(new Assign(ref, fst));
|
||||||
|
@ -587,7 +588,7 @@
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
return null;
|
return null;
|
||||||
}, this)();
|
})();
|
||||||
return this.unfoldedSoak = result || false;
|
return this.unfoldedSoak = result || false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1166,7 +1167,8 @@
|
||||||
};
|
};
|
||||||
|
|
||||||
Class.prototype.walkBody = function(name, o) {
|
Class.prototype.walkBody = function(name, o) {
|
||||||
return this.traverseChildren(false, __bind(function(child) {
|
var _this = this;
|
||||||
|
return this.traverseChildren(false, function(child) {
|
||||||
var exps, i, node, _len, _ref2;
|
var exps, i, node, _len, _ref2;
|
||||||
if (child instanceof Class) return false;
|
if (child instanceof Class) return false;
|
||||||
if (child instanceof Block) {
|
if (child instanceof Block) {
|
||||||
|
@ -1174,12 +1176,12 @@
|
||||||
for (i = 0, _len = _ref2.length; i < _len; i++) {
|
for (i = 0, _len = _ref2.length; i < _len; i++) {
|
||||||
node = _ref2[i];
|
node = _ref2[i];
|
||||||
if (node instanceof Value && node.isObject(true)) {
|
if (node instanceof Value && node.isObject(true)) {
|
||||||
exps[i] = this.addProperties(node, name, o);
|
exps[i] = _this.addProperties(node, name, o);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return child.expressions = exps = flatten(exps);
|
return child.expressions = exps = flatten(exps);
|
||||||
}
|
}
|
||||||
}, this));
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
Class.prototype.ensureConstructor = function(name) {
|
Class.prototype.ensureConstructor = function(name) {
|
||||||
|
@ -1429,7 +1431,7 @@
|
||||||
this.params = params || [];
|
this.params = params || [];
|
||||||
this.body = body || new Block;
|
this.body = body || new Block;
|
||||||
this.bound = tag === 'boundfunc';
|
this.bound = tag === 'boundfunc';
|
||||||
if (this.bound) this.context = 'this';
|
if (this.bound) this.context = '_this';
|
||||||
}
|
}
|
||||||
|
|
||||||
Code.prototype.children = ['params', 'body'];
|
Code.prototype.children = ['params', 'body'];
|
||||||
|
@ -1441,7 +1443,7 @@
|
||||||
Code.prototype.jumps = NO;
|
Code.prototype.jumps = NO;
|
||||||
|
|
||||||
Code.prototype.compileNode = function(o) {
|
Code.prototype.compileNode = function(o) {
|
||||||
var code, exprs, i, idt, lit, p, param, ref, splats, v, val, vars, wasEmpty, _i, _j, _k, _len, _len2, _len3, _len4, _ref2, _ref3, _ref4, _ref5;
|
var code, exprs, i, idt, lit, p, param, ref, splats, v, val, vars, wasEmpty, _i, _j, _k, _len, _len2, _len3, _len4, _ref2, _ref3, _ref4, _ref5, _ref6;
|
||||||
o.scope = new Scope(o.scope, this.body, this);
|
o.scope = new Scope(o.scope, this.body, this);
|
||||||
o.scope.shared = del(o, 'sharedScope');
|
o.scope.shared = del(o, 'sharedScope');
|
||||||
o.indent += TAB;
|
o.indent += TAB;
|
||||||
|
@ -1500,6 +1502,13 @@
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!(wasEmpty || this.noReturn)) this.body.makeReturn();
|
if (!(wasEmpty || this.noReturn)) this.body.makeReturn();
|
||||||
|
if (this.bound) {
|
||||||
|
if ((_ref6 = o.scope.parent.method) != null ? _ref6.bound : void 0) {
|
||||||
|
this.bound = o.scope.parent.method.context;
|
||||||
|
} else {
|
||||||
|
o.scope.parent.assign('_this', 'this');
|
||||||
|
}
|
||||||
|
}
|
||||||
idt = o.indent;
|
idt = o.indent;
|
||||||
code = 'function';
|
code = 'function';
|
||||||
if (this.ctor) code += ' ' + this.name;
|
if (this.ctor) code += ' ' + this.name;
|
||||||
|
@ -1509,9 +1518,6 @@
|
||||||
}
|
}
|
||||||
code += '}';
|
code += '}';
|
||||||
if (this.ctor) return this.tab + code;
|
if (this.ctor) return this.tab + code;
|
||||||
if (this.bound) {
|
|
||||||
return utility('bind') + ("(" + code + ", " + this.context + ")");
|
|
||||||
}
|
|
||||||
if (this.front || (o.level >= LEVEL_ACCESS)) {
|
if (this.front || (o.level >= LEVEL_ACCESS)) {
|
||||||
return "(" + code + ")";
|
return "(" + code + ")";
|
||||||
} else {
|
} else {
|
||||||
|
|
|
@ -310,6 +310,8 @@ exports.Literal = class Literal extends Base
|
||||||
compileNode: (o) ->
|
compileNode: (o) ->
|
||||||
code = if @isUndefined
|
code = if @isUndefined
|
||||||
if o.level >= LEVEL_ACCESS then '(void 0)' else 'void 0'
|
if o.level >= LEVEL_ACCESS then '(void 0)' else 'void 0'
|
||||||
|
else if @value is 'this'
|
||||||
|
if o.scope.method?.bound then o.scope.method.context else @value
|
||||||
else if @value.reserved and "#{@value}" not in ['eval', 'arguments']
|
else if @value.reserved and "#{@value}" not in ['eval', 'arguments']
|
||||||
"\"#{@value}\""
|
"\"#{@value}\""
|
||||||
else
|
else
|
||||||
|
@ -1080,7 +1082,7 @@ exports.Code = class Code extends Base
|
||||||
@params = params or []
|
@params = params or []
|
||||||
@body = body or new Block
|
@body = body or new Block
|
||||||
@bound = tag is 'boundfunc'
|
@bound = tag is 'boundfunc'
|
||||||
@context = 'this' if @bound
|
@context = '_this' if @bound
|
||||||
|
|
||||||
children: ['params', 'body']
|
children: ['params', 'body']
|
||||||
|
|
||||||
|
@ -1095,7 +1097,7 @@ exports.Code = class Code extends Base
|
||||||
# a closure.
|
# a closure.
|
||||||
compileNode: (o) ->
|
compileNode: (o) ->
|
||||||
o.scope = new Scope o.scope, @body, this
|
o.scope = new Scope o.scope, @body, this
|
||||||
o.scope.shared = del o, 'sharedScope'
|
o.scope.shared = del(o, 'sharedScope')
|
||||||
o.indent += TAB
|
o.indent += TAB
|
||||||
delete o.bare
|
delete o.bare
|
||||||
vars = []
|
vars = []
|
||||||
|
@ -1122,6 +1124,11 @@ exports.Code = class Code extends Base
|
||||||
@body.expressions.unshift exprs... if exprs.length
|
@body.expressions.unshift exprs... if exprs.length
|
||||||
o.scope.parameter vars[i] = v.compile o for v, i in vars unless splats
|
o.scope.parameter vars[i] = v.compile o for v, i in vars unless splats
|
||||||
@body.makeReturn() unless wasEmpty or @noReturn
|
@body.makeReturn() unless wasEmpty or @noReturn
|
||||||
|
if @bound
|
||||||
|
if o.scope.parent.method?.bound
|
||||||
|
@bound = o.scope.parent.method.context
|
||||||
|
else
|
||||||
|
o.scope.parent.assign '_this', 'this'
|
||||||
idt = o.indent
|
idt = o.indent
|
||||||
code = 'function'
|
code = 'function'
|
||||||
code += ' ' + @name if @ctor
|
code += ' ' + @name if @ctor
|
||||||
|
@ -1129,7 +1136,6 @@ exports.Code = class Code extends Base
|
||||||
code += "\n#{ @body.compileWithDeclarations o }\n#{@tab}" unless @body.isEmpty()
|
code += "\n#{ @body.compileWithDeclarations o }\n#{@tab}" unless @body.isEmpty()
|
||||||
code += '}'
|
code += '}'
|
||||||
return @tab + code if @ctor
|
return @tab + code if @ctor
|
||||||
return utility('bind') + "(#{code}, #{@context})" if @bound
|
|
||||||
if @front or (o.level >= LEVEL_ACCESS) then "(#{code})" else code
|
if @front or (o.level >= LEVEL_ACCESS) then "(#{code})" else code
|
||||||
|
|
||||||
# Short-circuit `traverseChildren` method to prevent it from crossing scope boundaries
|
# Short-circuit `traverseChildren` method to prevent it from crossing scope boundaries
|
||||||
|
|
|
@ -64,6 +64,21 @@ ok obj isnt obj.unbound()
|
||||||
eq obj, obj.nested()
|
eq obj, obj.nested()
|
||||||
|
|
||||||
|
|
||||||
|
test "even more fancy bound functions", ->
|
||||||
|
obj =
|
||||||
|
one: ->
|
||||||
|
do =>
|
||||||
|
return this.two()
|
||||||
|
two: ->
|
||||||
|
do =>
|
||||||
|
do =>
|
||||||
|
do =>
|
||||||
|
return this.three
|
||||||
|
three: 3
|
||||||
|
|
||||||
|
eq obj.one(), 3
|
||||||
|
|
||||||
|
|
||||||
test "self-referencing functions", ->
|
test "self-referencing functions", ->
|
||||||
changeMe = ->
|
changeMe = ->
|
||||||
changeMe = 2
|
changeMe = 2
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue