mathjs 5.0.0 → 5.0.4

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of mathjs might be problematic. Click here for more details.

Files changed (71) hide show
  1. package/HISTORY.md +48 -1
  2. package/README.md +2 -1
  3. package/dist/math.js +20114 -20090
  4. package/dist/math.min.js +7 -7
  5. package/dist/math.min.map +1 -1
  6. package/docs/core/configuration.md +1 -1
  7. package/docs/datatypes/numbers.md +1 -1
  8. package/docs/datatypes/units.md +1 -1
  9. package/docs/expressions/algebra.md +25 -1
  10. package/docs/getting_started.md +2 -2
  11. package/docs/reference/functions/format.md +2 -2
  12. package/docs/reference/functions/qr.md +2 -1
  13. package/docs/reference/functions/rationalize.md +13 -10
  14. package/docs/reference/functions/stirlingS2.md +1 -1
  15. package/docs/reference/functions/typeof.md +13 -13
  16. package/examples/advanced/add_new_datatypes/MyType.js +0 -10
  17. package/examples/advanced/add_new_datatypes/index.js +2 -6
  18. package/examples/browser/rocket_trajectory_optimization.html +2 -2
  19. package/lib/constants.js +3 -1
  20. package/lib/core/function/import.js +15 -2
  21. package/lib/core/typed.js +1 -1
  22. package/lib/expression/node/FunctionNode.js +5 -4
  23. package/lib/expression/parse.js +429 -466
  24. package/lib/function/algebra/decomposition/qr.js +1 -1
  25. package/lib/function/algebra/rationalize.js +41 -45
  26. package/lib/function/algebra/simplify/resolve.js +1 -1
  27. package/lib/function/algebra/simplify/simplifyCore.js +3 -3
  28. package/lib/function/algebra/simplify/util.js +1 -1
  29. package/lib/function/algebra/simplify.js +5 -0
  30. package/lib/function/combinatorics/stirlingS2.js +1 -1
  31. package/lib/function/probability/combinations.js +11 -10
  32. package/lib/function/probability/gamma.js +5 -13
  33. package/lib/function/probability/permutations.js +2 -12
  34. package/lib/function/probability/product.js +19 -0
  35. package/lib/function/string/format.js +2 -2
  36. package/lib/function/utils/typeof.js +13 -13
  37. package/lib/index.js +5 -1
  38. package/lib/type/bignumber/BigNumber.js +6 -2
  39. package/lib/type/matrix/utils/algorithm13.js +0 -2
  40. package/lib/type/unit/Unit.js +2 -2
  41. package/lib/utils/array.js +27 -19
  42. package/lib/utils/bignumber/formatter.js +3 -2
  43. package/lib/utils/number.js +15 -10
  44. package/lib/version.js +1 -1
  45. package/package.json +13 -8
  46. package/src/constants.js +3 -1
  47. package/src/core/function/import.js +15 -2
  48. package/src/core/typed.js +1 -1
  49. package/src/expression/node/FunctionNode.js +3 -4
  50. package/src/expression/parse.js +432 -470
  51. package/src/function/algebra/decomposition/qr.js +1 -1
  52. package/src/function/algebra/rationalize.js +41 -43
  53. package/src/function/algebra/simplify/resolve.js +1 -1
  54. package/src/function/algebra/simplify/simplifyCore.js +3 -3
  55. package/src/function/algebra/simplify/util.js +1 -1
  56. package/src/function/algebra/simplify.js +5 -0
  57. package/src/function/combinatorics/stirlingS2.js +1 -1
  58. package/src/function/probability/combinations.js +10 -8
  59. package/src/function/probability/gamma.js +5 -13
  60. package/src/function/probability/permutations.js +2 -11
  61. package/src/function/probability/product.js +17 -0
  62. package/src/function/string/format.js +2 -2
  63. package/src/function/utils/typeof.js +13 -13
  64. package/src/index.js +5 -1
  65. package/src/type/bignumber/BigNumber.js +2 -1
  66. package/src/type/matrix/utils/algorithm13.js +0 -2
  67. package/src/type/unit/Unit.js +2 -2
  68. package/src/utils/array.js +31 -23
  69. package/src/utils/bignumber/formatter.js +3 -2
  70. package/src/utils/number.js +15 -10
  71. package/src/version.js +1 -1
@@ -59,19 +59,18 @@ function factory (type, config, load, typed) {
59
59
  }
60
60
 
61
61
  // pass extra nodes
62
- extraNodes = (options && options.nodes) ? options.nodes : {}
62
+ let extraNodes = (options && options.nodes) ? options.nodes : {}
63
63
 
