mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
generated closures should only call() or apply() when necessary.
This commit is contained in:
parent
f36acc27e5
commit
065bf54094
7 changed files with 65 additions and 54 deletions
|
@ -90,7 +90,7 @@
|
|||
_b.push(' ');
|
||||
}
|
||||
return _b;
|
||||
}).call(this).join('') : '';
|
||||
})().join('') : '';
|
||||
desc = task.description ? ("# " + (task.description)) : '';
|
||||
puts(("cake " + name + spaces + " " + desc));
|
||||
}}
|
||||
|
|
|
@ -188,10 +188,10 @@
|
|||
tag = _e[0];
|
||||
value = _e[1];
|
||||
return "[" + tag + " " + value + "]";
|
||||
}).call(this));
|
||||
})());
|
||||
}
|
||||
return _a;
|
||||
}).call(this);
|
||||
})();
|
||||
return puts(strings.join(' '));
|
||||
};
|
||||
// Use the [OptionParser module](optparse.html) to extract all options from
|
||||
|
|
|
@ -713,10 +713,10 @@
|
|||
alt[1] = ("return " + (alt[1]));
|
||||
}
|
||||
return alt;
|
||||
}).call(this));
|
||||
})());
|
||||
}
|
||||
return _b;
|
||||
}).call(this);
|
||||
})();
|
||||
}}
|
||||
// Initialize the **Parser** with our list of terminal **tokens**, our **grammar**
|
||||
// rules, and the name of the root. Reverse the operators because Jison orders
|
||||
|
|
77
lib/nodes.js
77
lib/nodes.js
|
@ -155,7 +155,7 @@
|
|||
if (node.traverse) {
|
||||
return node.traverse(block);
|
||||
}
|
||||
}).call(this));
|
||||
})());
|
||||
}
|
||||
return _a;
|
||||
};
|
||||
|
@ -189,7 +189,7 @@
|
|||
return false;
|
||||
};
|
||||
return BaseNode;
|
||||
}).call(this);
|
||||
})();
|
||||
//### Expressions
|
||||
// The expressions body is the list of expressions that forms the body of an
|
||||
// indented block of code -- the implementation of a function, a clause in an
|
||||
|
@ -307,7 +307,7 @@
|
|||
}
|
||||
};
|
||||
return Expressions;
|
||||
}).call(this);
|
||||
})();
|
||||
// Wrap up the given nodes as an **Expressions**, unless it already happens
|
||||
// to be one.
|
||||
Expressions.wrap = function wrap(nodes) {
|
||||
|
@ -343,7 +343,7 @@
|
|||
return " \"" + this.value + "\"";
|
||||
};
|
||||
return LiteralNode;
|
||||
}).call(this);
|
||||
})();
|
||||
//### ReturnNode
|
||||
// A `return` is a *pure_statement* -- wrapping it in a closure wouldn't
|
||||
// make sense.
|
||||
|
@ -369,7 +369,7 @@
|
|||
return "" + (this.tab) + "return " + (this.expression.compile(o)) + ";";
|
||||
};
|
||||
return ReturnNode;
|
||||
}).call(this);
|
||||
})();
|
||||
statement(ReturnNode, true);
|
||||
//### ValueNode
|
||||
// A value, variable or literal or parenthesized, indexed or dotted into,
|
||||
|
@ -462,7 +462,7 @@
|
|||
}
|
||||
};
|
||||
return ValueNode;
|
||||
}).call(this);
|
||||
})();
|
||||
//### CommentNode
|
||||
// CoffeeScript passes through comments as JavaScript comments at the
|
||||
// same position.
|
||||
|
@ -480,7 +480,7 @@
|
|||
return ("" + this.tab + "//") + this.lines.join(("\n" + this.tab + "//"));
|
||||
};
|
||||
return CommentNode;
|
||||
}).call(this);
|
||||
})();
|
||||
statement(CommentNode);
|
||||
//### CallNode
|
||||
// Node for a function invocation. Takes care of converting `super()` calls into
|
||||
|
@ -552,7 +552,7 @@
|
|||
return "" + (this.prefix()) + (meth) + ".apply(" + obj + ", " + (this.compile_splat_arguments(o)) + ")";
|
||||
};
|
||||
return CallNode;
|
||||
}).call(this);
|
||||
})();
|
||||
//### CurryNode
|
||||
// Binds a context object and a list of arguments to a function,
|
||||
// returning the bound function. After ECMAScript 5, Prototype.js, and
|
||||
|
@ -600,7 +600,7 @@
|
|||
return (new CallNode(ref, [this.child, this.parent])).compile(o);
|
||||
};
|
||||
return ExtendsNode;
|
||||
}).call(this);
|
||||
})();
|
||||
//### AccessorNode
|
||||
// A `.` accessor into a property of a value, or the `::` shorthand for
|
||||
// an accessor into the object's prototype.
|
||||
|
@ -619,7 +619,7 @@
|
|||
return "." + proto_part + (this.name.compile(o));
|
||||
};
|
||||
return AccessorNode;
|
||||
}).call(this);
|
||||
})();
|
||||
//### IndexNode
|
||||
// A `[ ... ]` indexed accessor into an array or object.
|
||||
exports.IndexNode = (function() {
|
||||
|
@ -635,7 +635,7 @@
|
|||
return "[" + idx + "]";
|
||||
};
|
||||
return IndexNode;
|
||||
}).call(this);
|
||||
})();
|
||||
//### RangeNode
|
||||
// A range literal. Ranges can be used to extract portions (slices) of arrays,
|
||||
// to specify a range for comprehensions, or as a value, to be expanded into the
|
||||
|
@ -690,7 +690,7 @@
|
|||
return (new ParentheticalNode(new CallNode(new CodeNode([], arr.make_return())))).compile(o);
|
||||
};
|
||||
return RangeNode;
|
||||
}).call(this);
|
||||
})();
|
||||
//### SliceNode
|
||||
// An array slice literal. Unlike JavaScript's `Array#slice`, the second parameter
|
||||
// specifies the index of the end of the slice, just as the first parameter
|
||||
|
@ -710,7 +710,7 @@
|
|||
return ".slice(" + from + ", " + to + plus_part + ")";
|
||||
};
|
||||
return SliceNode;
|
||||
}).call(this);
|
||||
})();
|
||||
//### ObjectNode
|
||||
// An object literal, nothing fancy.
|
||||
exports.ObjectNode = (function() {
|
||||
|
@ -757,7 +757,7 @@
|
|||
return "{" + inner + "}";
|
||||
};
|
||||
return ObjectNode;
|
||||
}).call(this);
|
||||
})();
|
||||
//### ArrayNode
|
||||
// An array literal.
|
||||
exports.ArrayNode = (function() {
|
||||
|
@ -790,7 +790,7 @@
|
|||
return "[" + objects + ending;
|
||||
};
|
||||
return ArrayNode;
|
||||
}).call(this);
|
||||
})();
|
||||
//### ClassNode
|
||||
// The CoffeeScript class definition.
|
||||
exports.ClassNode = (function() {
|
||||
|
@ -848,7 +848,7 @@
|
|||
return "" + construct + extension + props + returns;
|
||||
};
|
||||
return ClassNode;
|
||||
}).call(this);
|
||||
})();
|
||||
statement(ClassNode);
|
||||
//### AssignNode
|
||||
// The **AssignNode** is used to assign a local variable to value, or to set the
|
||||
|
@ -970,7 +970,7 @@
|
|||
return "" + (name) + ".splice.apply(" + name + ", [" + from + ", " + to + "].concat(" + val + "))";
|
||||
};
|
||||
return AssignNode;
|
||||
}).call(this);
|
||||
})();
|
||||
//### CodeNode
|
||||
// A function definition. This is the only node that creates a new Scope.
|
||||
// When for the purposes of walking the contents of a function body, the CodeNode
|
||||
|
@ -1022,7 +1022,7 @@
|
|||
_d.push(param.compile(o));
|
||||
}
|
||||
return _d;
|
||||
}).call(this);
|
||||
})();
|
||||
this.body.make_return();
|
||||
_i = params;
|
||||
for (_h = 0, _j = _i.length; _h < _j; _h++) {
|
||||
|
@ -1075,7 +1075,7 @@
|
|||
return "\n" + idt + children;
|
||||
};
|
||||
return CodeNode;
|
||||
}).call(this);
|
||||
})();
|
||||
//### SplatNode
|
||||
// A splat, either as a parameter to a function, an argument to a call,
|
||||
// or as part of a destructuring assignment.
|
||||
|
@ -1199,7 +1199,7 @@
|
|||
return "" + pre + " {\n" + (this.body.compile(o)) + "\n" + this.tab + "}\n" + post;
|
||||
};
|
||||
return WhileNode;
|
||||
}).call(this);
|
||||
})();
|
||||
statement(WhileNode);
|
||||
//### OpNode
|
||||
// Simple Arithmetic and logical operations. Performs some conversion from
|
||||
|
@ -1302,7 +1302,7 @@
|
|||
return parts.join('');
|
||||
};
|
||||
return OpNode;
|
||||
}).call(this);
|
||||
})();
|
||||
//### TryNode
|
||||
// A classic *try/catch/finally* block.
|
||||
exports.TryNode = (function() {
|
||||
|
@ -1335,7 +1335,7 @@
|
|||
return "" + (this.tab) + "try {\n" + attempt_part + "\n" + this.tab + "}" + catch_part + finally_part;
|
||||
};
|
||||
return TryNode;
|
||||
}).call(this);
|
||||
})();
|
||||
statement(TryNode);
|
||||
//### ThrowNode
|
||||
// Simple node to throw an exception.
|
||||
|
@ -1353,7 +1353,7 @@
|
|||
return "" + (this.tab) + "throw " + (this.expression.compile(o)) + ";";
|
||||
};
|
||||
return ThrowNode;
|
||||
}).call(this);
|
||||
})();
|
||||
statement(ThrowNode);
|
||||
//### ExistenceNode
|
||||
// Checks a variable for existence -- not *null* and not *undefined*. This is
|
||||
|
@ -1422,7 +1422,7 @@
|
|||
}
|
||||
};
|
||||
return ParentheticalNode;
|
||||
}).call(this);
|
||||
})();
|
||||
//### ForNode
|
||||
// CoffeeScript's replacement for the *for* loop is our array and object
|
||||
// comprehensions, that compile into *for* loops here. They also act as an
|
||||
|
@ -1530,7 +1530,7 @@
|
|||
return "" + set_result + (source_part) + "for (" + for_part + ") {\n" + var_part + body + "\n" + this.tab + close + return_result;
|
||||
};
|
||||
return ForNode;
|
||||
}).call(this);
|
||||
})();
|
||||
statement(ForNode);
|
||||
//### IfNode
|
||||
// *If/else* statements. Our *switch/when* will be compiled into this. Acts as an
|
||||
|
@ -1675,7 +1675,7 @@
|
|||
return "" + if_part + " : " + else_part;
|
||||
};
|
||||
return IfNode;
|
||||
}).call(this);
|
||||
})();
|
||||
// Faux-Nodes
|
||||
// ----------
|
||||
//### PushNode
|
||||
|
@ -1697,23 +1697,30 @@
|
|||
// 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. If the body mentions `arguments`, then make sure
|
||||
// that the closure wrapper preserves the original arguments.
|
||||
// in which case, no dice. If the body mentions `this` or `arguments`,
|
||||
// then make sure that the closure wrapper preserves the original values.
|
||||
wrap: function wrap(expressions, statement) {
|
||||
var args, call, func, mentions_args, meth;
|
||||
var args, call, func, mentions_args, mentions_this, meth;
|
||||
if (expressions.contains_pure_statement()) {
|
||||
return expressions;
|
||||
}
|
||||
func = new ParentheticalNode(new CodeNode([], Expressions.wrap([expressions])));
|
||||
args = [];
|
||||
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'));
|
||||
mentions_this = expressions.contains(function(n) {
|
||||
return (n instanceof LiteralNode) && (n.value === 'this');
|
||||
});
|
||||
if (mentions_args || mentions_this) {
|
||||
meth = literal(mentions_args ? 'apply' : 'call');
|
||||
args = [literal('this')];
|
||||
if (mentions_args) {
|
||||
args.push(literal('arguments'));
|
||||
}
|
||||
func = new ValueNode(func, [new AccessorNode(meth)]);
|
||||
}
|
||||
func = new ParentheticalNode(new CodeNode([], Expressions.wrap([expressions])));
|
||||
call = new CallNode(new ValueNode(func, [new AccessorNode(meth)]), args);
|
||||
call = new CallNode(func, args);
|
||||
if (statement) {
|
||||
return Expressions.wrap([call]);
|
||||
} else {
|
||||
|
|
|
@ -63,14 +63,14 @@
|
|||
_d.push(' ');
|
||||
}
|
||||
return _d;
|
||||
}).call(this).join('') : '';
|
||||
})().join('') : '';
|
||||
let_part = rule.short_flag ? rule.short_flag + ', ' : ' ';
|
||||
lines.push((" " + let_part + (rule.long_flag) + spaces + (rule.description)));
|
||||
}
|
||||
return "\n" + (lines.join('\n')) + "\n";
|
||||
};
|
||||
return OptionParser;
|
||||
}).call(this);
|
||||
})();
|
||||
// Helpers
|
||||
// -------
|
||||
// Regex matchers for option flags.
|
||||
|
@ -90,7 +90,7 @@
|
|||
tuple.unshift(null);
|
||||
}
|
||||
return build_rule.apply(this, tuple);
|
||||
}).call(this));
|
||||
})());
|
||||
}
|
||||
return _a;
|
||||
};
|
||||
|
|
|
@ -267,7 +267,7 @@
|
|||
value > 0 ? _a.push(key) : null;
|
||||
}}
|
||||
return _a;
|
||||
}).call(this);
|
||||
})();
|
||||
if (unclosed.length) {
|
||||
open = unclosed[0];
|
||||
line = open_line[open] + 1;
|
||||
|
@ -323,7 +323,7 @@
|
|||
}, this));
|
||||
};
|
||||
return Rewriter;
|
||||
}).call(this);
|
||||
})();
|
||||
// Constants
|
||||
// ---------
|
||||
// List of the token pairs that must be balanced.
|
||||
|
@ -345,7 +345,7 @@
|
|||
_d.push(pair[0]);
|
||||
}
|
||||
return _d;
|
||||
}).call(this);
|
||||
})();
|
||||
// The tokens that signal the end of a balanced pair.
|
||||
EXPRESSION_END = (function() {
|
||||
_h = []; _j = BALANCED_PAIRS;
|
||||
|
@ -354,7 +354,7 @@
|
|||
_h.push(pair[1]);
|
||||
}
|
||||
return _h;
|
||||
}).call(this);
|
||||
})();
|
||||
// Tokens that indicate the close of a clause of an expression.
|
||||
EXPRESSION_CLOSE = ['CATCH', 'WHEN', 'ELSE', 'FINALLY'].concat(EXPRESSION_END);
|
||||
// Tokens that, if followed by an `IMPLICIT_CALL`, indicate a function invocation.
|
||||
|
|
|
@ -1263,16 +1263,20 @@ PushNode: exports.PushNode: {
|
|||
ClosureNode: exports.ClosureNode: {
|
||||
|
||||
# Wrap the expressions body, unless it contains a pure statement,
|
||||
# in which case, no dice. If the body mentions `arguments`, then make sure
|
||||
# that the closure wrapper preserves the original arguments.
|
||||
# in which case, no dice. If the body mentions `this` or `arguments`,
|
||||
# then make sure that the closure wrapper preserves the original values.
|
||||
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(meth)]), args)
|
||||
args: []
|
||||
mentions_args: expressions.contains (n) -> (n instanceof LiteralNode) and (n.value is 'arguments')
|
||||
mentions_this: expressions.contains (n) -> (n instanceof LiteralNode) and (n.value is 'this')
|
||||
if mentions_args or mentions_this
|
||||
meth: literal(if mentions_args then 'apply' else 'call')
|
||||
args: [literal('this')]
|
||||
args.push literal 'arguments' if mentions_args
|
||||
func: new ValueNode func, [new AccessorNode(meth)]
|
||||
call: new CallNode(func, args)
|
||||
if statement then Expressions.wrap([call]) else call
|
||||
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue