ifc-expressions 2.3.0 → 3.0.0-beta.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. package/README.md +242 -30
  2. package/dist/IfcExpression.d.ts +24 -26
  3. package/dist/IfcExpressionErrorListener.d.ts +3 -3
  4. package/dist/IfcExpressionOptions.d.ts +4 -0
  5. package/dist/autocomplete/CompletionItem.d.ts +24 -0
  6. package/dist/autocomplete/IfcExpressionAutocomplete.d.ts +10 -0
  7. package/dist/builtin/BuiltinRuntimeValueConverter.d.ts +7 -0
  8. package/dist/builtin/BuiltinVariableRegistry.d.ts +50 -0
  9. package/dist/cjs/IfcExpression.js +112 -37
  10. package/dist/cjs/IfcExpression.js.map +1 -1
  11. package/dist/cjs/IfcExpressionErrorListener.js +3 -8
  12. package/dist/cjs/IfcExpressionErrorListener.js.map +1 -1
  13. package/dist/cjs/IfcExpressionOptions.js +3 -0
  14. package/dist/cjs/IfcExpressionOptions.js.map +1 -0
  15. package/dist/cjs/autocomplete/CompletionItem.js +3 -0
  16. package/dist/cjs/autocomplete/CompletionItem.js.map +1 -0
  17. package/dist/cjs/autocomplete/IfcExpressionAutocomplete.js +532 -0
  18. package/dist/cjs/autocomplete/IfcExpressionAutocomplete.js.map +1 -0
  19. package/dist/cjs/builtin/BuiltinRuntimeValueConverter.js +124 -0
  20. package/dist/cjs/builtin/BuiltinRuntimeValueConverter.js.map +1 -0
  21. package/dist/cjs/builtin/BuiltinVariableRegistry.js +405 -0
  22. package/dist/cjs/builtin/BuiltinVariableRegistry.js.map +1 -0
  23. package/dist/cjs/compiler/ExprCompiler.js +44 -41
  24. package/dist/cjs/compiler/ExprCompiler.js.map +1 -1
  25. package/dist/cjs/compiler/ExprManager.js.map +1 -1
  26. package/dist/cjs/compiler/IfcExpressionValidationListener.js +85 -25
  27. package/dist/cjs/compiler/IfcExpressionValidationListener.js.map +1 -1
  28. package/dist/cjs/compiler/TypeManager.js.map +1 -1
  29. package/dist/cjs/context/IfcExpressionContext.js.map +1 -1
  30. package/dist/cjs/context/NopContext.js +3 -0
  31. package/dist/cjs/context/NopContext.js.map +1 -1
  32. package/dist/cjs/documentation/Documentation.js +11 -0
  33. package/dist/cjs/documentation/Documentation.js.map +1 -0
  34. package/dist/cjs/error/ExpressionTypeError.js.map +1 -1
  35. package/dist/cjs/error/IfcExpressionBuiltinConfigException.js +10 -0
  36. package/dist/cjs/error/IfcExpressionBuiltinConfigException.js.map +1 -0
  37. package/dist/cjs/error/InvalidSyntaxException.js.map +1 -1
  38. package/dist/cjs/error/NoSuchFunctionException.js.map +1 -1
  39. package/dist/cjs/error/NoSuchMemberException.js +13 -0
  40. package/dist/cjs/error/NoSuchMemberException.js.map +1 -0
  41. package/dist/cjs/error/ValidationException.js.map +1 -1
  42. package/dist/cjs/error/WrongFunctionArgumentTypeException.js.map +1 -1
  43. package/dist/cjs/expression/ExprKind.js +3 -0
  44. package/dist/cjs/expression/ExprKind.js.map +1 -1
  45. package/dist/cjs/expression/function/Func.js +18 -14
  46. package/dist/cjs/expression/function/Func.js.map +1 -1
  47. package/dist/cjs/expression/function/FuncArg.js +11 -5
  48. package/dist/cjs/expression/function/FuncArg.js.map +1 -1
  49. package/dist/cjs/expression/function/IfcExpressionFunctions.js +198 -42
  50. package/dist/cjs/expression/function/IfcExpressionFunctions.js.map +1 -1
  51. package/dist/cjs/expression/function/impl/CHOOSE.js.map +1 -1
  52. package/dist/cjs/expression/function/impl/IF.js.map +1 -1
  53. package/dist/cjs/expression/function/impl/MAP.js.map +1 -1
  54. package/dist/cjs/expression/function/impl/ReplacePattern.js +20 -2
  55. package/dist/cjs/expression/function/impl/ReplacePattern.js.map +1 -1
  56. package/dist/cjs/expression/reference/BuiltinFunctionCallExpr.js +59 -0
  57. package/dist/cjs/expression/reference/BuiltinFunctionCallExpr.js.map +1 -0
  58. package/dist/cjs/expression/reference/BuiltinPropertyAccessExpr.js +34 -0
  59. package/dist/cjs/expression/reference/BuiltinPropertyAccessExpr.js.map +1 -0
  60. package/dist/cjs/expression/reference/BuiltinRootReferenceExpr.js +29 -0
  61. package/dist/cjs/expression/reference/BuiltinRootReferenceExpr.js.map +1 -0
  62. package/dist/cjs/gen/parser/IfcExpressionLexer.js +126 -104
  63. package/dist/cjs/gen/parser/IfcExpressionLexer.js.map +1 -1
  64. package/dist/cjs/gen/parser/IfcExpressionListener.js +7 -4
  65. package/dist/cjs/gen/parser/IfcExpressionListener.js.map +1 -1
  66. package/dist/cjs/gen/parser/IfcExpressionParser.js +739 -682
  67. package/dist/cjs/gen/parser/IfcExpressionParser.js.map +1 -1
  68. package/dist/cjs/gen/parser/IfcExpressionVisitor.js +4 -4
  69. package/dist/cjs/gen/parser/IfcExpressionVisitor.js.map +1 -1
  70. package/dist/cjs/index.js +4 -1
  71. package/dist/cjs/index.js.map +1 -1
  72. package/dist/cjs/type/ContextObjectType.js +45 -0
  73. package/dist/cjs/type/ContextObjectType.js.map +1 -0
  74. package/dist/cjs/type/Types.js +4 -6
  75. package/dist/cjs/type/Types.js.map +1 -1
  76. package/dist/cjs/value/ContextObjectValue.js +23 -0
  77. package/dist/cjs/value/ContextObjectValue.js.map +1 -0
  78. package/dist/cjs/value/ExpressionValue.js.map +1 -1
  79. package/dist/cjs/value/Value.js.map +1 -1
  80. package/dist/compiler/ExprCompiler.d.ts +8 -3
  81. package/dist/compiler/ExprManager.d.ts +1 -1
  82. package/dist/compiler/IfcExpressionValidationListener.d.ts +9 -3
  83. package/dist/compiler/TypeManager.d.ts +1 -1
  84. package/dist/context/IfcExpressionContext.d.ts +3 -4
  85. package/dist/context/NopContext.d.ts +1 -0
  86. package/dist/documentation/Documentation.d.ts +12 -0
  87. package/dist/error/ExpressionTypeError.d.ts +1 -1
  88. package/dist/error/IfcExpressionBuiltinConfigException.d.ts +3 -0
  89. package/dist/error/InvalidSyntaxException.d.ts +1 -1
  90. package/dist/error/NoSuchFunctionException.d.ts +1 -1
  91. package/dist/error/NoSuchMemberException.d.ts +6 -0
  92. package/dist/error/ValidationException.d.ts +1 -1
  93. package/dist/error/WrongFunctionArgumentTypeException.d.ts +1 -1
  94. package/dist/expression/ExprKind.d.ts +3 -0
  95. package/dist/expression/function/Func.d.ts +7 -21
  96. package/dist/expression/function/FuncArg.d.ts +6 -5
  97. package/dist/expression/function/IfcExpressionFunctions.d.ts +1 -0
  98. package/dist/expression/function/impl/CHOOSE.d.ts +1 -1
  99. package/dist/expression/function/impl/IF.d.ts +1 -1
  100. package/dist/expression/function/impl/MAP.d.ts +1 -1
  101. package/dist/expression/reference/BuiltinFunctionCallExpr.d.ts +19 -0
  102. package/dist/expression/reference/BuiltinPropertyAccessExpr.d.ts +15 -0
  103. package/dist/expression/reference/BuiltinRootReferenceExpr.d.ts +14 -0
  104. package/dist/gen/parser/IfcExpressionLexer.d.ts +9 -8
  105. package/dist/gen/parser/IfcExpressionListener.d.ts +89 -59
  106. package/dist/gen/parser/IfcExpressionParser.d.ts +192 -169
  107. package/dist/gen/parser/IfcExpressionVisitor.d.ts +51 -35
  108. package/dist/index.d.ts +2 -2
  109. package/dist/mjs/IfcExpression.js +104 -32
  110. package/dist/mjs/IfcExpression.js.map +1 -1
  111. package/dist/mjs/IfcExpressionErrorListener.js +3 -8
  112. package/dist/mjs/IfcExpressionErrorListener.js.map +1 -1
  113. package/dist/mjs/IfcExpressionOptions.js +2 -0
  114. package/dist/mjs/IfcExpressionOptions.js.map +1 -0
  115. package/dist/mjs/autocomplete/CompletionItem.js +2 -0
  116. package/dist/mjs/autocomplete/CompletionItem.js.map +1 -0
  117. package/dist/mjs/autocomplete/IfcExpressionAutocomplete.js +528 -0
  118. package/dist/mjs/autocomplete/IfcExpressionAutocomplete.js.map +1 -0
  119. package/dist/mjs/builtin/BuiltinRuntimeValueConverter.js +117 -0
  120. package/dist/mjs/builtin/BuiltinRuntimeValueConverter.js.map +1 -0
  121. package/dist/mjs/builtin/BuiltinVariableRegistry.js +399 -0
  122. package/dist/mjs/builtin/BuiltinVariableRegistry.js.map +1 -0
  123. package/dist/mjs/compiler/ExprCompiler.js +43 -40
  124. package/dist/mjs/compiler/ExprCompiler.js.map +1 -1
  125. package/dist/mjs/compiler/ExprManager.js.map +1 -1
  126. package/dist/mjs/compiler/IfcExpressionValidationListener.js +85 -22
  127. package/dist/mjs/compiler/IfcExpressionValidationListener.js.map +1 -1
  128. package/dist/mjs/compiler/TypeManager.js.map +1 -1
  129. package/dist/mjs/context/IfcExpressionContext.js.map +1 -1
  130. package/dist/mjs/context/NopContext.js +3 -0
  131. package/dist/mjs/context/NopContext.js.map +1 -1
  132. package/dist/mjs/documentation/Documentation.js +7 -0
  133. package/dist/mjs/documentation/Documentation.js.map +1 -0
  134. package/dist/mjs/error/ExpressionTypeError.js.map +1 -1
  135. package/dist/mjs/error/IfcExpressionBuiltinConfigException.js +6 -0
  136. package/dist/mjs/error/IfcExpressionBuiltinConfigException.js.map +1 -0
  137. package/dist/mjs/error/InvalidSyntaxException.js.map +1 -1
  138. package/dist/mjs/error/NoSuchFunctionException.js.map +1 -1
  139. package/dist/mjs/error/NoSuchMemberException.js +9 -0
  140. package/dist/mjs/error/NoSuchMemberException.js.map +1 -0
  141. package/dist/mjs/error/ValidationException.js.map +1 -1
  142. package/dist/mjs/error/WrongFunctionArgumentTypeException.js.map +1 -1
  143. package/dist/mjs/expression/ExprKind.js +3 -0
  144. package/dist/mjs/expression/ExprKind.js.map +1 -1
  145. package/dist/mjs/expression/function/Func.js +18 -14
  146. package/dist/mjs/expression/function/Func.js.map +1 -1
  147. package/dist/mjs/expression/function/FuncArg.js +11 -5
  148. package/dist/mjs/expression/function/FuncArg.js.map +1 -1
  149. package/dist/mjs/expression/function/IfcExpressionFunctions.js +198 -42
  150. package/dist/mjs/expression/function/IfcExpressionFunctions.js.map +1 -1
  151. package/dist/mjs/expression/function/impl/CHOOSE.js.map +1 -1
  152. package/dist/mjs/expression/function/impl/IF.js.map +1 -1
  153. package/dist/mjs/expression/function/impl/MAP.js.map +1 -1
  154. package/dist/mjs/expression/function/impl/ReplacePattern.js +20 -2
  155. package/dist/mjs/expression/function/impl/ReplacePattern.js.map +1 -1
  156. package/dist/mjs/expression/reference/BuiltinFunctionCallExpr.js +55 -0
  157. package/dist/mjs/expression/reference/BuiltinFunctionCallExpr.js.map +1 -0
  158. package/dist/mjs/expression/reference/BuiltinPropertyAccessExpr.js +30 -0
  159. package/dist/mjs/expression/reference/BuiltinPropertyAccessExpr.js.map +1 -0
  160. package/dist/mjs/expression/reference/BuiltinRootReferenceExpr.js +25 -0
  161. package/dist/mjs/expression/reference/BuiltinRootReferenceExpr.js.map +1 -0
  162. package/dist/mjs/gen/parser/IfcExpressionLexer.js +101 -104
  163. package/dist/mjs/gen/parser/IfcExpressionLexer.js.map +1 -1
  164. package/dist/mjs/gen/parser/IfcExpressionListener.js +5 -3
  165. package/dist/mjs/gen/parser/IfcExpressionListener.js.map +1 -1
  166. package/dist/mjs/gen/parser/IfcExpressionParser.js +700 -670
  167. package/dist/mjs/gen/parser/IfcExpressionParser.js.map +1 -1
  168. package/dist/mjs/gen/parser/IfcExpressionVisitor.js +2 -3
  169. package/dist/mjs/gen/parser/IfcExpressionVisitor.js.map +1 -1
  170. package/dist/mjs/index.js +1 -1
  171. package/dist/mjs/index.js.map +1 -1
  172. package/dist/mjs/type/ContextObjectType.js +41 -0
  173. package/dist/mjs/type/ContextObjectType.js.map +1 -0
  174. package/dist/mjs/type/Types.js +4 -6
  175. package/dist/mjs/type/Types.js.map +1 -1
  176. package/dist/mjs/value/ContextObjectValue.js +19 -0
  177. package/dist/mjs/value/ContextObjectValue.js.map +1 -0
  178. package/dist/mjs/value/ExpressionValue.js.map +1 -1
  179. package/dist/mjs/value/Value.js.map +1 -1
  180. package/dist/type/ContextObjectType.d.ts +17 -0
  181. package/dist/type/Types.d.ts +2 -6
  182. package/dist/value/ContextObjectValue.d.ts +11 -0
  183. package/dist/value/ExpressionValue.d.ts +2 -1
  184. package/dist/value/Value.d.ts +1 -1
  185. package/package.json +5 -3
