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/// `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}