ifc-expressions 2.3.0 → 3.0.0-beta.2

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 +255 -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 +11 -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 +654 -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 +650 -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,235 @@ 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
+ For empty or whitespace-only expressions, you can also provide a curated starter list with `emptyExpressionStarters`. Use the same names users would type in expressions: builtin roots such as `"$result"` and builtin functions such as `"REPLACE"`.
231
+ Unknown starter names are ignored, and if you omit this option the built-in default starter list is used.
232
+
233
+ ```ts
234
+ const emptyStateCompletion = IfcExpressionAutocomplete.complete("", 0, {
235
+ builtinVariableRegistry,
236
+ emptyExpressionStarters: ["$result", "REPLACE", "$query", "TOBOOLEAN"],
237
+ });
238
+
239
+ console.log(emptyStateCompletion.items.map((item) => item.label));
240
+ // ["$result", "REPLACE", "$query", "TOBOOLEAN"]
241
+ ```
242
+
243
+ Example with localization:
244
+
245
+ ```ts
246
+ const completion = IfcExpressionAutocomplete.complete("REP", 3, {
247
+ localizer: {
248
+ t(key, fallback) {
249
+ return translations[key] ?? fallback;
250
+ },
251
+ },
252
+ });
253
+
254
+ console.log(completion.items[0].label);
255
+ // REPLACE
256
+ console.log(completion.items[0].documentation);
257
+ // e.g. "REPLACE(input, pattern, replacement): replace <pattern> in <input> with <replacement>"
258
+ ```
259
+
260
+ 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.
261
+
38
262
  ## Quick Reference
39
263
 
40
264
  Get the current property value:
@@ -43,7 +267,7 @@ Get the current property value:
43
267
 
44
268
  Get the name of the property set the property is in:
45
269
 
46
- `$property.propertySet.name()`
270
+ `$property.propertySet().name()`
47
271
 
48
272
  Get the name of the current element:
49
273
 
@@ -63,23 +287,23 @@ The last expression can also be written as
63
287
 
64
288
  Check if property `myProp` exists in property set `myPset` in the current element:
65
289
 
66
- `$element.propertySet('myPset').property('myProp').exists()`
290
+ `EXISTS($element.propertySet('myPset').property('myProp'))`
67
291
 
68
292
  Hints:
69
293
 
70
294
  - Function/Method names are case-insensitive
71
295
  - 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`)
296
+ - you have `&& || >< !` for booleans (`><` is xor)
297
+ - you have `== != >= <= > <` for strings, booleans and numerics
298
+ - you have a `.toString()` method on anything (or, equivalently, a function `toString(x)` for any `x`).
299
+ - you have `REPLACE`, which only knows the wildcard character `*`. (same for `MATCHES`, `CONTAINS`)
300
+ - you have `REGEXREPLACE` with full js Regular Expressions (same for `REGEXMATCHES`, `REGEXCONTAINS`)
77
301
 
78
302
  ## IFC Expression Language Syntax
79
303
 
80
- The project uses ANTLR4 for parsing. The grammar is in src/grammar/ifcExpression.g4.
304
+ The project uses ANTLR4 for parsing. The grammar is in `src/grammar/IfcExpression.g4`.
81
305
 
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`)
306
+ 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
307
 
84
308
  The language allows for specifying _a single expression_. There are no control statements and there is no way
85
309
  to define custom functions or custom types.
@@ -87,7 +311,7 @@ to define custom functions or custom types.
87
311
  An expression can be
88
312
 
89
313
  - a literal, such as `'hello world'`, or `17`
90
- - a variable reference, such as `$property` or `$element`,(for accessing the IFC model).
314
+ - a variable reference, such as `$property`, `$element`, or a configured client builtin such as `$query`
91
315
 
92
316
  ... or a combination of multiple expressions:
93
317
 
@@ -100,18 +324,19 @@ An expression can be
100
324
  - `string`, e.g. `'abc'` or `"abc"`: text enclosed in single or double quotes
101
325
  - `boolean`, e.g. `TRUE` or `false`: true or false, either spelled all-uppercase or all-lowercase
