Secure your code as it's written. Use Snyk Code to scan source code in minutes - no build needed - and fix issues immediately.
function same(expr1, expr2) {
// Handle numbers and variables.
if (expr1 === expr2) return true;
// Different functions are always unequal (we assume already simplified).
if (!isArray(expr1) || !isArray(expr2)) return false;
if (expr1[0] !== expr2[0]) return false;
let [fn, ...args1] = expr1;
let args2 = expr2.slice(1);
if ('+*'.includes(fn)) {
// Addition and multiplication are commutative.
let orders = permutations(args1);
return orders.some(p => p.every((a, i) => same(a, args2[i])));
} else {
return args1.every((a, i) => same(a, args2[i]))
}
}
// 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)) {
let placeholders = mergePlaceholders(a.map((a, i) => match(a, target[i+1])));
if (placeholders.length) return placeholders;
}
return [];
}
return mergePlaceholders(args.map((a, i) => match(a, target[i+1])));
}
function flattenAssociative(expr) {
if (isString(expr) || isNumber(expr)) return expr;
let [fn, ...args] = expr;
args = args.map(a => flattenAssociative(a));
if (!'+*'.includes(fn)) return [fn, ...args];
let newArgs = [];
for (let a of args) {
if (isArray(a) && a[0] == fn) {
newArgs.push(...a.slice(1))
} else {
newArgs.push(a);
}
}
return [fn, ...newArgs];
}