Skip to main content

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/// `refsetOperator`: `memberOf` or `refsetContainingAny`.
88#[derive(Debug, Clone, PartialEq, Eq, Hash)]
89pub enum RefsetOperator {
90    /// `^`: the members of the reference sets the focus names.
91    MemberOf(MemberOf),
92    /// `^R`: the reference sets with a member the focus names.
93    ContainingAny,
94}
95
96/// `subexpressionconstraint`.
97#[derive(Debug, Clone, PartialEq, Eq, Hash)]
98pub struct SubExpressionConstraint {
99    /// The constraint operator before the focus.
100    pub operator: Option<ConstraintOperator>,
101    /// The `^` or `^R` before the focus.
102    pub refset_operator: Option<RefsetOperator>,
103    /// The focus concept or nested constraint.
104    pub focus: FocusConcept,
105    /// `memberfilterconstraint`s, one list per `{{ M ... }}`.
106    pub member_filters: Vec<Vec<MemberFilter>>,
107    /// The description and concept filter constraints, in order.
108    pub filters: Vec<FilterConstraint>,
109    /// `historysupplement`.
110    pub history: Option<HistorySupplement>,
111}
112
113/// `descriptionfilterconstraint` or `conceptfilterconstraint`.
114#[derive(Debug, Clone, PartialEq, Eq, Hash)]
115pub enum FilterConstraint {
116    /// `{{ D ... }}`.
117    Description(Vec<DescriptionFilter>),
118    /// `{{ C ... }}`.
119    Concept(Vec<ConceptFilter>),
120}
121
122/// `expressionconstraint`.
123#[derive(Debug, Clone, PartialEq, Eq, Hash)]
124pub enum ExpressionConstraint {
125    /// `refinedexpressionconstraint`: a focus with `:` and a refinement.
126    Refined {
127        /// The constraint refined.
128        focus: SubExpressionConstraint,
129        /// The refinement.
130        refinement: Box<Refinement>,
131    },
132    /// `conjunctionexpressionconstraint`, two or more operands.
133    Conjunction(Vec<SubExpressionConstraint>),
134    /// `disjunctionexpressionconstraint`, two or more operands.
135    Disjunction(Vec<SubExpressionConstraint>),
136    /// `exclusionexpressionconstraint`.
137    Exclusion {
138        /// The set kept.
139        left: SubExpressionConstraint,
140        /// The set removed.
141        right: SubExpressionConstraint,
142    },
143    /// `dottedexpressionconstraint`: a focus followed by `. attribute` steps.
144    Dotted {
145        /// The constraint the walk starts from.
146        focus: SubExpressionConstraint,
147        /// The attribute names walked, in order.
148        attributes: Vec<SubExpressionConstraint>,
149    },
150    /// A bare `subexpressionconstraint`.
151    Sub(SubExpressionConstraint),
152}
153
154/// `eclrefinement`.
155#[derive(Debug, Clone, PartialEq, Eq, Hash)]
156pub enum Refinement {
157    /// One sub-refinement.
158    Single(Box<SubRefinement>),
159    /// Sub-refinements joined by `AND` or `,`, two or more.
160    Conjunction(Vec<SubRefinement>),
161    /// Sub-refinements joined by `OR`, two or more.
162    Disjunction(Vec<SubRefinement>),
163}
164
165/// `subrefinement`.
166#[derive(Debug, Clone, PartialEq, Eq, Hash)]
167pub enum SubRefinement {
168    /// An attribute set.
169    AttributeSet(AttributeSet),
170    /// `eclattributegroup`: `[c] { attributes }`.
171    Group {
172        /// The group cardinality.
173        cardinality: Option<Cardinality>,
174        /// The attributes in the group.
175        attributes: AttributeSet,
176    },
177    /// `( eclrefinement )`.
178    Nested(Box<Refinement>),
179}
180
181/// `eclattributeset`.
182#[derive(Debug, Clone, PartialEq, Eq, Hash)]
183pub enum AttributeSet {
184    /// One sub-attribute set.
185    Single(Box<SubAttributeSet>),
186    /// Joined by `AND` or `,`, two or more.
187    Conjunction(Vec<SubAttributeSet>),
188    /// Joined by `OR`, two or more.
189    Disjunction(Vec<SubAttributeSet>),
190}
191
192/// `subattributeset`.
193#[derive(Debug, Clone, PartialEq, Eq, Hash)]
194pub enum SubAttributeSet {
195    /// An attribute.
196    Attribute(Box<Attribute>),
197    /// `( eclattributeset )`.
198    Nested(Box<AttributeSet>),
199}
200
201/// `eclattribute`.
202#[derive(Debug, Clone, PartialEq, Eq, Hash)]
203pub struct Attribute {
204    /// `[min..max]` before the name.
205    pub cardinality: Option<Cardinality>,
206    /// The reverse flag `R`.
207    pub reverse: bool,
208    /// `eclattributename`, a sub-expression constraint.
209    pub name: SubExpressionConstraint,
210    /// The comparison and value.
211    pub value: AttributeValue,
212}
213
214/// The comparison and value of an attribute or a member field.
215#[derive(Debug, Clone, PartialEq, Eq, Hash)]
216pub enum AttributeValue {
217    /// `= sub` or `!= sub`.
218    Expression {
219        /// The operator.
220        operator: Equality,
221        /// The value constraint.
222        value: SubExpressionConstraint,
223    },
224    /// `op #number`.
225    Numeric {
226        /// The operator.
227        operator: Comparison,
228        /// The number.
229        value: NumericValue,
230    },
231    /// `= "string"` or `= ("string" "string")`: `concretestring` or
232    /// `concretestringset`.
233    String {
234        /// The operator.
235        operator: Equality,
236        /// The strings; one prints bare, more print as a set.
237        values: Vec<ConcreteString>,
238    },
239    /// `= true` or `= false`.
240    Boolean {
241        /// The operator.
242        operator: Equality,
243        /// The value.
244        value: bool,
245    },
246}
247
248/// `cardinality`: `min..max`, `max` absent for `*`.
249#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
250pub struct Cardinality {
251    /// The minimum.
252    pub min: u32,
253    /// The maximum, `None` for `*`.
254    pub max: Option<u32>,
255}
256
257/// `expressioncomparisonoperator`, `stringcomparisonoperator`,
258/// `booleancomparisonoperator`, and `idcomparisonoperator`.
259#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
260pub enum Equality {
261    /// `=`
262    Equal,
263    /// `!=`
264    NotEqual,
265}
266
267/// `numericcomparisonoperator` and `timecomparisonoperator`.
268#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
269pub enum Comparison {
270    /// `=`
271    Equal,
272    /// `!=`
273    NotEqual,
274    /// `<`
275    Less,
276    /// `<=`
277    LessOrEqual,
278    /// `>`
279    Greater,
280    /// `>=`
281    GreaterOrEqual,
282}
283
284/// `numericvalue`: the literal after `#`, as written (an optional sign,
285/// digits, an optional fraction).
286#[derive(Debug, Clone, PartialEq, Eq, Hash)]
287pub struct NumericValue(pub String);
288
289/// `concretestring`: the string between the quotes with its escapes
290/// (`\"`, `\\`, `\*`) decoded, compared exactly.
291#[derive(Debug, Clone, PartialEq, Eq, Hash)]
292pub struct ConcreteString(pub String);
293
294/// `activevalue`.
295#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
296pub enum ActiveValue {
297    /// `1` or `true`.
298    Active,
299    /// `0` or `false`.
300    Inactive,
301    /// `*`: either status.
302    Any,
303}
304
305/// `typedsearchterm`.
306#[derive(Debug, Clone, PartialEq, Eq, Hash)]
307pub enum TypedSearchTerm {
308    /// `"word word"` or `match:"..."`: every word must match as a prefix.
309    Match(Vec<String>),
310    /// `wild:"..."`: a pattern with `*` wildcards.
311    Wild(String),
312}
313
314/// `descriptionfilter`.
315#[derive(Debug, Clone, PartialEq, Eq, Hash)]
316pub enum DescriptionFilter {
317    /// `term op terms`.
318    Term {
319        /// The operator.
320        operator: Equality,
321        /// The search terms.
322        terms: Vec<TypedSearchTerm>,
323    },
324    /// `language op codes`.
325    Language {
326        /// The operator.
327        operator: Equality,
328        /// Two-letter language codes.
329        codes: Vec<String>,
330    },
331    /// `typeId op concepts`.
332    TypeId {
333        /// The operator.
334        operator: Equality,
335        /// The description type concepts.
336        value: ConceptSet,
337    },
338    /// `type op tokens`.
339    Type {
340        /// The operator.
341        operator: Equality,
342        /// The description type tokens.
343        tokens: Vec<TypeToken>,
344    },
345    /// `dialectId op value [acceptability]`.
346    DialectId {
347        /// The operator.
348        operator: Equality,
349        /// The language reference sets.
350        value: DialectIdValue,
351        /// The acceptability that applies to every dialect named.
352        acceptability: Option<AcceptabilitySet>,
353    },
354    /// `dialect op aliases [acceptability]`.
355    Dialect {
356        /// The operator.
357        operator: Equality,
358        /// The dialect aliases with their own acceptability.
359        aliases: Vec<DialectAlias>,
360        /// The acceptability that applies to every dialect named.
361        acceptability: Option<AcceptabilitySet>,
362    },
363    /// `moduleId op concepts`.
364    Module {
365        /// The operator.
366        operator: Equality,
367        /// The modules.
368        value: ConceptSet,
369    },
370    /// `effectiveTime op times`.
371    EffectiveTime {
372        /// The operator.
373        operator: Comparison,
374        /// The times.
375        values: Vec<TimeValue>,
376    },
377    /// `active op value`.
378    Active {
379        /// The operator.
380        operator: Equality,
381        /// The value.
382        value: ActiveValue,
383    },
384    /// `id op ids`.
385    Id {
386        /// The operator.
387        operator: Equality,
388        /// The description identifiers.
389        ids: Vec<Sctid>,
390    },
391}
392
393/// A sub-expression constraint or a set of two or more concept references
394/// (`subexpressionconstraint | eclconceptreferenceset`).
395#[derive(Debug, Clone, PartialEq, Eq, Hash)]
396pub enum ConceptSet {
397    /// A constraint.
398    Expression(SubExpressionConstraint),
399    /// `( ref ref ... )`, two or more.
400    Set(Vec<ConceptReference>),
401}
402
403/// `typetoken`.
404#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
405pub enum TypeToken {
406    /// `syn`
407    Synonym,
408    /// `fsn`
409    FullySpecifiedName,
410    /// `def`
411    Definition,
412}
413
414/// The value of a `dialectidfilter`.
415#[derive(Debug, Clone, PartialEq, Eq, Hash)]
416pub enum DialectIdValue {
417    /// A constraint.
418    Expression(SubExpressionConstraint),
419    /// `( ref [acceptability] ... )`, one or more.
420    Set(Vec<(ConceptReference, Option<AcceptabilitySet>)>),
421}
422
423/// One alias of a `dialectaliasfilter`.
424#[derive(Debug, Clone, PartialEq, Eq, Hash)]
425pub struct DialectAlias {
426    /// The alias (`en-gb`).
427    pub alias: String,
428    /// The acceptability for this alias alone.
429    pub acceptability: Option<AcceptabilitySet>,
430}
431
432/// `acceptabilityset`.
433#[derive(Debug, Clone, PartialEq, Eq, Hash)]
434pub enum AcceptabilitySet {
435    /// Acceptability concepts, one or more.
436    Concepts(Vec<ConceptReference>),
437    /// `accept` and `prefer` tokens, one or more.
438    Tokens(Vec<Acceptability>),
439}
440
441/// `acceptabilitytoken`.
442#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
443pub enum Acceptability {
444    /// `accept`
445    Acceptable,
446    /// `prefer`
447    Preferred,
448}
449
450/// `timevalue`: `YYYYMMDD` or empty.
451#[derive(Debug, Clone, PartialEq, Eq, Hash)]
452pub struct TimeValue(pub String);
453
454/// `conceptfilter`.
455#[derive(Debug, Clone, PartialEq, Eq, Hash)]
456pub enum ConceptFilter {
457    /// `definitionStatusId op concepts`.
458    DefinitionStatusId {
459        /// The operator.
460        operator: Equality,
461        /// The definition status concepts.
462        value: ConceptSet,
463    },
464    /// `definitionStatus op tokens`.
465    DefinitionStatus {
466        /// The operator.
467        operator: Equality,
468        /// The tokens.
469        tokens: Vec<DefinitionStatus>,
470    },
471    /// `moduleId op concepts`.
472    Module {
473        /// The operator.
474        operator: Equality,
475        /// The modules.
476        value: ConceptSet,
477    },
478    /// `effectiveTime op times`.
479    EffectiveTime {
480        /// The operator.
481        operator: Comparison,
482        /// The times.
483        values: Vec<TimeValue>,
484    },
485    /// `active op value`.
486    Active {
487        /// The operator.
488        operator: Equality,
489        /// The value.
490        value: ActiveValue,
491    },
492}
493
494/// `definitionstatustoken`.
495#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
496pub enum DefinitionStatus {
497    /// `primitive`
498    Primitive,
499    /// `defined`
500    Defined,
501}
502
503/// `memberfilter`.
504#[derive(Debug, Clone, PartialEq, Eq, Hash)]
505pub enum MemberFilter {
506    /// `moduleId op concepts`.
507    Module {
508        /// The operator.
509        operator: Equality,
510        /// The modules.
511        value: ConceptSet,
512    },
513    /// `effectiveTime op times`.
514    EffectiveTime {
515        /// The operator.
516        operator: Comparison,
517        /// The times.
518        values: Vec<TimeValue>,
519    },
520    /// `active op value`.
521    Active {
522        /// The operator.
523        operator: Equality,
524        /// The value.
525        value: ActiveValue,
526    },
527    /// `memberfieldfilter`: a reference set field compared to a value.
528    Field {
529        /// The field name.
530        name: String,
531        /// The comparison.
532        value: FieldValue,
533    },
534}
535
536/// The comparison of a `memberfieldfilter`.
537#[derive(Debug, Clone, PartialEq, Eq, Hash)]
538pub enum FieldValue {
539    /// `= sub` or `!= sub`.
540    Expression {
541        /// The operator.
542        operator: Equality,
543        /// The value constraint.
544        value: SubExpressionConstraint,
545    },
546    /// `op #number`.
547    Numeric {
548        /// The operator.
549        operator: Comparison,
550        /// The number.
551        value: NumericValue,
552    },
553    /// `= "string"` or a set.
554    String {
555        /// The operator.
556        operator: Equality,
557        /// The search terms.
558        terms: Vec<TypedSearchTerm>,
559    },
560    /// `= true` or `= false`.
561    Boolean {
562        /// The operator.
563        operator: Equality,
564        /// The value.
565        value: bool,
566    },
567    /// `< "time"` and the other ordering operators (`=` and `!=` with a
568    /// quoted value are string comparisons, the grammar's first match).
569    Time {
570        /// The operator: `Less`, `LessOrEqual`, `Greater`, or `GreaterOrEqual`.
571        operator: Comparison,
572        /// The times.
573        values: Vec<TimeValue>,
574    },
575}
576
577/// `historysupplement`.
578#[derive(Debug, Clone, PartialEq, Eq, Hash)]
579pub enum HistorySupplement {
580    /// `{{ + HISTORY }}`, the default profile.
581    Default,
582    /// `{{ + HISTORY-MIN }}`.
583    Minimum,
584    /// `{{ + HISTORY-MOD }}`.
585    Moderate,
586    /// `{{ + HISTORY-MAX }}`.
587    Maximum,
588    /// `{{ + HISTORY ( constraint ) }}`: the association reference sets.
589    Subset(Box<ExpressionConstraint>),
590}