sct_ecl/ast.rs
1// SPDX-FileCopyrightText: Cadasto B.V.
2// SPDX-License-Identifier: BUSL-1.1
3
4//! The syntax tree of an expression constraint, one type per grammar rule
5//! that carries meaning (`ECL.g4`; the rules that only spell a keyword or a
6//! character class are folded into their parents).
7
8/// A SNOMED CT identifier as written in an expression (`sctid`: 6 to 18
9/// digits, the first not zero).
10#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
11pub struct Sctid(pub u64);
12
13/// `eclconceptreference`: an identifier with its optional term.
14#[derive(Debug, Clone, PartialEq, Eq, Hash)]
15pub struct ConceptReference {
16 /// The identifier.
17 pub id: Sctid,
18 /// The term between pipes, trimmed.
19 pub term: Option<String>,
20}
21
22/// `altidentifier`: a code from another scheme (`LOINC#54486-6`).
23#[derive(Debug, Clone, PartialEq, Eq, Hash)]
24pub struct AltIdentifier {
25 /// The scheme alias before the `#`.
26 pub scheme: String,
27 /// The code after the `#`.
28 pub code: String,
29 /// The term between pipes, trimmed.
30 pub term: Option<String>,
31}
32
33/// `eclfocusconcept`, or a parenthesized nested constraint.
34#[derive(Debug, Clone, PartialEq, Eq, Hash)]
35pub enum FocusConcept {
36 /// A concept reference.
37 Reference(ConceptReference),
38 /// `*`, any concept.
39 Wildcard,
40 /// An alternate identifier.
41 AltIdentifier(AltIdentifier),
42 /// `( expressionconstraint )`.
43 Nested(Box<ExpressionConstraint>),
44}
45
46/// `constraintoperator`.
47#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
48pub enum ConstraintOperator {
49 /// `<`
50 DescendantOf,
51 /// `<<`
52 DescendantOrSelfOf,
53 /// `<!`
54 ChildOf,
55 /// `<<!`
56 ChildOrSelfOf,
57 /// `>`
58 AncestorOf,
59 /// `>>`
60 AncestorOrSelfOf,
61 /// `>!`
62 ParentOf,
63 /// `>>!`
64 ParentOrSelfOf,
65 /// `!!>`
66 Top,
67 /// `!!<`
68 Bottom,
69}
70
71/// The reference set fields a `memberof` names (`^ [field, field]`).
72#[derive(Debug, Clone, PartialEq, Eq, Hash)]
73pub enum RefsetFields {
74 /// `[*]`.
75 Any,
76 /// `[name, name]`.
77 Names(Vec<String>),
78}
79
80/// `memberof`: `^`, with its optional field selection.
81#[derive(Debug, Clone, PartialEq, Eq, Hash)]
82pub struct MemberOf {
83 /// The fields between brackets, when given.
84 pub fields: Option<RefsetFields>,
85}
86
87/// `subexpressionconstraint`.
88#[derive(Debug, Clone, PartialEq, Eq, Hash)]
89pub struct SubExpressionConstraint {
90 /// The constraint operator before the focus.
91 pub operator: Option<ConstraintOperator>,
92 /// The `^` before the focus.
93 pub member_of: Option<MemberOf>,
94 /// The focus concept or nested constraint.
95 pub focus: FocusConcept,
96 /// `memberfilterconstraint`s, one list per `{{ M ... }}`.
97 pub member_filters: Vec<Vec<MemberFilter>>,
98 /// The description and concept filter constraints, in order.
99 pub filters: Vec<FilterConstraint>,
100 /// `historysupplement`.
101 pub history: Option<HistorySupplement>,
102}
103
104/// `descriptionfilterconstraint` or `conceptfilterconstraint`.
105#[derive(Debug, Clone, PartialEq, Eq, Hash)]
106pub enum FilterConstraint {
107 /// `{{ D ... }}`.
108 Description(Vec<DescriptionFilter>),
109 /// `{{ C ... }}`.
110 Concept(Vec<ConceptFilter>),
111}
112
113/// `expressionconstraint`.
114#[derive(Debug, Clone, PartialEq, Eq, Hash)]
115pub enum ExpressionConstraint {
116 /// `refinedexpressionconstraint`: a focus with `:` and a refinement.
117 Refined {
118 /// The constraint refined.
119 focus: SubExpressionConstraint,
120 /// The refinement.
121 refinement: Box<Refinement>,
122 },
123 /// `conjunctionexpressionconstraint`, two or more operands.
124 Conjunction(Vec<SubExpressionConstraint>),
125 /// `disjunctionexpressionconstraint`, two or more operands.
126 Disjunction(Vec<SubExpressionConstraint>),
127 /// `exclusionexpressionconstraint`.
128 Exclusion {
129 /// The set kept.
130 left: SubExpressionConstraint,
131 /// The set removed.
132 right: SubExpressionConstraint,
133 },
134 /// `dottedexpressionconstraint`: a focus followed by `. attribute` steps.
135 Dotted {
136 /// The constraint the walk starts from.
137 focus: SubExpressionConstraint,
138 /// The attribute names walked, in order.
139 attributes: Vec<SubExpressionConstraint>,
140 },
141 /// A bare `subexpressionconstraint`.
142 Sub(SubExpressionConstraint),
143}
144
145/// `eclrefinement`.
146#[derive(Debug, Clone, PartialEq, Eq, Hash)]
147pub enum Refinement {
148 /// One sub-refinement.
149 Single(Box<SubRefinement>),
150 /// Sub-refinements joined by `AND` or `,`, two or more.
151 Conjunction(Vec<SubRefinement>),
152 /// Sub-refinements joined by `OR`, two or more.
153 Disjunction(Vec<SubRefinement>),
154}
155
156/// `subrefinement`.
157#[derive(Debug, Clone, PartialEq, Eq, Hash)]
158pub enum SubRefinement {
159 /// An attribute set.
160 AttributeSet(AttributeSet),
161 /// `eclattributegroup`: `[c] { attributes }`.
162 Group {
163 /// The group cardinality.
164 cardinality: Option<Cardinality>,
165 /// The attributes in the group.
166 attributes: AttributeSet,
167 },
168 /// `( eclrefinement )`.
169 Nested(Box<Refinement>),
170}
171
172/// `eclattributeset`.
173#[derive(Debug, Clone, PartialEq, Eq, Hash)]
174pub enum AttributeSet {
175 /// One sub-attribute set.
176 Single(Box<SubAttributeSet>),
177 /// Joined by `AND` or `,`, two or more.
178 Conjunction(Vec<SubAttributeSet>),
179 /// Joined by `OR`, two or more.
180 Disjunction(Vec<SubAttributeSet>),
181}
182
183/// `subattributeset`.
184#[derive(Debug, Clone, PartialEq, Eq, Hash)]
185pub enum SubAttributeSet {
186 /// An attribute.
187 Attribute(Box<Attribute>),
188 /// `( eclattributeset )`.
189 Nested(Box<AttributeSet>),
190}
191
192/// `eclattribute`.
193#[derive(Debug, Clone, PartialEq, Eq, Hash)]
194pub struct Attribute {
195 /// `[min..max]` before the name.
196 pub cardinality: Option<Cardinality>,
197 /// The reverse flag `R`.
198 pub reverse: bool,
199 /// `eclattributename`, a sub-expression constraint.
200 pub name: SubExpressionConstraint,
201 /// The comparison and value.
202 pub value: AttributeValue,
203}
204
205/// The comparison and value of an attribute or a member field.
206#[derive(Debug, Clone, PartialEq, Eq, Hash)]
207pub enum AttributeValue {
208 /// `= sub` or `!= sub`.
209 Expression {
210 /// The operator.
211 operator: Equality,
212 /// The value constraint.
213 value: SubExpressionConstraint,
214 },
215 /// `op #number`.
216 Numeric {
217 /// The operator.
218 operator: Comparison,
219 /// The number.
220 value: NumericValue,
221 },
222 /// `= "string"`, `= wild:"..."`, or a set of them.
223 String {
224 /// The operator.
225 operator: Equality,
226 /// The search terms; one prints bare, more print as a set.
227 terms: Vec<TypedSearchTerm>,
228 },
229 /// `= true` or `= false`.
230 Boolean {
231 /// The operator.
232 operator: Equality,
233 /// The value.
234 value: bool,
235 },
236}
237
238/// `cardinality`: `min..max`, `max` absent for `*`.
239#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
240pub struct Cardinality {
241 /// The minimum.
242 pub min: u32,
243 /// The maximum, `None` for `*`.
244 pub max: Option<u32>,
245}
246
247/// `expressioncomparisonoperator`, `stringcomparisonoperator`,
248/// `booleancomparisonoperator`, and `idcomparisonoperator`.
249#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
250pub enum Equality {
251 /// `=`
252 Equal,
253 /// `!=`
254 NotEqual,
255}
256
257/// `numericcomparisonoperator` and `timecomparisonoperator`.
258#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
259pub enum Comparison {
260 /// `=`
261 Equal,
262 /// `!=`
263 NotEqual,
264 /// `<`
265 Less,
266 /// `<=`
267 LessOrEqual,
268 /// `>`
269 Greater,
270 /// `>=`
271 GreaterOrEqual,
272}
273
274/// `numericvalue`: the literal after `#`, as written (an optional sign,
275/// digits, an optional fraction).
276#[derive(Debug, Clone, PartialEq, Eq, Hash)]
277pub struct NumericValue(pub String);
278
279/// `typedsearchterm`.
280#[derive(Debug, Clone, PartialEq, Eq, Hash)]
281pub enum TypedSearchTerm {
282 /// `"word word"` or `match:"..."`: every word must match as a prefix.
283 Match(Vec<String>),
284 /// `wild:"..."`: a pattern with `*` wildcards.
285 Wild(String),
286}
287
288/// `descriptionfilter`.
289#[derive(Debug, Clone, PartialEq, Eq, Hash)]
290pub enum DescriptionFilter {
291 /// `term op terms`.
292 Term {
293 /// The operator.
294 operator: Equality,
295 /// The search terms.
296 terms: Vec<TypedSearchTerm>,
297 },
298 /// `language op codes`.
299 Language {
300 /// The operator.
301 operator: Equality,
302 /// Two-letter language codes.
303 codes: Vec<String>,
304 },
305 /// `typeId op concepts`.
306 TypeId {
307 /// The operator.
308 operator: Equality,
309 /// The description type concepts.
310 value: ConceptSet,
311 },
312 /// `type op tokens`.
313 Type {
314 /// The operator.
315 operator: Equality,
316 /// The description type tokens.
317 tokens: Vec<TypeToken>,
318 },
319 /// `dialectId op value [acceptability]`.
320 DialectId {
321 /// The operator.
322 operator: Equality,
323 /// The language reference sets.
324 value: DialectIdValue,
325 /// The acceptability that applies to every dialect named.
326 acceptability: Option<AcceptabilitySet>,
327 },
328 /// `dialect op aliases [acceptability]`.
329 Dialect {
330 /// The operator.
331 operator: Equality,
332 /// The dialect aliases with their own acceptability.
333 aliases: Vec<DialectAlias>,
334 /// The acceptability that applies to every dialect named.
335 acceptability: Option<AcceptabilitySet>,
336 },
337 /// `moduleId op concepts`.
338 Module {
339 /// The operator.
340 operator: Equality,
341 /// The modules.
342 value: ConceptSet,
343 },
344 /// `effectiveTime op times`.
345 EffectiveTime {
346 /// The operator.
347 operator: Comparison,
348 /// The times.
349 values: Vec<TimeValue>,
350 },
351 /// `active op value`.
352 Active {
353 /// The operator.
354 operator: Equality,
355 /// The value.
356 value: bool,
357 },
358 /// `id op ids`.
359 Id {
360 /// The operator.
361 operator: Equality,
362 /// The description identifiers.
363 ids: Vec<Sctid>,
364 },
365}
366
367/// A sub-expression constraint or a set of two or more concept references
368/// (`subexpressionconstraint | eclconceptreferenceset`).
369#[derive(Debug, Clone, PartialEq, Eq, Hash)]
370pub enum ConceptSet {
371 /// A constraint.
372 Expression(SubExpressionConstraint),
373 /// `( ref ref ... )`, two or more.
374 Set(Vec<ConceptReference>),
375}
376
377/// `typetoken`.
378#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
379pub enum TypeToken {
380 /// `syn`
381 Synonym,
382 /// `fsn`
383 FullySpecifiedName,
384 /// `def`
385 Definition,
386}
387
388/// The value of a `dialectidfilter`.
389#[derive(Debug, Clone, PartialEq, Eq, Hash)]
390pub enum DialectIdValue {
391 /// A constraint.
392 Expression(SubExpressionConstraint),
393 /// `( ref [acceptability] ... )`, one or more.
394 Set(Vec<(ConceptReference, Option<AcceptabilitySet>)>),
395}
396
397/// One alias of a `dialectaliasfilter`.
398#[derive(Debug, Clone, PartialEq, Eq, Hash)]
399pub struct DialectAlias {
400 /// The alias (`en-gb`).
401 pub alias: String,
402 /// The acceptability for this alias alone.
403 pub acceptability: Option<AcceptabilitySet>,
404}
405
406/// `acceptabilityset`.
407#[derive(Debug, Clone, PartialEq, Eq, Hash)]
408pub enum AcceptabilitySet {
409 /// Acceptability concepts, one or more.
410 Concepts(Vec<ConceptReference>),
411 /// `accept` and `prefer` tokens, one or more.
412 Tokens(Vec<Acceptability>),
413}
414
415/// `acceptabilitytoken`.
416#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
417pub enum Acceptability {
418 /// `accept`
419 Acceptable,
420 /// `prefer`
421 Preferred,
422}
423
424/// `timevalue`: `YYYYMMDD` or empty.
425#[derive(Debug, Clone, PartialEq, Eq, Hash)]
426pub struct TimeValue(pub String);
427
428/// `conceptfilter`.
429#[derive(Debug, Clone, PartialEq, Eq, Hash)]
430pub enum ConceptFilter {
431 /// `definitionStatusId op concepts`.
432 DefinitionStatusId {
433 /// The operator.
434 operator: Equality,
435 /// The definition status concepts.
436 value: ConceptSet,
437 },
438 /// `definitionStatus op tokens`.
439 DefinitionStatus {
440 /// The operator.
441 operator: Equality,
442 /// The tokens.
443 tokens: Vec<DefinitionStatus>,
444 },
445 /// `moduleId op concepts`.
446 Module {
447 /// The operator.
448 operator: Equality,
449 /// The modules.
450 value: ConceptSet,
451 },
452 /// `effectiveTime op times`.
453 EffectiveTime {
454 /// The operator.
455 operator: Comparison,
456 /// The times.
457 values: Vec<TimeValue>,
458 },
459 /// `active op value`.
460 Active {
461 /// The operator.
462 operator: Equality,
463 /// The value.
464 value: bool,
465 },
466}
467
468/// `definitionstatustoken`.
469#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
470pub enum DefinitionStatus {
471 /// `primitive`
472 Primitive,
473 /// `defined`
474 Defined,
475}
476
477/// `memberfilter`.
478#[derive(Debug, Clone, PartialEq, Eq, Hash)]
479pub enum MemberFilter {
480 /// `moduleId op concepts`.
481 Module {
482 /// The operator.
483 operator: Equality,
484 /// The modules.
485 value: ConceptSet,
486 },
487 /// `effectiveTime op times`.
488 EffectiveTime {
489 /// The operator.
490 operator: Comparison,
491 /// The times.
492 values: Vec<TimeValue>,
493 },
494 /// `active op value`.
495 Active {
496 /// The operator.
497 operator: Equality,
498 /// The value.
499 value: bool,
500 },
501 /// `memberfieldfilter`: a reference set field compared to a value.
502 Field {
503 /// The field name.
504 name: String,
505 /// The comparison.
506 value: FieldValue,
507 },
508}
509
510/// The comparison of a `memberfieldfilter`.
511#[derive(Debug, Clone, PartialEq, Eq, Hash)]
512pub enum FieldValue {
513 /// `= sub` or `!= sub`.
514 Expression {
515 /// The operator.
516 operator: Equality,
517 /// The value constraint.
518 value: SubExpressionConstraint,
519 },
520 /// `op #number`.
521 Numeric {
522 /// The operator.
523 operator: Comparison,
524 /// The number.
525 value: NumericValue,
526 },
527 /// `= "string"` or a set.
528 String {
529 /// The operator.
530 operator: Equality,
531 /// The search terms.
532 terms: Vec<TypedSearchTerm>,
533 },
534 /// `= true` or `= false`.
535 Boolean {
536 /// The operator.
537 operator: Equality,
538 /// The value.
539 value: bool,
540 },
541 /// `< "time"` and the other ordering operators (`=` and `!=` with a
542 /// quoted value are string comparisons, the grammar's first match).
543 Time {
544 /// The operator: `Less`, `LessOrEqual`, `Greater`, or `GreaterOrEqual`.
545 operator: Comparison,
546 /// The times.
547 values: Vec<TimeValue>,
548 },
549}
550
551/// `historysupplement`.
552#[derive(Debug, Clone, PartialEq, Eq, Hash)]
553pub enum HistorySupplement {
554 /// `{{ + HISTORY }}`, the default profile.
555 Default,
556 /// `{{ + HISTORY-MIN }}`.
557 Minimum,
558 /// `{{ + HISTORY-MOD }}`.
559 Moderate,
560 /// `{{ + HISTORY-MAX }}`.
561 Maximum,
562 /// `{{ + HISTORY ( constraint ) }}`: the association reference sets.
563 Subset(Box<ExpressionConstraint>),
564}