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}