UNPKG

cal-mcp

Version:

A MCP server for evaluating mathematical expressions

1,511 lines (1,509 loc) 1.43 MB
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,