Skip to main content

sct_ecl/
ast.rs

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