package/README.md CHANGED
@@ -20,8 +20,8 @@ implementation of `src/context/IfcExpressionContext`. Without such a context, th
20
20
  contain references to the model cannot be evaluated.
21
21
 
22
22
  ```ts
23
- import {IfcExpression} from "ifc-expression";
24
- import {IfcExpressionContext} from "./IfcExpressionContext";
23
+ import { IfcExpression } from "ifc-expression";
24
+ import { IfcExpressionContext } from "./IfcExpressionContext";
25
25
 
26
26
  const result = IfcExpression.evaluate("1 + 1"); // evaluation without context
27
27
  console.log(JSON.stringify(result));
@@ -30,11 +30,222 @@ console.log(JSON.stringify(result));
30
30
  // result: NumericValue {
31
31
  // value: 2
32
32
  // }
33
- //}
34
- const ctx: IfcExpressionContext = ... ; // set to your context here
35
- const result2 = IfcExpression.evaluate("$element.property('width').value() * 2 ", ctx);
33
+ // }
34
+ const ctx: IfcExpressionContext = ...; // set to your context here
35
+ const result2 = IfcExpression.evaluate(
36
+ "$element.property('width').value() * 2",
37
+ ctx
38
+ );
36
39
  ```
37
40
 
41
+ ## Plain JS Value Unwrapping
42
+
43
+ `IfcExpression.evaluate(...)` returns library value objects such as `NumericValue`, `StringValue`, `LogicalValue`, `ContextObjectValue`, or IFC object references.
44
+ If you want a plain value structure for downstream code, use `IfcExpression.unwrapValue(...)` on the successful result value.
45
+
46
+ ```ts
47
+ import { IfcExpression, isExprEvalSuccess } from "ifc-expression";
48
+
49
+ const evaluation = IfcExpression.evaluate("$result.statusCode", ctx, {
50
+ builtinVariableRegistry,
51
+ });
52
+
53
+ if (isExprEvalSuccess(evaluation)) {
54
+ const value = IfcExpression.unwrapValue(evaluation.result);
55
+ // value is a Decimal here
56
+ }
57
+ ```
58
+
59
+ `unwrapValue` preserves the expression model's precision and nullability semantics:
60
+
61
+ - `NumericValue` and raw JS `number` values inside client builtin objects become `Decimal`
62
+ - `StringValue` becomes `string`
63
+ - `BooleanValue` becomes `boolean`
64
+ - `LogicalValue.UNKNOWN` becomes `undefined`
65
+ - `IfcTimeStampValue` becomes `Decimal`
66
+ - `IfcDateValue`, `IfcDateTimeValue`, `IfcTimeValue`, and `IfcDurationValue` become their canonical string representation
67
+ - arrays are unwrapped recursively
68
+ - client builtin objects are unwrapped recursively to plain JS object structures
69
+ - IFC object references such as `$element` and `$property` are unwrapped to plain objects containing their addressable attributes
70
+
71
+ For IFC object references, unwrapping currently includes object attributes only. It does not recursively expand nested IFC object relations such as property sets or parent/child IFC objects.
72
+
73
+ ## Client Builtins
74
+
75
+ In addition to the built-in IFC roots `$element` and `$property`, clients can register their own reserved builtins.
76
+ These builtins are configured at parse/compile time through `BuiltinVariableRegistry`, and their values are provided at evaluation time through `IfcExpressionContext.resolveBuiltinVariable(name)`.
77
+
78
+ Client builtins support:
79
+
80
+ - reserved names such as `$query`, `$result`, `$thequery`, or any other configured builtin name
81
+ - dotted property access such as `$result.statusCode`
82
+ - dotted function access such as `$query.matches('name')`
83
+ - static typing of members during parse/compile time
84
+ - protection against shadowing by ordinary identifiers
85
+
86
+ Example:
87
+
88
+ ```ts
89
+ import { BuiltinVariableRegistry, IfcExpression, Type } from "ifc-expression";
90
+
91
+ const builtinVariableRegistry = new BuiltinVariableRegistry([
92
+ {
93
+ name: "$query",
94
+ type: Type.CONTEXT_OBJECT_REF,
95
+ members: [
96
+ {
97
+ name: "property",
98
+ kind: "property",
99
+ valueType: Type.STRING,
100
+ },
101
+ {
102
+ name: "matches",
103
+ kind: "function",
104
+ argumentTypes: [Type.STRING],
105
+ returnType: Type.BOOLEAN,
106
+ },
107
+ ],
108
+ },
109
+ {
110
+ name: "$result",
111
+ type: Type.CONTEXT_OBJECT_REF,
112
+ members: [
113
+ {
114
+ name: "statusCode",
115
+ kind: "property",
116
+ valueType: Type.NUMERIC,
117
+ },
118
+ ],
119
+ },
120
+ ]);
121
+
122
+ const parseResult = IfcExpression.parse(
123
+ "$query.matches('name') && $result.statusCode == 200",
124
+ undefined,
125
+ {
126
+ builtinVariableRegistry,
127
+ }
128
+ );
129
+ ```
130
+
131
+ At evaluation time, the context supplies the values for those builtins:
132
+
133
+ ```ts
134
+ import { IfcExpressionContext } from "ifc-expression";
135
+
136
+ const ctx: IfcExpressionContext = {
137
+ resolveElemRef() {
138
+ return elementAccessor;
139
+ },
140
+ resolvePropRef() {
141
+ return propertyAccessor;
142
+ },
143
+ resolveBuiltinVariable(name: string) {
144
+ switch (name) {
145
+ case "query":
146
+ return {
147
+ property: "LoadBearing",
148
+ matches(value: string) {
149
+ return this.property === value;
150
+ },
151
+ };
152
+ case "result":
153
+ return {
154
+ statusCode: 200,
155
+ };
156
+ default:
157
+ return undefined;
158
+ }
159
+ },
160
+ };
161
+ ```
162
+
163
+ `CONTEXT_OBJECT_REF` is intended for client-supplied evaluation-context objects.
164
+ `IFC_OBJECT_REF` and its subtypes remain reserved for actual objects addressable in the IFC model.
165
+
166
+ ## Autocomplete
167
+
168
+ `ifc-expressions` exposes autocomplete through `IfcExpressionAutocomplete.complete(input, cursorOffset, options)`.
169
+ The autocompleter is aware of builtin roots, builtin functions, typed dotted member access, and function argument help.
170
+
171
+ ```ts
172
+ import {
173
+ BuiltinVariableRegistry,
174
+ IfcExpressionAutocomplete,
175
+ Type,
176
+ } from "ifc-expression";
177
+
178
+ const builtinVariableRegistry = new BuiltinVariableRegistry([
179
+ {
180
+ name: "$query",
181
+ type: Type.CONTEXT_OBJECT_REF,
182
+ members: [
183
+ {
184
+ name: "property",
185
+ kind: "property",
186
+ valueType: Type.STRING,
187
+ },
188
+ {
189
+ name: "matches",
190
+ kind: "function",
191
+ argumentTypes: [Type.STRING],
192
+ returnType: Type.BOOLEAN,
193
+ },
194
+ ],
195
+ },
196
+ ]);
197
+
198
+ const completion = IfcExpressionAutocomplete.complete("$query.mat", 10, {
199
+ builtinVariableRegistry,
200
+ });
201
+
202
+ console.log(completion.items);
203
+ ```
204
+
205
+ The returned `CompletionResult` contains:
206
+
207
+ - `items`: completion items for builtin roots, builtin functions, builtin member properties, and builtin member functions
208
+ - `replaceFrom` and `replaceTo`: the text range to replace when applying a completion
209
+ - `activeHelp`: optional signature help for the function or member function currently being typed
210
+
211
+ Each `CompletionItem` can include:
212
+
213
+ - `label`: the completion label
214
+ - `insertText`: text to insert, for example `REPLACE()`
215
+ - `cursorOffset`: where to place the cursor after insertion
216
+ - `argumentTypeNames`: argument types for callable member suggestions
217
+ - `returnTypeName`: return type for typed member suggestions
218
+ - `chainable`: whether the suggested member returns another object that can be accessed with `...`
219
+ - `documentation`: a localized one-line description
220
+
221
+ ### Autocomplete Hooks
222
+
223
+ The autocomplete surface is shaped by two inputs:
224
+
225
+ - `builtinVariableRegistry`: supplies reserved builtin roots and the typed member tree used for dotted access completion
226
+ - `localizer`: translates builtin, member, and function documentation plus active argument help
227
+
228
+ That means the same builtin definitions you use for parsing and evaluation also drive autocomplete. If a client registers `$thequery` or `$theresult`, those exact reserved names, their typed members, and their member functions participate in completion automatically.
229
+
230
+ Example with localization:
231
+
232
+ ```ts
233
+ const completion = IfcExpressionAutocomplete.complete("REP", 3, {
234
+ localizer: {
235
+ t(key, fallback) {
236
+ return translations[key] ?? fallback;
237
+ },
238
+ },
239
+ });
240
+
241
+ console.log(completion.items[0].label);
242
+ // REPLACE
243
+ console.log(completion.items[0].documentation);
244
+ // e.g. "REPLACE(input, pattern, replacement): replace <pattern> in <input> with <replacement>"
245
+ ```
246
+
247
+ When the cursor is inside a function call, `activeHelp` contains the current signature and the active parameter's label and documentation when available. This works for both global builtin functions and typed builtin member functions.
248
+
38
249
  ## Quick Reference
