1
0
Fork 0
mirror of https://github.com/jashkenas/coffeescript.git synced 2022-11-09 12:23:24 -05:00

more cleanups, added a utility helper function to the codegen

This commit is contained in:
Jeremy Ashkenas 2010-03-30 19:48:37 -04:00
parent 6d7a04228f
commit 998a7c8cb0
4 changed files with 35 additions and 33 deletions

View file

@ -1,5 +1,5 @@
(function(){
var AccessorNode, ArrayNode, AssignNode, BaseNode, CallNode, ClassNode, ClosureNode, CodeNode, CommentNode, CurryNode, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IfNode, IndexNode, LiteralNode, ObjectNode, OpNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, Scope, SliceNode, SplatNode, TAB, TRAILING_WHITESPACE, ThrowNode, TryNode, UTILITIES, ValueNode, WhileNode, compact, del, flatten, helpers, literal, merge, statement;
var AccessorNode, ArrayNode, AssignNode, BaseNode, CallNode, ClassNode, ClosureNode, CodeNode, CommentNode, CurryNode, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IfNode, IndexNode, LiteralNode, ObjectNode, OpNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, Scope, SliceNode, SplatNode, TAB, TRAILING_WHITESPACE, ThrowNode, TryNode, UTILITIES, ValueNode, WhileNode, compact, del, flatten, helpers, literal, merge, statement, utility;
var __extend = function(child, parent) {
var ctor = function(){ };
ctor.prototype = parent.prototype;
@ -596,14 +596,10 @@
};
CurryNode.prototype.compile_node = function compile_node(o) {
var ref;
CurryNode.assign_bind();
ref = new ValueNode(literal('__bind'));
utility('slice');
ref = new ValueNode(literal(utility('bind')));
return (new CallNode(ref, [this.meth, this.context, literal(this.arguments(o))])).compile(o);
};
CurryNode.assign_bind = function assign_bind() {
Scope.root.assign('__slice', UTILITIES['slice']);
return Scope.root.assign('__bind', UTILITIES['bind']);
};
return CurryNode;
}).call(this);
//### ExtendsNode
@ -620,7 +616,7 @@
// Hooks one constructor into another's prototype chain.
ExtendsNode.prototype.compile_node = function compile_node(o) {
var ref;
ref = new ValueNode(literal(Scope.root.assign('__extend', UTILITIES['extend'])));
ref = new ValueNode(literal(utility('extend')));
return (new CallNode(ref, [this.child, this.parent])).compile(o);
};
return ExtendsNode;
@ -745,7 +741,7 @@
to = (typeof (_b = this.range.to) !== "undefined" && _b !== null) ? this.range.to : literal('null');
exclusive = this.range.exclusive ? 'true' : 'false';
v = o.scope.free_variable();
rng = new CallNode(new ValueNode(literal(Scope.root.assign('__range', UTILITIES['range']))), [literal(array), from, to, literal(exclusive)]);
rng = new CallNode(new ValueNode(literal(utility('range'))), [literal(array), from, to, literal(exclusive)]);
args = literal("[(" + v + " = " + (rng.compile(o)) + ")[0], " + v + "[1] - " + v + "[0]].concat(" + (replace.compile(o)) + ")");
call = new CallNode(new ValueNode(literal(array), [literal('.splice.apply')]), [literal(array), args]);
return call.compile(o);
@ -756,7 +752,7 @@
from = (typeof (_a = this.range.from) !== "undefined" && _a !== null) ? this.range.from : literal('null');
to = (typeof (_b = this.range.to) !== "undefined" && _b !== null) ? this.range.to : literal('null');
exclusive = this.range.exclusive ? 'true' : 'false';
rng = new CallNode(new ValueNode(literal(Scope.root.assign('__range', UTILITIES['range']))), [literal(array), from, to, literal(exclusive)]);
rng = new CallNode(new ValueNode(literal(utility('range'))), [literal(array), from, to, literal(exclusive)]);
call = new CallNode(new ValueNode(literal(array), [literal('.slice.apply')]), [literal(array), rng]);
return call.compile(o);
};
@ -1088,8 +1084,8 @@
if (!(this.bound)) {
return func;
}
CurryNode.assign_bind();
ref = new ValueNode(literal('__bind'));
utility('slice');
ref = new ValueNode(literal(utility('bind')));
return (new CallNode(ref, [literal(func), literal('this')])).compile(o);
};
CodeNode.prototype.top_sensitive = function top_sensitive() {
@ -1160,15 +1156,14 @@
o.scope.assign(trailing.compile(o), "arguments[arguments.length - " + this.trailings.length + " + " + i + "]");
i += 1;
}
return "" + name + " = " + (Scope.root.assign('__slice', UTILITIES['slice'])) + ".call(arguments, " + this.index + ", arguments.length - " + (this.trailings.length) + ")";
return "" + name + " = " + (utility('slice')) + ".call(arguments, " + this.index + ", arguments.length - " + (this.trailings.length) + ")";
};
// A compiling a splat as a destructuring assignment means slicing arguments
// from the right-hand-side's corresponding array.
SplatNode.prototype.compile_value = function compile_value(o, name, index, trailings) {
var trail;
Scope.root.assign('__slice', UTILITIES['slice']);
trail = trailings ? ", " + (name) + ".length - " + trailings : '';
return "__slice.call(" + name + ", " + index + trail + ")";
return "" + (utility('slice')) + ".call(" + name + ", " + index + trail + ")";
};
// Utility function that converts arbitrary number of elements, mixed with
// splats, to a proper array
@ -1579,7 +1574,7 @@
body = PushNode.wrap(rvar, body);
}
this.filter ? (body = Expressions.wrap([new IfNode(this.filter, body)])) : null;
this.object ? (for_part = "" + ivar + " in " + svar + ") { if (" + (Scope.root.assign('__hasProp', UTILITIES['hasProp'])) + ".call(" + svar + ", " + ivar + ")") : null;
this.object ? (for_part = "" + ivar + " in " + svar + ") { if (" + (utility('hasProp')) + ".call(" + svar + ", " + ivar + ")") : null;
body = body.compile(merge(o, {
indent: body_dent,
top: true
@ -1796,4 +1791,11 @@
literal = function literal(name) {
return new LiteralNode(name);
};
// Helper for ensuring that utility functions are assigned at the top level.
utility = function utility(name) {
var ref;
ref = "__" + name;
Scope.root.assign(ref, UTILITIES[name]);
return ref;
};
})();

View file

@ -85,7 +85,7 @@
value: value,
assigned: true
};
return name;
return this.variables[name];
};
// Does this scope reference any variables that need to be declared in the
// given function body?

