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