Fixed Node.transform not recursing over replaced parts of the node tree (see #349).

This commit is contained in:
jos 2015-05-02 17:27:14 +02:00
parent 84aaada3df
commit f7c5381a13
17 changed files with 1040 additions and 926 deletions

View File

@ -7,6 +7,8 @@
the expressions result, string representation, or tex representation.
Thanks @FSMaxB.
- Fixed #309: Function median mutating the input matrix. Thanks @FSMaxB.
- Fixed `Node.transform` not recursing over replaced parts of the
node tree (see #349).
## 2015-04-22, version 1.6.0

1853
dist/math.js vendored

File diff suppressed because it is too large Load Diff

2
dist/math.map vendored

File diff suppressed because one or more lines are too long

23
dist/math.min.js vendored

File diff suppressed because one or more lines are too long

View File

@ -152,20 +152,16 @@ Node.prototype.traverse = function (callback) {
* @return {Node} Returns the original node or its replacement
*/
Node.prototype.transform = function (callback) {
// check itself
var replacement = callback(this, null, null);
if (replacement !== this) {
return replacement;
}
// traverse over all childs
function _transform (node, callback) {
return node.map(function(child, path, parent) {
var replacement = callback(child, path, parent);
return (replacement !== child) ? replacement : _transform(child, callback);
return _transform(replacement, callback);
});
}
return _transform(this, callback);
var replacement = callback(this, null, null);
return _transform(replacement, callback);
};
/**

View File

@ -164,7 +164,9 @@ describe('ArrayNode', function() {
var e = c.transform(function (node) {
return (node instanceof ArrayNode) ? d : node;
});
assert.strictEqual(e, d);
assert.notStrictEqual(e, c);
assert.deepEqual(e, d);
});
it ('should traverse an ArrayNode', function () {

View File

@ -149,7 +149,8 @@ describe('AssignmentNode', function() {
return node instanceof AssignmentNode ? e : node;
});
assert.strictEqual(f, e);
assert.notStrictEqual(f, d);
assert.deepEqual(f, e);
});
it ('should traverse an AssignmentNode', function () {

View File

@ -177,7 +177,9 @@ describe('BlockNode', function() {
var e = a.transform(function (node) {
return node instanceof BlockNode ? d : node;
});
assert.strictEqual(e, d);
assert.notStrictEqual(e, a);
assert.deepEqual(e, d);
});
it ('should traverse a BlockNode', function () {

View File

@ -179,9 +179,9 @@ describe('ConditionalNode', function() {
});
assert.notStrictEqual(f, n);
assert.strictEqual(f.condition, e);
assert.deepEqual(f.trueExpr, a);
assert.deepEqual(f.falseExpr, b);
assert.deepEqual(f.condition, e);
assert.deepEqual(f.trueExpr, a);
assert.deepEqual(f.falseExpr, b);
});
it ('should transform a ConditionalNodes trueExpr', function () {
@ -196,9 +196,9 @@ describe('ConditionalNode', function() {
});
assert.notStrictEqual(f, n);
assert.deepEqual(f.condition, condition);
assert.strictEqual(f.trueExpr, e);
assert.deepEqual(f.falseExpr, b);
assert.deepEqual(f.condition, condition);
assert.deepEqual(f.trueExpr, e);
assert.deepEqual(f.falseExpr, b);
});
it ('should transform a ConditionalNodes falseExpr', function () {
@ -215,7 +215,7 @@ describe('ConditionalNode', function() {
assert.notStrictEqual(f, n);
assert.deepEqual(f.condition, condition);
assert.deepEqual(f.trueExpr, a);
assert.strictEqual(f.falseExpr, e);
assert.deepEqual(f.falseExpr, e);
});
it ('should transform a ConditionalNode itself', function () {
@ -229,7 +229,8 @@ describe('ConditionalNode', function() {
return node instanceof ConditionalNode ? e : node;
});
assert.strictEqual(f, e);
assert.notStrictEqual(f, n);
assert.deepEqual(f, e);
});
it ('should clone a ConditionalNode itself', function () {

View File

@ -98,13 +98,13 @@ describe('ConstantNode', function() {
var c = a.transform(function (node) {
return node instanceof ConstantNode && node.value == '2' ? b : node;
});
assert.strictEqual(c, b);
assert.deepEqual(c, b);
// no match should leave the node as is
var d = a.transform(function (node) {
return node instanceof ConstantNode && node.value == '99' ? b : node;
});
assert.notStrictEqual(d, a);
assert.notStrictEqual(d, a);
assert.deepEqual(d, a);
});

View File

@ -223,7 +223,8 @@ describe('FunctionAssignmentNode', function() {
return node instanceof FunctionAssignmentNode ? e : node;
});
assert.strictEqual(f, e);
assert.notStrictEqual(f, n);
assert.deepEqual(f, e);
});
it ('should clone a FunctionAssignmentNode', function () {

View File

@ -205,7 +205,7 @@ describe('FunctionNode', function() {
return node instanceof FunctionNode ? e : node;
});
assert.strictEqual(f, e);
assert.deepEqual(f, e);
});
it ('should traverse a FunctionNode', function () {

View File

@ -238,7 +238,8 @@ describe('IndexNode', function() {
return node instanceof IndexNode ? e : node;
});
assert.strictEqual(f, e);
assert.notStrictEqual(f, n);
assert.deepEqual(f, e);
});
it ('should clone an IndexNode', function () {

View File

@ -5,11 +5,13 @@ var math = require('../../../index');
var Node = require('../../../lib/expression/node/Node');
describe('Node', function() {
function MyNode () {}
function MyNode (value) {
this.value = value;
}
MyNode.prototype = new Node();
MyNode.prototype.forEach = function () {};
MyNode.prototype.map = function () {
return new MyNode();
return new MyNode(this.value);
};
it ('should create a Node', function () {
@ -22,7 +24,7 @@ describe('Node', function() {
});
it ('should filter a Node', function () {
var n = new MyNode();
var n = new MyNode(2);
assert.deepEqual(n.filter(function () {return true}), [n]);
assert.deepEqual(n.filter(function (node) {return node instanceof Node}), [n]);
@ -30,30 +32,30 @@ describe('Node', function() {
});
it ('should transform a Node', function () {
var a = new MyNode();
var b = new MyNode();
var a = new MyNode(2);
var b = new MyNode(3);
var c = a.transform(function (node) {
return b;
});
assert.strictEqual(c, b);
assert.deepEqual(c, b);
// no match
a = new MyNode();
b = new MyNode();
a = new MyNode(2);
b = new MyNode(3);
c = a.transform(function (node) {
return node;
});
assert.notStrictEqual(c, a);
assert.deepEqual(c, a);
});
it ('should transform a Node using a replacement function', function () {
var a = new MyNode();
var b = new MyNode();
var a = new MyNode(2);
var b = new MyNode(3);
var c = a.transform(function (node) {
assert.deepEqual(node, a);
return b;
});
assert.strictEqual(c, b);
assert.deepEqual(c, b);
});
it ('should throw an error when cloning a Node interface', function () {

View File

@ -140,10 +140,6 @@ describe('OperatorNode', function() {
return node instanceof SymbolNode && node.name == 'x' ? f : node;
});
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);
});

View File

@ -197,7 +197,7 @@ describe('RangeNode', function() {
return node instanceof RangeNode ? e : node;
});
assert.strictEqual(f, e);
assert.deepEqual(f, e);
});
it ('should clone a RangeNode', function () {

View File

@ -277,7 +277,7 @@ describe('UpdateNode', function() {
return node instanceof UpdateNode ? e : node;
});
assert.strictEqual(f, e);
assert.deepEqual(f, e);
});
it ('should clone an UpdateNode', function () {