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(){ (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 __extend = function(child, parent) {
var ctor = function(){ }; var ctor = function(){ };
ctor.prototype = parent.prototype; ctor.prototype = parent.prototype;
@ -596,14 +596,10 @@
}; };
CurryNode.prototype.compile_node = function compile_node(o) { CurryNode.prototype.compile_node = function compile_node(o) {
var ref; var ref;
CurryNode.assign_bind(); utility('slice');
ref = new ValueNode(literal('__bind')); ref = new ValueNode(literal(utility('bind')));
return (new CallNode(ref, [this.meth, this.context, literal(this.arguments(o))])).compile(o); 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; return CurryNode;
}).call(this); }).call(this);
//### ExtendsNode //### ExtendsNode
@ -620,7 +616,7 @@
// Hooks one constructor into another's prototype chain. // Hooks one constructor into another's prototype chain.
ExtendsNode.prototype.compile_node = function compile_node(o) { ExtendsNode.prototype.compile_node = function compile_node(o) {
var ref; 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 (new CallNode(ref, [this.child, this.parent])).compile(o);
}; };
return ExtendsNode; return ExtendsNode;
@ -745,7 +741,7 @@
to = (typeof (_b = this.range.to) !== "undefined" && _b !== null) ? this.range.to : literal('null'); to = (typeof (_b = this.range.to) !== "undefined" && _b !== null) ? this.range.to : literal('null');
exclusive = this.range.exclusive ? 'true' : 'false'; exclusive = this.range.exclusive ? 'true' : 'false';
v = o.scope.free_variable(); 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)) + ")"); 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 = new CallNode(new ValueNode(literal(array), [literal('.splice.apply')]), [literal(array), args]);
return call.compile(o); return call.compile(o);
@ -756,7 +752,7 @@
from = (typeof (_a = this.range.from) !== "undefined" && _a !== null) ? this.range.from : literal('null'); 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'); to = (typeof (_b = this.range.to) !== "undefined" && _b !== null) ? this.range.to : literal('null');
exclusive = this.range.exclusive ? 'true' : 'false'; 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]); call = new CallNode(new ValueNode(literal(array), [literal('.slice.apply')]), [literal(array), rng]);
return call.compile(o); return call.compile(o);
}; };
@ -1088,8 +1084,8 @@
if (!(this.bound)) { if (!(this.bound)) {
return func; return func;
} }
CurryNode.assign_bind(); utility('slice');
ref = new ValueNode(literal('__bind')); ref = new ValueNode(literal(utility('bind')));
return (new CallNode(ref, [literal(func), literal('this')])).compile(o); return (new CallNode(ref, [literal(func), literal('this')])).compile(o);
}; };
CodeNode.prototype.top_sensitive = function top_sensitive() { CodeNode.prototype.top_sensitive = function top_sensitive() {
@ -1160,15 +1156,14 @@
o.scope.assign(trailing.compile(o), "arguments[arguments.length - " + this.trailings.length + " + " + i + "]"); o.scope.assign(trailing.compile(o), "arguments[arguments.length - " + this.trailings.length + " + " + i + "]");
i += 1; 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 // A compiling a splat as a destructuring assignment means slicing arguments
// from the right-hand-side's corresponding array. // from the right-hand-side's corresponding array.
SplatNode.prototype.compile_value = function compile_value(o, name, index, trailings) { SplatNode.prototype.compile_value = function compile_value(o, name, index, trailings) {
var trail; var trail;
Scope.root.assign('__slice', UTILITIES['slice']);
trail = trailings ? ", " + (name) + ".length - " + trailings : ''; 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 // Utility function that converts arbitrary number of elements, mixed with
// splats, to a proper array // splats, to a proper array
@ -1579,7 +1574,7 @@
body = PushNode.wrap(rvar, body); body = PushNode.wrap(rvar, body);
} }
this.filter ? (body = Expressions.wrap([new IfNode(this.filter, body)])) : null; 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, { body = body.compile(merge(o, {
indent: body_dent, indent: body_dent,
top: true top: true
@ -1796,4 +1791,11 @@
literal = function literal(name) { literal = function literal(name) {
return new LiteralNode(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, value: value,
assigned: true assigned: true
}; };
return name; return this.variables[name];
}; };
// Does this scope reference any variables that need to be declared in the // Does this scope reference any variables that need to be declared in the
// given function body? // given function body?

View file

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