UNPKG

11.3 kBJavaScriptView Raw
1'use strict';
2
3function _typeof(obj) { if (typeof Symbol === "function" && typeof Symbol.iterator === "symbol") { _typeof = function _typeof(obj) { return typeof obj; }; } else { _typeof = function _typeof(obj) { return obj && typeof Symbol === "function" && obj.constructor === Symbol && obj !== Symbol.prototype ? "symbol" : typeof obj; }; } return _typeof(obj); }
4
5var typedFunction = require('typed-function');
6
7var digits = require('./../utils/number').digits;
8
9var isBigNumber = require('./../utils/bignumber/isBigNumber');
10
11var isMatrix = require('./../utils/collection/isMatrix'); // returns a new instance of typed-function
12
13
14var _createTyped = function createTyped() {
15 // initially, return the original instance of typed-function
16 // consecutively, return a new instance from typed.create.
17 _createTyped = typedFunction.create;
18 return typedFunction;
19};
20/**
21 * Factory function for creating a new typed instance
22 * @param {Object} type Object with data types like Complex and BigNumber
23 * @returns {Function}
24 */
25
26
27exports.create = function create(type) {
28 // TODO: typed-function must be able to silently ignore signatures with unknown data types
29 // type checks for all known types
30 //
31 // note that:
32 //
33 // - check by duck-typing on a property like `isUnit`, instead of checking instanceof.
34 // instanceof cannot be used because that would not allow to pass data from
35 // one instance of math.js to another since each has it's own instance of Unit.
36 // - check the `isUnit` property via the constructor, so there will be no
37 // matches for "fake" instances like plain objects with a property `isUnit`.
38 // That is important for security reasons.
39 // - It must not be possible to override the type checks used internally,
40 // for security reasons, so these functions are not exposed in the expression
41 // parser.
42 type.isNumber = function (x) {
43 return typeof x === 'number';
44 };
45
46 type.isComplex = function (x) {
47 return type.Complex && x instanceof type.Complex || false;
48 };
49
50 type.isBigNumber = isBigNumber;
51
52 type.isFraction = function (x) {
53 return type.Fraction && x instanceof type.Fraction || false;
54 };
55
56 type.isUnit = function (x) {
57 return x && x.constructor.prototype.isUnit || false;
58 };
59
60 type.isString = function (x) {
61 return typeof x === 'string';
62 };
63
64 type.isArray = Array.isArray;
65 type.isMatrix = isMatrix;
66
67 type.isDenseMatrix = function (x) {
68 return x && x.isDenseMatrix && x.constructor.prototype.isMatrix || false;
69 };
70
71 type.isSparseMatrix = function (x) {
72 return x && x.isSparseMatrix && x.constructor.prototype.isMatrix || false;
73 };
74
75 type.isRange = function (x) {
76 return x && x.constructor.prototype.isRange || false;
77 };
78
79 type.isIndex = function (x) {
80 return x && x.constructor.prototype.isIndex || false;
81 };
82
83 type.isBoolean = function (x) {
84 return typeof x === 'boolean';
85 };
86
87 type.isResultSet = function (x) {
88 return x && x.constructor.prototype.isResultSet || false;
89 };
90
91 type.isHelp = function (x) {
92 return x && x.constructor.prototype.isHelp || false;
93 };
94
95 type.isFunction = function (x) {
96 return typeof x === 'function';
97 };
98
99 type.isDate = function (x) {
100 return x instanceof Date;
101 };
102
103 type.isRegExp = function (x) {
104 return x instanceof RegExp;
105 };
106
107 type.isObject = function (x) {
108 return _typeof(x) === 'object' && x.constructor === Object && !type.isComplex(x) && !type.isFraction(x);
109 };
110
111 type.isNull = function (x) {
112 return x === null;
113 };
114
115 type.isUndefined = function (x) {
116 return x === undefined;
117 };
118
119 type.isAccessorNode = function (x) {
120 return x && x.isAccessorNode && x.constructor.prototype.isNode || false;
121 };
122
123 type.isArrayNode = function (x) {
124 return x && x.isArrayNode && x.constructor.prototype.isNode || false;
125 };
126
127 type.isAssignmentNode = function (x) {
128 return x && x.isAssignmentNode && x.constructor.prototype.isNode || false;
129 };
130
131 type.isBlockNode = function (x) {
132 return x && x.isBlockNode && x.constructor.prototype.isNode || false;
133 };
134
135 type.isConditionalNode = function (x) {
136 return x && x.isConditionalNode && x.constructor.prototype.isNode || false;
137 };
138
139 type.isConstantNode = function (x) {
140 return x && x.isConstantNode && x.constructor.prototype.isNode || false;
141 };
142
143 type.isFunctionAssignmentNode = function (x) {
144 return x && x.isFunctionAssignmentNode && x.constructor.prototype.isNode || false;
145 };
146
147 type.isFunctionNode = function (x) {
148 return x && x.isFunctionNode && x.constructor.prototype.isNode || false;
149 };
150
151 type.isIndexNode = function (x) {
152 return x && x.isIndexNode && x.constructor.prototype.isNode || false;
153 };
154
155 type.isNode = function (x) {
156 return x && x.isNode && x.constructor.prototype.isNode || false;
157 };
158
159 type.isObjectNode = function (x) {
160 return x && x.isObjectNode && x.constructor.prototype.isNode || false;
161 };
162
163 type.isOperatorNode = function (x) {
164 return x && x.isOperatorNode && x.constructor.prototype.isNode || false;
165 };
166
167 type.isParenthesisNode = function (x) {
168 return x && x.isParenthesisNode && x.constructor.prototype.isNode || false;
169 };
170
171 type.isRangeNode = function (x) {
172 return x && x.isRangeNode && x.constructor.prototype.isNode || false;
173 };
174
175 type.isSymbolNode = function (x) {
176 return x && x.isSymbolNode && x.constructor.prototype.isNode || false;
177 };
178
179 type.isChain = function (x) {
180 return x && x.constructor.prototype.isChain || false;
181 }; // get a new instance of typed-function
182
183
184 var typed = _createTyped(); // define all types. The order of the types determines in which order function
185 // arguments are type-checked (so for performance it's important to put the
186 // most used types first).
187
188
189 typed.types = [{
190 name: 'number',
191 test: type.isNumber
192 }, {
193 name: 'Complex',
194 test: type.isComplex
195 }, {
196 name: 'BigNumber',
197 test: type.isBigNumber
198 }, {
199 name: 'Fraction',
200 test: type.isFraction
201 }, {
202 name: 'Unit',
203 test: type.isUnit
204 }, {
205 name: 'string',
206 test: type.isString
207 }, {
208 name: 'Array',
209 test: type.isArray
210 }, {
211 name: 'Matrix',
212 test: type.isMatrix
213 }, {
214 name: 'DenseMatrix',
215 test: type.isDenseMatrix
216 }, {
217 name: 'SparseMatrix',
218 test: type.isSparseMatrix
219 }, {
220 name: 'Range',
221 test: type.isRange
222 }, {
223 name: 'Index',
224 test: type.isIndex
225 }, {
226 name: 'boolean',
227 test: type.isBoolean
228 }, {
229 name: 'ResultSet',
230 test: type.isResultSet
231 }, {
232 name: 'Help',
233 test: type.isHelp
234 }, {
235 name: 'function',
236 test: type.isFunction
237 }, {
238 name: 'Date',
239 test: type.isDate
240 }, {
241 name: 'RegExp',
242 test: type.isRegExp
243 }, {
244 name: 'null',
245 test: type.isNull
246 }, {
247 name: 'undefined',
248 test: type.isUndefined
249 }, {
250 name: 'OperatorNode',
251 test: type.isOperatorNode
252 }, {
253 name: 'ConstantNode',
254 test: type.isConstantNode
255 }, {
256 name: 'SymbolNode',
257 test: type.isSymbolNode
258 }, {
259 name: 'ParenthesisNode',
260 test: type.isParenthesisNode
261 }, {
262 name: 'FunctionNode',
263 test: type.isFunctionNode
264 }, {
265 name: 'FunctionAssignmentNode',
266 test: type.isFunctionAssignmentNode
267 }, {
268 name: 'ArrayNode',
269 test: type.isArrayNode
270 }, {
271 name: 'AssignmentNode',
272 test: type.isAssignmentNode
273 }, {
274 name: 'BlockNode',
275 test: type.isBlockNode
276 }, {
277 name: 'ConditionalNode',
278 test: type.isConditionalNode
279 }, {
280 name: 'IndexNode',
281 test: type.isIndexNode
282 }, {
283 name: 'RangeNode',
284 test: type.isRangeNode
285 }, {
286 name: 'Node',
287 test: type.isNode
288 }, {
289 name: 'Object',
290 test: type.isObject // order 'Object' last, it matches on other classes too
291
292 }]; // TODO: add conversion from BigNumber to number?
293
294 typed.conversions = [{
295 from: 'number',
296 to: 'BigNumber',
297 convert: function convert(x) {
298 // note: conversion from number to BigNumber can fail if x has >15 digits
299 if (digits(x) > 15) {
300 throw new TypeError('Cannot implicitly convert a number with >15 significant digits to BigNumber ' + '(value: ' + x + '). ' + 'Use function bignumber(x) to convert to BigNumber.');
301 }
302
303 return new type.BigNumber(x);
304 }
305 }, {
306 from: 'number',
307 to: 'Complex',
308 convert: function convert(x) {
309 return new type.Complex(x, 0);
310 }
311 }, {
312 from: 'number',
313 to: 'string',
314 convert: function convert(x) {
315 return x + '';
316 }
317 }, {
318 from: 'BigNumber',
319 to: 'Complex',
320 convert: function convert(x) {
321 return new type.Complex(x.toNumber(), 0);
322 }
323 }, {
324 from: 'Fraction',
325 to: 'BigNumber',
326 convert: function convert(x) {
327 throw new TypeError('Cannot implicitly convert a Fraction to BigNumber or vice versa. ' + 'Use function bignumber(x) to convert to BigNumber or fraction(x) to convert to Fraction.');
328 }
329 }, {
330 from: 'Fraction',
331 to: 'Complex',
332 convert: function convert(x) {
333 return new type.Complex(x.valueOf(), 0);
334 }
335 }, {
336 from: 'number',
337 to: 'Fraction',
338 convert: function convert(x) {
339 var f = new type.Fraction(x);
340
341 if (f.valueOf() !== x) {
342 throw new TypeError('Cannot implicitly convert a number to a Fraction when there will be a loss of precision ' + '(value: ' + x + '). ' + 'Use function fraction(x) to convert to Fraction.');
343 }
344
345 return new type.Fraction(x);
346 }
347 }, {
348 // FIXME: add conversion from Fraction to number, for example for `sqrt(fraction(1,3))`
349 // from: 'Fraction',
350 // to: 'number',
351 // convert: function (x) {
352 // return x.valueOf()
353 // }
354 // }, {
355 from: 'string',
356 to: 'number',
357 convert: function convert(x) {
358 var n = Number(x);
359
360 if (isNaN(n)) {
361 throw new Error('Cannot convert "' + x + '" to a number');
362 }
363
364 return n;
365 }
366 }, {
367 from: 'string',
368 to: 'BigNumber',
369 convert: function convert(x) {
370 try {
371 return new type.BigNumber(x);
372 } catch (err) {
373 throw new Error('Cannot convert "' + x + '" to BigNumber');
374 }
375 }
376 }, {
377 from: 'string',
378 to: 'Fraction',
379 convert: function convert(x) {
380 try {
381 return new type.Fraction(x);
382 } catch (err) {
383 throw new Error('Cannot convert "' + x + '" to Fraction');
384 }
385 }
386 }, {
387 from: 'string',
388 to: 'Complex',
389 convert: function convert(x) {
390 try {
391 return new type.Complex(x);
392 } catch (err) {
393 throw new Error('Cannot convert "' + x + '" to Complex');
394 }
395 }
396 }, {
397 from: 'boolean',
398 to: 'number',
399 convert: function convert(x) {
400 return +x;
401 }
402 }, {
403 from: 'boolean',
404 to: 'BigNumber',
405 convert: function convert(x) {
406 return new type.BigNumber(+x);
407 }
408 }, {
409 from: 'boolean',
410 to: 'Fraction',
411 convert: function convert(x) {
412 return new type.Fraction(+x);
413 }
414 }, {
415 from: 'boolean',
416 to: 'string',
417 convert: function convert(x) {
418 return +x;
419 }
420 }, {
421 from: 'Array',
422 to: 'Matrix',
423 convert: function convert(array) {
424 return new type.DenseMatrix(array);
425 }
426 }, {
427 from: 'Matrix',
428 to: 'Array',
429 convert: function convert(matrix) {
430 return matrix.valueOf();
431 }
432 }];
433 return typed;
434};
\No newline at end of file