39
250
 
40
251
  Get the current property value:
@@ -43,7 +254,7 @@ Get the current property value:
43
254
 
44
255
  Get the name of the property set the property is in:
45
256
 
46
- `$property.propertySet.name()`
257
+ `$property.propertySet().name()`
47
258
 
48
259
  Get the name of the current element:
49
260
 
@@ -63,23 +274,23 @@ The last expression can also be written as
63
274
 
64
275
  Check if property `myProp` exists in property set `myPset` in the current element:
65
276
 
66
- `$element.propertySet('myPset').property('myProp').exists()`
277
+ `EXISTS($element.propertySet('myPset').property('myProp'))`
67
278
 
68
279
  Hints:
69
280
 
70
281
  - Function/Method names are case-insensitive
71
282
  - you have `+ - * / ^` for numerics
72
- - you have `&& || >< !` for booleans (`><`is xor)
73
- - you have `== != >= <= > <` for strings, booleans and numerics
74
- - you have a `.toString()` method on anything (or, equivalently, a function `toString(x)` for any `x` ).
75
- - you have `REPLACE`, which only knows the wildcard character `*`. (same for `MATCHES, CONTAINS`)
76
- - you have `REGEXREPLACE` with full js Regular Expressions (same for `REGEXMATCHES, REGEXCONTAINS`)
283
+ - you have `&& || >< !` for booleans (`><` is xor)
284
+ - you have `== != >= <= > <` for strings, booleans and numerics
285
+ - you have a `.toString()` method on anything (or, equivalently, a function `toString(x)` for any `x`).
286
+ - you have `REPLACE`, which only knows the wildcard character `*`. (same for `MATCHES`, `CONTAINS`)
287
+ - you have `REGEXREPLACE` with full js Regular Expressions (same for `REGEXMATCHES`, `REGEXCONTAINS`)
77
288
 
