@qrvey/formula-lang
Version:
QFormula support for qrvey projects
90 lines • 4.16 kB
JavaScript
import { getNodeValue } from '../utils';
import { createUnknownValue } from './syntax-errors';
import { getFunctionPrimitive } from '../utils/primitiveFunctions';
import { AST_PRIMITIVES, AST_TYPES } from '../constants';
import { FUNCTION_LIST, getFunctionDetail } from '../functions';
import { MissingParenthesisError } from '../errors';
export function transformFunctionExpression(program, node, inference, context, transformNodeFunction) {
const fnIdentifier = node.getChild('FunctionIdentifier');
const fnName = getNodeValue(program, fnIdentifier);
const fnString = getNodeValue(program, node);
const parenthesisStart = node.getChild('ParenthesisStart');
const parenthesisEnd = node.getChild('ParenthesisEnd');
const args = getFunctionArguments(node, parenthesisStart, program, inference, context, transformNodeFunction);
const functionIdentifier = createPositionASTFromSyntaxNode(fnIdentifier);
const baseNode = {
type: AST_TYPES.functionCall,
name: getNodeValue(program, fnIdentifier),
arguments: args,
from: node.from,
to: node.to,
parenthesisStart: !!parenthesisStart,
parenthesisEnd: !!parenthesisEnd,
functionText: fnString,
functionIdentifier,
};
const functionExists = FUNCTION_LIST.includes(fnName);
const functionDetail = functionExists
? getFunctionDetail(fnName)
: undefined;
const primitive = functionDetail
? getFunctionPrimitive(functionDetail, baseNode.arguments)
: AST_PRIMITIVES.UNKNOWN;
const resultNode = Object.assign(Object.assign({}, baseNode), { primitive });
if (functionExists && (!parenthesisStart || !parenthesisEnd)) {
inference.errorList.push(new MissingParenthesisError(Object.assign(Object.assign({}, resultNode), { from: !parenthesisStart ? resultNode.from : resultNode.to })));
}
inference.formulaFunctions.push(resultNode);
return resultNode;
}
function getFunctionArguments(fnNode, parenthesisStart, program, inference, context, transformNodeFunction) {
const allocatedArgs = [];
const args = fnNode.getChild('FunctionArguments');
if (parenthesisStart) {
allocatedArgs.push(...getFunctionStartingCommas(fnNode, program, parenthesisStart));
}
allocatedArgs.push(...extractFunctionArguments(args, fnNode, program, inference, context, transformNodeFunction));
return allocatedArgs;
}
function extractFunctionArguments(args, fnNode, program, inference, context, transformNodeFunction) {
const resultArgs = [];
args === null || args === void 0 ? void 0 : args.cursor().iterate(({ node: argNode }) => {
if (argNode.name === 'Expression' || argNode.type.isError) {
if (argNode.from === fnNode.to)
return false;
const astNode = createCommonASTFromNode(program, argNode, inference, context, transformNodeFunction);
if (astNode)
resultArgs.push(astNode);
return false;
}
});
return resultArgs;
}
function getFunctionStartingCommas(fnNode, program, parenthesisStart) {
const resultArgs = [];
fnNode === null || fnNode === void 0 ? void 0 : fnNode.cursor().iterate(({ node: fnNodeChild }) => {
if (fnNodeChild.name === 'FunctionArguments') {
return false; // Stop entering on function arguments
}
if (fnNodeChild.type.isError &&
getNodeValue(program, fnNodeChild) === ',' &&
fnNodeChild.from > parenthesisStart.from) {
const errorNodeStart = parenthesisStart.from + 1;
resultArgs.push(createUnknownValue({
from: errorNodeStart,
to: fnNodeChild.from,
}));
}
});
return resultArgs;
}
function createCommonASTFromNode(program, node, inference, context, transformNodeFunction) {
if (node.type.isError) {
return createUnknownValue(node);
}
return transformNodeFunction(program, node, inference, context);
}
export function createPositionASTFromSyntaxNode({ from, to, }) {
return { from, to };
}
//# sourceMappingURL=formula-parser.js.map