in client/src/components/special/cellprofiler/model/parameters/define-results/renderer/output-formula.js [44:171]
function parseExpression (parts = []) {
if (parts.length === 0) {
return [];
}
let i = 0;
const variables = new Set();
const parse = (root = true) => {
if (parts.length <= i) {
return [];
}
const result = [];
while (i < parts.length) {
const part = parts[i];
i += 1;
switch (part.toLowerCase()) {
case '(':
if (result.length > 0 && !result[result.length - 1].operator) {
result.push({operator: true, value: '*'});
}
result.push({value: parse(false)});
break;
case ')':
if (root) {
throw new Error('Wrong expression');
}
return result;
case '+':
case '-':
case ':':
case '*':
case '/':
case '^':
result.push({operator: true, value: part});
break;
default:
const e = /^([^A-Za-z]+)([A-Za-z]+)/.exec(part);
if (e) {
const number = e[1];
const variable = e[2];
result.push({value: number});
result.push({value: '*', operator: true});
result.push({value: variable});
variables.add(variable);
} else {
result.push({value: part});
if (Number.isNaN(Number(part))) {
variables.add(part);
}
}
break;
}
}
return result;
};
const parsed = parse();
const validate = (parsedExpression) => {
if (typeof parsedExpression === 'string') {
return true;
}
if (parsedExpression.length % 2 !== 1) {
throw new Error('Wrong expression');
}
if (parsedExpression[0].operator) {
throw new Error('Wrong expression');
}
if (
typeof parsedExpression[0].value !== 'string' &&
Array.isArray(parsedExpression[0].value)
) {
validate(parsedExpression[0].value);
}
for (let e = 1; e < parsedExpression.length - 1; e += 2) {
if (!parsedExpression[e] || !parsedExpression[e + 1]) {
throw new Error('Wrong expression');
}
if (!parsedExpression[e].operator || parsedExpression[e + 1].operator) {
throw new Error('Wrong expression');
}
validate(parsedExpression[e + 1].value);
}
return true;
};
validate(parsed);
const extract = (parsedExpression) => {
if (typeof parsedExpression === 'string') {
return parsedExpression;
}
if (typeof parsedExpression === 'object' && parsedExpression.value) {
return extract(parsedExpression.value);
}
const isArray = o => typeof o !== 'string' && Array.isArray(o);
const result = [...parsedExpression].map(o => o.value);
if (isArray(result) && result.length === 1) {
return extract(result[0]);
}
const extractByOperator = (...operator) => {
const idx = result.findIndex(o => operator.includes(o));
if (idx > 0) {
let left = result[idx - 1];
if (isArray(left)) {
left = extract(left);
}
let right = result[idx + 1];
if (isArray(right)) {
right = extract(right);
}
result.splice(idx - 1, 3, {left, right, operator: result[idx]});
extractByOperator(...operator);
}
};
extractByOperator('^');
extractByOperator('*', '/');
extractByOperator('+', '-');
return result[0];
};
const wrap = (part) => {
if (typeof part === 'string') {
return part;
}
const {
left,
right,
operator
} = part;
return [wrap(left), operator, wrap(right)];
};
return {expression: wrap(extract(parsed)), variables: [...variables]};
}