78
289
  ## IFC Expression Language Syntax
79
290
 
80
- The project uses ANTLR4 for parsing. The grammar is in src/grammar/ifcExpression.g4.
291
+ The project uses ANTLR4 for parsing. The grammar is in `src/grammar/IfcExpression.g4`.
81
292
 
82
- The result of expression evaluation is a value of type `string, numeric, boolean, ifcObjectRef`, where `ifcObjectRef` is a reference to some object in the IFC model, or a temporal type (`IfcDateTime`, `IfcDate`, `IfcTime`, `IfcDuration`, and `IfcTimeStamp`)
293
+ The result of expression evaluation is a value of type `string`, `numeric`, `boolean`, `ifcObjectRef`, `contextObjectRef`, or a temporal type (`IfcDateTime`, `IfcDate`, `IfcTime`, `IfcDuration`, and `IfcTimeStamp`). `ifcObjectRef` is a reference to some object in the IFC model. `contextObjectRef` is a client-supplied builtin object from the evaluation context.
83
294
 
84
295
  The language allows for specifying _a single expression_. There are no control statements and there is no way
85
296
  to define custom functions or custom types.
@@ -87,7 +298,7 @@ to define custom functions or custom types.
87
298
  An expression can be
88
299
 
89
300
  - a literal, such as `'hello world'`, or `17`
