Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
function match(expr, target) {
// Both expression and target are a number.
if (isNumber(target)) {
return (expr === target) ? [{}] : [];
}
if (isString(target)) {
// Matches any constants (numbers)
if (target[0] == 'c') {
return isNumber(expr) ? [{[target]: expr}] : [];
}
// Matches any variables (strings)
if (target[0] == 'v') {
return isString(expr) ? [{[target]: expr}] : [];
}
// Match any other expressions
return [{[target]: expr}];
}
// Check if functions are the same
if (!isArray(expr)) return [];
let [fn, ...args] = expr;
if (fn != target[0]) return [];
if (expr.length != target.length) return [];
// Match all arguments of a function. Addition and multiplication can
// match arguments in any order.
if ('+*'.includes(expr[0])) {
for (let a of permutations(args)) {
function mathML(expr) {
// TODO Implement MathML for all operators.
// TODO Distinguish between fractions and '÷'.
if (isNumber(expr)) return ``;
if (isString(expr)) return ``;
const [fn, ...args] = expr;
const argsStr = args.map(a => needsBrackets(a, fn) ? `` : mathML(a));
switch(fn) {
case 'sqrt': return ``;
case '/': return ``;
case '^': return ``;
case '*': return argsStr.join('');
case '+': return argsStr.join('');
case '-': return argsStr.join('');
default: return ``;
}
}
function match(expr, target) {
// Both expression and target are a number.
if (isNumber(target)) {
return (expr === target) ? [{}] : [];
}
if (isString(target)) {
// Matches any constants (numbers)
if (target[0] == 'c') {
return isNumber(expr) ? [{[target]: expr}] : [];
}
// Matches any variables (strings)
if (target[0] == 'v') {
return isString(expr) ? [{[target]: expr}] : [];
}
// Match any other expressions
return [{[target]: expr}];
}
// Check if functions are the same
if (!isArray(expr)) return [];
function evaluate(expr, vars={}) {
if (isNumber(expr)) return expr;
if (isString(expr)) {
if (expr in vars) return vars[expr];
if (expr in CONSTANTS) return CONSTANTS[expr];
return expr;
}
let [fn, ...args] = expr;
args = args.map(a => evaluate(a, vars));
if (args.every(a => isNumber(a))) {
if (fn in vars) return vars[fn](...args);
if (fn in FN_EVALUATE) return FN_EVALUATE[fn](...args);
if (fn in Math) return Math[fn](...args);
} else if ('+*'.includes(fn)) {
let constant = FN_EVALUATE[fn](...args.filter(a => isNumber(a)));
let variables = args.filter(a => !isNumber(a));
return [fn, constant,...variables]
function functions(tree) {
if (isNumber(tree) || isString(tree)) return [];
let fns = [tree[0]];
for (let a of tree.slice(1)) {
for (let v of functions(a)) {
if (!fns.includes(v)) fns.push(v);
}
}
return fns;
}
function stringify(expr) {
if (isNumber(expr)) return '' + expr;
if (isString(expr)) return expr;
let [fn, ...args] = expr;
args = args.map(a => needsBrackets(a, fn) ? `(${stringify(a)})` : stringify(a));
if (fn in FN_STRINGIFY) return FN_STRINGIFY[fn](...args);
return fn + '(' + args.join(', ') + ')';
}
function needsBrackets(expr, parentOperator) {
if (isNumber(expr) || isString(expr)) return false;
return PRECEDENCE.indexOf(parentOperator) < PRECEDENCE.indexOf(expr[0]);
}