102
326
  - `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
327
+ - `array`, e.g. `[1,2,"hi there"]`: an ordered list of expressions
328
+ - `contextObjectRef`: a typed client builtin object configured in `BuiltinVariableRegistry`
104
329
 
105
330
  ### Operators
106
331
 
107
332
  - 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)
333
+ - `+`, `-`, `*`, `/`: plus, minus, multiplication, division - with the usual precedence rules and associativity
334
+ - `^`: raise to the power, e.g. `2^3` (= 8)
110
335
  - boolean operators
111
- - `&&', `||`, `><`: boolean and, or, xor
336
+ - `&&`, `||`, `><`: boolean and, or, xor
112
337
  - `!`: boolean not
113
338
  - string operators
114
- - '+': string concatenation
339
+ - `+`: string concatenation
115
340
 
116
341
  ### Functions
117
342
 
@@ -125,7 +350,7 @@ An expression can be
125
350
 
126
351
  #### comparison functions
127
352
 
128
- `equals(a,b)`, `greaterThan(a,b)`, `greaterThanOrEquals(a,b)`, `lessThan(a,b)`, `lessThanOrEqual(a,b)`",
353
+ `equals(a,b)`, `greaterThan(a,b)`, `greaterThanOrEqual(a,b)`, `lessThan(a,b)`, `lessThanOrEqual(a,b)`
129
354
 
130
355
  #### boolean operator functions
131
356
 
@@ -135,11 +360,11 @@ An expression can be
135
360
 
136
361
  `contains(string, pattern)`, e.g. `contains('hello world', 'he*o')` returns true if the string contains the pattern. `*` matches any number of characters.
137
362
 
138
- `regexContains(string, regex)`, e.g. `regexContains('hello, world', 'h[aeiou]ll[aeiou]+\\\s')` returns true if the string contains the regular expression.
363
+ `regexContains(string, regex)`, e.g. `regexContains('hello, world', 'h[aeiou]ll[aeiou]+\\s')` returns true if the string contains the regular expression.
139
364
 
140
365
  `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
366
 
142
- `regexMatches(string, regex)`, e.g. `regexMatches('hello, world', 'h[aeiou]ll[aeiou]+\\\s')` returns true if the whole string matches the regular expression.
367
+ `regexMatches(string, regex)`, e.g. `regexMatches('hello, world', 'h[aeiou]ll[aeiou]+\\s')` returns true if the whole string matches the regular expression.
143
368
 
144
369
  #### string replacement
145
370
 
@@ -149,20 +374,20 @@ An expression can be
149
374
 
150
375
  #### ifc object accessor functions
151
376
 
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
377
+ `property(object: ifcPropertySetRef|ifcTypeObjectRef|ifcElementRef, name: string)`: returns an `ifcPropertyRef` or an error if object has no property with that name
153
378
 
154
379
  `propertySet(object: ifcProperty)`: returns an `ifcPropertySetRef`
155
380
 
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.
381
+ `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
382
 
158
- `type(object: ifcElementRef)`: returns an `ifcTypeObjectRef` or an error.
383
+ `type(object: ifcElementRef)`: returns an `ifcTypeObjectRef` or an error
159
384
 
160
- `exists(object: ifcObjectRef): boolean` check whether an object reference obtained by the above methods actually exists (suppresses the error they generate)
385
+ `exists(object: ifcObjectRef): boolean`: checks whether an object reference obtained by the above methods actually exists (suppresses the error they generate)
161
386
 
162
- #### Translation and condition functions
387
+ #### translation and condition functions
163
388
 
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.
389
+ `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
390
 
166
391
  `if(condition, thenValue, elseValue)`: returns `thenValue` if `condition` is `true`, `elseValue` otherwise.
167
392
 
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.
393
+ `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,11 @@
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
+ emptyExpressionStarters?: Array<string>;
8
+ };
9
+ export declare class IfcExpressionAutocomplete {
10
+ static complete(input: string, cursorOffset: number, options?: IfcExpressionAutocompleteOptions): CompletionResult;
11
+ }
@@ -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
+ }