90
- - a variable reference, such as `$property` or `$element`,(for accessing the IFC model).
301
+ - a variable reference, such as `$property`, `$element`, or a configured client builtin such as `$query`
91
302
 
92
303
  ... or a combination of multiple expressions:
93
304
 
@@ -100,18 +311,19 @@ An expression can be
100
311
  - `string`, e.g. `'abc'` or `"abc"`: text enclosed in single or double quotes
101
312
  - `boolean`, e.g. `TRUE` or `false`: true or false, either spelled all-uppercase or all-lowercase
102
313
  - `numeric`, e.g. `1` or `3.141`: a decimal number optionally containing one period to separate integer part from fractional part
103
- - `array`, e.g. `[1,2,"hi there"]: an ordered list of expressions
314
+ - `array`, e.g. `[1,2,"hi there"]`: an ordered list of expressions
315
+ - `contextObjectRef`: a typed client builtin object configured in `BuiltinVariableRegistry`
104
316
 
105
317
  ### Operators
106
318
 
107
319
  - numeric operators
108
- - '+', '-', '\*', '/': plus, minus, multiplication, division - with the ususal precedence rules and associativity
109
- - '^': raise to the power or, e.g. `2^3` (= 8)
320
+ - `+`, `-`, `*`, `/`: plus, minus, multiplication, division - with the usual precedence rules and associativity
321
+ - `^`: raise to the power, e.g. `2^3` (= 8)
110
322
  - boolean operators
111
- - `&&', `||`, `><`: boolean and, or, xor
323
+ - `&&`, `||`, `><`: boolean and, or, xor
112
324
  - `!`: boolean not
113
325
  - string operators
114
- - '+': string concatenation
326
+ - `+`: string concatenation
115
327
 
116
328
  ### Functions
117
329
 
