mirror of
https://github.com/josdejong/mathjs.git
synced 2026-01-18 14:59:29 +00:00
Merge branch 'v4_constant_node' into v4_binary_operator_node
This commit is contained in:
commit
ae8f61a84b
@ -24,6 +24,14 @@ Breaking changes:
|
||||
need to sort an array with text. See #680.
|
||||
- `null` is no longer implicitly casted to a number `0`, so input like
|
||||
`math.add(2, null)` is no longer supported. See #830, #353.
|
||||
- The class `ConstantNode` is changed such that it just holds a value
|
||||
instead of holding a stringified value and it's type.
|
||||
`ConstantNode(valueStr, valueType`) is now `ConstantNode(value)`
|
||||
Stringification uses `math.format`, which may result in differently
|
||||
formatted numeric output.
|
||||
- The constants `true`, `false`, `null`, `undefined`, `NaN`, `Infinity`,
|
||||
and `uninitialized` are now parsed as ConstantNodes instead of
|
||||
SymbolNodes in the expression parser. See #833.
|
||||
- In function `math.format`, the option `notation: 'fixed'` no longer rounds to
|
||||
zero digits when no precision is specified: it leaves the digits as is.
|
||||
See #676.
|
||||
|
||||
@ -405,13 +405,12 @@ var node2 = new math.expression.node.ConditionalNode(condition, trueExpr, fa
|
||||
Construction:
|
||||
|
||||
```
|
||||
new ConstantNode(value: * [, valueType: string])
|
||||
new ConstantNode(value: *)
|
||||
```
|
||||
|
||||
Properties:
|
||||
|
||||
- `value: *`
|
||||
- `valueType: string`
|
||||
|
||||
Examples:
|
||||
|
||||
@ -419,7 +418,7 @@ Examples:
|
||||
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');
|
||||
var node3 = new math.expression.node.ConstantNode('foo');
|
||||
```
|
||||
|
||||
|
||||
|
||||
@ -1,79 +1,36 @@
|
||||
'use strict';
|
||||
|
||||
var getType = require('../../utils/types').type;
|
||||
var stringify = require('../../utils/string').stringify;
|
||||
var escape = require('../../utils/string').escape;
|
||||
var format = require('../../utils/string').format;
|
||||
|
||||
function factory (type, config, load, typed) {
|
||||
var Node = load(require('./Node'));
|
||||
var getType = load(require('../../function/utils/typeof'));
|
||||
|
||||
/**
|
||||
* A ConstantNode holds a constant value like a number or string. A ConstantNode
|
||||
* stores a stringified version of the value and uses this to compile to
|
||||
* JavaScript.
|
||||
*
|
||||
* In case of a stringified number as input, this may be compiled to a BigNumber
|
||||
* when the math instance is configured for BigNumbers.
|
||||
* A ConstantNode holds a constant value like a number or string.
|
||||
*
|
||||
* Usage:
|
||||
*
|
||||
* // stringified values with type
|
||||
* new ConstantNode('2.3', 'number');
|
||||
* new ConstantNode('true', 'boolean');
|
||||
* new ConstantNode('hello', 'string');
|
||||
*
|
||||
* // non-stringified values, type will be automatically detected
|
||||
* new ConstantNode(2.3);
|
||||
* new ConstantNode('hello');
|
||||
*
|
||||
* @param {string | number | boolean | null | undefined} value
|
||||
* When valueType is provided, value must contain
|
||||
* an uninterpreted string representing the value.
|
||||
* When valueType is undefined, value can be a
|
||||
* number, string, boolean, null, or undefined, and
|
||||
* the type will be determined automatically.
|
||||
* @param {string} [valueType] The type of value. Choose from 'number', 'string',
|
||||
* 'boolean', 'undefined', 'null'
|
||||
* @param {*} value Value can be any type (number, BigNumber, string, ...)
|
||||
* @constructor ConstantNode
|
||||
* @extends {Node}
|
||||
*/
|
||||
function ConstantNode(value, valueType) {
|
||||
// TODO: make the whole valueType redundant, simply parse numbers in parse.js already
|
||||
|
||||
function ConstantNode(value) {
|
||||
if (!(this instanceof ConstantNode)) {
|
||||
throw new SyntaxError('Constructor must be called with the new operator');
|
||||
}
|
||||
|
||||
if (valueType) {
|
||||
if (typeof valueType !== 'string') {
|
||||
throw new TypeError('String expected for parameter "valueType"');
|
||||
}
|
||||
if (typeof value !== 'string') {
|
||||
throw new TypeError('String expected for parameter "value"');
|
||||
}
|
||||
|
||||
this.value = value;
|
||||
this.valueType = valueType;
|
||||
}
|
||||
else {
|
||||
// stringify the value and determine the type
|
||||
this.value = value + '';
|
||||
this.valueType = getType(value);
|
||||
if (arguments.length === 2) {
|
||||
// TODO: remove deprecation error some day (created 2018-01-23)
|
||||
throw new SyntaxError('new ConstantNode(valueStr, valueType) is not supported anymore since math v4.0.0. Use new ConstantNode(value) instead, where value is a non-stringified value.');
|
||||
}
|
||||
|
||||
if (!SUPPORTED_TYPES[this.valueType]) {
|
||||
throw new TypeError('Unsupported type of value "' + this.valueType + '"');
|
||||
}
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
var SUPPORTED_TYPES = {
|
||||
'number': true,
|
||||
'string': true,
|
||||
'boolean': true,
|
||||
'undefined': true,
|
||||
'null': true
|
||||
};
|
||||
|
||||
ConstantNode.prototype = new Node();
|
||||
|
||||
ConstantNode.prototype.type = 'ConstantNode';
|
||||
@ -94,74 +51,13 @@ function factory (type, config, load, typed) {
|
||||
* evalNode(scope: Object, args: Object, context: *)
|
||||
*/
|
||||
ConstantNode.prototype._compile = function (math, argNames) {
|
||||
var value;
|
||||
var value = this.value;
|
||||
|
||||
switch (this.valueType) {
|
||||
case 'number':
|
||||
if (config.number === 'BigNumber') {
|
||||
value = new type.BigNumber(this.value);
|
||||
return function evalConstantNode() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
else if (config.number === 'Fraction') {
|
||||
value = new type.Fraction(this.value);
|
||||
return function evalConstantNode() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// remove leading zeros like '003.2' which are not allowed by JavaScript
|
||||
validateNumericValue(this.value);
|
||||
value = parseFloat(this.value.replace(/^(0*)[0-9]/, function (match, zeros) {
|
||||
return match.substring(zeros.length);
|
||||
}));
|
||||
return function evalConstantNode() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
case 'string':
|
||||
value = this.value;
|
||||
return function evalConstantNode() {
|
||||
return value;
|
||||
};
|
||||
|
||||
case 'boolean':
|
||||
// prevent invalid values
|
||||
return String(this.value) === 'true'
|
||||
? function () { return true; }
|
||||
: function () { return false; };
|
||||
|
||||
case 'undefined':
|
||||
return function evalConstantNode() {
|
||||
return undefined;
|
||||
};
|
||||
|
||||
case 'null':
|
||||
return function evalConstantNode() {
|
||||
return null;
|
||||
};
|
||||
|
||||
default:
|
||||
// TODO: move this error to the constructor?
|
||||
throw new TypeError('Unsupported type of constant "' + this.valueType + '"');
|
||||
return function evalConstantNode() {
|
||||
return value;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Test whether value is a string containing a numeric value
|
||||
* @param {String} value
|
||||
* @return {boolean} Returns true when ok
|
||||
*/
|
||||
function validateNumericValue (value) {
|
||||
// The following regexp is relatively permissive
|
||||
if (typeof value !== 'string' ||
|
||||
!/^[\-+]?((\d+\.?\d*)|(\d*\.?\d+))([eE][+\-]?\d+)?$/.test(value)) {
|
||||
throw new Error('Invalid numeric value "' + value + '"');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute a callback for each of the child nodes of this node
|
||||
* @param {function(child: Node, path: string, parent: Node)} callback
|
||||
@ -170,7 +66,6 @@ function factory (type, config, load, typed) {
|
||||
// nothing to do, we don't have childs
|
||||
};
|
||||
|
||||
|
||||
/**
|
||||
* 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.
|
||||
@ -186,7 +81,7 @@ function factory (type, config, load, typed) {
|
||||
* @return {ConstantNode}
|
||||
*/
|
||||
ConstantNode.prototype.clone = function () {
|
||||
return new ConstantNode(this.value, this.valueType);
|
||||
return new ConstantNode(this.value);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -195,13 +90,7 @@ function factory (type, config, load, typed) {
|
||||
* @return {string} str
|
||||
*/
|
||||
ConstantNode.prototype._toString = function (options) {
|
||||
switch (this.valueType) {
|
||||
case 'string':
|
||||
return stringify(this.value);
|
||||
|
||||
default:
|
||||
return this.value;
|
||||
}
|
||||
return format (this.value, options);
|
||||
};
|
||||
|
||||
/**
|
||||
@ -210,9 +99,12 @@ function factory (type, config, load, typed) {
|
||||
* @return {string} str
|
||||
*/
|
||||
ConstantNode.prototype.toHTML = function (options) {
|
||||
var value = escape(this.value);
|
||||
switch (this.valueType) {
|
||||
case 'number':
|
||||
var value = this._toString(options);
|
||||
|
||||
switch (getType(this.value)) {
|
||||
case 'number':
|
||||
case 'BigNumber':
|
||||
case 'Fraction':
|
||||
return '<span class="math-number">' + value + '</span>';
|
||||
case 'string':
|
||||
return '<span class="math-string">' + value + '</span>';
|
||||
@ -234,20 +126,24 @@ function factory (type, config, load, typed) {
|
||||
* @return {string} str
|
||||
*/
|
||||
ConstantNode.prototype._toTex = function (options) {
|
||||
var value = this.value,
|
||||
index;
|
||||
switch (this.valueType) {
|
||||
var value = this._toString(options);
|
||||
|
||||
switch (getType(this.value)) {
|
||||
case 'string':
|
||||
return '\\mathtt{' + stringify(value) + '}';
|
||||
return '\\mathtt{' + value + '}';
|
||||
|
||||
case 'number':
|
||||
index = value.toLowerCase().indexOf('e');
|
||||
case 'BigNumber':
|
||||
var index = value.toLowerCase().indexOf('e');
|
||||
if (index !== -1) {
|
||||
return value.substring(0, index) + '\\cdot10^{' +
|
||||
value.substring(index + 1) + '}';
|
||||
}
|
||||
return value;
|
||||
|
||||
case 'Fraction':
|
||||
return this.value.toLatex();
|
||||
|
||||
default:
|
||||
return value;
|
||||
}
|
||||
|
||||
@ -188,7 +188,7 @@ function factory (type, config, load, typed) {
|
||||
IndexNode.prototype.isObjectProperty = function () {
|
||||
return this.dimensions.length === 1 &&
|
||||
type.isConstantNode(this.dimensions[0]) &&
|
||||
this.dimensions[0].valueType === 'string';
|
||||
typeof this.dimensions[0].value === 'string';
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@ -4,6 +4,9 @@ var ArgumentsError = require('../error/ArgumentsError');
|
||||
var deepMap = require('../utils/collection/deepMap');
|
||||
|
||||
function factory (type, config, load, typed) {
|
||||
var numeric = load(require('../type/numeric'));
|
||||
var uninitialized = require('../utils/array').UNINITIALIZED
|
||||
|
||||
var AccessorNode = load(require('./node/AccessorNode'));
|
||||
var ArrayNode = load(require('./node/ArrayNode'));
|
||||
var AssignmentNode = load(require('./node/AssignmentNode'));
|
||||
@ -19,7 +22,6 @@ function factory (type, config, load, typed) {
|
||||
var RangeNode = load(require('./node/RangeNode'));
|
||||
var SymbolNode = load(require('./node/SymbolNode'));
|
||||
|
||||
|
||||
/**
|
||||
* Parse an expression. Returns a node tree, which can be evaluated by
|
||||
* invoking node.eval();
|
||||
@ -143,6 +145,19 @@ function factory (type, config, load, typed) {
|
||||
'not': true
|
||||
};
|
||||
|
||||
var CONSTANTS = {
|
||||
'true': true,
|
||||
'false': false,
|
||||
'null': null,
|
||||
'undefined': undefined,
|
||||
'uninitialized': uninitialized
|
||||
}
|
||||
|
||||
var NUMERIC_CONSTANTS = [
|
||||
'NaN',
|
||||
'Infinity'
|
||||
]
|
||||
|
||||
var extra_nodes = {}; // current extra nodes
|
||||
var expression = ''; // current expression
|
||||
var comment = ''; // last parsed comment
|
||||
@ -557,7 +572,7 @@ function factory (type, config, load, typed) {
|
||||
}
|
||||
else {
|
||||
if (!node) {
|
||||
node = new ConstantNode('undefined', 'undefined');
|
||||
node = new ConstantNode(undefined);
|
||||
node.comment = comment;
|
||||
}
|
||||
|
||||
@ -858,7 +873,7 @@ function factory (type, config, load, typed) {
|
||||
|
||||
if (token === ':') {
|
||||
// implicit start=1 (one-based)
|
||||
node = new ConstantNode('1', 'number');
|
||||
node = new ConstantNode(1);
|
||||
}
|
||||
else {
|
||||
// explicit start
|
||||
@ -1136,8 +1151,17 @@ function factory (type, config, load, typed) {
|
||||
|
||||
getToken();
|
||||
|
||||
if (CONSTANTS.hasOwnProperty(name)) { // true, false, null, ...
|
||||
node = new ConstantNode(CONSTANTS[name]);
|
||||
}
|
||||
else if (NUMERIC_CONSTANTS.indexOf(name) !== -1) { // NaN, Infinity
|
||||
node = new ConstantNode(numeric(name));
|
||||
}
|
||||
else {
|
||||
node = new SymbolNode(name);
|
||||
}
|
||||
|
||||
// parse function parameters and matrix index
|
||||
node = new SymbolNode(name);
|
||||
node = parseAccessors(node);
|
||||
return node;
|
||||
}
|
||||
@ -1250,7 +1274,7 @@ function factory (type, config, load, typed) {
|
||||
str = parseStringToken();
|
||||
|
||||
// create constant
|
||||
node = new ConstantNode(str, 'string');
|
||||
node = new ConstantNode(str);
|
||||
|
||||
// parse index parameters
|
||||
node = parseAccessors(node);
|
||||
@ -1439,14 +1463,14 @@ function factory (type, config, load, typed) {
|
||||
* @private
|
||||
*/
|
||||
function parseNumber () {
|
||||
var number;
|
||||
var numberStr;
|
||||
|
||||
if (token_type === TOKENTYPE.NUMBER) {
|
||||
// this is a number
|
||||
number = token;
|
||||
numberStr = token;
|
||||
getToken();
|
||||
|
||||
return new ConstantNode(number, 'number');
|
||||
return new ConstantNode(numeric(numberStr, config.number));
|
||||
}
|
||||
|
||||
return parseParentheses();
|
||||
|
||||
@ -3,6 +3,9 @@
|
||||
function factory (type, config, load, typed) {
|
||||
var parse = load(require('../../expression/parse'));
|
||||
var simplify = load(require('./simplify'));
|
||||
var equal = load(require('../relational/equal'));
|
||||
var isZero = load(require('../utils/isZero'));
|
||||
var numeric = load(require('../../type/numeric'));
|
||||
var ConstantNode = load(require('../../expression/node/ConstantNode'));
|
||||
var FunctionNode = load(require('../../expression/node/FunctionNode'));
|
||||
var OperatorNode = load(require('../../expression/node/OperatorNode'));
|
||||
@ -142,7 +145,7 @@ function factory (type, config, load, typed) {
|
||||
'Object, SymbolNode, string': function (constNodes, node, varName) {
|
||||
// Treat other variables like constants. For reasoning, see:
|
||||
// https://en.wikipedia.org/wiki/Partial_derivative
|
||||
if (node.name != varName) {
|
||||
if (node.name !== varName) {
|
||||
return constNodes[node] = true;
|
||||
}
|
||||
return false;
|
||||
@ -153,14 +156,14 @@ function factory (type, config, load, typed) {
|
||||
},
|
||||
|
||||
'Object, FunctionAssignmentNode, string': function (constNodes, node, varName) {
|
||||
if (node.params.indexOf(varName) == -1) {
|
||||
if (node.params.indexOf(varName) === -1) {
|
||||
return constNodes[node] = true;
|
||||
}
|
||||
return constTag(constNodes, node.expr, varName);
|
||||
},
|
||||
|
||||
'Object, FunctionNode | OperatorNode, string': function (constNodes, node, varName) {
|
||||
if (node.args.length != 0) {
|
||||
if (node.args.length !== 0) {
|
||||
var isConst = constTag(constNodes, node.args[0], varName);
|
||||
for (var i = 1; i < node.args.length; ++i) {
|
||||
isConst = constTag(constNodes, node.args[i], varName) && isConst;
|
||||
@ -183,14 +186,14 @@ function factory (type, config, load, typed) {
|
||||
*/
|
||||
var _derivative = typed('_derivative', {
|
||||
'ConstantNode, Object': function (node) {
|
||||
return new ConstantNode('0', node.valueType);
|
||||
return createConstantNode(0);
|
||||
},
|
||||
|
||||
'SymbolNode, Object': function (node, constNodes) {
|
||||
if (constNodes[node] !== undefined) {
|
||||
return new ConstantNode('0', config.number);
|
||||
return createConstantNode(0);
|
||||
}
|
||||
return new ConstantNode('1', config.number);
|
||||
return createConstantNode(1);
|
||||
},
|
||||
|
||||
'ParenthesisNode, Object': function (node, constNodes) {
|
||||
@ -199,18 +202,18 @@ function factory (type, config, load, typed) {
|
||||
|
||||
'FunctionAssignmentNode, Object': function (node, constNodes) {
|
||||
if (constNodes[node] !== undefined) {
|
||||
return new ConstantNode('0', config.number);
|
||||
return createConstantNode(0);
|
||||
}
|
||||
return _derivative(node.expr, constNodes);
|
||||
},
|
||||
|
||||
'FunctionNode, Object': function (node, constNodes) {
|
||||
if (node.args.length != 1) {
|
||||
if (node.args.length !== 1) {
|
||||
funcArgsCheck(node);
|
||||
}
|
||||
|
||||
if (constNodes[node] !== undefined) {
|
||||
return new ConstantNode('0', config.number);
|
||||
return createConstantNode(0);
|
||||
}
|
||||
|
||||
var arg1 = node.args[0];
|
||||
@ -225,12 +228,12 @@ function factory (type, config, load, typed) {
|
||||
// d/dx(cbrt(x)) = 1 / (3x^(2/3))
|
||||
div = true;
|
||||
funcDerivative = new OperatorNode('*', 'multiply', [
|
||||
new ConstantNode('3', config.number),
|
||||
createConstantNode(3),
|
||||
new OperatorNode('^', 'pow', [
|
||||
arg1,
|
||||
new OperatorNode('/', 'divide', [
|
||||
new ConstantNode('2', config.number),
|
||||
new ConstantNode('3', config.number)
|
||||
createConstantNode(2),
|
||||
createConstantNode(3)
|
||||
])
|
||||
])
|
||||
]);
|
||||
@ -238,10 +241,10 @@ function factory (type, config, load, typed) {
|
||||
case 'sqrt':
|
||||
case 'nthRoot':
|
||||
// d/dx(sqrt(x)) = 1 / (2*sqrt(x))
|
||||
if (node.args.length == 1) {
|
||||
if (node.args.length === 1) {
|
||||
div = true;
|
||||
funcDerivative = new OperatorNode('*', 'multiply', [
|
||||
new ConstantNode('2', config.number),
|
||||
createConstantNode(2),
|
||||
new FunctionNode('sqrt', [arg1])
|
||||
]);
|
||||
break;
|
||||
@ -249,7 +252,7 @@ function factory (type, config, load, typed) {
|
||||
|
||||
// Rearrange from nthRoot(x, a) -> x^(1/a)
|
||||
arg2 = new OperatorNode('/', 'divide', [
|
||||
new ConstantNode('1', config.number),
|
||||
createConstantNode(1),
|
||||
node.args[1]
|
||||
]);
|
||||
|
||||
@ -258,9 +261,10 @@ function factory (type, config, load, typed) {
|
||||
|
||||
return _derivative(new OperatorNode('^', 'pow', [arg1, arg2]), constNodes);
|
||||
case 'log10':
|
||||
arg2 = new ConstantNode('10', config.number);
|
||||
arg2 = createConstantNode(10);
|
||||
/* fall through! */
|
||||
case 'log':
|
||||
if (!arg2 && node.args.length == 1) {
|
||||
if (!arg2 && node.args.length === 1) {
|
||||
// d/dx(log(x)) = 1 / x
|
||||
funcDerivative = arg1.clone();
|
||||
} else if (arg2 || constNodes[node.args[1]] !== undefined) {
|
||||
@ -297,7 +301,7 @@ function factory (type, config, load, typed) {
|
||||
// d/dx(tan(x)) = sec(x)^2
|
||||
funcDerivative = new OperatorNode('^', 'pow', [
|
||||
new FunctionNode('sec', [arg1.clone()]),
|
||||
new ConstantNode('2', config.number)
|
||||
createConstantNode(2)
|
||||
]);
|
||||
break;
|
||||
case 'sec':
|
||||
@ -320,7 +324,7 @@ function factory (type, config, load, typed) {
|
||||
negative = true;
|
||||
funcDerivative = new OperatorNode('^', 'pow', [
|
||||
new FunctionNode('csc', [arg1.clone()]),
|
||||
new ConstantNode('2', config.number)
|
||||
createConstantNode(2)
|
||||
]);
|
||||
break;
|
||||
case 'asin':
|
||||
@ -328,10 +332,10 @@ function factory (type, config, load, typed) {
|
||||
div = true;
|
||||
funcDerivative = new FunctionNode('sqrt', [
|
||||
new OperatorNode('-', 'subtract', [
|
||||
new ConstantNode('1', config.number),
|
||||
createConstantNode(1),
|
||||
new OperatorNode('^', 'pow', [
|
||||
arg1.clone(),
|
||||
new ConstantNode('2', config.number)
|
||||
createConstantNode(2)
|
||||
])
|
||||
])
|
||||
]);
|
||||
@ -342,10 +346,10 @@ function factory (type, config, load, typed) {
|
||||
negative = true;
|
||||
funcDerivative = new FunctionNode('sqrt', [
|
||||
new OperatorNode('-', 'subtract', [
|
||||
new ConstantNode('1', config.number),
|
||||
createConstantNode(1),
|
||||
new OperatorNode('^', 'pow', [
|
||||
arg1.clone(),
|
||||
new ConstantNode('2', config.number)
|
||||
createConstantNode(2)
|
||||
])
|
||||
])
|
||||
]);
|
||||
@ -356,9 +360,9 @@ function factory (type, config, load, typed) {
|
||||
funcDerivative = new OperatorNode('+', 'add', [
|
||||
new OperatorNode('^', 'pow', [
|
||||
arg1.clone(),
|
||||
new ConstantNode('2', config.number)
|
||||
createConstantNode(2)
|
||||
]),
|
||||
new ConstantNode('1', config.number)
|
||||
createConstantNode(1)
|
||||
]);
|
||||
break;
|
||||
case 'asec':
|
||||
@ -370,9 +374,9 @@ function factory (type, config, load, typed) {
|
||||
new OperatorNode('-', 'subtract', [
|
||||
new OperatorNode('^', 'pow', [
|
||||
arg1.clone(),
|
||||
new ConstantNode('2', config.number)
|
||||
createConstantNode(2)
|
||||
]),
|
||||
new ConstantNode('1', config.number)
|
||||
createConstantNode(1)
|
||||
])
|
||||
])
|
||||
]);
|
||||
@ -387,9 +391,9 @@ function factory (type, config, load, typed) {
|
||||
new OperatorNode('-', 'subtract', [
|
||||
new OperatorNode('^', 'pow', [
|
||||
arg1.clone(),
|
||||
new ConstantNode('2', config.number)
|
||||
createConstantNode(2)
|
||||
]),
|
||||
new ConstantNode('1', config.number)
|
||||
createConstantNode(1)
|
||||
])
|
||||
])
|
||||
]);
|
||||
@ -401,9 +405,9 @@ function factory (type, config, load, typed) {
|
||||
funcDerivative = new OperatorNode('+', 'add', [
|
||||
new OperatorNode('^', 'pow', [
|
||||
arg1.clone(),
|
||||
new ConstantNode('2', config.number)
|
||||
createConstantNode(2)
|
||||
]),
|
||||
new ConstantNode('1', config.number)
|
||||
createConstantNode(1)
|
||||
]);
|
||||
break;
|
||||
case 'sinh':
|
||||
@ -418,7 +422,7 @@ function factory (type, config, load, typed) {
|
||||
// d/dx(tanh(x)) = sech(x)^2
|
||||
funcDerivative = new OperatorNode('^', 'pow', [
|
||||
new FunctionNode('sech', [arg1.clone()]),
|
||||
new ConstantNode('2', config.number)
|
||||
createConstantNode(2)
|
||||
]);
|
||||
break;
|
||||
case 'sech':
|
||||
@ -442,7 +446,7 @@ function factory (type, config, load, typed) {
|
||||
negative = true;
|
||||
funcDerivative = new OperatorNode('^', 'pow', [
|
||||
new FunctionNode('csch', [arg1.clone()]),
|
||||
new ConstantNode('2', config.number)
|
||||
createConstantNode(2)
|
||||
]);
|
||||
break;
|
||||
case 'asinh':
|
||||
@ -452,9 +456,9 @@ function factory (type, config, load, typed) {
|
||||
new OperatorNode('+', 'add', [
|
||||
new OperatorNode('^', 'pow', [
|
||||
arg1.clone(),
|
||||
new ConstantNode('2', config.number)
|
||||
createConstantNode(2)
|
||||
]),
|
||||
new ConstantNode('1', config.number)
|
||||
createConstantNode(1)
|
||||
])
|
||||
]);
|
||||
break;
|
||||
@ -465,9 +469,9 @@ function factory (type, config, load, typed) {
|
||||
new OperatorNode('-', 'subtract', [
|
||||
new OperatorNode('^', 'pow', [
|
||||
arg1.clone(),
|
||||
new ConstantNode('2', config.number)
|
||||
createConstantNode(2)
|
||||
]),
|
||||
new ConstantNode('1', config.number),
|
||||
createConstantNode(1)
|
||||
])
|
||||
]);
|
||||
break;
|
||||
@ -475,10 +479,10 @@ function factory (type, config, load, typed) {
|
||||
// d/dx(atanh(x)) = 1 / (1 - x^2)
|
||||
div = true;
|
||||
funcDerivative = new OperatorNode('-', 'subtract', [
|
||||
new ConstantNode('1', config.number),
|
||||
createConstantNode(1),
|
||||
new OperatorNode('^', 'pow', [
|
||||
arg1.clone(),
|
||||
new ConstantNode('2', config.number)
|
||||
createConstantNode(2)
|
||||
])
|
||||
]);
|
||||
break;
|
||||
@ -490,10 +494,10 @@ function factory (type, config, load, typed) {
|
||||
arg1.clone(),
|
||||
new FunctionNode('sqrt', [
|
||||
new OperatorNode('-', 'subtract', [
|
||||
new ConstantNode('1', config.number),
|
||||
createConstantNode(1),
|
||||
new OperatorNode('^', 'pow', [
|
||||
arg1.clone(),
|
||||
new ConstantNode('2', config.number)
|
||||
createConstantNode(2)
|
||||
])
|
||||
])
|
||||
])
|
||||
@ -509,9 +513,9 @@ function factory (type, config, load, typed) {
|
||||
new OperatorNode('+', 'add', [
|
||||
new OperatorNode('^', 'pow', [
|
||||
arg1.clone(),
|
||||
new ConstantNode('2', config.number)
|
||||
createConstantNode(2)
|
||||
]),
|
||||
new ConstantNode('1', config.number)
|
||||
createConstantNode(1)
|
||||
])
|
||||
])
|
||||
]);
|
||||
@ -521,10 +525,10 @@ function factory (type, config, load, typed) {
|
||||
div = true;
|
||||
negative = true;
|
||||
funcDerivative = new OperatorNode('-', 'subtract', [
|
||||
new ConstantNode('1', config.number),
|
||||
createConstantNode(1),
|
||||
new OperatorNode('^', 'pow', [
|
||||
arg1.clone(),
|
||||
new ConstantNode('2', config.number)
|
||||
createConstantNode(2)
|
||||
])
|
||||
]);
|
||||
break;
|
||||
@ -560,7 +564,7 @@ function factory (type, config, load, typed) {
|
||||
|
||||
'OperatorNode, Object': function (node, constNodes) {
|
||||
if (constNodes[node] !== undefined) {
|
||||
return new ConstantNode('0', config.number);
|
||||
return createConstantNode(0);
|
||||
}
|
||||
|
||||
var arg1 = node.args[0];
|
||||
@ -574,7 +578,7 @@ function factory (type, config, load, typed) {
|
||||
}));
|
||||
case '-':
|
||||
// d/dx(+/-f(x)) = +/-f'(x)
|
||||
if (node.args.length == 1) {
|
||||
if (node.args.length === 1) {
|
||||
return new OperatorNode(node.op, node.fn, [_derivative(arg1, constNodes)]);
|
||||
}
|
||||
|
||||
@ -623,7 +627,7 @@ function factory (type, config, load, typed) {
|
||||
new OperatorNode('-', 'unaryMinus', [arg1]),
|
||||
new OperatorNode('/', 'divide', [
|
||||
_derivative(arg2, constNodes),
|
||||
new OperatorNode('^', 'pow', [arg2.clone(), new ConstantNode('2', config.number)])
|
||||
new OperatorNode('^', 'pow', [arg2.clone(), createConstantNode(2)])
|
||||
])
|
||||
]);
|
||||
}
|
||||
@ -634,13 +638,13 @@ function factory (type, config, load, typed) {
|
||||
new OperatorNode('*', 'multiply', [_derivative(arg1, constNodes), arg2.clone()]),
|
||||
new OperatorNode('*', 'multiply', [arg1.clone(), _derivative(arg2, constNodes)])
|
||||
]),
|
||||
new OperatorNode('^', 'pow', [arg2.clone(), new ConstantNode('2', config.number)])
|
||||
new OperatorNode('^', 'pow', [arg2.clone(), createConstantNode(2)])
|
||||
]);
|
||||
case '^':
|
||||
if (constNodes[arg1] !== undefined) {
|
||||
// If is secretly constant; 0^f(x) = 1 (in JS), 1^f(x) = 1
|
||||
if (type.isConstantNode(arg1) && (arg1.value === '0' || arg1.value === '1')) {
|
||||
return new ConstantNode('0', config.number);
|
||||
if (type.isConstantNode(arg1) && (isZero(arg1.value) || equal(arg1.value, 1))) {
|
||||
return createConstantNode(0);
|
||||
}
|
||||
|
||||
// d/dx(c^f(x)) = c^f(x)*ln(c)*f'(x)
|
||||
@ -655,14 +659,12 @@ function factory (type, config, load, typed) {
|
||||
|
||||
if (constNodes[arg2] !== undefined) {
|
||||
if (type.isConstantNode(arg2)) {
|
||||
var expValue = arg2.value;
|
||||
|
||||
// If is secretly constant; f(x)^0 = 1 -> d/dx(1) = 0
|
||||
if (expValue === '0') {
|
||||
return new ConstantNode('0', config.number);
|
||||
if (isZero(arg2.value)) {
|
||||
return createConstantNode(0);
|
||||
}
|
||||
// Ignore exponent; f(x)^1 = f(x)
|
||||
if (expValue === '1') {
|
||||
if (equal(arg2.value, 1)) {
|
||||
return _derivative(arg1, constNodes);
|
||||
}
|
||||
}
|
||||
@ -672,7 +674,7 @@ function factory (type, config, load, typed) {
|
||||
arg1.clone(),
|
||||
new OperatorNode('-', 'subtract', [
|
||||
arg2,
|
||||
new ConstantNode('1', config.number)
|
||||
createConstantNode(1)
|
||||
])
|
||||
]);
|
||||
|
||||
@ -681,7 +683,7 @@ function factory (type, config, load, typed) {
|
||||
new OperatorNode('*', 'multiply', [
|
||||
_derivative(arg1, constNodes),
|
||||
powMinusOne
|
||||
]),
|
||||
])
|
||||
]);
|
||||
}
|
||||
|
||||
@ -714,7 +716,7 @@ function factory (type, config, load, typed) {
|
||||
*/
|
||||
function funcArgsCheck(node) {
|
||||
//TODO add min, max etc
|
||||
if ((node.name == 'log' || node.name == 'nthRoot') && node.args.length == 2) {
|
||||
if ((node.name === 'log' || node.name === 'nthRoot') && node.args.length === 2) {
|
||||
return;
|
||||
}
|
||||
|
||||
@ -723,13 +725,23 @@ function factory (type, config, load, typed) {
|
||||
// Change all args to constants to avoid unidentified
|
||||
// symbol error when compiling function
|
||||
for (var i = 0; i < node.args.length; ++i) {
|
||||
node.args[i] = new ConstantNode(0);
|
||||
node.args[i] = createConstantNode(0);
|
||||
}
|
||||
|
||||
node.compile().eval();
|
||||
throw new Error('Expected TypeError, but none found');
|
||||
}
|
||||
|
||||
/**
|
||||
* Helper function to create a constant node with a specific type
|
||||
* (number, BigNumber, Fraction)
|
||||
* @param {number} value
|
||||
* @param {string} [valueType]
|
||||
* @return {ConstantNode}
|
||||
*/
|
||||
function createConstantNode(value, valueType) {
|
||||
return new ConstantNode(numeric(value, valueType || config.number));
|
||||
}
|
||||
|
||||
return derivative;
|
||||
}
|
||||
|
||||
@ -3,6 +3,7 @@
|
||||
|
||||
function factory (type, config, load, typed, math) {
|
||||
var parse = load(require('../../expression/parse'));
|
||||
var equal = load(require('../relational/equal'));
|
||||
var ConstantNode = load(require('../../expression/node/ConstantNode'));
|
||||
var FunctionNode = load(require('../../expression/node/FunctionNode'));
|
||||
var OperatorNode = load(require('../../expression/node/OperatorNode'));
|
||||
@ -599,7 +600,7 @@ function factory (type, config, load, typed, math) {
|
||||
}
|
||||
else if (rule instanceof ConstantNode) {
|
||||
// Literal constant must match exactly
|
||||
if(rule.value !== node.value) {
|
||||
if(!equal(rule.value, node.value)) {
|
||||
return [];
|
||||
}
|
||||
}
|
||||
@ -624,7 +625,7 @@ function factory (type, config, load, typed, math) {
|
||||
*/
|
||||
function _exactMatch(p, q) {
|
||||
if(p instanceof ConstantNode && q instanceof ConstantNode) {
|
||||
if(p.value !== q.value) {
|
||||
if(!equal(p.value, q.value)) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@ -4,6 +4,7 @@ var digits = require('./../../../utils/number').digits;
|
||||
// TODO this could be improved by simplifying seperated constants under associative and commutative operators
|
||||
function factory(type, config, load, typed, math) {
|
||||
var util = load(require('./util'));
|
||||
var isNumeric = load(require('../../utils/isNumeric'));
|
||||
var isCommutative = util.isCommutative;
|
||||
var isAssociative = util.isAssociative;
|
||||
var allChildren = util.allChildren;
|
||||
@ -151,7 +152,7 @@ function factory(type, config, load, typed, math) {
|
||||
case 'SymbolNode':
|
||||
return node;
|
||||
case 'ConstantNode':
|
||||
if (node.valueType === 'number') {
|
||||
if (typeof node.value === 'number') {
|
||||
return _toNumber(node.value);
|
||||
}
|
||||
return node;
|
||||
|
||||
@ -1,6 +1,15 @@
|
||||
'use strict';
|
||||
|
||||
function factory(type, config, load, typed, math) {
|
||||
var equal = load(require('../../relational/equal'));
|
||||
var isZero = load(require('../../utils/isZero'));
|
||||
var isNumeric = load(require('../../utils/isNumeric'));
|
||||
var add = load(require('../../arithmetic/add'));
|
||||
var subtract = load(require('../../arithmetic/subtract'));
|
||||
var multiply = load(require('../../arithmetic/multiply'));
|
||||
var divide = load(require('../../arithmetic/divide'));
|
||||
var pow = load(require('../../arithmetic/pow'));
|
||||
|
||||
var ConstantNode = math.expression.node.ConstantNode;
|
||||
var OperatorNode = math.expression.node.OperatorNode;
|
||||
var FunctionNode = math.expression.node.FunctionNode;
|
||||
@ -41,13 +50,13 @@ function factory(type, config, load, typed, math) {
|
||||
return node.args[0];
|
||||
}
|
||||
if (type.isConstantNode(a0)) {
|
||||
if (a0.value === "0") {
|
||||
if (isZero(a0.value)) {
|
||||
return a1;
|
||||
} else if (type.isConstantNode(a1) && a0.value && a0.value.length < 5 && a1.value && a1.value.length < 5) {
|
||||
return new ConstantNode(Number(a0.value) + Number(a1.value));
|
||||
} else if (type.isConstantNode(a1)) {
|
||||
return new ConstantNode(add(a0.value, a1.value));
|
||||
}
|
||||
}
|
||||
if (type.isConstantNode(a1) && a1.value === "0") {
|
||||
if (type.isConstantNode(a1) && isZero(a1.value)) {
|
||||
return a0;
|
||||
}
|
||||
if (node.args.length === 2 && type.isOperatorNode(a1) && a1.op === '-' && a1.fn === 'unaryMinus') {
|
||||
@ -56,14 +65,14 @@ function factory(type, config, load, typed, math) {
|
||||
return new OperatorNode(node.op, node.fn, a1 ? [a0,a1] : [a0]);
|
||||
} else if (node.op === "-") {
|
||||
if (type.isConstantNode(a0) && a1) {
|
||||
if (type.isConstantNode(a1) && a0.value && a0.value.length < 5 && a1.value && a1.value.length < 5) {
|
||||
return new ConstantNode(Number(a0.value) - Number(a1.value));
|
||||
} else if (a0.value === "0") {
|
||||
if (type.isConstantNode(a1)) {
|
||||
return new ConstantNode(subtract(a0.value, a1.value));
|
||||
} else if (isZero(a0.value)) {
|
||||
return new OperatorNode("-", "unaryMinus", [a1]);
|
||||
}
|
||||
}
|
||||
if (node.fn === "subtract" && node.args.length === 2) {
|
||||
if (type.isConstantNode(a1) && a1.value === "0") {
|
||||
if (type.isConstantNode(a1) && isZero(a1.value)) {
|
||||
return a0;
|
||||
}
|
||||
if (type.isOperatorNode(a1) && a1.fn === "unaryMinus") {
|
||||
@ -83,23 +92,23 @@ function factory(type, config, load, typed, math) {
|
||||
throw new Error('never happens');
|
||||
} else if (node.op === "*") {
|
||||
if (type.isConstantNode(a0)) {
|
||||
if (a0.value === "0") {
|
||||
if (isZero(a0.value)) {
|
||||
return node0;
|
||||
} else if (a0.value === "1") {
|
||||
} else if (equal(a0.value, 1)) {
|
||||
return a1;
|
||||
} else if (type.isConstantNode(a1) && a0.value && a0.value.length < 5 && a1.value && a1.value.length < 5) {
|
||||
return new ConstantNode(Number(a0.value) * Number(a1.value));
|
||||
} else if (type.isConstantNode(a1)) {
|
||||
return new ConstantNode(multiply(a0.value, a1.value));
|
||||
}
|
||||
}
|
||||
if (type.isConstantNode(a1)) {
|
||||
if (a1.value === "0") {
|
||||
if (isZero(a1.value)) {
|
||||
return node0;
|
||||
} else if (a1.value === "1") {
|
||||
} else if (equal(a1.value, 1)) {
|
||||
return a0;
|
||||
} else if (type.isOperatorNode(a0) && a0.op === node.op) {
|
||||
var a00 = a0.args[0];
|
||||
if (type.isConstantNode(a00) && a1.value && a1.value.length < 5 && a00.value && a00.value.length < 5) {
|
||||
var a00_a1 = new ConstantNode(Number(a0.args[0].value) * Number(a1.value));
|
||||
if (type.isConstantNode(a00)) {
|
||||
var a00_a1 = new ConstantNode(multiply(a00.value, a1.value));
|
||||
return new OperatorNode(node.op, node.fn, [a00_a1, a0.args[1]]); // constants on left
|
||||
}
|
||||
}
|
||||
@ -108,32 +117,30 @@ function factory(type, config, load, typed, math) {
|
||||
return new OperatorNode(node.op, node.fn, [a0, a1]);
|
||||
} else if (node.op === "/") {
|
||||
if (type.isConstantNode(a0)) {
|
||||
if (a0.value === "0") {
|
||||
if (isZero(a0.value)) {
|
||||
return node0;
|
||||
} else if (type.isConstantNode(a1) && a0.value && a0.value.length < 5 && (a1.value === "1" || a1.value==="2" || a1.value==="4")) {
|
||||
return new ConstantNode(Number(a0.value) / Number(a1.value));
|
||||
} else if (type.isConstantNode(a1) &&
|
||||
(equal(a1.value, 1) || equal(a1.value, 2) || equal(a1.value, 4))) {
|
||||
return new ConstantNode(divide(a0.value, a1.value));
|
||||
}
|
||||
}
|
||||
return new OperatorNode(node.op, node.fn, [a0, a1]);
|
||||
} else if (node.op === "^") {
|
||||
if (type.isConstantNode(a1)) {
|
||||
if (a1.value === "0") {
|
||||
if (isZero(a1.value)) {
|
||||
return node1;
|
||||
} else if (a1.value === "1") {
|
||||
} else if (equal(a1.value, 1)) {
|
||||
return a0;
|
||||
} else {
|
||||
if (type.isConstantNode(a0) &&
|
||||
a0.value && a0.value.length < 5 &&
|
||||
a1.value && a1.value.length < 2) {
|
||||
if (type.isConstantNode(a0)) {
|
||||
// fold constant
|
||||
return new ConstantNode(
|
||||
math.pow(Number(a0.value), Number(a1.value)));
|
||||
return new ConstantNode(pow(a0.value, a1.value));
|
||||
} else if (type.isOperatorNode(a0) && a0.op === "^") {
|
||||
var a01 = a0.args[1];
|
||||
if (type.isConstantNode(a01)) {
|
||||
return new OperatorNode(node.op, node.fn, [
|
||||
a0.args[0],
|
||||
new ConstantNode(a01.value * a1.value)
|
||||
new ConstantNode(multiply(a01.value, a1.value))
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,7 +1,5 @@
|
||||
'use strict';
|
||||
|
||||
var types = require('../../utils/types');
|
||||
|
||||
function factory (type, config, load, typed) {
|
||||
/**
|
||||
* Determine the type of a variable.
|
||||
@ -48,11 +46,19 @@ function factory (type, config, load, typed) {
|
||||
*/
|
||||
var _typeof = typed('_typeof', {
|
||||
'any': function (x) {
|
||||
// JavaScript types
|
||||
var t = types.type(x);
|
||||
var t = typeof x;
|
||||
|
||||
// math.js types
|
||||
if (t === 'Object') {
|
||||
if (t === 'object') {
|
||||
// JavaScript types
|
||||
if (x === null) return 'null';
|
||||
if (Array.isArray(x)) return 'Array';
|
||||
if (x instanceof Date) return 'Date';
|
||||
if (x instanceof RegExp) return 'RegExp';
|
||||
if (x instanceof Boolean) return 'boolean';
|
||||
if (x instanceof Number) return 'number';
|
||||
if (x instanceof String) return 'string';
|
||||
|
||||
// math.js types
|
||||
if (type.isBigNumber(x)) return 'BigNumber';
|
||||
if (type.isComplex(x)) return 'Complex';
|
||||
if (type.isFraction(x)) return 'Fraction';
|
||||
@ -62,9 +68,13 @@ function factory (type, config, load, typed) {
|
||||
if (type.isRange(x)) return 'Range';
|
||||
if (type.isChain(x)) return 'Chain';
|
||||
if (type.isHelp(x)) return 'Help';
|
||||
|
||||
return 'Object';
|
||||
}
|
||||
|
||||
return t;
|
||||
if (t === 'function') return 'Function';
|
||||
|
||||
return t; // can be 'string', 'number', 'boolean', ...
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
50
lib/type/numeric.js
Normal file
50
lib/type/numeric.js
Normal file
@ -0,0 +1,50 @@
|
||||
'use strict';
|
||||
|
||||
function factory(type, config, load, typed) {
|
||||
|
||||
// TODO: expose this function to mathjs, add documentation
|
||||
|
||||
/**
|
||||
* Create a numeric value with a specific type: number, BigNumber, or Fraction
|
||||
*
|
||||
* @param {string | number} value
|
||||
* @param {'number' | 'BigNumber' | 'Fraction'}
|
||||
* @return {number | BigNumber | Fraction} Returns an instance of the
|
||||
* numeric requested type
|
||||
*/
|
||||
return function numeric (value, valueType) {
|
||||
if (valueType === 'BigNumber') {
|
||||
return new type.BigNumber(value);
|
||||
}
|
||||
else if (valueType === 'Fraction') {
|
||||
return new type.Fraction(value);
|
||||
}
|
||||
else {
|
||||
// valueType === 'number' or undefined // TODO: check this
|
||||
if (typeof value === 'number') {
|
||||
return value;
|
||||
}
|
||||
else {
|
||||
if (value === 'Infinity') {
|
||||
return Infinity;
|
||||
}
|
||||
|
||||
if (value === 'NaN') {
|
||||
return NaN;
|
||||
}
|
||||
|
||||
// The following regexp is relatively permissive
|
||||
if (!/^[\-+]?((\d+\.?\d*)|(\d*\.?\d+))([eE][+\-]?\d+)?$/.test(value)) {
|
||||
throw new Error('Invalid numeric value "' + value + '"');
|
||||
}
|
||||
|
||||
// remove leading zeros like '003.2' which are not allowed by JavaScript
|
||||
return parseFloat(value.replace(/^(0*)[0-9]/, function (match, zeros) {
|
||||
return match.substring(zeros.length);
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
exports.factory = factory;
|
||||
@ -2,8 +2,6 @@
|
||||
|
||||
var number = require('./number');
|
||||
var string = require('./string');
|
||||
var object = require('./object');
|
||||
var types = require('./types');
|
||||
|
||||
var DimensionError = require('../error/DimensionError');
|
||||
var IndexError = require('../error/IndexError');
|
||||
|
||||
@ -6,5 +6,4 @@ exports['function'] = require('./function');
|
||||
exports.number = require('./number');
|
||||
exports.object = require('./object');
|
||||
exports.string = require('./string');
|
||||
exports.types = require('./types');
|
||||
exports.emitter = require('./emitter');
|
||||
|
||||
@ -1,44 +0,0 @@
|
||||
'use strict';
|
||||
|
||||
/**
|
||||
* Determine the type of a variable
|
||||
*
|
||||
* type(x)
|
||||
*
|
||||
* The following types are recognized:
|
||||
*
|
||||
* 'undefined'
|
||||
* 'null'
|
||||
* 'boolean'
|
||||
* 'number'
|
||||
* 'string'
|
||||
* 'Array'
|
||||
* 'Function'
|
||||
* 'Date'
|
||||
* 'RegExp'
|
||||
* 'Object'
|
||||
*
|
||||
* @param {*} x
|
||||
* @return {string} Returns the name of the type. Primitive types are lower case,
|
||||
* non-primitive types are upper-camel-case.
|
||||
* For example 'number', 'string', 'Array', 'Date'.
|
||||
*/
|
||||
exports.type = function(x) {
|
||||
var type = typeof x;
|
||||
|
||||
if (type === 'object') {
|
||||
if (x === null) return 'null';
|
||||
if (Array.isArray(x)) return 'Array';
|
||||
if (x instanceof Date) return 'Date';
|
||||
if (x instanceof RegExp) return 'RegExp';
|
||||
if (x instanceof Boolean) return 'boolean';
|
||||
if (x instanceof Number) return 'number';
|
||||
if (x instanceof String) return 'string';
|
||||
|
||||
return 'Object';
|
||||
}
|
||||
|
||||
if (type === 'function') return 'Function';
|
||||
|
||||
return type;
|
||||
};
|
||||
@ -411,7 +411,7 @@ describe('AccessorNode', function() {
|
||||
return string;
|
||||
}
|
||||
else if (node.type === 'ConstantNode') {
|
||||
return 'const(' + node.value + ', ' + node.valueType + ')'
|
||||
return 'const(' + node.value + ', ' + math.typeof(node.value) + ')'
|
||||
}
|
||||
};
|
||||
|
||||
@ -450,7 +450,7 @@ describe('AccessorNode', function() {
|
||||
return latex;
|
||||
}
|
||||
else if (node.type === 'ConstantNode') {
|
||||
return 'const\\left(' + node.value + ', ' + node.valueType + '\\right)'
|
||||
return 'const\\left(' + node.value + ', ' + math.typeof(node.value) + '\\right)'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -266,7 +266,7 @@ describe('ArrayNode', function() {
|
||||
return string;
|
||||
}
|
||||
else if (node.type === 'ConstantNode') {
|
||||
return 'const(' + node.value + ', ' + node.valueType + ')'
|
||||
return 'const(' + node.value + ', ' + math.typeof(node.value) + ')'
|
||||
}
|
||||
};
|
||||
|
||||
@ -303,7 +303,7 @@ describe('ArrayNode', function() {
|
||||
return latex;
|
||||
}
|
||||
else if (node.type === 'ConstantNode') {
|
||||
return 'const\\left(' + node.value + ', ' + node.valueType + '\\right)'
|
||||
return 'const\\left(' + node.value + ', ' + math.typeof(node.value) + '\\right)'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -153,7 +153,7 @@ describe('AssignmentNode', function() {
|
||||
new bigmath.expression.node.ConstantNode(2),
|
||||
new bigmath.expression.node.ConstantNode(1)
|
||||
]);
|
||||
var value = new bigmath.expression.node.ConstantNode(5);
|
||||
var value = new bigmath.expression.node.ConstantNode(bigmath.bignumber(5));
|
||||
var n = new bigmath.expression.node.AssignmentNode(object, index, value);
|
||||
var expr = n.compile();
|
||||
|
||||
@ -190,8 +190,8 @@ describe('AssignmentNode', function() {
|
||||
assert.deepEqual(n.filter(function (node) {return node.isAssignmentNode}), [n]);
|
||||
assert.deepEqual(n.filter(function (node) {return node.isSymbolNode}), [a]);
|
||||
assert.deepEqual(n.filter(function (node) {return node.isConstantNode}), [b, c, v]);
|
||||
assert.deepEqual(n.filter(function (node) {return node.value === '1'}), [c]);
|
||||
assert.deepEqual(n.filter(function (node) {return node.value === '2'}), [b, v]);
|
||||
assert.deepEqual(n.filter(function (node) {return node.value === 1}), [c]);
|
||||
assert.deepEqual(n.filter(function (node) {return node.value === 2}), [b, v]);
|
||||
assert.deepEqual(n.filter(function (node) {return node.name === 'q'}), []);
|
||||
});
|
||||
|
||||
@ -203,7 +203,7 @@ describe('AssignmentNode', function() {
|
||||
assert.deepEqual(n.filter(function (node) {return node.isAssignmentNode}), [n]);
|
||||
assert.deepEqual(n.filter(function (node) {return node.isSymbolNode}), [a]);
|
||||
assert.deepEqual(n.filter(function (node) {return node.isConstantNode}), [v]);
|
||||
assert.deepEqual(n.filter(function (node) {return node.value === '2'}), [v]);
|
||||
assert.deepEqual(n.filter(function (node) {return node.value === 2}), [v]);
|
||||
assert.deepEqual(n.filter(function (node) {return node.name === 'q'}), []);
|
||||
});
|
||||
|
||||
@ -498,7 +498,7 @@ describe('AssignmentNode', function() {
|
||||
' equals ' + node.value.toString(options);
|
||||
}
|
||||
else if (node.type === 'ConstantNode') {
|
||||
return 'const(' + node.value + ', ' + node.valueType + ')'
|
||||
return 'const(' + node.value + ', ' + math.typeof(node.value) + ')'
|
||||
}
|
||||
};
|
||||
|
||||
@ -533,7 +533,7 @@ describe('AssignmentNode', function() {
|
||||
'\\mbox{equals}' + node.value.toTex(options);
|
||||
}
|
||||
else if (node.type === 'ConstantNode') {
|
||||
return 'const\\left(' + node.value + ', ' + node.valueType + '\\right)'
|
||||
return 'const\\left(' + node.value + ', ' + math.typeof(node.value) + '\\right)'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -281,7 +281,7 @@ describe('BlockNode', function() {
|
||||
return string;
|
||||
}
|
||||
else if (node.type === 'ConstantNode') {
|
||||
return 'const(' + node.value + ', ' + node.valueType + ')'
|
||||
return 'const(' + node.value + ', ' + math.typeof(node.value) + ')'
|
||||
}
|
||||
};
|
||||
|
||||
@ -315,7 +315,7 @@ describe('BlockNode', function() {
|
||||
return latex;
|
||||
}
|
||||
else if (node.type === 'ConstantNode') {
|
||||
return 'const\\left(' + node.value + ', ' + node.valueType + '\\right)'
|
||||
return 'const\\left(' + node.value + ', ' + math.typeof(node.value) + '\\right)'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -288,7 +288,7 @@ describe('ConditionalNode', function() {
|
||||
+ ' else ' + node.falseExpr.toString(options);
|
||||
}
|
||||
else if (node.type === 'ConstantNode') {
|
||||
return 'const(' + node.value + ', ' + node.valueType + ')'
|
||||
return 'const(' + node.value + ', ' + math.typeof(node.value) + ')'
|
||||
}
|
||||
};
|
||||
|
||||
@ -317,7 +317,7 @@ describe('ConditionalNode', function() {
|
||||
+ ' else ' + node.falseExpr.toTex(options);
|
||||
}
|
||||
else if (node.type === 'ConstantNode') {
|
||||
return 'const\\left(' + node.value + ', ' + node.valueType + '\\right)'
|
||||
return 'const\\left(' + node.value + ', ' + math.typeof(node.value) + '\\right)'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -6,27 +6,22 @@ var bigmath = require('../../../index').create({number: 'BigNumber'});
|
||||
var Node = math.expression.node.Node;
|
||||
var ConstantNode = math.expression.node.ConstantNode;
|
||||
var SymbolNode = math.expression.node.SymbolNode;
|
||||
var Fraction = require('../../../lib/type/fraction/Fraction');
|
||||
|
||||
describe('ConstantNode', function() {
|
||||
|
||||
it ('should create a ConstantNode with value type', function () {
|
||||
var a = new ConstantNode('3', 'number');
|
||||
assert(a instanceof Node);
|
||||
assert.equal(a.type, 'ConstantNode');
|
||||
});
|
||||
|
||||
it ('should create a ConstantNode without value type', function () {
|
||||
it ('should create a ConstantNode', function () {
|
||||
var a = new ConstantNode(3);
|
||||
assert(a instanceof Node);
|
||||
assert.equal(a.type, 'ConstantNode');
|
||||
// TODO: extensively test each of the supported types
|
||||
|
||||
assert.deepEqual(new ConstantNode(3), new ConstantNode('3', 'number'));
|
||||
assert.deepEqual(new ConstantNode('hello'), new ConstantNode('hello', 'string'));
|
||||
assert.deepEqual(new ConstantNode(true), new ConstantNode('true', 'boolean'));
|
||||
assert.deepEqual(new ConstantNode(false), new ConstantNode('false', 'boolean'));
|
||||
assert.deepEqual(new ConstantNode(null), new ConstantNode('null', 'null'));
|
||||
assert.deepEqual(new ConstantNode(undefined), new ConstantNode('undefined', 'undefined'));
|
||||
assert.strictEqual(new ConstantNode(3).value, 3);
|
||||
assert.strictEqual(new ConstantNode('hello').value, 'hello');
|
||||
assert.strictEqual(new ConstantNode(true).value, true);
|
||||
assert.strictEqual(new ConstantNode(false).value, false);
|
||||
assert.strictEqual(new ConstantNode(null).value, null);
|
||||
assert.strictEqual(new ConstantNode(undefined).value, undefined);
|
||||
});
|
||||
|
||||
it ('should have isConstantNode', function () {
|
||||
@ -35,68 +30,50 @@ describe('ConstantNode', function() {
|
||||
});
|
||||
|
||||
it ('should throw an error when calling without new operator', function () {
|
||||
assert.throws(function () {ConstantNode('3', 'number')}, SyntaxError);
|
||||
});
|
||||
|
||||
it ('should throw an error in case of wrong construction arguments', function () {
|
||||
assert.throws(function () {new ConstantNode(3, 'number');}, TypeError);
|
||||
assert.throws(function () {new ConstantNode(new Date());}, TypeError);
|
||||
assert.throws(function () {new ConstantNode('3', Number);}, TypeError);
|
||||
});
|
||||
|
||||
it ('should throw an error in case of unknown type of constant', function () {
|
||||
assert.throws(function () {new ConstantNode('3', 'bla').compile();}, TypeError);
|
||||
assert.throws(function () {ConstantNode(3)}, SyntaxError);
|
||||
});
|
||||
|
||||
it ('should compile a ConstantNode', function () {
|
||||
var expr = new ConstantNode('2.3', 'number').compile();
|
||||
var expr = new ConstantNode(2.3).compile();
|
||||
assert.strictEqual(expr.eval(), 2.3);
|
||||
|
||||
expr = new ConstantNode('002.3', 'number').compile();
|
||||
expr = new ConstantNode(2.3).compile();
|
||||
assert.strictEqual(expr.eval(), 2.3);
|
||||
|
||||
expr = new ConstantNode('hello', 'string').compile();
|
||||
expr = new ConstantNode('hello').compile();
|
||||
assert.strictEqual(expr.eval(), 'hello');
|
||||
|
||||
expr = new ConstantNode('true', 'boolean').compile();
|
||||
expr = new ConstantNode(true).compile();
|
||||
assert.strictEqual(expr.eval(), true);
|
||||
|
||||
expr = new ConstantNode('undefined', 'undefined').compile();
|
||||
expr = new ConstantNode(undefined).compile();
|
||||
assert.strictEqual(expr.eval(), undefined);
|
||||
|
||||
expr = new ConstantNode('null', 'null').compile();
|
||||
expr = new ConstantNode(null).compile();
|
||||
assert.strictEqual(expr.eval(), null);
|
||||
|
||||
});
|
||||
|
||||
it ('should compile a ConstantNode with bigmath', function () {
|
||||
var expr = new bigmath.expression.node.ConstantNode('2.3', 'number').compile();
|
||||
var constantNode = bigmath.parse('2.3');
|
||||
assert.ok(constantNode.isConstantNode);
|
||||
var expr = constantNode.compile();
|
||||
assert.deepEqual(expr.eval(), new bigmath.type.BigNumber(2.3));
|
||||
});
|
||||
|
||||
it ('should find a ConstantNode', function () {
|
||||
var a = new ConstantNode('2', 'number');
|
||||
var a = new ConstantNode(2);
|
||||
assert.deepEqual(a.filter(function (node) {return node instanceof ConstantNode}), [a]);
|
||||
assert.deepEqual(a.filter(function (node) {return node instanceof SymbolNode}), []);
|
||||
});
|
||||
|
||||
it ('should throw an error when compiling an invalid value', function () {
|
||||
var clone = math.create();
|
||||
clone.config({number: 'number'});
|
||||
assert.throws(function () { new ConstantNode('console.log("foo")', 'number').compile() }, /Invalid numeric value/)
|
||||
clone.config({number: 'BigNumber'});
|
||||
assert.throws(function () { new ConstantNode('console.log("foo")', 'number').compile() }, /Invalid numeric value/)
|
||||
clone.config({number: 'Fraction'});
|
||||
assert.throws(function () { new ConstantNode('console.log("foo")', 'number').compile() }, /Invalid numeric value/)
|
||||
});
|
||||
|
||||
it ('should leave quotes in strings as is (no escaping)', function () {
|
||||
assert.strictEqual( new ConstantNode('"+foo+"', 'string').compile().eval(), '"+foo+"')
|
||||
assert.strictEqual( new ConstantNode('\\"escaped\\"', 'string').compile().eval(), '\\"escaped\\"')
|
||||
assert.strictEqual( new ConstantNode('"+foo+"').compile().eval(), '"+foo+"')
|
||||
assert.strictEqual( new ConstantNode('\\"escaped\\"').compile().eval(), '\\"escaped\\"')
|
||||
});
|
||||
|
||||
it ('should find a ConstantNode', function () {
|
||||
var a = new ConstantNode('2', 'number');
|
||||
var a = new ConstantNode(2);
|
||||
assert.deepEqual(a.filter(function (node) {return node instanceof ConstantNode}), [a]);
|
||||
assert.deepEqual(a.filter(function (node) {return node instanceof SymbolNode}), []);
|
||||
});
|
||||
@ -152,61 +129,71 @@ describe('ConstantNode', function() {
|
||||
assert.strictEqual(a.equals(undefined), false);
|
||||
assert.strictEqual(a.equals(new ConstantNode(2)), true);
|
||||
assert.strictEqual(a.equals(new ConstantNode(3)), false);
|
||||
assert.strictEqual(a.equals(new ConstantNode('2', 'number')), true);
|
||||
assert.strictEqual(a.equals(new ConstantNode('2', 'string')), false);
|
||||
assert.strictEqual(a.equals(new ConstantNode('2')), false);
|
||||
assert.strictEqual(a.equals(new SymbolNode('2')), false);
|
||||
assert.strictEqual(a.equals({value:2, valueType: 'number'}), false);
|
||||
assert.strictEqual(a.equals({value:2}), false);
|
||||
});
|
||||
|
||||
it ('should stringify a ConstantNode', function () {
|
||||
assert.equal(new ConstantNode('3', 'number').toString(), '3');
|
||||
assert.deepEqual(new ConstantNode('3', 'number').toString(), '3');
|
||||
assert.equal(new ConstantNode('hi', 'string').toString(), '"hi"');
|
||||
assert.equal(new ConstantNode('true', 'boolean').toString(), 'true');
|
||||
assert.equal(new ConstantNode('false', 'boolean').toString(), 'false');
|
||||
assert.equal(new ConstantNode('undefined', 'undefined').toString(), 'undefined');
|
||||
assert.equal(new ConstantNode('null', 'null').toString(), 'null');
|
||||
assert.equal(new ConstantNode(3).toString(), '3');
|
||||
assert.deepEqual(new ConstantNode(3).toString(), '3');
|
||||
assert.deepEqual(new ConstantNode(math.bignumber('1e500')).toString(), '1e+500');
|
||||
assert.deepEqual(new ConstantNode(math.fraction(2,3)).toString(), '2/3');
|
||||
assert.equal(new ConstantNode('hi').toString(), '"hi"');
|
||||
assert.equal(new ConstantNode(true).toString(), 'true');
|
||||
assert.equal(new ConstantNode(false).toString(), 'false');
|
||||
assert.equal(new ConstantNode(undefined).toString(), 'undefined');
|
||||
assert.equal(new ConstantNode(null).toString(), 'null');
|
||||
});
|
||||
|
||||
it ('should stringify a ConstantNode with custom toString', function () {
|
||||
//Also checks if the custom functions get passed on to the children
|
||||
var customFunction = function (node, options) {
|
||||
if (node.type === 'ConstantNode') {
|
||||
return 'const(' + node.value + ', ' + node.valueType + ')'
|
||||
return 'const(' + node.value + ')'
|
||||
}
|
||||
};
|
||||
|
||||
var n = new ConstantNode(1);
|
||||
|
||||
assert.equal(n.toString({handler: customFunction}), 'const(1, number)');
|
||||
assert.equal(n.toString({handler: customFunction}), 'const(1)');
|
||||
});
|
||||
|
||||
it ('should LaTeX a ConstantNode', function () {
|
||||
assert.equal(new ConstantNode('3', 'number').toTex(), '3');
|
||||
assert.deepEqual(new ConstantNode('3', 'number').toTex(), '3');
|
||||
assert.equal(new ConstantNode('hi', 'string').toTex(), '\\mathtt{"hi"}');
|
||||
assert.equal(new ConstantNode('true', 'boolean').toTex(), 'true');
|
||||
assert.equal(new ConstantNode('false', 'boolean').toTex(), 'false');
|
||||
assert.equal(new ConstantNode('undefined', 'undefined').toTex(), 'undefined');
|
||||
assert.equal(new ConstantNode('null', 'null').toTex(), 'null');
|
||||
assert.equal(new ConstantNode(3).toTex(), '3');
|
||||
assert.deepEqual(new ConstantNode(3).toTex(), '3');
|
||||
assert.deepEqual(new ConstantNode(math.bignumber('3')).toTex(), '3');
|
||||
assert.equal(new ConstantNode('hi').toTex(), '\\mathtt{"hi"}');
|
||||
assert.equal(new ConstantNode(true).toTex(), 'true');
|
||||
assert.equal(new ConstantNode(false).toTex(), 'false');
|
||||
assert.equal(new ConstantNode(undefined).toTex(), 'undefined');
|
||||
assert.equal(new ConstantNode(null).toTex(), 'null');
|
||||
});
|
||||
|
||||
it ('should LaTeX a ConstantNode in exponential notation', function () {
|
||||
var n = new ConstantNode('1e10', 'number');
|
||||
assert.equal(n.toTex(), '1\\cdot10^{10}');
|
||||
var n = new ConstantNode(1e10);
|
||||
assert.equal(n.toTex(), '1\\cdot10^{+10}');
|
||||
});
|
||||
|
||||
it ('should LaTeX a ConstantNode with custom toTex', function () {
|
||||
//Also checks if the custom functions get passed on to the children
|
||||
var customFunction = function (node, options) {
|
||||
if (node.type === 'ConstantNode') {
|
||||
return 'const\\left(' + node.value + ', ' + node.valueType + '\\right)'
|
||||
return 'const\\left(' + node.value + '\\right)'
|
||||
}
|
||||
};
|
||||
|
||||
var n = new ConstantNode(1);
|
||||
|
||||
assert.equal(n.toTex({handler: customFunction}), 'const\\left(1, number\\right)');
|
||||
assert.equal(n.toTex({handler: customFunction}), 'const\\left(1\\right)');
|
||||
});
|
||||
|
||||
it ('should LaTeX a ConstantNode with a fraction', function () {
|
||||
var positive = new ConstantNode(new math.type.Fraction(1.5));
|
||||
var negative = new ConstantNode(new math.type.Fraction(-1.5));
|
||||
|
||||
assert.equal(positive.toTex(), '\\frac{3}{2}');
|
||||
assert.equal(negative.toTex(), '-\\frac{3}{2}');
|
||||
});
|
||||
|
||||
});
|
||||
|
||||
@ -381,7 +381,7 @@ describe('FunctionAssignmentNode', function() {
|
||||
return string;
|
||||
}
|
||||
else if (node.type === 'ConstantNode') {
|
||||
return 'const(' + node.value + ', ' + node.valueType + ')'
|
||||
return 'const(' + node.value + ', ' + math.typeof(node.value) + ')'
|
||||
}
|
||||
};
|
||||
|
||||
@ -424,7 +424,7 @@ describe('FunctionAssignmentNode', function() {
|
||||
return latex;
|
||||
}
|
||||
else if (node.type === 'ConstantNode') {
|
||||
return 'const\\left(' + node.value + ', ' + node.valueType + '\\right)'
|
||||
return 'const\\left(' + node.value + ', ' + math.typeof(node.value) + '\\right)'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -410,7 +410,7 @@ describe('FunctionNode', function() {
|
||||
return string;
|
||||
}
|
||||
else if (node.type === 'ConstantNode') {
|
||||
return 'const(' + node.value + ', ' + node.valueType + ')'
|
||||
return 'const(' + node.value + ', ' + math.typeof(node.value) + ')'
|
||||
}
|
||||
};
|
||||
|
||||
@ -478,7 +478,7 @@ describe('FunctionNode', function() {
|
||||
return latex;
|
||||
}
|
||||
else if (node.type === 'ConstantNode') {
|
||||
return 'const\\left(' + node.value + ', ' + node.valueType + '\\right)'
|
||||
return 'const\\left(' + node.value + ', ' + math.typeof(node.value) + '\\right)'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -85,7 +85,7 @@ describe('IndexNode', function() {
|
||||
paths.push(path);
|
||||
assert.strictEqual(parent, n);
|
||||
|
||||
return node.isConstantNode && node.value === '1' ? e : node;
|
||||
return node.isConstantNode && node.value === 1 ? e : node;
|
||||
});
|
||||
|
||||
assert.equal(nodes.length, 2);
|
||||
@ -115,7 +115,7 @@ describe('IndexNode', function() {
|
||||
|
||||
var e = new SymbolNode('c');
|
||||
var f = n.transform(function (node) {
|
||||
return node.isConstantNode && node.value === '1' ? e : node;
|
||||
return node.isConstantNode && node.value === 1 ? e : node;
|
||||
});
|
||||
|
||||
assert.notStrictEqual(f, n);
|
||||
@ -197,7 +197,7 @@ describe('IndexNode', function() {
|
||||
}).join(', ');
|
||||
}
|
||||
else if (node.type === 'ConstantNode') {
|
||||
return 'const(' + node.value + ', ' + node.valueType + ')'
|
||||
return 'const(' + node.value + ', ' + math.typeof(node.value) + ')'
|
||||
}
|
||||
};
|
||||
|
||||
@ -240,7 +240,7 @@ describe('IndexNode', function() {
|
||||
return latex;
|
||||
}
|
||||
else if (node.type === 'ConstantNode') {
|
||||
return 'const\\left(' + node.value + ', ' + node.valueType + '\\right)'
|
||||
return 'const\\left(' + node.value + ', ' + math.typeof(node.value) + '\\right)'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -247,7 +247,7 @@ describe('ObjectNode', function() {
|
||||
it ('should stringify an ObjectNode with custom toString', function () {
|
||||
var customFunction = function (node, options) {
|
||||
if (node.type === 'ConstantNode') {
|
||||
return 'const(' + node.value + ', ' + node.valueType + ')'
|
||||
return 'const(' + node.value + ', ' + math.typeof(node.value) + ')'
|
||||
}
|
||||
};
|
||||
|
||||
@ -271,7 +271,7 @@ describe('ObjectNode', function() {
|
||||
it ('should LaTeX an ObjectNode with custom toTex', function () {
|
||||
var customFunction = function (node, options) {
|
||||
if (node.type === 'ConstantNode') {
|
||||
return 'const\\left(' + node.value + ', ' + node.valueType + '\\right)'
|
||||
return 'const\\left(' + node.value + ', ' + math.typeof(node.value) + '\\right)'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -367,7 +367,7 @@ describe('OperatorNode', function() {
|
||||
+ ', ' + node.args[1].toString(options) + ')';
|
||||
}
|
||||
else if (node.type === 'ConstantNode') {
|
||||
return 'const(' + node.value + ', ' + node.valueType + ')'
|
||||
return 'const(' + node.value + ', ' + math.typeof(node.value) + ')'
|
||||
}
|
||||
};
|
||||
|
||||
@ -390,7 +390,7 @@ describe('OperatorNode', function() {
|
||||
node.args[1].toString(options);
|
||||
}
|
||||
else if (node.type === 'ConstantNode') {
|
||||
return 'const(' + node.value + ', ' + node.valueType + ')'
|
||||
return 'const(' + node.value + ', ' + math.typeof(node.value) + ')'
|
||||
}
|
||||
};
|
||||
|
||||
@ -591,7 +591,7 @@ describe('OperatorNode', function() {
|
||||
+ ', ' + node.args[1].toTex(options) + ')';
|
||||
}
|
||||
else if (node.type === 'ConstantNode') {
|
||||
return 'const\\left(' + node.value + ', ' + node.valueType + '\\right)'
|
||||
return 'const\\left(' + node.value + ', ' + math.typeof(node.value) + '\\right)'
|
||||
}
|
||||
};
|
||||
|
||||
@ -614,7 +614,7 @@ describe('OperatorNode', function() {
|
||||
node.args[1].toTex(options);
|
||||
}
|
||||
else if (node.type === 'ConstantNode') {
|
||||
return 'const\\left(' + node.value + ', ' + node.valueType + '\\right)'
|
||||
return 'const\\left(' + node.value + ', ' + math.typeof(node.value) + '\\right)'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -301,7 +301,7 @@ describe('RangeNode', function() {
|
||||
+ ' with steps of ' + node.step.toString(options);
|
||||
}
|
||||
else if (node.type === 'ConstantNode') {
|
||||
return 'const(' + node.value + ', ' + node.valueType + ')'
|
||||
return 'const(' + node.value + ', ' + math.typeof(node.value) + ')'
|
||||
}
|
||||
};
|
||||
|
||||
@ -345,7 +345,7 @@ describe('RangeNode', function() {
|
||||
+ ' with steps of ' + node.step.toTex(options);
|
||||
}
|
||||
else if (node.type === 'ConstantNode') {
|
||||
return 'const\\left(' + node.value + ', ' + node.valueType + '\\right)'
|
||||
return 'const\\left(' + node.value + ', ' + math.typeof(node.value) + '\\right)'
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -5,6 +5,7 @@ var math = require('../../index');
|
||||
var ArgumentsError = require('../../lib/error/ArgumentsError');
|
||||
var parse = math.expression.parse;
|
||||
var ConditionalNode = math.expression.node.ConditionalNode;
|
||||
var ConstantNode = math.expression.node.ConstantNode;
|
||||
var OperatorNode = math.expression.node.OperatorNode;
|
||||
var RangeNode = math.expression.node.RangeNode;
|
||||
var Complex = math.type.Complex;
|
||||
@ -368,10 +369,6 @@ describe('parse', function() {
|
||||
assert.ok(parseAndEval('5cm') instanceof Unit);
|
||||
});
|
||||
|
||||
it('should parse constants', function() {
|
||||
assert.equal(parseAndEval('pi'), Math.PI);
|
||||
});
|
||||
|
||||
it('should parse physical constants', function() {
|
||||
var expected = new Unit(299792458, 'm/s');
|
||||
expected.fixPrefix = true;
|
||||
@ -844,12 +841,35 @@ describe('parse', function() {
|
||||
|
||||
describe('constants', function () {
|
||||
|
||||
it('should parse constants', function() {
|
||||
it ('should parse symbolic constants', function () {
|
||||
assert.strictEqual(parse('i').type, 'SymbolNode');
|
||||
assert.deepEqual(parseAndEval('i'), new Complex(0, 1));
|
||||
approx.equal(parseAndEval('pi'), Math.PI);
|
||||
approx.equal(parseAndEval('e'), Math.E);
|
||||
})
|
||||
|
||||
it('should parse constants', function() {
|
||||
assert.strictEqual(parse('true').type, 'ConstantNode');
|
||||
assert.deepStrictEqual(parse('true'), createConstantNode(true));
|
||||
assert.deepStrictEqual(parse('false'), createConstantNode(false));
|
||||
assert.deepStrictEqual(parse('null'), createConstantNode(null));
|
||||
assert.deepStrictEqual(parse('undefined'), createConstantNode(undefined));
|
||||
assert.deepStrictEqual(parse('uninitialized'), createConstantNode(math.uninitialized));
|
||||
});
|
||||
|
||||
it('should parse numeric constants', function() {
|
||||
var nanConstantNode = parse('NaN');
|
||||
assert.deepStrictEqual(nanConstantNode.type, 'ConstantNode');
|
||||
assert.ok(isNaN(nanConstantNode.value));
|
||||
assert.deepStrictEqual(parse('Infinity'), createConstantNode(Infinity));
|
||||
});
|
||||
|
||||
// helper function to create a ConstantNode with empty comment
|
||||
function createConstantNode (value) {
|
||||
var c = new ConstantNode(value);
|
||||
c.comment = ''
|
||||
return c;
|
||||
}
|
||||
});
|
||||
|
||||
describe('variables', function () {
|
||||
|
||||
@ -192,7 +192,7 @@ describe('security', function () {
|
||||
|
||||
it ('should not allow calling eval via clone', function () {
|
||||
assert.throws(function () {
|
||||
math.eval('expression.node.ConstantNode.prototype.clone.call({"value":"eval", "valueType":"null"}).eval()("console.log(\'hacked...\')")')
|
||||
math.eval('expression.node.ConstantNode.prototype.clone.call({"value":"eval"}).eval()("console.log(\'hacked...\')")')
|
||||
}, /Error: Undefined symbol expression/);
|
||||
})
|
||||
|
||||
|
||||
@ -260,15 +260,16 @@ describe('simplify', function() {
|
||||
assert.equal(math.simplify('LN10', ['LN10 -> 1']).toString(), '1');
|
||||
assert.equal(math.simplify('LOG2E', ['LOG2E -> 1']).toString(), '1');
|
||||
assert.equal(math.simplify('LOG10E', ['LOG10E -> 1']).toString(), '1');
|
||||
assert.equal(math.simplify('NaN', ['NaN -> 1']).toString(), '1');
|
||||
assert.equal(math.simplify('null', ['null -> 1']).toString(), '1');
|
||||
assert.equal(math.simplify('phi', ['phi -> 1']).toString(), '1');
|
||||
assert.equal(math.simplify('SQRT1_2', ['SQRT1_2 -> 1']).toString(), '1');
|
||||
assert.equal(math.simplify('SQRT2', ['SQRT2 -> 1']).toString(), '1');
|
||||
assert.equal(math.simplify('tau', ['tau -> 1']).toString(), '1');
|
||||
|
||||
// note that NaN is a special case, we can't compare two values both NaN.
|
||||
});
|
||||
|
||||
it('should throw an error for invalid built-in constant symbols in rules', function() {
|
||||
assert.throws(function(){ math.simplify('null', ['null -> 1']).toString(); });
|
||||
assert.throws(function(){ math.simplify('uninitialized', ['uninitialized -> 1']).toString(); });
|
||||
assert.throws(function(){ math.simplify('version', ['version -> 1']).toString(); });
|
||||
});
|
||||
|
||||
@ -14,6 +14,8 @@ describe('typeof', function() {
|
||||
it('should return number type for a number', function() {
|
||||
assert.equal(math.typeof(2), 'number');
|
||||
assert.equal(math.typeof(new Number(2)), 'number');
|
||||
assert.equal(math.typeof(new Number(2.3)), 'number');
|
||||
assert.equal(math.typeof(NaN), 'number');
|
||||
});
|
||||
|
||||
it('should return bignumber type for a bignumber', function() {
|
||||
@ -66,7 +68,7 @@ describe('typeof', function() {
|
||||
assert.equal(math.typeof(null), 'null');
|
||||
});
|
||||
|
||||
it('should return undefined type for undefined', function() {
|
||||
it('should return undefined type for undefined', function() {
|
||||
assert.equal(math.typeof(undefined), 'undefined');
|
||||
});
|
||||
|
||||
@ -74,6 +76,10 @@ describe('typeof', function() {
|
||||
assert.equal(math.typeof(new Date()), 'Date');
|
||||
});
|
||||
|
||||
it('should return the type of a regexp', function () {
|
||||
assert.equal(math.typeof(/regexp/), 'RegExp');
|
||||
});
|
||||
|
||||
it('should return function type for a function', function() {
|
||||
assert.equal(math.typeof(function () {}), 'Function');
|
||||
assert.equal(math.typeof(new Function ()), 'Function');
|
||||
@ -110,4 +116,9 @@ describe('typeof', function() {
|
||||
assert.equal(expression.toTex(), '\\mathrm{typeof}\\left(1\\right)');
|
||||
});
|
||||
|
||||
it('should throw an error in case of wrong number of arguments', function () {
|
||||
assert.throws(function () {math.typeof()}, /Too few arguments in function _typeof/);
|
||||
assert.throws(function () {math.typeof(1,2,3)}, /Too many arguments in function _typeof/);
|
||||
})
|
||||
|
||||
});
|
||||
|
||||
@ -1,53 +0,0 @@
|
||||
// test types utils
|
||||
var assert = require('assert'),
|
||||
approx = require('../../tools/approx'),
|
||||
types = require('../../lib/utils/types');
|
||||
|
||||
describe ('types', function () {
|
||||
|
||||
it('should return the type of undefined', function () {
|
||||
assert.equal(types.type(undefined), 'undefined');
|
||||
assert.equal(types.type(), 'undefined');
|
||||
});
|
||||
|
||||
it('should return the type of a boolean', function () {
|
||||
|
||||
assert.equal(types.type(false), 'boolean');
|
||||
assert.equal(types.type(true), 'boolean');
|
||||
});
|
||||
|
||||
it('should return the type of a number', function () {
|
||||
assert.equal(types.type(2.3), 'number');
|
||||
assert.equal(types.type(Number(2.3)), 'number');
|
||||
assert.equal(types.type(new Number(2.3)), 'number');
|
||||
assert.equal(types.type(NaN), 'number');
|
||||
});
|
||||
|
||||
it('should return the type of a string', function () {
|
||||
assert.equal(types.type('bla'), 'string');
|
||||
assert.equal(types.type(new String('bla')), 'string');
|
||||
});
|
||||
|
||||
it('should return the type of an object', function () {
|
||||
assert.equal(types.type({}), 'Object');
|
||||
assert.equal(types.type(new Object()), 'Object');
|
||||
});
|
||||
|
||||
it('should return the type of an array', function () {
|
||||
assert.equal(types.type([]), 'Array');
|
||||
assert.equal(types.type(new Array()), 'Array');
|
||||
});
|
||||
|
||||
it('should return the type of a function', function () {
|
||||
assert.equal(types.type(function () {}), 'Function');
|
||||
});
|
||||
|
||||
it('should return the type of a date', function () {
|
||||
assert.equal(types.type(new Date()), 'Date');
|
||||
});
|
||||
|
||||
it('should return the type of a regexp', function () {
|
||||
assert.equal(types.type(/regexp/), 'RegExp');
|
||||
});
|
||||
|
||||
});
|
||||
Loading…
x
Reference in New Issue
Block a user