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() {
|
||||
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;
|
||||
|
||||
|
@ -397,8 +397,8 @@
|
|||
};
|
||||
|
||||
Literal.prototype.compileNode = function(o) {
|
||||
var code, _ref2;
|
||||
code = this.isUndefined ? o.level >= LEVEL_ACCESS ? '(void 0)' : 'void 0' : this.value.reserved && ((_ref2 = "" + this.value) !== 'eval' && _ref2 !== 'arguments') ? "\"" + this.value + "\"" : this.value;
|
||||
var code, _ref2, _ref3;
|
||||
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()) {
|
||||
return "" + this.tab + code + ";";
|
||||
} else {
|
||||
|
@ -563,20 +563,21 @@
|
|||
|
||||
Value.prototype.unfoldSoak = function(o) {
|
||||
var result;
|
||||
var _this = this;
|
||||
if (this.unfoldedSoak != null) return this.unfoldedSoak;
|
||||
result = __bind(function() {
|
||||
result = (function() {
|
||||
var fst, i, ifn, prop, ref, snd, _len, _ref2;
|
||||
if (ifn = this.base.unfoldSoak(o)) {
|
||||
Array.prototype.push.apply(ifn.body.properties, this.properties);
|
||||
if (ifn = _this.base.unfoldSoak(o)) {
|
||||
Array.prototype.push.apply(ifn.body.properties, _this.properties);
|
||||
return ifn;
|
||||
}
|
||||
_ref2 = this.properties;
|
||||
_ref2 = _this.properties;
|
||||
for (i = 0, _len = _ref2.length; i < _len; i++) {
|
||||
prop = _ref2[i];
|
||||
if (!prop.soak) continue;
|
||||
prop.soak = false;
|
||||
fst = new Value(this.base, this.properties.slice(0, i));
|
||||
snd = new Value(this.base, this.properties.slice(i));
|
||||
fst = new Value(_this.base, _this.properties.slice(0, i));
|
||||
snd = new Value(_this.base, _this.properties.slice(i));
|
||||
if (fst.isComplex()) {
|
||||
ref = new Literal(o.scope.freeVariable('ref'));
|
||||
fst = new Parens(new Assign(ref, fst));
|
||||
|
@ -587,7 +588,7 @@
|
|||
});
|
||||
}
|
||||
return null;
|
||||
}, this)();
|
||||
})();
|
||||
return this.unfoldedSoak = result || false;
|
||||
};
|
||||
|
||||
|
@ -1166,7 +1167,8 @@
|
|||
};
|
||||
|
||||
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;
|
||||
if (child instanceof Class) return false;
|
||||
if (child instanceof Block) {
|
||||
|
@ -1174,12 +1176,12 @@
|
|||
for (i = 0, _len = _ref2.length; i < _len; i++) {
|
||||
node = _ref2[i];
|
||||
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);
|
||||
}
|
||||
}, this));
|
||||
});
|
||||
};
|
||||
|
||||
Class.prototype.ensureConstructor = function(name) {
|
||||
|
@ -1429,7 +1431,7 @@
|
|||
this.params = params || [];
|
||||
this.body = body || new Block;
|
||||
this.bound = tag === 'boundfunc';
|
||||
if (this.bound) this.context = 'this';
|
||||
if (this.bound) this.context = '_this';
|
||||
}
|
||||
|
||||
Code.prototype.children = ['params', 'body'];
|
||||
|
@ -1441,7 +1443,7 @@
|
|||
Code.prototype.jumps = NO;
|
||||
|
||||
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.shared = del(o, 'sharedScope');
|
||||
o.indent += TAB;
|
||||
|
@ -1500,6 +1502,13 @@
|
|||
}
|
||||
}
|
||||
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;
|
||||
code = 'function';
|
||||
if (this.ctor) code += ' ' + this.name;
|
||||
|
@ -1509,9 +1518,6 @@
|
|||
}
|
||||
code += '}';
|
||||
if (this.ctor) return this.tab + code;
|
||||
if (this.bound) {
|
||||
return utility('bind') + ("(" + code + ", " + this.context + ")");
|
||||
}
|
||||
if (this.front || (o.level >= LEVEL_ACCESS)) {
|
||||
return "(" + code + ")";
|
||||
} else {
|
||||
|
|
|
@ -310,6 +310,8 @@ exports.Literal = class Literal extends Base
|
|||
compileNode: (o) ->
|
||||
code = if @isUndefined
|
||||
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']
|
||||
"\"#{@value}\""
|
||||
else
|
||||
|
@ -1080,7 +1082,7 @@ exports.Code = class Code extends Base
|
|||
@params = params or []
|
||||
@body = body or new Block
|
||||
@bound = tag is 'boundfunc'
|
||||
@context = 'this' if @bound
|
||||
@context = '_this' if @bound
|
||||
|
||||
children: ['params', 'body']
|
||||
|
||||
|
@ -1095,7 +1097,7 @@ exports.Code = class Code extends Base
|
|||
# a closure.
|
||||
compileNode: (o) ->
|
||||
o.scope = new Scope o.scope, @body, this
|
||||
o.scope.shared = del o, 'sharedScope'
|
||||
o.scope.shared = del(o, 'sharedScope')
|
||||
o.indent += TAB
|
||||
delete o.bare
|
||||
vars = []
|
||||
|
@ -1122,6 +1124,11 @@ exports.Code = class Code extends Base
|
|||
@body.expressions.unshift exprs... if exprs.length
|
||||
o.scope.parameter vars[i] = v.compile o for v, i in vars unless splats
|
||||
@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
|
||||
code = 'function'
|
||||
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 += '}'
|
||||
return @tab + code if @ctor
|
||||
return utility('bind') + "(#{code}, #{@context})" if @bound
|
||||
if @front or (o.level >= LEVEL_ACCESS) then "(#{code})" else code
|
||||
|
||||
# Short-circuit `traverseChildren` method to prevent it from crossing scope boundaries
|
||||
|
|
|
@ -64,6 +64,21 @@ ok obj isnt obj.unbound()
|
|||
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", ->
|
||||
changeMe = ->
|
||||
changeMe = 2
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue