I played around with this a while today and got a version working that does not require defining a formal AST, and only uses eval() to instantiate an arrow function that calculates each index of the output based on the input lists and an incrementing input index.
'use strict';
const json={
formula: '{{a45bc2a1-ed82-4ccd-a455-f7959e875aad}}+({{f6c2ef2b-a4fa-4cfb-b62d-d0d7c3e266d9}}*{{335563ad-a715-47b9-8e54-2b8553768168}})'
}
const map = {
'a45bc2a1-ed82-4ccd-a455-f7959e875aad': [1, 2, 3, 4, 5],
'f6c2ef2b-a4fa-4cfb-b62d-d0d7c3e266d9': [10, 20, 30, 40, 50],
'335563ad-a715-47b9-8e54-2b8553768168': [1, 2, 3, 4, 5]
}
function parseFormula (formula) {
const template = /{{([^}]*)}}/;
const idList = [];
for (let i = 0; template.test(formula); i++) {
idList.push(formula.match(template)[0].replace(/[{}]/g, ''));
formula = formula.replace(template, `input[${i}][i]`);
}
return {idList, formula};
}
function calculateFormula(map, parsed) {
const input = [];
const result = [];
const lambda = eval(`(input, i) => ${parsed.formula}`)
parsed.idList.forEach(id => input.push(map[id]));
for (let i = 0; i < input[0].length; i++) {
result.push(lambda(input, i));
}
return result;
}
const parsed = parseFormula(json.formula);
console.log(parsed);
console.log(calculateFormula(map, parsed));
Output:
{
idList: [
'a45bc2a1-ed82-4ccd-a455-f7959e875aad',
'f6c2ef2b-a4fa-4cfb-b62d-d0d7c3e266d9',
'335563ad-a715-47b9-8e54-2b8553768168'
],
formula: 'input[0][i]+(input[1][i]*input[2][i])'
}
[ 11, 42, 93, 164, 255 ]