mirror of
https://github.com/josdejong/mathjs.git
synced 2026-01-18 14:59:29 +00:00
Created Node.map, changed traverse to use Node.map
This commit is contained in:
parent
20c96894ab
commit
a1f60db0d1
@ -52,26 +52,36 @@ ArrayNode.prototype._compile = function (defs) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Recursively execute a callback for each of the child nodes of this node
|
||||
* @param {function(Node, string, Node)} callback
|
||||
* @private
|
||||
* Execute a callback for each of the child nodes of this node
|
||||
* @param {function(child: Node, path: string, parent: Node)} callback
|
||||
*/
|
||||
ArrayNode.prototype._traverse = function (callback) {
|
||||
ArrayNode.prototype.forEach = function (callback) {
|
||||
for (var i = 0; i < this.nodes.length; i++) {
|
||||
var node = this.nodes[i];
|
||||
callback(node, 'nodes.' + i, this);
|
||||
node._traverse(callback);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a clone of this node
|
||||
* Create a new ArrayNode having it's childs be the results of calling
|
||||
* the provided callback function for each of the childs of the original node.
|
||||
* @param {function(child: Node, path: string, parent: Node): Node} callback
|
||||
* @returns {ArrayNode} Returns a transformed copy of the node
|
||||
*/
|
||||
ArrayNode.prototype.map = function (callback) {
|
||||
var nodes = [];
|
||||
for (var i = 0; i < this.nodes.length; i++) {
|
||||
nodes[i] = callback(this.nodes[i], 'nodes.' + i, this);
|
||||
}
|
||||
return new ArrayNode(nodes);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a clone of this node, a shallow copy
|
||||
* @return {ArrayNode}
|
||||
*/
|
||||
ArrayNode.prototype.clone = function() {
|
||||
return new ArrayNode(this.nodes.map(function(node) {
|
||||
return node.clone();
|
||||
}))
|
||||
return new ArrayNode(this.nodes.slice(0))
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -47,21 +47,29 @@ AssignmentNode.prototype._compile = function (defs) {
|
||||
|
||||
|
||||
/**
|
||||
* Recursively execute a callback for each of the child nodes of this node
|
||||
* @param {function(Node, string, Node)} callback
|
||||
* @private
|
||||
* Execute a callback for each of the child nodes of this node
|
||||
* @param {function(child: Node, path: string, parent: Node)} callback
|
||||
*/
|
||||
AssignmentNode.prototype._traverse = function (callback) {
|
||||
AssignmentNode.prototype.forEach = function (callback) {
|
||||
callback(this.expr, 'expr', this);
|
||||
this.expr._traverse(callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a clone of this node
|
||||
* Create a new AssignmentNode having it's childs be the results of calling
|
||||
* the provided callback function for each of the childs of the original node.
|
||||
* @param {function(child: Node, path: string, parent: Node): Node} callback
|
||||
* @returns {AssignmentNode} Returns a transformed copy of the node
|
||||
*/
|
||||
AssignmentNode.prototype.map = function (callback) {
|
||||
return new AssignmentNode(this.name, callback(this.expr, 'expr', this));
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a clone of this node, a shallow copy
|
||||
* @return {AssignmentNode}
|
||||
*/
|
||||
AssignmentNode.prototype.clone = function() {
|
||||
return new AssignmentNode(this.name, this.expr.clone());
|
||||
return new AssignmentNode(this.name, this.expr);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -66,26 +66,41 @@ BlockNode.prototype._compile = function (defs) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Recursively execute a callback for each of the child blocks of this node
|
||||
* @param {function(Node, string, Node)} callback
|
||||
* @private
|
||||
* Execute a callback for each of the child blocks of this node
|
||||
* @param {function(child: Node, path: string, parent: Node)} callback
|
||||
*/
|
||||
BlockNode.prototype._traverse = function (callback) {
|
||||
BlockNode.prototype.forEach = function (callback) {
|
||||
for (var i = 0; i < this.blocks.length; i++) {
|
||||
var node = this.blocks[i].node;
|
||||
callback(node, 'blocks.' + i + '.node', this);
|
||||
node._traverse(callback);
|
||||
callback(this.blocks[i].node, 'blocks.' + i + '.node', this);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a clone of this node
|
||||
* Create a new BlockNode having it's childs be the results of calling
|
||||
* the provided callback function for each of the childs of the original node.
|
||||
* @param {function(child: Node, path: string, parent: Node): Node} callback
|
||||
* @returns {BlockNode} Returns a transformed copy of the node
|
||||
*/
|
||||
BlockNode.prototype.map = function (callback) {
|
||||
var blocks = [];
|
||||
for (var i = 0; i < this.blocks.length; i++) {
|
||||
var block = this.blocks[i];
|
||||
blocks[i] = {
|
||||
node: callback(block.node, 'blocks.' + i + '.node', this),
|
||||
visible: block.visible
|
||||
};
|
||||
}
|
||||
return new BlockNode(blocks);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a clone of this node, a shallow copy
|
||||
* @return {BlockNode}
|
||||
*/
|
||||
BlockNode.prototype.clone = function() {
|
||||
var blocks = this.blocks.map(function(block) {
|
||||
return {
|
||||
node: block.node.clone(),
|
||||
node: block.node,
|
||||
visible: block.visible
|
||||
};
|
||||
});
|
||||
|
||||
@ -83,27 +83,35 @@ ConditionalNode.prototype._compile = function(defs) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Recursively execute a callback for each of the child nodes of this node
|
||||
* @param {function(Node, string, Node)} callback
|
||||
* @private
|
||||
* Execute a callback for each of the child nodes of this node
|
||||
* @param {function(child: Node, path: string, parent: Node)} callback
|
||||
*/
|
||||
ConditionalNode.prototype._traverse = function (callback) {
|
||||
ConditionalNode.prototype.forEach = function (callback) {
|
||||
callback(this.condition, 'condition', this);
|
||||
this.condition._traverse(callback);
|
||||
|
||||
callback(this.trueExpr, 'trueExpr', this);
|
||||
this.trueExpr._traverse(callback);
|
||||
|
||||
callback(this.falseExpr, 'falseExpr', this);
|
||||
this.falseExpr._traverse(callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a clone of this node
|
||||
* Create a new ConditionalNode having it's childs be the results of calling
|
||||
* the provided callback function for each of the childs of the original node.
|
||||
* @param {function(child: Node, path: string, parent: Node): Node} callback
|
||||
* @returns {ConditionalNode} Returns a transformed copy of the node
|
||||
*/
|
||||
ConditionalNode.prototype.map = function (callback) {
|
||||
return new ConditionalNode(
|
||||
callback(this.condition, 'condition', this),
|
||||
callback(this.trueExpr, 'trueExpr', this),
|
||||
callback(this.falseExpr, 'falseExpr', this)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a clone of this node, a shallow copy
|
||||
* @return {ConditionalNode}
|
||||
*/
|
||||
ConditionalNode.prototype.clone = function() {
|
||||
return new ConditionalNode(this.condition.clone(), this.trueExpr.clone(), this.falseExpr.clone());
|
||||
return new ConditionalNode(this.condition, this.trueExpr, this.falseExpr);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -115,15 +115,25 @@ ConstantNode.prototype._compile = function (defs) {
|
||||
|
||||
/**
|
||||
* Execute a callback for each of the child nodes of this node
|
||||
* @param {function(Node, string, Node)} callback
|
||||
* @private
|
||||
* @param {function(child: Node, path: string, parent: Node)} callback
|
||||
*/
|
||||
ConstantNode.prototype._traverse = function (callback) {
|
||||
ConstantNode.prototype.forEach = function (callback) {
|
||||
// nothing to do, we don't have childs
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* Create a clone of this node
|
||||
* Create a new ConstantNode having it's childs be the results of calling
|
||||
* the provided callback function for each of the childs of the original node.
|
||||
* @param {function(child: Node, path: string, parent: Node) : Node} callback
|
||||
* @returns {ConstantNode} Returns a clone of the node
|
||||
*/
|
||||
ConstantNode.prototype.map = function (callback) {
|
||||
return this.clone();
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a clone of this node, a shallow copy
|
||||
* @return {ConstantNode}
|
||||
*/
|
||||
ConstantNode.prototype.clone = function() {
|
||||
|
||||
@ -64,21 +64,32 @@ FunctionAssignmentNode.prototype._compile = function (defs) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Recursively execute a callback for each of the child nodes of this node
|
||||
* @param {function(Node, string, Node)} callback
|
||||
* Execute a callback for each of the child nodes of this node
|
||||
* @param {function(child: Node, path: string, parent: Node)} callback
|
||||
* @private
|
||||
*/
|
||||
FunctionAssignmentNode.prototype._traverse = function (callback) {
|
||||
FunctionAssignmentNode.prototype.forEach = function (callback) {
|
||||
callback(this.expr, 'expr', this);
|
||||
this.expr._traverse(callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a clone of this node
|
||||
* Create a new FunctionAssignmentNode having it's childs be the results of calling
|
||||
* the provided callback function for each of the childs of the original node.
|
||||
* @param {function(child: Node, path: string, parent: Node): Node} callback
|
||||
* @returns {FunctionAssignmentNode} Returns a transformed copy of the node
|
||||
*/
|
||||
FunctionAssignmentNode.prototype.map = function (callback) {
|
||||
var expr = callback(this.expr, 'expr', this);
|
||||
|
||||
return new FunctionAssignmentNode(this.name, this.params.slice(0), expr);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a clone of this node, a shallow copy
|
||||
* @return {FunctionAssignmentNode}
|
||||
*/
|
||||
FunctionAssignmentNode.prototype.clone = function() {
|
||||
return new FunctionAssignmentNode(this.name, this.params.concat(), this.expr.clone());
|
||||
return new FunctionAssignmentNode(this.name, this.params.slice(0), this.expr);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -46,8 +46,8 @@ FunctionNode.prototype._compile = function (defs) {
|
||||
var isRaw = (typeof fn === 'function') && (fn.rawArgs == true);
|
||||
|
||||
// compile the parameters
|
||||
var args = this.args.map(function (param) {
|
||||
return param._compile(defs);
|
||||
var args = this.args.map(function (arg) {
|
||||
return arg._compile(defs);
|
||||
});
|
||||
|
||||
if (isRaw) {
|
||||
@ -71,27 +71,35 @@ FunctionNode.prototype._compile = function (defs) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Recursively execute a callback for each of the child nodes of this node
|
||||
* @param {function(Node, string, Node)} callback
|
||||
* @private
|
||||
* Execute a callback for each of the child nodes of this node
|
||||
* @param {function(child: Node, path: string, parent: Node)} callback
|
||||
*/
|
||||
FunctionNode.prototype._traverse = function (callback) {
|
||||
// args
|
||||
FunctionNode.prototype.forEach = function (callback) {
|
||||
for (var i = 0; i < this.args.length; i++) {
|
||||
var param = this.args[i];
|
||||
callback(param, 'args.' + i, this);
|
||||
param._traverse(callback);
|
||||
callback(this.args[i], 'args.' + i, this);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a clone of this node
|
||||
* Create a new FunctionNode having it's childs be the results of calling
|
||||
* the provided callback function for each of the childs of the original node.
|
||||
* @param {function(child: Node, path: string, parent: Node): Node} callback
|
||||
* @returns {FunctionNode} Returns a transformed copy of the node
|
||||
*/
|
||||
FunctionNode.prototype.map = function (callback) {
|
||||
var args = [];
|
||||
for (var i = 0; i < this.args.length; i++) {
|
||||
args[i] = callback(this.args[i], 'args.' + i, this);
|
||||
}
|
||||
return new FunctionNode(this.name, args);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a clone of this node, a shallow copy
|
||||
* @return {FunctionNode}
|
||||
*/
|
||||
FunctionNode.prototype.clone = function() {
|
||||
return new FunctionNode(this.name, this.args.map(function (param) {
|
||||
return param.clone();
|
||||
}));
|
||||
return new FunctionNode(this.name, this.args.slice(0));
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -152,23 +152,36 @@ IndexNode.prototype.compileSubset = function(defs, replacement) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Recursively execute a callback for each of the child nodes of this node
|
||||
* @param {function(Node, string, Node)} callback
|
||||
* @private
|
||||
* Execute a callback for each of the child nodes of this node
|
||||
* @param {function(child: Node, path: string, parent: Node)} callback
|
||||
*/
|
||||
IndexNode.prototype._traverse = function (callback) {
|
||||
IndexNode.prototype.forEach = function (callback) {
|
||||
// object
|
||||
callback(this.object, 'object', this);
|
||||
this.object._traverse(callback);
|
||||
|
||||
// ranges
|
||||
for (var i = 0; i < this.ranges.length; i++) {
|
||||
var range = this.ranges[i];
|
||||
callback(range, 'ranges.' + i, this);
|
||||
range._traverse(callback);
|
||||
callback(this.ranges[i], 'ranges.' + i, this);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new IndexNode having it's childs be the results of calling
|
||||
* the provided callback function for each of the childs of the original node.
|
||||
* @param {function(child: Node, path: string, parent: Node): Node} callback
|
||||
* @returns {IndexNode} Returns a transformed copy of the node
|
||||
*/
|
||||
IndexNode.prototype.map = function (callback) {
|
||||
var object = callback(this.object, 'object', this);
|
||||
|
||||
var ranges = [];
|
||||
for (var i = 0; i < this.ranges.length; i++) {
|
||||
ranges[i] = callback(this.ranges[i], 'ranges.' + i, this);
|
||||
}
|
||||
|
||||
return new IndexNode(object, ranges);
|
||||
};
|
||||
|
||||
/**
|
||||
* Get the name of the object linked to this IndexNode
|
||||
* @return {string} name
|
||||
@ -178,13 +191,11 @@ IndexNode.prototype.objectName = function() {
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a clone of this node
|
||||
* Create a clone of this node, a shallow copy
|
||||
* @return {IndexNode}
|
||||
*/
|
||||
IndexNode.prototype.clone = function() {
|
||||
return new IndexNode(this.object.clone(), this.ranges.map(function (range) {
|
||||
return range.clone();
|
||||
}));
|
||||
return new IndexNode(this.object, this.ranges.slice(0));
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -76,38 +76,59 @@ Node.prototype._compile = function (defs) {
|
||||
|
||||
/**
|
||||
* Execute a callback for each of the child nodes of this node
|
||||
* @param {function(Node, string, Node)} callback
|
||||
* @param {function(child: Node, path: string, parent: Node)} callback
|
||||
* @private
|
||||
*/
|
||||
Node.prototype._traverse = function (callback) {
|
||||
// must be implemented by each of the Node implementations having child nodes
|
||||
throw new Error('Cannot traverse a Node interface');
|
||||
Node.prototype.forEach = function (callback) {
|
||||
// must be implemented by each of the Node implementations
|
||||
throw new Error('Cannot run forEach on a Node interface');
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new Node having it's childs be the results of calling
|
||||
* the provided callback function for each of the childs of the original node.
|
||||
* @param {function(child: Node, path: string, parent: Node): Node} callback
|
||||
* @returns {OperatorNode} Returns a transformed copy of the node
|
||||
*/
|
||||
Node.prototype.map = function (callback) {
|
||||
// must be implemented by each of the Node implementations
|
||||
throw new Error('Cannot run map on a Node interface');
|
||||
};
|
||||
|
||||
/**
|
||||
* Recursively traverse all nodes in a node tree. Executes given callback for
|
||||
* this node and each of its child nodes. Similar to Array.forEach, except
|
||||
* recursive.
|
||||
* @param {function(Node, string, Node)} callback
|
||||
* this node and each of its child nodes.
|
||||
* @param {function(node: Node, path: string, parent: Node)} callback
|
||||
* A callback called for every node in the node tree.
|
||||
* Signature: callback(node: Node, index: string, parent: Node) : Node
|
||||
*/
|
||||
Node.prototype.traverse = function (callback) {
|
||||
// execute callback for itself
|
||||
callback(this, null, null);
|
||||
|
||||
// traverse over all children
|
||||
// recursively traverse over all childs
|
||||
this._traverse(callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Transform a node tree via a transform function. Similar to Array.map,
|
||||
* but recursively executed on all nodes in the node tree.
|
||||
* Recursively traverse all childs of this node
|
||||
* @param {function(node: Node, path: string, parent: Node)} callback
|
||||
* A callback called for every node in the node tree.
|
||||
* @private
|
||||
*/
|
||||
Node.prototype._traverse = function (callback) {
|
||||
this.forEach(function(child, path, parent) {
|
||||
callback(child, path, parent);
|
||||
child._traverse(callback);
|
||||
});
|
||||
};
|
||||
|
||||
/**
|
||||
* Recursively transform a node tree via a transform function.
|
||||
*
|
||||
* For example, to replace all nodes of type SymbolNode having name 'x' with a
|
||||
* ConstantNode with value 2:
|
||||
*
|
||||
* var res = Node.transform(function (node) {
|
||||
* var res = Node.transform(function (node, path, parent) {
|
||||
* if (node instanceof SymbolNode) && (node.name == 'x')) {
|
||||
* return new ConstantNode(2);
|
||||
* }
|
||||
@ -116,7 +137,7 @@ Node.prototype.traverse = function (callback) {
|
||||
* }
|
||||
* });
|
||||
*
|
||||
* @param {function(Node, string, Node)} callback
|
||||
* @param {function(node: Node, path: string, parent: Node) : Node} callback
|
||||
* A mapping function accepting a node, and returning
|
||||
* a replacement for the node or the original node.
|
||||
* Signature: callback(node: Node, index: string, parent: Node) : Node
|
||||
@ -124,30 +145,33 @@ Node.prototype.traverse = function (callback) {
|
||||
*/
|
||||
Node.prototype.transform = function (callback) {
|
||||
// check itself
|
||||
var res = callback(this, null, null);
|
||||
|
||||
if (res === this) {
|
||||
// recurse over the child nodes
|
||||
res._traverse(function (node, index, parent) {
|
||||
var replacement = callback(node, index, parent);
|
||||
if (index.indexOf('.') !== -1) {
|
||||
// traverse path
|
||||
var props = index.split('.');
|
||||
var obj = parent;
|
||||
while (props.length > 1) {
|
||||
obj = obj[props.shift()];
|
||||
}
|
||||
obj[props.shift()] = replacement;
|
||||
}
|
||||
else {
|
||||
parent[index] = replacement;
|
||||
}
|
||||
});
|
||||
var replacement = callback(this, null, null);
|
||||
if (replacement !== this) {
|
||||
return replacement;
|
||||
}
|
||||
|
||||
return res;
|
||||
// traverse over all childs
|
||||
return this._transform(callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Recursively transform all childs of this node
|
||||
* @param {function(node: Node, path: string, parent: Node) : Node} callback
|
||||
* A mapping function accepting a node, and returning
|
||||
* a replacement for the node or the original node.
|
||||
* Signature: callback(node: Node, index: string, parent: Node) : Node
|
||||
* @return {Node} Returns the original node or its replacement
|
||||
* @private
|
||||
*/
|
||||
Node.prototype._transform = function (callback) {
|
||||
return this.map(function(child, path, parent) {
|
||||
var replacement = callback(child, path, parent);
|
||||
return (replacement !== child) ? replacement : child._transform(callback);
|
||||
});
|
||||
};
|
||||
|
||||
// TODO: create map and forEach
|
||||
|
||||
/**
|
||||
* Find any node in the node tree matching given filter function. For example, to
|
||||
* find all nodes of type SymbolNode having name 'x':
|
||||
@ -184,11 +208,12 @@ Node.prototype.match = function () {
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a clone of this node
|
||||
* Create a clone of this node, a shallow copy
|
||||
* @return {Node}
|
||||
*/
|
||||
Node.prototype.clone = function() {
|
||||
return new Node();
|
||||
// must be implemented by each of the Node implementations
|
||||
throw new Error('Cannot clone a Node interface');
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -43,33 +43,42 @@ OperatorNode.prototype._compile = function (defs) {
|
||||
throw new Error('Function ' + this.fn + ' missing in provided namespace "math"');
|
||||
}
|
||||
|
||||
var args = this.args.map(function (param) {
|
||||
return param._compile(defs);
|
||||
var args = this.args.map(function (arg) {
|
||||
return arg._compile(defs);
|
||||
});
|
||||
return 'math.' + this.fn + '(' + args.join(', ') + ')';
|
||||
};
|
||||
|
||||
/**
|
||||
* Recursively execute a callback for each of the child nodes of this node
|
||||
* @param {function(Node, string, Node)} callback
|
||||
* @private
|
||||
* Execute a callback for each of the child nodes of this node
|
||||
* @param {function(child: Node, path: string, parent: Node)} callback
|
||||
*/
|
||||
OperatorNode.prototype._traverse = function (callback) {
|
||||
OperatorNode.prototype.forEach = function (callback) {
|
||||
for (var i = 0; i < this.args.length; i++) {
|
||||
var param = this.args[i];
|
||||
callback(param, 'args.' + i, this);
|
||||
param._traverse(callback);
|
||||
callback(this.args[i], 'args.' + i, this);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a clone of this node
|
||||
* Create a new OperatorNode having it's childs be the results of calling
|
||||
* the provided callback function for each of the childs of the original node.
|
||||
* @param {function(child: Node, path: string, parent: Node): Node} callback
|
||||
* @returns {OperatorNode} Returns a transformed copy of the node
|
||||
*/
|
||||
OperatorNode.prototype.map = function (callback) {
|
||||
var args = [];
|
||||
for (var i = 0; i < this.args.length; i++) {
|
||||
args[i] = callback(this.args[i], 'args.' + i, this);
|
||||
}
|
||||
return new OperatorNode(this.op, this.fn, args);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a clone of this node, a shallow copy
|
||||
* @return {OperatorNode}
|
||||
*/
|
||||
OperatorNode.prototype.clone = function() {
|
||||
return new OperatorNode(this.op, this.fn, this.args.map(function (param) {
|
||||
return param.clone();
|
||||
}));
|
||||
return new OperatorNode(this.op, this.fn, this.args.slice(0));
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -49,33 +49,39 @@ RangeNode.prototype._compile = function (defs) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Recursively execute a callback for each of the child nodes of this node
|
||||
* @param {function(Node, string, Node)} callback
|
||||
* @private
|
||||
* Execute a callback for each of the child nodes of this node
|
||||
* @param {function(child: Node, path: string, parent: Node)} callback
|
||||
*/
|
||||
RangeNode.prototype._traverse = function (callback) {
|
||||
RangeNode.prototype.forEach = function (callback) {
|
||||
callback(this.start, 'start', this);
|
||||
this.start._traverse(callback);
|
||||
|
||||
if (this.step) {
|
||||
callback(this.step, 'step', this);
|
||||
this.step._traverse(callback);
|
||||
}
|
||||
|
||||
callback(this.end, 'end', this);
|
||||
this.end._traverse(callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a clone of this node
|
||||
* Create a new RangeNode having it's childs be the results of calling
|
||||
* the provided callback function for each of the childs of the original node.
|
||||
* @param {function(child: Node, path: string, parent: Node): Node} callback
|
||||
* @returns {RangeNode} Returns a transformed copy of the node
|
||||
*/
|
||||
RangeNode.prototype.map = function (callback) {
|
||||
return new RangeNode(
|
||||
callback(this.start, 'start', this),
|
||||
callback(this.end, 'end', this),
|
||||
this.step && callback(this.step, 'step', this)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a clone of this node, a shallow copy
|
||||
* @return {RangeNode}
|
||||
*/
|
||||
RangeNode.prototype.clone = function() {
|
||||
return new RangeNode(
|
||||
this.start.clone(),
|
||||
this.end.clone(),
|
||||
this.step && this.step.clone()
|
||||
);
|
||||
return new RangeNode(this.start, this.end, this.step && this.step);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -56,13 +56,22 @@ SymbolNode.prototype._compile = function (defs) {
|
||||
|
||||
/**
|
||||
* Execute a callback for each of the child nodes of this node
|
||||
* @param {function(Node, string, Node)} callback
|
||||
* @private
|
||||
* @param {function(child: Node, path: string, parent: Node)} callback
|
||||
*/
|
||||
SymbolNode.prototype._traverse = function (callback) {
|
||||
SymbolNode.prototype.forEach = function (callback) {
|
||||
// nothing to do, we don't have childs
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a new SymbolNode having it's childs be the results of calling
|
||||
* the provided callback function for each of the childs of the original node.
|
||||
* @param {function(child: Node, path: string, parent: Node) : Node} callback
|
||||
* @returns {SymbolNode} Returns a clone of the node
|
||||
*/
|
||||
SymbolNode.prototype.map = function (callback) {
|
||||
return this.clone();
|
||||
};
|
||||
|
||||
/**
|
||||
* Throws an error 'Undefined symbol {name}'
|
||||
* @param {String} name
|
||||
@ -72,7 +81,7 @@ function undef (name) {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a clone of this node
|
||||
* Create a clone of this node, a shallow copy
|
||||
* @return {SymbolNode}
|
||||
*/
|
||||
SymbolNode.prototype.clone = function() {
|
||||
|
||||
@ -45,24 +45,33 @@ UpdateNode.prototype._compile = function (defs) {
|
||||
};
|
||||
|
||||
/**
|
||||
* Recursively execute a callback for each of the child nodes of this node
|
||||
* @param {function(Node, string, Node)} callback
|
||||
* @private
|
||||
* Execute a callback for each of the child nodes of this node
|
||||
* @param {function(child: Node, path: string, parent: Node)} callback
|
||||
*/
|
||||
UpdateNode.prototype._traverse = function (callback) {
|
||||
UpdateNode.prototype.forEach = function (callback) {
|
||||
callback(this.index, 'index', this);
|
||||
this.index._traverse(callback);
|
||||
|
||||
callback(this.expr, 'expr', this);
|
||||
this.expr._traverse(callback);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a clone of this node
|
||||
* Create a new UpdateNode having it's childs be the results of calling
|
||||
* the provided callback function for each of the childs of the original node.
|
||||
* @param {function(child: Node, path: string, parent: Node): Node} callback
|
||||
* @returns {UpdateNode} Returns a transformed copy of the node
|
||||
*/
|
||||
UpdateNode.prototype.map = function (callback) {
|
||||
return new UpdateNode(
|
||||
callback(this.index, 'index', this),
|
||||
callback(this.expr, 'expr', this)
|
||||
);
|
||||
};
|
||||
|
||||
/**
|
||||
* Create a clone of this node, a shallow copy
|
||||
* @return {UpdateNode}
|
||||
*/
|
||||
UpdateNode.prototype.clone = function() {
|
||||
return new UpdateNode(this.index.clone(), this.expr.clone());
|
||||
return new UpdateNode(this.index, this.expr);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -91,7 +91,7 @@ describe('ArrayNode', function() {
|
||||
return (node instanceof SymbolNode) && (node.name == 'x') ? d : node;
|
||||
});
|
||||
|
||||
assert.strictEqual(e, c);
|
||||
assert.notStrictEqual(e, c);
|
||||
assert.deepEqual(e.nodes[0], d);
|
||||
assert.deepEqual(e.nodes[1], b);
|
||||
});
|
||||
@ -115,25 +115,26 @@ describe('ArrayNode', function() {
|
||||
var c = new ArrayNode([a, b]);
|
||||
|
||||
var count = 0;
|
||||
c.traverse(function (node, index, parent) {
|
||||
c.traverse(function (node, path, parent) {
|
||||
console.log('traverse', node.toString(), path)
|
||||
count++;
|
||||
|
||||
switch(count) {
|
||||
case 1:
|
||||
assert.strictEqual(node, c);
|
||||
assert.strictEqual(index, null);
|
||||
assert.strictEqual(path, null);
|
||||
assert.strictEqual(parent, null);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
assert.strictEqual(node, a);
|
||||
assert.strictEqual(index, 'nodes.0');
|
||||
assert.strictEqual(path, 'nodes.0');
|
||||
assert.strictEqual(parent, c);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
assert.strictEqual(node, b);
|
||||
assert.strictEqual(index, 'nodes.1');
|
||||
assert.strictEqual(path, 'nodes.1');
|
||||
assert.strictEqual(parent, c);
|
||||
break;
|
||||
}
|
||||
@ -152,8 +153,8 @@ describe('ArrayNode', function() {
|
||||
assert(d instanceof ArrayNode);
|
||||
assert.deepEqual(c, d);
|
||||
assert.notStrictEqual(c, d);
|
||||
assert.notStrictEqual(c.nodes[0], d.nodes[0]);
|
||||
assert.notStrictEqual(c.nodes[1], d.nodes[1]);
|
||||
assert.strictEqual(c.nodes[0], d.nodes[0]);
|
||||
assert.strictEqual(c.nodes[1], d.nodes[1]);
|
||||
});
|
||||
|
||||
it ('should stringify an ArrayNode', function () {
|
||||
|
||||
@ -81,7 +81,7 @@ describe('AssignmentNode', function() {
|
||||
return node instanceof SymbolNode && node.name == 'x' ? e : node;
|
||||
});
|
||||
|
||||
assert.strictEqual(f, d);
|
||||
assert.notStrictEqual(f, d);
|
||||
assert.deepEqual(f.expr.args[0], e);
|
||||
assert.deepEqual(f.expr.args[1], b);
|
||||
});
|
||||
@ -139,7 +139,7 @@ describe('AssignmentNode', function() {
|
||||
assert(e instanceof AssignmentNode);
|
||||
assert.deepEqual(e, d);
|
||||
assert.notStrictEqual(e, d);
|
||||
assert.notStrictEqual(e.expr, d.expr);
|
||||
assert.strictEqual(e.expr, d.expr);
|
||||
});
|
||||
|
||||
it ('should stringify a AssignmentNode', function () {
|
||||
|
||||
@ -91,7 +91,7 @@ describe('BlockNode', function() {
|
||||
return node instanceof SymbolNode && node.name == 'x' ? d : node;
|
||||
});
|
||||
|
||||
assert.strictEqual(e, a);
|
||||
assert.notStrictEqual(e, a);
|
||||
assert.deepEqual(e.blocks[0].node, d);
|
||||
assert.deepEqual(e.blocks[1].node, c);
|
||||
});
|
||||
@ -156,8 +156,11 @@ describe('BlockNode', function() {
|
||||
assert(d instanceof BlockNode);
|
||||
assert.deepEqual(a, d);
|
||||
assert.notStrictEqual(a, d);
|
||||
assert.notStrictEqual(a.blocks, d.blocks);
|
||||
assert.notStrictEqual(a.blocks[0], d.blocks[0]);
|
||||
assert.notStrictEqual(a.blocks[1], d.blocks[1]);
|
||||
assert.strictEqual(a.blocks[0].node, d.blocks[0].node);
|
||||
assert.strictEqual(a.blocks[1].node, d.blocks[1].node);
|
||||
});
|
||||
|
||||
it ('should stringify a BlockNode', function () {
|
||||
|
||||
@ -117,7 +117,7 @@ describe('ConditionalNode', function() {
|
||||
return node instanceof ConstantNode && node.value == '1' ? e : node;
|
||||
});
|
||||
|
||||
assert.strictEqual(f, n);
|
||||
assert.notStrictEqual(f, n);
|
||||
assert.deepEqual(f.condition, e);
|
||||
assert.deepEqual(f.trueExpr, a);
|
||||
assert.deepEqual(f.falseExpr, b);
|
||||
@ -134,7 +134,7 @@ describe('ConditionalNode', function() {
|
||||
return node instanceof ConstantNode && node.value == '2' ? e : node;
|
||||
});
|
||||
|
||||
assert.strictEqual(f, n);
|
||||
assert.notStrictEqual(f, n);
|
||||
assert.deepEqual(f.condition, condition);
|
||||
assert.deepEqual(f.trueExpr, e);
|
||||
assert.deepEqual(f.falseExpr, b);
|
||||
@ -151,7 +151,7 @@ describe('ConditionalNode', function() {
|
||||
return node instanceof ConstantNode && node.value == '3' ? e : node;
|
||||
});
|
||||
|
||||
assert.strictEqual(f, n);
|
||||
assert.notStrictEqual(f, n);
|
||||
assert.deepEqual(f.condition, condition);
|
||||
assert.deepEqual(f.trueExpr, a);
|
||||
assert.deepEqual(f.falseExpr, e);
|
||||
@ -182,9 +182,9 @@ describe('ConditionalNode', function() {
|
||||
assert(d instanceof ConditionalNode);
|
||||
assert.deepEqual(d, c);
|
||||
assert.notStrictEqual(d, c);
|
||||
assert.notStrictEqual(d.condition, c.condition);
|
||||
assert.notStrictEqual(d.trueExpr, c.trueExpr);
|
||||
assert.notStrictEqual(d.falseExpr, c.falseExpr);
|
||||
assert.strictEqual(d.condition, c.condition);
|
||||
assert.strictEqual(d.trueExpr, c.trueExpr);
|
||||
assert.strictEqual(d.falseExpr, c.falseExpr);
|
||||
});
|
||||
|
||||
it ('should stringify a ConditionalNode', function () {
|
||||
|
||||
@ -87,7 +87,7 @@ describe('ConstantNode', function() {
|
||||
var d = a.transform(function (node) {
|
||||
return node instanceof ConstantNode && node.value == '99' ? b : node;
|
||||
});
|
||||
assert.strictEqual(d, a);
|
||||
assert.notStrictEqual(d, a);
|
||||
assert.deepEqual(d, a);
|
||||
});
|
||||
|
||||
|
||||
@ -86,7 +86,7 @@ describe('FunctionAssignmentNode', function() {
|
||||
return node instanceof SymbolNode && node.name == 'x' ? e : node;
|
||||
});
|
||||
|
||||
assert.strictEqual(f, n);
|
||||
assert.notStrictEqual(f, n);
|
||||
assert.deepEqual(f.expr.args[0], a);
|
||||
assert.deepEqual(f.expr.args[1], e);
|
||||
});
|
||||
@ -117,7 +117,7 @@ describe('FunctionAssignmentNode', function() {
|
||||
assert(e instanceof FunctionAssignmentNode);
|
||||
assert.deepEqual(e, d);
|
||||
assert.notStrictEqual(e, d);
|
||||
assert.notStrictEqual(e.expr, d.expr);
|
||||
assert.strictEqual(e.expr, d.expr);
|
||||
});
|
||||
|
||||
it ('should stringify a FunctionAssignmentNode', function () {
|
||||
|
||||
@ -107,7 +107,7 @@ describe('FunctionNode', function() {
|
||||
return node instanceof SymbolNode && node.name == 'x' ? g : node;
|
||||
});
|
||||
|
||||
assert.strictEqual(h, f);
|
||||
assert.notStrictEqual(h, f);
|
||||
assert.deepEqual(h.args[0].args[0], g);
|
||||
assert.deepEqual(h.args[0].args[1], b);
|
||||
assert.deepEqual(h.name, 'multiply');
|
||||
@ -127,7 +127,7 @@ describe('FunctionNode', function() {
|
||||
return node;
|
||||
});
|
||||
|
||||
assert.strictEqual(f, d);
|
||||
assert.notStrictEqual(f, d);
|
||||
assert.deepEqual(f.name, 'subtract');
|
||||
});
|
||||
|
||||
@ -152,25 +152,25 @@ describe('FunctionNode', function() {
|
||||
var d = new FunctionNode('add', [b, c]);
|
||||
|
||||
var count = 0;
|
||||
d.traverse(function (node, index, parent) {
|
||||
d.traverse(function (node, path, parent) {
|
||||
count++;
|
||||
|
||||
switch(count) {
|
||||
case 1:
|
||||
assert.strictEqual(node, d);
|
||||
assert.strictEqual(index, null);
|
||||
assert.strictEqual(path, null);
|
||||
assert.strictEqual(parent, null);
|
||||
break;
|
||||
|
||||
case 2:
|
||||
assert.strictEqual(node, b);
|
||||
assert.strictEqual(index, 'args.0');
|
||||
assert.strictEqual(path, 'args.0');
|
||||
assert.strictEqual(parent, d);
|
||||
break;
|
||||
|
||||
case 3:
|
||||
assert.strictEqual(node, c);
|
||||
assert.strictEqual(index, 'args.1');
|
||||
assert.strictEqual(path, 'args.1');
|
||||
assert.strictEqual(parent, d);
|
||||
break;
|
||||
}
|
||||
@ -190,8 +190,9 @@ describe('FunctionNode', function() {
|
||||
assert.deepEqual(e, d);
|
||||
assert.notStrictEqual(e, d);
|
||||
assert.equal(e.name, d.name);
|
||||
assert.notStrictEqual(e.args[0], d.args[0]);
|
||||
assert.notStrictEqual(e.args[1], d.args[1]);
|
||||
assert.notStrictEqual(e.args, d.args);
|
||||
assert.strictEqual(e.args[0], d.args[0]);
|
||||
assert.strictEqual(e.args[1], d.args[1]);
|
||||
});
|
||||
|
||||
it ('should stringify a FunctionNode', function () {
|
||||
|
||||
@ -143,7 +143,7 @@ describe('IndexNode', function() {
|
||||
return node instanceof SymbolNode ? e : node;
|
||||
});
|
||||
|
||||
assert.strictEqual(f, n);
|
||||
assert.notStrictEqual(f, n);
|
||||
assert.deepEqual(f.object, e);
|
||||
assert.deepEqual(f.ranges[0], b);
|
||||
assert.deepEqual(f.ranges[1], c);
|
||||
@ -160,7 +160,7 @@ describe('IndexNode', function() {
|
||||
return node instanceof ConstantNode && node.value == '1' ? e : node;
|
||||
});
|
||||
|
||||
assert.strictEqual(f, n);
|
||||
assert.notStrictEqual(f, n);
|
||||
assert.deepEqual(f.object, a);
|
||||
assert.deepEqual(f.ranges[0], b);
|
||||
assert.deepEqual(f.ranges[1], e);
|
||||
@ -190,9 +190,10 @@ describe('IndexNode', function() {
|
||||
assert(d instanceof IndexNode);
|
||||
assert.deepEqual(d, n);
|
||||
assert.notStrictEqual(d, n);
|
||||
assert.notStrictEqual(d.object, n.object);
|
||||
assert.notStrictEqual(d.ranges[0], n.ranges[0]);
|
||||
assert.notStrictEqual(d.ranges[1], n.ranges[1]);
|
||||
assert.strictEqual(d.object, n.object);
|
||||
assert.notStrictEqual(d.ranges, n.ranges);
|
||||
assert.strictEqual(d.ranges[0], n.ranges[0]);
|
||||
assert.strictEqual(d.ranges[1], n.ranges[1]);
|
||||
});
|
||||
|
||||
it ('should stringify an IndexNode', function () {
|
||||
|
||||
@ -7,7 +7,10 @@ var Node = require('../../../lib/expression/node/Node');
|
||||
describe('Node', function() {
|
||||
function MyNode () {}
|
||||
MyNode.prototype = new Node();
|
||||
MyNode.prototype._traverse = function () {};
|
||||
MyNode.prototype.forEach = function () {};
|
||||
MyNode.prototype.map = function () {
|
||||
return new MyNode();
|
||||
};
|
||||
|
||||
it ('should create a Node', function () {
|
||||
var n = new Node();
|
||||
@ -40,7 +43,7 @@ describe('Node', function() {
|
||||
c = a.transform(function (node) {
|
||||
return node;
|
||||
});
|
||||
assert.strictEqual(c, a);
|
||||
assert.notStrictEqual(c, a);
|
||||
});
|
||||
|
||||
it ('should transform a Node using a replacement function', function () {
|
||||
@ -53,11 +56,11 @@ describe('Node', function() {
|
||||
assert.strictEqual(c, b);
|
||||
});
|
||||
|
||||
it ('should clone a Node', function () {
|
||||
var a = new Node();
|
||||
var b = a.clone();
|
||||
assert.deepEqual(a, b);
|
||||
assert.notStrictEqual(a, b);
|
||||
it ('should throw an error when cloning a Node interface', function () {
|
||||
assert.throws(function () {
|
||||
var a = new Node();
|
||||
a.clone();
|
||||
}, /Cannot clone a Node interface/);
|
||||
});
|
||||
|
||||
it ('should test whether an object is a Node', function () {
|
||||
|
||||
@ -76,7 +76,8 @@ describe('OperatorNode', function() {
|
||||
return node instanceof SymbolNode && node.name == 'x' ? f : node;
|
||||
});
|
||||
|
||||
assert.strictEqual(g, e);
|
||||
assert.notStrictEqual(g, e);
|
||||
assert.notStrictEqual(g.args[0], e.args[0]);
|
||||
assert.strictEqual(g.args[0].args[0], f);
|
||||
assert.deepEqual(g.args[0].args[1], b);
|
||||
assert.deepEqual(g.args[1], f);
|
||||
@ -107,8 +108,9 @@ describe('OperatorNode', function() {
|
||||
assert(d instanceof OperatorNode);
|
||||
assert.deepEqual(d, c);
|
||||
assert.notStrictEqual(d, c);
|
||||
assert.notStrictEqual(d.args[0], c.args[0]);
|
||||
assert.notStrictEqual(d.args[1], c.args[1]);
|
||||
assert.notStrictEqual(d.args, c.args);
|
||||
assert.strictEqual(d.args[0], c.args[0]);
|
||||
assert.strictEqual(d.args[1], c.args[1]);
|
||||
});
|
||||
|
||||
it ('should stringify an OperatorNode', function () {
|
||||
|
||||
@ -69,7 +69,7 @@ describe('RangeNode', function() {
|
||||
return node instanceof ConstantNode && node.value == '0' ? e : node;
|
||||
});
|
||||
|
||||
assert.strictEqual(f, n);
|
||||
assert.notStrictEqual(f, n);
|
||||
assert.deepEqual(f.start, e);
|
||||
assert.deepEqual(f.end, end);
|
||||
assert.deepEqual(f.step, step);
|
||||
@ -86,7 +86,7 @@ describe('RangeNode', function() {
|
||||
return node instanceof ConstantNode && node.value == '10' ? e : node;
|
||||
});
|
||||
|
||||
assert.strictEqual(f, n);
|
||||
assert.notStrictEqual(f, n);
|
||||
assert.deepEqual(f.start, start);
|
||||
assert.deepEqual(f.end, e);
|
||||
assert.deepEqual(f.step, step);
|
||||
@ -103,7 +103,7 @@ describe('RangeNode', function() {
|
||||
return node instanceof ConstantNode && node.value == '2' ? e : node;
|
||||
});
|
||||
|
||||
assert.strictEqual(f, n);
|
||||
assert.notStrictEqual(f, n);
|
||||
assert.deepEqual(f.start, start);
|
||||
assert.deepEqual(f.end, end);
|
||||
assert.deepEqual(f.step, e);
|
||||
@ -119,7 +119,7 @@ describe('RangeNode', function() {
|
||||
return node instanceof ConstantNode && node.value == '10' ? e : node;
|
||||
});
|
||||
|
||||
assert.strictEqual(f, n);
|
||||
assert.notStrictEqual(f, n);
|
||||
assert.deepEqual(f.start, start);
|
||||
assert.deepEqual(f.end, e);
|
||||
});
|
||||
@ -148,9 +148,9 @@ describe('RangeNode', function() {
|
||||
|
||||
assert.deepEqual(d, c);
|
||||
assert.notStrictEqual(d, c);
|
||||
assert.notStrictEqual(d.start, c.start);
|
||||
assert.notStrictEqual(d.end, c.end);
|
||||
assert.notStrictEqual(d.step, c.step);
|
||||
assert.strictEqual(d.start, c.start);
|
||||
assert.strictEqual(d.end, c.end);
|
||||
assert.strictEqual(d.step, c.step);
|
||||
});
|
||||
|
||||
it ('should clone a RangeNode without step', function () {
|
||||
@ -163,8 +163,8 @@ describe('RangeNode', function() {
|
||||
assert(d instanceof RangeNode);
|
||||
assert.deepEqual(d, c);
|
||||
assert.notStrictEqual(d, c);
|
||||
assert.notStrictEqual(d.start, c.start);
|
||||
assert.notStrictEqual(d.end, c.end);
|
||||
assert.strictEqual(d.start, c.start);
|
||||
assert.strictEqual(d.end, c.end);
|
||||
assert.strictEqual(d.step, c.step);
|
||||
assert.strictEqual(d.step, null);
|
||||
});
|
||||
|
||||
@ -164,7 +164,7 @@ describe('UpdateNode', function() {
|
||||
return node instanceof SymbolNode && node.name == 'x' ? e : node;
|
||||
});
|
||||
|
||||
assert.strictEqual(f, n);
|
||||
assert.notStrictEqual(f, n);
|
||||
assert.deepEqual(f.index.object, a);
|
||||
assert.deepEqual(f.index.ranges[0], b);
|
||||
assert.deepEqual(f.index.ranges[1], e);
|
||||
@ -185,7 +185,7 @@ describe('UpdateNode', function() {
|
||||
return node instanceof ConstantNode && node.value == '3' ? e : node;
|
||||
});
|
||||
|
||||
assert.strictEqual(g, n);
|
||||
assert.notStrictEqual(g, n);
|
||||
assert.deepEqual(g.index, i);
|
||||
assert.deepEqual(g.index.object, a);
|
||||
assert.deepEqual(g.index.ranges[0], b);
|
||||
@ -225,8 +225,8 @@ describe('UpdateNode', function() {
|
||||
assert(e instanceof UpdateNode);
|
||||
assert.deepEqual(e, d);
|
||||
assert.notStrictEqual(e, d);
|
||||
assert.notStrictEqual(e.index, d.index);
|
||||
assert.notStrictEqual(e.expr, d.expr);
|
||||
assert.strictEqual(e.index, d.index);
|
||||
assert.strictEqual(e.expr, d.expr);
|
||||
});
|
||||
|
||||
it ('should stringify an UpdateNode', function () {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user