64
64
  if (typeof expr === 'string') {
65
65
  // parse a single expression
66
- expression = expr
67
- return parseStart()
66
+
67
+ return parseStart(expr, extraNodes)
68
68
  } else if (Array.isArray(expr) || expr instanceof type.Matrix) {
69
69
  // parse an array or matrix with expressions
70
70
  return deepMap(expr, function (elem) {
71
71
  if (typeof elem !== 'string') throw new TypeError('String expected')
72
72
 
73
- expression = elem
74
- return parseStart()
73
+ return parseStart(elem, extraNodes)
75
74
  })
76
75
  } else {
77
76
  // oops
@@ -154,101 +153,68 @@ function factory (type, config, load, typed) {
154
153
  'Infinity'
155
154
  ]
156
155
 
157
- let extraNodes = {} // current extra nodes
158
- let expression = '' // current expression
159
- let comment = '' // last parsed comment
160
- let index = 0 // current index in expr
161
- let c = '' // current token character in expr
162
- let token = '' // current token
163
- let tokenType = TOKENTYPE.NULL // type of the token
164
- let nestingLevel = 0 // level of nesting inside parameters, used to ignore newline characters
165
- let conditionalLevel = null // when a conditional is being parsed, the level of the conditional is stored here
166
- const tokenStates = [] // holds saved token states
167
-
168
- /**
169
- * Get the first character from the expression.
170
- * The character is stored into the char c. If the end of the expression is
171
- * reached, the function puts an empty string in c.
172
- * @private
173
- */
174
- function first () {
175
- index = 0
176
- c = expression.charAt(0)
177
- nestingLevel = 0
178
- conditionalLevel = null
156
+ function initialState () {
157
+ return {
158
+ extraNodes: {}, // current extra nodes, must be careful not to mutate
159
+ expression: '', // current expression
160
+ comment: '', // last parsed comment
161
+ index: 0, // current index in expr
162
+ token: '', // current token
163
+ tokenType: TOKENTYPE.NULL, // type of the token
164
+ nestingLevel: 0, // level of nesting inside parameters, used to ignore newline characters
165
+ conditionalLevel: null // when a conditional is being parsed, the level of the conditional is stored here
166
+ }
179
167
  }
180
168
 
181
169
  /**
182
- * Get the next character from the expression.
183
- * The character is stored into the char c. If the end of the expression is
184
- * reached, the function puts an empty string in c.
170
+ * View upto `length` characters of the expression starting at the current character.
171
+ *
172
+ * @param {State} state
173
+ * @param {number} [length=1] Number of characters to view
174
+ * @returns {string}
185
175
  * @private
186
176
  */
187
- function next () {
188
- index++
189
- c = expression.charAt(index)
177
+ function currentString (state, length) {
178
+ return state.expression.substr(state.index, length)
190
179
  }
191
180
 
192
181
  /**
193
- * Preview the previous character from the expression.
194
- * @return {string} cNext
182
+ * View the current character. Returns '' if end of expression is reached.
183
+ *
184
+ * @param {State} state
185
+ * @returns {string}
195
186
  * @private
196
187
  */
197
- function prevPreview () {
198
- return expression.charAt(index - 1)
188
+ function currentCharacter (state) {
189
+ return currentString(state, 1)
199
190
  }
200
191
 
201
192
  /**
202
- * Preview the next character from the expression.
203
- * @return {string} cNext
193
+ * Get the next character from the expression.
194
+ * The character is stored into the char c. If the end of the expression is
195
+ * reached, the function puts an empty string in c.
204
196
  * @private
205
197
  */
206
- function nextPreview () {
207
- return expression.charAt(index + 1)
198
+ function next (state) {
199
+ state.index++
208
200
  }
209
201
 
210
202
  /**
211
- * Preview the second next character from the expression.
203
+ * Preview the previous character from the expression.
212
204
  * @return {string} cNext
213
205
  * @private
214
206
  */
215
- function nextNextPreview () {
216
- return expression.charAt(index + 2)
217
- }
218
-
219
- /**
220
- * Save the current token state so we can rewind later if necessary.
221
- * @private
222
- */
223
- function pushTokenState () {
224
- tokenStates.push({
225
- tokenType: tokenType,
226
- token: token,
227
- comment: comment,
228
- index: index,
229
- c: c
230
- })
231
- }
232
-
233
- /**
234
- * Rewind the parser by one token by restoring the last saved token state
235
- * @private
236
- */
237
- function popTokenState () {
238
- const restoredState = tokenStates.pop()
239
- tokenType = restoredState.tokenType
240
- token = restoredState.token
241
- comment = restoredState.comment
242
- index = restoredState.index
243
- c = restoredState.c
207
+ function prevCharacter (state) {
208
+ return state.expression.charAt(state.index - 1)
244
209
  }
245
210
 
246
211
  /**
247
- * Discard the most recent token state without restoring it
212
+ * Preview the next character from the expression.
213
+ * @return {string} cNext
248
214
  * @private
249
215
  */
250
- function discardTokenState () {
251
- tokenStates.pop()
216
+ function nextCharacter (state) {
217
+ return state.expression.charAt(state.index + 1)
252
218
  }
253
219
 
254
220
  /**
@@ -256,125 +222,123 @@ function factory (type, config, load, typed) {
256
222
  * The token and token type are available as token and tokenType
257
223
  * @private
258
224
  */
259
- function getToken () {
260
- tokenType = TOKENTYPE.NULL
261
- token = ''
262
- comment = ''
225
+ function getToken (state) {
226
+ state.tokenType = TOKENTYPE.NULL
227
+ state.token = ''
228
+ state.comment = ''
263
229
 
264
230
  // skip over whitespaces
265
231
  // space, tab, and newline when inside parameters
266
- while (parse.isWhitespace(c, nestingLevel)) {
267
- next()
232
+ while (parse.isWhitespace(currentCharacter(state), state.nestingLevel)) {
233
+ next(state)
268
234
  }
269
235
 
270
236
  // skip comment
271
- if (c === '#') {
272
- while (c !== '\n' && c !== '') {
273
- comment += c
274
- next()
237
+ if (currentCharacter(state) === '#') {
238
+ while (currentCharacter(state) !== '\n' && currentCharacter(state) !== '') {
239
+ state.comment += currentCharacter(state)
240
+ next(state)
275
241
  }
276
242
  }
277
243
 
278
244
  // check for end of expression
279
- if (c === '') {
245
+ if (currentCharacter(state) === '') {
280
246
  // token is still empty
281
- tokenType = TOKENTYPE.DELIMITER
247
+ state.tokenType = TOKENTYPE.DELIMITER
282
248
  return
283
249
  }
284
250
 
285
251
  // check for new line character
286
- if (c === '\n' && !nestingLevel) {
287
- tokenType = TOKENTYPE.DELIMITER
288
- token = c
289
- next()
252
+ if (currentCharacter(state) === '\n' && !state.nestingLevel) {
253
+ state.tokenType = TOKENTYPE.DELIMITER
254
+ state.token = currentCharacter(state)
255
+ next(state)
290
256
  return
291
257
  }
292
258
 
293
- // check for delimiters consisting of 3 characters
294
- let c2 = c + nextPreview()
295
- const c3 = c2 + nextNextPreview()
259
+ const c1 = currentCharacter(state)
260
+ const c2 = currentString(state, 2)
261
+ const c3 = currentString(state, 3)
296
262
  if (c3.length === 3 && DELIMITERS[c3]) {
297
- tokenType = TOKENTYPE.DELIMITER
298
- token = c3
299
- next()
300
- next()
301
- next()
263
+ state.tokenType = TOKENTYPE.DELIMITER
264
+ state.token = c3
265
+ next(state)
266
+ next(state)
267
+ next(state)
302
268
  return
303
269
  }
304
270
 
305
271
  // check for delimiters consisting of 2 characters
306
272
  if (c2.length === 2 && DELIMITERS[c2]) {
307
- tokenType = TOKENTYPE.DELIMITER
308
- token = c2
309
- next()
310
- next()
273
+ state.tokenType = TOKENTYPE.DELIMITER
274
+ state.token = c2
275
+ next(state)
276
+ next(state)
311
277
  return
312
278
  }
313
279
 
314
280
  // check for delimiters consisting of 1 character
315
- if (DELIMITERS[c]) {
316
- tokenType = TOKENTYPE.DELIMITER
317
- token = c
318
- next()
281
+ if (DELIMITERS[c1]) {
282
+ state.tokenType = TOKENTYPE.DELIMITER
283
+ state.token = c1
284
+ next(state)
319
285
  return
320
286
  }
321
287
 
322
288
  // check for a number
323
- if (parse.isDigitDot(c)) {
324
- tokenType = TOKENTYPE.NUMBER
289
+ if (parse.isDigitDot(c1)) {
290
+ state.tokenType = TOKENTYPE.NUMBER
325
291
 
326
292
  // get number, can have a single dot
327
- if (c === '.') {
328
- token += c
329
- next()
293
+ if (currentCharacter(state) === '.') {
294
+ state.token += currentCharacter(state)
295
+ next(state)
330
296
 
331
- if (!parse.isDigit(c)) {
297
+ if (!parse.isDigit(currentCharacter(state))) {
332
298
  // this is no number, it is just a dot (can be dot notation)
333
- tokenType = TOKENTYPE.DELIMITER
299
+ state.tokenType = TOKENTYPE.DELIMITER
334
300
  }
335
301
  } else {
336
- while (parse.isDigit(c)) {
337
- token += c
338
- next()
302
+ while (parse.isDigit(currentCharacter(state))) {
303
+ state.token += currentCharacter(state)
304
+ next(state)
339
305
  }
340
- if (parse.isDecimalMark(c, nextPreview())) {
341
- token += c
342
- next()
306
+ if (parse.isDecimalMark(currentCharacter(state), nextCharacter(state))) {
307
+ state.token += currentCharacter(state)
308
+ next(state)
343
309
  }
344
310
  }
345
- while (parse.isDigit(c)) {
346
- token += c
347
- next()
348
- }
349
311
 
312
+ while (parse.isDigit(currentCharacter(state))) {
313
+ state.token += currentCharacter(state)
314
+ next(state)
315
+ }
350
316
  // check for exponential notation like "2.3e-4", "1.23e50" or "2e+4"
351
- c2 = nextPreview()
352
- if (c === 'E' || c === 'e') {
353
- if (parse.isDigit(c2) || c2 === '-' || c2 === '+') {
354
- token += c
355
- next()
356
-
357
- if (c === '+' || c === '-') {
358
- token += c
359
- next()
317
+ if (currentCharacter(state) === 'E' || currentCharacter(state) === 'e') {
318
+ if (parse.isDigit(nextCharacter(state)) || nextCharacter(state) === '-' || nextCharacter(state) === '+') {
319
+ state.token += currentCharacter(state)
320
+ next(state)
321
+
322
+ if (currentCharacter(state) === '+' || currentCharacter(state) === '-') {
323
+ state.token += currentCharacter(state)
324
+ next(state)
360
325
  }
361
-
362
326
  // Scientific notation MUST be followed by an exponent
363
- if (!parse.isDigit(c)) {
364
- throw createSyntaxError('Digit expected, got "' + c + '"')
327
+ if (!parse.isDigit(currentCharacter(state))) {
328
+ throw createSyntaxError(state, 'Digit expected, got "' + currentCharacter(state) + '"')
365
329
  }
366
330
 
367
- while (parse.isDigit(c)) {
368
- token += c
369
- next()
331
+ while (parse.isDigit(currentCharacter(state))) {
332
+ state.token += currentCharacter(state)
333
+ next(state)
370
334
  }
371
335
 
372
- if (parse.isDecimalMark(c, nextPreview())) {
373
- throw createSyntaxError('Digit expected, got "' + c + '"')
336
+ if (parse.isDecimalMark(currentCharacter(state), nextCharacter(state))) {
337
+ throw createSyntaxError(state, 'Digit expected, got "' + currentCharacter(state) + '"')
374
338
  }
375
- } else if (c2 === '.') {
376
- next()
377
- throw createSyntaxError('Digit expected, got "' + c + '"')
339
+ } else if (nextCharacter(state) === '.') {
340
+ next(state)
341
+ throw createSyntaxError(state, 'Digit expected, got "' + currentCharacter(state) + '"')
378
342
  }
379
343
  }
380
344
 
@@ -382,54 +346,54 @@ function factory (type, config, load, typed) {
382
346
  }
383
347
 
384
348
  // check for variables, functions, named operators
385
- if (parse.isAlpha(c, prevPreview(), nextPreview())) {
386
- while (parse.isAlpha(c, prevPreview(), nextPreview()) || parse.isDigit(c)) {
387
- token += c
388
- next()
349
+ if (parse.isAlpha(currentCharacter(state), prevCharacter(state), nextCharacter(state))) {
350
+ while (parse.isAlpha(currentCharacter(state), prevCharacter(state), nextCharacter(state)) || parse.isDigit(currentCharacter(state))) {
351
+ state.token += currentCharacter(state)
352
+ next(state)
389
353
  }
390
354
 
391
- if (NAMED_DELIMITERS.hasOwnProperty(token)) {
392
- tokenType = TOKENTYPE.DELIMITER
355
+ if (NAMED_DELIMITERS.hasOwnProperty(state.token)) {
356
+ state.tokenType = TOKENTYPE.DELIMITER
393
357
  } else {
394
- tokenType = TOKENTYPE.SYMBOL
358
+ state.tokenType = TOKENTYPE.SYMBOL
395
359
  }
396
360
 
397
361
  return
398
362
  }
399
363
 
400
364
  // something unknown is found, wrong characters -> a syntax error
401
- tokenType = TOKENTYPE.UNKNOWN
402
- while (c !== '') {
403
- token += c
404
- next()
365
+ state.tokenType = TOKENTYPE.UNKNOWN
366
+ while (currentCharacter(state) !== '') {
367
+ state.token += currentCharacter(state)
368
+ next(state)
405
369
  }
406
- throw createSyntaxError('Syntax error in part "' + token + '"')
370
+ throw createSyntaxError(state, 'Syntax error in part "' + state.token + '"')
407
371
  }
408
372
 
409
373
  /**
410
374
  * Get next token and skip newline tokens
411
375
  */
412
- function getTokenSkipNewline () {
376
+ function getTokenSkipNewline (state) {
413
377
  do {
414
- getToken()
378
+ getToken(state)
415
379
  }
416
- while (token === '\n') // eslint-disable-line no-unmodified-loop-condition
380
+ while (state.token === '\n') // eslint-disable-line no-unmodified-loop-condition
417
381
  }
418
382
 
419
383
  /**
420
384
  * Open parameters.
421
- * New line characters will be ignored until closeParams() is called
385
+ * New line characters will be ignored until closeParams(state) is called
422
386
  */
423
- function openParams () {
424
- nestingLevel++
387
+ function openParams (state) {
388
+ state.nestingLevel++
425
389
  }
426
390
 
427
391
  /**
428
392
  * Close parameters.
429
393
  * New line characters will no longer be ignored
430
394
  */
431
- function closeParams () {
432
- nestingLevel--
395
+ function closeParams (state) {
396
+ state.nestingLevel--
433
397
  }
434
398
 
435
399
  /**
@@ -531,24 +495,23 @@ function factory (type, config, load, typed) {
531
495
  * @return {Node} node
532
496
  * @private
533
497
  */
534
- function parseStart () {
535
- // get the first character in expression
536
- first()
537
-
538
- getToken()
498
+ function parseStart (expression, extraNodes) {
499
+ const state = initialState()
500
+ Object.assign(state, { expression, extraNodes })
501
+ getToken(state)
539
502
 
540
- const node = parseBlock()
503
+ const node = parseBlock(state)
541
504
 
542
505
  // check for garbage at the end of the expression
543
506
  // an expression ends with a empty character '' and tokenType DELIMITER
544
- if (token !== '') {
545
- if (tokenType === TOKENTYPE.DELIMITER) {
507
+ if (state.token !== '') {
508
+ if (state.tokenType === TOKENTYPE.DELIMITER) {
546
509
  // user entered a not existing operator like "//"
547
510
 
548
511
  // TODO: give hints for aliases, for example with "<>" give as hint " did you mean !== ?"
549
- throw createError('Unexpected operator ' + token)
512
+ throw createError(state, 'Unexpected operator ' + state.token)
550
513
  } else {
551
- throw createSyntaxError('Unexpected part "' + token + '"')
514
+ throw createSyntaxError(state, 'Unexpected part "' + state.token + '"')
552
515
  }
553
516
  }
554
517
 
@@ -562,32 +525,32 @@ function factory (type, config, load, typed) {
562
525
  * @return {Node} node
563
526
  * @private
564
527
  */
565
- function parseBlock () {
528
+ function parseBlock (state) {
566
529
  let node
567
530
  const blocks = []
568
531
  let visible
569
532
 
570
- if (token !== '' && token !== '\n' && token !== ';') {
571
- node = parseAssignment()
572
- node.comment = comment
533
+ if (state.token !== '' && state.token !== '\n' && state.token !== ';') {
534
+ node = parseAssignment(state)
535
+ node.comment = state.comment
573
536
  }
574
537
 
575
538
  // TODO: simplify this loop
576
- while (token === '\n' || token === ';') { // eslint-disable-line no-unmodified-loop-condition
539
+ while (state.token === '\n' || state.token === ';') { // eslint-disable-line no-unmodified-loop-condition
577
540
  if (blocks.length === 0 && node) {
578
- visible = (token !== ';')
541
+ visible = (state.token !== ';')
579
542
  blocks.push({
580
543
  node: node,
581
544
  visible: visible
582
545
  })
583
546
  }
584
547
 
585
- getToken()
586
- if (token !== '\n' && token !== ';' && token !== '') {
587
- node = parseAssignment()
588
- node.comment = comment
548
+ getToken(state)
549
+ if (state.token !== '\n' && state.token !== ';' && state.token !== '') {
550
+ node = parseAssignment(state)
551
+ node.comment = state.comment
589
552
 
590
- visible = (token !== ';')
553
+ visible = (state.token !== ';')
591
554
  blocks.push({
592
555
  node: node,
593
556
  visible: visible
@@ -600,7 +563,7 @@ function factory (type, config, load, typed) {
600
563
  } else {
601
564
  if (!node) {
602
565
  node = new ConstantNode(undefined)
603
- node.comment = comment
566
+ node.comment = state.comment
604
567
  }
605
568
 
606
569
  return node
@@ -615,22 +578,22 @@ function factory (type, config, load, typed) {
615
578
  * @return {Node} node
616
579
  * @private
617
580
  */
618
- function parseAssignment () {
581
+ function parseAssignment (state) {
619
582
  let name, args, value, valid
620
583
 
621
- const node = parseConditional()
584
+ const node = parseConditional(state)
622
585
 
623
- if (token === '=') {
586
+ if (state.token === '=') {
624
587
  if (type.isSymbolNode(node)) {
625
588
  // parse a variable assignment like 'a = 2/3'
626
589
  name = node.name
627
- getTokenSkipNewline()
628
- value = parseAssignment()
590
+ getTokenSkipNewline(state)
591
+ value = parseAssignment(state)
629
592
  return new AssignmentNode(new SymbolNode(name), value)
630
593
  } else if (type.isAccessorNode(node)) {
631
594
  // parse a matrix subset assignment like 'A[1,2] = 4'
632
- getTokenSkipNewline()
633
- value = parseAssignment()
595
+ getTokenSkipNewline(state)
596
+ value = parseAssignment(state)
634
597
  return new AssignmentNode(node.object, node.index, value)
635
598
  } else if (type.isFunctionNode(node) && type.isSymbolNode(node.fn)) {
636
599
  // parse function assignment like 'f(x) = x^2'
@@ -647,13 +610,13 @@ function factory (type, config, load, typed) {
647
610
  })
648
611
 
649
612
  if (valid) {
650
- getTokenSkipNewline()
651
- value = parseAssignment()
613
+ getTokenSkipNewline(state)
614
+ value = parseAssignment(state)
652
615
  return new FunctionAssignmentNode(name, args, value)
653
616
  }
654
617
  }
655
618
 
656
- throw createSyntaxError('Invalid left hand side of assignment operator =')
619
+ throw createSyntaxError(state, 'Invalid left hand side of assignment operator =')
657
620
  }
658
621
 
659
622
  return node
@@ -669,30 +632,30 @@ function factory (type, config, load, typed) {
669
632
  * @return {Node} node
670
633
  * @private
671
634
  */
672
- function parseConditional () {
673
- let node = parseLogicalOr()
635
+ function parseConditional (state) {
636
+ let node = parseLogicalOr(state)
674
637
 
675
- while (token === '?') { // eslint-disable-line no-unmodified-loop-condition
638
+ while (state.token === '?') { // eslint-disable-line no-unmodified-loop-condition
676
639
  // set a conditional level, the range operator will be ignored as long
677
- // as conditionalLevel === nestingLevel.
678
- const prev = conditionalLevel
679
- conditionalLevel = nestingLevel
680
- getTokenSkipNewline()
640
+ // as conditionalLevel === state.nestingLevel.
641
+ const prev = state.conditionalLevel
642
+ state.conditionalLevel = state.nestingLevel
643
+ getTokenSkipNewline(state)
681
644
 
682
645
  const condition = node
683
- const trueExpr = parseAssignment()
646
+ const trueExpr = parseAssignment(state)
684
647
 
685
- if (token !== ':') throw createSyntaxError('False part of conditional expression expected')
648
+ if (state.token !== ':') throw createSyntaxError(state, 'False part of conditional expression expected')
686
649
 
687
- conditionalLevel = null
688
- getTokenSkipNewline()
650
+ state.conditionalLevel = null
651
+ getTokenSkipNewline(state)
689
652
 
690
- const falseExpr = parseAssignment() // Note: check for conditional operator again, right associativity
653
+ const falseExpr = parseAssignment(state) // Note: check for conditional operator again, right associativity
691
654
 
692
655
  node = new ConditionalNode(condition, trueExpr, falseExpr)
693
656
 
694
657
  // restore the previous conditional level
695
- conditionalLevel = prev
658
+ state.conditionalLevel = prev
696
659
  }
697
660
 
698
661
  return node
@@ -703,12 +666,12 @@ function factory (type, config, load, typed) {
703
666
  * @return {Node} node
704
667
  * @private
705
668
  */
706
- function parseLogicalOr () {
707
- let node = parseLogicalXor()
669
+ function parseLogicalOr (state) {
670
+ let node = parseLogicalXor(state)
708
671
 
709
- while (token === 'or') { // eslint-disable-line no-unmodified-loop-condition
710
- getTokenSkipNewline()
711
- node = new OperatorNode('or', 'or', [node, parseLogicalXor()])
672
+ while (state.token === 'or') { // eslint-disable-line no-unmodified-loop-condition
673
+ getTokenSkipNewline(state)
674
+ node = new OperatorNode('or', 'or', [node, parseLogicalXor(state)])
712
675
  }
713
676
 
714
677
  return node
@@ -719,12 +682,12 @@ function factory (type, config, load, typed) {
719
682
  * @return {Node} node
720
683
  * @private
721
684
  */
722
- function parseLogicalXor () {
723
- let node = parseLogicalAnd()
685
+ function parseLogicalXor (state) {
686
+ let node = parseLogicalAnd(state)
724
687
 
725
- while (token === 'xor') { // eslint-disable-line no-unmodified-loop-condition
726
- getTokenSkipNewline()
727
- node = new OperatorNode('xor', 'xor', [node, parseLogicalAnd()])
688
+ while (state.token === 'xor') { // eslint-disable-line no-unmodified-loop-condition
689
+ getTokenSkipNewline(state)
690
+ node = new OperatorNode('xor', 'xor', [node, parseLogicalAnd(state)])
728
691
  }
729
692
 
730
693
  return node
@@ -735,12 +698,12 @@ function factory (type, config, load, typed) {
735
698
  * @return {Node} node
736
699
  * @private
737
700
  */
738
- function parseLogicalAnd () {
739
- let node = parseBitwiseOr()
701
+ function parseLogicalAnd (state) {
702
+ let node = parseBitwiseOr(state)
740
703
 
741
- while (token === 'and') { // eslint-disable-line no-unmodified-loop-condition
742
- getTokenSkipNewline()
743
- node = new OperatorNode('and', 'and', [node, parseBitwiseOr()])
704
+ while (state.token === 'and') { // eslint-disable-line no-unmodified-loop-condition
705
+ getTokenSkipNewline(state)
706
+ node = new OperatorNode('and', 'and', [node, parseBitwiseOr(state)])
744
707
  }
745
708
 
746
709
  return node
@@ -751,12 +714,12 @@ function factory (type, config, load, typed) {
751
714
  * @return {Node} node
752
715
  * @private
753
716
  */
754
- function parseBitwiseOr () {
755
- let node = parseBitwiseXor()
717
+ function parseBitwiseOr (state) {
718
+ let node = parseBitwiseXor(state)
756
719
 
757
- while (token === '|') { // eslint-disable-line no-unmodified-loop-condition
758
- getTokenSkipNewline()
759
- node = new OperatorNode('|', 'bitOr', [node, parseBitwiseXor()])
720
+ while (state.token === '|') { // eslint-disable-line no-unmodified-loop-condition
721
+ getTokenSkipNewline(state)
722
+ node = new OperatorNode('|', 'bitOr', [node, parseBitwiseXor(state)])
760
723
  }
761
724
 
762
725
  return node
@@ -767,12 +730,12 @@ function factory (type, config, load, typed) {
767
730
  * @return {Node} node
768
731
  * @private
769
732
  */
770
- function parseBitwiseXor () {
771
- let node = parseBitwiseAnd()
733
+ function parseBitwiseXor (state) {
734
+ let node = parseBitwiseAnd(state)
772
735
 
773
- while (token === '^|') { // eslint-disable-line no-unmodified-loop-condition
774
- getTokenSkipNewline()
775
- node = new OperatorNode('^|', 'bitXor', [node, parseBitwiseAnd()])
736
+ while (state.token === '^|') { // eslint-disable-line no-unmodified-loop-condition
737
+ getTokenSkipNewline(state)
738
+ node = new OperatorNode('^|', 'bitXor', [node, parseBitwiseAnd(state)])
776
739
  }
777
740
 
778
741
  return node
@@ -783,12 +746,12 @@ function factory (type, config, load, typed) {
783
746
  * @return {Node} node
784
747
  * @private
785
748
  */
786
- function parseBitwiseAnd () {
787
- let node = parseRelational()
749
+ function parseBitwiseAnd (state) {
750
+ let node = parseRelational(state)
788
751
 
789
- while (token === '&') { // eslint-disable-line no-unmodified-loop-condition
790
- getTokenSkipNewline()
791
- node = new OperatorNode('&', 'bitAnd', [node, parseRelational()])
752
+ while (state.token === '&') { // eslint-disable-line no-unmodified-loop-condition
753
+ getTokenSkipNewline(state)
754
+ node = new OperatorNode('&', 'bitAnd', [node, parseRelational(state)])
792
755
  }
793
756
 
794
757
  return node
@@ -799,10 +762,10 @@ function factory (type, config, load, typed) {
799
762
  * @return {Node} node
800
763
  * @private
801
764
  */
802
- function parseRelational () {
765
+ function parseRelational (state) {
803
766
  let node, operators, name, fn, params
804
767
 
805
- node = parseShift()
768
+ node = parseShift(state)
806
769
 
807
770
  operators = {
808
771
  '==': 'equal',
@@ -812,12 +775,12 @@ function factory (type, config, load, typed) {
812
775
  '<=': 'smallerEq',
813
776
  '>=': 'largerEq'
814
777
  }
815
- while (operators.hasOwnProperty(token)) {
816
- name = token
778
+ while (operators.hasOwnProperty(state.token)) {
779
+ name = state.token
817
780
  fn = operators[name]
818
781
 
819
- getTokenSkipNewline()
820
- params = [node, parseShift()]
782
+ getTokenSkipNewline(state)
783
+ params = [node, parseShift(state)]
821
784
  node = new OperatorNode(name, fn, params)
822
785
  }
823
786
 
@@ -829,10 +792,10 @@ function factory (type, config, load, typed) {
829
792
  * @return {Node} node
830
793
  * @private
831
794
  */
832
- function parseShift () {
795
+ function parseShift (state) {
833
796
  let node, operators, name, fn, params
834
797
 
835
- node = parseConversion()
798
+ node = parseConversion(state)
836
799
 
837
800
  operators = {
838
801
  '<<': 'leftShift',
@@ -840,12 +803,12 @@ function factory (type, config, load, typed) {
840
803
  '>>>': 'rightLogShift'
841
804
  }
842
805
 
843
- while (operators.hasOwnProperty(token)) {
844
- name = token
806
+ while (operators.hasOwnProperty(state.token)) {
807
+ name = state.token
845
808
  fn = operators[name]
846
809
 
847
- getTokenSkipNewline()
848
- params = [node, parseConversion()]
810
+ getTokenSkipNewline(state)
811
+ params = [node, parseConversion(state)]
849
812
  node = new OperatorNode(name, fn, params)
850
813
  }
851
814
 
@@ -857,28 +820,28 @@ function factory (type, config, load, typed) {
857
820
  * @return {Node} node
858
821
  * @private
859
822
  */
860
- function parseConversion () {
823
+ function parseConversion (state) {
861
824
  let node, operators, name, fn, params
862
825
 
863
- node = parseRange()
826
+ node = parseRange(state)
864
827
 
865
828
  operators = {
866
829
  'to': 'to',
867
830
  'in': 'to' // alias of 'to'
868
831
  }
869
832
 
870
- while (operators.hasOwnProperty(token)) {
871
- name = token
833
+ while (operators.hasOwnProperty(state.token)) {
834
+ name = state.token
872
835
  fn = operators[name]
873
836
 
874
- getTokenSkipNewline()
837
+ getTokenSkipNewline(state)
875
838
 
876
- if (name === 'in' && token === '') {
839
+ if (name === 'in' && state.token === '') {
877
840
  // end of expression -> this is the unit 'in' ('inch')
878
841
  node = new OperatorNode('*', 'multiply', [node, new SymbolNode('in')], true)
879
842
  } else {
880
843
  // operator 'a to b' or 'a in b'
881
- params = [node, parseRange()]
844
+ params = [node, parseRange(state)]
882
845
  node = new OperatorNode(name, fn, params)
883
846
  }
884
847
  }
@@ -891,32 +854,32 @@ function factory (type, config, load, typed) {
891
854
  * @return {Node} node
892
855
  * @private
893
856
  */
894
- function parseRange () {
857
+ function parseRange (state) {
895
858
  let node
896
859
  const params = []
897
860
 
898
- if (token === ':') {
861
+ if (state.token === ':') {
899
862
  // implicit start=1 (one-based)
900
863
  node = new ConstantNode(1)
901
864
  } else {
902
865
  // explicit start
903
- node = parseAddSubtract()
866
+ node = parseAddSubtract(state)
904
867
  }
905
868
 
906
- if (token === ':' && (conditionalLevel !== nestingLevel)) {
869
+ if (state.token === ':' && (state.conditionalLevel !== state.nestingLevel)) {
907
870
  // we ignore the range operator when a conditional operator is being processed on the same level
908
871
  params.push(node)
909
872
 
910
873
  // parse step and end
911
- while (token === ':' && params.length < 3) { // eslint-disable-line no-unmodified-loop-condition
912
- getTokenSkipNewline()
874
+ while (state.token === ':' && params.length < 3) { // eslint-disable-line no-unmodified-loop-condition
875
+ getTokenSkipNewline(state)
913
876
 
914
- if (token === ')' || token === ']' || token === ',' || token === '') {
877
+ if (state.token === ')' || state.token === ']' || state.token === ',' || state.token === '') {
915
878
  // implicit end
916
879
  params.push(new SymbolNode('end'))
917
880
  } else {
918
881
  // explicit end
919
- params.push(parseAddSubtract())
882
+ params.push(parseAddSubtract(state))
920
883
  }
921
884
  }
922
885
 
@@ -937,21 +900,21 @@ function factory (type, config, load, typed) {
937
900
  * @return {Node} node
938
901
  * @private
939
902
  */
940
- function parseAddSubtract () {
903
+ function parseAddSubtract (state) {
941
904
  let node, operators, name, fn, params
942
905
 
943
- node = parseMultiplyDivide()
906
+ node = parseMultiplyDivide(state)
944
907
 
945
908
  operators = {
946
909
  '+': 'add',
947
910
  '-': 'subtract'
948
911
  }
949
- while (operators.hasOwnProperty(token)) {
950
- name = token
912
+ while (operators.hasOwnProperty(state.token)) {
913
+ name = state.token
951
914
  fn = operators[name]
952
915
 
953
- getTokenSkipNewline()
954
- params = [node, parseMultiplyDivide()]
916
+ getTokenSkipNewline(state)
917
+ params = [node, parseMultiplyDivide(state)]
955
918
  node = new OperatorNode(name, fn, params)
956
919
  }
957
920
 
@@ -963,10 +926,10 @@ function factory (type, config, load, typed) {
963
926
  * @return {Node} node
964
927
  * @private
965
928
  */
966
- function parseMultiplyDivide () {
929
+ function parseMultiplyDivide (state) {
967
930
  let node, last, operators, name, fn
968
931
 
969
- node = parseImplicitMultiplication()
932
+ node = parseImplicitMultiplication(state)
970
933
  last = node
971
934
 
972
935
  operators = {
@@ -979,14 +942,14 @@ function factory (type, config, load, typed) {
979
942
  }
980
943
 
981
944
  while (true) {
982
- if (operators.hasOwnProperty(token)) {
945
+ if (operators.hasOwnProperty(state.token)) {
983
946
  // explicit operators
984
- name = token
947
+ name = state.token
985
948
  fn = operators[name]
986
949
 
987
- getTokenSkipNewline()
950
+ getTokenSkipNewline(state)
988
951
 
989
- last = parseImplicitMultiplication()
952
+ last = parseImplicitMultiplication(state)
990
953
  node = new OperatorNode(name, fn, [node, last])
991
954
  } else {
992
955
  break
@@ -1001,25 +964,25 @@ function factory (type, config, load, typed) {
1001
964
  * @return {Node} node
1002
965
  * @private
1003
966
  */
1004
- function parseImplicitMultiplication () {
967
+ function parseImplicitMultiplication (state) {
1005
968
  let node, last
1006
969
 
1007
- node = parseRule2()
970
+ node = parseRule2(state)
1008
971
  last = node
1009
972
 
1010
973
  while (true) {
1011
- if ((tokenType === TOKENTYPE.SYMBOL) ||
1012
- (token === 'in' && type.isConstantNode(node)) ||
1013
- (tokenType === TOKENTYPE.NUMBER &&
974
+ if ((state.tokenType === TOKENTYPE.SYMBOL) ||
975
+ (state.token === 'in' && type.isConstantNode(node)) ||
976
+ (state.tokenType === TOKENTYPE.NUMBER &&
1014
977
  !type.isConstantNode(last) &&
1015
978
  (!type.isOperatorNode(last) || last.op === '!')) ||
1016
- (token === '(')) {
979
+ (state.token === '(')) {
1017
980
  // parse implicit multiplication
1018
981
  //
1019
982
  // symbol: implicit multiplication like '2a', '(2+3)a', 'a b'
1020
983
  // number: implicit multiplication like '(2+3)2'
1021
984
  // parenthesis: implicit multiplication like '2(3+4)', '(3+4)(1+2)'
1022
- last = parseRule2()
985
+ last = parseRule2(state)
1023
986
  node = new OperatorNode('*', 'multiply', [node, last], true /* implicit */)
1024
987
  } else {
1025
988
  break
@@ -1036,42 +999,41 @@ function factory (type, config, load, typed) {
1036
999
  * @return {Node} node
1037
1000
  * @private
1038
1001
  */
1039
- function parseRule2 () {
1040
- let node, last
1041
-
1042
- node = parseUnary()
1043
- last = node
1002
+ function parseRule2 (state) {
1003
+ let node = parseUnary(state)
1004
+ let last = node
1005
+ let tokenStates = []
1044
1006
 
1045
1007
  while (true) {
1046
1008
  // Match the "number /" part of the pattern "number / number symbol"
1047
- if (token === '/' && type.isConstantNode(last)) {
1009
+ if (state.token === '/' && type.isConstantNode(last)) {
1048
1010
  // Look ahead to see if the next token is a number
1049
- pushTokenState()
1050
- getTokenSkipNewline()
1011
+ tokenStates.push(Object.assign({}, state))
1012
+ getTokenSkipNewline(state)
1051
1013
 
1052
1014
  // Match the "number / number" part of the pattern
1053
- if (tokenType === TOKENTYPE.NUMBER) {
1015
+ if (state.tokenType === TOKENTYPE.NUMBER) {
1054
1016
  // Look ahead again
1055
- pushTokenState()
1056
- getTokenSkipNewline()
1017
+ tokenStates.push(Object.assign({}, state))
1018
+ getTokenSkipNewline(state)
1057
1019
 
1058
1020
  // Match the "symbol" part of the pattern, or a left parenthesis
1059
- if (tokenType === TOKENTYPE.SYMBOL || token === '(') {
1021
+ if (state.tokenType === TOKENTYPE.SYMBOL || state.token === '(') {
1060
1022
  // We've matched the pattern "number / number symbol".
1061
1023
  // Rewind once and build the "number / number" node; the symbol will be consumed later
1062
- popTokenState()
1063
- discardTokenState()
1064
- last = parseUnary()
1024
+ Object.assign(state, tokenStates.pop())
1025
+ tokenStates.pop()
1026
+ last = parseUnary(state)
1065
1027
  node = new OperatorNode('/', 'divide', [node, last])
1066
1028
  } else {
1067
1029
  // Not a match, so rewind
1068
- popTokenState()
1069
- popTokenState()
1030
+ tokenStates.pop()
1031
+ Object.assign(state, tokenStates.pop())
1070
1032
  break
1071
1033
  }
1072
1034
  } else {
1073
1035
  // Not a match, so rewind
1074
- popTokenState()
1036
+ Object.assign(state, tokenStates.pop())
1075
1037
  break
1076
1038
  }
1077
1039
  } else {
@@ -1087,7 +1049,7 @@ function factory (type, config, load, typed) {
1087
1049
  * @return {Node} node
1088
1050
  * @private
1089
1051
  */
1090
- function parseUnary () {
1052
+ function parseUnary (state) {
1091
1053
  let name, params, fn
1092
1054
  const operators = {
1093
1055
  '-': 'unaryMinus',
@@ -1096,17 +1058,17 @@ function factory (type, config, load, typed) {
1096
1058
  'not': 'not'
1097
1059
  }
1098
1060
 
1099
- if (operators.hasOwnProperty(token)) {
1100
- fn = operators[token]
1101
- name = token
1061
+ if (operators.hasOwnProperty(state.token)) {
1062
+ fn = operators[state.token]
1063
+ name = state.token
1102
1064
 
1103
- getTokenSkipNewline()
1104
- params = [parseUnary()]
1065
+ getTokenSkipNewline(state)
1066
+ params = [parseUnary(state)]
1105
1067
 
1106
1068
  return new OperatorNode(name, fn, params)
1107
1069
  }
1108
1070
 
1109
- return parsePow()
1071
+ return parsePow(state)
1110
1072
  }
1111
1073
 
1112
1074
  /**
@@ -1115,17 +1077,17 @@ function factory (type, config, load, typed) {
1115
1077
  * @return {Node} node
1116
1078
  * @private
1117
1079
  */
1118
- function parsePow () {
1080
+ function parsePow (state) {
1119
1081
  let node, name, fn, params
1120
1082
 
1121
- node = parseLeftHandOperators()
1083
+ node = parseLeftHandOperators(state)
1122
1084
 
1123
- if (token === '^' || token === '.^') {
1124
- name = token
1085
+ if (state.token === '^' || state.token === '.^') {
1086
+ name = state.token
1125
1087
  fn = (name === '^') ? 'pow' : 'dotPow'
1126
1088
 
1127
- getTokenSkipNewline()
1128
- params = [node, parseUnary()] // Go back to unary, we can have '2^-3'
1089
+ getTokenSkipNewline(state)
1090
+ params = [node, parseUnary(state)] // Go back to unary, we can have '2^-3'
1129
1091
  node = new OperatorNode(name, fn, params)
1130
1092
  }
1131
1093
 
@@ -1137,25 +1099,25 @@ function factory (type, config, load, typed) {
1137
1099
  * @return {Node} node
1138
1100
  * @private
1139
1101
  */
1140
- function parseLeftHandOperators () {
1102
+ function parseLeftHandOperators (state) {
1141
1103
  let node, operators, name, fn, params
1142
1104
 
1143
- node = parseCustomNodes()
1105
+ node = parseCustomNodes(state)
1144
1106
 
1145
1107
  operators = {
1146
1108
  '!': 'factorial',
1147
1109
  '\'': 'ctranspose'
1148
1110
  }
1149
1111
 
1150
- while (operators.hasOwnProperty(token)) {
1151
- name = token
1112
+ while (operators.hasOwnProperty(state.token)) {
1113
+ name = state.token
1152
1114
  fn = operators[name]
1153
1115
 
1154
- getToken()
1116
+ getToken(state)
1155
1117
  params = [node]
1156
1118
 
1157
1119
  node = new OperatorNode(name, fn, params)
1158
- node = parseAccessors(node)
1120
+ node = parseAccessors(state, node)
1159
1121
  }
1160
1122
 
1161
1123
  return node
@@ -1189,36 +1151,36 @@ function factory (type, config, load, typed) {
1189
1151
  * @return {Node} node
1190
1152
  * @private
1191
1153
  */
1192
- function parseCustomNodes () {
1154
+ function parseCustomNodes (state) {
1193
1155
  let params = []
1194
1156
 
1195
- if (tokenType === TOKENTYPE.SYMBOL && extraNodes.hasOwnProperty(token)) {
1196
- const CustomNode = extraNodes[token]
1157
+ if (state.tokenType === TOKENTYPE.SYMBOL && state.extraNodes.hasOwnProperty(state.token)) {
1158
+ const CustomNode = state.extraNodes[state.token]
1197
1159
 
1198
- getToken()
1160
+ getToken(state)
1199
1161
 
1200
1162
  // parse parameters
1201
- if (token === '(') {
1163
+ if (state.token === '(') {
1202
1164
  params = []
1203
1165
 
1204
- openParams()
1205
- getToken()
1166
+ openParams(state)
1167
+ getToken(state)
1206
1168
 
1207
- if (token !== ')') {
1208
- params.push(parseAssignment())
1169
+ if (state.token !== ')') {
1170
+ params.push(parseAssignment(state))
1209
1171
 
1210
1172
  // parse a list with parameters
1211
- while (token === ',') { // eslint-disable-line no-unmodified-loop-condition
1212
- getToken()
1213
- params.push(parseAssignment())
1173
+ while (state.token === ',') { // eslint-disable-line no-unmodified-loop-condition
1174
+ getToken(state)
1175
+ params.push(parseAssignment(state))
1214
1176
  }
1215
1177
  }
1216
1178
 
1217
- if (token !== ')') {
1218
- throw createSyntaxError('Parenthesis ) expected')
1179
+ if (state.token !== ')') {
1180
+ throw createSyntaxError(state, 'Parenthesis ) expected')
1219
1181
  }
1220
- closeParams()
1221
- getToken()
1182
+ closeParams(state)
1183
+ getToken(state)
1222
1184
  }
1223
1185
 
1224
1186
  // create a new custom node
@@ -1226,7 +1188,7 @@ function factory (type, config, load, typed) {
1226
1188
  return new CustomNode(params)
1227
1189
  }
1228
1190
 
1229
- return parseSymbol()
1191
+ return parseSymbol(state)
1230
1192
  }
1231
1193
 
1232
1194
  /**
@@ -1234,14 +1196,14 @@ function factory (type, config, load, typed) {
1234
1196
  * @return {Node} node
1235
1197
  * @private
1236
1198
  */
1237
- function parseSymbol () {
1199
+ function parseSymbol (state) {
1238
1200
  let node, name
1239
1201
 
1240
- if (tokenType === TOKENTYPE.SYMBOL ||
1241
- (tokenType === TOKENTYPE.DELIMITER && token in NAMED_DELIMITERS)) {
1242
- name = token
1202
+ if (state.tokenType === TOKENTYPE.SYMBOL ||
1203
+ (state.tokenType === TOKENTYPE.DELIMITER && state.token in NAMED_DELIMITERS)) {
1204
+ name = state.token
1243
1205
 
1244
- getToken()
1206
+ getToken(state)
1245
1207
 
1246
1208
  if (CONSTANTS.hasOwnProperty(name)) { // true, false, null, ...
1247
1209
  node = new ConstantNode(CONSTANTS[name])
@@ -1252,11 +1214,11 @@ function factory (type, config, load, typed) {
1252
1214
  }
1253
1215
 
1254
1216
  // parse function parameters and matrix index
1255
- node = parseAccessors(node)
1217
+ node = parseAccessors(state, node)
1256
1218
  return node
1257
1219
  }
1258
1220
 
1259
- return parseString()
1221
+ return parseString(state)
1260
1222
  }
1261
1223
 
1262
1224
  /**
@@ -1272,34 +1234,34 @@ function factory (type, config, load, typed) {
1272
1234
  * @return {Node} node
1273
1235
  * @private
1274
1236
  */
1275
- function parseAccessors (node, types) {
1237
+ function parseAccessors (state, node, types) {
1276
1238
  let params
1277
1239
 
1278
- while ((token === '(' || token === '[' || token === '.') &&
1279
- (!types || types.indexOf(token) !== -1)) { // eslint-disable-line no-unmodified-loop-condition
1240
+ while ((state.token === '(' || state.token === '[' || state.token === '.') &&
1241
+ (!types || types.indexOf(state.token) !== -1)) { // eslint-disable-line no-unmodified-loop-condition
1280
1242
  params = []
1281
1243
 
1282
- if (token === '(') {
1244
+ if (state.token === '(') {
1283
1245
  if (type.isSymbolNode(node) || type.isAccessorNode(node)) {
1284
1246
  // function invocation like fn(2, 3) or obj.fn(2, 3)
1285
- openParams()
1286
- getToken()
1247
+ openParams(state)
1248
+ getToken(state)
1287
1249
 
1288
- if (token !== ')') {
1289
- params.push(parseAssignment())
1250
+ if (state.token !== ')') {
1251
+ params.push(parseAssignment(state))
1290
1252
 
1291
1253
  // parse a list with parameters
1292
- while (token === ',') { // eslint-disable-line no-unmodified-loop-condition
1293
- getToken()
1294
- params.push(parseAssignment())
1254
+ while (state.token === ',') { // eslint-disable-line no-unmodified-loop-condition
1255
+ getToken(state)
1256
+ params.push(parseAssignment(state))
1295
1257
  }
1296
1258
  }
1297
1259
 
1298
- if (token !== ')') {
1299
- throw createSyntaxError('Parenthesis ) expected')
1260
+ if (state.token !== ')') {
1261
+ throw createSyntaxError(state, 'Parenthesis ) expected')
1300
1262
  }
1301
- closeParams()
1302
- getToken()
1263
+ closeParams(state)
1264
+ getToken(state)
1303
1265
 
1304
1266
  node = new FunctionNode(node, params)
1305
1267
  } else {
@@ -1308,37 +1270,37 @@ function factory (type, config, load, typed) {
1308
1270
  // with correct precedence
1309
1271
  return node
1310
1272
  }
1311
- } else if (token === '[') {
1273
+ } else if (state.token === '[') {
1312
1274
  // index notation like variable[2, 3]
1313
- openParams()
1314
- getToken()
1275
+ openParams(state)
1276
+ getToken(state)
1315
1277
 
1316
- if (token !== ']') {
1317
- params.push(parseAssignment())
1278
+ if (state.token !== ']') {
1279
+ params.push(parseAssignment(state))
1318
1280
 
1319
1281
  // parse a list with parameters
1320
- while (token === ',') { // eslint-disable-line no-unmodified-loop-condition
1321
- getToken()
1322
- params.push(parseAssignment())
1282
+ while (state.token === ',') { // eslint-disable-line no-unmodified-loop-condition
1283
+ getToken(state)
1284
+ params.push(parseAssignment(state))
1323
1285
  }
1324
1286
  }
1325
1287
 
1326
- if (token !== ']') {
1327
- throw createSyntaxError('Parenthesis ] expected')
1288
+ if (state.token !== ']') {
1289
+ throw createSyntaxError(state, 'Parenthesis ] expected')
1328
1290
  }
1329
- closeParams()
1330
- getToken()
1291
+ closeParams(state)
1292
+ getToken(state)
1331
1293
 
1332
1294
  node = new AccessorNode(node, new IndexNode(params))
1333
1295
  } else {
1334
1296
  // dot notation like variable.prop
1335
- getToken()
1297
+ getToken(state)
1336
1298
 
1337
- if (tokenType !== TOKENTYPE.SYMBOL) {
1338
- throw createSyntaxError('Property name expected after dot')
1299
+ if (state.tokenType !== TOKENTYPE.SYMBOL) {
1300
+ throw createSyntaxError(state, 'Property name expected after dot')
1339
1301
  }
1340
- params.push(new ConstantNode(token))
1341
- getToken()
1302
+ params.push(new ConstantNode(state.token))
1303
+ getToken(state)
1342
1304
 
1343
1305
  const dotNotation = true
1344
1306
  node = new AccessorNode(node, new IndexNode(params, dotNotation))
@@ -1354,48 +1316,48 @@ function factory (type, config, load, typed) {
1354
1316
  * @return {Node} node
1355
1317
  * @private
1356
1318
  */
1357
- function parseString () {
1319
+ function parseString (state) {
1358
1320
  let node, str
1359
1321
 
1360
- if (token === '"') {
1361
- str = parseStringToken()
1322
+ if (state.token === '"') {
1323
+ str = parseStringToken(state)
1362
1324
 
1363
1325
  // create constant
1364
1326
  node = new ConstantNode(str)
1365
1327
 
1366
1328
  // parse index parameters
1367
- node = parseAccessors(node)
1329
+ node = parseAccessors(state, node)
1368
1330
 
1369
1331
  return node
1370
1332
  }
1371
1333
 
1372
- return parseMatrix()
1334
+ return parseMatrix(state)
1373
1335
  }
1374
1336
 
1375
1337
  /**
1376
1338
  * Parse a string surrounded by double quotes "..."
1377
1339
  * @return {string}
1378
1340
  */
1379
- function parseStringToken () {
1341
+ function parseStringToken (state) {
1380
1342
  let str = ''
1381
1343
 
1382
- while (c !== '' && c !== '"') {
1383
- if (c === '\\') {
1344
+ while (currentCharacter(state) !== '' && currentCharacter(state) !== '"') {
1345
+ if (currentCharacter(state) === '\\') {
1384
1346
  // escape character, immediately process the next
1385
1347
  // character to prevent stopping at a next '\"'
1386
- str += c
1387
- next()
1348
+ str += currentCharacter(state)
1349
+ next(state)
1388
1350
  }
1389
1351
 
1390
- str += c
1391
- next()
1352
+ str += currentCharacter(state)
1353
+ next(state)
1392
1354
  }
1393
1355
 
1394
- getToken()
1395
- if (token !== '"') {
1396
- throw createSyntaxError('End of string " expected')
1356
+ getToken(state)
1357
+ if (state.token !== '"') {
1358
+ throw createSyntaxError(state, 'End of string " expected')
1397
1359
  }
1398
- getToken()
1360
+ getToken(state)
1399
1361
 
1400
1362
  return JSON.parse('"' + str + '"') // unescape escaped characters
1401
1363
  }
@@ -1405,42 +1367,42 @@ function factory (type, config, load, typed) {
1405
1367
  * @return {Node} node
1406
1368
  * @private
1407
1369
  */
1408
- function parseMatrix () {
1370
+ function parseMatrix (state) {
1409
1371
  let array, params, rows, cols
1410
1372
 
1411
- if (token === '[') {
1373
+ if (state.token === '[') {
1412
1374
  // matrix [...]
1413
- openParams()
1414
- getToken()
1375
+ openParams(state)
1376
+ getToken(state)
1415
1377
 
1416
- if (token !== ']') {
1378
+ if (state.token !== ']') {
1417
1379
  // this is a non-empty matrix
1418
- const row = parseRow()
1380
+ const row = parseRow(state)
1419
1381
 
1420
- if (token === ';') {
1382
+ if (state.token === ';') {
1421
1383
  // 2 dimensional array
1422
1384
  rows = 1
1423
1385
  params = [row]
1424
1386
 
1425
1387
  // the rows of the matrix are separated by dot-comma's
1426
- while (token === ';') { // eslint-disable-line no-unmodified-loop-condition
1427
- getToken()
1388
+ while (state.token === ';') { // eslint-disable-line no-unmodified-loop-condition
1389
+ getToken(state)
1428
1390
 
1429
- params[rows] = parseRow()
1391
+ params[rows] = parseRow(state)
1430
1392
  rows++
1431
1393
  }
1432
1394
 
1433
- if (token !== ']') {
1434
- throw createSyntaxError('End of matrix ] expected')
1395
+ if (state.token !== ']') {
1396
+ throw createSyntaxError(state, 'End of matrix ] expected')
1435
1397
  }
1436
- closeParams()
1437
- getToken()
1398
+ closeParams(state)
1399
+ getToken(state)
1438
1400
 
1439
1401
  // check if the number of columns matches in all rows
1440
1402
  cols = params[0].items.length
1441
1403
  for (let r = 1; r < rows; r++) {
1442
1404
  if (params[r].items.length !== cols) {
1443
- throw createError('Column dimensions mismatch ' +
1405
+ throw createError(state, 'Column dimensions mismatch ' +
1444
1406
  '(' + params[r].items.length + ' !== ' + cols + ')')
1445
1407
  }
1446
1408
  }
@@ -1448,40 +1410,40 @@ function factory (type, config, load, typed) {
1448
1410
  array = new ArrayNode(params)
1449
1411
  } else {
1450
1412
  // 1 dimensional vector
1451
- if (token !== ']') {
1452
- throw createSyntaxError('End of matrix ] expected')
1413
+ if (state.token !== ']') {
1414
+ throw createSyntaxError(state, 'End of matrix ] expected')
1453
1415
  }
1454
- closeParams()
1455
- getToken()
1416
+ closeParams(state)
1417
+ getToken(state)
1456
1418
 
1457
1419
  array = row
1458
1420
  }
1459
1421
  } else {
1460
1422
  // this is an empty matrix "[ ]"
1461
- closeParams()
1462
- getToken()
1423
+ closeParams(state)
1424
+ getToken(state)
1463
1425
  array = new ArrayNode([])
1464
1426
  }
1465
1427
 
1466
- return parseAccessors(array)
1428
+ return parseAccessors(state, array)
1467
1429
  }
1468
1430
 
1469
- return parseObject()
1431
+ return parseObject(state)
1470
1432
  }
1471
1433
 
1472
1434
  /**
1473
1435
  * Parse a single comma-separated row from a matrix, like 'a, b, c'
1474
1436
  * @return {ArrayNode} node
1475
1437
  */
1476
- function parseRow () {
1477
- const params = [parseAssignment()]
1438
+ function parseRow (state) {
1439
+ const params = [parseAssignment(state)]
1478
1440
  let len = 1
1479
1441
 
1480
- while (token === ',') { // eslint-disable-line no-unmodified-loop-condition
1481
- getToken()
1442
+ while (state.token === ',') { // eslint-disable-line no-unmodified-loop-condition
1443
+ getToken(state)
1482
1444
 
1483
1445
  // parse expression
1484
- params[len] = parseAssignment()
1446
+ params[len] = parseAssignment(state)
1485
1447
  len++
1486
1448
  }
1487
1449
 
@@ -1493,51 +1455,51 @@ function factory (type, config, load, typed) {
1493
1455
  * @return {Node} node
1494
1456
  * @private
1495
1457
  */
1496
- function parseObject () {
1497
- if (token === '{') {
1458
+ function parseObject (state) {
1459
+ if (state.token === '{') {
1498
1460
  let key
1499
1461
 
1500
1462
  const properties = {}
1501
1463
  do {
1502
- getToken()
1464
+ getToken(state)
1503
1465
 
1504
- if (token !== '}') {
1466
+ if (state.token !== '}') {
1505
1467
  // parse key
1506
- if (token === '"') {
1507
- key = parseStringToken()
1508
- } else if (tokenType === TOKENTYPE.SYMBOL) {
1509
- key = token
1510
- getToken()
1468
+ if (state.token === '"') {
1469
+ key = parseStringToken(state)
1470
+ } else if (state.tokenType === TOKENTYPE.SYMBOL) {
1471
+ key = state.token
1472
+ getToken(state)
1511
1473
  } else {
1512
- throw createSyntaxError('Symbol or string expected as object key')
1474
+ throw createSyntaxError(state, 'Symbol or string expected as object key')
1513
1475
  }
1514
1476
 
1515
1477
  // parse key/value separator
1516
- if (token !== ':') {
1517
- throw createSyntaxError('Colon : expected after object key')
1478
+ if (state.token !== ':') {
1479
+ throw createSyntaxError(state, 'Colon : expected after object key')
1518
1480
  }
1519
- getToken()
1481
+ getToken(state)
1520
1482
 
1521
1483
  // parse key
1522
- properties[key] = parseAssignment()
1484
+ properties[key] = parseAssignment(state)
1523
1485
  }
1524
1486
  }
1525
- while (token === ',') // eslint-disable-line no-unmodified-loop-condition
1487
+ while (state.token === ',') // eslint-disable-line no-unmodified-loop-condition
1526
1488
 
1527
- if (token !== '}') {
1528
- throw createSyntaxError('Comma , or bracket } expected after object value')
1489
+ if (state.token !== '}') {
1490
+ throw createSyntaxError(state, 'Comma , or bracket } expected after object value')
1529
1491
  }
1530
- getToken()
1492
+ getToken(state)
1531
1493
 
1532
1494
  let node = new ObjectNode(properties)
1533
1495
 
1534
1496
  // parse index parameters
1535
- node = parseAccessors(node)
1497
+ node = parseAccessors(state, node)
1536
1498
 
1537
1499
  return node
1538
1500
  }
1539
1501
 
1540
- return parseNumber()
1502
+ return parseNumber(state)
1541
1503
  }
1542
1504
 
1543
1505
  /**
@@ -1545,18 +1507,18 @@ function factory (type, config, load, typed) {
1545
1507
  * @return {Node} node
1546
1508
  * @private
1547
1509
  */
1548
- function parseNumber () {
1510
+ function parseNumber (state) {
1549
1511
  let numberStr
1550
1512
 
1551
- if (tokenType === TOKENTYPE.NUMBER) {
1513
+ if (state.tokenType === TOKENTYPE.NUMBER) {
1552
1514
  // this is a number
1553
- numberStr = token
1554
- getToken()
1515
+ numberStr = state.token
1516
+ getToken(state)
1555
1517
 
1556
1518
  return new ConstantNode(numeric(numberStr, config.number))
1557
1519
  }
1558
1520
 
1559
- return parseParentheses()
1521
+ return parseParentheses(state)
1560
1522
  }
1561
1523
 
1562
1524
  /**
@@ -1564,29 +1526,29 @@ function factory (type, config, load, typed) {
1564
1526
  * @return {Node} node
1565
1527
  * @private
1566
1528
  */
1567
- function parseParentheses () {
1529
+ function parseParentheses (state) {
1568
1530
  let node
1569
1531
 
1570
1532
  // check if it is a parenthesized expression
1571
- if (token === '(') {
1533
+ if (state.token === '(') {
1572
1534
  // parentheses (...)
1573
- openParams()
1574
- getToken()
1535
+ openParams(state)
1536
+ getToken(state)
1575
1537
 
1576
- node = parseAssignment() // start again
1538
+ node = parseAssignment(state) // start again
1577
1539
 
1578
- if (token !== ')') {
1579
- throw createSyntaxError('Parenthesis ) expected')
1540
+ if (state.token !== ')') {
1541
+ throw createSyntaxError(state, 'Parenthesis ) expected')
1580
1542
  }
1581
- closeParams()
1582
- getToken()
1543
+ closeParams(state)
1544
+ getToken(state)
1583
1545
 
1584
1546
  node = new ParenthesisNode(node)
1585
- node = parseAccessors(node)
1547
+ node = parseAccessors(state, node)
1586
1548
  return node
1587
1549
  }
1588
1550
 
1589
- return parseEnd()
1551
+ return parseEnd(state)
1590
1552
  }
1591
1553
 
1592
1554
  /**
@@ -1594,14 +1556,14 @@ function factory (type, config, load, typed) {
1594
1556
  * @return {Node} res
1595
1557
  * @private
1596
1558
  */
1597
- function parseEnd () {
1598
- if (token === '') {
1559
+ function parseEnd (state) {
1560
+ if (state.token === '') {
1599
1561
  // syntax error or unexpected end of expression
1600
- throw createSyntaxError('Unexpected end of expression')
1601
- } else if (token === "'") {
1602
- throw createSyntaxError('Value expected. Note: strings must be enclosed by double quotes')
1562
+ throw createSyntaxError(state, 'Unexpected end of expression')
1563
+ } else if (state.token === "'") {
1564
+ throw createSyntaxError(state, 'Value expected. Note: strings must be enclosed by double quotes')
1603
1565
  } else {
1604
- throw createSyntaxError('Value expected')
1566
+ throw createSyntaxError(state, 'Value expected')
1605
1567
  }
1606
1568
  }
1607
1569
 
@@ -1618,11 +1580,11 @@ function factory (type, config, load, typed) {
1618
1580
 
1619
1581
  /**
1620
1582
  * Shortcut for getting the current col value (one based)
1621
- * Returns the column (position) where the last token starts
1583
+ * Returns the column (position) where the last state.token starts
1622
1584
  * @private
1623
1585
  */
1624
- function col () {
1625
- return index - token.length + 1
1586
+ function col (state) {
1587
+ return state.index - state.token.length + 1
1626
1588
  }
1627
1589
 
1628
1590
  /**
@@ -1631,8 +1593,8 @@ function factory (type, config, load, typed) {
1631
1593
  * @return {SyntaxError} instantiated error
1632
1594
  * @private
1633
1595
  */
1634
- function createSyntaxError (message) {
1635
- const c = col()
1596
+ function createSyntaxError (state, message) {
1597
+ const c = col(state)
1636
1598
  const error = new SyntaxError(message + ' (char ' + c + ')')
1637
1599
  error['char'] = c
1638
1600
 
@@ -1645,8 +1607,8 @@ function factory (type, config, load, typed) {
1645
1607
  * @return {Error} instantiated error
1646
1608
  * @private
1647
1609
  */
1648
- function createError (message) {
1649
- const c = col()
1610
+ function createError (state, message) {
1611
+ const c = col(state)
1650
1612
  const error = new SyntaxError(message + ' (char ' + c + ')')
1651
1613
  error['char'] = c
1652
1614