mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
safely preserving the arguments object through generated closure wrappers.
This commit is contained in:
parent
491ad6de95
commit
f36acc27e5
3 changed files with 27 additions and 6 deletions
17
lib/nodes.js
17
lib/nodes.js
|
@ -582,7 +582,7 @@
|
|||
return (new CallNode(ref, [this.meth, this.context, literal(this.arguments(o))])).compile(o);
|
||||
};
|
||||
return CurryNode;
|
||||
}).call(this);
|
||||
}).apply(this, arguments);
|
||||
//### ExtendsNode
|
||||
// Node to extend an object's prototype with an ancestor object.
|
||||
// After `goog.inherits` from the
|
||||
|
@ -1697,14 +1697,23 @@
|
|||
// A faux-node used to wrap an expressions body in a closure.
|
||||
ClosureNode = (exports.ClosureNode = {
|
||||
// Wrap the expressions body, unless it contains a pure statement,
|
||||
// in which case, no dice.
|
||||
// in which case, no dice. If the body mentions `arguments`, then make sure
|
||||
// that the closure wrapper preserves the original arguments.
|
||||
wrap: function wrap(expressions, statement) {
|
||||
var call, func;
|
||||
var args, call, func, mentions_args, meth;
|
||||
if (expressions.contains_pure_statement()) {
|
||||
return expressions;
|
||||
}
|
||||
mentions_args = expressions.contains(function(n) {
|
||||
return (n instanceof LiteralNode) && (n.value === 'arguments');
|
||||
});
|
||||
meth = literal(mentions_args ? 'apply' : 'call');
|
||||
args = [literal('this')];
|
||||
if (mentions_args) {
|
||||
args.push(literal('arguments'));
|
||||
}
|
||||
func = new ParentheticalNode(new CodeNode([], Expressions.wrap([expressions])));
|
||||
call = new CallNode(new ValueNode(func, [new AccessorNode(literal('call'))]), [literal('this')]);
|
||||
call = new CallNode(new ValueNode(func, [new AccessorNode(meth)]), args);
|
||||
if (statement) {
|
||||
return Expressions.wrap([call]);
|
||||
} else {
|
||||
|
|
|
@ -1263,11 +1263,16 @@ PushNode: exports.PushNode: {
|
|||
ClosureNode: exports.ClosureNode: {
|
||||
|
||||
# Wrap the expressions body, unless it contains a pure statement,
|
||||
# in which case, no dice.
|
||||
# in which case, no dice. If the body mentions `arguments`, then make sure
|
||||
# that the closure wrapper preserves the original arguments.
|
||||
wrap: (expressions, statement) ->
|
||||
return expressions if expressions.contains_pure_statement()
|
||||
mentions_args: expressions.contains (n) -> (n instanceof LiteralNode) and (n.value is 'arguments')
|
||||
meth: literal(if mentions_args then 'apply' else 'call')
|
||||
args: [literal('this')]
|
||||
args.push literal 'arguments' if mentions_args
|
||||
func: new ParentheticalNode(new CodeNode([], Expressions.wrap([expressions])))
|
||||
call: new CallNode(new ValueNode(func, [new AccessorNode(literal('call'))]), [literal('this')])
|
||||
call: new CallNode(new ValueNode(func, [new AccessorNode(meth)]), args)
|
||||
if statement then Expressions.wrap([call]) else call
|
||||
|
||||
}
|
||||
|
|
|
@ -92,3 +92,10 @@ store: (obj) -> result: obj
|
|||
store (x * 2 for x in [3, 2, 1])
|
||||
|
||||
ok result.join(' ') is '6 4 2'
|
||||
|
||||
|
||||
# Closure-wrapped comprehensions that refer to the "arguments" object.
|
||||
expr: ->
|
||||
result: item * item for item in arguments
|
||||
|
||||
ok expr(2, 4, 8).join(' ') is '4 16 64'
|
||||
|
|
Loading…
Add table
Reference in a new issue