ifc-expressions
Version:
Parsing and evaluation of IFC expressions
126 lines (125 loc) • 6.47 kB
JavaScript
"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