lightview 2.3.4 → 2.3.5
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/docs/calculator.html +427 -0
- package/docs/cdom-nav.html +1 -1
- package/docs/cdom.html +2 -2
- package/jprx/README.md +1 -1
- package/jprx/helpers/calc.js +82 -0
- package/jprx/helpers/lookup.js +39 -0
- package/jprx/helpers/math.js +4 -0
- package/jprx/index.js +3 -0
- package/jprx/package.json +2 -2
- package/jprx/parser.js +35 -3
- package/lightview-all.js +1724 -23
- package/lightview-cdom.js +1724 -23
- package/package.json +3 -2
- package/src/lightview-cdom.js +3 -1
- package/start-dev.js +1 -1
- package/cDOMIntro.md +0 -279
package/lightview-all.js
CHANGED
|
@@ -2371,7 +2371,7 @@
|
|
|
2371
2371
|
const resolveTemplate = (node, context2) => {
|
|
2372
2372
|
if (typeof node === "string") {
|
|
2373
2373
|
if (node.startsWith("=")) {
|
|
2374
|
-
const res = resolveExpression(node, context2);
|
|
2374
|
+
const res = resolveExpression$1(node, context2);
|
|
2375
2375
|
const final = res instanceof LazyValue ? res.resolve(context2) : res;
|
|
2376
2376
|
return unwrapSignal(final);
|
|
2377
2377
|
}
|
|
@@ -2427,7 +2427,7 @@
|
|
|
2427
2427
|
} else if (globalMode && !arg.startsWith("=") && !arg.startsWith("./")) {
|
|
2428
2428
|
nestedExpr = `=/${arg}`;
|
|
2429
2429
|
}
|
|
2430
|
-
const val = resolveExpression(nestedExpr, context);
|
|
2430
|
+
const val = resolveExpression$1(nestedExpr, context);
|
|
2431
2431
|
if (val instanceof LazyValue) {
|
|
2432
2432
|
return { value: val, isLazy: true };
|
|
2433
2433
|
}
|
|
@@ -2906,7 +2906,7 @@
|
|
|
2906
2906
|
const ast = parser.parseExpression(0);
|
|
2907
2907
|
return evaluateAST(ast, context);
|
|
2908
2908
|
};
|
|
2909
|
-
const resolveExpression = (expr, context) => {
|
|
2909
|
+
const resolveExpression$1 = (expr, context) => {
|
|
2910
2910
|
var _a2, _b2;
|
|
2911
2911
|
if (typeof expr !== "string") return expr;
|
|
2912
2912
|
if (hasOperatorSyntax(expr)) {
|
|
@@ -2993,7 +2993,7 @@
|
|
|
2993
2993
|
const parseExpression = (expr, context) => {
|
|
2994
2994
|
const LV = getLV();
|
|
2995
2995
|
if (!LV || typeof expr !== "string") return expr;
|
|
2996
|
-
return LV.computed(() => resolveExpression(expr, context));
|
|
2996
|
+
return LV.computed(() => resolveExpression$1(expr, context));
|
|
2997
2997
|
};
|
|
2998
2998
|
const parseCDOMC = (input) => {
|
|
2999
2999
|
let i = 0;
|
|
@@ -3284,6 +3284,32 @@
|
|
|
3284
3284
|
while (j < len2 && /\s/.test(input[j])) j++;
|
|
3285
3285
|
if (input[j] === ":") {
|
|
3286
3286
|
result += `"${word}"`;
|
|
3287
|
+
} else if (input[j] === "(") {
|
|
3288
|
+
let expr = word;
|
|
3289
|
+
i = j;
|
|
3290
|
+
let parenDepth = 0;
|
|
3291
|
+
let inQuote = null;
|
|
3292
|
+
while (i < len2) {
|
|
3293
|
+
const c = input[i];
|
|
3294
|
+
if (inQuote) {
|
|
3295
|
+
if (c === inQuote && input[i - 1] !== "\\") inQuote = null;
|
|
3296
|
+
} else if (c === '"' || c === "'") {
|
|
3297
|
+
inQuote = c;
|
|
3298
|
+
} else {
|
|
3299
|
+
if (c === "(") parenDepth++;
|
|
3300
|
+
else if (c === ")") {
|
|
3301
|
+
parenDepth--;
|
|
3302
|
+
if (parenDepth === 0) {
|
|
3303
|
+
expr += c;
|
|
3304
|
+
i++;
|
|
3305
|
+
break;
|
|
3306
|
+
}
|
|
3307
|
+
}
|
|
3308
|
+
}
|
|
3309
|
+
expr += c;
|
|
3310
|
+
i++;
|
|
3311
|
+
}
|
|
3312
|
+
result += JSON.stringify("=" + expr);
|
|
3287
3313
|
} else {
|
|
3288
3314
|
if (word === "true" || word === "false" || word === "null") {
|
|
3289
3315
|
result += word;
|
|
@@ -3315,7 +3341,7 @@
|
|
|
3315
3341
|
throw e;
|
|
3316
3342
|
}
|
|
3317
3343
|
};
|
|
3318
|
-
const add = (...args) => args.reduce((a, b) => Number(a) + Number(b), 0);
|
|
3344
|
+
const add$1 = (...args) => args.reduce((a, b) => Number(a) + Number(b), 0);
|
|
3319
3345
|
const subtract = (a, b) => Number(a) - Number(b);
|
|
3320
3346
|
const multiply = (...args) => args.reduce((a, b) => Number(a) * Number(b), 1);
|
|
3321
3347
|
const divide = (a, b) => Number(a) / Number(b);
|
|
@@ -3323,12 +3349,14 @@
|
|
|
3323
3349
|
const ceil = (val) => Math.ceil(val);
|
|
3324
3350
|
const floor = (val) => Math.floor(val);
|
|
3325
3351
|
const abs = (val) => Math.abs(val);
|
|
3326
|
-
const mod = (a, b) => a % b;
|
|
3352
|
+
const mod$1 = (a, b) => a % b;
|
|
3327
3353
|
const pow = (a, b) => Math.pow(a, b);
|
|
3328
3354
|
const sqrt = (val) => Math.sqrt(val);
|
|
3355
|
+
const negate = (val) => -Number(val);
|
|
3356
|
+
const toPercent = (val) => Number(val) / 100;
|
|
3329
3357
|
const registerMathHelpers = (register) => {
|
|
3330
|
-
register("+", add);
|
|
3331
|
-
register("add", add);
|
|
3358
|
+
register("+", add$1);
|
|
3359
|
+
register("add", add$1);
|
|
3332
3360
|
register("-", subtract);
|
|
3333
3361
|
register("sub", subtract);
|
|
3334
3362
|
register("*", multiply);
|
|
@@ -3339,11 +3367,13 @@
|
|
|
3339
3367
|
register("ceil", ceil);
|
|
3340
3368
|
register("floor", floor);
|
|
3341
3369
|
register("abs", abs);
|
|
3342
|
-
register("mod", mod);
|
|
3370
|
+
register("mod", mod$1);
|
|
3343
3371
|
register("pow", pow);
|
|
3344
3372
|
register("sqrt", sqrt);
|
|
3373
|
+
register("negate", negate);
|
|
3374
|
+
register("toPercent", toPercent);
|
|
3345
3375
|
};
|
|
3346
|
-
const ifHelper = (
|
|
3376
|
+
const ifHelper = (condition2, thenVal, elseVal) => condition2 ? thenVal : elseVal;
|
|
3347
3377
|
const andHelper = (...args) => args.every(Boolean);
|
|
3348
3378
|
const orHelper = (...args) => args.some(Boolean);
|
|
3349
3379
|
const notHelper = (val) => !val;
|
|
@@ -3367,7 +3397,7 @@
|
|
|
3367
3397
|
const items = args.slice(0, -1);
|
|
3368
3398
|
return items.join(separator);
|
|
3369
3399
|
};
|
|
3370
|
-
const concat = (...args) => args.join("");
|
|
3400
|
+
const concat$1 = (...args) => args.join("");
|
|
3371
3401
|
const upper = (s) => String(s).toUpperCase();
|
|
3372
3402
|
const lower = (s) => String(s).toLowerCase();
|
|
3373
3403
|
const trim = (s) => String(s).trim();
|
|
@@ -3381,13 +3411,13 @@
|
|
|
3381
3411
|
const titleCase = (s) => {
|
|
3382
3412
|
return String(s).toLowerCase().split(" ").map((word) => word.charAt(0).toUpperCase() + word.slice(1)).join(" ");
|
|
3383
3413
|
};
|
|
3384
|
-
const contains$
|
|
3414
|
+
const contains$2 = (s, search) => String(s).includes(search);
|
|
3385
3415
|
const startsWith = (s, prefix) => String(s).startsWith(prefix);
|
|
3386
3416
|
const endsWith = (s, suffix) => String(s).endsWith(suffix);
|
|
3387
3417
|
const defaultHelper = (val, fallback) => val !== void 0 && val !== null ? val : fallback;
|
|
3388
3418
|
const registerStringHelpers = (register) => {
|
|
3389
3419
|
register("join", join$1);
|
|
3390
|
-
register("concat", concat);
|
|
3420
|
+
register("concat", concat$1);
|
|
3391
3421
|
register("upper", upper);
|
|
3392
3422
|
register("lower", lower);
|
|
3393
3423
|
register("trim", trim);
|
|
@@ -3396,7 +3426,7 @@
|
|
|
3396
3426
|
register("split", split);
|
|
3397
3427
|
register("capitalize", capitalize);
|
|
3398
3428
|
register("titleCase", titleCase);
|
|
3399
|
-
register("contains", contains$
|
|
3429
|
+
register("contains", contains$2);
|
|
3400
3430
|
register("startsWith", startsWith);
|
|
3401
3431
|
register("endsWith", endsWith);
|
|
3402
3432
|
register("default", defaultHelper);
|
|
@@ -3469,7 +3499,7 @@
|
|
|
3469
3499
|
const lte = (a, b) => a <= b;
|
|
3470
3500
|
const neq = (a, b) => a !== b;
|
|
3471
3501
|
const between = (val, min2, max2) => val >= min2 && val <= max2;
|
|
3472
|
-
const contains = (arr, val) => Array.isArray(arr) && arr.includes(val);
|
|
3502
|
+
const contains$1 = (arr, val) => Array.isArray(arr) && arr.includes(val);
|
|
3473
3503
|
const registerCompareHelpers = (register) => {
|
|
3474
3504
|
register("gt", gt);
|
|
3475
3505
|
register(">", gt);
|
|
@@ -3482,7 +3512,7 @@
|
|
|
3482
3512
|
register("neq", neq);
|
|
3483
3513
|
register("!=", neq);
|
|
3484
3514
|
register("between", between);
|
|
3485
|
-
register("in", contains);
|
|
3515
|
+
register("in", contains$1);
|
|
3486
3516
|
};
|
|
3487
3517
|
const sumIf = (arr, predicate) => {
|
|
3488
3518
|
if (!Array.isArray(arr)) return 0;
|
|
@@ -3573,16 +3603,35 @@
|
|
|
3573
3603
|
};
|
|
3574
3604
|
const index = (arr, idx) => Array.isArray(arr) ? arr[idx] : void 0;
|
|
3575
3605
|
const match = (val, arr) => Array.isArray(arr) ? arr.indexOf(val) : -1;
|
|
3606
|
+
const pathRef = (path, context) => {
|
|
3607
|
+
if (path && typeof path === "object" && "value" in path) {
|
|
3608
|
+
return unwrapSignal(path.value);
|
|
3609
|
+
}
|
|
3610
|
+
if (typeof path === "string") {
|
|
3611
|
+
const normalized = path.startsWith("=") ? path : "=" + path;
|
|
3612
|
+
const resolved = resolvePath(normalized, context);
|
|
3613
|
+
const value = unwrapSignal(resolved);
|
|
3614
|
+
if (typeof value === "number") return value;
|
|
3615
|
+
if (typeof value === "string" && value !== "" && !isNaN(parseFloat(value)) && isFinite(Number(value))) {
|
|
3616
|
+
return parseFloat(value);
|
|
3617
|
+
}
|
|
3618
|
+
return value;
|
|
3619
|
+
}
|
|
3620
|
+
return unwrapSignal(path);
|
|
3621
|
+
};
|
|
3576
3622
|
const registerLookupHelpers = (register) => {
|
|
3577
3623
|
register("lookup", lookup);
|
|
3578
3624
|
register("vlookup", vlookup);
|
|
3579
3625
|
register("index", index);
|
|
3580
3626
|
register("match", match);
|
|
3627
|
+
register("$", pathRef, { pathAware: true });
|
|
3628
|
+
register("val", pathRef, { pathAware: true });
|
|
3629
|
+
register("indirect", pathRef, { pathAware: true });
|
|
3581
3630
|
};
|
|
3582
3631
|
const sum = (...args) => args.reduce((a, b) => a + (Number(b) || 0), 0);
|
|
3583
3632
|
const avg = (...args) => args.length === 0 ? 0 : sum(...args) / args.length;
|
|
3584
|
-
const min = (...args) => Math.min(...args);
|
|
3585
|
-
const max = (...args) => Math.max(...args);
|
|
3633
|
+
const min$1 = (...args) => Math.min(...args);
|
|
3634
|
+
const max$1 = (...args) => Math.max(...args);
|
|
3586
3635
|
const median = (...args) => {
|
|
3587
3636
|
if (args.length === 0) return 0;
|
|
3588
3637
|
const sorted = [...args].sort((a, b) => a - b);
|
|
@@ -3604,8 +3653,8 @@
|
|
|
3604
3653
|
const registerStatsHelpers = (register) => {
|
|
3605
3654
|
register("sum", sum);
|
|
3606
3655
|
register("avg", avg);
|
|
3607
|
-
register("min", min);
|
|
3608
|
-
register("max", max);
|
|
3656
|
+
register("min", min$1);
|
|
3657
|
+
register("max", max$1);
|
|
3609
3658
|
register("median", median);
|
|
3610
3659
|
register("stdev", stdev);
|
|
3611
3660
|
register("var", variance);
|
|
@@ -3720,6 +3769,1657 @@
|
|
|
3720
3769
|
const registerNetworkHelpers = (register) => {
|
|
3721
3770
|
register("fetch", fetchHelper);
|
|
3722
3771
|
};
|
|
3772
|
+
var INUMBER = "INUMBER";
|
|
3773
|
+
var IOP1 = "IOP1";
|
|
3774
|
+
var IOP2 = "IOP2";
|
|
3775
|
+
var IOP3 = "IOP3";
|
|
3776
|
+
var IVAR = "IVAR";
|
|
3777
|
+
var IVARNAME = "IVARNAME";
|
|
3778
|
+
var IFUNCALL = "IFUNCALL";
|
|
3779
|
+
var IFUNDEF = "IFUNDEF";
|
|
3780
|
+
var IEXPR = "IEXPR";
|
|
3781
|
+
var IEXPREVAL = "IEXPREVAL";
|
|
3782
|
+
var IMEMBER = "IMEMBER";
|
|
3783
|
+
var IENDSTATEMENT = "IENDSTATEMENT";
|
|
3784
|
+
var IARRAY = "IARRAY";
|
|
3785
|
+
function Instruction(type, value) {
|
|
3786
|
+
this.type = type;
|
|
3787
|
+
this.value = value !== void 0 && value !== null ? value : 0;
|
|
3788
|
+
}
|
|
3789
|
+
Instruction.prototype.toString = function() {
|
|
3790
|
+
switch (this.type) {
|
|
3791
|
+
case INUMBER:
|
|
3792
|
+
case IOP1:
|
|
3793
|
+
case IOP2:
|
|
3794
|
+
case IOP3:
|
|
3795
|
+
case IVAR:
|
|
3796
|
+
case IVARNAME:
|
|
3797
|
+
case IENDSTATEMENT:
|
|
3798
|
+
return this.value;
|
|
3799
|
+
case IFUNCALL:
|
|
3800
|
+
return "CALL " + this.value;
|
|
3801
|
+
case IFUNDEF:
|
|
3802
|
+
return "DEF " + this.value;
|
|
3803
|
+
case IARRAY:
|
|
3804
|
+
return "ARRAY " + this.value;
|
|
3805
|
+
case IMEMBER:
|
|
3806
|
+
return "." + this.value;
|
|
3807
|
+
default:
|
|
3808
|
+
return "Invalid Instruction";
|
|
3809
|
+
}
|
|
3810
|
+
};
|
|
3811
|
+
function unaryInstruction(value) {
|
|
3812
|
+
return new Instruction(IOP1, value);
|
|
3813
|
+
}
|
|
3814
|
+
function binaryInstruction(value) {
|
|
3815
|
+
return new Instruction(IOP2, value);
|
|
3816
|
+
}
|
|
3817
|
+
function ternaryInstruction(value) {
|
|
3818
|
+
return new Instruction(IOP3, value);
|
|
3819
|
+
}
|
|
3820
|
+
function simplify(tokens, unaryOps, binaryOps, ternaryOps, values) {
|
|
3821
|
+
var nstack = [];
|
|
3822
|
+
var newexpression = [];
|
|
3823
|
+
var n1, n2, n3;
|
|
3824
|
+
var f;
|
|
3825
|
+
for (var i = 0; i < tokens.length; i++) {
|
|
3826
|
+
var item = tokens[i];
|
|
3827
|
+
var type = item.type;
|
|
3828
|
+
if (type === INUMBER || type === IVARNAME) {
|
|
3829
|
+
if (Array.isArray(item.value)) {
|
|
3830
|
+
nstack.push.apply(nstack, simplify(item.value.map(function(x) {
|
|
3831
|
+
return new Instruction(INUMBER, x);
|
|
3832
|
+
}).concat(new Instruction(IARRAY, item.value.length)), unaryOps, binaryOps, ternaryOps, values));
|
|
3833
|
+
} else {
|
|
3834
|
+
nstack.push(item);
|
|
3835
|
+
}
|
|
3836
|
+
} else if (type === IVAR && values.hasOwnProperty(item.value)) {
|
|
3837
|
+
item = new Instruction(INUMBER, values[item.value]);
|
|
3838
|
+
nstack.push(item);
|
|
3839
|
+
} else if (type === IOP2 && nstack.length > 1) {
|
|
3840
|
+
n2 = nstack.pop();
|
|
3841
|
+
n1 = nstack.pop();
|
|
3842
|
+
f = binaryOps[item.value];
|
|
3843
|
+
item = new Instruction(INUMBER, f(n1.value, n2.value));
|
|
3844
|
+
nstack.push(item);
|
|
3845
|
+
} else if (type === IOP3 && nstack.length > 2) {
|
|
3846
|
+
n3 = nstack.pop();
|
|
3847
|
+
n2 = nstack.pop();
|
|
3848
|
+
n1 = nstack.pop();
|
|
3849
|
+
if (item.value === "?") {
|
|
3850
|
+
nstack.push(n1.value ? n2.value : n3.value);
|
|
3851
|
+
} else {
|
|
3852
|
+
f = ternaryOps[item.value];
|
|
3853
|
+
item = new Instruction(INUMBER, f(n1.value, n2.value, n3.value));
|
|
3854
|
+
nstack.push(item);
|
|
3855
|
+
}
|
|
3856
|
+
} else if (type === IOP1 && nstack.length > 0) {
|
|
3857
|
+
n1 = nstack.pop();
|
|
3858
|
+
f = unaryOps[item.value];
|
|
3859
|
+
item = new Instruction(INUMBER, f(n1.value));
|
|
3860
|
+
nstack.push(item);
|
|
3861
|
+
} else if (type === IEXPR) {
|
|
3862
|
+
while (nstack.length > 0) {
|
|
3863
|
+
newexpression.push(nstack.shift());
|
|
3864
|
+
}
|
|
3865
|
+
newexpression.push(new Instruction(IEXPR, simplify(item.value, unaryOps, binaryOps, ternaryOps, values)));
|
|
3866
|
+
} else if (type === IMEMBER && nstack.length > 0) {
|
|
3867
|
+
n1 = nstack.pop();
|
|
3868
|
+
nstack.push(new Instruction(INUMBER, n1.value[item.value]));
|
|
3869
|
+
} else {
|
|
3870
|
+
while (nstack.length > 0) {
|
|
3871
|
+
newexpression.push(nstack.shift());
|
|
3872
|
+
}
|
|
3873
|
+
newexpression.push(item);
|
|
3874
|
+
}
|
|
3875
|
+
}
|
|
3876
|
+
while (nstack.length > 0) {
|
|
3877
|
+
newexpression.push(nstack.shift());
|
|
3878
|
+
}
|
|
3879
|
+
return newexpression;
|
|
3880
|
+
}
|
|
3881
|
+
function substitute(tokens, variable, expr) {
|
|
3882
|
+
var newexpression = [];
|
|
3883
|
+
for (var i = 0; i < tokens.length; i++) {
|
|
3884
|
+
var item = tokens[i];
|
|
3885
|
+
var type = item.type;
|
|
3886
|
+
if (type === IVAR && item.value === variable) {
|
|
3887
|
+
for (var j = 0; j < expr.tokens.length; j++) {
|
|
3888
|
+
var expritem = expr.tokens[j];
|
|
3889
|
+
var replitem;
|
|
3890
|
+
if (expritem.type === IOP1) {
|
|
3891
|
+
replitem = unaryInstruction(expritem.value);
|
|
3892
|
+
} else if (expritem.type === IOP2) {
|
|
3893
|
+
replitem = binaryInstruction(expritem.value);
|
|
3894
|
+
} else if (expritem.type === IOP3) {
|
|
3895
|
+
replitem = ternaryInstruction(expritem.value);
|
|
3896
|
+
} else {
|
|
3897
|
+
replitem = new Instruction(expritem.type, expritem.value);
|
|
3898
|
+
}
|
|
3899
|
+
newexpression.push(replitem);
|
|
3900
|
+
}
|
|
3901
|
+
} else if (type === IEXPR) {
|
|
3902
|
+
newexpression.push(new Instruction(IEXPR, substitute(item.value, variable, expr)));
|
|
3903
|
+
} else {
|
|
3904
|
+
newexpression.push(item);
|
|
3905
|
+
}
|
|
3906
|
+
}
|
|
3907
|
+
return newexpression;
|
|
3908
|
+
}
|
|
3909
|
+
function evaluate(tokens, expr, values) {
|
|
3910
|
+
var nstack = [];
|
|
3911
|
+
var n1, n2, n3;
|
|
3912
|
+
var f, args, argCount;
|
|
3913
|
+
if (isExpressionEvaluator(tokens)) {
|
|
3914
|
+
return resolveExpression(tokens, values);
|
|
3915
|
+
}
|
|
3916
|
+
var numTokens = tokens.length;
|
|
3917
|
+
for (var i = 0; i < numTokens; i++) {
|
|
3918
|
+
var item = tokens[i];
|
|
3919
|
+
var type = item.type;
|
|
3920
|
+
if (type === INUMBER || type === IVARNAME) {
|
|
3921
|
+
nstack.push(item.value);
|
|
3922
|
+
} else if (type === IOP2) {
|
|
3923
|
+
n2 = nstack.pop();
|
|
3924
|
+
n1 = nstack.pop();
|
|
3925
|
+
if (item.value === "and") {
|
|
3926
|
+
nstack.push(n1 ? !!evaluate(n2, expr, values) : false);
|
|
3927
|
+
} else if (item.value === "or") {
|
|
3928
|
+
nstack.push(n1 ? true : !!evaluate(n2, expr, values));
|
|
3929
|
+
} else if (item.value === "=") {
|
|
3930
|
+
f = expr.binaryOps[item.value];
|
|
3931
|
+
nstack.push(f(n1, evaluate(n2, expr, values), values));
|
|
3932
|
+
} else {
|
|
3933
|
+
f = expr.binaryOps[item.value];
|
|
3934
|
+
nstack.push(f(resolveExpression(n1, values), resolveExpression(n2, values)));
|
|
3935
|
+
}
|
|
3936
|
+
} else if (type === IOP3) {
|
|
3937
|
+
n3 = nstack.pop();
|
|
3938
|
+
n2 = nstack.pop();
|
|
3939
|
+
n1 = nstack.pop();
|
|
3940
|
+
if (item.value === "?") {
|
|
3941
|
+
nstack.push(evaluate(n1 ? n2 : n3, expr, values));
|
|
3942
|
+
} else {
|
|
3943
|
+
f = expr.ternaryOps[item.value];
|
|
3944
|
+
nstack.push(f(resolveExpression(n1, values), resolveExpression(n2, values), resolveExpression(n3, values)));
|
|
3945
|
+
}
|
|
3946
|
+
} else if (type === IVAR) {
|
|
3947
|
+
if (item.value in expr.functions) {
|
|
3948
|
+
nstack.push(expr.functions[item.value]);
|
|
3949
|
+
} else if (item.value in expr.unaryOps && expr.parser.isOperatorEnabled(item.value)) {
|
|
3950
|
+
nstack.push(expr.unaryOps[item.value]);
|
|
3951
|
+
} else {
|
|
3952
|
+
var v = values[item.value];
|
|
3953
|
+
if (v !== void 0) {
|
|
3954
|
+
nstack.push(v);
|
|
3955
|
+
} else {
|
|
3956
|
+
throw new Error("undefined variable: " + item.value);
|
|
3957
|
+
}
|
|
3958
|
+
}
|
|
3959
|
+
} else if (type === IOP1) {
|
|
3960
|
+
n1 = nstack.pop();
|
|
3961
|
+
f = expr.unaryOps[item.value];
|
|
3962
|
+
nstack.push(f(resolveExpression(n1, values)));
|
|
3963
|
+
} else if (type === IFUNCALL) {
|
|
3964
|
+
argCount = item.value;
|
|
3965
|
+
args = [];
|
|
3966
|
+
while (argCount-- > 0) {
|
|
3967
|
+
args.unshift(resolveExpression(nstack.pop(), values));
|
|
3968
|
+
}
|
|
3969
|
+
f = nstack.pop();
|
|
3970
|
+
if (f.apply && f.call) {
|
|
3971
|
+
nstack.push(f.apply(void 0, args));
|
|
3972
|
+
} else {
|
|
3973
|
+
throw new Error(f + " is not a function");
|
|
3974
|
+
}
|
|
3975
|
+
} else if (type === IFUNDEF) {
|
|
3976
|
+
nstack.push(function() {
|
|
3977
|
+
var n22 = nstack.pop();
|
|
3978
|
+
var args2 = [];
|
|
3979
|
+
var argCount2 = item.value;
|
|
3980
|
+
while (argCount2-- > 0) {
|
|
3981
|
+
args2.unshift(nstack.pop());
|
|
3982
|
+
}
|
|
3983
|
+
var n12 = nstack.pop();
|
|
3984
|
+
var f2 = function() {
|
|
3985
|
+
var scope = Object.assign({}, values);
|
|
3986
|
+
for (var i2 = 0, len2 = args2.length; i2 < len2; i2++) {
|
|
3987
|
+
scope[args2[i2]] = arguments[i2];
|
|
3988
|
+
}
|
|
3989
|
+
return evaluate(n22, expr, scope);
|
|
3990
|
+
};
|
|
3991
|
+
Object.defineProperty(f2, "name", {
|
|
3992
|
+
value: n12,
|
|
3993
|
+
writable: false
|
|
3994
|
+
});
|
|
3995
|
+
values[n12] = f2;
|
|
3996
|
+
return f2;
|
|
3997
|
+
}());
|
|
3998
|
+
} else if (type === IEXPR) {
|
|
3999
|
+
nstack.push(createExpressionEvaluator(item, expr));
|
|
4000
|
+
} else if (type === IEXPREVAL) {
|
|
4001
|
+
nstack.push(item);
|
|
4002
|
+
} else if (type === IMEMBER) {
|
|
4003
|
+
n1 = nstack.pop();
|
|
4004
|
+
nstack.push(n1[item.value]);
|
|
4005
|
+
} else if (type === IENDSTATEMENT) {
|
|
4006
|
+
nstack.pop();
|
|
4007
|
+
} else if (type === IARRAY) {
|
|
4008
|
+
argCount = item.value;
|
|
4009
|
+
args = [];
|
|
4010
|
+
while (argCount-- > 0) {
|
|
4011
|
+
args.unshift(nstack.pop());
|
|
4012
|
+
}
|
|
4013
|
+
nstack.push(args);
|
|
4014
|
+
} else {
|
|
4015
|
+
throw new Error("invalid Expression");
|
|
4016
|
+
}
|
|
4017
|
+
}
|
|
4018
|
+
if (nstack.length > 1) {
|
|
4019
|
+
throw new Error("invalid Expression (parity)");
|
|
4020
|
+
}
|
|
4021
|
+
return nstack[0] === 0 ? 0 : resolveExpression(nstack[0], values);
|
|
4022
|
+
}
|
|
4023
|
+
function createExpressionEvaluator(token, expr, values) {
|
|
4024
|
+
if (isExpressionEvaluator(token)) return token;
|
|
4025
|
+
return {
|
|
4026
|
+
type: IEXPREVAL,
|
|
4027
|
+
value: function(scope) {
|
|
4028
|
+
return evaluate(token.value, expr, scope);
|
|
4029
|
+
}
|
|
4030
|
+
};
|
|
4031
|
+
}
|
|
4032
|
+
function isExpressionEvaluator(n) {
|
|
4033
|
+
return n && n.type === IEXPREVAL;
|
|
4034
|
+
}
|
|
4035
|
+
function resolveExpression(n, values) {
|
|
4036
|
+
return isExpressionEvaluator(n) ? n.value(values) : n;
|
|
4037
|
+
}
|
|
4038
|
+
function expressionToString(tokens, toJS) {
|
|
4039
|
+
var nstack = [];
|
|
4040
|
+
var n1, n2, n3;
|
|
4041
|
+
var f, args, argCount;
|
|
4042
|
+
for (var i = 0; i < tokens.length; i++) {
|
|
4043
|
+
var item = tokens[i];
|
|
4044
|
+
var type = item.type;
|
|
4045
|
+
if (type === INUMBER) {
|
|
4046
|
+
if (typeof item.value === "number" && item.value < 0) {
|
|
4047
|
+
nstack.push("(" + item.value + ")");
|
|
4048
|
+
} else if (Array.isArray(item.value)) {
|
|
4049
|
+
nstack.push("[" + item.value.map(escapeValue).join(", ") + "]");
|
|
4050
|
+
} else {
|
|
4051
|
+
nstack.push(escapeValue(item.value));
|
|
4052
|
+
}
|
|
4053
|
+
} else if (type === IOP2) {
|
|
4054
|
+
n2 = nstack.pop();
|
|
4055
|
+
n1 = nstack.pop();
|
|
4056
|
+
f = item.value;
|
|
4057
|
+
if (toJS) {
|
|
4058
|
+
if (f === "^") {
|
|
4059
|
+
nstack.push("Math.pow(" + n1 + ", " + n2 + ")");
|
|
4060
|
+
} else if (f === "and") {
|
|
4061
|
+
nstack.push("(!!" + n1 + " && !!" + n2 + ")");
|
|
4062
|
+
} else if (f === "or") {
|
|
4063
|
+
nstack.push("(!!" + n1 + " || !!" + n2 + ")");
|
|
4064
|
+
} else if (f === "||") {
|
|
4065
|
+
nstack.push("(function(a,b){ return Array.isArray(a) && Array.isArray(b) ? a.concat(b) : String(a) + String(b); }((" + n1 + "),(" + n2 + ")))");
|
|
4066
|
+
} else if (f === "==") {
|
|
4067
|
+
nstack.push("(" + n1 + " === " + n2 + ")");
|
|
4068
|
+
} else if (f === "!=") {
|
|
4069
|
+
nstack.push("(" + n1 + " !== " + n2 + ")");
|
|
4070
|
+
} else if (f === "[") {
|
|
4071
|
+
nstack.push(n1 + "[(" + n2 + ") | 0]");
|
|
4072
|
+
} else {
|
|
4073
|
+
nstack.push("(" + n1 + " " + f + " " + n2 + ")");
|
|
4074
|
+
}
|
|
4075
|
+
} else {
|
|
4076
|
+
if (f === "[") {
|
|
4077
|
+
nstack.push(n1 + "[" + n2 + "]");
|
|
4078
|
+
} else {
|
|
4079
|
+
nstack.push("(" + n1 + " " + f + " " + n2 + ")");
|
|
4080
|
+
}
|
|
4081
|
+
}
|
|
4082
|
+
} else if (type === IOP3) {
|
|
4083
|
+
n3 = nstack.pop();
|
|
4084
|
+
n2 = nstack.pop();
|
|
4085
|
+
n1 = nstack.pop();
|
|
4086
|
+
f = item.value;
|
|
4087
|
+
if (f === "?") {
|
|
4088
|
+
nstack.push("(" + n1 + " ? " + n2 + " : " + n3 + ")");
|
|
4089
|
+
} else {
|
|
4090
|
+
throw new Error("invalid Expression");
|
|
4091
|
+
}
|
|
4092
|
+
} else if (type === IVAR || type === IVARNAME) {
|
|
4093
|
+
nstack.push(item.value);
|
|
4094
|
+
} else if (type === IOP1) {
|
|
4095
|
+
n1 = nstack.pop();
|
|
4096
|
+
f = item.value;
|
|
4097
|
+
if (f === "-" || f === "+") {
|
|
4098
|
+
nstack.push("(" + f + n1 + ")");
|
|
4099
|
+
} else if (toJS) {
|
|
4100
|
+
if (f === "not") {
|
|
4101
|
+
nstack.push("(!" + n1 + ")");
|
|
4102
|
+
} else if (f === "!") {
|
|
4103
|
+
nstack.push("fac(" + n1 + ")");
|
|
4104
|
+
} else {
|
|
4105
|
+
nstack.push(f + "(" + n1 + ")");
|
|
4106
|
+
}
|
|
4107
|
+
} else if (f === "!") {
|
|
4108
|
+
nstack.push("(" + n1 + "!)");
|
|
4109
|
+
} else {
|
|
4110
|
+
nstack.push("(" + f + " " + n1 + ")");
|
|
4111
|
+
}
|
|
4112
|
+
} else if (type === IFUNCALL) {
|
|
4113
|
+
argCount = item.value;
|
|
4114
|
+
args = [];
|
|
4115
|
+
while (argCount-- > 0) {
|
|
4116
|
+
args.unshift(nstack.pop());
|
|
4117
|
+
}
|
|
4118
|
+
f = nstack.pop();
|
|
4119
|
+
nstack.push(f + "(" + args.join(", ") + ")");
|
|
4120
|
+
} else if (type === IFUNDEF) {
|
|
4121
|
+
n2 = nstack.pop();
|
|
4122
|
+
argCount = item.value;
|
|
4123
|
+
args = [];
|
|
4124
|
+
while (argCount-- > 0) {
|
|
4125
|
+
args.unshift(nstack.pop());
|
|
4126
|
+
}
|
|
4127
|
+
n1 = nstack.pop();
|
|
4128
|
+
if (toJS) {
|
|
4129
|
+
nstack.push("(" + n1 + " = function(" + args.join(", ") + ") { return " + n2 + " })");
|
|
4130
|
+
} else {
|
|
4131
|
+
nstack.push("(" + n1 + "(" + args.join(", ") + ") = " + n2 + ")");
|
|
4132
|
+
}
|
|
4133
|
+
} else if (type === IMEMBER) {
|
|
4134
|
+
n1 = nstack.pop();
|
|
4135
|
+
nstack.push(n1 + "." + item.value);
|
|
4136
|
+
} else if (type === IARRAY) {
|
|
4137
|
+
argCount = item.value;
|
|
4138
|
+
args = [];
|
|
4139
|
+
while (argCount-- > 0) {
|
|
4140
|
+
args.unshift(nstack.pop());
|
|
4141
|
+
}
|
|
4142
|
+
nstack.push("[" + args.join(", ") + "]");
|
|
4143
|
+
} else if (type === IEXPR) {
|
|
4144
|
+
nstack.push("(" + expressionToString(item.value, toJS) + ")");
|
|
4145
|
+
} else if (type === IENDSTATEMENT) ;
|
|
4146
|
+
else {
|
|
4147
|
+
throw new Error("invalid Expression");
|
|
4148
|
+
}
|
|
4149
|
+
}
|
|
4150
|
+
if (nstack.length > 1) {
|
|
4151
|
+
if (toJS) {
|
|
4152
|
+
nstack = [nstack.join(",")];
|
|
4153
|
+
} else {
|
|
4154
|
+
nstack = [nstack.join(";")];
|
|
4155
|
+
}
|
|
4156
|
+
}
|
|
4157
|
+
return String(nstack[0]);
|
|
4158
|
+
}
|
|
4159
|
+
function escapeValue(v) {
|
|
4160
|
+
if (typeof v === "string") {
|
|
4161
|
+
return JSON.stringify(v).replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
|
|
4162
|
+
}
|
|
4163
|
+
return v;
|
|
4164
|
+
}
|
|
4165
|
+
function contains(array, obj) {
|
|
4166
|
+
for (var i = 0; i < array.length; i++) {
|
|
4167
|
+
if (array[i] === obj) {
|
|
4168
|
+
return true;
|
|
4169
|
+
}
|
|
4170
|
+
}
|
|
4171
|
+
return false;
|
|
4172
|
+
}
|
|
4173
|
+
function getSymbols(tokens, symbols, options) {
|
|
4174
|
+
options = options || {};
|
|
4175
|
+
var withMembers = !!options.withMembers;
|
|
4176
|
+
var prevVar = null;
|
|
4177
|
+
for (var i = 0; i < tokens.length; i++) {
|
|
4178
|
+
var item = tokens[i];
|
|
4179
|
+
if (item.type === IVAR || item.type === IVARNAME) {
|
|
4180
|
+
if (!withMembers && !contains(symbols, item.value)) {
|
|
4181
|
+
symbols.push(item.value);
|
|
4182
|
+
} else if (prevVar !== null) {
|
|
4183
|
+
if (!contains(symbols, prevVar)) {
|
|
4184
|
+
symbols.push(prevVar);
|
|
4185
|
+
}
|
|
4186
|
+
prevVar = item.value;
|
|
4187
|
+
} else {
|
|
4188
|
+
prevVar = item.value;
|
|
4189
|
+
}
|
|
4190
|
+
} else if (item.type === IMEMBER && withMembers && prevVar !== null) {
|
|
4191
|
+
prevVar += "." + item.value;
|
|
4192
|
+
} else if (item.type === IEXPR) {
|
|
4193
|
+
getSymbols(item.value, symbols, options);
|
|
4194
|
+
} else if (prevVar !== null) {
|
|
4195
|
+
if (!contains(symbols, prevVar)) {
|
|
4196
|
+
symbols.push(prevVar);
|
|
4197
|
+
}
|
|
4198
|
+
prevVar = null;
|
|
4199
|
+
}
|
|
4200
|
+
}
|
|
4201
|
+
if (prevVar !== null && !contains(symbols, prevVar)) {
|
|
4202
|
+
symbols.push(prevVar);
|
|
4203
|
+
}
|
|
4204
|
+
}
|
|
4205
|
+
function Expression(tokens, parser) {
|
|
4206
|
+
this.tokens = tokens;
|
|
4207
|
+
this.parser = parser;
|
|
4208
|
+
this.unaryOps = parser.unaryOps;
|
|
4209
|
+
this.binaryOps = parser.binaryOps;
|
|
4210
|
+
this.ternaryOps = parser.ternaryOps;
|
|
4211
|
+
this.functions = parser.functions;
|
|
4212
|
+
}
|
|
4213
|
+
Expression.prototype.simplify = function(values) {
|
|
4214
|
+
values = values || {};
|
|
4215
|
+
return new Expression(simplify(this.tokens, this.unaryOps, this.binaryOps, this.ternaryOps, values), this.parser);
|
|
4216
|
+
};
|
|
4217
|
+
Expression.prototype.substitute = function(variable, expr) {
|
|
4218
|
+
if (!(expr instanceof Expression)) {
|
|
4219
|
+
expr = this.parser.parse(String(expr));
|
|
4220
|
+
}
|
|
4221
|
+
return new Expression(substitute(this.tokens, variable, expr), this.parser);
|
|
4222
|
+
};
|
|
4223
|
+
Expression.prototype.evaluate = function(values) {
|
|
4224
|
+
values = values || {};
|
|
4225
|
+
return evaluate(this.tokens, this, values);
|
|
4226
|
+
};
|
|
4227
|
+
Expression.prototype.toString = function() {
|
|
4228
|
+
return expressionToString(this.tokens, false);
|
|
4229
|
+
};
|
|
4230
|
+
Expression.prototype.symbols = function(options) {
|
|
4231
|
+
options = options || {};
|
|
4232
|
+
var vars = [];
|
|
4233
|
+
getSymbols(this.tokens, vars, options);
|
|
4234
|
+
return vars;
|
|
4235
|
+
};
|
|
4236
|
+
Expression.prototype.variables = function(options) {
|
|
4237
|
+
options = options || {};
|
|
4238
|
+
var vars = [];
|
|
4239
|
+
getSymbols(this.tokens, vars, options);
|
|
4240
|
+
var functions = this.functions;
|
|
4241
|
+
return vars.filter(function(name) {
|
|
4242
|
+
return !(name in functions);
|
|
4243
|
+
});
|
|
4244
|
+
};
|
|
4245
|
+
Expression.prototype.toJSFunction = function(param, variables) {
|
|
4246
|
+
var expr = this;
|
|
4247
|
+
var f = new Function(param, "with(this.functions) with (this.ternaryOps) with (this.binaryOps) with (this.unaryOps) { return " + expressionToString(this.simplify(variables).tokens, true) + "; }");
|
|
4248
|
+
return function() {
|
|
4249
|
+
return f.apply(expr, arguments);
|
|
4250
|
+
};
|
|
4251
|
+
};
|
|
4252
|
+
var TEOF = "TEOF";
|
|
4253
|
+
var TOP = "TOP";
|
|
4254
|
+
var TNUMBER = "TNUMBER";
|
|
4255
|
+
var TSTRING = "TSTRING";
|
|
4256
|
+
var TPAREN = "TPAREN";
|
|
4257
|
+
var TBRACKET = "TBRACKET";
|
|
4258
|
+
var TCOMMA = "TCOMMA";
|
|
4259
|
+
var TNAME = "TNAME";
|
|
4260
|
+
var TSEMICOLON = "TSEMICOLON";
|
|
4261
|
+
function Token(type, value, index2) {
|
|
4262
|
+
this.type = type;
|
|
4263
|
+
this.value = value;
|
|
4264
|
+
this.index = index2;
|
|
4265
|
+
}
|
|
4266
|
+
Token.prototype.toString = function() {
|
|
4267
|
+
return this.type + ": " + this.value;
|
|
4268
|
+
};
|
|
4269
|
+
function TokenStream(parser, expression) {
|
|
4270
|
+
this.pos = 0;
|
|
4271
|
+
this.current = null;
|
|
4272
|
+
this.unaryOps = parser.unaryOps;
|
|
4273
|
+
this.binaryOps = parser.binaryOps;
|
|
4274
|
+
this.ternaryOps = parser.ternaryOps;
|
|
4275
|
+
this.consts = parser.consts;
|
|
4276
|
+
this.expression = expression;
|
|
4277
|
+
this.savedPosition = 0;
|
|
4278
|
+
this.savedCurrent = null;
|
|
4279
|
+
this.options = parser.options;
|
|
4280
|
+
this.parser = parser;
|
|
4281
|
+
}
|
|
4282
|
+
TokenStream.prototype.newToken = function(type, value, pos) {
|
|
4283
|
+
return new Token(type, value, pos != null ? pos : this.pos);
|
|
4284
|
+
};
|
|
4285
|
+
TokenStream.prototype.save = function() {
|
|
4286
|
+
this.savedPosition = this.pos;
|
|
4287
|
+
this.savedCurrent = this.current;
|
|
4288
|
+
};
|
|
4289
|
+
TokenStream.prototype.restore = function() {
|
|
4290
|
+
this.pos = this.savedPosition;
|
|
4291
|
+
this.current = this.savedCurrent;
|
|
4292
|
+
};
|
|
4293
|
+
TokenStream.prototype.next = function() {
|
|
4294
|
+
if (this.pos >= this.expression.length) {
|
|
4295
|
+
return this.newToken(TEOF, "EOF");
|
|
4296
|
+
}
|
|
4297
|
+
if (this.isWhitespace() || this.isComment()) {
|
|
4298
|
+
return this.next();
|
|
4299
|
+
} else if (this.isRadixInteger() || this.isNumber() || this.isOperator() || this.isString() || this.isParen() || this.isBracket() || this.isComma() || this.isSemicolon() || this.isNamedOp() || this.isConst() || this.isName()) {
|
|
4300
|
+
return this.current;
|
|
4301
|
+
} else {
|
|
4302
|
+
this.parseError('Unknown character "' + this.expression.charAt(this.pos) + '"');
|
|
4303
|
+
}
|
|
4304
|
+
};
|
|
4305
|
+
TokenStream.prototype.isString = function() {
|
|
4306
|
+
var r = false;
|
|
4307
|
+
var startPos = this.pos;
|
|
4308
|
+
var quote = this.expression.charAt(startPos);
|
|
4309
|
+
if (quote === "'" || quote === '"') {
|
|
4310
|
+
var index2 = this.expression.indexOf(quote, startPos + 1);
|
|
4311
|
+
while (index2 >= 0 && this.pos < this.expression.length) {
|
|
4312
|
+
this.pos = index2 + 1;
|
|
4313
|
+
if (this.expression.charAt(index2 - 1) !== "\\") {
|
|
4314
|
+
var rawString = this.expression.substring(startPos + 1, index2);
|
|
4315
|
+
this.current = this.newToken(TSTRING, this.unescape(rawString), startPos);
|
|
4316
|
+
r = true;
|
|
4317
|
+
break;
|
|
4318
|
+
}
|
|
4319
|
+
index2 = this.expression.indexOf(quote, index2 + 1);
|
|
4320
|
+
}
|
|
4321
|
+
}
|
|
4322
|
+
return r;
|
|
4323
|
+
};
|
|
4324
|
+
TokenStream.prototype.isParen = function() {
|
|
4325
|
+
var c = this.expression.charAt(this.pos);
|
|
4326
|
+
if (c === "(" || c === ")") {
|
|
4327
|
+
this.current = this.newToken(TPAREN, c);
|
|
4328
|
+
this.pos++;
|
|
4329
|
+
return true;
|
|
4330
|
+
}
|
|
4331
|
+
return false;
|
|
4332
|
+
};
|
|
4333
|
+
TokenStream.prototype.isBracket = function() {
|
|
4334
|
+
var c = this.expression.charAt(this.pos);
|
|
4335
|
+
if ((c === "[" || c === "]") && this.isOperatorEnabled("[")) {
|
|
4336
|
+
this.current = this.newToken(TBRACKET, c);
|
|
4337
|
+
this.pos++;
|
|
4338
|
+
return true;
|
|
4339
|
+
}
|
|
4340
|
+
return false;
|
|
4341
|
+
};
|
|
4342
|
+
TokenStream.prototype.isComma = function() {
|
|
4343
|
+
var c = this.expression.charAt(this.pos);
|
|
4344
|
+
if (c === ",") {
|
|
4345
|
+
this.current = this.newToken(TCOMMA, ",");
|
|
4346
|
+
this.pos++;
|
|
4347
|
+
return true;
|
|
4348
|
+
}
|
|
4349
|
+
return false;
|
|
4350
|
+
};
|
|
4351
|
+
TokenStream.prototype.isSemicolon = function() {
|
|
4352
|
+
var c = this.expression.charAt(this.pos);
|
|
4353
|
+
if (c === ";") {
|
|
4354
|
+
this.current = this.newToken(TSEMICOLON, ";");
|
|
4355
|
+
this.pos++;
|
|
4356
|
+
return true;
|
|
4357
|
+
}
|
|
4358
|
+
return false;
|
|
4359
|
+
};
|
|
4360
|
+
TokenStream.prototype.isConst = function() {
|
|
4361
|
+
var startPos = this.pos;
|
|
4362
|
+
var i = startPos;
|
|
4363
|
+
for (; i < this.expression.length; i++) {
|
|
4364
|
+
var c = this.expression.charAt(i);
|
|
4365
|
+
if (c.toUpperCase() === c.toLowerCase()) {
|
|
4366
|
+
if (i === this.pos || c !== "_" && c !== "." && (c < "0" || c > "9")) {
|
|
4367
|
+
break;
|
|
4368
|
+
}
|
|
4369
|
+
}
|
|
4370
|
+
}
|
|
4371
|
+
if (i > startPos) {
|
|
4372
|
+
var str = this.expression.substring(startPos, i);
|
|
4373
|
+
if (str in this.consts) {
|
|
4374
|
+
this.current = this.newToken(TNUMBER, this.consts[str]);
|
|
4375
|
+
this.pos += str.length;
|
|
4376
|
+
return true;
|
|
4377
|
+
}
|
|
4378
|
+
}
|
|
4379
|
+
return false;
|
|
4380
|
+
};
|
|
4381
|
+
TokenStream.prototype.isNamedOp = function() {
|
|
4382
|
+
var startPos = this.pos;
|
|
4383
|
+
var i = startPos;
|
|
4384
|
+
for (; i < this.expression.length; i++) {
|
|
4385
|
+
var c = this.expression.charAt(i);
|
|
4386
|
+
if (c.toUpperCase() === c.toLowerCase()) {
|
|
4387
|
+
if (i === this.pos || c !== "_" && (c < "0" || c > "9")) {
|
|
4388
|
+
break;
|
|
4389
|
+
}
|
|
4390
|
+
}
|
|
4391
|
+
}
|
|
4392
|
+
if (i > startPos) {
|
|
4393
|
+
var str = this.expression.substring(startPos, i);
|
|
4394
|
+
if (this.isOperatorEnabled(str) && (str in this.binaryOps || str in this.unaryOps || str in this.ternaryOps)) {
|
|
4395
|
+
this.current = this.newToken(TOP, str);
|
|
4396
|
+
this.pos += str.length;
|
|
4397
|
+
return true;
|
|
4398
|
+
}
|
|
4399
|
+
}
|
|
4400
|
+
return false;
|
|
4401
|
+
};
|
|
4402
|
+
TokenStream.prototype.isName = function() {
|
|
4403
|
+
var startPos = this.pos;
|
|
4404
|
+
var i = startPos;
|
|
4405
|
+
var hasLetter = false;
|
|
4406
|
+
for (; i < this.expression.length; i++) {
|
|
4407
|
+
var c = this.expression.charAt(i);
|
|
4408
|
+
if (c.toUpperCase() === c.toLowerCase()) {
|
|
4409
|
+
if (i === this.pos && (c === "$" || c === "_")) {
|
|
4410
|
+
if (c === "_") {
|
|
4411
|
+
hasLetter = true;
|
|
4412
|
+
}
|
|
4413
|
+
continue;
|
|
4414
|
+
} else if (i === this.pos || !hasLetter || c !== "_" && (c < "0" || c > "9")) {
|
|
4415
|
+
break;
|
|
4416
|
+
}
|
|
4417
|
+
} else {
|
|
4418
|
+
hasLetter = true;
|
|
4419
|
+
}
|
|
4420
|
+
}
|
|
4421
|
+
if (hasLetter) {
|
|
4422
|
+
var str = this.expression.substring(startPos, i);
|
|
4423
|
+
this.current = this.newToken(TNAME, str);
|
|
4424
|
+
this.pos += str.length;
|
|
4425
|
+
return true;
|
|
4426
|
+
}
|
|
4427
|
+
return false;
|
|
4428
|
+
};
|
|
4429
|
+
TokenStream.prototype.isWhitespace = function() {
|
|
4430
|
+
var r = false;
|
|
4431
|
+
var c = this.expression.charAt(this.pos);
|
|
4432
|
+
while (c === " " || c === " " || c === "\n" || c === "\r") {
|
|
4433
|
+
r = true;
|
|
4434
|
+
this.pos++;
|
|
4435
|
+
if (this.pos >= this.expression.length) {
|
|
4436
|
+
break;
|
|
4437
|
+
}
|
|
4438
|
+
c = this.expression.charAt(this.pos);
|
|
4439
|
+
}
|
|
4440
|
+
return r;
|
|
4441
|
+
};
|
|
4442
|
+
var codePointPattern = /^[0-9a-f]{4}$/i;
|
|
4443
|
+
TokenStream.prototype.unescape = function(v) {
|
|
4444
|
+
var index2 = v.indexOf("\\");
|
|
4445
|
+
if (index2 < 0) {
|
|
4446
|
+
return v;
|
|
4447
|
+
}
|
|
4448
|
+
var buffer = v.substring(0, index2);
|
|
4449
|
+
while (index2 >= 0) {
|
|
4450
|
+
var c = v.charAt(++index2);
|
|
4451
|
+
switch (c) {
|
|
4452
|
+
case "'":
|
|
4453
|
+
buffer += "'";
|
|
4454
|
+
break;
|
|
4455
|
+
case '"':
|
|
4456
|
+
buffer += '"';
|
|
4457
|
+
break;
|
|
4458
|
+
case "\\":
|
|
4459
|
+
buffer += "\\";
|
|
4460
|
+
break;
|
|
4461
|
+
case "/":
|
|
4462
|
+
buffer += "/";
|
|
4463
|
+
break;
|
|
4464
|
+
case "b":
|
|
4465
|
+
buffer += "\b";
|
|
4466
|
+
break;
|
|
4467
|
+
case "f":
|
|
4468
|
+
buffer += "\f";
|
|
4469
|
+
break;
|
|
4470
|
+
case "n":
|
|
4471
|
+
buffer += "\n";
|
|
4472
|
+
break;
|
|
4473
|
+
case "r":
|
|
4474
|
+
buffer += "\r";
|
|
4475
|
+
break;
|
|
4476
|
+
case "t":
|
|
4477
|
+
buffer += " ";
|
|
4478
|
+
break;
|
|
4479
|
+
case "u":
|
|
4480
|
+
var codePoint = v.substring(index2 + 1, index2 + 5);
|
|
4481
|
+
if (!codePointPattern.test(codePoint)) {
|
|
4482
|
+
this.parseError("Illegal escape sequence: \\u" + codePoint);
|
|
4483
|
+
}
|
|
4484
|
+
buffer += String.fromCharCode(parseInt(codePoint, 16));
|
|
4485
|
+
index2 += 4;
|
|
4486
|
+
break;
|
|
4487
|
+
default:
|
|
4488
|
+
throw this.parseError('Illegal escape sequence: "\\' + c + '"');
|
|
4489
|
+
}
|
|
4490
|
+
++index2;
|
|
4491
|
+
var backslash = v.indexOf("\\", index2);
|
|
4492
|
+
buffer += v.substring(index2, backslash < 0 ? v.length : backslash);
|
|
4493
|
+
index2 = backslash;
|
|
4494
|
+
}
|
|
4495
|
+
return buffer;
|
|
4496
|
+
};
|
|
4497
|
+
TokenStream.prototype.isComment = function() {
|
|
4498
|
+
var c = this.expression.charAt(this.pos);
|
|
4499
|
+
if (c === "/" && this.expression.charAt(this.pos + 1) === "*") {
|
|
4500
|
+
this.pos = this.expression.indexOf("*/", this.pos) + 2;
|
|
4501
|
+
if (this.pos === 1) {
|
|
4502
|
+
this.pos = this.expression.length;
|
|
4503
|
+
}
|
|
4504
|
+
return true;
|
|
4505
|
+
}
|
|
4506
|
+
return false;
|
|
4507
|
+
};
|
|
4508
|
+
TokenStream.prototype.isRadixInteger = function() {
|
|
4509
|
+
var pos = this.pos;
|
|
4510
|
+
if (pos >= this.expression.length - 2 || this.expression.charAt(pos) !== "0") {
|
|
4511
|
+
return false;
|
|
4512
|
+
}
|
|
4513
|
+
++pos;
|
|
4514
|
+
var radix;
|
|
4515
|
+
var validDigit;
|
|
4516
|
+
if (this.expression.charAt(pos) === "x") {
|
|
4517
|
+
radix = 16;
|
|
4518
|
+
validDigit = /^[0-9a-f]$/i;
|
|
4519
|
+
++pos;
|
|
4520
|
+
} else if (this.expression.charAt(pos) === "b") {
|
|
4521
|
+
radix = 2;
|
|
4522
|
+
validDigit = /^[01]$/i;
|
|
4523
|
+
++pos;
|
|
4524
|
+
} else {
|
|
4525
|
+
return false;
|
|
4526
|
+
}
|
|
4527
|
+
var valid = false;
|
|
4528
|
+
var startPos = pos;
|
|
4529
|
+
while (pos < this.expression.length) {
|
|
4530
|
+
var c = this.expression.charAt(pos);
|
|
4531
|
+
if (validDigit.test(c)) {
|
|
4532
|
+
pos++;
|
|
4533
|
+
valid = true;
|
|
4534
|
+
} else {
|
|
4535
|
+
break;
|
|
4536
|
+
}
|
|
4537
|
+
}
|
|
4538
|
+
if (valid) {
|
|
4539
|
+
this.current = this.newToken(TNUMBER, parseInt(this.expression.substring(startPos, pos), radix));
|
|
4540
|
+
this.pos = pos;
|
|
4541
|
+
}
|
|
4542
|
+
return valid;
|
|
4543
|
+
};
|
|
4544
|
+
TokenStream.prototype.isNumber = function() {
|
|
4545
|
+
var valid = false;
|
|
4546
|
+
var pos = this.pos;
|
|
4547
|
+
var startPos = pos;
|
|
4548
|
+
var resetPos = pos;
|
|
4549
|
+
var foundDot = false;
|
|
4550
|
+
var foundDigits = false;
|
|
4551
|
+
var c;
|
|
4552
|
+
while (pos < this.expression.length) {
|
|
4553
|
+
c = this.expression.charAt(pos);
|
|
4554
|
+
if (c >= "0" && c <= "9" || !foundDot && c === ".") {
|
|
4555
|
+
if (c === ".") {
|
|
4556
|
+
foundDot = true;
|
|
4557
|
+
} else {
|
|
4558
|
+
foundDigits = true;
|
|
4559
|
+
}
|
|
4560
|
+
pos++;
|
|
4561
|
+
valid = foundDigits;
|
|
4562
|
+
} else {
|
|
4563
|
+
break;
|
|
4564
|
+
}
|
|
4565
|
+
}
|
|
4566
|
+
if (valid) {
|
|
4567
|
+
resetPos = pos;
|
|
4568
|
+
}
|
|
4569
|
+
if (c === "e" || c === "E") {
|
|
4570
|
+
pos++;
|
|
4571
|
+
var acceptSign = true;
|
|
4572
|
+
var validExponent = false;
|
|
4573
|
+
while (pos < this.expression.length) {
|
|
4574
|
+
c = this.expression.charAt(pos);
|
|
4575
|
+
if (acceptSign && (c === "+" || c === "-")) {
|
|
4576
|
+
acceptSign = false;
|
|
4577
|
+
} else if (c >= "0" && c <= "9") {
|
|
4578
|
+
validExponent = true;
|
|
4579
|
+
acceptSign = false;
|
|
4580
|
+
} else {
|
|
4581
|
+
break;
|
|
4582
|
+
}
|
|
4583
|
+
pos++;
|
|
4584
|
+
}
|
|
4585
|
+
if (!validExponent) {
|
|
4586
|
+
pos = resetPos;
|
|
4587
|
+
}
|
|
4588
|
+
}
|
|
4589
|
+
if (valid) {
|
|
4590
|
+
this.current = this.newToken(TNUMBER, parseFloat(this.expression.substring(startPos, pos)));
|
|
4591
|
+
this.pos = pos;
|
|
4592
|
+
} else {
|
|
4593
|
+
this.pos = resetPos;
|
|
4594
|
+
}
|
|
4595
|
+
return valid;
|
|
4596
|
+
};
|
|
4597
|
+
TokenStream.prototype.isOperator = function() {
|
|
4598
|
+
var startPos = this.pos;
|
|
4599
|
+
var c = this.expression.charAt(this.pos);
|
|
4600
|
+
if (c === "+" || c === "-" || c === "*" || c === "/" || c === "%" || c === "^" || c === "?" || c === ":" || c === ".") {
|
|
4601
|
+
this.current = this.newToken(TOP, c);
|
|
4602
|
+
} else if (c === "∙" || c === "•") {
|
|
4603
|
+
this.current = this.newToken(TOP, "*");
|
|
4604
|
+
} else if (c === ">") {
|
|
4605
|
+
if (this.expression.charAt(this.pos + 1) === "=") {
|
|
4606
|
+
this.current = this.newToken(TOP, ">=");
|
|
4607
|
+
this.pos++;
|
|
4608
|
+
} else {
|
|
4609
|
+
this.current = this.newToken(TOP, ">");
|
|
4610
|
+
}
|
|
4611
|
+
} else if (c === "<") {
|
|
4612
|
+
if (this.expression.charAt(this.pos + 1) === "=") {
|
|
4613
|
+
this.current = this.newToken(TOP, "<=");
|
|
4614
|
+
this.pos++;
|
|
4615
|
+
} else {
|
|
4616
|
+
this.current = this.newToken(TOP, "<");
|
|
4617
|
+
}
|
|
4618
|
+
} else if (c === "|") {
|
|
4619
|
+
if (this.expression.charAt(this.pos + 1) === "|") {
|
|
4620
|
+
this.current = this.newToken(TOP, "||");
|
|
4621
|
+
this.pos++;
|
|
4622
|
+
} else {
|
|
4623
|
+
return false;
|
|
4624
|
+
}
|
|
4625
|
+
} else if (c === "=") {
|
|
4626
|
+
if (this.expression.charAt(this.pos + 1) === "=") {
|
|
4627
|
+
this.current = this.newToken(TOP, "==");
|
|
4628
|
+
this.pos++;
|
|
4629
|
+
} else {
|
|
4630
|
+
this.current = this.newToken(TOP, c);
|
|
4631
|
+
}
|
|
4632
|
+
} else if (c === "!") {
|
|
4633
|
+
if (this.expression.charAt(this.pos + 1) === "=") {
|
|
4634
|
+
this.current = this.newToken(TOP, "!=");
|
|
4635
|
+
this.pos++;
|
|
4636
|
+
} else {
|
|
4637
|
+
this.current = this.newToken(TOP, c);
|
|
4638
|
+
}
|
|
4639
|
+
} else {
|
|
4640
|
+
return false;
|
|
4641
|
+
}
|
|
4642
|
+
this.pos++;
|
|
4643
|
+
if (this.isOperatorEnabled(this.current.value)) {
|
|
4644
|
+
return true;
|
|
4645
|
+
} else {
|
|
4646
|
+
this.pos = startPos;
|
|
4647
|
+
return false;
|
|
4648
|
+
}
|
|
4649
|
+
};
|
|
4650
|
+
TokenStream.prototype.isOperatorEnabled = function(op) {
|
|
4651
|
+
return this.parser.isOperatorEnabled(op);
|
|
4652
|
+
};
|
|
4653
|
+
TokenStream.prototype.getCoordinates = function() {
|
|
4654
|
+
var line = 0;
|
|
4655
|
+
var column;
|
|
4656
|
+
var newline = -1;
|
|
4657
|
+
do {
|
|
4658
|
+
line++;
|
|
4659
|
+
column = this.pos - newline;
|
|
4660
|
+
newline = this.expression.indexOf("\n", newline + 1);
|
|
4661
|
+
} while (newline >= 0 && newline < this.pos);
|
|
4662
|
+
return {
|
|
4663
|
+
line,
|
|
4664
|
+
column
|
|
4665
|
+
};
|
|
4666
|
+
};
|
|
4667
|
+
TokenStream.prototype.parseError = function(msg) {
|
|
4668
|
+
var coords = this.getCoordinates();
|
|
4669
|
+
throw new Error("parse error [" + coords.line + ":" + coords.column + "]: " + msg);
|
|
4670
|
+
};
|
|
4671
|
+
function ParserState(parser, tokenStream, options) {
|
|
4672
|
+
this.parser = parser;
|
|
4673
|
+
this.tokens = tokenStream;
|
|
4674
|
+
this.current = null;
|
|
4675
|
+
this.nextToken = null;
|
|
4676
|
+
this.next();
|
|
4677
|
+
this.savedCurrent = null;
|
|
4678
|
+
this.savedNextToken = null;
|
|
4679
|
+
this.allowMemberAccess = options.allowMemberAccess !== false;
|
|
4680
|
+
}
|
|
4681
|
+
ParserState.prototype.next = function() {
|
|
4682
|
+
this.current = this.nextToken;
|
|
4683
|
+
return this.nextToken = this.tokens.next();
|
|
4684
|
+
};
|
|
4685
|
+
ParserState.prototype.tokenMatches = function(token, value) {
|
|
4686
|
+
if (typeof value === "undefined") {
|
|
4687
|
+
return true;
|
|
4688
|
+
} else if (Array.isArray(value)) {
|
|
4689
|
+
return contains(value, token.value);
|
|
4690
|
+
} else if (typeof value === "function") {
|
|
4691
|
+
return value(token);
|
|
4692
|
+
} else {
|
|
4693
|
+
return token.value === value;
|
|
4694
|
+
}
|
|
4695
|
+
};
|
|
4696
|
+
ParserState.prototype.save = function() {
|
|
4697
|
+
this.savedCurrent = this.current;
|
|
4698
|
+
this.savedNextToken = this.nextToken;
|
|
4699
|
+
this.tokens.save();
|
|
4700
|
+
};
|
|
4701
|
+
ParserState.prototype.restore = function() {
|
|
4702
|
+
this.tokens.restore();
|
|
4703
|
+
this.current = this.savedCurrent;
|
|
4704
|
+
this.nextToken = this.savedNextToken;
|
|
4705
|
+
};
|
|
4706
|
+
ParserState.prototype.accept = function(type, value) {
|
|
4707
|
+
if (this.nextToken.type === type && this.tokenMatches(this.nextToken, value)) {
|
|
4708
|
+
this.next();
|
|
4709
|
+
return true;
|
|
4710
|
+
}
|
|
4711
|
+
return false;
|
|
4712
|
+
};
|
|
4713
|
+
ParserState.prototype.expect = function(type, value) {
|
|
4714
|
+
if (!this.accept(type, value)) {
|
|
4715
|
+
var coords = this.tokens.getCoordinates();
|
|
4716
|
+
throw new Error("parse error [" + coords.line + ":" + coords.column + "]: Expected " + (value || type));
|
|
4717
|
+
}
|
|
4718
|
+
};
|
|
4719
|
+
ParserState.prototype.parseAtom = function(instr) {
|
|
4720
|
+
var unaryOps = this.tokens.unaryOps;
|
|
4721
|
+
function isPrefixOperator(token) {
|
|
4722
|
+
return token.value in unaryOps;
|
|
4723
|
+
}
|
|
4724
|
+
if (this.accept(TNAME) || this.accept(TOP, isPrefixOperator)) {
|
|
4725
|
+
instr.push(new Instruction(IVAR, this.current.value));
|
|
4726
|
+
} else if (this.accept(TNUMBER)) {
|
|
4727
|
+
instr.push(new Instruction(INUMBER, this.current.value));
|
|
4728
|
+
} else if (this.accept(TSTRING)) {
|
|
4729
|
+
instr.push(new Instruction(INUMBER, this.current.value));
|
|
4730
|
+
} else if (this.accept(TPAREN, "(")) {
|
|
4731
|
+
this.parseExpression(instr);
|
|
4732
|
+
this.expect(TPAREN, ")");
|
|
4733
|
+
} else if (this.accept(TBRACKET, "[")) {
|
|
4734
|
+
if (this.accept(TBRACKET, "]")) {
|
|
4735
|
+
instr.push(new Instruction(IARRAY, 0));
|
|
4736
|
+
} else {
|
|
4737
|
+
var argCount = this.parseArrayList(instr);
|
|
4738
|
+
instr.push(new Instruction(IARRAY, argCount));
|
|
4739
|
+
}
|
|
4740
|
+
} else {
|
|
4741
|
+
throw new Error("unexpected " + this.nextToken);
|
|
4742
|
+
}
|
|
4743
|
+
};
|
|
4744
|
+
ParserState.prototype.parseExpression = function(instr) {
|
|
4745
|
+
var exprInstr = [];
|
|
4746
|
+
if (this.parseUntilEndStatement(instr, exprInstr)) {
|
|
4747
|
+
return;
|
|
4748
|
+
}
|
|
4749
|
+
this.parseVariableAssignmentExpression(exprInstr);
|
|
4750
|
+
if (this.parseUntilEndStatement(instr, exprInstr)) {
|
|
4751
|
+
return;
|
|
4752
|
+
}
|
|
4753
|
+
this.pushExpression(instr, exprInstr);
|
|
4754
|
+
};
|
|
4755
|
+
ParserState.prototype.pushExpression = function(instr, exprInstr) {
|
|
4756
|
+
for (var i = 0, len2 = exprInstr.length; i < len2; i++) {
|
|
4757
|
+
instr.push(exprInstr[i]);
|
|
4758
|
+
}
|
|
4759
|
+
};
|
|
4760
|
+
ParserState.prototype.parseUntilEndStatement = function(instr, exprInstr) {
|
|
4761
|
+
if (!this.accept(TSEMICOLON)) return false;
|
|
4762
|
+
if (this.nextToken && this.nextToken.type !== TEOF && !(this.nextToken.type === TPAREN && this.nextToken.value === ")")) {
|
|
4763
|
+
exprInstr.push(new Instruction(IENDSTATEMENT));
|
|
4764
|
+
}
|
|
4765
|
+
if (this.nextToken.type !== TEOF) {
|
|
4766
|
+
this.parseExpression(exprInstr);
|
|
4767
|
+
}
|
|
4768
|
+
instr.push(new Instruction(IEXPR, exprInstr));
|
|
4769
|
+
return true;
|
|
4770
|
+
};
|
|
4771
|
+
ParserState.prototype.parseArrayList = function(instr) {
|
|
4772
|
+
var argCount = 0;
|
|
4773
|
+
while (!this.accept(TBRACKET, "]")) {
|
|
4774
|
+
this.parseExpression(instr);
|
|
4775
|
+
++argCount;
|
|
4776
|
+
while (this.accept(TCOMMA)) {
|
|
4777
|
+
this.parseExpression(instr);
|
|
4778
|
+
++argCount;
|
|
4779
|
+
}
|
|
4780
|
+
}
|
|
4781
|
+
return argCount;
|
|
4782
|
+
};
|
|
4783
|
+
ParserState.prototype.parseVariableAssignmentExpression = function(instr) {
|
|
4784
|
+
this.parseConditionalExpression(instr);
|
|
4785
|
+
while (this.accept(TOP, "=")) {
|
|
4786
|
+
var varName = instr.pop();
|
|
4787
|
+
var varValue = [];
|
|
4788
|
+
var lastInstrIndex = instr.length - 1;
|
|
4789
|
+
if (varName.type === IFUNCALL) {
|
|
4790
|
+
if (!this.tokens.isOperatorEnabled("()=")) {
|
|
4791
|
+
throw new Error("function definition is not permitted");
|
|
4792
|
+
}
|
|
4793
|
+
for (var i = 0, len2 = varName.value + 1; i < len2; i++) {
|
|
4794
|
+
var index2 = lastInstrIndex - i;
|
|
4795
|
+
if (instr[index2].type === IVAR) {
|
|
4796
|
+
instr[index2] = new Instruction(IVARNAME, instr[index2].value);
|
|
4797
|
+
}
|
|
4798
|
+
}
|
|
4799
|
+
this.parseVariableAssignmentExpression(varValue);
|
|
4800
|
+
instr.push(new Instruction(IEXPR, varValue));
|
|
4801
|
+
instr.push(new Instruction(IFUNDEF, varName.value));
|
|
4802
|
+
continue;
|
|
4803
|
+
}
|
|
4804
|
+
if (varName.type !== IVAR && varName.type !== IMEMBER) {
|
|
4805
|
+
throw new Error("expected variable for assignment");
|
|
4806
|
+
}
|
|
4807
|
+
this.parseVariableAssignmentExpression(varValue);
|
|
4808
|
+
instr.push(new Instruction(IVARNAME, varName.value));
|
|
4809
|
+
instr.push(new Instruction(IEXPR, varValue));
|
|
4810
|
+
instr.push(binaryInstruction("="));
|
|
4811
|
+
}
|
|
4812
|
+
};
|
|
4813
|
+
ParserState.prototype.parseConditionalExpression = function(instr) {
|
|
4814
|
+
this.parseOrExpression(instr);
|
|
4815
|
+
while (this.accept(TOP, "?")) {
|
|
4816
|
+
var trueBranch = [];
|
|
4817
|
+
var falseBranch = [];
|
|
4818
|
+
this.parseConditionalExpression(trueBranch);
|
|
4819
|
+
this.expect(TOP, ":");
|
|
4820
|
+
this.parseConditionalExpression(falseBranch);
|
|
4821
|
+
instr.push(new Instruction(IEXPR, trueBranch));
|
|
4822
|
+
instr.push(new Instruction(IEXPR, falseBranch));
|
|
4823
|
+
instr.push(ternaryInstruction("?"));
|
|
4824
|
+
}
|
|
4825
|
+
};
|
|
4826
|
+
ParserState.prototype.parseOrExpression = function(instr) {
|
|
4827
|
+
this.parseAndExpression(instr);
|
|
4828
|
+
while (this.accept(TOP, "or")) {
|
|
4829
|
+
var falseBranch = [];
|
|
4830
|
+
this.parseAndExpression(falseBranch);
|
|
4831
|
+
instr.push(new Instruction(IEXPR, falseBranch));
|
|
4832
|
+
instr.push(binaryInstruction("or"));
|
|
4833
|
+
}
|
|
4834
|
+
};
|
|
4835
|
+
ParserState.prototype.parseAndExpression = function(instr) {
|
|
4836
|
+
this.parseComparison(instr);
|
|
4837
|
+
while (this.accept(TOP, "and")) {
|
|
4838
|
+
var trueBranch = [];
|
|
4839
|
+
this.parseComparison(trueBranch);
|
|
4840
|
+
instr.push(new Instruction(IEXPR, trueBranch));
|
|
4841
|
+
instr.push(binaryInstruction("and"));
|
|
4842
|
+
}
|
|
4843
|
+
};
|
|
4844
|
+
var COMPARISON_OPERATORS = ["==", "!=", "<", "<=", ">=", ">", "in"];
|
|
4845
|
+
ParserState.prototype.parseComparison = function(instr) {
|
|
4846
|
+
this.parseAddSub(instr);
|
|
4847
|
+
while (this.accept(TOP, COMPARISON_OPERATORS)) {
|
|
4848
|
+
var op = this.current;
|
|
4849
|
+
this.parseAddSub(instr);
|
|
4850
|
+
instr.push(binaryInstruction(op.value));
|
|
4851
|
+
}
|
|
4852
|
+
};
|
|
4853
|
+
var ADD_SUB_OPERATORS = ["+", "-", "||"];
|
|
4854
|
+
ParserState.prototype.parseAddSub = function(instr) {
|
|
4855
|
+
this.parseTerm(instr);
|
|
4856
|
+
while (this.accept(TOP, ADD_SUB_OPERATORS)) {
|
|
4857
|
+
var op = this.current;
|
|
4858
|
+
this.parseTerm(instr);
|
|
4859
|
+
instr.push(binaryInstruction(op.value));
|
|
4860
|
+
}
|
|
4861
|
+
};
|
|
4862
|
+
var TERM_OPERATORS = ["*", "/", "%"];
|
|
4863
|
+
ParserState.prototype.parseTerm = function(instr) {
|
|
4864
|
+
this.parseFactor(instr);
|
|
4865
|
+
while (this.accept(TOP, TERM_OPERATORS)) {
|
|
4866
|
+
var op = this.current;
|
|
4867
|
+
this.parseFactor(instr);
|
|
4868
|
+
instr.push(binaryInstruction(op.value));
|
|
4869
|
+
}
|
|
4870
|
+
};
|
|
4871
|
+
ParserState.prototype.parseFactor = function(instr) {
|
|
4872
|
+
var unaryOps = this.tokens.unaryOps;
|
|
4873
|
+
function isPrefixOperator(token) {
|
|
4874
|
+
return token.value in unaryOps;
|
|
4875
|
+
}
|
|
4876
|
+
this.save();
|
|
4877
|
+
if (this.accept(TOP, isPrefixOperator)) {
|
|
4878
|
+
if (this.current.value !== "-" && this.current.value !== "+") {
|
|
4879
|
+
if (this.nextToken.type === TPAREN && this.nextToken.value === "(") {
|
|
4880
|
+
this.restore();
|
|
4881
|
+
this.parseExponential(instr);
|
|
4882
|
+
return;
|
|
4883
|
+
} else if (this.nextToken.type === TSEMICOLON || this.nextToken.type === TCOMMA || this.nextToken.type === TEOF || this.nextToken.type === TPAREN && this.nextToken.value === ")") {
|
|
4884
|
+
this.restore();
|
|
4885
|
+
this.parseAtom(instr);
|
|
4886
|
+
return;
|
|
4887
|
+
}
|
|
4888
|
+
}
|
|
4889
|
+
var op = this.current;
|
|
4890
|
+
this.parseFactor(instr);
|
|
4891
|
+
instr.push(unaryInstruction(op.value));
|
|
4892
|
+
} else {
|
|
4893
|
+
this.parseExponential(instr);
|
|
4894
|
+
}
|
|
4895
|
+
};
|
|
4896
|
+
ParserState.prototype.parseExponential = function(instr) {
|
|
4897
|
+
this.parsePostfixExpression(instr);
|
|
4898
|
+
while (this.accept(TOP, "^")) {
|
|
4899
|
+
this.parseFactor(instr);
|
|
4900
|
+
instr.push(binaryInstruction("^"));
|
|
4901
|
+
}
|
|
4902
|
+
};
|
|
4903
|
+
ParserState.prototype.parsePostfixExpression = function(instr) {
|
|
4904
|
+
this.parseFunctionCall(instr);
|
|
4905
|
+
while (this.accept(TOP, "!")) {
|
|
4906
|
+
instr.push(unaryInstruction("!"));
|
|
4907
|
+
}
|
|
4908
|
+
};
|
|
4909
|
+
ParserState.prototype.parseFunctionCall = function(instr) {
|
|
4910
|
+
var unaryOps = this.tokens.unaryOps;
|
|
4911
|
+
function isPrefixOperator(token) {
|
|
4912
|
+
return token.value in unaryOps;
|
|
4913
|
+
}
|
|
4914
|
+
if (this.accept(TOP, isPrefixOperator)) {
|
|
4915
|
+
var op = this.current;
|
|
4916
|
+
this.parseAtom(instr);
|
|
4917
|
+
instr.push(unaryInstruction(op.value));
|
|
4918
|
+
} else {
|
|
4919
|
+
this.parseMemberExpression(instr);
|
|
4920
|
+
while (this.accept(TPAREN, "(")) {
|
|
4921
|
+
if (this.accept(TPAREN, ")")) {
|
|
4922
|
+
instr.push(new Instruction(IFUNCALL, 0));
|
|
4923
|
+
} else {
|
|
4924
|
+
var argCount = this.parseArgumentList(instr);
|
|
4925
|
+
instr.push(new Instruction(IFUNCALL, argCount));
|
|
4926
|
+
}
|
|
4927
|
+
}
|
|
4928
|
+
}
|
|
4929
|
+
};
|
|
4930
|
+
ParserState.prototype.parseArgumentList = function(instr) {
|
|
4931
|
+
var argCount = 0;
|
|
4932
|
+
while (!this.accept(TPAREN, ")")) {
|
|
4933
|
+
this.parseExpression(instr);
|
|
4934
|
+
++argCount;
|
|
4935
|
+
while (this.accept(TCOMMA)) {
|
|
4936
|
+
this.parseExpression(instr);
|
|
4937
|
+
++argCount;
|
|
4938
|
+
}
|
|
4939
|
+
}
|
|
4940
|
+
return argCount;
|
|
4941
|
+
};
|
|
4942
|
+
ParserState.prototype.parseMemberExpression = function(instr) {
|
|
4943
|
+
this.parseAtom(instr);
|
|
4944
|
+
while (this.accept(TOP, ".") || this.accept(TBRACKET, "[")) {
|
|
4945
|
+
var op = this.current;
|
|
4946
|
+
if (op.value === ".") {
|
|
4947
|
+
if (!this.allowMemberAccess) {
|
|
4948
|
+
throw new Error('unexpected ".", member access is not permitted');
|
|
4949
|
+
}
|
|
4950
|
+
this.expect(TNAME);
|
|
4951
|
+
instr.push(new Instruction(IMEMBER, this.current.value));
|
|
4952
|
+
} else if (op.value === "[") {
|
|
4953
|
+
if (!this.tokens.isOperatorEnabled("[")) {
|
|
4954
|
+
throw new Error('unexpected "[]", arrays are disabled');
|
|
4955
|
+
}
|
|
4956
|
+
this.parseExpression(instr);
|
|
4957
|
+
this.expect(TBRACKET, "]");
|
|
4958
|
+
instr.push(binaryInstruction("["));
|
|
4959
|
+
} else {
|
|
4960
|
+
throw new Error("unexpected symbol: " + op.value);
|
|
4961
|
+
}
|
|
4962
|
+
}
|
|
4963
|
+
};
|
|
4964
|
+
function add(a, b) {
|
|
4965
|
+
return Number(a) + Number(b);
|
|
4966
|
+
}
|
|
4967
|
+
function sub(a, b) {
|
|
4968
|
+
return a - b;
|
|
4969
|
+
}
|
|
4970
|
+
function mul(a, b) {
|
|
4971
|
+
return a * b;
|
|
4972
|
+
}
|
|
4973
|
+
function div(a, b) {
|
|
4974
|
+
return a / b;
|
|
4975
|
+
}
|
|
4976
|
+
function mod(a, b) {
|
|
4977
|
+
return a % b;
|
|
4978
|
+
}
|
|
4979
|
+
function concat(a, b) {
|
|
4980
|
+
if (Array.isArray(a) && Array.isArray(b)) {
|
|
4981
|
+
return a.concat(b);
|
|
4982
|
+
}
|
|
4983
|
+
return "" + a + b;
|
|
4984
|
+
}
|
|
4985
|
+
function equal(a, b) {
|
|
4986
|
+
return a === b;
|
|
4987
|
+
}
|
|
4988
|
+
function notEqual(a, b) {
|
|
4989
|
+
return a !== b;
|
|
4990
|
+
}
|
|
4991
|
+
function greaterThan(a, b) {
|
|
4992
|
+
return a > b;
|
|
4993
|
+
}
|
|
4994
|
+
function lessThan(a, b) {
|
|
4995
|
+
return a < b;
|
|
4996
|
+
}
|
|
4997
|
+
function greaterThanEqual(a, b) {
|
|
4998
|
+
return a >= b;
|
|
4999
|
+
}
|
|
5000
|
+
function lessThanEqual(a, b) {
|
|
5001
|
+
return a <= b;
|
|
5002
|
+
}
|
|
5003
|
+
function andOperator(a, b) {
|
|
5004
|
+
return Boolean(a && b);
|
|
5005
|
+
}
|
|
5006
|
+
function orOperator(a, b) {
|
|
5007
|
+
return Boolean(a || b);
|
|
5008
|
+
}
|
|
5009
|
+
function inOperator(a, b) {
|
|
5010
|
+
return contains(b, a);
|
|
5011
|
+
}
|
|
5012
|
+
function sinh(a) {
|
|
5013
|
+
return (Math.exp(a) - Math.exp(-a)) / 2;
|
|
5014
|
+
}
|
|
5015
|
+
function cosh(a) {
|
|
5016
|
+
return (Math.exp(a) + Math.exp(-a)) / 2;
|
|
5017
|
+
}
|
|
5018
|
+
function tanh(a) {
|
|
5019
|
+
if (a === Infinity) return 1;
|
|
5020
|
+
if (a === -Infinity) return -1;
|
|
5021
|
+
return (Math.exp(a) - Math.exp(-a)) / (Math.exp(a) + Math.exp(-a));
|
|
5022
|
+
}
|
|
5023
|
+
function asinh(a) {
|
|
5024
|
+
if (a === -Infinity) return a;
|
|
5025
|
+
return Math.log(a + Math.sqrt(a * a + 1));
|
|
5026
|
+
}
|
|
5027
|
+
function acosh(a) {
|
|
5028
|
+
return Math.log(a + Math.sqrt(a * a - 1));
|
|
5029
|
+
}
|
|
5030
|
+
function atanh(a) {
|
|
5031
|
+
return Math.log((1 + a) / (1 - a)) / 2;
|
|
5032
|
+
}
|
|
5033
|
+
function log10(a) {
|
|
5034
|
+
return Math.log(a) * Math.LOG10E;
|
|
5035
|
+
}
|
|
5036
|
+
function neg(a) {
|
|
5037
|
+
return -a;
|
|
5038
|
+
}
|
|
5039
|
+
function not(a) {
|
|
5040
|
+
return !a;
|
|
5041
|
+
}
|
|
5042
|
+
function trunc(a) {
|
|
5043
|
+
return a < 0 ? Math.ceil(a) : Math.floor(a);
|
|
5044
|
+
}
|
|
5045
|
+
function random(a) {
|
|
5046
|
+
return Math.random() * (a || 1);
|
|
5047
|
+
}
|
|
5048
|
+
function factorial(a) {
|
|
5049
|
+
return gamma(a + 1);
|
|
5050
|
+
}
|
|
5051
|
+
function isInteger(value) {
|
|
5052
|
+
return isFinite(value) && value === Math.round(value);
|
|
5053
|
+
}
|
|
5054
|
+
var GAMMA_G = 4.7421875;
|
|
5055
|
+
var GAMMA_P = [
|
|
5056
|
+
0.9999999999999971,
|
|
5057
|
+
57.15623566586292,
|
|
5058
|
+
-59.59796035547549,
|
|
5059
|
+
14.136097974741746,
|
|
5060
|
+
-0.4919138160976202,
|
|
5061
|
+
3399464998481189e-20,
|
|
5062
|
+
4652362892704858e-20,
|
|
5063
|
+
-9837447530487956e-20,
|
|
5064
|
+
1580887032249125e-19,
|
|
5065
|
+
-21026444172410488e-20,
|
|
5066
|
+
21743961811521265e-20,
|
|
5067
|
+
-1643181065367639e-19,
|
|
5068
|
+
8441822398385275e-20,
|
|
5069
|
+
-26190838401581408e-21,
|
|
5070
|
+
36899182659531625e-22
|
|
5071
|
+
];
|
|
5072
|
+
function gamma(n) {
|
|
5073
|
+
var t, x;
|
|
5074
|
+
if (isInteger(n)) {
|
|
5075
|
+
if (n <= 0) {
|
|
5076
|
+
return isFinite(n) ? Infinity : NaN;
|
|
5077
|
+
}
|
|
5078
|
+
if (n > 171) {
|
|
5079
|
+
return Infinity;
|
|
5080
|
+
}
|
|
5081
|
+
var value = n - 2;
|
|
5082
|
+
var res = n - 1;
|
|
5083
|
+
while (value > 1) {
|
|
5084
|
+
res *= value;
|
|
5085
|
+
value--;
|
|
5086
|
+
}
|
|
5087
|
+
if (res === 0) {
|
|
5088
|
+
res = 1;
|
|
5089
|
+
}
|
|
5090
|
+
return res;
|
|
5091
|
+
}
|
|
5092
|
+
if (n < 0.5) {
|
|
5093
|
+
return Math.PI / (Math.sin(Math.PI * n) * gamma(1 - n));
|
|
5094
|
+
}
|
|
5095
|
+
if (n >= 171.35) {
|
|
5096
|
+
return Infinity;
|
|
5097
|
+
}
|
|
5098
|
+
if (n > 85) {
|
|
5099
|
+
var twoN = n * n;
|
|
5100
|
+
var threeN = twoN * n;
|
|
5101
|
+
var fourN = threeN * n;
|
|
5102
|
+
var fiveN = fourN * n;
|
|
5103
|
+
return Math.sqrt(2 * Math.PI / n) * Math.pow(n / Math.E, n) * (1 + 1 / (12 * n) + 1 / (288 * twoN) - 139 / (51840 * threeN) - 571 / (2488320 * fourN) + 163879 / (209018880 * fiveN) + 5246819 / (75246796800 * fiveN * n));
|
|
5104
|
+
}
|
|
5105
|
+
--n;
|
|
5106
|
+
x = GAMMA_P[0];
|
|
5107
|
+
for (var i = 1; i < GAMMA_P.length; ++i) {
|
|
5108
|
+
x += GAMMA_P[i] / (n + i);
|
|
5109
|
+
}
|
|
5110
|
+
t = n + GAMMA_G + 0.5;
|
|
5111
|
+
return Math.sqrt(2 * Math.PI) * Math.pow(t, n + 0.5) * Math.exp(-t) * x;
|
|
5112
|
+
}
|
|
5113
|
+
function stringOrArrayLength(s) {
|
|
5114
|
+
if (Array.isArray(s)) {
|
|
5115
|
+
return s.length;
|
|
5116
|
+
}
|
|
5117
|
+
return String(s).length;
|
|
5118
|
+
}
|
|
5119
|
+
function hypot() {
|
|
5120
|
+
var sum2 = 0;
|
|
5121
|
+
var larg = 0;
|
|
5122
|
+
for (var i = 0; i < arguments.length; i++) {
|
|
5123
|
+
var arg = Math.abs(arguments[i]);
|
|
5124
|
+
var div2;
|
|
5125
|
+
if (larg < arg) {
|
|
5126
|
+
div2 = larg / arg;
|
|
5127
|
+
sum2 = sum2 * div2 * div2 + 1;
|
|
5128
|
+
larg = arg;
|
|
5129
|
+
} else if (arg > 0) {
|
|
5130
|
+
div2 = arg / larg;
|
|
5131
|
+
sum2 += div2 * div2;
|
|
5132
|
+
} else {
|
|
5133
|
+
sum2 += arg;
|
|
5134
|
+
}
|
|
5135
|
+
}
|
|
5136
|
+
return larg === Infinity ? Infinity : larg * Math.sqrt(sum2);
|
|
5137
|
+
}
|
|
5138
|
+
function condition(cond, yep, nope) {
|
|
5139
|
+
return cond ? yep : nope;
|
|
5140
|
+
}
|
|
5141
|
+
function roundTo(value, exp) {
|
|
5142
|
+
if (typeof exp === "undefined" || +exp === 0) {
|
|
5143
|
+
return Math.round(value);
|
|
5144
|
+
}
|
|
5145
|
+
value = +value;
|
|
5146
|
+
exp = -+exp;
|
|
5147
|
+
if (isNaN(value) || !(typeof exp === "number" && exp % 1 === 0)) {
|
|
5148
|
+
return NaN;
|
|
5149
|
+
}
|
|
5150
|
+
value = value.toString().split("e");
|
|
5151
|
+
value = Math.round(+(value[0] + "e" + (value[1] ? +value[1] - exp : -exp)));
|
|
5152
|
+
value = value.toString().split("e");
|
|
5153
|
+
return +(value[0] + "e" + (value[1] ? +value[1] + exp : exp));
|
|
5154
|
+
}
|
|
5155
|
+
function setVar(name, value, variables) {
|
|
5156
|
+
if (variables) variables[name] = value;
|
|
5157
|
+
return value;
|
|
5158
|
+
}
|
|
5159
|
+
function arrayIndex(array, index2) {
|
|
5160
|
+
return array[index2 | 0];
|
|
5161
|
+
}
|
|
5162
|
+
function max(array) {
|
|
5163
|
+
if (arguments.length === 1 && Array.isArray(array)) {
|
|
5164
|
+
return Math.max.apply(Math, array);
|
|
5165
|
+
} else {
|
|
5166
|
+
return Math.max.apply(Math, arguments);
|
|
5167
|
+
}
|
|
5168
|
+
}
|
|
5169
|
+
function min(array) {
|
|
5170
|
+
if (arguments.length === 1 && Array.isArray(array)) {
|
|
5171
|
+
return Math.min.apply(Math, array);
|
|
5172
|
+
} else {
|
|
5173
|
+
return Math.min.apply(Math, arguments);
|
|
5174
|
+
}
|
|
5175
|
+
}
|
|
5176
|
+
function arrayMap(f, a) {
|
|
5177
|
+
if (typeof f !== "function") {
|
|
5178
|
+
throw new Error("First argument to map is not a function");
|
|
5179
|
+
}
|
|
5180
|
+
if (!Array.isArray(a)) {
|
|
5181
|
+
throw new Error("Second argument to map is not an array");
|
|
5182
|
+
}
|
|
5183
|
+
return a.map(function(x, i) {
|
|
5184
|
+
return f(x, i);
|
|
5185
|
+
});
|
|
5186
|
+
}
|
|
5187
|
+
function arrayFold(f, init, a) {
|
|
5188
|
+
if (typeof f !== "function") {
|
|
5189
|
+
throw new Error("First argument to fold is not a function");
|
|
5190
|
+
}
|
|
5191
|
+
if (!Array.isArray(a)) {
|
|
5192
|
+
throw new Error("Second argument to fold is not an array");
|
|
5193
|
+
}
|
|
5194
|
+
return a.reduce(function(acc, x, i) {
|
|
5195
|
+
return f(acc, x, i);
|
|
5196
|
+
}, init);
|
|
5197
|
+
}
|
|
5198
|
+
function arrayFilter(f, a) {
|
|
5199
|
+
if (typeof f !== "function") {
|
|
5200
|
+
throw new Error("First argument to filter is not a function");
|
|
5201
|
+
}
|
|
5202
|
+
if (!Array.isArray(a)) {
|
|
5203
|
+
throw new Error("Second argument to filter is not an array");
|
|
5204
|
+
}
|
|
5205
|
+
return a.filter(function(x, i) {
|
|
5206
|
+
return f(x, i);
|
|
5207
|
+
});
|
|
5208
|
+
}
|
|
5209
|
+
function stringOrArrayIndexOf(target, s) {
|
|
5210
|
+
if (!(Array.isArray(s) || typeof s === "string")) {
|
|
5211
|
+
throw new Error("Second argument to indexOf is not a string or array");
|
|
5212
|
+
}
|
|
5213
|
+
return s.indexOf(target);
|
|
5214
|
+
}
|
|
5215
|
+
function arrayJoin(sep, a) {
|
|
5216
|
+
if (!Array.isArray(a)) {
|
|
5217
|
+
throw new Error("Second argument to join is not an array");
|
|
5218
|
+
}
|
|
5219
|
+
return a.join(sep);
|
|
5220
|
+
}
|
|
5221
|
+
function sign(x) {
|
|
5222
|
+
return (x > 0) - (x < 0) || +x;
|
|
5223
|
+
}
|
|
5224
|
+
var ONE_THIRD = 1 / 3;
|
|
5225
|
+
function cbrt(x) {
|
|
5226
|
+
return x < 0 ? -Math.pow(-x, ONE_THIRD) : Math.pow(x, ONE_THIRD);
|
|
5227
|
+
}
|
|
5228
|
+
function expm1(x) {
|
|
5229
|
+
return Math.exp(x) - 1;
|
|
5230
|
+
}
|
|
5231
|
+
function log1p(x) {
|
|
5232
|
+
return Math.log(1 + x);
|
|
5233
|
+
}
|
|
5234
|
+
function log2(x) {
|
|
5235
|
+
return Math.log(x) / Math.LN2;
|
|
5236
|
+
}
|
|
5237
|
+
function Parser(options) {
|
|
5238
|
+
this.options = options || {};
|
|
5239
|
+
this.unaryOps = {
|
|
5240
|
+
sin: Math.sin,
|
|
5241
|
+
cos: Math.cos,
|
|
5242
|
+
tan: Math.tan,
|
|
5243
|
+
asin: Math.asin,
|
|
5244
|
+
acos: Math.acos,
|
|
5245
|
+
atan: Math.atan,
|
|
5246
|
+
sinh: Math.sinh || sinh,
|
|
5247
|
+
cosh: Math.cosh || cosh,
|
|
5248
|
+
tanh: Math.tanh || tanh,
|
|
5249
|
+
asinh: Math.asinh || asinh,
|
|
5250
|
+
acosh: Math.acosh || acosh,
|
|
5251
|
+
atanh: Math.atanh || atanh,
|
|
5252
|
+
sqrt: Math.sqrt,
|
|
5253
|
+
cbrt: Math.cbrt || cbrt,
|
|
5254
|
+
log: Math.log,
|
|
5255
|
+
log2: Math.log2 || log2,
|
|
5256
|
+
ln: Math.log,
|
|
5257
|
+
lg: Math.log10 || log10,
|
|
5258
|
+
log10: Math.log10 || log10,
|
|
5259
|
+
expm1: Math.expm1 || expm1,
|
|
5260
|
+
log1p: Math.log1p || log1p,
|
|
5261
|
+
abs: Math.abs,
|
|
5262
|
+
ceil: Math.ceil,
|
|
5263
|
+
floor: Math.floor,
|
|
5264
|
+
round: Math.round,
|
|
5265
|
+
trunc: Math.trunc || trunc,
|
|
5266
|
+
"-": neg,
|
|
5267
|
+
"+": Number,
|
|
5268
|
+
exp: Math.exp,
|
|
5269
|
+
not,
|
|
5270
|
+
length: stringOrArrayLength,
|
|
5271
|
+
"!": factorial,
|
|
5272
|
+
sign: Math.sign || sign
|
|
5273
|
+
};
|
|
5274
|
+
this.binaryOps = {
|
|
5275
|
+
"+": add,
|
|
5276
|
+
"-": sub,
|
|
5277
|
+
"*": mul,
|
|
5278
|
+
"/": div,
|
|
5279
|
+
"%": mod,
|
|
5280
|
+
"^": Math.pow,
|
|
5281
|
+
"||": concat,
|
|
5282
|
+
"==": equal,
|
|
5283
|
+
"!=": notEqual,
|
|
5284
|
+
">": greaterThan,
|
|
5285
|
+
"<": lessThan,
|
|
5286
|
+
">=": greaterThanEqual,
|
|
5287
|
+
"<=": lessThanEqual,
|
|
5288
|
+
and: andOperator,
|
|
5289
|
+
or: orOperator,
|
|
5290
|
+
"in": inOperator,
|
|
5291
|
+
"=": setVar,
|
|
5292
|
+
"[": arrayIndex
|
|
5293
|
+
};
|
|
5294
|
+
this.ternaryOps = {
|
|
5295
|
+
"?": condition
|
|
5296
|
+
};
|
|
5297
|
+
this.functions = {
|
|
5298
|
+
random,
|
|
5299
|
+
fac: factorial,
|
|
5300
|
+
min,
|
|
5301
|
+
max,
|
|
5302
|
+
hypot: Math.hypot || hypot,
|
|
5303
|
+
pyt: Math.hypot || hypot,
|
|
5304
|
+
// backward compat
|
|
5305
|
+
pow: Math.pow,
|
|
5306
|
+
atan2: Math.atan2,
|
|
5307
|
+
"if": condition,
|
|
5308
|
+
gamma,
|
|
5309
|
+
roundTo,
|
|
5310
|
+
map: arrayMap,
|
|
5311
|
+
fold: arrayFold,
|
|
5312
|
+
filter: arrayFilter,
|
|
5313
|
+
indexOf: stringOrArrayIndexOf,
|
|
5314
|
+
join: arrayJoin
|
|
5315
|
+
};
|
|
5316
|
+
this.consts = {
|
|
5317
|
+
E: Math.E,
|
|
5318
|
+
PI: Math.PI,
|
|
5319
|
+
"true": true,
|
|
5320
|
+
"false": false
|
|
5321
|
+
};
|
|
5322
|
+
}
|
|
5323
|
+
Parser.prototype.parse = function(expr) {
|
|
5324
|
+
var instr = [];
|
|
5325
|
+
var parserState = new ParserState(
|
|
5326
|
+
this,
|
|
5327
|
+
new TokenStream(this, expr),
|
|
5328
|
+
{ allowMemberAccess: this.options.allowMemberAccess }
|
|
5329
|
+
);
|
|
5330
|
+
parserState.parseExpression(instr);
|
|
5331
|
+
parserState.expect(TEOF, "EOF");
|
|
5332
|
+
return new Expression(instr, this);
|
|
5333
|
+
};
|
|
5334
|
+
Parser.prototype.evaluate = function(expr, variables) {
|
|
5335
|
+
return this.parse(expr).evaluate(variables);
|
|
5336
|
+
};
|
|
5337
|
+
var sharedParser = new Parser();
|
|
5338
|
+
Parser.parse = function(expr) {
|
|
5339
|
+
return sharedParser.parse(expr);
|
|
5340
|
+
};
|
|
5341
|
+
Parser.evaluate = function(expr, variables) {
|
|
5342
|
+
return sharedParser.parse(expr).evaluate(variables);
|
|
5343
|
+
};
|
|
5344
|
+
var optionNameMap = {
|
|
5345
|
+
"+": "add",
|
|
5346
|
+
"-": "subtract",
|
|
5347
|
+
"*": "multiply",
|
|
5348
|
+
"/": "divide",
|
|
5349
|
+
"%": "remainder",
|
|
5350
|
+
"^": "power",
|
|
5351
|
+
"!": "factorial",
|
|
5352
|
+
"<": "comparison",
|
|
5353
|
+
">": "comparison",
|
|
5354
|
+
"<=": "comparison",
|
|
5355
|
+
">=": "comparison",
|
|
5356
|
+
"==": "comparison",
|
|
5357
|
+
"!=": "comparison",
|
|
5358
|
+
"||": "concatenate",
|
|
5359
|
+
"and": "logical",
|
|
5360
|
+
"or": "logical",
|
|
5361
|
+
"not": "logical",
|
|
5362
|
+
"?": "conditional",
|
|
5363
|
+
":": "conditional",
|
|
5364
|
+
"=": "assignment",
|
|
5365
|
+
"[": "array",
|
|
5366
|
+
"()=": "fndef"
|
|
5367
|
+
};
|
|
5368
|
+
function getOptionName(op) {
|
|
5369
|
+
return optionNameMap.hasOwnProperty(op) ? optionNameMap[op] : op;
|
|
5370
|
+
}
|
|
5371
|
+
Parser.prototype.isOperatorEnabled = function(op) {
|
|
5372
|
+
var optionName = getOptionName(op);
|
|
5373
|
+
var operators2 = this.options.operators || {};
|
|
5374
|
+
return !(optionName in operators2) || !!operators2[optionName];
|
|
5375
|
+
};
|
|
5376
|
+
const calc = (expression, context) => {
|
|
5377
|
+
if (typeof expression !== "string") {
|
|
5378
|
+
return expression;
|
|
5379
|
+
}
|
|
5380
|
+
let processedExpression = expression;
|
|
5381
|
+
try {
|
|
5382
|
+
const pathResolver = (path) => {
|
|
5383
|
+
let currentPath = path;
|
|
5384
|
+
let value;
|
|
5385
|
+
let depth = 0;
|
|
5386
|
+
while (typeof currentPath === "string" && (currentPath.startsWith("/") || currentPath.startsWith("=/")) && depth < 5) {
|
|
5387
|
+
const normalizedPath = currentPath.startsWith("/") ? "=" + currentPath : currentPath;
|
|
5388
|
+
const resolved = resolvePath(normalizedPath, context);
|
|
5389
|
+
value = unwrapSignal(resolved);
|
|
5390
|
+
if (typeof value === "string" && (value.startsWith("/") || value.startsWith("=/")) && value !== currentPath) {
|
|
5391
|
+
currentPath = value;
|
|
5392
|
+
depth++;
|
|
5393
|
+
} else {
|
|
5394
|
+
break;
|
|
5395
|
+
}
|
|
5396
|
+
}
|
|
5397
|
+
if (typeof value === "number") return value;
|
|
5398
|
+
if (typeof value === "string") {
|
|
5399
|
+
const num = parseFloat(value);
|
|
5400
|
+
if (!isNaN(num) && isFinite(Number(value))) return num;
|
|
5401
|
+
return value === "" ? 0 : `"${value.replace(/"/g, '\\"')}"`;
|
|
5402
|
+
}
|
|
5403
|
+
return value === void 0 || value === null ? 0 : value;
|
|
5404
|
+
};
|
|
5405
|
+
const pathRegex = /\$\(\s*['"](.*?)['"]\s*\)/g;
|
|
5406
|
+
processedExpression = expression.replace(pathRegex, (match2, path) => {
|
|
5407
|
+
const val = pathResolver(path);
|
|
5408
|
+
return val;
|
|
5409
|
+
});
|
|
5410
|
+
const parser = new Parser();
|
|
5411
|
+
const parsed = parser.parse(processedExpression);
|
|
5412
|
+
return parsed.evaluate();
|
|
5413
|
+
} catch (error) {
|
|
5414
|
+
console.error("JPRX calc error:", error.message);
|
|
5415
|
+
console.error("Original expression:", expression);
|
|
5416
|
+
console.error("Processed expression:", processedExpression);
|
|
5417
|
+
return NaN;
|
|
5418
|
+
}
|
|
5419
|
+
};
|
|
5420
|
+
const registerCalcHelpers = (register) => {
|
|
5421
|
+
register("calc", calc, { pathAware: true });
|
|
5422
|
+
};
|
|
3723
5423
|
registerMathHelpers(registerHelper);
|
|
3724
5424
|
registerLogicHelpers(registerHelper);
|
|
3725
5425
|
registerStringHelpers(registerHelper);
|
|
@@ -3732,6 +5432,7 @@
|
|
|
3732
5432
|
registerStatsHelpers(registerHelper);
|
|
3733
5433
|
registerStateHelpers((name, fn) => registerHelper(name, fn, { pathAware: true }));
|
|
3734
5434
|
registerNetworkHelpers(registerHelper);
|
|
5435
|
+
registerCalcHelpers(registerHelper);
|
|
3735
5436
|
registerHelper("move", (selector, location = "beforeend") => {
|
|
3736
5437
|
return {
|
|
3737
5438
|
isLazy: true,
|
|
@@ -3865,8 +5566,8 @@
|
|
|
3865
5566
|
const isEvent = eventOrNode && typeof eventOrNode === "object" && "target" in eventOrNode;
|
|
3866
5567
|
const target = isEvent ? eventOrNode.currentTarget || eventOrNode.target : eventOrNode;
|
|
3867
5568
|
const context = getContext(target, isEvent ? eventOrNode : null);
|
|
3868
|
-
const result = resolveExpression(expr, context);
|
|
3869
|
-
if (result && typeof result === "object" && result.isLazy) return result.resolve(
|
|
5569
|
+
const result = resolveExpression$1(expr, context);
|
|
5570
|
+
if (result && typeof result === "object" && result.isLazy) return result.resolve(context);
|
|
3870
5571
|
return result;
|
|
3871
5572
|
};
|
|
3872
5573
|
const hydrate = (node, parent = null) => {
|
|
@@ -3952,7 +5653,7 @@
|
|
|
3952
5653
|
parseExpression,
|
|
3953
5654
|
resolvePath,
|
|
3954
5655
|
resolvePathAsContext,
|
|
3955
|
-
resolveExpression,
|
|
5656
|
+
resolveExpression: resolveExpression$1,
|
|
3956
5657
|
parseCDOMC,
|
|
3957
5658
|
parseJPRX,
|
|
3958
5659
|
unwrapSignal,
|