cal-mcp
Version:
A MCP server for evaluating mathematical expressions
1,511 lines (1,509 loc) • 1.43 MB
JavaScript
import { createRequire } from "node:module";
var __create = Object.create;
var __getProtoOf = Object.getPrototypeOf;
var __defProp = Object.defineProperty;
var __getOwnPropNames = Object.getOwnPropertyNames;
var __hasOwnProp = Object.prototype.hasOwnProperty;
var __toESM = (mod, isNodeMode, target) => {
target = mod != null ? __create(__getProtoOf(mod)) : {};
const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
for (let key of __getOwnPropNames(mod))
if (!__hasOwnProp.call(to, key))
__defProp(to, key, {
get: () => mod[key],
enumerable: true
});
return to;
};
var __commonJS = (cb, mod) => () => (mod || cb((mod = { exports: {} }).exports, mod), mod.exports);
var __require = /* @__PURE__ */ createRequire(import.meta.url);
// node_modules/expr-eval/dist/bundle.js
var require_bundle = __commonJS((exports, module) => {
(function(global2, factory) {
typeof exports === "object" && typeof module !== "undefined" ? factory(exports) : typeof define === "function" && define.amd ? define(["exports"], factory) : (global2 = global2 || self, factory(global2.exprEval = {}));
})(exports, function(exports2) {
var INUMBER = "INUMBER";
var IOP1 = "IOP1";
var IOP2 = "IOP2";
var IOP3 = "IOP3";
var IVAR = "IVAR";
var IVARNAME = "IVARNAME";
var IFUNCALL = "IFUNCALL";
var IFUNDEF = "IFUNDEF";
var IEXPR = "IEXPR";
var IEXPREVAL = "IEXPREVAL";
var IMEMBER = "IMEMBER";
var IENDSTATEMENT = "IENDSTATEMENT";
var IARRAY = "IARRAY";
function Instruction(type, value) {
this.type = type;
this.value = value !== undefined && value !== null ? value : 0;
}
Instruction.prototype.toString = function() {
switch (this.type) {
case INUMBER:
case IOP1:
case IOP2:
case IOP3:
case IVAR:
case IVARNAME:
case IENDSTATEMENT:
return this.value;
case IFUNCALL:
return "CALL " + this.value;
case IFUNDEF:
return "DEF " + this.value;
case IARRAY:
return "ARRAY " + this.value;
case IMEMBER:
return "." + this.value;
default:
return "Invalid Instruction";
}
};
function unaryInstruction(value) {
return new Instruction(IOP1, value);
}
function binaryInstruction(value) {
return new Instruction(IOP2, value);
}
function ternaryInstruction(value) {
return new Instruction(IOP3, value);
}
function simplify(tokens, unaryOps, binaryOps, ternaryOps, values) {
var nstack = [];
var newexpression = [];
var n1, n2, n3;
var f;
for (var i = 0;i < tokens.length; i++) {
var item = tokens[i];
var type = item.type;
if (type === INUMBER || type === IVARNAME) {
if (Array.isArray(item.value)) {
nstack.push.apply(nstack, simplify(item.value.map(function(x) {
return new Instruction(INUMBER, x);
}).concat(new Instruction(IARRAY, item.value.length)), unaryOps, binaryOps, ternaryOps, values));
} else {
nstack.push(item);
}
} else if (type === IVAR && values.hasOwnProperty(item.value)) {
item = new Instruction(INUMBER, values[item.value]);
nstack.push(item);
} else if (type === IOP2 && nstack.length > 1) {
n2 = nstack.pop();
n1 = nstack.pop();
f = binaryOps[item.value];
item = new Instruction(INUMBER, f(n1.value, n2.value));
nstack.push(item);
} else if (type === IOP3 && nstack.length > 2) {
n3 = nstack.pop();
n2 = nstack.pop();
n1 = nstack.pop();
if (item.value === "?") {
nstack.push(n1.value ? n2.value : n3.value);
} else {
f = ternaryOps[item.value];
item = new Instruction(INUMBER, f(n1.value, n2.value, n3.value));
nstack.push(item);
}
} else if (type === IOP1 && nstack.length > 0) {
n1 = nstack.pop();
f = unaryOps[item.value];
item = new Instruction(INUMBER, f(n1.value));
nstack.push(item);
} else if (type === IEXPR) {
while (nstack.length > 0) {
newexpression.push(nstack.shift());
}
newexpression.push(new Instruction(IEXPR, simplify(item.value, unaryOps, binaryOps, ternaryOps, values)));
} else if (type === IMEMBER && nstack.length > 0) {
n1 = nstack.pop();
nstack.push(new Instruction(INUMBER, n1.value[item.value]));
} else {
while (nstack.length > 0) {
newexpression.push(nstack.shift());
}
newexpression.push(item);
}
}
while (nstack.length > 0) {
newexpression.push(nstack.shift());
}
return newexpression;
}
function substitute(tokens, variable, expr) {
var newexpression = [];
for (var i = 0;i < tokens.length; i++) {
var item = tokens[i];
var type = item.type;
if (type === IVAR && item.value === variable) {
for (var j = 0;j < expr.tokens.length; j++) {
var expritem = expr.tokens[j];
var replitem;
if (expritem.type === IOP1) {
replitem = unaryInstruction(expritem.value);
} else if (expritem.type === IOP2) {
replitem = binaryInstruction(expritem.value);
} else if (expritem.type === IOP3) {
replitem = ternaryInstruction(expritem.value);
} else {
replitem = new Instruction(expritem.type, expritem.value);
}
newexpression.push(replitem);
}
} else if (type === IEXPR) {
newexpression.push(new Instruction(IEXPR, substitute(item.value, variable, expr)));
} else {
newexpression.push(item);
}
}
return newexpression;
}
function evaluate(tokens, expr, values) {
var nstack = [];
var n1, n2, n3;
var f, args, argCount;
if (isExpressionEvaluator(tokens)) {
return resolveExpression(tokens, values);
}
var numTokens = tokens.length;
for (var i = 0;i < numTokens; i++) {
var item = tokens[i];
var type = item.type;
if (type === INUMBER || type === IVARNAME) {
nstack.push(item.value);
} else if (type === IOP2) {
n2 = nstack.pop();
n1 = nstack.pop();
if (item.value === "and") {
nstack.push(n1 ? !!evaluate(n2, expr, values) : false);
} else if (item.value === "or") {
nstack.push(n1 ? true : !!evaluate(n2, expr, values));
} else if (item.value === "=") {
f = expr.binaryOps[item.value];
nstack.push(f(n1, evaluate(n2, expr, values), values));
} else {
f = expr.binaryOps[item.value];
nstack.push(f(resolveExpression(n1, values), resolveExpression(n2, values)));
}
} else if (type === IOP3) {
n3 = nstack.pop();
n2 = nstack.pop();
n1 = nstack.pop();
if (item.value === "?") {
nstack.push(evaluate(n1 ? n2 : n3, expr, values));
} else {
f = expr.ternaryOps[item.value];
nstack.push(f(resolveExpression(n1, values), resolveExpression(n2, values), resolveExpression(n3, values)));
}
} else if (type === IVAR) {
if (item.value in expr.functions) {
nstack.push(expr.functions[item.value]);
} else if (item.value in expr.unaryOps && expr.parser.isOperatorEnabled(item.value)) {
nstack.push(expr.unaryOps[item.value]);
} else {
var v = values[item.value];
if (v !== undefined) {
nstack.push(v);
} else {
throw new Error("undefined variable: " + item.value);
}
}
} else if (type === IOP1) {
n1 = nstack.pop();
f = expr.unaryOps[item.value];
nstack.push(f(resolveExpression(n1, values)));
} else if (type === IFUNCALL) {
argCount = item.value;
args = [];
while (argCount-- > 0) {
args.unshift(resolveExpression(nstack.pop(), values));
}
f = nstack.pop();
if (f.apply && f.call) {
nstack.push(f.apply(undefined, args));
} else {
throw new Error(f + " is not a function");
}
} else if (type === IFUNDEF) {
nstack.push(function() {
var n22 = nstack.pop();
var args2 = [];
var argCount2 = item.value;
while (argCount2-- > 0) {
args2.unshift(nstack.pop());
}
var n12 = nstack.pop();
var f2 = function() {
var scope = Object.assign({}, values);
for (var i2 = 0, len = args2.length;i2 < len; i2++) {
scope[args2[i2]] = arguments[i2];
}
return evaluate(n22, expr, scope);
};
Object.defineProperty(f2, "name", {
value: n12,
writable: false
});
values[n12] = f2;
return f2;
}());
} else if (type === IEXPR) {
nstack.push(createExpressionEvaluator(item, expr));
} else if (type === IEXPREVAL) {
nstack.push(item);
} else if (type === IMEMBER) {
n1 = nstack.pop();
nstack.push(n1[item.value]);
} else if (type === IENDSTATEMENT) {
nstack.pop();
} else if (type === IARRAY) {
argCount = item.value;
args = [];
while (argCount-- > 0) {
args.unshift(nstack.pop());
}
nstack.push(args);
} else {
throw new Error("invalid Expression");
}
}
if (nstack.length > 1) {
throw new Error("invalid Expression (parity)");
}
return nstack[0] === 0 ? 0 : resolveExpression(nstack[0], values);
}
function createExpressionEvaluator(token, expr, values) {
if (isExpressionEvaluator(token))
return token;
return {
type: IEXPREVAL,
value: function(scope) {
return evaluate(token.value, expr, scope);
}
};
}
function isExpressionEvaluator(n) {
return n && n.type === IEXPREVAL;
}
function resolveExpression(n, values) {
return isExpressionEvaluator(n) ? n.value(values) : n;
}
function expressionToString(tokens, toJS) {
var nstack = [];
var n1, n2, n3;
var f, args, argCount;
for (var i = 0;i < tokens.length; i++) {
var item = tokens[i];
var type = item.type;
if (type === INUMBER) {
if (typeof item.value === "number" && item.value < 0) {
nstack.push("(" + item.value + ")");
} else if (Array.isArray(item.value)) {
nstack.push("[" + item.value.map(escapeValue).join(", ") + "]");
} else {
nstack.push(escapeValue(item.value));
}
} else if (type === IOP2) {
n2 = nstack.pop();
n1 = nstack.pop();
f = item.value;
if (toJS) {
if (f === "^") {
nstack.push("Math.pow(" + n1 + ", " + n2 + ")");
} else if (f === "and") {
nstack.push("(!!" + n1 + " && !!" + n2 + ")");
} else if (f === "or") {
nstack.push("(!!" + n1 + " || !!" + n2 + ")");
} else if (f === "||") {
nstack.push("(function(a,b){ return Array.isArray(a) && Array.isArray(b) ? a.concat(b) : String(a) + String(b); }((" + n1 + "),(" + n2 + ")))");
} else if (f === "==") {
nstack.push("(" + n1 + " === " + n2 + ")");
} else if (f === "!=") {
nstack.push("(" + n1 + " !== " + n2 + ")");
} else if (f === "[") {
nstack.push(n1 + "[(" + n2 + ") | 0]");
} else {
nstack.push("(" + n1 + " " + f + " " + n2 + ")");
}
} else {
if (f === "[") {
nstack.push(n1 + "[" + n2 + "]");
} else {
nstack.push("(" + n1 + " " + f + " " + n2 + ")");
}
}
} else if (type === IOP3) {
n3 = nstack.pop();
n2 = nstack.pop();
n1 = nstack.pop();
f = item.value;
if (f === "?") {
nstack.push("(" + n1 + " ? " + n2 + " : " + n3 + ")");
} else {
throw new Error("invalid Expression");
}
} else if (type === IVAR || type === IVARNAME) {
nstack.push(item.value);
} else if (type === IOP1) {
n1 = nstack.pop();
f = item.value;
if (f === "-" || f === "+") {
nstack.push("(" + f + n1 + ")");
} else if (toJS) {
if (f === "not") {
nstack.push("(" + "!" + n1 + ")");
} else if (f === "!") {
nstack.push("fac(" + n1 + ")");
} else {
nstack.push(f + "(" + n1 + ")");
}
} else if (f === "!") {
nstack.push("(" + n1 + "!)");
} else {
nstack.push("(" + f + " " + n1 + ")");
}
} else if (type === IFUNCALL) {
argCount = item.value;
args = [];
while (argCount-- > 0) {
args.unshift(nstack.pop());
}
f = nstack.pop();
nstack.push(f + "(" + args.join(", ") + ")");
} else if (type === IFUNDEF) {
n2 = nstack.pop();
argCount = item.value;
args = [];
while (argCount-- > 0) {
args.unshift(nstack.pop());
}
n1 = nstack.pop();
if (toJS) {
nstack.push("(" + n1 + " = function(" + args.join(", ") + ") { return " + n2 + " })");
} else {
nstack.push("(" + n1 + "(" + args.join(", ") + ") = " + n2 + ")");
}
} else if (type === IMEMBER) {
n1 = nstack.pop();
nstack.push(n1 + "." + item.value);
} else if (type === IARRAY) {
argCount = item.value;
args = [];
while (argCount-- > 0) {
args.unshift(nstack.pop());
}
nstack.push("[" + args.join(", ") + "]");
} else if (type === IEXPR) {
nstack.push("(" + expressionToString(item.value, toJS) + ")");
} else if (type === IENDSTATEMENT)
;
else {
throw new Error("invalid Expression");
}
}
if (nstack.length > 1) {
if (toJS) {
nstack = [nstack.join(",")];
} else {
nstack = [nstack.join(";")];
}
}
return String(nstack[0]);
}
function escapeValue(v) {
if (typeof v === "string") {
return JSON.stringify(v).replace(/\u2028/g, "\\u2028").replace(/\u2029/g, "\\u2029");
}
return v;
}
function contains(array, obj) {
for (var i = 0;i < array.length; i++) {
if (array[i] === obj) {
return true;
}
}
return false;
}
function getSymbols(tokens, symbols, options) {
options = options || {};
var withMembers = !!options.withMembers;
var prevVar = null;
for (var i = 0;i < tokens.length; i++) {
var item = tokens[i];
if (item.type === IVAR || item.type === IVARNAME) {
if (!withMembers && !contains(symbols, item.value)) {
symbols.push(item.value);
} else if (prevVar !== null) {
if (!contains(symbols, prevVar)) {
symbols.push(prevVar);
}
prevVar = item.value;
} else {
prevVar = item.value;
}
} else if (item.type === IMEMBER && withMembers && prevVar !== null) {
prevVar += "." + item.value;
} else if (item.type === IEXPR) {
getSymbols(item.value, symbols, options);
} else if (prevVar !== null) {
if (!contains(symbols, prevVar)) {
symbols.push(prevVar);
}
prevVar = null;
}
}
if (prevVar !== null && !contains(symbols, prevVar)) {
symbols.push(prevVar);
}
}
function Expression(tokens, parser) {
this.tokens = tokens;
this.parser = parser;
this.unaryOps = parser.unaryOps;
this.binaryOps = parser.binaryOps;
this.ternaryOps = parser.ternaryOps;
this.functions = parser.functions;
}
Expression.prototype.simplify = function(values) {
values = values || {};
return new Expression(simplify(this.tokens, this.unaryOps, this.binaryOps, this.ternaryOps, values), this.parser);
};
Expression.prototype.substitute = function(variable, expr) {
if (!(expr instanceof Expression)) {
expr = this.parser.parse(String(expr));
}
return new Expression(substitute(this.tokens, variable, expr), this.parser);
};
Expression.prototype.evaluate = function(values) {
values = values || {};
return evaluate(this.tokens, this, values);
};
Expression.prototype.toString = function() {
return expressionToString(this.tokens, false);
};
Expression.prototype.symbols = function(options) {
options = options || {};
var vars = [];
getSymbols(this.tokens, vars, options);
return vars;
};
Expression.prototype.variables = function(options) {
options = options || {};
var vars = [];
getSymbols(this.tokens, vars, options);
var functions = this.functions;
return vars.filter(function(name) {
return !(name in functions);
});
};
Expression.prototype.toJSFunction = function(param, variables) {
var expr = this;
var f = new Function(param, "with(this.functions) with (this.ternaryOps) with (this.binaryOps) with (this.unaryOps) { return " + expressionToString(this.simplify(variables).tokens, true) + "; }");
return function() {
return f.apply(expr, arguments);
};
};
var TEOF = "TEOF";
var TOP = "TOP";
var TNUMBER = "TNUMBER";
var TSTRING = "TSTRING";
var TPAREN = "TPAREN";
var TBRACKET = "TBRACKET";
var TCOMMA = "TCOMMA";
var TNAME = "TNAME";
var TSEMICOLON = "TSEMICOLON";
function Token(type, value, index2) {
this.type = type;
this.value = value;
this.index = index2;
}
Token.prototype.toString = function() {
return this.type + ": " + this.value;
};
function TokenStream(parser, expression) {
this.pos = 0;
this.current = null;
this.unaryOps = parser.unaryOps;
this.binaryOps = parser.binaryOps;
this.ternaryOps = parser.ternaryOps;
this.consts = parser.consts;
this.expression = expression;
this.savedPosition = 0;
this.savedCurrent = null;
this.options = parser.options;
this.parser = parser;
}
TokenStream.prototype.newToken = function(type, value, pos) {
return new Token(type, value, pos != null ? pos : this.pos);
};
TokenStream.prototype.save = function() {
this.savedPosition = this.pos;
this.savedCurrent = this.current;
};
TokenStream.prototype.restore = function() {
this.pos = this.savedPosition;
this.current = this.savedCurrent;
};
TokenStream.prototype.next = function() {
if (this.pos >= this.expression.length) {
return this.newToken(TEOF, "EOF");
}
if (this.isWhitespace() || this.isComment()) {
return this.next();
} else if (this.isRadixInteger() || this.isNumber() || this.isOperator() || this.isString() || this.isParen() || this.isBracket() || this.isComma() || this.isSemicolon() || this.isNamedOp() || this.isConst() || this.isName()) {
return this.current;
} else {
this.parseError('Unknown character "' + this.expression.charAt(this.pos) + '"');
}
};
TokenStream.prototype.isString = function() {
var r = false;
var startPos = this.pos;
var quote = this.expression.charAt(startPos);
if (quote === "'" || quote === '"') {
var index2 = this.expression.indexOf(quote, startPos + 1);
while (index2 >= 0 && this.pos < this.expression.length) {
this.pos = index2 + 1;
if (this.expression.charAt(index2 - 1) !== "\\") {
var rawString = this.expression.substring(startPos + 1, index2);
this.current = this.newToken(TSTRING, this.unescape(rawString), startPos);
r = true;
break;
}
index2 = this.expression.indexOf(quote, index2 + 1);
}
}
return r;
};
TokenStream.prototype.isParen = function() {
var c = this.expression.charAt(this.pos);
if (c === "(" || c === ")") {
this.current = this.newToken(TPAREN, c);
this.pos++;
return true;
}
return false;
};
TokenStream.prototype.isBracket = function() {
var c = this.expression.charAt(this.pos);
if ((c === "[" || c === "]") && this.isOperatorEnabled("[")) {
this.current = this.newToken(TBRACKET, c);
this.pos++;
return true;
}
return false;
};
TokenStream.prototype.isComma = function() {
var c = this.expression.charAt(this.pos);
if (c === ",") {
this.current = this.newToken(TCOMMA, ",");
this.pos++;
return true;
}
return false;
};
TokenStream.prototype.isSemicolon = function() {
var c = this.expression.charAt(this.pos);
if (c === ";") {
this.current = this.newToken(TSEMICOLON, ";");
this.pos++;
return true;
}
return false;
};
TokenStream.prototype.isConst = function() {
var startPos = this.pos;
var i = startPos;
for (;i < this.expression.length; i++) {
var c = this.expression.charAt(i);
if (c.toUpperCase() === c.toLowerCase()) {
if (i === this.pos || c !== "_" && c !== "." && (c < "0" || c > "9")) {
break;
}
}
}
if (i > startPos) {
var str = this.expression.substring(startPos, i);
if (str in this.consts) {
this.current = this.newToken(TNUMBER, this.consts[str]);
this.pos += str.length;
return true;
}
}
return false;
};
TokenStream.prototype.isNamedOp = function() {
var startPos = this.pos;
var i = startPos;
for (;i < this.expression.length; i++) {
var c = this.expression.charAt(i);
if (c.toUpperCase() === c.toLowerCase()) {
if (i === this.pos || c !== "_" && (c < "0" || c > "9")) {
break;
}
}
}
if (i > startPos) {
var str = this.expression.substring(startPos, i);
if (this.isOperatorEnabled(str) && ((str in this.binaryOps) || (str in this.unaryOps) || (str in this.ternaryOps))) {
this.current = this.newToken(TOP, str);
this.pos += str.length;
return true;
}
}
return false;
};
TokenStream.prototype.isName = function() {
var startPos = this.pos;
var i = startPos;
var hasLetter = false;
for (;i < this.expression.length; i++) {
var c = this.expression.charAt(i);
if (c.toUpperCase() === c.toLowerCase()) {
if (i === this.pos && (c === "$" || c === "_")) {
if (c === "_") {
hasLetter = true;
}
continue;
} else if (i === this.pos || !hasLetter || c !== "_" && (c < "0" || c > "9")) {
break;
}
} else {
hasLetter = true;
}
}
if (hasLetter) {
var str = this.expression.substring(startPos, i);
this.current = this.newToken(TNAME, str);
this.pos += str.length;
return true;
}
return false;
};
TokenStream.prototype.isWhitespace = function() {
var r = false;
var c = this.expression.charAt(this.pos);
while (c === " " || c === "\t" || c === `
` || c === "\r") {
r = true;
this.pos++;
if (this.pos >= this.expression.length) {
break;
}
c = this.expression.charAt(this.pos);
}
return r;
};
var codePointPattern = /^[0-9a-f]{4}$/i;
TokenStream.prototype.unescape = function(v) {
var index2 = v.indexOf("\\");
if (index2 < 0) {
return v;
}
var buffer = v.substring(0, index2);
while (index2 >= 0) {
var c = v.charAt(++index2);
switch (c) {
case "'":
buffer += "'";
break;
case '"':
buffer += '"';
break;
case "\\":
buffer += "\\";
break;
case "/":
buffer += "/";
break;
case "b":
buffer += "\b";
break;
case "f":
buffer += "\f";
break;
case "n":
buffer += `
`;
break;
case "r":
buffer += "\r";
break;
case "t":
buffer += "\t";
break;
case "u":
var codePoint = v.substring(index2 + 1, index2 + 5);
if (!codePointPattern.test(codePoint)) {
this.parseError("Illegal escape sequence: \\u" + codePoint);
}
buffer += String.fromCharCode(parseInt(codePoint, 16));
index2 += 4;
break;
default:
throw this.parseError('Illegal escape sequence: "\\' + c + '"');
}
++index2;
var backslash = v.indexOf("\\", index2);
buffer += v.substring(index2, backslash < 0 ? v.length : backslash);
index2 = backslash;
}
return buffer;
};
TokenStream.prototype.isComment = function() {
var c = this.expression.charAt(this.pos);
if (c === "/" && this.expression.charAt(this.pos + 1) === "*") {
this.pos = this.expression.indexOf("*/", this.pos) + 2;
if (this.pos === 1) {
this.pos = this.expression.length;
}
return true;
}
return false;
};
TokenStream.prototype.isRadixInteger = function() {
var pos = this.pos;
if (pos >= this.expression.length - 2 || this.expression.charAt(pos) !== "0") {
return false;
}
++pos;
var radix;
var validDigit;
if (this.expression.charAt(pos) === "x") {
radix = 16;
validDigit = /^[0-9a-f]$/i;
++pos;
} else if (this.expression.charAt(pos) === "b") {
radix = 2;
validDigit = /^[01]$/i;
++pos;
} else {
return false;
}
var valid = false;
var startPos = pos;
while (pos < this.expression.length) {
var c = this.expression.charAt(pos);
if (validDigit.test(c)) {
pos++;
valid = true;
} else {
break;
}
}
if (valid) {
this.current = this.newToken(TNUMBER, parseInt(this.expression.substring(startPos, pos), radix));
this.pos = pos;
}
return valid;
};
TokenStream.prototype.isNumber = function() {
var valid = false;
var pos = this.pos;
var startPos = pos;
var resetPos = pos;
var foundDot = false;
var foundDigits = false;
var c;
while (pos < this.expression.length) {
c = this.expression.charAt(pos);
if (c >= "0" && c <= "9" || !foundDot && c === ".") {
if (c === ".") {
foundDot = true;
} else {
foundDigits = true;
}
pos++;
valid = foundDigits;
} else {
break;
}
}
if (valid) {
resetPos = pos;
}
if (c === "e" || c === "E") {
pos++;
var acceptSign = true;
var validExponent = false;
while (pos < this.expression.length) {
c = this.expression.charAt(pos);
if (acceptSign && (c === "+" || c === "-")) {
acceptSign = false;
} else if (c >= "0" && c <= "9") {
validExponent = true;
acceptSign = false;
} else {
break;
}
pos++;
}
if (!validExponent) {
pos = resetPos;
}
}
if (valid) {
this.current = this.newToken(TNUMBER, parseFloat(this.expression.substring(startPos, pos)));
this.pos = pos;
} else {
this.pos = resetPos;
}
return valid;
};
TokenStream.prototype.isOperator = function() {
var startPos = this.pos;
var c = this.expression.charAt(this.pos);
if (c === "+" || c === "-" || c === "*" || c === "/" || c === "%" || c === "^" || c === "?" || c === ":" || c === ".") {
this.current = this.newToken(TOP, c);
} else if (c === "∙" || c === "•") {
this.current = this.newToken(TOP, "*");
} else if (c === ">") {
if (this.expression.charAt(this.pos + 1) === "=") {
this.current = this.newToken(TOP, ">=");
this.pos++;
} else {
this.current = this.newToken(TOP, ">");
}
} else if (c === "<") {
if (this.expression.charAt(this.pos + 1) === "=") {
this.current = this.newToken(TOP, "<=");
this.pos++;
} else {
this.current = this.newToken(TOP, "<");
}
} else if (c === "|") {
if (this.expression.charAt(this.pos + 1) === "|") {
this.current = this.newToken(TOP, "||");
this.pos++;
} else {
return false;
}
} else if (c === "=") {
if (this.expression.charAt(this.pos + 1) === "=") {
this.current = this.newToken(TOP, "==");
this.pos++;
} else {
this.current = this.newToken(TOP, c);
}
} else if (c === "!") {
if (this.expression.charAt(this.pos + 1) === "=") {
this.current = this.newToken(TOP, "!=");
this.pos++;
} else {
this.current = this.newToken(TOP, c);
}
} else {
return false;
}
this.pos++;
if (this.isOperatorEnabled(this.current.value)) {
return true;
} else {
this.pos = startPos;
return false;
}
};
TokenStream.prototype.isOperatorEnabled = function(op) {
return this.parser.isOperatorEnabled(op);
};
TokenStream.prototype.getCoordinates = function() {
var line = 0;
var column;
var newline = -1;
do {
line++;
column = this.pos - newline;
newline = this.expression.indexOf(`
`, newline + 1);
} while (newline >= 0 && newline < this.pos);
return {
line,
column
};
};
TokenStream.prototype.parseError = function(msg) {
var coords = this.getCoordinates();
throw new Error("parse error [" + coords.line + ":" + coords.column + "]: " + msg);
};
function ParserState(parser, tokenStream, options) {
this.parser = parser;
this.tokens = tokenStream;
this.current = null;
this.nextToken = null;
this.next();
this.savedCurrent = null;
this.savedNextToken = null;
this.allowMemberAccess = options.allowMemberAccess !== false;
}
ParserState.prototype.next = function() {
this.current = this.nextToken;
return this.nextToken = this.tokens.next();
};
ParserState.prototype.tokenMatches = function(token, value) {
if (typeof value === "undefined") {
return true;
} else if (Array.isArray(value)) {
return contains(value, token.value);
} else if (typeof value === "function") {
return value(token);
} else {
return token.value === value;
}
};
ParserState.prototype.save = function() {
this.savedCurrent = this.current;
this.savedNextToken = this.nextToken;
this.tokens.save();
};
ParserState.prototype.restore = function() {
this.tokens.restore();
this.current = this.savedCurrent;
this.nextToken = this.savedNextToken;
};
ParserState.prototype.accept = function(type, value) {
if (this.nextToken.type === type && this.tokenMatches(this.nextToken, value)) {
this.next();
return true;
}
return false;
};
ParserState.prototype.expect = function(type, value) {
if (!this.accept(type, value)) {
var coords = this.tokens.getCoordinates();
throw new Error("parse error [" + coords.line + ":" + coords.column + "]: Expected " + (value || type));
}
};
ParserState.prototype.parseAtom = function(instr) {
var unaryOps = this.tokens.unaryOps;
function isPrefixOperator(token) {
return token.value in unaryOps;
}
if (this.accept(TNAME) || this.accept(TOP, isPrefixOperator)) {
instr.push(new Instruction(IVAR, this.current.value));
} else if (this.accept(TNUMBER)) {
instr.push(new Instruction(INUMBER, this.current.value));
} else if (this.accept(TSTRING)) {
instr.push(new Instruction(INUMBER, this.current.value));
} else if (this.accept(TPAREN, "(")) {
this.parseExpression(instr);
this.expect(TPAREN, ")");
} else if (this.accept(TBRACKET, "[")) {
if (this.accept(TBRACKET, "]")) {
instr.push(new Instruction(IARRAY, 0));
} else {
var argCount = this.parseArrayList(instr);
instr.push(new Instruction(IARRAY, argCount));
}
} else {
throw new Error("unexpected " + this.nextToken);
}
};
ParserState.prototype.parseExpression = function(instr) {
var exprInstr = [];
if (this.parseUntilEndStatement(instr, exprInstr)) {
return;
}
this.parseVariableAssignmentExpression(exprInstr);
if (this.parseUntilEndStatement(instr, exprInstr)) {
return;
}
this.pushExpression(instr, exprInstr);
};
ParserState.prototype.pushExpression = function(instr, exprInstr) {
for (var i = 0, len = exprInstr.length;i < len; i++) {
instr.push(exprInstr[i]);
}
};
ParserState.prototype.parseUntilEndStatement = function(instr, exprInstr) {
if (!this.accept(TSEMICOLON))
return false;
if (this.nextToken && this.nextToken.type !== TEOF && !(this.nextToken.type === TPAREN && this.nextToken.value === ")")) {
exprInstr.push(new Instruction(IENDSTATEMENT));
}
if (this.nextToken.type !== TEOF) {
this.parseExpression(exprInstr);
}
instr.push(new Instruction(IEXPR, exprInstr));
return true;
};
ParserState.prototype.parseArrayList = function(instr) {
var argCount = 0;
while (!this.accept(TBRACKET, "]")) {
this.parseExpression(instr);
++argCount;
while (this.accept(TCOMMA)) {
this.parseExpression(instr);
++argCount;
}
}
return argCount;
};
ParserState.prototype.parseVariableAssignmentExpression = function(instr) {
this.parseConditionalExpression(instr);
while (this.accept(TOP, "=")) {
var varName = instr.pop();
var varValue = [];
var lastInstrIndex = instr.length - 1;
if (varName.type === IFUNCALL) {
if (!this.tokens.isOperatorEnabled("()=")) {
throw new Error("function definition is not permitted");
}
for (var i = 0, len = varName.value + 1;i < len; i++) {
var index2 = lastInstrIndex - i;
if (instr[index2].type === IVAR) {
instr[index2] = new Instruction(IVARNAME, instr[index2].value);
}
}
this.parseVariableAssignmentExpression(varValue);
instr.push(new Instruction(IEXPR, varValue));
instr.push(new Instruction(IFUNDEF, varName.value));
continue;
}
if (varName.type !== IVAR && varName.type !== IMEMBER) {
throw new Error("expected variable for assignment");
}
this.parseVariableAssignmentExpression(varValue);
instr.push(new Instruction(IVARNAME, varName.value));
instr.push(new Instruction(IEXPR, varValue));
instr.push(binaryInstruction("="));
}
};
ParserState.prototype.parseConditionalExpression = function(instr) {
this.parseOrExpression(instr);
while (this.accept(TOP, "?")) {
var trueBranch = [];
var falseBranch = [];
this.parseConditionalExpression(trueBranch);
this.expect(TOP, ":");
this.parseConditionalExpression(falseBranch);
instr.push(new Instruction(IEXPR, trueBranch));
instr.push(new Instruction(IEXPR, falseBranch));
instr.push(ternaryInstruction("?"));
}
};
ParserState.prototype.parseOrExpression = function(instr) {
this.parseAndExpression(instr);
while (this.accept(TOP, "or")) {
var falseBranch = [];
this.parseAndExpression(falseBranch);
instr.push(new Instruction(IEXPR, falseBranch));
instr.push(binaryInstruction("or"));
}
};
ParserState.prototype.parseAndExpression = function(instr) {
this.parseComparison(instr);
while (this.accept(TOP, "and")) {
var trueBranch = [];
this.parseComparison(trueBranch);
instr.push(new Instruction(IEXPR, trueBranch));
instr.push(binaryInstruction("and"));
}
};
var COMPARISON_OPERATORS = ["==", "!=", "<", "<=", ">=", ">", "in"];
ParserState.prototype.parseComparison = function(instr) {
this.parseAddSub(instr);
while (this.accept(TOP, COMPARISON_OPERATORS)) {
var op = this.current;
this.parseAddSub(instr);
instr.push(binaryInstruction(op.value));
}
};
var ADD_SUB_OPERATORS = ["+", "-", "||"];
ParserState.prototype.parseAddSub = function(instr) {
this.parseTerm(instr);
while (this.accept(TOP, ADD_SUB_OPERATORS)) {
var op = this.current;
this.parseTerm(instr);
instr.push(binaryInstruction(op.value));
}
};
var TERM_OPERATORS = ["*", "/", "%"];
ParserState.prototype.parseTerm = function(instr) {
this.parseFactor(instr);
while (this.accept(TOP, TERM_OPERATORS)) {
var op = this.current;
this.parseFactor(instr);
instr.push(binaryInstruction(op.value));
}
};
ParserState.prototype.parseFactor = function(instr) {
var unaryOps = this.tokens.unaryOps;
function isPrefixOperator(token) {
return token.value in unaryOps;
}
this.save();
if (this.accept(TOP, isPrefixOperator)) {
if (this.current.value !== "-" && this.current.value !== "+") {
if (this.nextToken.type === TPAREN && this.nextToken.value === "(") {
this.restore();
this.parseExponential(instr);
return;
} else if (this.nextToken.type === TSEMICOLON || this.nextToken.type === TCOMMA || this.nextToken.type === TEOF || this.nextToken.type === TPAREN && this.nextToken.value === ")") {
this.restore();
this.parseAtom(instr);
return;
}
}
var op = this.current;
this.parseFactor(instr);
instr.push(unaryInstruction(op.value));
} else {
this.parseExponential(instr);
}
};
ParserState.prototype.parseExponential = function(instr) {
this.parsePostfixExpression(instr);
while (this.accept(TOP, "^")) {
this.parseFactor(instr);
instr.push(binaryInstruction("^"));
}
};
ParserState.prototype.parsePostfixExpression = function(instr) {
this.parseFunctionCall(instr);
while (this.accept(TOP, "!")) {
instr.push(unaryInstruction("!"));
}
};
ParserState.prototype.parseFunctionCall = function(instr) {
var unaryOps = this.tokens.unaryOps;
function isPrefixOperator(token) {
return token.value in unaryOps;
}
if (this.accept(TOP, isPrefixOperator)) {
var op = this.current;
this.parseAtom(instr);
instr.push(unaryInstruction(op.value));
} else {
this.parseMemberExpression(instr);
while (this.accept(TPAREN, "(")) {
if (this.accept(TPAREN, ")")) {
instr.push(new Instruction(IFUNCALL, 0));
} else {
var argCount = this.parseArgumentList(instr);
instr.push(new Instruction(IFUNCALL, argCount));
}
}
}
};
ParserState.prototype.parseArgumentList = function(instr) {
var argCount = 0;
while (!this.accept(TPAREN, ")")) {
this.parseExpression(instr);
++argCount;
while (this.accept(TCOMMA)) {
this.parseExpression(instr);
++argCount;
}
}
return argCount;
};
ParserState.prototype.parseMemberExpression = function(instr) {
this.parseAtom(instr);
while (this.accept(TOP, ".") || this.accept(TBRACKET, "[")) {
var op = this.current;
if (op.value === ".") {
if (!this.allowMemberAccess) {
throw new Error('unexpected ".", member access is not permitted');
}
this.expect(TNAME);
instr.push(new Instruction(IMEMBER, this.current.value));
} else if (op.value === "[") {
if (!this.tokens.isOperatorEnabled("[")) {
throw new Error('unexpected "[]", arrays are disabled');
}
this.parseExpression(instr);
this.expect(TBRACKET, "]");
instr.push(binaryInstruction("["));
} else {
throw new Error("unexpected symbol: " + op.value);
}
}
};
function add(a, b) {
return Number(a) + Number(b);
}
function sub(a, b) {
return a - b;
}
function mul(a, b) {
return a * b;
}
function div(a, b) {
return a / b;
}
function mod(a, b) {
return a % b;
}
function concat(a, b) {
if (Array.isArray(a) && Array.isArray(b)) {
return a.concat(b);
}
return "" + a + b;
}
function equal(a, b) {
return a === b;
}
function notEqual(a, b) {
return a !== b;
}
function greaterThan(a, b) {
return a > b;
}
function lessThan(a, b) {
return a < b;
}
function greaterThanEqual(a, b) {
return a >= b;
}
function lessThanEqual(a, b) {
return a <= b;
}
function andOperator(a, b) {
return Boolean(a && b);
}
function orOperator(a, b) {
return Boolean(a || b);
}
function inOperator(a, b) {
return contains(b, a);
}
function sinh(a) {
return (Math.exp(a) - Math.exp(-a)) / 2;
}
function cosh(a) {
return (Math.exp(a) + Math.exp(-a)) / 2;
}
function tanh(a) {
if (a === Infinity)
return 1;
if (a === -Infinity)
return -1;
return (Math.exp(a) - Math.exp(-a)) / (Math.exp(a) + Math.exp(-a));
}
function asinh(a) {
if (a === -Infinity)
return a;
return Math.log(a + Math.sqrt(a * a + 1));
}
function acosh(a) {
return Math.log(a + Math.sqrt(a * a - 1));
}
function atanh(a) {
return Math.log((1 + a) / (1 - a)) / 2;
}
function log10(a) {
return Math.log(a) * Math.LOG10E;
}
function neg(a) {
return -a;
}
function not(a) {
return !a;
}
function trunc(a) {
return a < 0 ? Math.ceil(a) : Math.floor(a);
}
function random(a) {
return Math.random() * (a || 1);
}
function factorial(a) {
return gamma(a + 1);
}
function isInteger(value) {
return isFinite(value) && value === Math.round(value);
}
var GAMMA_G = 4.7421875;
var GAMMA_P = [
0.9999999999999971,
57.15623566586292,
-59.59796035547549,
14.136097974741746,
-0.4919138160976202,
0.00003399464998481189,
0.00004652362892704858,
-0.00009837447530487956,
0.0001580887032249125,
-0.00021026444172410488,
0.00021743961811521265,
-0.0001643181065367639,
0.00008441822398385275,
-0.000026190838401581408,
0.0000036899182659531625
];
function gamma(n) {
var t, x;
if (isInteger(n)) {
if (n <= 0) {
return isFinite(n) ? Infinity : NaN;
}
if (n > 171) {
return Infinity;
}
var value = n - 2;
var res = n - 1;
while (value > 1) {
res *= value;
value--;
}
if (res === 0) {
res = 1;
}
return res;
}
if (n < 0.5) {
return Math.PI / (Math.sin(Math.PI * n) * gamma(1 - n));
}
if (n >= 171.35) {
return Infinity;
}
if (n > 85) {
var twoN = n * n;
var threeN = twoN * n;
var fourN = threeN * n;
var fiveN = fourN * n;
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));
}
--n;
x = GAMMA_P[0];
for (var i = 1;i < GAMMA_P.length; ++i) {
x += GAMMA_P[i] / (n + i);
}
t = n + GAMMA_G + 0.5;
return Math.sqrt(2 * Math.PI) * Math.pow(t, n + 0.5) * Math.exp(-t) * x;
}
function stringOrArrayLength(s) {
if (Array.isArray(s)) {
return s.length;
}
return String(s).length;
}
function hypot() {
var sum = 0;
var larg = 0;
for (var i = 0;i < arguments.length; i++) {
var arg = Math.abs(arguments[i]);
var div2;
if (larg < arg) {
div2 = larg / arg;
sum = sum * div2 * div2 + 1;
larg = arg;
} else if (arg > 0) {
div2 = arg / larg;
sum += div2 * div2;
} else {
sum += arg;
}
}
return larg === Infinity ? Infinity : larg * Math.sqrt(sum);
}
function condition(cond, yep, nope) {
return cond ? yep : nope;
}
function roundTo(value, exp) {
if (typeof exp === "undefined" || +exp === 0) {
return Math.round(value);
}
value = +value;
exp = -+exp;
if (isNaN(value) || !(typeof exp === "number" && exp % 1 === 0)) {
return NaN;
}
value = value.toString().split("e");
value = Math.round(+(value[0] + "e" + (value[1] ? +value[1] - exp : -exp)));
value = value.toString().split("e");
return +(value[0] + "e" + (value[1] ? +value[1] + exp : exp));
}
function setVar(name, value, variables) {
if (variables)
variables[name] = value;
return value;
}
function arrayIndex(array, index2) {
return array[index2 | 0];
}
function max(array) {
if (arguments.length === 1 && Array.isArray(array)) {
return Math.max.apply(Math, array);
} else {
return Math.max.apply(Math, arguments);
}
}
function min(array) {
if (arguments.length === 1 && Array.isArray(array)) {
return Math.min.apply(Math, array);
} else {
return Math.min.apply(Math, arguments);
}
}
function arrayMap(f, a) {
if (typeof f !== "function") {
throw new Error("First argument to map is not a function");
}
if (!Array.isArray(a)) {
throw new Error("Second argument to map is not an array");
}
return a.map(function(x, i) {
return f(x, i);
});
}
function arrayFold(f, init, a) {
if (typeof f !== "function") {
throw new Error("First argument to fold is not a function");
}
if (!Array.isArray(a)) {
throw new Error("Second argument to fold is not an array");
}
return a.reduce(function(acc, x, i) {
return f(acc, x, i);
}, init);
}
function arrayFilter(f, a) {
if (typeof f !== "function") {
throw new Error("First argument to filter is not a function");
}
if (!Array.isArray(a)) {
throw new Error("Second argument to filter is not an array");
}
return a.filter(function(x, i) {
return f(x, i);
});
}
function stringOrArrayIndexOf(target, s) {
if (!(Array.isArray(s) || typeof s === "string")) {
throw new Error("Second argument to indexOf is not a string or array");
}
return s.indexOf(target);
}
function arrayJoin(sep, a) {
if (!Array.isArray(a)) {
throw new Error("Second argument to join is not an array");
}
return a.join(sep);
}
function sign(x) {
return (x > 0) - (x < 0) || +x;
}
var ONE_THIRD = 1 / 3;
function cbrt(x) {
return x < 0 ? -Math.pow(-x, ONE_THIRD) : Math.pow(x, ONE_THIRD);
}
function expm1(x) {
return Math.exp(x) - 1;
}
function log1p(x) {
return Math.log(1 + x);
}
function log2(x) {
return Math.log(x) / Math.LN2;
}
function Parser(options) {
this.options = options || {};
this.unaryOps = {
sin: Math.sin,
cos: Math.cos,
tan: Math.tan,
asin: Math.asin,
acos: Math.acos,
atan: Math.atan,
sinh: Math.sinh || sinh,