UNPKG

ifc-expressions

Version:

Parsing and evaluation of IFC expressions

261 lines (260 loc) 16.9 kB
"use strict"; var __importDefault = (this && this.__importDefault) || function (mod) { return (mod && mod.__esModule) ? mod : { "default": mod }; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.IfcExpression = exports.IfcExpressionParseResult = exports.IfcExpressionAutocomplete = exports.BuiltinVariableRegistry = exports.ContextObjectType = exports.Types = exports.TypeDisjunction = exports.TupleType = exports.SimpleType = exports.ArrayType = exports.ExprFacade = exports.ExprToTextInputLinker = exports.isExprEvalSuccess = exports.isExprEvalError = exports.isNullish = exports.isPresent = exports.IfcExpressionVisitor = exports.IfcExpressionErrorListener = exports.IfcExpressionEvaluationException = exports.ExprKind = exports.ExprCompiler = exports.NamedObjectAccessor = exports.IfcTypeObjectAccessor = exports.IfcRootObjectAccessor = exports.IfcPropertyAccessor = exports.IfcPropertySetAccessor = exports.IfcTimeStampValue = exports.IfcDurationValue = exports.IfcTimeValue = exports.IfcDateTimeValue = exports.IfcDateValue = exports.ReferenceValue = exports.NumericValue = exports.LogicalValue = exports.BooleanValue = exports.StringValue = exports.IfcElementAccessor = void 0; const antlr4ng_1 = require("antlr4ng"); const decimal_js_1 = __importDefault(require("decimal.js")); const ExprCompiler_js_1 = require("./compiler/ExprCompiler.js"); Object.defineProperty(exports, "ExprCompiler", { enumerable: true, get: function () { return ExprCompiler_js_1.ExprCompiler; } }); const IfcExpressionErrorListener_js_1 = require("./IfcExpressionErrorListener.js"); Object.defineProperty(exports, "IfcExpressionErrorListener", { enumerable: true, get: function () { return IfcExpressionErrorListener_js_1.IfcExpressionErrorListener; } }); const IfcExpressionValidationListener_js_1 = require("./compiler/IfcExpressionValidationListener.js"); const IfcExpressionUtils_js_1 = require("./util/IfcExpressionUtils.js"); Object.defineProperty(exports, "isNullish", { enumerable: true, get: function () { return IfcExpressionUtils_js_1.isNullish; } }); Object.defineProperty(exports, "isPresent", { enumerable: true, get: function () { return IfcExpressionUtils_js_1.isPresent; } }); const IfcElementAccessor_js_1 = require("./context/IfcElementAccessor.js"); Object.defineProperty(exports, "IfcElementAccessor", { enumerable: true, get: function () { return IfcElementAccessor_js_1.IfcElementAccessor; } }); const StringValue_js_1 = require("./value/StringValue.js"); Object.defineProperty(exports, "StringValue", { enumerable: true, get: function () { return StringValue_js_1.StringValue; } }); const NumericValue_js_1 = require("./value/NumericValue.js"); Object.defineProperty(exports, "NumericValue", { enumerable: true, get: function () { return NumericValue_js_1.NumericValue; } }); const BooleanValue_js_1 = require("./value/BooleanValue.js"); Object.defineProperty(exports, "BooleanValue", { enumerable: true, get: function () { return BooleanValue_js_1.BooleanValue; } }); const LogicalValue_js_1 = require("./value/LogicalValue.js"); Object.defineProperty(exports, "LogicalValue", { enumerable: true, get: function () { return LogicalValue_js_1.LogicalValue; } }); const ReferenceValue_js_1 = require("./value/ReferenceValue.js"); Object.defineProperty(exports, "ReferenceValue", { enumerable: true, get: function () { return ReferenceValue_js_1.ReferenceValue; } }); const IfcPropertySetAccessor_js_1 = require("./context/IfcPropertySetAccessor.js"); Object.defineProperty(exports, "IfcPropertySetAccessor", { enumerable: true, get: function () { return IfcPropertySetAccessor_js_1.IfcPropertySetAccessor; } }); const IfcPropertyAccessor_js_1 = require("./context/IfcPropertyAccessor.js"); Object.defineProperty(exports, "IfcPropertyAccessor", { enumerable: true, get: function () { return IfcPropertyAccessor_js_1.IfcPropertyAccessor; } }); const IfcRootObjectAccessor_js_1 = require("./context/IfcRootObjectAccessor.js"); Object.defineProperty(exports, "IfcRootObjectAccessor", { enumerable: true, get: function () { return IfcRootObjectAccessor_js_1.IfcRootObjectAccessor; } }); const IfcTypeObjectAccessor_js_1 = require("./context/IfcTypeObjectAccessor.js"); Object.defineProperty(exports, "IfcTypeObjectAccessor", { enumerable: true, get: function () { return IfcTypeObjectAccessor_js_1.IfcTypeObjectAccessor; } }); const NamedObjectAccessor_js_1 = require("./context/NamedObjectAccessor.js"); Object.defineProperty(exports, "NamedObjectAccessor", { enumerable: true, get: function () { return NamedObjectAccessor_js_1.NamedObjectAccessor; } }); const IfcExpressionParser_js_1 = require("./gen/parser/IfcExpressionParser.js"); const IfcExpressionVisitor_js_1 = require("./gen/parser/IfcExpressionVisitor.js"); Object.defineProperty(exports, "IfcExpressionVisitor", { enumerable: true, get: function () { return IfcExpressionVisitor_js_1.IfcExpressionVisitor; } }); const IfcExpressionLexer_js_1 = require("./gen/parser/IfcExpressionLexer.js"); const IfcExpressionEvaluationException_js_1 = require("./expression/IfcExpressionEvaluationException.js"); Object.defineProperty(exports, "IfcExpressionEvaluationException", { enumerable: true, get: function () { return IfcExpressionEvaluationException_js_1.IfcExpressionEvaluationException; } }); const ArrayValue_js_1 = require("./value/ArrayValue.js"); const ContextObjectValue_js_1 = require("./value/ContextObjectValue.js"); const ExprEvalResult_js_1 = require("./expression/ExprEvalResult.js"); Object.defineProperty(exports, "isExprEvalError", { enumerable: true, get: function () { return ExprEvalResult_js_1.isExprEvalError; } }); Object.defineProperty(exports, "isExprEvalSuccess", { enumerable: true, get: function () { return ExprEvalResult_js_1.isExprEvalSuccess; } }); const ExprKind_js_1 = require("./expression/ExprKind.js"); Object.defineProperty(exports, "ExprKind", { enumerable: true, get: function () { return ExprKind_js_1.ExprKind; } }); const ValidationException_js_1 = require("./error/ValidationException.js"); const ExceptionToExprEvalErrorMapper_js_1 = require("./error/ExceptionToExprEvalErrorMapper.js"); const NopContext_js_1 = require("./context/NopContext.js"); const ExprToTextInputLinker_js_1 = require("./compiler/ExprToTextInputLinker.js"); Object.defineProperty(exports, "ExprToTextInputLinker", { enumerable: true, get: function () { return ExprToTextInputLinker_js_1.ExprToTextInputLinker; } }); const ExprFacade_js_1 = require("./expression/ExprFacade.js"); Object.defineProperty(exports, "ExprFacade", { enumerable: true, get: function () { return ExprFacade_js_1.ExprFacade; } }); const IfcDurationValue_js_1 = require("./value/IfcDurationValue.js"); Object.defineProperty(exports, "IfcDurationValue", { enumerable: true, get: function () { return IfcDurationValue_js_1.IfcDurationValue; } }); const IfcDateValue_js_1 = require("./value/IfcDateValue.js"); Object.defineProperty(exports, "IfcDateValue", { enumerable: true, get: function () { return IfcDateValue_js_1.IfcDateValue; } }); const IfcDateTimeValue_js_1 = require("./value/IfcDateTimeValue.js"); Object.defineProperty(exports, "IfcDateTimeValue", { enumerable: true, get: function () { return IfcDateTimeValue_js_1.IfcDateTimeValue; } }); const IfcTimeValue_js_1 = require("./value/IfcTimeValue.js"); Object.defineProperty(exports, "IfcTimeValue", { enumerable: true, get: function () { return IfcTimeValue_js_1.IfcTimeValue; } }); const IfcTimeStampValue_js_1 = require("./value/IfcTimeStampValue.js"); Object.defineProperty(exports, "IfcTimeStampValue", { enumerable: true, get: function () { return IfcTimeStampValue_js_1.IfcTimeStampValue; } }); const ArrayType_js_1 = require("./type/ArrayType.js"); Object.defineProperty(exports, "ArrayType", { enumerable: true, get: function () { return ArrayType_js_1.ArrayType; } }); const SimpleType_js_1 = require("./type/SimpleType.js"); Object.defineProperty(exports, "SimpleType", { enumerable: true, get: function () { return SimpleType_js_1.SimpleType; } }); const TupleType_js_1 = require("./type/TupleType.js"); Object.defineProperty(exports, "TupleType", { enumerable: true, get: function () { return TupleType_js_1.TupleType; } }); const TypeDisjunction_js_1 = require("./type/TypeDisjunction.js"); Object.defineProperty(exports, "TypeDisjunction", { enumerable: true, get: function () { return TypeDisjunction_js_1.TypeDisjunction; } }); const Types_js_1 = require("./type/Types.js"); Object.defineProperty(exports, "Types", { enumerable: true, get: function () { return Types_js_1.Types; } }); const ContextObjectType_js_1 = require("./type/ContextObjectType.js"); Object.defineProperty(exports, "ContextObjectType", { enumerable: true, get: function () { return ContextObjectType_js_1.ContextObjectType; } }); const BuiltinVariableRegistry_js_1 = require("./builtin/BuiltinVariableRegistry.js"); Object.defineProperty(exports, "BuiltinVariableRegistry", { enumerable: true, get: function () { return BuiltinVariableRegistry_js_1.BuiltinVariableRegistry; } }); const IfcExpressionAutocomplete_js_1 = require("./autocomplete/IfcExpressionAutocomplete.js"); Object.defineProperty(exports, "IfcExpressionAutocomplete", { enumerable: true, get: function () { return IfcExpressionAutocomplete_js_1.IfcExpressionAutocomplete; } }); const ObjectAccessorValue_js_1 = require("./value/ObjectAccessorValue.js"); class IfcExpressionParseResult { constructor(input, typeManager, exprContext, builtinVariableRegistry) { this._typeManager = typeManager; this._parseTree = exprContext; this._input = input; this._builtinVariableRegistry = builtinVariableRegistry; } get typeManager() { return this._typeManager; } get parseTree() { return this._parseTree; } get input() { return this._input; } get builtinVariableRegistry() { return this._builtinVariableRegistry; } } exports.IfcExpressionParseResult = IfcExpressionParseResult; class IfcExpression { static parse(input, errorListener, options = {}) { const builtinVariableRegistry = options.builtinVariableRegistry ?? BuiltinVariableRegistry_js_1.BuiltinVariableRegistry.getDefaultRegistry(); const chars = antlr4ng_1.CharStream.fromString(input); const lexer = new IfcExpressionLexer_js_1.IfcExpressionLexer(chars); const tokens = new antlr4ng_1.CommonTokenStream(lexer); const parser = new IfcExpressionParser_js_1.IfcExpressionParser(tokens); lexer.removeErrorListeners(); parser.removeErrorListeners(); const myErrorListener = new IfcExpressionErrorListener_js_1.IfcExpressionErrorListener(); if ((0, IfcExpressionUtils_js_1.isPresent)(errorListener)) { lexer.addErrorListener(errorListener); parser.addErrorListener(errorListener); } lexer.addErrorListener(myErrorListener); parser.addErrorListener(myErrorListener); let expr; expr = parser.expr(); const validationListener = new IfcExpressionValidationListener_js_1.IfcExpressionValidationListener(builtinVariableRegistry); if (!myErrorListener.isErrorOccurred()) { const walker = new antlr4ng_1.ParseTreeWalker(); try { walker.walk(validationListener, expr); } catch (e) { if (e instanceof ValidationException_js_1.ValidationException) { if (errorListener instanceof IfcExpressionErrorListener_js_1.IfcExpressionErrorListener) { errorListener.validationException(e); } myErrorListener.validationException(e); } } } return new IfcExpressionParseResult(input, validationListener.getTypeManager(), expr, builtinVariableRegistry); } static compile(parseResult) { const compiler = new ExprCompiler_js_1.ExprCompiler(parseResult.typeManager, parseResult.builtinVariableRegistry); const expr = compiler.visit(parseResult.parseTree); ExprToTextInputLinker_js_1.ExprToTextInputLinker.linkTextToExpressions(parseResult.input, expr, compiler.getExprManager()); return new ExprFacade_js_1.ExprFacade(expr); } static evaluate(expression, context = new NopContext_js_1.NopContext(), options = {}) { const errorListener = new IfcExpressionErrorListener_js_1.IfcExpressionErrorListener(); const parseResult = IfcExpression.parse(expression, errorListener, options); if (errorListener.isErrorOccurred()) { return (0, ExceptionToExprEvalErrorMapper_js_1.mapException)(errorListener.getException()); } const compiledExpression = this.compile(parseResult); return compiledExpression.evaluate(context); } static formatError(input, error) { const lines = ["** Error **"]; if (!(0, IfcExpressionUtils_js_1.isNullish)(error["textSpan"])) { const span = error["textSpan"]; const underlined = span.underline(input, "^"); const startString = "Input: "; const indented = this.indent(underlined, startString.length); const replaced = startString + indented.substr(startString.length); replaced.split("\n").forEach((line) => lines.push(line)); } lines.push("Problem: " + error.message); return lines.join("\n"); } static indent(s, by) { return s .split("\n") .map((line) => " ".repeat(by) + line) .join("\n"); } static evaluateExpression(expr, context = new NopContext_js_1.NopContext()) { return expr.evaluate(context); } static unwrapValue(value) { return this.unwrapUnknownValue(value); } static unwrapUnknownValue(value) { if (value instanceof StringValue_js_1.StringValue || value instanceof BooleanValue_js_1.BooleanValue) { return value.getValue(); } if (value instanceof NumericValue_js_1.NumericValue) { return value.getValue(); } if (value instanceof LogicalValue_js_1.LogicalValue) { return value.isUnknown() ? undefined : value.getValue(); } if (value instanceof ReferenceValue_js_1.ReferenceValue) { return value.getValue(); } if (value instanceof IfcTimeStampValue_js_1.IfcTimeStampValue) { return value.getTimeStampSeconds(); } if (value instanceof IfcDateValue_js_1.IfcDateValue || value instanceof IfcDateTimeValue_js_1.IfcDateTimeValue || value instanceof IfcTimeValue_js_1.IfcTimeValue || value instanceof IfcDurationValue_js_1.IfcDurationValue) { return value.toString(); } if (value instanceof ArrayValue_js_1.ArrayValue) { return value.getValue().map((entry) => this.unwrapUnknownValue(entry)); } if (value instanceof ObjectAccessorValue_js_1.ObjectAccessorValue) { return this.unwrapObjectAccessor(value.getValue()); } if (value instanceof ContextObjectValue_js_1.ContextObjectValue) { return this.unwrapPlainObject(value.getValue()); } if (decimal_js_1.default.isDecimal(value)) { return value; } if (typeof value === "number") { return NumericValue_js_1.NumericValue.of(value).getValue(); } if (typeof value === "string" || typeof value === "boolean" || typeof value === "undefined") { return value; } if (Array.isArray(value)) { return value.map((entry) => this.unwrapUnknownValue(entry)); } if (value instanceof Date) { return value.toISOString(); } if (this.isPlainObject(value)) { return this.unwrapPlainObject(value); } return undefined; } static unwrapObjectAccessor(objectAccessor) { const result = {}; for (const attributeName of objectAccessor.listAttributes()) { const attributeValue = objectAccessor.getAttribute(attributeName); if (typeof attributeValue !== "undefined") { result[attributeName] = this.unwrapUnknownValue(attributeValue); } } return result; } static unwrapPlainObject(value) { const result = {}; for (const [key, nestedValue] of Object.entries(value)) { result[key] = this.unwrapUnknownValue(nestedValue); } return result; } static isPlainObject(value) { return (typeof value === "object" && value !== null && Object.getPrototypeOf(value) === Object.prototype); } } exports.IfcExpression = IfcExpression; //# sourceMappingURL=IfcExpression.js.map