# Expression trees When parsing an expression via `math.parse(expr)`, math.js generates an expression tree and returns the root node of the tree. An expression tree can be used to analyze, manipulate, and evaluate expressions. Example: ```js var node = math.parse('sqrt(2 + x)'); ``` In this case, the expression `sqrt(2 + x)` is parsed as: ``` FunctionNode sqrt | OperatorNode + / \ ConstantNode 2 x SymbolNode ``` Alternatively, this expression tree can be build by manually creating nodes: ```js var node1 = new math.expression.node.ConstantNode(2); var node2 = new math.expression.node.SymbolNode('x'); var node3 = new math.expression.node.OperatorNode('+', 'add', [node1, node2]); var node4 = new math.expression.node.FunctionNode('sqrt', [node3]); ``` The resulting expression tree with root node `node4` is equal to the expression tree generated by `math.parse('sqrt(2 + x)')`. ## API ### Methods All nodes have the following methods: - `clone() : Node` Recursively clone an expression tree. - `compile(namespace: Object) : Object` Compile an expression into optimized JavaScript code. The expression is compiled against a namespace, typically `math`, needed to bind internally used functions. `compile` returns an object with a function `eval([scope])` to evaluate. Example: ```js var node = math.parse('2 + x'); // returns the root Node of an expression tree var code = node.compile(math); // returns {eval: function (scope) {...}} var eval = code.eval({x: 3}; // returns 5 ``` - `filter(callback: function) : Array.` Filter nodes in an expression tree. The `callback` function is called as `callback(node: Node, path: string, parent: Node) : boolean` for every node in the tree, and must return a boolean. The function `filter` returns an array with nodes for which the test returned true. Parameter `path` is a string containing a relative JSON Path. Example: ```js var node = math.parse('x^2 + x/4 + 3*y'); var filtered = node.filter(function (node) { return node.type == 'SymbolNode' && node.name == 'x'; }); // returns an array with two entries: two SymbolNodes 'x' ``` - `forEach(callback: function) : Array.` Execute a callback for each of the child nodes of this node. The `callback` function is called as `callback(child: Node, path: string, parent: Node)`. Parameter `path` is a string containing a relative JSON Path. See also `traverse`, which is a recursive version of `forEach`. Example: ```js var node = math.parse('3 * x + 2'); node.forEach(function (node, path, parent) { switch (node.type) { case 'OperatorNode': console.log(node.type, node.op); break; case 'ConstantNode': console.log(node.type, node.value); break; case 'SymbolNode': console.log(node.type, node.name); break; default: console.log(node.type); } }); // outputs: // OperatorNode * // ConstantNode 2 ``` - `map(callback: function) : Array.` Transform a node. Creates 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. The `callback` function is called as `callback(child: Node, path: string, parent: Node)` and must return a Node. Parameter `path` is a string containing a relative JSON Path. See also `transform`, which is a recursive version of `map`. - `toString() : string` Get a string representation of the parsed expression. This is not exactly the same as the original input. Example: ```js var node = math.parse('3+4*2'); node.toString(); // returns '3 + (4 * 2)' ``` - `toTex(): string` Get a [LaTeX](http://en.wikipedia.org/wiki/LaTeX) representation of the expression. Example: ```js var node = math.parse('sqrt(2/3)'); node.toTex(); // returns '\sqrt{\frac{2}{3}}' ``` - `transform(callback: function)` Recursively transform an expression tree via a transform function. Similar to `Array.map`, but recursively executed on all nodes in the expression tree. The callback function is a mapping function accepting a node, and returning a replacement for the node or the original node. Function `callback` is called as `callback(node: Node, path: string, parent: Node)` for every node in the tree, and must return a `Node`. Parameter `path` is a string containing a relative JSON Path. For example, to replace all nodes of type `SymbolNode` having name 'x' with a ConstantNode with value 2: ```js var node = math.parse('x^2 + 5*x'); var transformed = node.transform(function (node, path, parent) { if (node.type == 'SymbolNode' && node.name == 'x') { return new math.expression.node.ConstantNode(3); } else { return node; } }); transformed.toString(); // returns '(3 ^ 2) + (5 * 3)' ``` - `traverse(callback)` 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. The callback function is a mapping function accepting a node, and returning a replacement for the node or the original node. Function `callback` is called as `callback(node: Node, path: string, parent: Node)` for every node in the tree. Parameter `path` is a string containing a relative JSON Path. Example: ```js var node = math.parse('3 * x + 2'); node.traverse(function (node, path, parent) { switch (node.type) { case 'OperatorNode': console.log(node.type, node.op); break; case 'ConstantNode': console.log(node.type, node.value); break; case 'SymbolNode': console.log(node.type, node.name); break; default: console.log(node.type); } }); // outputs: // OperatorNode + // OperatorNode * // ConstantNode 3 // SymbolNode x // ConstantNode 2 ``` ### Static methods - `Node.isNode(object) : boolean` Test whether an object is a `Node`. Returns `true` when `object` is an instance of `Node`, else returns `false`. ### Properties Each `Node` has the following properties: - `type: string` The type of the node, for example `'SymbolNode'`. ## Nodes math.js has the following types of nodes. All nodes are available at the namespace `math.expression.node`. ### ArrayNode Construction: ``` new ArrayNode(nodes: Node[]) ``` Properties: - `nodes: Node[]` Examples: ```js var node1 = math.parse('[1, 2, 3]'); var one = new math.expression.node.ConstantNode(1); var two = new math.expression.node.ConstantNode(2); var three = new math.expression.node.ConstantNode(3); var node2 = new math.expression.node.ArrayNode([one, two, three]); ``` ### AssignmentNode Construction: ``` new AssignmentNode(name: string, expr: Node) ``` Properties: - `name: string` - `expr: Node` Examples: ```js var node1 = math.parse('a = 3'); var expr = new math.expression.node.ConstantNode(3); var node2 = new math.expression.node.AssignmentNode('a', expr); ``` ### BlockNode A `BlockNode` is created when parsing a multi line expression like `a=2;b=3` or `a=2\nb=3`. Evaluating a `BlockNode` returns a `ResultSet`. The results can be retrieved via `ResultSet.entries` or `ResultSet.valueOf()`, which contains an `Array` with the results of the visible lines (i.e. lines not ending with a semicolon). Construction: ``` block = new BlockNode(Array.<{node: Node} | {node: Node, visible: boolean}>) ``` Properties: - `blocks: Array.<{node: Node, visible: boolean}>` Examples: ```js var block1 = math.parse('a=1; b=2; c=3'); var one = new math.expression.node.ConstantNode(1); var a = new math.expression.node.AssignmentNode('a', one); var two = new math.expression.node.ConstantNode(2); var b = new math.expression.node.AssignmentNode('b', two); var three = new math.expression.node.ConstantNode(3); var c = new math.expression.node.AssignmentNode('c', three); var block2 = new BlockNode([ {node: a, visible: false}, {node: b, visible: false}, {node: c, visible: true} ]); ``` ### ConditionalNode Construction: ``` new ConditionalNode(condition: Node, trueExpr: Node, falseExpr: Node) ``` Properties: - `condition: Node` - `trueExpr: Node` - `falseExpr: Node` Examples: ```js var node1 = math.parse('a > 0 ? a : -a'); var a = new math.expression.node.SymbolNode('a'); var zero = new math.expression.node.ConstantNode(0); var condition = new math.expression.node.OperatorNode('>', 'larger', [a, zero]); var trueExpr = a; var falseExpr = new math.expression.node.OperatorNode('-', 'unaryMinus', [a]); var node2 = new math.expression.node.ConditionalNode(condition, trueExpr, falseExpr); ``` ### ConstantNode Construction: ``` new ConstantNode(value: * [, valueType: string]) ``` Properties: - `value: *` - `valueType: string` Examples: ```js var node1 = math.parse('2.4'); var node2 = new math.expression.node.ConstantNode(2.4); var node3 = new math.expression.node.ConstantNode('2.4', 'number'); ``` ### FunctionAssignmentNode Construction: ``` new FunctionAssignmentNode(name: string, params: string[], expr: Node) ``` Properties: - `name: string` - `params: string[]` - `expr: Node` Examples: ```js var node1 = math.parse('f(x) = x^2'); var x = new math.expression.node.SymbolNode('x'); var two = new math.expression.node.ConstantNode(2); var expr = new math.expression.node.OperatorNode('^', 'pow', [x, 2]); var node2 = new math.expression.node.FunctionAssignmentNode('f', ['x'], expr); ``` ### FunctionNode Construction: ``` new FunctionNode(name: string, args: Node[]) ``` Properties: - `symbol: Node` - `args: Node[]` Examples: ```js var node1 = math.parse('sqrt(4)'); var four = new math.expression.node.ConstantNode(4); var node2 = new math.expression.node.FunctionNode('sqrt', [four]); ``` ### IndexNode Construction: ``` new IndexNode(object: Node, ranges: Node[]) ``` Note that ranges are one-based, including range end. Properties: - `object: Node` - `ranges: Node[]` Examples: ```js var node1 = math.parse('A[1:3, 2]'); var A = new math.expression.node.SymbolNode('A'); var one = new math.expression.node.ConstantNode(1); var two = new math.expression.node.ConstantNode(2); var three = new math.expression.node.ConstantNode(3); var range = new math.expression.node.RangeNode(one, three); var node2 = new math.expression.node.IndexNode(A, [range, two]); ``` ### OperatorNode Construction: ``` new OperatorNode(op: string, fn: string, args: Node[]) ``` Properties: - `op: string` - `fn: string` - `args: Node[]` Examples: ```js var node1 = math.parse('2.3 + 5'); var a = new math.expression.node.ConstantNode(2.3); var b = new math.expression.node.ConstantNode(5); var node2 = new math.expression.node.OperatorNode('+', 'add', [a, b]); ``` ### RangeNode Construction: ``` new RangeNode(start: Node, end: Node [, step: Node]) ``` Properties: - `start: Node` - `end: Node` - `step: Node | null` Examples: ```js var node1 = math.parse('1:10'); var node2 = math.parse('0:2:10'); var zero = new math.expression.node.ConstantNode(0); var one = new math.expression.node.ConstantNode(1); var two = new math.expression.node.ConstantNode(2); var ten = new math.expression.node.ConstantNode(10); var node3 = new math.expression.node.RangeNode(one, ten); var node4 = new math.expression.node.RangeNode(zero, ten, two); ``` ### SymbolNode Construction: ``` new SymbolNode(name: string) ``` Properties: - `name: string` Examples: ```js var node = math.parse('x'); var x = new math.expression.node.SymbolNode('x'); ``` ### UpdateNode Construction: ``` new UpdateNode(index: IndexNode, expr: Node) ``` Properties: - `index: IndexNode` - `expr: Node` Examples: ```js var node1 = math.parse('A[3, 1] = 4'); var A = new math.expression.node.SymbolNode('A'); var one = new math.expression.node.ConstantNode(1); var three = new math.expression.node.ConstantNode(3); var four = new math.expression.node.ConstantNode(4); var index = new math.expression.node.IndexNode(A, [three, one]); var node2 = new math.expression.node.UpdateNode(index, four); ```