View file

@ -430,14 +430,10 @@ exports.CurryNode: class CurryNode extends CallNode
(new ArrayNode(@args)).compile o
compile_node: (o) ->
CurryNode.assign_bind()
ref: new ValueNode literal '__bind'
utility 'slice'
ref: new ValueNode literal utility 'bind'
(new CallNode(ref, [@meth, @context, literal(@arguments(o))])).compile o
@assign_bind: ->
Scope.root.assign '__slice', UTILITIES['slice']
Scope.root.assign '__bind', UTILITIES['bind']
#### ExtendsNode
@ -452,7 +448,7 @@ exports.ExtendsNode: class ExtendsNode extends BaseNode
# Hooks one constructor into another's prototype chain.
compile_node: (o) ->
ref: new ValueNode literal(Scope.root.assign('__extend', UTILITIES['extend']))
ref: new ValueNode literal utility 'extend'
(new CallNode ref, [@child, @parent]).compile o
#### AccessorNode
@ -553,7 +549,7 @@ exports.SliceNode: class SliceNode extends BaseNode
to: if @range.to? then @range.to else literal('null')
exclusive: if @range.exclusive then 'true' else 'false'
v: o.scope.free_variable()
rng: new CallNode new ValueNode(literal(Scope.root.assign('__range', UTILITIES['range']))), [literal(array), from, to, literal(exclusive)]
rng: new CallNode new ValueNode(literal(utility('range'))), [literal(array), from, to, literal(exclusive)]
args: literal "[($v = ${rng.compile(o)})[0], $v[1] - $v[0]].concat(${replace.compile(o)})"
call: new CallNode new ValueNode(literal(array), [literal('.splice.apply')]), [literal(array), args]
call.compile(o)
@ -563,7 +559,7 @@ exports.SliceNode: class SliceNode extends BaseNode
from: if @range.from? then @range.from else literal('null')
to: if @range.to? then @range.to else literal('null')
exclusive: if @range.exclusive then 'true' else 'false'
rng: new CallNode new ValueNode(literal(Scope.root.assign('__range', UTILITIES['range']))), [literal(array), from, to, literal(exclusive)]
rng: new CallNode new ValueNode(literal(utility('range'))), [literal(array), from, to, literal(exclusive)]
call: new CallNode new ValueNode(literal(array), [literal('.slice.apply')]), [literal(array), rng]
call.compile(o)
@ -807,8 +803,8 @@ exports.CodeNode: class CodeNode extends BaseNode
func: "function${ if @bound then '' else name_part }(${ params.join(', ') }) {$code${@idt(if @bound then 1 else 0)}}"
func: "($func)" if top and not @bound
return func unless @bound
CurryNode.assign_bind()
ref: new ValueNode literal('__bind')
utility 'slice'
ref: new ValueNode literal utility 'bind'
(new CallNode ref, [literal(func), literal('this')]).compile o
top_sensitive: ->
@ -852,14 +848,13 @@ exports.SplatNode: class SplatNode extends BaseNode
for trailing in @trailings
o.scope.assign(trailing.compile(o), "arguments[arguments.length - $@trailings.length + $i]")
i: + 1
"$name = ${Scope.root.assign('__slice', UTILITIES['slice'])}.call(arguments, $@index, arguments.length - ${@trailings.length})"
"$name = ${utility('slice')}.call(arguments, $@index, arguments.length - ${@trailings.length})"
# A compiling a splat as a destructuring assignment means slicing arguments
# from the right-hand-side's corresponding array.
compile_value: (o, name, index, trailings) ->
Scope.root.assign '__slice', UTILITIES['slice']
trail: if trailings then ", ${name}.length - $trailings" else ''
"__slice.call($name, $index$trail)"
"${utility 'slice'}.call($name, $index$trail)"
# Utility function that converts arbitrary number of elements, mixed with
# splats, to a proper array
@ -1178,7 +1173,7 @@ exports.ForNode: class ForNode extends BaseNode
if @filter
body: Expressions.wrap([new IfNode(@filter, body)])
if @object
for_part: "$ivar in $svar) { if (${Scope.root.assign('__hasProp', UTILITIES['hasProp'])}.call($svar, $ivar)"
for_part: "$ivar in $svar) { if (${utility('hasProp')}.call($svar, $ivar)"
body: body.compile(merge(o, {indent: body_dent, top: true}))
vars: if range then name else "$name, $ivar"
close: if @object then '}}\n' else '}\n'
@ -1385,3 +1380,9 @@ IDENTIFIER: /^[a-zA-Z\$_](\w|\$)*$/
# Handy helper for a generating LiteralNode.
literal: (name) ->
new LiteralNode(name)
# Helper for ensuring that utility functions are assigned at the top level.
utility: (name) ->
ref: "__$name"
Scope.root.assign ref, UTILITIES[name]
ref

View file

@ -62,7 +62,6 @@ exports.Scope: class Scope
# (or at the top-level scope, if requested).
assign: (name, value) ->
@variables[name]: {value: value, assigned: true}
name
# Does this scope reference any variables that need to be declared in the
# given function body?