mirror of
https://github.com/jashkenas/coffeescript.git
synced 2022-11-09 12:23:24 -05:00
nodes: re{name,formatt}ed things
This commit is contained in:
parent
69b901a5b6
commit
f90f1ef8e0
2 changed files with 127 additions and 124 deletions
99
lib/nodes.js
99
lib/nodes.js
|
@ -1,7 +1,7 @@
|
|||
(function() {
|
||||
var AccessorNode, ArrayNode, AssignNode, BaseNode, CallNode, ClassNode, ClosureNode, CodeNode, CommentNode, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IS_STRING, IfNode, InNode, IndexNode, LiteralNode, NO, NUMBER, ObjectNode, OpNode, ParamNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, SIMPLENUM, Scope, SliceNode, SplatNode, SwitchNode, TAB, THIS, TRAILING_WHITESPACE, ThrowNode, TryNode, UTILITIES, ValueNode, WhileNode, YES, _ref, compact, del, ends, flatten, include, indexOf, last, literal, merge, starts, utility;
|
||||
var __extends = function(child, parent) {
|
||||
var ctor = function(){};
|
||||
var ctor = function() {};
|
||||
ctor.prototype = parent.prototype;
|
||||
child.prototype = new ctor();
|
||||
child.prototype.constructor = child;
|
||||
|
@ -89,13 +89,13 @@
|
|||
return contains;
|
||||
};
|
||||
BaseNode.prototype.containsType = function(type) {
|
||||
return this instanceof type || this.contains(function(n) {
|
||||
return n instanceof type;
|
||||
return this instanceof type || this.contains(function(node) {
|
||||
return node instanceof type;
|
||||
});
|
||||
};
|
||||
BaseNode.prototype.containsPureStatement = function() {
|
||||
return this.isPureStatement() || this.contains(function(n) {
|
||||
return (typeof n.isPureStatement !== "function" ? undefined : n.isPureStatement());
|
||||
return this.isPureStatement() || this.contains(function(node) {
|
||||
return node.isPureStatement();
|
||||
});
|
||||
};
|
||||
BaseNode.prototype.traverse = function(block) {
|
||||
|
@ -222,7 +222,7 @@
|
|||
var code;
|
||||
code = this.compileNode(o);
|
||||
if (o.scope.hasAssignments(this)) {
|
||||
code = ("" + (this.tab) + "var " + (o.scope.compiledAssignments()) + ";\n" + code);
|
||||
code = ("" + (this.tab) + "var " + (o.scope.compiledAssignments().replace(/\n/g, '$&' + this.tab)) + ";\n" + code);
|
||||
}
|
||||
if (!o.globals && o.scope.hasDeclarations(this)) {
|
||||
code = ("" + (this.tab) + "var " + (o.scope.compiledDeclarations()) + ";\n" + code);
|
||||
|
@ -567,7 +567,7 @@
|
|||
return "" + (this.superReference(o)) + ".call(this" + (args.length ? ', ' : '') + args + ")";
|
||||
};
|
||||
CallNode.prototype.compileSplat = function(o) {
|
||||
var _i, _len, _ref2, a, arg, argvar, b, base, c, call, fun, idt, name, ref, splatargs;
|
||||
var _i, _len, _ref2, arg, argvar, base, call, ctor, fun, idt, name, ref, result, splatargs;
|
||||
splatargs = this.compileSplatArguments(o);
|
||||
if (this.isSuper) {
|
||||
return ("" + (this.superReference(o)) + ".apply(this, " + splatargs + ")");
|
||||
|
@ -588,8 +588,8 @@
|
|||
return ("" + fun + ".apply(" + ref + ", " + splatargs + ")");
|
||||
}
|
||||
call = 'call(this)';
|
||||
argvar = function(n) {
|
||||
return n instanceof LiteralNode && n.value === 'arguments';
|
||||
argvar = function(node) {
|
||||
return node instanceof LiteralNode && node.value === 'arguments';
|
||||
};
|
||||
_ref2 = this.args;
|
||||
for (_i = 0, _len = _ref2.length; _i < _len; _i++) {
|
||||
|
@ -599,10 +599,10 @@
|
|||
break;
|
||||
}
|
||||
}
|
||||
a = o.scope.freeVariable('ctor');
|
||||
b = o.scope.freeVariable('ref');
|
||||
c = o.scope.freeVariable('result');
|
||||
return "(function() {\n" + (idt = this.idt(1)) + "var ctor = function() {};\n" + idt + (utility('extends')) + "(ctor, " + a + " = " + (this.variable.compile(o)) + ");\n" + idt + "return typeof (" + c + " = " + a + ".apply(" + b + " = new ctor, " + splatargs + ")) === \"object\" ? " + c + " : " + b + ";\n" + (this.tab) + "})." + call;
|
||||
ctor = o.scope.freeVariable('ctor');
|
||||
ref = o.scope.freeVariable('ref');
|
||||
result = o.scope.freeVariable('result');
|
||||
return "(function() {\n" + (idt = this.idt(1)) + "var ctor = function() {};\n" + idt + (utility('extends')) + "(ctor, " + ctor + " = " + (this.variable.compile(o)) + ");\n" + idt + "return typeof (" + result + " = " + ctor + ".apply(" + ref + " = new ctor, " + splatargs + ")) === \"object\" ? " + result + " : " + ref + ";\n" + (this.tab) + "})." + call;
|
||||
};
|
||||
return CallNode;
|
||||
})();
|
||||
|
@ -873,11 +873,11 @@
|
|||
})();
|
||||
exports.ClassNode = (function() {
|
||||
ClassNode = (function() {
|
||||
return function ClassNode(_arg, _arg2, _arg3) {
|
||||
this.properties = _arg3;
|
||||
this.parent = _arg2;
|
||||
this.variable = _arg;
|
||||
return function ClassNode(variable, _arg, _arg2) {
|
||||
this.properties = _arg2;
|
||||
this.parent = _arg;
|
||||
ClassNode.__super__.constructor.call(this);
|
||||
this.variable = variable === '__temp__' ? literal(variable) : variable;
|
||||
this.properties || (this.properties = []);
|
||||
this.returns = false;
|
||||
return this;
|
||||
|
@ -891,15 +891,16 @@
|
|||
return this;
|
||||
};
|
||||
ClassNode.prototype.compileNode = function(o) {
|
||||
var _i, _len, _ref2, _ref3, access, applied, className, constScope, construct, constructor, extension, func, me, pname, prop, props, pvar, returns, val;
|
||||
if (this.variable === '__temp__') {
|
||||
this.variable = literal(o.scope.freeVariable('ctor'));
|
||||
var _i, _len, _ref2, _ref3, access, applied, className, constScope, construct, constructor, extension, func, me, pname, prop, props, pvar, returns, val, variable;
|
||||
variable = this.variable;
|
||||
if (variable.value === '__temp__') {
|
||||
variable = literal(o.scope.freeVariable('ctor'));
|
||||
}
|
||||
extension = this.parent && new ExtendsNode(this.variable, this.parent);
|
||||
extension = this.parent && new ExtendsNode(variable, this.parent);
|
||||
props = new Expressions;
|
||||
o.top = true;
|
||||
me = null;
|
||||
className = this.variable.compile(o);
|
||||
className = variable.compile(o);
|
||||
constScope = null;
|
||||
if (this.parent) {
|
||||
applied = new ValueNode(this.parent, [new AccessorNode(literal('apply'))]);
|
||||
|
@ -917,8 +918,8 @@
|
|||
}
|
||||
func.name = className;
|
||||
func.body.push(new ReturnNode(literal('this')));
|
||||
this.variable = new ValueNode(this.variable);
|
||||
this.variable.namespaced = include(func.name, '.');
|
||||
variable = new ValueNode(variable);
|
||||
variable.namespaced = include(func.name, '.');
|
||||
constructor = func;
|
||||
continue;
|
||||
}
|
||||
|
@ -938,7 +939,7 @@
|
|||
}
|
||||
if (pvar) {
|
||||
access = prop.context === 'this' ? pvar.base.properties[0] : new AccessorNode(pvar, 'prototype');
|
||||
val = new ValueNode(this.variable, [access]);
|
||||
val = new ValueNode(variable, [access]);
|
||||
prop = new AssignNode(val, func);
|
||||
}
|
||||
props.push(prop);
|
||||
|
@ -947,12 +948,12 @@
|
|||
if (me) {
|
||||
constructor.body.unshift(literal("" + me + " = this"));
|
||||
}
|
||||
construct = this.idt() + (new AssignNode(this.variable, constructor)).compile(merge(o, {
|
||||
construct = this.idt() + new AssignNode(variable, constructor).compile(merge(o, {
|
||||
sharedScope: constScope
|
||||
})) + ';';
|
||||
props = !props.empty() ? '\n' + props.compile(o) : '';
|
||||
extension = extension ? '\n' + this.idt() + extension.compile(o) + ';' : '';
|
||||
returns = this.returns ? '\n' + new ReturnNode(this.variable).compile(o) : '';
|
||||
returns = this.returns ? '\n' + new ReturnNode(variable).compile(o) : '';
|
||||
return construct + extension + props + returns;
|
||||
};
|
||||
return ClassNode;
|
||||
|
@ -1640,8 +1641,8 @@
|
|||
topLevel = del(o, 'top') && !this.returns;
|
||||
range = this.source instanceof ValueNode && this.source.base instanceof RangeNode && !this.source.properties.length;
|
||||
source = range ? this.source.base : this.source;
|
||||
codeInBody = this.body.contains(function(n) {
|
||||
return n instanceof CodeNode;
|
||||
codeInBody = this.body.contains(function(node) {
|
||||
return node instanceof CodeNode;
|
||||
});
|
||||
scope = o.scope;
|
||||
name = this.name && this.name.compile(o);
|
||||
|
@ -1849,7 +1850,7 @@
|
|||
})().join(' || ');
|
||||
};
|
||||
IfNode.prototype.compileNode = function(o) {
|
||||
return this.isStatement(o) ? this.compileStatement(o) : this.compileTernary(o);
|
||||
return this.isStatement(o) ? this.compileStatement(o) : this.compileExpression(o);
|
||||
};
|
||||
IfNode.prototype.makeReturn = function() {
|
||||
if (this.isStatement()) {
|
||||
|
@ -1883,7 +1884,7 @@
|
|||
})) : (" else {\n" + (this.elseBody.compile(o)) + "\n" + (this.tab) + "}");
|
||||
return "" + ifPart + elsePart;
|
||||
};
|
||||
IfNode.prototype.compileTernary = function(o) {
|
||||
IfNode.prototype.compileExpression = function(o) {
|
||||
var code, elsePart, ifPart;
|
||||
this.bodyNode().tags.operation = (this.condition.tags.operation = true);
|
||||
if (this.elseBody) {
|
||||
|
@ -1896,31 +1897,23 @@
|
|||
};
|
||||
return IfNode;
|
||||
})();
|
||||
PushNode = (exports.PushNode = {
|
||||
wrap: function(array, expressions) {
|
||||
var expr;
|
||||
expr = expressions.unwrap();
|
||||
if (expr.isPureStatement() || expr.containsPureStatement()) {
|
||||
PushNode = {
|
||||
wrap: function(name, expressions) {
|
||||
if (expressions.empty() || expressions.containsPureStatement()) {
|
||||
return expressions;
|
||||
}
|
||||
return Expressions.wrap([new CallNode(new ValueNode(literal(array), [new AccessorNode(literal('push'))]), [expr])]);
|
||||
return Expressions.wrap([new CallNode(new ValueNode(literal(name), [new AccessorNode(literal('push'))]), [expressions.unwrap()])]);
|
||||
}
|
||||
});
|
||||
ClosureNode = (exports.ClosureNode = {
|
||||
};
|
||||
ClosureNode = {
|
||||
wrap: function(expressions, statement) {
|
||||
var args, call, func, mentionsArgs, mentionsThis, meth;
|
||||
var args, call, func, mentionsArgs, meth;
|
||||
if (expressions.containsPureStatement()) {
|
||||
return expressions;
|
||||
}
|
||||
func = new ParentheticalNode(new CodeNode([], Expressions.wrap([expressions])));
|
||||
args = [];
|
||||
mentionsArgs = expressions.contains(function(n) {
|
||||
return n instanceof LiteralNode && (n.value === 'arguments');
|
||||
});
|
||||
mentionsThis = expressions.contains(function(n) {
|
||||
return (n instanceof LiteralNode && (n.value === 'this')) || (n instanceof CodeNode && n.bound);
|
||||
});
|
||||
if (mentionsArgs || mentionsThis) {
|
||||
if ((mentionsArgs = expressions.contains(this.literalArgs)) || (expressions.contains(this.literalThis))) {
|
||||
meth = literal(mentionsArgs ? 'apply' : 'call');
|
||||
args = [literal('this')];
|
||||
if (mentionsArgs) {
|
||||
|
@ -1930,11 +1923,17 @@
|
|||
}
|
||||
call = new CallNode(func, args);
|
||||
return statement ? Expressions.wrap([call]) : call;
|
||||
},
|
||||
literalArgs: function(node) {
|
||||
return node instanceof LiteralNode && node.value === 'arguments';
|
||||
},
|
||||
literalThis: function(node) {
|
||||
return node instanceof LiteralNode && node.value === 'this' || node instanceof CodeNode && node.bound;
|
||||
}
|
||||
});
|
||||
};
|
||||
UTILITIES = {
|
||||
"extends": "function(child, parent) {\n var ctor = function(){};\n ctor.prototype = parent.prototype;\n child.prototype = new ctor();\n child.prototype.constructor = child;\n if (typeof parent.extended === \"function\") parent.extended(child);\n child.__super__ = parent.prototype;\n }",
|
||||
bind: "function(func, context) {\n return function(){ return func.apply(context, arguments); };\n }",
|
||||
"extends": 'function(child, parent) {\n var ctor = function() {};\n ctor.prototype = parent.prototype;\n child.prototype = new ctor();\n child.prototype.constructor = child;\n if (typeof parent.extended === "function") parent.extended(child);\n child.__super__ = parent.prototype;\n}',
|
||||
bind: 'function(func, context) {\n return function() { return func.apply(context, arguments); };\n}',
|
||||
hasProp: 'Object.prototype.hasOwnProperty',
|
||||
slice: 'Array.prototype.slice'
|
||||
};
|
||||
|
|
152
src/nodes.coffee
152
src/nodes.coffee
|
@ -98,12 +98,12 @@ exports.BaseNode = class BaseNode
|
|||
|
||||
# Is this node of a certain type, or does it contain the type?
|
||||
containsType: (type) ->
|
||||
this instanceof type or @contains (n) -> n instanceof type
|
||||
this instanceof type or @contains (node) -> node instanceof type
|
||||
|
||||
# Convenience for the most common use of contains. Does the node contain
|
||||
# a pure statement?
|
||||
containsPureStatement: ->
|
||||
@isPureStatement() or @contains (n) -> n.isPureStatement?()
|
||||
@isPureStatement() or @contains (node) -> node.isPureStatement()
|
||||
|
||||
# Perform an in-order traversal of the AST. Crosses scope boundaries.
|
||||
traverse: (block) -> @traverseChildren true, block
|
||||
|
@ -209,8 +209,14 @@ exports.Expressions = class Expressions extends BaseNode
|
|||
# declarations of all inner variables pushed up to the top.
|
||||
compileWithDeclarations: (o) ->
|
||||
code = @compileNode(o)
|
||||
code = "#{@tab}var #{o.scope.compiledAssignments()};\n#{code}" if o.scope.hasAssignments(this)
|
||||
code = "#{@tab}var #{o.scope.compiledDeclarations()};\n#{code}" if not o.globals and o.scope.hasDeclarations(this)
|
||||
code = """
|
||||
#{@tab}var #{ o.scope.compiledAssignments().replace /\n/g, '$&' + @tab };
|
||||
#{code}
|
||||
""" if o.scope.hasAssignments this
|
||||
code = """
|
||||
#{@tab}var #{o.scope.compiledDeclarations()};
|
||||
#{code}
|
||||
""" if not o.globals and o.scope.hasDeclarations this
|
||||
code
|
||||
|
||||
# Compiles a single expression within the expressions body. If we need to
|
||||
|
@ -522,18 +528,18 @@ exports.CallNode = class CallNode extends BaseNode
|
|||
fun += name.compile o if name
|
||||
return "#{fun}.apply(#{ref}, #{splatargs})"
|
||||
call = 'call(this)'
|
||||
argvar = (n) -> n instanceof LiteralNode and n.value is 'arguments'
|
||||
argvar = (node) -> node instanceof LiteralNode and node.value is 'arguments'
|
||||
for arg in @args when arg.contains argvar
|
||||
call = 'apply(this, arguments)'
|
||||
break
|
||||
a = o.scope.freeVariable 'ctor'
|
||||
b = o.scope.freeVariable 'ref'
|
||||
c = o.scope.freeVariable 'result'
|
||||
ctor = o.scope.freeVariable 'ctor'
|
||||
ref = o.scope.freeVariable 'ref'
|
||||
result = o.scope.freeVariable 'result'
|
||||
"""
|
||||
(function() {
|
||||
#{idt = @idt 1}var ctor = function() {};
|
||||
#{idt}#{utility 'extends'}(ctor, #{a} = #{ @variable.compile o });
|
||||
#{idt}return typeof (#{c} = #{a}.apply(#{b} = new ctor, #{splatargs})) === "object" ? #{c} : #{b};
|
||||
#{idt}#{utility 'extends'}(ctor, #{ctor} = #{ @variable.compile o });
|
||||
#{idt}return typeof (#{result} = #{ctor}.apply(#{ref} = new ctor, #{splatargs})) === "object" ? #{result} : #{ref};
|
||||
#{@tab}}).#{call}
|
||||
"""
|
||||
|
||||
|
@ -756,8 +762,9 @@ exports.ClassNode = class ClassNode extends BaseNode
|
|||
|
||||
# Initialize a **ClassNode** with its name, an optional superclass, and a
|
||||
# list of prototype property assignments.
|
||||
constructor: (@variable, @parent, @properties) ->
|
||||
constructor: (variable, @parent, @properties) ->
|
||||
super()
|
||||
@variable = if variable is '__temp__' then literal variable else variable
|
||||
@properties or= []
|
||||
@returns = false
|
||||
|
||||
|
@ -769,12 +776,13 @@ exports.ClassNode = class ClassNode extends BaseNode
|
|||
# equivalent syntax tree and compile that, in pieces. You can see the
|
||||
# constructor, property assignments, and inheritance getting built out below.
|
||||
compileNode: (o) ->
|
||||
@variable = literal o.scope.freeVariable 'ctor' if @variable is '__temp__'
|
||||
extension = @parent and new ExtendsNode(@variable, @parent)
|
||||
{variable} = this
|
||||
variable = literal o.scope.freeVariable 'ctor' if variable.value is '__temp__'
|
||||
extension = @parent and new ExtendsNode variable, @parent
|
||||
props = new Expressions
|
||||
o.top = true
|
||||
me = null
|
||||
className = @variable.compile o
|
||||
className = variable.compile o
|
||||
constScope = null
|
||||
|
||||
if @parent
|
||||
|
@ -791,8 +799,8 @@ exports.ClassNode = class ClassNode extends BaseNode
|
|||
throw new Error "cannot define a constructor as a bound function." if func.bound
|
||||
func.name = className
|
||||
func.body.push new ReturnNode literal 'this'
|
||||
@variable = new ValueNode @variable
|
||||
@variable.namespaced = include func.name, '.'
|
||||
variable = new ValueNode variable
|
||||
variable.namespaced = include func.name, '.'
|
||||
constructor = func
|
||||
continue
|
||||
if func instanceof CodeNode and func.bound
|
||||
|
@ -807,16 +815,16 @@ exports.ClassNode = class ClassNode extends BaseNode
|
|||
constructor.body.unshift literal "this.#{pname} = function(){ return #{className}.prototype.#{pname}.apply(#{me}, arguments); }"
|
||||
if pvar
|
||||
access = if prop.context is 'this' then pvar.base.properties[0] else new AccessorNode(pvar, 'prototype')
|
||||
val = new ValueNode(@variable, [access])
|
||||
val = new ValueNode variable, [access]
|
||||
prop = new AssignNode(val, func)
|
||||
props.push prop
|
||||
|
||||
constructor.className = className.match /[\w\d\$_]+$/
|
||||
constructor.body.unshift literal "#{me} = this" if me
|
||||
construct = @idt() + (new AssignNode(@variable, constructor)).compile(merge o, {sharedScope: constScope}) + ';'
|
||||
props = if !props.empty() then '\n' + props.compile(o) else ''
|
||||
extension = if extension then '\n' + @idt() + extension.compile(o) + ';' else ''
|
||||
returns = if @returns then '\n' + new ReturnNode(@variable).compile(o) else ''
|
||||
construct = @idt() + new AssignNode(variable, constructor).compile(merge o, sharedScope: constScope) + ';'
|
||||
props = if !props.empty() then '\n' + props.compile(o) else ''
|
||||
extension = if extension then '\n' + @idt() + extension.compile(o) + ';' else ''
|
||||
returns = if @returns then '\n' + new ReturnNode(variable).compile(o) else ''
|
||||
construct + extension + props + returns
|
||||
|
||||
#### AssignNode
|
||||
|
@ -1401,7 +1409,7 @@ exports.ForNode = class ForNode extends BaseNode
|
|||
topLevel = del(o, 'top') and not @returns
|
||||
range = @source instanceof ValueNode and @source.base instanceof RangeNode and not @source.properties.length
|
||||
source = if range then @source.base else @source
|
||||
codeInBody = @body.contains (n) -> n instanceof CodeNode
|
||||
codeInBody = @body.contains (node) -> node instanceof CodeNode
|
||||
scope = o.scope
|
||||
name = @name and @name.compile o
|
||||
index = @index and @index.compile o
|
||||
|
@ -1498,7 +1506,7 @@ exports.SwitchNode = class SwitchNode extends BaseNode
|
|||
# *If/else* statements. Acts as an expression by pushing down requested returns
|
||||
# to the last line of each clause.
|
||||
#
|
||||
# Single-expression **IfNodes** are compiled into ternary operators if possible,
|
||||
# Single-expression **IfNodes** are compiled into conditional operators if possible,
|
||||
# because ternaries are already proper expressions, and don't need conversion.
|
||||
exports.IfNode = class IfNode extends BaseNode
|
||||
|
||||
|
@ -1529,7 +1537,7 @@ exports.IfNode = class IfNode extends BaseNode
|
|||
this
|
||||
|
||||
# The **IfNode** only compiles into a statement if either of its bodies needs
|
||||
# to be a statement. Otherwise a ternary is safe.
|
||||
# to be a statement. Otherwise a conditional operator is safe.
|
||||
isStatement: (o) ->
|
||||
@statement or= !!((o and o.top) or @bodyNode().isStatement(o) or (@elseBody and @elseBodyNode().isStatement(o)))
|
||||
|
||||
|
@ -1539,7 +1547,7 @@ exports.IfNode = class IfNode extends BaseNode
|
|||
(cond.compile(o) for cond in conditions).join(' || ')
|
||||
|
||||
compileNode: (o) ->
|
||||
if @isStatement(o) then @compileStatement(o) else @compileTernary(o)
|
||||
if @isStatement o then @compileStatement o else @compileExpression o
|
||||
|
||||
makeReturn: ->
|
||||
if @isStatement()
|
||||
|
@ -1571,8 +1579,8 @@ exports.IfNode = class IfNode extends BaseNode
|
|||
" else {\n#{ @elseBody.compile(o) }\n#{@tab}}"
|
||||
"#{ifPart}#{elsePart}"
|
||||
|
||||
# Compile the IfNode as a ternary operator.
|
||||
compileTernary: (o) ->
|
||||
# Compile the IfNode as a conditional operator.
|
||||
compileExpression: (o) ->
|
||||
@bodyNode().tags.operation = @condition.tags.operation = yes
|
||||
@elseBodyNode().tags.operation = yes if @elseBody
|
||||
ifPart = @condition.compile(o) + ' ? ' + @bodyNode().compile(o)
|
||||
|
@ -1582,79 +1590,76 @@ exports.IfNode = class IfNode extends BaseNode
|
|||
|
||||
# Faux-Nodes
|
||||
# ----------
|
||||
# Faux-nodes are never created by the grammar, but are used during code
|
||||
# generation to generate other combinations of nodes.
|
||||
|
||||
#### PushNode
|
||||
|
||||
# Faux-nodes are never created by the grammar, but are used during code
|
||||
# generation to generate other combinations of nodes. The **PushNode** creates
|
||||
# the tree for `array.push(value)`, which is helpful for recording the result
|
||||
# arrays from comprehensions.
|
||||
PushNode = exports.PushNode =
|
||||
wrap: (array, expressions) ->
|
||||
expr = expressions.unwrap()
|
||||
return expressions if expr.isPureStatement() or expr.containsPureStatement()
|
||||
Expressions.wrap([new CallNode(
|
||||
new ValueNode(literal(array), [new AccessorNode(literal('push'))]), [expr]
|
||||
)])
|
||||
# The **PushNode** creates the tree for `array.push(value)`,
|
||||
# which is helpful for recording the result arrays from comprehensions.
|
||||
PushNode =
|
||||
wrap: (name, expressions) ->
|
||||
return expressions if expressions.empty() or expressions.containsPureStatement()
|
||||
Expressions.wrap [new CallNode(
|
||||
new ValueNode literal(name), [new AccessorNode literal 'push']
|
||||
[expressions.unwrap()]
|
||||
)]
|
||||
|
||||
#### ClosureNode
|
||||
|
||||
# A faux-node used to wrap an expressions body in a closure.
|
||||
ClosureNode = exports.ClosureNode =
|
||||
ClosureNode =
|
||||
|
||||
# Wrap the expressions body, unless it contains a pure statement,
|
||||
# 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.containsPureStatement()
|
||||
func = new ParentheticalNode(new CodeNode([], Expressions.wrap([expressions])))
|
||||
func = new ParentheticalNode new CodeNode [], Expressions.wrap [expressions]
|
||||
args = []
|
||||
mentionsArgs = expressions.contains (n) ->
|
||||
n instanceof LiteralNode and (n.value is 'arguments')
|
||||
mentionsThis = expressions.contains (n) ->
|
||||
(n instanceof LiteralNode and (n.value is 'this')) or
|
||||
(n instanceof CodeNode and n.bound)
|
||||
if mentionsArgs or mentionsThis
|
||||
meth = literal(if mentionsArgs then 'apply' else 'call')
|
||||
args = [literal('this')]
|
||||
if (mentionsArgs = expressions.contains @literalArgs) or
|
||||
( expressions.contains @literalThis)
|
||||
meth = literal if mentionsArgs then 'apply' else 'call'
|
||||
args = [literal 'this']
|
||||
args.push literal 'arguments' if mentionsArgs
|
||||
func = new ValueNode func, [new AccessorNode(meth)]
|
||||
call = new CallNode(func, args)
|
||||
if statement then Expressions.wrap([call]) else call
|
||||
func = new ValueNode func, [new AccessorNode meth]
|
||||
call = new CallNode func, args
|
||||
if statement then Expressions.wrap [call] else call
|
||||
|
||||
# Utility Functions
|
||||
# -----------------
|
||||
literalArgs: (node) -> node instanceof LiteralNode and node.value is 'arguments'
|
||||
literalThis: (node) -> node instanceof LiteralNode and node.value is 'this' or
|
||||
node instanceof CodeNode and node.bound
|
||||
|
||||
# Constants
|
||||
# ---------
|
||||
|
||||
UTILITIES =
|
||||
|
||||
# Correctly set up a prototype chain for inheritance, including a reference
|
||||
# to the superclass for `super()` calls. See:
|
||||
# [goog.inherits](http://closure-library.googlecode.com/svn/docs/closureGoogBase.js.source.html#line1206).
|
||||
extends: """
|
||||
function(child, parent) {
|
||||
var ctor = function(){};
|
||||
ctor.prototype = parent.prototype;
|
||||
child.prototype = new ctor();
|
||||
child.prototype.constructor = child;
|
||||
if (typeof parent.extended === "function") parent.extended(child);
|
||||
child.__super__ = parent.prototype;
|
||||
}
|
||||
"""
|
||||
extends: '''
|
||||
function(child, parent) {
|
||||
var ctor = function() {};
|
||||
ctor.prototype = parent.prototype;
|
||||
child.prototype = new ctor();
|
||||
child.prototype.constructor = child;
|
||||
if (typeof parent.extended === "function") parent.extended(child);
|
||||
child.__super__ = parent.prototype;
|
||||
}
|
||||
'''
|
||||
|
||||
# Create a function bound to the current value of "this".
|
||||
bind: """
|
||||
function(func, context) {
|
||||
return function(){ return func.apply(context, arguments); };
|
||||
}
|
||||
"""
|
||||
bind: '''
|
||||
function(func, context) {
|
||||
return function() { return func.apply(context, arguments); };
|
||||
}
|
||||
'''
|
||||
|
||||
# Shortcuts to speed up the lookup time for native functions.
|
||||
hasProp: 'Object.prototype.hasOwnProperty'
|
||||
slice: 'Array.prototype.slice'
|
||||
|
||||
# Constants
|
||||
# ---------
|
||||
|
||||
# Tabs are two spaces for pretty printing.
|
||||
TAB = ' '
|
||||
|
||||
|
@ -1672,9 +1677,8 @@ IS_STRING = /^['"]/
|
|||
# Utility Functions
|
||||
# -----------------
|
||||
|
||||
# Handy helper for a generating LiteralNode.
|
||||
literal = (name) ->
|
||||
new LiteralNode(name)
|
||||
# Handy helper for generating a LiteralNode.
|
||||
literal = (name) -> new LiteralNode name
|
||||
|
||||
# Helper for ensuring that utility functions are assigned at the top level.
|
||||
utility = (name) ->
|
||||
|
|
Loading…
Reference in a new issue