@@ -125,7 +337,7 @@ An expression can be
125
337
 
126
338
  #### comparison functions
127
339
 
128
- `equals(a,b)`, `greaterThan(a,b)`, `greaterThanOrEquals(a,b)`, `lessThan(a,b)`, `lessThanOrEqual(a,b)`",
340
+ `equals(a,b)`, `greaterThan(a,b)`, `greaterThanOrEqual(a,b)`, `lessThan(a,b)`, `lessThanOrEqual(a,b)`
129
341
 
130
342
  #### boolean operator functions
131
343
 
@@ -135,11 +347,11 @@ An expression can be
135
347
 
136
348
  `contains(string, pattern)`, e.g. `contains('hello world', 'he*o')` returns true if the string contains the pattern. `*` matches any number of characters.
137
349
 
138
- `regexContains(string, regex)`, e.g. `regexContains('hello, world', 'h[aeiou]ll[aeiou]+\\\s')` returns true if the string contains the regular expression.
350
+ `regexContains(string, regex)`, e.g. `regexContains('hello, world', 'h[aeiou]ll[aeiou]+\\s')` returns true if the string contains the regular expression.
139
351
 
140
352
  `matches(string, pattern)`, e.g. `matches('hello world', 'he*o')` returns true if the whole string matches the pattern. `*` matches any number of characters.
141
353
 
142
- `regexMatches(string, regex)`, e.g. `regexMatches('hello, world', 'h[aeiou]ll[aeiou]+\\\s')` returns true if the whole string matches the regular expression.
354
+ `regexMatches(string, regex)`, e.g. `regexMatches('hello, world', 'h[aeiou]ll[aeiou]+\\s')` returns true if the whole string matches the regular expression.
143
355
 
144
356
  #### string replacement
145
357
 
@@ -149,20 +361,20 @@ An expression can be
149
361
 
150
362
  #### ifc object accessor functions
151
363
 
152
- `property(object: ifcPropertySetRef|ifcTypeObjectRef|ifcElementRef, name: string)`: returns an `ifcPropertyRef` or an error or an error if object has no property with that name
364
+ `property(object: ifcPropertySetRef|ifcTypeObjectRef|ifcElementRef, name: string)`: returns an `ifcPropertyRef` or an error if object has no property with that name
153
365
 
154
366
  `propertySet(object: ifcProperty)`: returns an `ifcPropertySetRef`
155
367
 
156
- `propertySet(object: ifcTypeObjectRef|ifcElementRef, name: string)`: returns an `ifcPropertySetRef` or an error if the element or type has no property set with that name.
368
+ `propertySet(object: ifcTypeObjectRef|ifcElementRef, name: string)`: returns an `ifcPropertySetRef` or an error if the element or type has no property set with that name
157
369
 
158
- `type(object: ifcElementRef)`: returns an `ifcTypeObjectRef` or an error.
370
+ `type(object: ifcElementRef)`: returns an `ifcTypeObjectRef` or an error
159
371
 
160
- `exists(object: ifcObjectRef): boolean` check whether an object reference obtained by the above methods actually exists (suppresses the error they generate)
372
+ `exists(object: ifcObjectRef): boolean`: checks whether an object reference obtained by the above methods actually exists (suppresses the error they generate)
161
373
 
162
- #### Translation and condition functions
374
+ #### translation and condition functions
163
375
 
164
- `map(input, mapping: [[in, out], [in, out], ... ], default)`: finds the first `[in,out]` pair in the specified mapping where `in == input` and returns that pair's `out` value. If none is found, `default` is returned.
376
+ `map(input, mapping: [[in, out], [in, out], ...], default)`: finds the first `[in, out]` pair in the specified mapping where `in == input` and returns that pair's `out` value. If none is found, `default` is returned.
165
377
 
166
378
  `if(condition, thenValue, elseValue)`: returns `thenValue` if `condition` is `true`, `elseValue` otherwise.
167
379
 
168
- `choose([[condition, out], [condition, out], ... ], default)`: finds the first `[condition, out]` pair where `condition == true` and returns its `out` value. In none is found, `default` is returned.
380
+ `choose([[condition, out], [condition, out], ...], default)`: finds the first `[condition, out]` pair where `condition == true` and returns its `out` value. If none is found, `default` is returned.
@@ -1,4 +1,5 @@
1
- import { ErrorListener, ParserRuleContext, Token } from "antlr4";
1
+ import { ANTLRErrorListener, ParserRuleContext } from "antlr4ng";
2
+ import Decimal from "decimal.js";
2
3
  import { ExprCompiler } from "./compiler/ExprCompiler.js";
3
4
  import { IfcExpressionErrorListener } from "./IfcExpressionErrorListener.js";
4
5
  import { isNullish, isPresent } from "./util/IfcExpressionUtils.js";
@@ -16,7 +17,7 @@ import { IfcPropertyAccessor } from "./context/IfcPropertyAccessor.js";
16
17
  import { IfcRootObjectAccessor } from "./context/IfcRootObjectAccessor.js";
17
18
  import { IfcTypeObjectAccessor } from "./context/IfcTypeObjectAccessor.js";
18
19
  import { NamedObjectAccessor } from "./context/NamedObjectAccessor.js";
19
- import IfcExpressionVisitor from "./gen/parser/IfcExpressionVisitor.js";
20
+ import { IfcExpressionVisitor } from "./gen/parser/IfcExpressionVisitor.js";
20
21
  import { ObjectAccessor } from "./context/ObjectAccessor.js";
21
22
  import { IfcExpressionEvaluationException } from "./expression/IfcExpressionEvaluationException.js";
22
23
  import type { ExpressionValue } from "./value/ExpressionValue.js";
@@ -37,41 +38,38 @@ import { SimpleType } from "./type/SimpleType.js";
37
38
  import { TupleType } from "./type/TupleType.js";
38
39
  import { TypeDisjunction } from "./type/TypeDisjunction.js";
39
40
  import { Types } from "./type/Types.js";
