From f24111ea9f2bff0cc76d0a68a015ba905e28ef63 Mon Sep 17 00:00:00 2001 From: Zaid Abdulla Date: Mon, 25 Oct 2021 13:42:59 -0700 Subject: [PATCH] Support modulo operator in expressions --- lib/common/expression-parser.ts | 7 ++++++- lib/common/expression.ts | 18 +++++++++++++++--- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/lib/common/expression-parser.ts b/lib/common/expression-parser.ts index ea6b294..9802f4d 100644 --- a/lib/common/expression-parser.ts +++ b/lib/common/expression-parser.ts @@ -285,7 +285,11 @@ const lang = parsimmon.createLanguage({ .skip(parsimmon.optWhitespace), binaryLeft( parsimmon - .alt(parsimmon.string("*"), parsimmon.string("/")) + .alt( + parsimmon.string("*"), + parsimmon.string("/"), + parsimmon.string("%") + ) .skip(parsimmon.optWhitespace), parsimmon.alt( r.Value, @@ -384,6 +388,7 @@ export function stringify(exp: Expression, level = 0): string { "-": 31, "*": 32, "/": 32, + "%": 32, }; const op = exp[0].toUpperCase(); diff --git a/lib/common/expression.ts b/lib/common/expression.ts index 5b01eb6..8693ea1 100644 --- a/lib/common/expression.ts +++ b/lib/common/expression.ts @@ -244,9 +244,12 @@ export function evaluateCallback(exp: Expression): Expression { } else if (exp[0] === "/") { return reduce(exp, (a, b, i) => { if (a == null || b == null) return null; - if (!isArray(a) && !isArray(b)) - return i === 0 ? toNumber(a) / toNumber(b) : toNumber(a) * toNumber(b); - return REDUCE_SKIP; + if (isArray(a) || isArray(b)) return REDUCE_SKIP; + const n1 = toNumber(a); + const n2 = toNumber(b); + if (i !== 0) return n1 * n2; + if (n2 === 0) return null; + return n1 / n2; }); } else if (exp[0] === "+") { return reduce(exp, (a, b) => { @@ -261,6 +264,15 @@ export function evaluateCallback(exp: Expression): Expression { return i === 0 ? toNumber(a) - toNumber(b) : toNumber(a) + toNumber(b); return REDUCE_SKIP; }); + } else if (exp[0] === "%") { + return reduce(exp, (a, b, i) => { + if (a == null || b == null) return null; + if (isArray(a) || isArray(b) || i !== 0) return REDUCE_SKIP; + const n1 = toNumber(a); + const n2 = Math.trunc(toNumber(b)); + if (n2 === 0) return null; + return n1 % n2; + }); } else if (exp[0] === "||") { return reduce(exp, (a, b) => { if (a == null || b == null) return null;