mirror of
https://github.com/jashkenas/coffeescript.git
synced 2026-02-18 19:34:27 -05:00
determine @children dynamically based on attribute names, instead of manual bookkeeping
This commit is contained in:
222
lib/nodes.js
222
lib/nodes.js
@@ -1,15 +1,15 @@
|
|||||||
(function(){
|
(function(){
|
||||||
var AccessorNode, ArrayNode, AssignNode, BaseNode, CallNode, ClassNode, ClosureNode, CodeNode, CommentNode, CurryNode, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IS_STRING, IfNode, IndexNode, LiteralNode, ObjectNode, OpNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, Scope, SliceNode, SplatNode, TAB, TRAILING_WHITESPACE, ThrowNode, TryNode, UTILITIES, ValueNode, WhileNode, _a, compact, del, flatten, helpers, literal, merge, statement, utility;
|
var AccessorNode, ArrayNode, AssignNode, BaseNode, CallNode, ClassNode, ClosureNode, CodeNode, CommentNode, CurryNode, ExistenceNode, Expressions, ExtendsNode, ForNode, IDENTIFIER, IS_STRING, IfNode, IndexNode, LiteralNode, ObjectNode, OpNode, ParentheticalNode, PushNode, RangeNode, ReturnNode, Scope, SliceNode, SplatNode, TAB, TRAILING_WHITESPACE, ThrowNode, TryNode, UTILITIES, ValueNode, WhileNode, _a, children, compact, del, flatten, helpers, literal, merge, statement, utility;
|
||||||
var __extends = function(child, parent) {
|
var __slice = Array.prototype.slice, __bind = function(func, obj, args) {
|
||||||
|
return function() {
|
||||||
|
return func.apply(obj || {}, args ? args.concat(__slice.call(arguments, 0)) : arguments);
|
||||||
|
};
|
||||||
|
}, __extends = function(child, parent) {
|
||||||
var ctor = function(){ };
|
var ctor = function(){ };
|
||||||
ctor.prototype = parent.prototype;
|
ctor.prototype = parent.prototype;
|
||||||
child.__superClass__ = parent.prototype;
|
child.__superClass__ = parent.prototype;
|
||||||
child.prototype = new ctor();
|
child.prototype = new ctor();
|
||||||
child.prototype.constructor = child;
|
child.prototype.constructor = child;
|
||||||
}, __slice = Array.prototype.slice, __bind = function(func, obj, args) {
|
|
||||||
return function() {
|
|
||||||
return func.apply(obj || {}, args ? args.concat(__slice.call(arguments, 0)) : arguments);
|
|
||||||
};
|
|
||||||
};
|
};
|
||||||
// `nodes.coffee` contains all of the node classes for the syntax tree. Most
|
// `nodes.coffee` contains all of the node classes for the syntax tree. Most
|
||||||
// nodes are created as the result of actions in the [grammar](grammar.html),
|
// nodes are created as the result of actions in the [grammar](grammar.html),
|
||||||
@@ -46,6 +46,12 @@
|
|||||||
return klass.prototype.is_pure_statement;
|
return klass.prototype.is_pure_statement;
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
children = function children(klass) {
|
||||||
|
var child_attrs;
|
||||||
|
child_attrs = __slice.call(arguments, 1, arguments.length - 0);
|
||||||
|
klass.prototype._children_attributes = child_attrs;
|
||||||
|
return klass.prototype._children_attributes;
|
||||||
|
};
|
||||||
//### BaseNode
|
//### BaseNode
|
||||||
// The **BaseNode** is the abstract base class for all nodes in the syntax tree.
|
// The **BaseNode** is the abstract base class for all nodes in the syntax tree.
|
||||||
// Each subclass implements the `compile_node` method, which performs the
|
// Each subclass implements the `compile_node` method, which performs the
|
||||||
@@ -119,18 +125,15 @@
|
|||||||
// and returning true when the block finds a match. `contains` does not cross
|
// and returning true when the block finds a match. `contains` does not cross
|
||||||
// scope boundaries.
|
// scope boundaries.
|
||||||
BaseNode.prototype.contains = function contains(block) {
|
BaseNode.prototype.contains = function contains(block) {
|
||||||
var _b, _c, _d, node;
|
var contains;
|
||||||
_c = this.children;
|
contains = false;
|
||||||
for (_b = 0, _d = _c.length; _b < _d; _b++) {
|
this._traverse_children(false, __bind(function(node, attr, index) {
|
||||||
node = _c[_b];
|
if (block(node)) {
|
||||||
if (block(node)) {
|
contains = true;
|
||||||
return true;
|
return false;
|
||||||
}
|
}
|
||||||
if (node.contains && node.contains(block)) {
|
}, this));
|
||||||
return true;
|
return contains;
|
||||||
}
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
};
|
};
|
||||||
// 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?
|
||||||
BaseNode.prototype.contains_type = function contains_type(type) {
|
BaseNode.prototype.contains_type = function contains_type(type) {
|
||||||
@@ -147,18 +150,7 @@
|
|||||||
};
|
};
|
||||||
// Perform an in-order traversal of the AST. Crosses scope boundaries.
|
// Perform an in-order traversal of the AST. Crosses scope boundaries.
|
||||||
BaseNode.prototype.traverse = function traverse(block) {
|
BaseNode.prototype.traverse = function traverse(block) {
|
||||||
var _b, _c, _d, _e, node;
|
return this._traverse_children(true, block);
|
||||||
_b = []; _d = this.children;
|
|
||||||
for (_c = 0, _e = _d.length; _c < _e; _c++) {
|
|
||||||
node = _d[_c];
|
|
||||||
_b.push((function() {
|
|
||||||
block(node);
|
|
||||||
if (node.traverse) {
|
|
||||||
return node.traverse(block);
|
|
||||||
}
|
|
||||||
})());
|
|
||||||
}
|
|
||||||
return _b;
|
|
||||||
};
|
};
|
||||||
// `toString` representation of the node, for inspecting the parse tree.
|
// `toString` representation of the node, for inspecting the parse tree.
|
||||||
// This is what `coffee --nodes` prints out.
|
// This is what `coffee --nodes` prints out.
|
||||||
@@ -166,7 +158,7 @@
|
|||||||
var _b, _c, _d, _e, child;
|
var _b, _c, _d, _e, child;
|
||||||
idt = idt || '';
|
idt = idt || '';
|
||||||
return '\n' + idt + this.constructor.name + (function() {
|
return '\n' + idt + this.constructor.name + (function() {
|
||||||
_b = []; _d = this.children;
|
_b = []; _d = this.children();
|
||||||
for (_c = 0, _e = _d.length; _c < _e; _c++) {
|
for (_c = 0, _e = _d.length; _c < _e; _c++) {
|
||||||
child = _d[_c];
|
child = _d[_c];
|
||||||
_b.push(child.toString(idt + TAB));
|
_b.push(child.toString(idt + TAB));
|
||||||
@@ -174,12 +166,55 @@
|
|||||||
return _b;
|
return _b;
|
||||||
}).call(this).join('');
|
}).call(this).join('');
|
||||||
};
|
};
|
||||||
|
BaseNode.prototype.children = function children() {
|
||||||
|
var _children;
|
||||||
|
_children = [];
|
||||||
|
this._each_child(function(child) {
|
||||||
|
return _children.push(child);
|
||||||
|
});
|
||||||
|
return _children;
|
||||||
|
};
|
||||||
|
BaseNode.prototype._each_child = function _each_child(func) {
|
||||||
|
var _b, _c, _d, _e, _f, _g, attr, child, child_collection, i, result;
|
||||||
|
_c = this._children_attributes;
|
||||||
|
for (_b = 0, _d = _c.length; _b < _d; _b++) {
|
||||||
|
attr = _c[_b];
|
||||||
|
child_collection = this[attr];
|
||||||
|
if (!((typeof child_collection !== "undefined" && child_collection !== null))) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (child_collection instanceof Array) {
|
||||||
|
i = 0;
|
||||||
|
_f = child_collection;
|
||||||
|
for (_e = 0, _g = _f.length; _e < _g; _e++) {
|
||||||
|
child = _f[_e];
|
||||||
|
result = func(child, attr, i);
|
||||||
|
if (result === false) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
i += 1;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
func(child_collection, attr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
BaseNode.prototype._traverse_children = function _traverse_children(cross_scope, func) {
|
||||||
|
if (!(this._children_attributes)) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
return this._each_child(function(child, attr, i) {
|
||||||
|
func.apply(this, arguments);
|
||||||
|
if (child instanceof BaseNode) {
|
||||||
|
return child._traverse_children(cross_scope, func);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
// Default implementations of the common node identification methods. Nodes
|
// Default implementations of the common node identification methods. Nodes
|
||||||
// will override these with custom logic, if needed.
|
// will override these with custom logic, if needed.
|
||||||
BaseNode.prototype.unwrap = function unwrap() {
|
BaseNode.prototype.unwrap = function unwrap() {
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
BaseNode.prototype.children = [];
|
|
||||||
BaseNode.prototype.is_statement = function is_statement() {
|
BaseNode.prototype.is_statement = function is_statement() {
|
||||||
return false;
|
return false;
|
||||||
};
|
};
|
||||||
@@ -197,7 +232,7 @@
|
|||||||
// `if`, `switch`, or `try`, and so on...
|
// `if`, `switch`, or `try`, and so on...
|
||||||
exports.Expressions = (function() {
|
exports.Expressions = (function() {
|
||||||
Expressions = function Expressions(nodes) {
|
Expressions = function Expressions(nodes) {
|
||||||
this.children = (this.expressions = compact(flatten(nodes || [])));
|
this.expressions = compact(flatten(nodes || []));
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
__extends(Expressions, BaseNode);
|
__extends(Expressions, BaseNode);
|
||||||
@@ -226,7 +261,7 @@
|
|||||||
};
|
};
|
||||||
// Make a copy of this node.
|
// Make a copy of this node.
|
||||||
Expressions.prototype.copy = function copy() {
|
Expressions.prototype.copy = function copy() {
|
||||||
return new Expressions(this.children.slice());
|
return new Expressions(this.Expressions.slice());
|
||||||
};
|
};
|
||||||
// An Expressions node does not return its entire body, rather it
|
// An Expressions node does not return its entire body, rather it
|
||||||
// ensures that the final expression is returned.
|
// ensures that the final expression is returned.
|
||||||
@@ -317,6 +352,7 @@
|
|||||||
}
|
}
|
||||||
return new Expressions(nodes);
|
return new Expressions(nodes);
|
||||||
};
|
};
|
||||||
|
children(Expressions, 'expressions');
|
||||||
statement(Expressions);
|
statement(Expressions);
|
||||||
//### LiteralNode
|
//### LiteralNode
|
||||||
// Literals are static values that can be passed through directly into
|
// Literals are static values that can be passed through directly into
|
||||||
@@ -350,7 +386,7 @@
|
|||||||
// make sense.
|
// make sense.
|
||||||
exports.ReturnNode = (function() {
|
exports.ReturnNode = (function() {
|
||||||
ReturnNode = function ReturnNode(expression) {
|
ReturnNode = function ReturnNode(expression) {
|
||||||
this.children = [(this.expression = expression)];
|
this.expression = expression;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
__extends(ReturnNode, BaseNode);
|
__extends(ReturnNode, BaseNode);
|
||||||
@@ -372,12 +408,14 @@
|
|||||||
return ReturnNode;
|
return ReturnNode;
|
||||||
})();
|
})();
|
||||||
statement(ReturnNode, true);
|
statement(ReturnNode, true);
|
||||||
|
children(ReturnNode, 'expression');
|
||||||
//### ValueNode
|
//### ValueNode
|
||||||
// A value, variable or literal or parenthesized, indexed or dotted into,
|
// A value, variable or literal or parenthesized, indexed or dotted into,
|
||||||
// or vanilla.
|
// or vanilla.
|
||||||
exports.ValueNode = (function() {
|
exports.ValueNode = (function() {
|
||||||
ValueNode = function ValueNode(base, properties) {
|
ValueNode = function ValueNode(base, properties) {
|
||||||
this.children = flatten([(this.base = base), (this.properties = (properties || []))]);
|
this.base = base;
|
||||||
|
this.properties = (properties || []);
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
__extends(ValueNode, BaseNode);
|
__extends(ValueNode, BaseNode);
|
||||||
@@ -386,7 +424,6 @@
|
|||||||
// Add a property access to the list.
|
// Add a property access to the list.
|
||||||
ValueNode.prototype.push = function push(prop) {
|
ValueNode.prototype.push = function push(prop) {
|
||||||
this.properties.push(prop);
|
this.properties.push(prop);
|
||||||
this.children.push(prop);
|
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
ValueNode.prototype.has_properties = function has_properties() {
|
ValueNode.prototype.has_properties = function has_properties() {
|
||||||
@@ -464,6 +501,7 @@
|
|||||||
};
|
};
|
||||||
return ValueNode;
|
return ValueNode;
|
||||||
})();
|
})();
|
||||||
|
children(ValueNode, 'base', 'properties');
|
||||||
//### CommentNode
|
//### CommentNode
|
||||||
// CoffeeScript passes through comments as JavaScript comments at the
|
// CoffeeScript passes through comments as JavaScript comments at the
|
||||||
// same position.
|
// same position.
|
||||||
@@ -491,7 +529,7 @@
|
|||||||
this.is_new = false;
|
this.is_new = false;
|
||||||
this.is_super = variable === 'super';
|
this.is_super = variable === 'super';
|
||||||
this.variable = this.is_super ? null : variable;
|
this.variable = this.is_super ? null : variable;
|
||||||
this.children = compact(flatten([this.variable, (this.args = (args || []))]));
|
this.args = (args || []);
|
||||||
this.compile_splat_arguments = __bind(SplatNode.compile_mixed_array, this, [this.args]);
|
this.compile_splat_arguments = __bind(SplatNode.compile_mixed_array, this, [this.args]);
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
@@ -558,13 +596,16 @@
|
|||||||
};
|
};
|
||||||
return CallNode;
|
return CallNode;
|
||||||
})();
|
})();
|
||||||
|
children(CallNode, 'variable', 'args');
|
||||||
//### CurryNode
|
//### CurryNode
|
||||||
// Binds a context object and a list of arguments to a function,
|
// Binds a context object and a list of arguments to a function,
|
||||||
// returning the bound function. After ECMAScript 5, Prototype.js, and
|
// returning the bound function. After ECMAScript 5, Prototype.js, and
|
||||||
// Underscore's `bind` functions.
|
// Underscore's `bind` functions.
|
||||||
exports.CurryNode = (function() {
|
exports.CurryNode = (function() {
|
||||||
CurryNode = function CurryNode(meth, args) {
|
CurryNode = function CurryNode(meth, args) {
|
||||||
this.children = flatten([(this.meth = meth), (this.context = args[0]), (this.args = (args.slice(1) || []))]);
|
this.meth = meth;
|
||||||
|
this.context = args[0];
|
||||||
|
this.args = (args.slice(1) || []);
|
||||||
this.compile_splat_arguments = __bind(SplatNode.compile_mixed_array, this, [this.args]);
|
this.compile_splat_arguments = __bind(SplatNode.compile_mixed_array, this, [this.args]);
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
@@ -588,13 +629,15 @@
|
|||||||
};
|
};
|
||||||
return CurryNode;
|
return CurryNode;
|
||||||
}).apply(this, arguments);
|
}).apply(this, arguments);
|
||||||
|
children(CurryNode, 'meth', 'context', 'args');
|
||||||
//### ExtendsNode
|
//### ExtendsNode
|
||||||
// Node to extend an object's prototype with an ancestor object.
|
// Node to extend an object's prototype with an ancestor object.
|
||||||
// After `goog.inherits` from the
|
// After `goog.inherits` from the
|
||||||
// [Closure Library](http://closure-library.googlecode.com/svn/docs/closure_goog_base.js.html).
|
// [Closure Library](http://closure-library.googlecode.com/svn/docs/closure_goog_base.js.html).
|
||||||
exports.ExtendsNode = (function() {
|
exports.ExtendsNode = (function() {
|
||||||
ExtendsNode = function ExtendsNode(child, parent) {
|
ExtendsNode = function ExtendsNode(child, parent) {
|
||||||
this.children = [(this.child = child), (this.parent = parent)];
|
this.child = child;
|
||||||
|
this.parent = parent;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
__extends(ExtendsNode, BaseNode);
|
__extends(ExtendsNode, BaseNode);
|
||||||
@@ -606,12 +649,13 @@
|
|||||||
};
|
};
|
||||||
return ExtendsNode;
|
return ExtendsNode;
|
||||||
})();
|
})();
|
||||||
|
children(ExtendsNode, 'child', 'parent');
|
||||||
//### AccessorNode
|
//### AccessorNode
|
||||||
// A `.` accessor into a property of a value, or the `::` shorthand for
|
// A `.` accessor into a property of a value, or the `::` shorthand for
|
||||||
// an accessor into the object's prototype.
|
// an accessor into the object's prototype.
|
||||||
exports.AccessorNode = (function() {
|
exports.AccessorNode = (function() {
|
||||||
AccessorNode = function AccessorNode(name, tag) {
|
AccessorNode = function AccessorNode(name, tag) {
|
||||||
this.children = [(this.name = name)];
|
this.name = name;
|
||||||
this.prototype = tag === 'prototype';
|
this.prototype = tag === 'prototype';
|
||||||
this.soak_node = tag === 'soak';
|
this.soak_node = tag === 'soak';
|
||||||
this;
|
this;
|
||||||
@@ -625,11 +669,12 @@
|
|||||||
};
|
};
|
||||||
return AccessorNode;
|
return AccessorNode;
|
||||||
})();
|
})();
|
||||||
|
children(AccessorNode, 'name');
|
||||||
//### IndexNode
|
//### IndexNode
|
||||||
// A `[ ... ]` indexed accessor into an array or object.
|
// A `[ ... ]` indexed accessor into an array or object.
|
||||||
exports.IndexNode = (function() {
|
exports.IndexNode = (function() {
|
||||||
IndexNode = function IndexNode(index, tag) {
|
IndexNode = function IndexNode(index, tag) {
|
||||||
this.children = [(this.index = index)];
|
this.index = index;
|
||||||
this.soak_node = tag === 'soak';
|
this.soak_node = tag === 'soak';
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
@@ -641,13 +686,15 @@
|
|||||||
};
|
};
|
||||||
return IndexNode;
|
return IndexNode;
|
||||||
})();
|
})();
|
||||||
|
children(IndexNode, 'index');
|
||||||
//### RangeNode
|
//### RangeNode
|
||||||
// A range literal. Ranges can be used to extract portions (slices) of arrays,
|
// 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
|
// to specify a range for comprehensions, or as a value, to be expanded into the
|
||||||
// corresponding array of integers at runtime.
|
// corresponding array of integers at runtime.
|
||||||
exports.RangeNode = (function() {
|
exports.RangeNode = (function() {
|
||||||
RangeNode = function RangeNode(from, to, exclusive) {
|
RangeNode = function RangeNode(from, to, exclusive) {
|
||||||
this.children = [(this.from = from), (this.to = to)];
|
this.from = from;
|
||||||
|
this.to = to;
|
||||||
this.exclusive = !!exclusive;
|
this.exclusive = !!exclusive;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
@@ -697,13 +744,14 @@
|
|||||||
};
|
};
|
||||||
return RangeNode;
|
return RangeNode;
|
||||||
})();
|
})();
|
||||||
|
children(RangeNode, 'from', 'to');
|
||||||
//### SliceNode
|
//### SliceNode
|
||||||
// An array slice literal. Unlike JavaScript's `Array#slice`, the second parameter
|
// 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
|
// specifies the index of the end of the slice, just as the first parameter
|
||||||
// is the index of the beginning.
|
// is the index of the beginning.
|
||||||
exports.SliceNode = (function() {
|
exports.SliceNode = (function() {
|
||||||
SliceNode = function SliceNode(range) {
|
SliceNode = function SliceNode(range) {
|
||||||
this.children = [(this.range = range)];
|
this.range = range;
|
||||||
this;
|
this;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
@@ -717,11 +765,12 @@
|
|||||||
};
|
};
|
||||||
return SliceNode;
|
return SliceNode;
|
||||||
})();
|
})();
|
||||||
|
children(SliceNode, 'range');
|
||||||
//### ObjectNode
|
//### ObjectNode
|
||||||
// An object literal, nothing fancy.
|
// An object literal, nothing fancy.
|
||||||
exports.ObjectNode = (function() {
|
exports.ObjectNode = (function() {
|
||||||
ObjectNode = function ObjectNode(props) {
|
ObjectNode = function ObjectNode(props) {
|
||||||
this.children = (this.objects = (this.properties = props || []));
|
this.objects = (this.properties = props || []);
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
__extends(ObjectNode, BaseNode);
|
__extends(ObjectNode, BaseNode);
|
||||||
@@ -767,11 +816,12 @@
|
|||||||
};
|
};
|
||||||
return ObjectNode;
|
return ObjectNode;
|
||||||
})();
|
})();
|
||||||
|
children(ObjectNode, 'properties');
|
||||||
//### ArrayNode
|
//### ArrayNode
|
||||||
// An array literal.
|
// An array literal.
|
||||||
exports.ArrayNode = (function() {
|
exports.ArrayNode = (function() {
|
||||||
ArrayNode = function ArrayNode(objects) {
|
ArrayNode = function ArrayNode(objects) {
|
||||||
this.children = (this.objects = objects || []);
|
this.objects = objects || [];
|
||||||
this.compile_splat_literal = __bind(SplatNode.compile_mixed_array, this, [this.objects]);
|
this.compile_splat_literal = __bind(SplatNode.compile_mixed_array, this, [this.objects]);
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
@@ -803,11 +853,14 @@
|
|||||||
};
|
};
|
||||||
return ArrayNode;
|
return ArrayNode;
|
||||||
})();
|
})();
|
||||||
|
children(ArrayNode, 'objects');
|
||||||
//### ClassNode
|
//### ClassNode
|
||||||
// The CoffeeScript class definition.
|
// The CoffeeScript class definition.
|
||||||
exports.ClassNode = (function() {
|
exports.ClassNode = (function() {
|
||||||
ClassNode = function ClassNode(variable, parent, props) {
|
ClassNode = function ClassNode(variable, parent, props) {
|
||||||
this.children = compact(flatten([(this.variable = variable), (this.parent = parent), (this.properties = props || [])]));
|
this.variable = variable;
|
||||||
|
this.parent = parent;
|
||||||
|
this.properties = props || [];
|
||||||
this.returns = false;
|
this.returns = false;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
@@ -862,12 +915,14 @@
|
|||||||
return ClassNode;
|
return ClassNode;
|
||||||
})();
|
})();
|
||||||
statement(ClassNode);
|
statement(ClassNode);
|
||||||
|
children(ClassNode, 'variable', 'parent', 'properties');
|
||||||
//### AssignNode
|
//### AssignNode
|
||||||
// The **AssignNode** is used to assign a local variable to value, or to set the
|
// The **AssignNode** is used to assign a local variable to value, or to set the
|
||||||
// property of an object -- including within object literals.
|
// property of an object -- including within object literals.
|
||||||
exports.AssignNode = (function() {
|
exports.AssignNode = (function() {
|
||||||
AssignNode = function AssignNode(variable, value, context) {
|
AssignNode = function AssignNode(variable, value, context) {
|
||||||
this.children = [(this.variable = variable), (this.value = value)];
|
this.variable = variable;
|
||||||
|
this.value = value;
|
||||||
this.context = context;
|
this.context = context;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
@@ -994,6 +1049,7 @@
|
|||||||
};
|
};
|
||||||
return AssignNode;
|
return AssignNode;
|
||||||
})();
|
})();
|
||||||
|
children(AssignNode, 'variable', 'value');
|
||||||
//### CodeNode
|
//### CodeNode
|
||||||
// A function definition. This is the only node that creates a new Scope.
|
// 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
|
// When for the purposes of walking the contents of a function body, the CodeNode
|
||||||
@@ -1068,27 +1124,18 @@
|
|||||||
CodeNode.prototype.top_sensitive = function top_sensitive() {
|
CodeNode.prototype.top_sensitive = function top_sensitive() {
|
||||||
return true;
|
return true;
|
||||||
};
|
};
|
||||||
// When traversing (for printing or inspecting), return the real children of
|
// Short-circuit _traverse_children method to prevent it from crossing scope boundaries
|
||||||
// the function -- the parameters and body of expressions.
|
// unless cross_scope is true
|
||||||
CodeNode.prototype.real_children = function real_children() {
|
CodeNode.prototype._traverse_children = function _traverse_children(cross_scope, func) {
|
||||||
return flatten([this.params, this.body.expressions]);
|
if (cross_scope) {
|
||||||
};
|
return CodeNode.__superClass__._traverse_children.call(this, cross_scope, func);
|
||||||
// Custom `traverse` implementation that uses the `real_children`.
|
|
||||||
CodeNode.prototype.traverse = function traverse(block) {
|
|
||||||
var _b, _c, _d, _e, child;
|
|
||||||
block(this);
|
|
||||||
_b = []; _d = this.real_children();
|
|
||||||
for (_c = 0, _e = _d.length; _c < _e; _c++) {
|
|
||||||
child = _d[_c];
|
|
||||||
_b.push(child.traverse(block));
|
|
||||||
}
|
}
|
||||||
return _b;
|
|
||||||
};
|
};
|
||||||
CodeNode.prototype.toString = function toString(idt) {
|
CodeNode.prototype.toString = function toString(idt) {
|
||||||
var _b, _c, _d, _e, child, children;
|
var _b, _c, _d, _e, child;
|
||||||
idt = idt || '';
|
idt = idt || '';
|
||||||
children = (function() {
|
children = (function() {
|
||||||
_b = []; _d = this.real_children();
|
_b = []; _d = this.children();
|
||||||
for (_c = 0, _e = _d.length; _c < _e; _c++) {
|
for (_c = 0, _e = _d.length; _c < _e; _c++) {
|
||||||
child = _d[_c];
|
child = _d[_c];
|
||||||
_b.push(child.toString(idt + TAB));
|
_b.push(child.toString(idt + TAB));
|
||||||
@@ -1099,6 +1146,7 @@
|
|||||||
};
|
};
|
||||||
return CodeNode;
|
return CodeNode;
|
||||||
})();
|
})();
|
||||||
|
children(CodeNode, 'params', 'body');
|
||||||
//### SplatNode
|
//### SplatNode
|
||||||
// A splat, either as a parameter to a function, an argument to a call,
|
// A splat, either as a parameter to a function, an argument to a call,
|
||||||
// or as part of a destructuring assignment.
|
// or as part of a destructuring assignment.
|
||||||
@@ -1107,7 +1155,7 @@
|
|||||||
if (!(name.compile)) {
|
if (!(name.compile)) {
|
||||||
name = literal(name);
|
name = literal(name);
|
||||||
}
|
}
|
||||||
this.children = [(this.name = name)];
|
this.name = name;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
__extends(SplatNode, BaseNode);
|
__extends(SplatNode, BaseNode);
|
||||||
@@ -1170,6 +1218,7 @@
|
|||||||
};
|
};
|
||||||
return SplatNode;
|
return SplatNode;
|
||||||
}).call(this);
|
}).call(this);
|
||||||
|
children(SplatNode, 'name');
|
||||||
//### WhileNode
|
//### WhileNode
|
||||||
// A while loop, the only sort of low-level loop exposed by CoffeeScript. From
|
// A while loop, the only sort of low-level loop exposed by CoffeeScript. From
|
||||||
// it, all other loops can be manufactured. Useful in cases where you need more
|
// it, all other loops can be manufactured. Useful in cases where you need more
|
||||||
@@ -1179,13 +1228,13 @@
|
|||||||
if (opts && opts.invert) {
|
if (opts && opts.invert) {
|
||||||
condition = new OpNode('!', condition);
|
condition = new OpNode('!', condition);
|
||||||
}
|
}
|
||||||
this.children = [(this.condition = condition)];
|
this.condition = condition;
|
||||||
this.guard = opts && opts.guard;
|
this.guard = opts && opts.guard;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
__extends(WhileNode, BaseNode);
|
__extends(WhileNode, BaseNode);
|
||||||
WhileNode.prototype.add_body = function add_body(body) {
|
WhileNode.prototype.add_body = function add_body(body) {
|
||||||
this.children.push((this.body = body));
|
this.body = body;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
WhileNode.prototype.make_return = function make_return() {
|
WhileNode.prototype.make_return = function make_return() {
|
||||||
@@ -1227,13 +1276,15 @@
|
|||||||
return WhileNode;
|
return WhileNode;
|
||||||
})();
|
})();
|
||||||
statement(WhileNode);
|
statement(WhileNode);
|
||||||
|
children(WhileNode, 'condition', 'guard', 'body');
|
||||||
//### OpNode
|
//### OpNode
|
||||||
// Simple Arithmetic and logical operations. Performs some conversion from
|
// Simple Arithmetic and logical operations. Performs some conversion from
|
||||||
// CoffeeScript operations into their JavaScript equivalents.
|
// CoffeeScript operations into their JavaScript equivalents.
|
||||||
exports.OpNode = (function() {
|
exports.OpNode = (function() {
|
||||||
OpNode = function OpNode(operator, first, second, flip) {
|
OpNode = function OpNode(operator, first, second, flip) {
|
||||||
this.constructor.name += ' ' + operator;
|
this.constructor.name += ' ' + operator;
|
||||||
this.children = compact([(this.first = first), (this.second = second)]);
|
this.first = first;
|
||||||
|
this.second = second;
|
||||||
this.operator = this.CONVERSIONS[operator] || operator;
|
this.operator = this.CONVERSIONS[operator] || operator;
|
||||||
this.flip = !!flip;
|
this.flip = !!flip;
|
||||||
return this;
|
return this;
|
||||||
@@ -1329,11 +1380,14 @@
|
|||||||
};
|
};
|
||||||
return OpNode;
|
return OpNode;
|
||||||
})();
|
})();
|
||||||
|
children(OpNode, 'first', 'second');
|
||||||
//### TryNode
|
//### TryNode
|
||||||
// A classic *try/catch/finally* block.
|
// A classic *try/catch/finally* block.
|
||||||
exports.TryNode = (function() {
|
exports.TryNode = (function() {
|
||||||
TryNode = function TryNode(attempt, error, recovery, ensure) {
|
TryNode = function TryNode(attempt, error, recovery, ensure) {
|
||||||
this.children = compact([(this.attempt = attempt), (this.recovery = recovery), (this.ensure = ensure)]);
|
this.attempt = attempt;
|
||||||
|
this.recovery = recovery;
|
||||||
|
this.ensure = ensure;
|
||||||
this.error = error;
|
this.error = error;
|
||||||
this;
|
this;
|
||||||
return this;
|
return this;
|
||||||
@@ -1363,11 +1417,12 @@
|
|||||||
return TryNode;
|
return TryNode;
|
||||||
})();
|
})();
|
||||||
statement(TryNode);
|
statement(TryNode);
|
||||||
|
children(TryNode, 'attempt', 'recovery', 'ensure');
|
||||||
//### ThrowNode
|
//### ThrowNode
|
||||||
// Simple node to throw an exception.
|
// Simple node to throw an exception.
|
||||||
exports.ThrowNode = (function() {
|
exports.ThrowNode = (function() {
|
||||||
ThrowNode = function ThrowNode(expression) {
|
ThrowNode = function ThrowNode(expression) {
|
||||||
this.children = [(this.expression = expression)];
|
this.expression = expression;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
__extends(ThrowNode, BaseNode);
|
__extends(ThrowNode, BaseNode);
|
||||||
@@ -1381,13 +1436,14 @@
|
|||||||
return ThrowNode;
|
return ThrowNode;
|
||||||
})();
|
})();
|
||||||
statement(ThrowNode);
|
statement(ThrowNode);
|
||||||
|
children(ThrowNode, 'expression');
|
||||||
//### ExistenceNode
|
//### ExistenceNode
|
||||||
// Checks a variable for existence -- not *null* and not *undefined*. This is
|
// Checks a variable for existence -- not *null* and not *undefined*. This is
|
||||||
// similar to `.nil?` in Ruby, and avoids having to consult a JavaScript truth
|
// similar to `.nil?` in Ruby, and avoids having to consult a JavaScript truth
|
||||||
// table.
|
// table.
|
||||||
exports.ExistenceNode = (function() {
|
exports.ExistenceNode = (function() {
|
||||||
ExistenceNode = function ExistenceNode(expression) {
|
ExistenceNode = function ExistenceNode(expression) {
|
||||||
this.children = [(this.expression = expression)];
|
this.expression = expression;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
__extends(ExistenceNode, BaseNode);
|
__extends(ExistenceNode, BaseNode);
|
||||||
@@ -1414,6 +1470,7 @@
|
|||||||
};
|
};
|
||||||
return ExistenceNode;
|
return ExistenceNode;
|
||||||
}).call(this);
|
}).call(this);
|
||||||
|
children(ExistenceNode, 'expression');
|
||||||
//### ParentheticalNode
|
//### ParentheticalNode
|
||||||
// An extra set of parentheses, specified explicitly in the source. At one time
|
// An extra set of parentheses, specified explicitly in the source. At one time
|
||||||
// we tried to clean up the results by detecting and removing redundant
|
// we tried to clean up the results by detecting and removing redundant
|
||||||
@@ -1421,7 +1478,7 @@
|
|||||||
// Parentheses are a good way to force any statement to become an expression.
|
// Parentheses are a good way to force any statement to become an expression.
|
||||||
exports.ParentheticalNode = (function() {
|
exports.ParentheticalNode = (function() {
|
||||||
ParentheticalNode = function ParentheticalNode(expression) {
|
ParentheticalNode = function ParentheticalNode(expression) {
|
||||||
this.children = [(this.expression = expression)];
|
this.expression = expression;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
__extends(ParentheticalNode, BaseNode);
|
__extends(ParentheticalNode, BaseNode);
|
||||||
@@ -1449,6 +1506,7 @@
|
|||||||
};
|
};
|
||||||
return ParentheticalNode;
|
return ParentheticalNode;
|
||||||
})();
|
})();
|
||||||
|
children(ParentheticalNode, 'expression');
|
||||||
//### ForNode
|
//### ForNode
|
||||||
// CoffeeScript's replacement for the *for* loop is our array and object
|
// CoffeeScript's replacement for the *for* loop is our array and object
|
||||||
// comprehensions, that compile into *for* loops here. They also act as an
|
// comprehensions, that compile into *for* loops here. They also act as an
|
||||||
@@ -1475,7 +1533,6 @@
|
|||||||
if (this.index instanceof ValueNode) {
|
if (this.index instanceof ValueNode) {
|
||||||
throw new Error('index cannot be a pattern matching expression');
|
throw new Error('index cannot be a pattern matching expression');
|
||||||
}
|
}
|
||||||
this.children = compact([this.body, this.source, this.guard]);
|
|
||||||
this.returns = false;
|
this.returns = false;
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
@@ -1566,6 +1623,7 @@
|
|||||||
return ForNode;
|
return ForNode;
|
||||||
})();
|
})();
|
||||||
statement(ForNode);
|
statement(ForNode);
|
||||||
|
children(ForNode, 'body', 'source', 'guard');
|
||||||
//### IfNode
|
//### IfNode
|
||||||
// *If/else* statements. Our *switch/when* will be compiled into this. Acts as an
|
// *If/else* statements. Our *switch/when* will be compiled into this. Acts as an
|
||||||
// expression by pushing down requested returns to the last line of each clause.
|
// expression by pushing down requested returns to the last line of each clause.
|
||||||
@@ -1576,7 +1634,6 @@
|
|||||||
this.condition = condition;
|
this.condition = condition;
|
||||||
this.body = body;
|
this.body = body;
|
||||||
this.else_body = null;
|
this.else_body = null;
|
||||||
this.populate_children();
|
|
||||||
this.tags = tags || {};
|
this.tags = tags || {};
|
||||||
if (this.condition instanceof Array) {
|
if (this.condition instanceof Array) {
|
||||||
this.multiple = true;
|
this.multiple = true;
|
||||||
@@ -1588,10 +1645,6 @@
|
|||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
__extends(IfNode, BaseNode);
|
__extends(IfNode, BaseNode);
|
||||||
IfNode.prototype.populate_children = function populate_children() {
|
|
||||||
this.children = compact(flatten([this.condition, this.body, this.else_body]));
|
|
||||||
return this.children;
|
|
||||||
};
|
|
||||||
IfNode.prototype.body_node = function body_node() {
|
IfNode.prototype.body_node = function body_node() {
|
||||||
return this.body == undefined ? undefined : this.body.unwrap();
|
return this.body == undefined ? undefined : this.body.unwrap();
|
||||||
};
|
};
|
||||||
@@ -1611,12 +1664,11 @@
|
|||||||
// Rewrite a chain of **IfNodes** with their switch condition for equality.
|
// Rewrite a chain of **IfNodes** with their switch condition for equality.
|
||||||
// Ensure that the switch expression isn't evaluated more than once.
|
// Ensure that the switch expression isn't evaluated more than once.
|
||||||
IfNode.prototype.rewrite_switch = function rewrite_switch(o) {
|
IfNode.prototype.rewrite_switch = function rewrite_switch(o) {
|
||||||
var _b, _c, _d, assigner, cond, i, variable;
|
var _b, _c, _d, cond, i, variable;
|
||||||
assigner = this.switch_subject;
|
this.assigner = this.switch_subject;
|
||||||
if (!((this.switch_subject.unwrap() instanceof LiteralNode))) {
|
if (!((this.switch_subject.unwrap() instanceof LiteralNode))) {
|
||||||
variable = literal(o.scope.free_variable());
|
variable = literal(o.scope.free_variable());
|
||||||
assigner = new AssignNode(variable, this.switch_subject);
|
this.assigner = new AssignNode(variable, this.switch_subject);
|
||||||
this.children.push(assigner);
|
|
||||||
this.switch_subject = variable;
|
this.switch_subject = variable;
|
||||||
}
|
}
|
||||||
this.condition = (function() {
|
this.condition = (function() {
|
||||||
@@ -1624,11 +1676,11 @@
|
|||||||
_b = []; _c = this.condition;
|
_b = []; _c = this.condition;
|
||||||
for (i = 0, _d = _c.length; i < _d; i++) {
|
for (i = 0, _d = _c.length; i < _d; i++) {
|
||||||
cond = _c[i];
|
cond = _c[i];
|
||||||
_b.push(new OpNode('==', (i === 0 ? assigner : this.switch_subject), cond));
|
_b.push(new OpNode('==', (i === 0 ? this.assigner : this.switch_subject), cond));
|
||||||
}
|
}
|
||||||
return _b;
|
return _b;
|
||||||
} else {
|
} else {
|
||||||
return new OpNode('==', assigner, this.condition);
|
return new OpNode('==', this.assigner, this.condition);
|
||||||
}
|
}
|
||||||
}).call(this);
|
}).call(this);
|
||||||
if (this.is_chain) {
|
if (this.is_chain) {
|
||||||
@@ -1645,7 +1697,6 @@
|
|||||||
} else {
|
} else {
|
||||||
this.is_chain = else_body instanceof IfNode;
|
this.is_chain = else_body instanceof IfNode;
|
||||||
this.else_body = this.ensure_expressions(else_body);
|
this.else_body = this.ensure_expressions(else_body);
|
||||||
this.populate_children();
|
|
||||||
}
|
}
|
||||||
return this;
|
return this;
|
||||||
};
|
};
|
||||||
@@ -1717,6 +1768,7 @@
|
|||||||
};
|
};
|
||||||
return IfNode;
|
return IfNode;
|
||||||
})();
|
})();
|
||||||
|
children(IfNode, 'condition', 'body', 'else_body', 'assigner');
|
||||||
// Faux-Nodes
|
// Faux-Nodes
|
||||||
// ----------
|
// ----------
|
||||||
//### PushNode
|
//### PushNode
|
||||||
|
|||||||
175
src/nodes.coffee
175
src/nodes.coffee
@@ -24,6 +24,9 @@ statement: (klass, only) ->
|
|||||||
klass::is_statement: -> true
|
klass::is_statement: -> true
|
||||||
(klass::is_pure_statement: -> true) if only
|
(klass::is_pure_statement: -> true) if only
|
||||||
|
|
||||||
|
children: (klass, child_attrs...) ->
|
||||||
|
klass::_children_attributes: child_attrs
|
||||||
|
|
||||||
#### BaseNode
|
#### BaseNode
|
||||||
|
|
||||||
# The **BaseNode** is the abstract base class for all nodes in the syntax tree.
|
# The **BaseNode** is the abstract base class for all nodes in the syntax tree.
|
||||||
@@ -90,10 +93,12 @@ exports.BaseNode: class BaseNode
|
|||||||
# and returning true when the block finds a match. `contains` does not cross
|
# and returning true when the block finds a match. `contains` does not cross
|
||||||
# scope boundaries.
|
# scope boundaries.
|
||||||
contains: (block) ->
|
contains: (block) ->
|
||||||
for node in @children
|
contains: false
|
||||||
return true if block(node)
|
@_traverse_children false, (node, attr, index) =>
|
||||||
return true if node.contains and node.contains block
|
if block(node)
|
||||||
false
|
contains: true
|
||||||
|
return false
|
||||||
|
return contains
|
||||||
|
|
||||||
# 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?
|
||||||
contains_type: (type) ->
|
contains_type: (type) ->
|
||||||
@@ -105,21 +110,41 @@ exports.BaseNode: class BaseNode
|
|||||||
@is_pure_statement() or @contains (n) -> n.is_pure_statement()
|
@is_pure_statement() or @contains (n) -> n.is_pure_statement()
|
||||||
|
|
||||||
# Perform an in-order traversal of the AST. Crosses scope boundaries.
|
# Perform an in-order traversal of the AST. Crosses scope boundaries.
|
||||||
traverse: (block) ->
|
traverse: (block) -> @_traverse_children true, block
|
||||||
for node in @children
|
|
||||||
block node
|
|
||||||
node.traverse block if node.traverse
|
|
||||||
|
|
||||||
# `toString` representation of the node, for inspecting the parse tree.
|
# `toString` representation of the node, for inspecting the parse tree.
|
||||||
# This is what `coffee --nodes` prints out.
|
# This is what `coffee --nodes` prints out.
|
||||||
toString: (idt) ->
|
toString: (idt) ->
|
||||||
idt: or ''
|
idt: or ''
|
||||||
'\n' + idt + @constructor.name + (child.toString(idt + TAB) for child in @children).join('')
|
'\n' + idt + @constructor.name + (child.toString(idt + TAB) for child in @children()).join('')
|
||||||
|
|
||||||
|
children: ->
|
||||||
|
_children: []
|
||||||
|
@_each_child (child) -> _children.push(child)
|
||||||
|
_children
|
||||||
|
|
||||||
|
_each_child: (func) ->
|
||||||
|
for attr in @_children_attributes
|
||||||
|
child_collection: this[attr]
|
||||||
|
continue unless child_collection?
|
||||||
|
if child_collection instanceof Array
|
||||||
|
i: 0
|
||||||
|
for child in child_collection
|
||||||
|
result: func(child, attr, i)
|
||||||
|
return if result is false
|
||||||
|
i += 1
|
||||||
|
else
|
||||||
|
func(child_collection, attr)
|
||||||
|
|
||||||
|
_traverse_children: (cross_scope, func) ->
|
||||||
|
return unless @_children_attributes
|
||||||
|
@_each_child (child, attr, i) ->
|
||||||
|
func.apply(this, arguments)
|
||||||
|
child._traverse_children(cross_scope, func) if child instanceof BaseNode
|
||||||
|
|
||||||
# Default implementations of the common node identification methods. Nodes
|
# Default implementations of the common node identification methods. Nodes
|
||||||
# will override these with custom logic, if needed.
|
# will override these with custom logic, if needed.
|
||||||
unwrap: -> this
|
unwrap: -> this
|
||||||
children: []
|
|
||||||
is_statement: -> false
|
is_statement: -> false
|
||||||
is_pure_statement: -> false
|
is_pure_statement: -> false
|
||||||
top_sensitive: -> false
|
top_sensitive: -> false
|
||||||
@@ -132,7 +157,7 @@ exports.BaseNode: class BaseNode
|
|||||||
exports.Expressions: class Expressions extends BaseNode
|
exports.Expressions: class Expressions extends BaseNode
|
||||||
|
|
||||||
constructor: (nodes) ->
|
constructor: (nodes) ->
|
||||||
@children: @expressions: compact flatten nodes or []
|
@expressions: compact flatten nodes or []
|
||||||
|
|
||||||
# Tack an expression on to the end of this expression list.
|
# Tack an expression on to the end of this expression list.
|
||||||
push: (node) ->
|
push: (node) ->
|
||||||
@@ -155,7 +180,7 @@ exports.Expressions: class Expressions extends BaseNode
|
|||||||
|
|
||||||
# Make a copy of this node.
|
# Make a copy of this node.
|
||||||
copy: ->
|
copy: ->
|
||||||
new Expressions @children.slice()
|
new Expressions @Expressions.slice()
|
||||||
|
|
||||||
# An Expressions node does not return its entire body, rather it
|
# An Expressions node does not return its entire body, rather it
|
||||||
# ensures that the final expression is returned.
|
# ensures that the final expression is returned.
|
||||||
@@ -206,6 +231,7 @@ Expressions.wrap: (nodes) ->
|
|||||||
return nodes[0] if nodes.length is 1 and nodes[0] instanceof Expressions
|
return nodes[0] if nodes.length is 1 and nodes[0] instanceof Expressions
|
||||||
new Expressions(nodes)
|
new Expressions(nodes)
|
||||||
|
|
||||||
|
children Expressions, 'expressions'
|
||||||
statement Expressions
|
statement Expressions
|
||||||
|
|
||||||
#### LiteralNode
|
#### LiteralNode
|
||||||
@@ -239,7 +265,7 @@ exports.LiteralNode: class LiteralNode extends BaseNode
|
|||||||
exports.ReturnNode: class ReturnNode extends BaseNode
|
exports.ReturnNode: class ReturnNode extends BaseNode
|
||||||
|
|
||||||
constructor: (expression) ->
|
constructor: (expression) ->
|
||||||
@children: [@expression: expression]
|
@expression: expression
|
||||||
|
|
||||||
top_sensitive: ->
|
top_sensitive: ->
|
||||||
true
|
true
|
||||||
@@ -252,6 +278,7 @@ exports.ReturnNode: class ReturnNode extends BaseNode
|
|||||||
"${@tab}return ${@expression.compile(o)};"
|
"${@tab}return ${@expression.compile(o)};"
|
||||||
|
|
||||||
statement ReturnNode, true
|
statement ReturnNode, true
|
||||||
|
children ReturnNode, 'expression'
|
||||||
|
|
||||||
#### ValueNode
|
#### ValueNode
|
||||||
|
|
||||||
@@ -263,12 +290,12 @@ exports.ValueNode: class ValueNode extends BaseNode
|
|||||||
|
|
||||||
# A **ValueNode** has a base and a list of property accesses.
|
# A **ValueNode** has a base and a list of property accesses.
|
||||||
constructor: (base, properties) ->
|
constructor: (base, properties) ->
|
||||||
@children: flatten [@base: base, @properties: (properties or [])]
|
@base: base
|
||||||
|
@properties: (properties or [])
|
||||||
|
|
||||||
# Add a property access to the list.
|
# Add a property access to the list.
|
||||||
push: (prop) ->
|
push: (prop) ->
|
||||||
@properties.push(prop)
|
@properties.push(prop)
|
||||||
@children.push(prop)
|
|
||||||
this
|
this
|
||||||
|
|
||||||
has_properties: ->
|
has_properties: ->
|
||||||
@@ -327,6 +354,8 @@ exports.ValueNode: class ValueNode extends BaseNode
|
|||||||
|
|
||||||
if op and soaked then "($complete)" else complete
|
if op and soaked then "($complete)" else complete
|
||||||
|
|
||||||
|
children ValueNode, 'base', 'properties'
|
||||||
|
|
||||||
#### CommentNode
|
#### CommentNode
|
||||||
|
|
||||||
# CoffeeScript passes through comments as JavaScript comments at the
|
# CoffeeScript passes through comments as JavaScript comments at the
|
||||||
@@ -355,7 +384,7 @@ exports.CallNode: class CallNode extends BaseNode
|
|||||||
@is_new: false
|
@is_new: false
|
||||||
@is_super: variable is 'super'
|
@is_super: variable is 'super'
|
||||||
@variable: if @is_super then null else variable
|
@variable: if @is_super then null else variable
|
||||||
@children: compact flatten [@variable, @args: (args or [])]
|
@args: (args or [])
|
||||||
@compile_splat_arguments: SplatNode.compile_mixed_array <- @, @args
|
@compile_splat_arguments: SplatNode.compile_mixed_array <- @, @args
|
||||||
|
|
||||||
# Tag this invocation as creating a new instance.
|
# Tag this invocation as creating a new instance.
|
||||||
@@ -398,6 +427,8 @@ exports.CallNode: class CallNode extends BaseNode
|
|||||||
meth: "($temp = ${ @variable.source })${ @variable.last }"
|
meth: "($temp = ${ @variable.source })${ @variable.last }"
|
||||||
"${@prefix()}${meth}.apply($obj, ${ @compile_splat_arguments(o) })"
|
"${@prefix()}${meth}.apply($obj, ${ @compile_splat_arguments(o) })"
|
||||||
|
|
||||||
|
children CallNode, 'variable', 'args'
|
||||||
|
|
||||||
#### CurryNode
|
#### CurryNode
|
||||||
|
|
||||||
# Binds a context object and a list of arguments to a function,
|
# Binds a context object and a list of arguments to a function,
|
||||||
@@ -406,7 +437,9 @@ exports.CallNode: class CallNode extends BaseNode
|
|||||||
exports.CurryNode: class CurryNode extends CallNode
|
exports.CurryNode: class CurryNode extends CallNode
|
||||||
|
|
||||||
constructor: (meth, args) ->
|
constructor: (meth, args) ->
|
||||||
@children: flatten [@meth: meth, @context: args[0], @args: (args.slice(1) or [])]
|
@meth: meth
|
||||||
|
@context: args[0]
|
||||||
|
@args: (args.slice(1) or [])
|
||||||
@compile_splat_arguments: SplatNode.compile_mixed_array <- @, @args
|
@compile_splat_arguments: SplatNode.compile_mixed_array <- @, @args
|
||||||
|
|
||||||
arguments: (o) ->
|
arguments: (o) ->
|
||||||
@@ -419,6 +452,7 @@ exports.CurryNode: class CurryNode extends CallNode
|
|||||||
ref: new ValueNode literal utility '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
|
||||||
|
|
||||||
|
children CurryNode, 'meth', 'context', 'args'
|
||||||
|
|
||||||
#### ExtendsNode
|
#### ExtendsNode
|
||||||
|
|
||||||
@@ -428,13 +462,16 @@ exports.CurryNode: class CurryNode extends CallNode
|
|||||||
exports.ExtendsNode: class ExtendsNode extends BaseNode
|
exports.ExtendsNode: class ExtendsNode extends BaseNode
|
||||||
|
|
||||||
constructor: (child, parent) ->
|
constructor: (child, parent) ->
|
||||||
@children: [@child: child, @parent: parent]
|
@child: child
|
||||||
|
@parent: parent
|
||||||
|
|
||||||
# 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 utility 'extends'
|
ref: new ValueNode literal utility 'extends'
|
||||||
(new CallNode ref, [@child, @parent]).compile o
|
(new CallNode ref, [@child, @parent]).compile o
|
||||||
|
|
||||||
|
children ExtendsNode, 'child', 'parent'
|
||||||
|
|
||||||
#### AccessorNode
|
#### AccessorNode
|
||||||
|
|
||||||
# A `.` accessor into a property of a value, or the `::` shorthand for
|
# A `.` accessor into a property of a value, or the `::` shorthand for
|
||||||
@@ -442,7 +479,7 @@ exports.ExtendsNode: class ExtendsNode extends BaseNode
|
|||||||
exports.AccessorNode: class AccessorNode extends BaseNode
|
exports.AccessorNode: class AccessorNode extends BaseNode
|
||||||
|
|
||||||
constructor: (name, tag) ->
|
constructor: (name, tag) ->
|
||||||
@children: [@name: name]
|
@name: name
|
||||||
@prototype:tag is 'prototype'
|
@prototype:tag is 'prototype'
|
||||||
@soak_node: tag is 'soak'
|
@soak_node: tag is 'soak'
|
||||||
this
|
this
|
||||||
@@ -451,19 +488,23 @@ exports.AccessorNode: class AccessorNode extends BaseNode
|
|||||||
proto_part: if @prototype then 'prototype.' else ''
|
proto_part: if @prototype then 'prototype.' else ''
|
||||||
".$proto_part${@name.compile(o)}"
|
".$proto_part${@name.compile(o)}"
|
||||||
|
|
||||||
|
children AccessorNode, 'name'
|
||||||
|
|
||||||
#### IndexNode
|
#### IndexNode
|
||||||
|
|
||||||
# A `[ ... ]` indexed accessor into an array or object.
|
# A `[ ... ]` indexed accessor into an array or object.
|
||||||
exports.IndexNode: class IndexNode extends BaseNode
|
exports.IndexNode: class IndexNode extends BaseNode
|
||||||
|
|
||||||
constructor: (index, tag) ->
|
constructor: (index, tag) ->
|
||||||
@children: [@index: index]
|
@index: index
|
||||||
@soak_node: tag is 'soak'
|
@soak_node: tag is 'soak'
|
||||||
|
|
||||||
compile_node: (o) ->
|
compile_node: (o) ->
|
||||||
idx: @index.compile o
|
idx: @index.compile o
|
||||||
"[$idx]"
|
"[$idx]"
|
||||||
|
|
||||||
|
children IndexNode, 'index'
|
||||||
|
|
||||||
#### RangeNode
|
#### RangeNode
|
||||||
|
|
||||||
# A range literal. Ranges can be used to extract portions (slices) of arrays,
|
# A range literal. Ranges can be used to extract portions (slices) of arrays,
|
||||||
@@ -472,7 +513,8 @@ exports.IndexNode: class IndexNode extends BaseNode
|
|||||||
exports.RangeNode: class RangeNode extends BaseNode
|
exports.RangeNode: class RangeNode extends BaseNode
|
||||||
|
|
||||||
constructor: (from, to, exclusive) ->
|
constructor: (from, to, exclusive) ->
|
||||||
@children: [@from: from, @to: to]
|
@from: from
|
||||||
|
@to: to
|
||||||
@exclusive: !!exclusive
|
@exclusive: !!exclusive
|
||||||
|
|
||||||
# Compiles the range's source variables -- where it starts and where it ends.
|
# Compiles the range's source variables -- where it starts and where it ends.
|
||||||
@@ -505,6 +547,9 @@ exports.RangeNode: class RangeNode extends BaseNode
|
|||||||
arr: Expressions.wrap([new ForNode(body, {source: (new ValueNode(this))}, literal(name))])
|
arr: Expressions.wrap([new ForNode(body, {source: (new ValueNode(this))}, literal(name))])
|
||||||
(new ParentheticalNode(new CallNode(new CodeNode([], arr.make_return())))).compile(o)
|
(new ParentheticalNode(new CallNode(new CodeNode([], arr.make_return())))).compile(o)
|
||||||
|
|
||||||
|
children RangeNode, 'from', 'to'
|
||||||
|
|
||||||
|
|
||||||
#### SliceNode
|
#### SliceNode
|
||||||
|
|
||||||
# An array slice literal. Unlike JavaScript's `Array#slice`, the second parameter
|
# An array slice literal. Unlike JavaScript's `Array#slice`, the second parameter
|
||||||
@@ -513,7 +558,7 @@ exports.RangeNode: class RangeNode extends BaseNode
|
|||||||
exports.SliceNode: class SliceNode extends BaseNode
|
exports.SliceNode: class SliceNode extends BaseNode
|
||||||
|
|
||||||
constructor: (range) ->
|
constructor: (range) ->
|
||||||
@children: [@range: range]
|
@range: range
|
||||||
this
|
this
|
||||||
|
|
||||||
compile_node: (o) ->
|
compile_node: (o) ->
|
||||||
@@ -522,13 +567,15 @@ exports.SliceNode: class SliceNode extends BaseNode
|
|||||||
plus_part: if @range.exclusive then '' else ' + 1'
|
plus_part: if @range.exclusive then '' else ' + 1'
|
||||||
".slice($from, $to$plus_part)"
|
".slice($from, $to$plus_part)"
|
||||||
|
|
||||||
|
children SliceNode, 'range'
|
||||||
|
|
||||||
#### ObjectNode
|
#### ObjectNode
|
||||||
|
|
||||||
# An object literal, nothing fancy.
|
# An object literal, nothing fancy.
|
||||||
exports.ObjectNode: class ObjectNode extends BaseNode
|
exports.ObjectNode: class ObjectNode extends BaseNode
|
||||||
|
|
||||||
constructor: (props) ->
|
constructor: (props) ->
|
||||||
@children: @objects: @properties: props or []
|
@objects: @properties: props or []
|
||||||
|
|
||||||
# All the mucking about with commas is to make sure that CommentNodes and
|
# All the mucking about with commas is to make sure that CommentNodes and
|
||||||
# AssignNodes get interleaved correctly, with no trailing commas or
|
# AssignNodes get interleaved correctly, with no trailing commas or
|
||||||
@@ -548,13 +595,15 @@ exports.ObjectNode: class ObjectNode extends BaseNode
|
|||||||
inner: if props then '\n' + props + '\n' + @idt() else ''
|
inner: if props then '\n' + props + '\n' + @idt() else ''
|
||||||
"{$inner}"
|
"{$inner}"
|
||||||
|
|
||||||
|
children ObjectNode, 'properties'
|
||||||
|
|
||||||
#### ArrayNode
|
#### ArrayNode
|
||||||
|
|
||||||
# An array literal.
|
# An array literal.
|
||||||
exports.ArrayNode: class ArrayNode extends BaseNode
|
exports.ArrayNode: class ArrayNode extends BaseNode
|
||||||
|
|
||||||
constructor: (objects) ->
|
constructor: (objects) ->
|
||||||
@children: @objects: objects or []
|
@objects: objects or []
|
||||||
@compile_splat_literal: SplatNode.compile_mixed_array <- @, @objects
|
@compile_splat_literal: SplatNode.compile_mixed_array <- @, @objects
|
||||||
|
|
||||||
compile_node: (o) ->
|
compile_node: (o) ->
|
||||||
@@ -576,6 +625,8 @@ exports.ArrayNode: class ArrayNode extends BaseNode
|
|||||||
else
|
else
|
||||||
"[$objects]"
|
"[$objects]"
|
||||||
|
|
||||||
|
children ArrayNode, 'objects'
|
||||||
|
|
||||||
#### ClassNode
|
#### ClassNode
|
||||||
|
|
||||||
# The CoffeeScript class definition.
|
# The CoffeeScript class definition.
|
||||||
@@ -584,7 +635,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, props) ->
|
constructor: (variable, parent, props) ->
|
||||||
@children: compact flatten [@variable: variable, @parent: parent, @properties: props or []]
|
@variable: variable
|
||||||
|
@parent: parent
|
||||||
|
@properties: props or []
|
||||||
@returns: false
|
@returns: false
|
||||||
|
|
||||||
make_return: ->
|
make_return: ->
|
||||||
@@ -628,6 +681,7 @@ exports.ClassNode: class ClassNode extends BaseNode
|
|||||||
"$construct$extension$props$returns"
|
"$construct$extension$props$returns"
|
||||||
|
|
||||||
statement ClassNode
|
statement ClassNode
|
||||||
|
children ClassNode, 'variable', 'parent', 'properties'
|
||||||
|
|
||||||
#### AssignNode
|
#### AssignNode
|
||||||
|
|
||||||
@@ -640,7 +694,8 @@ exports.AssignNode: class AssignNode extends BaseNode
|
|||||||
LEADING_DOT: /^\.(prototype\.)?/
|
LEADING_DOT: /^\.(prototype\.)?/
|
||||||
|
|
||||||
constructor: (variable, value, context) ->
|
constructor: (variable, value, context) ->
|
||||||
@children: [@variable: variable, @value: value]
|
@variable: variable
|
||||||
|
@value: value
|
||||||
@context: context
|
@context: context
|
||||||
|
|
||||||
top_sensitive: ->
|
top_sensitive: ->
|
||||||
@@ -727,6 +782,8 @@ exports.AssignNode: class AssignNode extends BaseNode
|
|||||||
val: @value.compile(o)
|
val: @value.compile(o)
|
||||||
"${name}.splice.apply($name, [$from, $to].concat($val))"
|
"${name}.splice.apply($name, [$from, $to].concat($val))"
|
||||||
|
|
||||||
|
children AssignNode, 'variable', 'value'
|
||||||
|
|
||||||
#### CodeNode
|
#### CodeNode
|
||||||
|
|
||||||
# A function definition. This is the only node that creates a new Scope.
|
# A function definition. This is the only node that creates a new Scope.
|
||||||
@@ -781,21 +838,17 @@ exports.CodeNode: class CodeNode extends BaseNode
|
|||||||
top_sensitive: ->
|
top_sensitive: ->
|
||||||
true
|
true
|
||||||
|
|
||||||
# When traversing (for printing or inspecting), return the real children of
|
# Short-circuit _traverse_children method to prevent it from crossing scope boundaries
|
||||||
# the function -- the parameters and body of expressions.
|
# unless cross_scope is true
|
||||||
real_children: ->
|
_traverse_children: (cross_scope, func) -> super(cross_scope, func) if cross_scope
|
||||||
flatten [@params, @body.expressions]
|
|
||||||
|
|
||||||
# Custom `traverse` implementation that uses the `real_children`.
|
|
||||||
traverse: (block) ->
|
|
||||||
block this
|
|
||||||
child.traverse block for child in @real_children()
|
|
||||||
|
|
||||||
toString: (idt) ->
|
toString: (idt) ->
|
||||||
idt: or ''
|
idt: or ''
|
||||||
children: (child.toString(idt + TAB) for child in @real_children()).join('')
|
children: (child.toString(idt + TAB) for child in @children()).join('')
|
||||||
"\n$idt$children"
|
"\n$idt$children"
|
||||||
|
|
||||||
|
children CodeNode, 'params', 'body'
|
||||||
|
|
||||||
#### SplatNode
|
#### SplatNode
|
||||||
|
|
||||||
# A splat, either as a parameter to a function, an argument to a call,
|
# A splat, either as a parameter to a function, an argument to a call,
|
||||||
@@ -804,7 +857,7 @@ exports.SplatNode: class SplatNode extends BaseNode
|
|||||||
|
|
||||||
constructor: (name) ->
|
constructor: (name) ->
|
||||||
name: literal(name) unless name.compile
|
name: literal(name) unless name.compile
|
||||||
@children: [@name: name]
|
@name: name
|
||||||
|
|
||||||
compile_node: (o) ->
|
compile_node: (o) ->
|
||||||
if @index? then @compile_param(o) else @name.compile(o)
|
if @index? then @compile_param(o) else @name.compile(o)
|
||||||
@@ -847,6 +900,8 @@ exports.SplatNode: class SplatNode extends BaseNode
|
|||||||
i: + 1
|
i: + 1
|
||||||
args.join('')
|
args.join('')
|
||||||
|
|
||||||
|
children SplatNode, 'name'
|
||||||
|
|
||||||
#### WhileNode
|
#### WhileNode
|
||||||
|
|
||||||
# A while loop, the only sort of low-level loop exposed by CoffeeScript. From
|
# A while loop, the only sort of low-level loop exposed by CoffeeScript. From
|
||||||
@@ -856,11 +911,11 @@ exports.WhileNode: class WhileNode extends BaseNode
|
|||||||
|
|
||||||
constructor: (condition, opts) ->
|
constructor: (condition, opts) ->
|
||||||
condition: new OpNode('!', condition) if opts and opts.invert
|
condition: new OpNode('!', condition) if opts and opts.invert
|
||||||
@children:[@condition: condition]
|
@condition: condition
|
||||||
@guard: opts and opts.guard
|
@guard: opts and opts.guard
|
||||||
|
|
||||||
add_body: (body) ->
|
add_body: (body) ->
|
||||||
@children.push @body: body
|
@body: body
|
||||||
this
|
this
|
||||||
|
|
||||||
make_return: ->
|
make_return: ->
|
||||||
@@ -893,6 +948,7 @@ exports.WhileNode: class WhileNode extends BaseNode
|
|||||||
"$pre {\n${ @body.compile(o) }\n$@tab}\n$post"
|
"$pre {\n${ @body.compile(o) }\n$@tab}\n$post"
|
||||||
|
|
||||||
statement WhileNode
|
statement WhileNode
|
||||||
|
children WhileNode, 'condition', 'guard', 'body'
|
||||||
|
|
||||||
#### OpNode
|
#### OpNode
|
||||||
|
|
||||||
@@ -918,7 +974,8 @@ exports.OpNode: class OpNode extends BaseNode
|
|||||||
|
|
||||||
constructor: (operator, first, second, flip) ->
|
constructor: (operator, first, second, flip) ->
|
||||||
@constructor.name: + ' ' + operator
|
@constructor.name: + ' ' + operator
|
||||||
@children: compact [@first: first, @second: second]
|
@first: first
|
||||||
|
@second: second
|
||||||
@operator: @CONVERSIONS[operator] or operator
|
@operator: @CONVERSIONS[operator] or operator
|
||||||
@flip: !!flip
|
@flip: !!flip
|
||||||
|
|
||||||
@@ -970,13 +1027,17 @@ exports.OpNode: class OpNode extends BaseNode
|
|||||||
parts: parts.reverse() if @flip
|
parts: parts.reverse() if @flip
|
||||||
parts.join('')
|
parts.join('')
|
||||||
|
|
||||||
|
children OpNode, 'first', 'second'
|
||||||
|
|
||||||
#### TryNode
|
#### TryNode
|
||||||
|
|
||||||
# A classic *try/catch/finally* block.
|
# A classic *try/catch/finally* block.
|
||||||
exports.TryNode: class TryNode extends BaseNode
|
exports.TryNode: class TryNode extends BaseNode
|
||||||
|
|
||||||
constructor: (attempt, error, recovery, ensure) ->
|
constructor: (attempt, error, recovery, ensure) ->
|
||||||
@children: compact [@attempt: attempt, @recovery: recovery, @ensure: ensure]
|
@attempt: attempt
|
||||||
|
@recovery: recovery
|
||||||
|
@ensure: ensure
|
||||||
@error: error
|
@error: error
|
||||||
this
|
this
|
||||||
|
|
||||||
@@ -997,6 +1058,7 @@ exports.TryNode: class TryNode extends BaseNode
|
|||||||
"${@tab}try {\n$attempt_part\n$@tab}$catch_part$finally_part"
|
"${@tab}try {\n$attempt_part\n$@tab}$catch_part$finally_part"
|
||||||
|
|
||||||
statement TryNode
|
statement TryNode
|
||||||
|
children TryNode, 'attempt', 'recovery', 'ensure'
|
||||||
|
|
||||||
#### ThrowNode
|
#### ThrowNode
|
||||||
|
|
||||||
@@ -1004,7 +1066,7 @@ statement TryNode
|
|||||||
exports.ThrowNode: class ThrowNode extends BaseNode
|
exports.ThrowNode: class ThrowNode extends BaseNode
|
||||||
|
|
||||||
constructor: (expression) ->
|
constructor: (expression) ->
|
||||||
@children: [@expression: expression]
|
@expression: expression
|
||||||
|
|
||||||
# A **ThrowNode** is already a return, of sorts...
|
# A **ThrowNode** is already a return, of sorts...
|
||||||
make_return: ->
|
make_return: ->
|
||||||
@@ -1014,6 +1076,7 @@ exports.ThrowNode: class ThrowNode extends BaseNode
|
|||||||
"${@tab}throw ${@expression.compile(o)};"
|
"${@tab}throw ${@expression.compile(o)};"
|
||||||
|
|
||||||
statement ThrowNode
|
statement ThrowNode
|
||||||
|
children ThrowNode, 'expression'
|
||||||
|
|
||||||
#### ExistenceNode
|
#### ExistenceNode
|
||||||
|
|
||||||
@@ -1023,7 +1086,7 @@ statement ThrowNode
|
|||||||
exports.ExistenceNode: class ExistenceNode extends BaseNode
|
exports.ExistenceNode: class ExistenceNode extends BaseNode
|
||||||
|
|
||||||
constructor: (expression) ->
|
constructor: (expression) ->
|
||||||
@children: [@expression: expression]
|
@expression: expression
|
||||||
|
|
||||||
compile_node: (o) ->
|
compile_node: (o) ->
|
||||||
ExistenceNode.compile_test(o, @expression)
|
ExistenceNode.compile_test(o, @expression)
|
||||||
@@ -1038,6 +1101,8 @@ exports.ExistenceNode: class ExistenceNode extends BaseNode
|
|||||||
[first, second]: [first.compile(o), second.compile(o)]
|
[first, second]: [first.compile(o), second.compile(o)]
|
||||||
"(typeof $first !== \"undefined\" && $second !== null)"
|
"(typeof $first !== \"undefined\" && $second !== null)"
|
||||||
|
|
||||||
|
children ExistenceNode, 'expression'
|
||||||
|
|
||||||
#### ParentheticalNode
|
#### ParentheticalNode
|
||||||
|
|
||||||
# An extra set of parentheses, specified explicitly in the source. At one time
|
# An extra set of parentheses, specified explicitly in the source. At one time
|
||||||
@@ -1048,7 +1113,7 @@ exports.ExistenceNode: class ExistenceNode extends BaseNode
|
|||||||
exports.ParentheticalNode: class ParentheticalNode extends BaseNode
|
exports.ParentheticalNode: class ParentheticalNode extends BaseNode
|
||||||
|
|
||||||
constructor: (expression) ->
|
constructor: (expression) ->
|
||||||
@children: [@expression: expression]
|
@expression: expression
|
||||||
|
|
||||||
is_statement: ->
|
is_statement: ->
|
||||||
@expression.is_statement()
|
@expression.is_statement()
|
||||||
@@ -1063,6 +1128,8 @@ exports.ParentheticalNode: class ParentheticalNode extends BaseNode
|
|||||||
code: code.substr(o, l-1) if code.substr(l-1, 1) is ';'
|
code: code.substr(o, l-1) if code.substr(l-1, 1) is ';'
|
||||||
if @expression instanceof AssignNode then code else "($code)"
|
if @expression instanceof AssignNode then code else "($code)"
|
||||||
|
|
||||||
|
children ParentheticalNode, 'expression'
|
||||||
|
|
||||||
#### ForNode
|
#### ForNode
|
||||||
|
|
||||||
# CoffeeScript's replacement for the *for* loop is our array and object
|
# CoffeeScript's replacement for the *for* loop is our array and object
|
||||||
@@ -1085,7 +1152,6 @@ exports.ForNode: class ForNode extends BaseNode
|
|||||||
[@name, @index]: [@index, @name] if @object
|
[@name, @index]: [@index, @name] if @object
|
||||||
@pattern: @name instanceof ValueNode
|
@pattern: @name instanceof ValueNode
|
||||||
throw new Error('index cannot be a pattern matching expression') if @index instanceof ValueNode
|
throw new Error('index cannot be a pattern matching expression') if @index instanceof ValueNode
|
||||||
@children: compact [@body, @source, @guard]
|
|
||||||
@returns: false
|
@returns: false
|
||||||
|
|
||||||
top_sensitive: ->
|
top_sensitive: ->
|
||||||
@@ -1146,6 +1212,7 @@ exports.ForNode: class ForNode extends BaseNode
|
|||||||
"$set_result${source_part}for ($for_part) {\n$var_part$body\n$@tab$close$return_result"
|
"$set_result${source_part}for ($for_part) {\n$var_part$body\n$@tab$close$return_result"
|
||||||
|
|
||||||
statement ForNode
|
statement ForNode
|
||||||
|
children ForNode, 'body', 'source', 'guard'
|
||||||
|
|
||||||
#### IfNode
|
#### IfNode
|
||||||
|
|
||||||
@@ -1160,15 +1227,11 @@ exports.IfNode: class IfNode extends BaseNode
|
|||||||
@condition: condition
|
@condition: condition
|
||||||
@body: body
|
@body: body
|
||||||
@else_body: null
|
@else_body: null
|
||||||
@populate_children()
|
|
||||||
@tags: tags or {}
|
@tags: tags or {}
|
||||||
@multiple: true if @condition instanceof Array
|
@multiple: true if @condition instanceof Array
|
||||||
@condition: new OpNode('!', new ParentheticalNode(@condition)) if @tags.invert
|
@condition: new OpNode('!', new ParentheticalNode(@condition)) if @tags.invert
|
||||||
@is_chain: false
|
@is_chain: false
|
||||||
|
|
||||||
populate_children: ->
|
|
||||||
@children: compact flatten [@condition, @body, @else_body]
|
|
||||||
|
|
||||||
body_node: -> @body?.unwrap()
|
body_node: -> @body?.unwrap()
|
||||||
else_body_node: -> @else_body?.unwrap()
|
else_body_node: -> @else_body?.unwrap()
|
||||||
|
|
||||||
@@ -1185,17 +1248,16 @@ exports.IfNode: class IfNode extends BaseNode
|
|||||||
# Rewrite a chain of **IfNodes** with their switch condition for equality.
|
# Rewrite a chain of **IfNodes** with their switch condition for equality.
|
||||||
# Ensure that the switch expression isn't evaluated more than once.
|
# Ensure that the switch expression isn't evaluated more than once.
|
||||||
rewrite_switch: (o) ->
|
rewrite_switch: (o) ->
|
||||||
assigner: @switch_subject
|
@assigner: @switch_subject
|
||||||
unless (@switch_subject.unwrap() instanceof LiteralNode)
|
unless (@switch_subject.unwrap() instanceof LiteralNode)
|
||||||
variable: literal(o.scope.free_variable())
|
variable: literal(o.scope.free_variable())
|
||||||
assigner: new AssignNode(variable, @switch_subject)
|
@assigner: new AssignNode(variable, @switch_subject)
|
||||||
@children.push(assigner)
|
|
||||||
@switch_subject: variable
|
@switch_subject: variable
|
||||||
@condition: if @multiple
|
@condition: if @multiple
|
||||||
for cond, i in @condition
|
for cond, i in @condition
|
||||||
new OpNode('==', (if i is 0 then assigner else @switch_subject), cond)
|
new OpNode('==', (if i is 0 then @assigner else @switch_subject), cond)
|
||||||
else
|
else
|
||||||
new OpNode('==', assigner, @condition)
|
new OpNode('==', @assigner, @condition)
|
||||||
@else_body_node().switches_over(@switch_subject) if @is_chain
|
@else_body_node().switches_over(@switch_subject) if @is_chain
|
||||||
# prevent this rewrite from happening again
|
# prevent this rewrite from happening again
|
||||||
@switch_subject: undefined
|
@switch_subject: undefined
|
||||||
@@ -1208,7 +1270,6 @@ exports.IfNode: class IfNode extends BaseNode
|
|||||||
else
|
else
|
||||||
@is_chain: else_body instanceof IfNode
|
@is_chain: else_body instanceof IfNode
|
||||||
@else_body: @ensure_expressions else_body
|
@else_body: @ensure_expressions else_body
|
||||||
@populate_children()
|
|
||||||
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
|
||||||
@@ -1257,6 +1318,10 @@ exports.IfNode: class IfNode extends BaseNode
|
|||||||
else_part: if @else_body then @else_body_node().compile(o) else 'null'
|
else_part: if @else_body then @else_body_node().compile(o) else 'null'
|
||||||
"$if_part : $else_part"
|
"$if_part : $else_part"
|
||||||
|
|
||||||
|
|
||||||
|
children IfNode, 'condition', 'body', 'else_body', 'assigner'
|
||||||
|
|
||||||
|
|
||||||
# Faux-Nodes
|
# Faux-Nodes
|
||||||
# ----------
|
# ----------
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user