40
- export { IfcElementAccessor, IfcExpressionContext, Value, StringValue, BooleanValue, LogicalValue, NumericValue, ExpressionValue, ReferenceValue, IfcDateValue, IfcDateTimeValue, IfcTimeValue, IfcDurationValue, IfcTimeStampValue, IfcPropertySetAccessor, IfcPropertyAccessor, IfcRootObjectAccessor, IfcTypeObjectAccessor, NamedObjectAccessor, ObjectAccessor, Expr, ExprCompiler, ExprKind, IfcExpressionEvaluationException, IfcExpressionErrorListener, IfcExpressionVisitor, isPresent, isNullish, ExprEvalResult, ExprEvalError, isExprEvalError, isExprEvalSuccess, ExprToTextInputLinker, ExprFacade, ArrayType, ExprType, SimpleType, TupleType, TypeDisjunction, Types, };
41
- export type { BoxedValueTypes };
41
+ import { ContextObjectType } from "./type/ContextObjectType.js";
42
+ import { BuiltinVariableRegistry } from "./builtin/BuiltinVariableRegistry.js";
43
+ import { IfcExpressionOptions } from "./IfcExpressionOptions.js";
44
+ import { IfcExpressionAutocomplete } from "./autocomplete/IfcExpressionAutocomplete.js";
45
+ import type { CompletionItem, CompletionResult } from "./autocomplete/CompletionItem.js";
46
+ import type { IfcExpressionAutocompleteOptions } from "./autocomplete/IfcExpressionAutocomplete.js";
47
+ export { IfcElementAccessor, IfcExpressionContext, Value, StringValue, BooleanValue, LogicalValue, NumericValue, ExpressionValue, ReferenceValue, IfcDateValue, IfcDateTimeValue, IfcTimeValue, IfcDurationValue, IfcTimeStampValue, IfcPropertySetAccessor, IfcPropertyAccessor, IfcRootObjectAccessor, IfcTypeObjectAccessor, NamedObjectAccessor, ObjectAccessor, Expr, ExprCompiler, ExprKind, IfcExpressionEvaluationException, IfcExpressionErrorListener, IfcExpressionVisitor, isPresent, isNullish, ExprEvalResult, ExprEvalError, isExprEvalError, isExprEvalSuccess, ExprToTextInputLinker, ExprFacade, ArrayType, ExprType, SimpleType, TupleType, TypeDisjunction, Types, ContextObjectType, BuiltinVariableRegistry, IfcExpressionAutocomplete, };
48
+ export type { BoxedValueTypes, IfcExpressionOptions, CompletionItem, CompletionResult, IfcExpressionAutocompleteOptions, };
49
+ export type UnwrappedExpressionValue = string | boolean | Decimal | undefined | UnwrappedExpressionValue[] | {
50
+ [key: string]: UnwrappedExpressionValue;
51
+ };
42
52
  export declare class IfcExpressionParseResult {
43
53
  private readonly _input;
44
54
  private readonly _typeManager;
45
55
  private readonly _parseTree;
46
- constructor(input: string, typeManager: TypeManager, exprContext: any);
56
+ private readonly _builtinVariableRegistry;
57
+ constructor(input: string, typeManager: TypeManager, exprContext: any, builtinVariableRegistry: BuiltinVariableRegistry);
47
58
  get typeManager(): TypeManager;
48
59
  get parseTree(): ParserRuleContext;
49
60
  get input(): string;
61
+ get builtinVariableRegistry(): BuiltinVariableRegistry;
50
62
  }
51
63
  export declare class IfcExpression {
52
- /**
53
- * Parses the input and returns a parse result, which contains the parse tree, the type information per parse tree node, and the input.
54
- * @param input
55
- * @param errorListener
56
- * @return the parse result, which can subequently be compiled into an Expr using compile().
57
- */
58
- static parse(input: string, errorListener?: ErrorListener<Token | number>): IfcExpressionParseResult;
59
- /**
60
- * Compiles the specified parseResult into an Expr.
61
- * @param parseResult
62
- * @return the Expression (Expr), which can be evaluated to obtain its result.
63
- */
64
+ static parse(input: string, errorListener?: ANTLRErrorListener, options?: IfcExpressionOptions): IfcExpressionParseResult;
64
65
  static compile(parseResult: IfcExpressionParseResult): ExprFacade<ExpressionValue>;
65
- /**
66
- * Evaluates the specified input expression and returns the evaluation result. The parse
67
- * and compile steps are done internally.
68
- *
69
- * @param expression: the input expression
70
- * @param context: the context required for accessing the IFC model
71
- * @return the result (or an error object).
72
- */
73
- static evaluate(expression: string, context?: IfcExpressionContext): ExprEvalResult<ExpressionValue>;
66
+ static evaluate(expression: string, context?: IfcExpressionContext, options?: IfcExpressionOptions): ExprEvalResult<ExpressionValue>;
74
67
  static formatError(input: string, error: ExprEvalError): string;
75
68
  private static indent;
76
69
  static evaluateExpression(expr: ExprFacade<ExpressionValue>, context?: IfcExpressionContext): ExprEvalResult<ExpressionValue>;
70
+ static unwrapValue(value: ExpressionValue): UnwrappedExpressionValue;
71
+ private static unwrapUnknownValue;
72
+ private static unwrapObjectAccessor;
73
+ private static unwrapPlainObject;
74
+ private static isPlainObject;
77
75
  }
@@ -1,10 +1,10 @@
1
- import { ErrorListener, RecognitionException, Recognizer, Token } from "antlr4";
1
+ import { BaseErrorListener, RecognitionException, Recognizer, Token } from "antlr4ng";
2
2
  import { SyntaxErrorException } from "./error/SyntaxErrorException.js";
3
3
  import { ValidationException } from "./error/ValidationException.js";
