UNPKG

ifc-expressions

Version:

Parsing and evaluation of IFC expressions

126 lines (125 loc) 6.47 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Func = void 0; const IfcExpressionFunctionConfigException_js_1 = require("../../error/IfcExpressionFunctionConfigException.js"); const IfcExpressionUtils_js_1 = require("../../util/IfcExpressionUtils.js"); const ExprEvalResult_js_1 = require("../ExprEvalResult.js"); const ExprKind_js_1 = require("../ExprKind.js"); const Types_js_1 = require("../../type/Types.js"); const MissingFunctionArgumentException_js_1 = require("../../error/MissingFunctionArgumentException.js"); const WrongFunctionArgumentTypeException_js_1 = require("../../error/WrongFunctionArgumentTypeException.js"); const SpuriousFunctionArgumentException_js_1 = require("../../error/SpuriousFunctionArgumentException.js"); class Func { constructor(name, args) { this.name = name; if ((0, IfcExpressionUtils_js_1.isNullish)(this.name)) { throw new IfcExpressionFunctionConfigException_js_1.IfcExpressionFunctionConfigException("Function must have a name"); } this.formalArguments = args; this.checkArgs(args); } checkArgumentsAndGetReturnType(argumentTypes, ctx) { this.checkArgumentTypes(argumentTypes, ctx); return this.getReturnType(argumentTypes.map((t) => t[1])); } checkArgumentTypes(providedArgumentTypes, ctx) { const numProvided = providedArgumentTypes.length; if (!(0, IfcExpressionUtils_js_1.isNullish)(this.formalArguments)) { if (numProvided > this.formalArguments.length) { throw new SpuriousFunctionArgumentException_js_1.SpuriousFunctionArgumentException(this.name, "[unexpected argument]", this.formalArguments.length, ctx, `Function expects (at most) ${this.formalArguments.length} arguments`); } for (let i = 0; i < this.formalArguments.length; i++) { const currentArg = this.formalArguments[i]; if (numProvided > i) { Types_js_1.Types.requireWeakIsAssignableFrom(this.formalArguments[i].getType(), providedArgumentTypes[i][1], () => new WrongFunctionArgumentTypeException_js_1.WrongFunctionArgumentTypeException(this.name, this.formalArguments[i].name, this.formalArguments[i].getType(), providedArgumentTypes[i][1], i, providedArgumentTypes[i][0])); } else { if (currentArg.hasDefaultValue()) { //should be fine. } if (currentArg.required) { throw new MissingFunctionArgumentException_js_1.MissingFunctionArgumentException(this.name, currentArg.name, i, ctx); } } } } } getName() { return this.name; } evaluate(callingExpr, funcArgs) { const evaluatedArguments = this.getArgumentValues(callingExpr, funcArgs); if ((0, ExprEvalResult_js_1.isExprEvalError)(evaluatedArguments)) { return evaluatedArguments; } const argumentsReadyForUse = new Map(); for (const [argName, argValue] of evaluatedArguments.entries()) { if ((0, ExprEvalResult_js_1.isExprEvalError)(argValue)) { return argValue; } argumentsReadyForUse.set(argName, argValue.result); } return this.calculateResult(callingExpr, argumentsReadyForUse); } /** * Override to transform individual arguments if needed. After this step, if any of the ExprEvalResult objects in the * returned array is an ExprEvalError, the function evaluation fails. * @param callingExpr * @param evaluatedArguments * @protected */ transformArguments(callingExpr, evaluatedArguments) { } /** * Gets the argument values from the list of provided arguments in the form of 'name' -> ExprEvalResult (which may contain errors). * Generates an error if a required value is missing. * @param callingExpr * @param provided * @protected */ getArgumentValues(callingExpr, provided) { const result = new Map(); const numProvided = provided.length; if (!(0, IfcExpressionUtils_js_1.isNullish)(this.formalArguments)) { for (let i = 0; i < this.formalArguments.length; i++) { const currentArg = this.formalArguments[i]; if (numProvided > i) { result.set(currentArg.name, currentArg.transformValue(callingExpr, provided[i])); } else { if (currentArg.hasDefaultValue()) { result.set(currentArg.name, new ExprEvalResult_js_1.ExprEvalSuccessObj(currentArg.defaultValue)); } if (currentArg.required) { return new ExprEvalResult_js_1.ExprEvalMissingRequiredFunctionArgumentErrorObj(ExprKind_js_1.ExprKind.FUNCTION_ARGUMENTS, `Required argument ${currentArg.name}, expected at position ${i} (starting at 0), is missing`, this.name, currentArg.name, i, callingExpr.getTextSpan()); } } } } this.transformArguments(callingExpr, result); return result; } checkArgs(args) { if (!Array.isArray(this.formalArguments)) { throw new IfcExpressionFunctionConfigException_js_1.IfcExpressionFunctionConfigException("Formal function arguments is not an array"); } let optionalArgsReached = false; const names = new Set(); for (let i = 0; i < this.formalArguments.length; i++) { if (names.has(this.formalArguments[i].name)) { throw new IfcExpressionFunctionConfigException_js_1.IfcExpressionFunctionConfigException(`Duplicate argument name '${this.formalArguments[i].name}'.`); } if (optionalArgsReached) { if (this.formalArguments[i].required) { throw new IfcExpressionFunctionConfigException_js_1.IfcExpressionFunctionConfigException(`Optional arguments must follow required ones. Argument '${this.formalArguments[i].name}' is required but follows an optional one`); } } else { if (!this.formalArguments[i].required) { optionalArgsReached = true; } } } } } exports.Func = Func; //# sourceMappingURL=Func.js.map