fable 3.0.132 → 3.0.134
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/debug/Harness.js +27 -36
- package/dist/fable.compatible.js +336 -165
- package/dist/fable.compatible.min.js +2 -2
- package/dist/fable.compatible.min.js.map +1 -1
- package/dist/fable.js +277 -106
- package/dist/fable.min.js +2 -2
- package/dist/fable.min.js.map +1 -1
- package/example_applications/data/Fruit-Data.json +694 -0
- package/example_applications/data/Fruit-Manyfest.json +56 -0
- package/example_applications/mathematical_playground/AppData.json +8 -0
- package/example_applications/mathematical_playground/Equations.json +12 -0
- package/example_applications/mathematical_playground/Math-Solver-Harness.js +89 -0
- package/package.json +3 -3
- package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-FunctionMap.json +80 -20
- package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-Postfix.js +218 -200
- package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-SolvePostfixedExpression.js +11 -1
- package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-TokenMap.json +1 -0
- package/source/services/Fable-Service-ExpressionParser.js +22 -3
- package/source/services/Fable-Service-Math.js +570 -19
- package/test/ExpressionParser_tests.js +20 -1
- package/test/Math_test.js +54 -3
- package/test/data/chocodata.json +248 -0
package/source/services/Fable-Service-ExpressionParser/Fable-Service-ExpressionParser-Postfix.js
CHANGED
|
@@ -20,28 +20,6 @@ class ExpressionParserPostfix extends libExpressionParserOperationBase
|
|
|
20
20
|
|
|
21
21
|
let tmpDepthSolveList = Array.isArray(pDepthSolveList) ? pDepthSolveList : false;
|
|
22
22
|
|
|
23
|
-
// // Although we have a `Token.Type == "Parenthesis"` option to check on, keeping these explicit means the solver won't
|
|
24
|
-
// // allow users to pass in parenthesis in the wrong order.
|
|
25
|
-
// // The linter does blow up as does the postfix, but, just in case we'll leave these explicit.
|
|
26
|
-
// // It really doesn't hurt anything.
|
|
27
|
-
// if (pLeftValue.Token === ')')
|
|
28
|
-
// {
|
|
29
|
-
// // We have found a close parenthesis which needs to pull the proper virtual symbol for the last operation on this stack.
|
|
30
|
-
// // This ensures we are not expressing the parenthesis virtual symbols to the solver.
|
|
31
|
-
// pLeftValue.VirtualSymbolName = pLayerStackMap[pLeftValue.SolveLayerStack];
|
|
32
|
-
// this.log.error(`ERROR: ExpressionParser.getPosfixSolveListOperation found a close parenthesis in the left value of an operation.`);
|
|
33
|
-
// }
|
|
34
|
-
// else if (pRightValue.Token === '(')
|
|
35
|
-
// {
|
|
36
|
-
// // We have found a close parenthesis which needs to pull the proper virtual symbol for the last operation on this stack.
|
|
37
|
-
// // This ensures we are not expressing the parenthesis virtual symbols to the solver.
|
|
38
|
-
// pRightValue.VirtualSymbolName = pLayerStackMap[pRightValue.SolveLayerStack];
|
|
39
|
-
// this.log.error(`ERROR: ExpressionParser.getPosfixSolveListOperation found a close parenthesis in the left value of an operation.`);
|
|
40
|
-
// }
|
|
41
|
-
|
|
42
|
-
// // Set the layer stack map virtual symbol name to the last operation performed on this stack.
|
|
43
|
-
// pLayerStackMap[pOperation.SolveLayerStack] = pOperation.VirtualSymbolName;
|
|
44
|
-
|
|
45
23
|
/* These two if blocks are very complex -- they basically provide a
|
|
46
24
|
* way to deal with recursion that can be expressed to the user in
|
|
47
25
|
* a meaningful way.
|
|
@@ -56,27 +34,13 @@ class ExpressionParserPostfix extends libExpressionParserOperationBase
|
|
|
56
34
|
else
|
|
57
35
|
{
|
|
58
36
|
// We need to set the left value to a virtual symbol instead of the looked up value if it's already used in another operation
|
|
59
|
-
|
|
60
|
-
// Now walk backwards and see if we need to update a previous symbol for a previously unparsed operator
|
|
61
|
-
if (tmpDepthSolveList)
|
|
37
|
+
if ('LeftVirtualSymbolName' in tmpOperation.Operation)
|
|
62
38
|
{
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
// Anything >3 does not have commutative properties
|
|
69
|
-
(tmpDepthSolveList[i].Descriptor.Precedence > 3))
|
|
70
|
-
{
|
|
71
|
-
// If the symbol to its right is not the same as this operation
|
|
72
|
-
if (tmpDepthSolveList[i+1].VirtualSymbolName !== tmpOperation.VirtualSymbolName)
|
|
73
|
-
{
|
|
74
|
-
// This is the recursive "shunting" being simulated
|
|
75
|
-
tmpDepthSolveList[i+1].VirtualSymbolName = tmpOperation.VirtualSymbolName;
|
|
76
|
-
}
|
|
77
|
-
break;
|
|
78
|
-
}
|
|
79
|
-
}
|
|
39
|
+
tmpOperation.LeftValue = this.getTokenContainerObject(tmpOperation.Operation.LeftVirtualSymbolName, 'Token.VirtualSymbol');
|
|
40
|
+
}
|
|
41
|
+
else
|
|
42
|
+
{
|
|
43
|
+
tmpOperation.LeftValue = this.getTokenContainerObject(tmpOperation.LeftValue.VirtualSymbolName, 'Token.VirtualSymbol');
|
|
80
44
|
}
|
|
81
45
|
}
|
|
82
46
|
if (!tmpOperation.RightValue.VirtualSymbolName)
|
|
@@ -86,31 +50,14 @@ class ExpressionParserPostfix extends libExpressionParserOperationBase
|
|
|
86
50
|
else
|
|
87
51
|
{
|
|
88
52
|
// We need to set the right value to a virtual symbol instead of the looked up value if it's already used in another operation
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
if (tmpDepthSolveList)
|
|
53
|
+
//if ('LeftVirtualSymbolName' in tmpOperation.RightValue)
|
|
54
|
+
if ('RightVirtualSymbolName' in tmpOperation.Operation)
|
|
92
55
|
{
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
// Anything >3 does not have commutative properties
|
|
99
|
-
(tmpDepthSolveList[i].Descriptor.Precedence > 3))
|
|
100
|
-
{
|
|
101
|
-
// If the symbol to its right is not the same as this operation
|
|
102
|
-
if (tmpDepthSolveList[i-1].VirtualSymbolName !== tmpOperation.VirtualSymbolName)
|
|
103
|
-
{
|
|
104
|
-
// This is the recursive "shunting" being simulated
|
|
105
|
-
tmpDepthSolveList[i-1].VirtualSymbolName = tmpOperation.VirtualSymbolName;
|
|
106
|
-
}
|
|
107
|
-
break;
|
|
108
|
-
}
|
|
109
|
-
else if ((tmpDepthSolveList[i].Type === 'Token.Operator') && (!tmpDepthSolveList[i].Parsed))
|
|
110
|
-
{
|
|
111
|
-
break;
|
|
112
|
-
}
|
|
113
|
-
}
|
|
56
|
+
tmpOperation.RightValue = this.getTokenContainerObject(tmpOperation.Operation.RightVirtualSymbolName, 'Token.VirtualSymbol');
|
|
57
|
+
}
|
|
58
|
+
else
|
|
59
|
+
{
|
|
60
|
+
tmpOperation.RightValue = this.getTokenContainerObject(tmpOperation.RightValue.VirtualSymbolName, 'Token.VirtualSymbol');
|
|
114
61
|
}
|
|
115
62
|
}
|
|
116
63
|
|
|
@@ -204,11 +151,6 @@ class ExpressionParserPostfix extends libExpressionParserOperationBase
|
|
|
204
151
|
{
|
|
205
152
|
// Set the type of this to be a function
|
|
206
153
|
tmpResults.PostfixTokenObjects[i-1].Type = 'Token.Function';
|
|
207
|
-
// tmpResults.PostfixTokenObjects[i-1].Descriptor = this.ExpressionParser.tokenMap[pTokenizedExpression[i-1]];
|
|
208
|
-
// Rename the virtual symbol n ame to include the function
|
|
209
|
-
// tmpResults.PostfixTokenObjects[i].VirtualSymbolName = `Fn_${tmpVirtualParenthesisIndex}_D_${tmpDepth}_${this.fable.DataFormat.cleanNonAlphaCharacters(tmpResults.PostfixTokenObjects[i-1].Token)}`;
|
|
210
|
-
// The function and the parenthesis are at the same depth and virtual symbol
|
|
211
|
-
// tmpResults.PostfixTokenObjects[i-1].VirtualSymbolName = tmpResults.PostfixTokenObjects[i].VirtualSymbolName;
|
|
212
154
|
}
|
|
213
155
|
}
|
|
214
156
|
|
|
@@ -242,24 +184,6 @@ class ExpressionParserPostfix extends libExpressionParserOperationBase
|
|
|
242
184
|
tmpResults.PostfixTokenObjects[i].VirtualSymbolName = tmpSolveLayerStack.pop();
|
|
243
185
|
tmpResults.PostfixTokenObjects[i].SolveLayerStack = tmpSolveLayerStack[tmpSolveLayerStack.length-1];
|
|
244
186
|
}
|
|
245
|
-
|
|
246
|
-
// 3. If it's a state address or Symbol, set depth
|
|
247
|
-
// It was much more complex later on solving these as virtual symbols of their own.
|
|
248
|
-
// We are saving the value resolution for the very end.
|
|
249
|
-
else if ((tmpResults.PostfixTokenObjects[i].Type === 'Token.Symbol'))
|
|
250
|
-
{
|
|
251
|
-
// Set the depth of the current solution depth
|
|
252
|
-
tmpResults.PostfixTokenObjects[i].Depth = tmpDepth;
|
|
253
|
-
tmpResults.PostfixTokenObjects[i].SolveLayerStack = tmpSolveLayerStack[tmpSolveLayerStack.length-1];
|
|
254
|
-
// Generate a virtual symbol name that's somewhat human readable
|
|
255
|
-
//tmpResults.PostfixTokenObjects[i].VirtualSymbolName = `Sm_${tmpVirtualParenthesisIndex}_D_${tmpDepth}_${this.fable.DataFormat.cleanNonAlphaCharacters(tmpResults.PostfixTokenObjects[i].Token)}`;
|
|
256
|
-
|
|
257
|
-
// We've used up this virtual symbol index so increment it
|
|
258
|
-
// The reason we only use these once is to make sure if we use, say, sin(x) twice at the same depth we still have unique names for each virtual solution
|
|
259
|
-
//tmpVirtualParenthesisIndex++;
|
|
260
|
-
}
|
|
261
|
-
|
|
262
|
-
// 4. If it's an operator or constant or comment, just set the depth
|
|
263
187
|
else
|
|
264
188
|
{
|
|
265
189
|
tmpResults.PostfixTokenObjects[i].Depth = tmpDepth;
|
|
@@ -356,7 +280,7 @@ class ExpressionParserPostfix extends libExpressionParserOperationBase
|
|
|
356
280
|
// The - at the beginning of an expression is a number line orientation modifier
|
|
357
281
|
else if ((i == 0) && (tmpToken.Token == '-'))
|
|
358
282
|
{
|
|
359
|
-
tmpToken.VirtualSymbolName = `
|
|
283
|
+
tmpToken.VirtualSymbolName = `VNLO_${tmpVirtualSymbolIndex}`;
|
|
360
284
|
tmpResults.PostfixLayerstackMap[tmpToken.SolveLayerStack] = tmpToken.VirtualSymbolName;
|
|
361
285
|
tmpVirtualSymbolIndex++;
|
|
362
286
|
}
|
|
@@ -364,7 +288,7 @@ class ExpressionParserPostfix extends libExpressionParserOperationBase
|
|
|
364
288
|
else if ((i > 0) && (tmpToken.Token == '-') && ((tmpSolveLayerTokens[i-1].Type === 'Token.Operator') || (tmpSolveLayerTokens[i-1].Token === '(')))
|
|
365
289
|
{
|
|
366
290
|
// The number line negation operator is a special case that generates a virtual constant (-1.0) and multiplies it by the next token
|
|
367
|
-
tmpToken.VirtualSymbolName = `
|
|
291
|
+
tmpToken.VirtualSymbolName = `VNLO_${tmpVirtualSymbolIndex}`;
|
|
368
292
|
tmpVirtualSymbolIndex++;
|
|
369
293
|
}
|
|
370
294
|
// The + at the beginning is also a number line orientation modifier ... THAT WE IGNORE
|
|
@@ -397,7 +321,7 @@ class ExpressionParserPostfix extends libExpressionParserOperationBase
|
|
|
397
321
|
else if ((tmpSolveLayerTokens[i].Type === 'Token.Function') && (tmpPrecedence === 0))
|
|
398
322
|
{
|
|
399
323
|
let tmpToken = tmpSolveLayerTokens[i];
|
|
400
|
-
tmpToken.VirtualSymbolName = `
|
|
324
|
+
tmpToken.VirtualSymbolName = `VFE_${tmpVirtualSymbolIndex}`;
|
|
401
325
|
tmpVirtualSymbolIndex++;
|
|
402
326
|
tmpResults.PostfixLayerstackMap[tmpToken.SolveLayerStack] = tmpToken.VirtualSymbolName;
|
|
403
327
|
}
|
|
@@ -405,156 +329,230 @@ class ExpressionParserPostfix extends libExpressionParserOperationBase
|
|
|
405
329
|
}
|
|
406
330
|
}
|
|
407
331
|
|
|
408
|
-
// 5.
|
|
332
|
+
// 5.15 Generate Virtual Symbol Clusters for Functions and Parenthesis
|
|
409
333
|
// ... this gets funny because of precedence of operations surrounding them, parenthesis and functions.
|
|
410
|
-
let
|
|
334
|
+
let tmpFunctionCacheLIFOStack = [];
|
|
411
335
|
for (let i = 0; i < tmpResults.PostfixTokenObjects.length; i++)
|
|
412
336
|
{
|
|
413
337
|
let tmpPostfixTokenObject = tmpResults.PostfixTokenObjects[i];
|
|
414
338
|
|
|
415
339
|
if (tmpPostfixTokenObject.Type === 'Token.Parenthesis')
|
|
416
340
|
{
|
|
417
|
-
// This is just to track the parenthesis stack level
|
|
341
|
+
// This is just to track the parenthesis stack level for User feedback
|
|
418
342
|
tmpPostfixTokenObject.ParenthesisStack = tmpPostfixTokenObject.VirtualSymbolName;
|
|
419
343
|
|
|
420
|
-
|
|
344
|
+
// At the beginning of the expression, this must be an open parenthesis to be legal.
|
|
345
|
+
if (i == 0)
|
|
421
346
|
{
|
|
422
|
-
|
|
423
|
-
|
|
347
|
+
tmpPostfixTokenObject.IsFunction = false;
|
|
348
|
+
let tmpVirtualSymbolName = tmpResults.PostfixLayerstackMap[tmpPostfixTokenObject.VirtualSymbolName];
|
|
349
|
+
if (!tmpVirtualSymbolName)
|
|
424
350
|
{
|
|
425
|
-
|
|
426
|
-
{
|
|
427
|
-
|
|
428
|
-
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
351
|
+
// ... this parenthesis group has no operators in it; make a virtual symbol name.
|
|
352
|
+
tmpVirtualSymbolName = `VP_${tmpVirtualSymbolIndex}`;
|
|
353
|
+
tmpVirtualSymbolIndex++;
|
|
354
|
+
}
|
|
355
|
+
tmpPostfixTokenObject.VirtualSymbolName = tmpVirtualSymbolName;
|
|
356
|
+
tmpFunctionCacheLIFOStack.push(tmpPostfixTokenObject);
|
|
357
|
+
}
|
|
358
|
+
// If it's an open parenthesis
|
|
359
|
+
else if (tmpPostfixTokenObject.Token === '(')
|
|
360
|
+
{
|
|
361
|
+
// ... supporting a function
|
|
362
|
+
if (tmpResults.PostfixTokenObjects[i-1].Type === 'Token.Function')
|
|
363
|
+
{
|
|
364
|
+
tmpPostfixTokenObject.IsFunction = true;
|
|
365
|
+
tmpPostfixTokenObject.Function = tmpResults.PostfixTokenObjects[i-1];
|
|
366
|
+
let tmpVirtualSymbolName = tmpResults.PostfixLayerstackMap[tmpPostfixTokenObject.VirtualSymbolName];
|
|
367
|
+
if (!tmpVirtualSymbolName)
|
|
434
368
|
{
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
let tmpVirtualSymbolName = tmpResults.PostfixLayerstackMap[tmpPostfixTokenObject.VirtualSymbolName];
|
|
439
|
-
if (!tmpVirtualSymbolName)
|
|
440
|
-
{
|
|
441
|
-
// This is a parenthesis group with no operators in it; make a virtual symbol name.
|
|
442
|
-
tmpVirtualSymbolName = `V_${tmpVirtualSymbolIndex}`;
|
|
443
|
-
tmpVirtualSymbolIndex++;
|
|
444
|
-
}
|
|
445
|
-
tmpPostfixTokenObject.VirtualSymbolName = tmpVirtualSymbolName;
|
|
446
|
-
|
|
447
|
-
if (i > 1)
|
|
448
|
-
{
|
|
449
|
-
// Todo: This needs to be enhanced to deal with negations
|
|
450
|
-
let tmpTokenBeforeFunction = tmpResults.PostfixTokenObjects[i-2];
|
|
451
|
-
if (tmpTokenBeforeFunction.Type === 'Token.Operator')
|
|
452
|
-
{
|
|
453
|
-
tmpPostfixTokenObject.PreviousVirtualSymbolName = tmpResults.PostfixTokenObjects[i-2].VirtualSymbolName;
|
|
454
|
-
tmpPostfixTokenObject.PreviousPrecedence = tmpResults.PostfixTokenObjects[i-2].Descriptor.Precedence;
|
|
455
|
-
}
|
|
456
|
-
}
|
|
369
|
+
// ... this parenthesis group has no operators in it; make a virtual symbol name.
|
|
370
|
+
tmpVirtualSymbolName = `VFP_${tmpVirtualSymbolIndex}`;
|
|
371
|
+
tmpVirtualSymbolIndex++;
|
|
457
372
|
}
|
|
373
|
+
tmpPostfixTokenObject.VirtualSymbolName = tmpVirtualSymbolName;
|
|
458
374
|
}
|
|
459
375
|
else
|
|
460
376
|
{
|
|
461
|
-
tmpPostfixTokenObject.
|
|
377
|
+
tmpPostfixTokenObject.IsFunction = false;
|
|
378
|
+
let tmpVirtualSymbolName = tmpResults.PostfixLayerstackMap[tmpPostfixTokenObject.VirtualSymbolName];
|
|
379
|
+
if (!tmpVirtualSymbolName)
|
|
380
|
+
{
|
|
381
|
+
// This is a parenthesis group with no operators in it; make a virtual symbol name.
|
|
382
|
+
tmpVirtualSymbolName = `VP_${tmpVirtualSymbolIndex}`;
|
|
383
|
+
tmpVirtualSymbolIndex++;
|
|
384
|
+
}
|
|
385
|
+
tmpPostfixTokenObject.VirtualSymbolName = tmpVirtualSymbolName;
|
|
462
386
|
}
|
|
463
|
-
|
|
387
|
+
tmpFunctionCacheLIFOStack.push(tmpPostfixTokenObject);
|
|
464
388
|
}
|
|
465
389
|
if (tmpPostfixTokenObject.Token === ')')
|
|
466
390
|
{
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
// It's at the end of the tokens -- use the stack's identifier
|
|
470
|
-
if (i >= tmpResults.PostfixTokenObjects.length - 1)
|
|
391
|
+
let tmpOpenParenthesis = tmpFunctionCacheLIFOStack.pop();
|
|
392
|
+
if (tmpOpenParenthesis.IsFunction)
|
|
471
393
|
{
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
tmpPostfixTokenObject.VirtualSymbolName = tmpOpenParenthesis.PreviousVirtualSymbolName;
|
|
475
|
-
}
|
|
476
|
-
else
|
|
477
|
-
{
|
|
478
|
-
tmpPostfixTokenObject.VirtualSymbolName = tmpOpenParenthesis.VirtualSymbolName;
|
|
479
|
-
}
|
|
394
|
+
tmpPostfixTokenObject.IsFunction = true;
|
|
395
|
+
tmpPostfixTokenObject.VirtualSymbolName = tmpOpenParenthesis.Function.VirtualSymbolName;
|
|
480
396
|
}
|
|
481
397
|
else
|
|
482
398
|
{
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
399
|
+
tmpPostfixTokenObject.IsFunction = false;
|
|
400
|
+
tmpPostfixTokenObject.VirtualSymbolName = tmpOpenParenthesis.VirtualSymbolName
|
|
401
|
+
}
|
|
402
|
+
}
|
|
403
|
+
}
|
|
404
|
+
}
|
|
405
|
+
|
|
406
|
+
// X. Postprocess the parenthesis groups to ensure they respect the order of operations for their boundaries
|
|
407
|
+
for (let tmpSolveLayerIndex = 0; tmpSolveLayerIndex < tmpSolveLayerKeys.length; tmpSolveLayerIndex++)
|
|
408
|
+
{
|
|
409
|
+
let tmpParenthesisStack = [];
|
|
410
|
+
let tmpLastOperator = false;
|
|
491
411
|
|
|
492
|
-
|
|
412
|
+
let tmpSolveLayerTokens = tmpSolveLayerMap[tmpSolveLayerKeys[tmpSolveLayerIndex]];
|
|
413
|
+
for (let i = 0; i < tmpSolveLayerTokens.length; i++)
|
|
414
|
+
{
|
|
415
|
+
let tmpPostfixTokenObject = tmpSolveLayerTokens[i];
|
|
493
416
|
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
|
|
497
|
-
|
|
498
|
-
|
|
499
|
-
|
|
500
|
-
|
|
501
|
-
|
|
417
|
+
// Keep track of the last operator
|
|
418
|
+
if (tmpPostfixTokenObject.Type === 'Token.Operator')
|
|
419
|
+
{
|
|
420
|
+
tmpLastOperator = tmpPostfixTokenObject;
|
|
421
|
+
}
|
|
422
|
+
|
|
423
|
+
// This is only important to do at the close parenthesis.
|
|
424
|
+
if (tmpPostfixTokenObject.Type === 'Token.Function')
|
|
425
|
+
{
|
|
426
|
+
tmpPostfixTokenObject.PreviousOperator = tmpLastOperator;
|
|
427
|
+
}
|
|
428
|
+
else if ((tmpPostfixTokenObject.Type === 'Token.Parenthesis') && (tmpPostfixTokenObject.Token === '(') && tmpPostfixTokenObject.IsFunction)
|
|
429
|
+
{
|
|
430
|
+
tmpParenthesisStack.push(tmpPostfixTokenObject);
|
|
431
|
+
if (tmpPostfixTokenObject.Function.PreviousOperator)
|
|
432
|
+
{
|
|
433
|
+
tmpPostfixTokenObject.PreviousOperator = tmpPostfixTokenObject.Function.PreviousOperator;
|
|
434
|
+
}
|
|
435
|
+
}
|
|
436
|
+
else if ((tmpPostfixTokenObject.Type === 'Token.Parenthesis') && (tmpPostfixTokenObject.Token === '('))
|
|
437
|
+
{
|
|
438
|
+
tmpPostfixTokenObject.PreviousOperator = tmpLastOperator;
|
|
439
|
+
tmpParenthesisStack.push(tmpPostfixTokenObject);
|
|
440
|
+
}
|
|
441
|
+
else if ((tmpPostfixTokenObject.Type === 'Token.Parenthesis') && (tmpPostfixTokenObject.Token === ')'))
|
|
442
|
+
{
|
|
443
|
+
// This is ultra complex, and binds the order of operations logic to the open parenthesis for the group
|
|
444
|
+
let tmpOpenParenthesis = tmpParenthesisStack.pop();
|
|
445
|
+
if (i < tmpSolveLayerTokens.length - 1)
|
|
446
|
+
{
|
|
447
|
+
for (let j = i + 1; j < tmpSolveLayerTokens.length; j++)
|
|
448
|
+
{
|
|
449
|
+
if (tmpSolveLayerTokens[j].Type === 'Token.Operator')
|
|
502
450
|
{
|
|
503
|
-
|
|
451
|
+
tmpOpenParenthesis.NextOperator = tmpSolveLayerTokens[j];
|
|
452
|
+
break;
|
|
504
453
|
}
|
|
505
454
|
}
|
|
506
|
-
|
|
507
|
-
|
|
455
|
+
}
|
|
456
|
+
if (tmpOpenParenthesis.PreviousOperator && tmpOpenParenthesis.NextOperator)
|
|
457
|
+
{
|
|
458
|
+
if (tmpOpenParenthesis.PreviousOperator.Descriptor.Precedence <= tmpOpenParenthesis.NextOperator.Descriptor.Precedence)
|
|
508
459
|
{
|
|
509
|
-
|
|
510
|
-
// If the operater is at the same precedence or higher than the open parenthesis previous operator, use the previous operator's identifier
|
|
511
|
-
// NOTE: This line of code is insanely complex
|
|
512
|
-
if (tmpPeekedNextToken.Descriptor.Precedence <= tmpOpenParenthesis.PreviousPrecedence)
|
|
513
|
-
{
|
|
514
|
-
tmpPostfixTokenObject.VirtualSymbolName = tmpOpenParenthesis.PreviousVirtualSymbolName;
|
|
515
|
-
}
|
|
516
|
-
// Otherwise use this one -- it is the higher precedence. And update the previous parenthesis operator's virtual symbol to be the peeked token's virtual symbol.
|
|
517
|
-
else
|
|
518
|
-
{
|
|
519
|
-
tmpPostfixTokenObject.VirtualSymbolName = tmpResults.PostfixLayerstackMap[tmpPostfixTokenObject.VirtualSymbolName];
|
|
520
|
-
tmpOpenParenthesis.VirtualSymbolName = tmpPeekedNextToken.VirtualSymbolName;
|
|
521
|
-
}
|
|
460
|
+
tmpOpenParenthesis.NextOperator.LeftVirtualSymbolName = tmpOpenParenthesis.PreviousOperator.VirtualSymbolName;
|
|
522
461
|
}
|
|
523
462
|
else
|
|
524
463
|
{
|
|
525
|
-
|
|
526
|
-
if (tmpOpenParenthesis.IsFunction)
|
|
527
|
-
{
|
|
528
|
-
tmpPostfixTokenObject.VirtualSymbolName = tmpOpenParenthesis.PreviousVirtualSymbolName;
|
|
529
|
-
}
|
|
530
|
-
else
|
|
531
|
-
{
|
|
532
|
-
tmpPostfixTokenObject.VirtualSymbolName = tmpResults.PostfixLayerstackMap[tmpPostfixTokenObject.VirtualSymbolName];
|
|
533
|
-
}
|
|
464
|
+
tmpOpenParenthesis.PreviousOperator.RightVirtualSymbolName = tmpOpenParenthesis.NextOperator.VirtualSymbolName;
|
|
534
465
|
}
|
|
535
466
|
}
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
467
|
+
}
|
|
468
|
+
else
|
|
469
|
+
{
|
|
470
|
+
if (!('SolveLayerStack' in tmpPostfixTokenObject))
|
|
539
471
|
{
|
|
540
|
-
|
|
472
|
+
// Decorate the solve layer stack for the token
|
|
473
|
+
if (tmpParenthesisStack.length > 0)
|
|
474
|
+
{
|
|
475
|
+
tmpPostfixTokenObject.SolveLayerStack = tmpParenthesisStack[tmpParenthesisStack.length-1].SolveLayerStack;
|
|
476
|
+
}
|
|
477
|
+
else
|
|
478
|
+
{
|
|
479
|
+
tmpPostfixTokenObject.SolveLayerStack = 'Expression_Root';
|
|
480
|
+
}
|
|
541
481
|
}
|
|
542
482
|
}
|
|
543
483
|
}
|
|
544
484
|
}
|
|
545
485
|
|
|
486
|
+
// 5.2.9: Make sure the affinity of operators is respecting order of operations.
|
|
487
|
+
// Walk backwards and forwards, hoisting same value precedence backwards/forwards
|
|
488
|
+
// across each layer... the precedence change needs to be decreasing to matter
|
|
546
489
|
for (let tmpSolveLayerIndex = 0; tmpSolveLayerIndex < tmpSolveLayerKeys.length; tmpSolveLayerIndex++)
|
|
547
490
|
{
|
|
491
|
+
let tmpLastPrecedence = false;
|
|
492
|
+
let tmpFinalChainToken = false;
|
|
548
493
|
let tmpSolveLayerTokens = tmpSolveLayerMap[tmpSolveLayerKeys[tmpSolveLayerIndex]];
|
|
549
494
|
|
|
550
|
-
|
|
495
|
+
for (let i = tmpSolveLayerTokens.length-1; i >= 0; i--)
|
|
496
|
+
{
|
|
497
|
+
let tmpToken = tmpSolveLayerTokens[i];
|
|
498
|
+
|
|
499
|
+
if (tmpToken.Type === 'Token.Operator')
|
|
500
|
+
{
|
|
501
|
+
if (!tmpFinalChainToken)
|
|
502
|
+
{
|
|
503
|
+
tmpFinalChainToken = tmpToken;
|
|
504
|
+
}
|
|
505
|
+
else if (tmpToken.Descriptor.Precedence > tmpLastPrecedence)
|
|
506
|
+
{
|
|
507
|
+
// This is less imporant than the last precedence, so hoist back the virtual value
|
|
508
|
+
tmpToken.RightVirtualSymbolName = tmpFinalChainToken.VirtualSymbolName;
|
|
509
|
+
//console.log(`Hoisting ${tmpToken.Token} back to ${tmpFinalChainToken.Token}`);
|
|
510
|
+
tmpFinalChainToken = tmpToken;
|
|
511
|
+
}
|
|
512
|
+
else if (tmpToken.Descriptor.Precedence < tmpLastPrecedence)
|
|
513
|
+
{
|
|
514
|
+
tmpFinalChainToken = tmpToken;
|
|
515
|
+
}
|
|
516
|
+
tmpLastPrecedence = tmpToken.Descriptor.Precedence;
|
|
517
|
+
}
|
|
518
|
+
}
|
|
519
|
+
let tmpDecreasingPrecedenceStack = [];
|
|
520
|
+
let tmpLastToken = false;
|
|
521
|
+
for (let i = tmpSolveLayerTokens.length-1; i >= 0; i--)
|
|
551
522
|
{
|
|
552
|
-
|
|
553
|
-
|
|
554
|
-
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
523
|
+
let tmpToken = tmpSolveLayerTokens[i];
|
|
524
|
+
|
|
525
|
+
if (tmpToken.Type === 'Token.Operator')
|
|
526
|
+
{
|
|
527
|
+
if (!tmpLastToken)
|
|
528
|
+
{
|
|
529
|
+
tmpLastToken = tmpToken;
|
|
530
|
+
}
|
|
531
|
+
else if (tmpToken.Descriptor.Precedence > tmpLastPrecedence)
|
|
532
|
+
{
|
|
533
|
+
// Check and see if this needs to be resolved in the stack
|
|
534
|
+
if (tmpDecreasingPrecedenceStack.length > 0)
|
|
535
|
+
{
|
|
536
|
+
for (let j = tmpDecreasingPrecedenceStack.length-1; j >= 0; j--)
|
|
537
|
+
{
|
|
538
|
+
if (tmpDecreasingPrecedenceStack[j].Descriptor.Precedence >= tmpToken.Descriptor.Precedence)
|
|
539
|
+
{
|
|
540
|
+
//console.log(`Hoisting ${tmpDecreasingPrecedenceStack[j].Token} up to ${tmpToken.Token}`);
|
|
541
|
+
tmpDecreasingPrecedenceStack[j].LeftVirtualSymbolName = tmpToken.VirtualSymbolName;
|
|
542
|
+
tmpDecreasingPrecedenceStack.slice(j, 1);
|
|
543
|
+
break;
|
|
544
|
+
}
|
|
545
|
+
}
|
|
546
|
+
}
|
|
547
|
+
tmpLastToken = tmpToken;
|
|
548
|
+
}
|
|
549
|
+
else if (tmpToken.Descriptor.Precedence < tmpLastPrecedence)
|
|
550
|
+
{
|
|
551
|
+
tmpDecreasingPrecedenceStack.push(tmpLastToken);
|
|
552
|
+
tmpLastToken = tmpToken;
|
|
553
|
+
}
|
|
554
|
+
tmpLastPrecedence = tmpToken.Descriptor.Precedence;
|
|
555
|
+
}
|
|
558
556
|
}
|
|
559
557
|
}
|
|
560
558
|
|
|
@@ -563,6 +561,27 @@ class ExpressionParserPostfix extends libExpressionParserOperationBase
|
|
|
563
561
|
{
|
|
564
562
|
let tmpSolveLayerTokens = tmpSolveLayerMap[tmpSolveLayerKeys[tmpSolveLayerIndex]];
|
|
565
563
|
|
|
564
|
+
// If this is a layer with one value, presume it's an assignment.
|
|
565
|
+
if (tmpSolveLayerTokens.length === 1)
|
|
566
|
+
{
|
|
567
|
+
let tmpAbstractAssignToken = this.getTokenContainerObject('=');
|
|
568
|
+
tmpAbstractAssignToken.VirtualSymbolName = tmpResults.PostfixLayerstackMap[tmpSolveLayerTokens[0].SolveLayerStack];
|
|
569
|
+
// If this doesn't have a matching solvelayerstack, get the virtual symbol name from the parenthesis group it's in
|
|
570
|
+
if (!tmpAbstractAssignToken.VirtualSymbolName)
|
|
571
|
+
{
|
|
572
|
+
for (let i = 0; i < tmpResults.PostfixTokenObjects.length; i++)
|
|
573
|
+
{
|
|
574
|
+
if (tmpResults.PostfixTokenObjects[i].ParenthesisStack === tmpSolveLayerTokens[0].SolveLayerStack)
|
|
575
|
+
{
|
|
576
|
+
tmpAbstractAssignToken.VirtualSymbolName = tmpResults.PostfixTokenObjects[i].VirtualSymbolName;
|
|
577
|
+
break;
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
tmpResults.PostfixSolveList.push(this.getPosfixSolveListOperation(tmpAbstractAssignToken, tmpSolveLayerTokens[0], this.getTokenContainerObject('0.0')));
|
|
582
|
+
continue;
|
|
583
|
+
}
|
|
584
|
+
|
|
566
585
|
// For each precedence level in the layer
|
|
567
586
|
for (let tmpPrecedence = 0; tmpPrecedence <= this.ExpressionParser.tokenMaxPrecedence; tmpPrecedence++)
|
|
568
587
|
{
|
|
@@ -580,7 +599,7 @@ class ExpressionParserPostfix extends libExpressionParserOperationBase
|
|
|
580
599
|
{
|
|
581
600
|
// The number line negation operator is a special case that generates a virtual constant (-1.0) and multiplies it by the next token
|
|
582
601
|
// This is an abstract operation that isn't in the expression.
|
|
583
|
-
let tmpAbstractMultiplyToken = this.
|
|
602
|
+
let tmpAbstractMultiplyToken = this.getTokenContainerObject('*');
|
|
584
603
|
tmpAbstractMultiplyToken.VirtualSymbolName = tmpToken.VirtualSymbolName;
|
|
585
604
|
tmpResults.PostfixSolveList.push(this.getPosfixSolveListOperation(tmpAbstractMultiplyToken, this.getTokenContainerObject('-1.0'), tmpSolveLayerTokens[i+1]));
|
|
586
605
|
}
|
|
@@ -588,7 +607,7 @@ class ExpressionParserPostfix extends libExpressionParserOperationBase
|
|
|
588
607
|
else if ((i > 0) && (tmpToken.Token == '-') && ((tmpSolveLayerTokens[i-1].Type === 'Token.Operator') || (tmpSolveLayerTokens[i-1].Token === '(')))
|
|
589
608
|
{
|
|
590
609
|
// The number line negation operator is a special case that generates a virtual constant (-1.0) and multiplies it by the next token
|
|
591
|
-
let tmpAbstractMultiplyToken = this.
|
|
610
|
+
let tmpAbstractMultiplyToken = this.getTokenContainerObject('*');
|
|
592
611
|
tmpAbstractMultiplyToken.VirtualSymbolName = tmpToken.VirtualSymbolName;
|
|
593
612
|
tmpResults.PostfixSolveList.push(this.getPosfixSolveListOperation(tmpAbstractMultiplyToken, this.getTokenContainerObject('-1.0'), tmpSolveLayerTokens[i+1]));
|
|
594
613
|
}
|
|
@@ -612,14 +631,13 @@ class ExpressionParserPostfix extends libExpressionParserOperationBase
|
|
|
612
631
|
else if ((tmpSolveLayerTokens[i].Type === 'Token.Function') && (tmpPrecedence === 0))
|
|
613
632
|
{
|
|
614
633
|
let tmpToken = tmpSolveLayerTokens[i];
|
|
615
|
-
// Not sure what to do with the other token.
|
|
616
634
|
tmpResults.PostfixSolveList.push(this.getPosfixSolveListOperation(tmpToken, tmpSolveLayerTokens[i+1], this.getTokenContainerObject('0.0')));
|
|
617
635
|
}
|
|
618
636
|
}
|
|
619
637
|
}
|
|
620
638
|
}
|
|
621
639
|
|
|
622
|
-
//
|
|
640
|
+
// 7. Lastly set the assignment address.
|
|
623
641
|
let tmpAssignmentInstruction = this.getPosfixSolveListOperation(this.getTokenContainerObject('Assign', 'Token.SolverInstruction'), this.getTokenContainerObject('DestinationHash', 'Token.SolverInstruction'), this.getTokenContainerObject('Resulting', 'Token.SolverInstruction'));
|
|
624
642
|
tmpAssignmentInstruction.VirtualSymbolName = tmpResults.PostfixedAssignmentAddress;
|
|
625
643
|
tmpResults.PostfixSolveList.push(tmpAssignmentInstruction);
|
|
@@ -68,6 +68,16 @@ class ExpressionParserSolver extends libExpressionParserOperationBase
|
|
|
68
68
|
tmpStepResultObject.ExpressionStep.RightValue.Value = tmpManifest.getValueAtAddress(tmpResults.VirtualSymbols, tmpStepResultObject.ExpressionStep.RightValue.VirtualSymbolName);
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
// Virtual Constants
|
|
72
|
+
if (tmpStepResultObject.ExpressionStep.LeftValue.Type === 'Token.Constant' && !('Value' in tmpStepResultObject.ExpressionStep.LeftValue))
|
|
73
|
+
{
|
|
74
|
+
tmpStepResultObject.ExpressionStep.LeftValue.Value = tmpStepResultObject.ExpressionStep.LeftValue.Token;
|
|
75
|
+
}
|
|
76
|
+
if (tmpStepResultObject.ExpressionStep.RightValue.Type === 'Token.Constant' && !('Value' in tmpStepResultObject.ExpressionStep.RightValue))
|
|
77
|
+
{
|
|
78
|
+
tmpStepResultObject.ExpressionStep.RightValue.Value = tmpStepResultObject.ExpressionStep.RightValue.Token;
|
|
79
|
+
}
|
|
80
|
+
|
|
71
81
|
if (tmpStepResultObject.ExpressionStep.Operation.Type = 'Operator')
|
|
72
82
|
{
|
|
73
83
|
// TODO: This can be optimized. A lot. If necessary. Seems pretty fast honestly for even thousands of operations. Slowest part is arbitrary precision.
|
|
@@ -90,7 +100,7 @@ class ExpressionParserSolver extends libExpressionParserOperationBase
|
|
|
90
100
|
}
|
|
91
101
|
catch (pError)
|
|
92
102
|
{
|
|
93
|
-
tmpResults.ExpressionParserLog.push(`ERROR: ExpressionParser.solvePostfixedExpression failed to solve step ${i} with function ${tmpStepResultObject.ExpressionStep.Operation.Token}
|
|
103
|
+
tmpResults.ExpressionParserLog.push(`ERROR: ExpressionParser.solvePostfixedExpression failed to solve step ${i} with function ${tmpStepResultObject.ExpressionStep.Operation.Token}: ${pError}`);
|
|
94
104
|
this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);
|
|
95
105
|
return false;
|
|
96
106
|
}
|
|
@@ -113,9 +113,18 @@ class FableServiceExpressionParser extends libFableServiceBase
|
|
|
113
113
|
}
|
|
114
114
|
catch(pError)
|
|
115
115
|
{
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
116
|
+
// TODO: Should we allow this to be a function? Good god the complexity and beauty of that...
|
|
117
|
+
if (Array.isArray(tmpValue) || (typeof(tmpValue) === 'object'))
|
|
118
|
+
{
|
|
119
|
+
tmpToken.Resolved = true;
|
|
120
|
+
tmpToken.Value = tmpValue;
|
|
121
|
+
}
|
|
122
|
+
else
|
|
123
|
+
{
|
|
124
|
+
tmpResults.ExpressionParserLog.push(`INFO: ExpressionParser.substituteValuesInTokenizedObjects found a non-numeric, non-set value for the state address ${tmpToken.Token} at index ${i}`);
|
|
125
|
+
this.log.error(tmpResults.ExpressionParserLog[tmpResults.ExpressionParserLog.length-1]);
|
|
126
|
+
tmpToken.Resolved = false;
|
|
127
|
+
}
|
|
119
128
|
}
|
|
120
129
|
}
|
|
121
130
|
}
|
|
@@ -190,6 +199,16 @@ class FableServiceExpressionParser extends libFableServiceBase
|
|
|
190
199
|
return this.Solver.solvePostfixedExpression(pPostfixedExpression, pDataDestinationObject, pResultObject, pManifest);
|
|
191
200
|
}
|
|
192
201
|
|
|
202
|
+
/**
|
|
203
|
+
* Solves the given expression using the provided data and manifest.
|
|
204
|
+
*
|
|
205
|
+
* @param {string} pExpression - The expression to solve.
|
|
206
|
+
* @param {object} pDataSourceObject - (optional) The data source object (e.g. AppData).
|
|
207
|
+
* @param {object} pResultObject - (optional) The result object containing the full postfix expression list, internal variables and solver history.
|
|
208
|
+
* @param {object} pManifest - (optional) The manifest object for dereferencing variables.
|
|
209
|
+
* @param {object} pDataDestinationObject - (optional) The data destination object for where to marshal the result into.
|
|
210
|
+
* @returns {any} - The result of solving the expression.
|
|
211
|
+
*/
|
|
193
212
|
solve(pExpression, pDataSourceObject, pResultObject, pManifest, pDataDestinationObject)
|
|
194
213
|
{
|
|
195
214
|
let tmpResultsObject = (typeof(pResultObject) === 'object') ? pResultObject : {};
|