4
- export declare class IfcExpressionErrorListener extends ErrorListener<Token | number> {
4
+ export declare class IfcExpressionErrorListener extends BaseErrorListener {
5
5
  private exception;
6
6
  validationException(validationException: ValidationException): void;
7
- syntaxError(recognizer: Recognizer<Token | number>, offendingSymbol: Token | number, line: number, column: number, msg: string, e: RecognitionException | undefined): void;
7
+ syntaxError<S extends Token, T extends import("antlr4ng").ATNSimulator>(recognizer: Recognizer<T>, offendingSymbol: S | null, line: number, column: number, msg: string, e: RecognitionException | null): void;
8
8
  isErrorOccurred(): boolean;
9
9
  getException(): SyntaxErrorException | ValidationException;
10
10
  }
@@ -0,0 +1,4 @@
1
+ import { BuiltinVariableRegistry } from "./builtin/BuiltinVariableRegistry.js";
2
+ export interface IfcExpressionOptions {
3
+ builtinVariableRegistry?: BuiltinVariableRegistry;
4
+ }
@@ -0,0 +1,24 @@
1
+ export type CompletionItemKind = "builtinRoot" | "builtinFunction" | "builtinMemberProperty" | "builtinMemberFunction";
2
+ export type CompletionItem = {
3
+ kind: CompletionItemKind;
4
+ label: string;
5
+ insertText?: string;
6
+ cursorOffset?: number;
7
+ argumentTypeNames?: Array<string>;
8
+ returnTypeName?: string;
9
+ chainable?: boolean;
10
+ documentation?: string;
11
+ };
12
+ export type ActiveHelp = {
13
+ label: string;
14
+ documentation: string;
15
+ activeParameterIndex?: number;
16
+ activeParameterLabel?: string;
17
+ activeParameterDocumentation?: string;
18
+ };
19
+ export type CompletionResult = {
20
+ items: Array<CompletionItem>;
21
+ replaceFrom: number;
22
+ replaceTo: number;
23
+ activeHelp?: ActiveHelp;
24
+ };
@@ -0,0 +1,10 @@
1
+ import { BuiltinVariableRegistry } from "../builtin/BuiltinVariableRegistry.js";
2
+ import { CompletionResult } from "./CompletionItem.js";
3
+ import { DocumentationLocalizer } from "../documentation/Documentation.js";
4
+ export type IfcExpressionAutocompleteOptions = {
5
+ builtinVariableRegistry?: BuiltinVariableRegistry;
6
+ localizer?: DocumentationLocalizer;
7
+ };
8
+ export declare class IfcExpressionAutocomplete {
9
+ static complete(input: string, cursorOffset: number, options?: IfcExpressionAutocompleteOptions): CompletionResult;
10
+ }
@@ -0,0 +1,7 @@
1
+ import { ExprType } from "../type/ExprType.js";
2
+ import { ExpressionValue } from "../value/ExpressionValue.js";
3
+ import { ContextObjectValue } from "../value/ContextObjectValue.js";
4
+ export declare function toExpressionValue(value: unknown, expectedType: ExprType): ExpressionValue;
5
+ export declare function inferExpressionValue(value: unknown, fallbackType?: ExprType): ExpressionValue;
6
+ export declare function unwrapExpressionValue(value: ExpressionValue): unknown;
7
+ export declare function getBuiltinMemberValue(value: ContextObjectValue, memberName: string): unknown;
@@ -0,0 +1,50 @@
1
+ import { ExprType } from "../type/ExprType.js";
2
+ import { Expr } from "../expression/Expr.js";
3
+ import { ArgumentDocumentation, LocalizedText } from "../documentation/Documentation.js";
4
+ export type BuiltinPropertyDefinition = {
5
+ name: string;
6
+ kind: "property";
7
+ valueType: ExprType;
8
+ documentation?: LocalizedText;
9
+ };
10
+ export type BuiltinFunctionDefinition = {
11
+ name: string;
12
+ kind: "function";
13
+ returnType: ExprType;
14
+ argumentTypes: Array<ExprType>;
15
+ documentation?: LocalizedText;
16
+ argumentDocumentation?: Array<ArgumentDocumentation>;
17
+ };
18
+ export type BuiltinMemberDefinition = BuiltinPropertyDefinition | BuiltinFunctionDefinition;
19
+ export declare function isBuiltinPropertyDefinition(definition: BuiltinMemberDefinition | undefined): definition is BuiltinPropertyDefinition;
20
+ export declare function isBuiltinFunctionDefinition(definition: BuiltinMemberDefinition | undefined): definition is BuiltinFunctionDefinition;
21
+ export type BuiltinVariableDefinition = {
22
+ name: string;
23
+ type?: ExprType;
24
+ documentation?: LocalizedText;
25
+ members?: Array<BuiltinMemberDefinition>;
26
+ createReferenceExpr?: () => Expr<any>;
27
+ };
28
+ export type RegisteredBuiltinVariableDefinition = {
29
+ name: string;
30
+ type: ExprType;
31
+ documentation?: LocalizedText;
32
+ members: Map<string, BuiltinMemberDefinition>;
33
+ createReferenceExpr: () => Expr<any>;
34
+ };
35
+ export declare class BuiltinVariableRegistry {
36
+ private static readonly defaultRegistry;
37
+ private readonly builtinVariables;
38
+ constructor(definitions?: Array<BuiltinVariableDefinition>);
39
+ static getDefaultRegistry(): BuiltinVariableRegistry;
40
+ static normalizeName(name: string): string;
41
+ static isBuiltinVariable(name: string): boolean;
42
+ static isReservedName(name: string): boolean;
43
+ static getDefinition(name: string): RegisteredBuiltinVariableDefinition | undefined;
44
+ isBuiltinVariable(name: string): boolean;
45
+ isReservedName(name: string): boolean;
46
+ getDefinition(name: string): RegisteredBuiltinVariableDefinition | undefined;
47
+ getDefinitions(): Array<RegisteredBuiltinVariableDefinition>;
48
+ private register;
49
+ private registerMembers;
50
+ }