ifc-expressions
Version:
Parsing and evaluation of IFC expressions
261 lines (260 loc) • 16.9 kB
JavaScript
;
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