Skip to main content

sct_ecl/
print.rs

1//! The canonical text of a syntax tree: `Display` for every node, in the
2//! grammar's own spelling, so `parse(print(tree)) == tree`.
3
4use std::fmt::{self, Display, Formatter};
5
6use crate::ast::{
7    Acceptability, AcceptabilitySet, AltIdentifier, Attribute, AttributeSet, AttributeValue,
8    Cardinality, Comparison, ConceptFilter, ConceptReference, ConceptSet, ConstraintOperator,
9    DefinitionStatus, DescriptionFilter, DialectAlias, DialectIdValue, Equality,
10    ExpressionConstraint, FieldValue, FilterConstraint, FocusConcept, HistorySupplement,
11    MemberFilter, MemberOf, NumericValue, Refinement, RefsetFields, Sctid, SubAttributeSet,
12    SubExpressionConstraint, SubRefinement, TimeValue, TypeToken, TypedSearchTerm,
13};
14
15/// Writes `items` separated by `separator`.
16fn join<T: Display>(f: &mut Formatter<'_>, items: &[T], separator: &str) -> fmt::Result {
17    for (i, item) in items.iter().enumerate() {
18        if i > 0 {
19            f.write_str(separator)?;
20        }
21        write!(f, "{item}")?;
22    }
23    Ok(())
24}
25
26/// Writes one item bare and several as `( a b )`.
27fn bare_or_set<T: Display>(f: &mut Formatter<'_>, items: &[T]) -> fmt::Result {
28    match items {
29        [one] => write!(f, "{one}"),
30        many => {
31            f.write_str("(")?;
32            join(f, many, " ")?;
33            f.write_str(")")
34        }
35    }
36}
37
38/// Writes a quoted string.
39fn quoted(f: &mut Formatter<'_>, text: &str) -> fmt::Result {
40    write!(f, "\"{text}\"")
41}
42
43impl Display for Sctid {
44    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
45        write!(f, "{}", self.0)
46    }
47}
48
49impl Display for ConceptReference {
50    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
51        write!(f, "{}", self.id)?;
52        if let Some(term) = &self.term {
53            write!(f, " |{term}|")?;
54        }
55        Ok(())
56    }
57}
58
59impl Display for AltIdentifier {
60    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
61        let bare = self
62            .code
63            .chars()
64            .all(|c| c.is_ascii_alphanumeric() || matches!(c, '-' | '.' | '_'));
65        if bare {
66            write!(f, "{}#{}", self.scheme, self.code)?;
67        } else {
68            write!(f, "\"{}#{}\"", self.scheme, self.code)?;
69        }
70        if let Some(term) = &self.term {
71            write!(f, " |{term}|")?;
72        }
73        Ok(())
74    }
75}
76
77impl Display for FocusConcept {
78    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
79        match self {
80            Self::Reference(reference) => write!(f, "{reference}"),
81            Self::Wildcard => f.write_str("*"),
82            Self::AltIdentifier(alt) => write!(f, "{alt}"),
83            Self::Nested(inner) => write!(f, "( {inner} )"),
84        }
85    }
86}
87
88impl Display for ConstraintOperator {
89    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
90        f.write_str(match self {
91            Self::DescendantOf => "<",
92            Self::DescendantOrSelfOf => "<<",
93            Self::ChildOf => "<!",
94            Self::ChildOrSelfOf => "<<!",
95            Self::AncestorOf => ">",
96            Self::AncestorOrSelfOf => ">>",
97            Self::ParentOf => ">!",
98            Self::ParentOrSelfOf => ">>!",
99            Self::Top => "!!>",
100            Self::Bottom => "!!<",
101        })
102    }
103}
104
105impl Display for MemberOf {
106    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
107        f.write_str("^")?;
108        match &self.fields {
109            None => Ok(()),
110            Some(RefsetFields::Any) => f.write_str(" [*]"),
111            Some(RefsetFields::Names(names)) => {
112                f.write_str(" [")?;
113                join(f, names, ", ")?;
114                f.write_str("]")
115            }
116        }
117    }
118}
119
120impl Display for SubExpressionConstraint {
121    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
122        if let Some(operator) = self.operator {
123            write!(f, "{operator} ")?;
124        }
125        if let Some(member_of) = &self.member_of {
126            write!(f, "{member_of} ")?;
127        }
128        write!(f, "{}", self.focus)?;
129        for filters in &self.member_filters {
130            f.write_str(" {{ M ")?;
131            join(f, filters, ", ")?;
132            f.write_str(" }}")?;
133        }
134        for filter in &self.filters {
135            write!(f, " {filter}")?;
136        }
137        if let Some(history) = &self.history {
138            write!(f, " {history}")?;
139        }
140        Ok(())
141    }
142}
143
144impl Display for FilterConstraint {
145    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
146        match self {
147            Self::Description(filters) => {
148                f.write_str("{{ D ")?;
149                join(f, filters, ", ")?;
150                f.write_str(" }}")
151            }
152            Self::Concept(filters) => {
153                f.write_str("{{ C ")?;
154                join(f, filters, ", ")?;
155                f.write_str(" }}")
156            }
157        }
158    }
159}
160
161impl Display for ExpressionConstraint {
162    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
163        match self {
164            Self::Refined { focus, refinement } => write!(f, "{focus} : {refinement}"),
165            Self::Conjunction(operands) => join(f, operands, " AND "),
166            Self::Disjunction(operands) => join(f, operands, " OR "),
167            Self::Exclusion { left, right } => write!(f, "{left} MINUS {right}"),
168            Self::Dotted { focus, attributes } => {
169                write!(f, "{focus}")?;
170                for attribute in attributes {
171                    write!(f, " . {attribute}")?;
172                }
173                Ok(())
174            }
175            Self::Sub(sub) => write!(f, "{sub}"),
176        }
177    }
178}
179
180impl Display for Refinement {
181    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
182        match self {
183            Self::Single(one) => write!(f, "{one}"),
184            Self::Conjunction(items) => join(f, items, ", "),
185            Self::Disjunction(items) => join(f, items, " OR "),
186        }
187    }
188}
189
190impl Display for SubRefinement {
191    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
192        match self {
193            Self::AttributeSet(set) => write!(f, "{set}"),
194            Self::Group {
195                cardinality,
196                attributes,
197            } => {
198                if let Some(cardinality) = cardinality {
199                    write!(f, "{cardinality} ")?;
200                }
201                write!(f, "{{ {attributes} }}")
202            }
203            Self::Nested(inner) => write!(f, "( {inner} )"),
204        }
205    }
206}
207
208impl Display for AttributeSet {
209    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
210        match self {
211            Self::Single(one) => write!(f, "{one}"),
212            Self::Conjunction(items) => join(f, items, ", "),
213            Self::Disjunction(items) => join(f, items, " OR "),
214        }
215    }
216}
217
218impl Display for SubAttributeSet {
219    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
220        match self {
221            Self::Attribute(attribute) => write!(f, "{attribute}"),
222            Self::Nested(inner) => write!(f, "( {inner} )"),
223        }
224    }
225}
226
227impl Display for Attribute {
228    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
229        if let Some(cardinality) = self.cardinality {
230            write!(f, "{cardinality} ")?;
231        }
232        if self.reverse {
233            f.write_str("R ")?;
234        }
235        write!(f, "{} {}", self.name, self.value)
236    }
237}
238
239impl Display for AttributeValue {
240    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
241        match self {
242            Self::Expression { operator, value } => write!(f, "{operator} {value}"),
243            Self::Numeric { operator, value } => write!(f, "{operator} {value}"),
244            Self::String { operator, terms } => {
245                write!(f, "{operator} ")?;
246                bare_or_set(f, terms)
247            }
248            Self::Boolean { operator, value } => write!(f, "{operator} {value}"),
249        }
250    }
251}
252
253impl Display for Cardinality {
254    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
255        match self.max {
256            Some(max) => write!(f, "[{}..{max}]", self.min),
257            None => write!(f, "[{}..*]", self.min),
258        }
259    }
260}
261
262impl Display for Equality {
263    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
264        f.write_str(match self {
265            Self::Equal => "=",
266            Self::NotEqual => "!=",
267        })
268    }
269}
270
271impl Display for Comparison {
272    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
273        f.write_str(match self {
274            Self::Equal => "=",
275            Self::NotEqual => "!=",
276            Self::Less => "<",
277            Self::LessOrEqual => "<=",
278            Self::Greater => ">",
279            Self::GreaterOrEqual => ">=",
280        })
281    }
282}
283
284impl Display for NumericValue {
285    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
286        write!(f, "#{}", self.0)
287    }
288}
289
290impl Display for TypedSearchTerm {
291    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
292        match self {
293            Self::Match(words) => {
294                f.write_str("\"")?;
295                join(f, words, " ")?;
296                f.write_str("\"")
297            }
298            Self::Wild(pattern) => {
299                f.write_str("wild:")?;
300                quoted(f, pattern)
301            }
302        }
303    }
304}
305
306impl Display for DescriptionFilter {
307    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
308        match self {
309            Self::Term { operator, terms } => {
310                write!(f, "term {operator} ")?;
311                bare_or_set(f, terms)
312            }
313            Self::Language { operator, codes } => {
314                write!(f, "language {operator} ")?;
315                bare_or_set(f, codes)
316            }
317            Self::TypeId { operator, value } => write!(f, "typeId {operator} {value}"),
318            Self::Type { operator, tokens } => {
319                write!(f, "type {operator} ")?;
320                bare_or_set(f, tokens)
321            }
322            Self::DialectId {
323                operator,
324                value,
325                acceptability,
326            } => {
327                write!(f, "dialectId {operator} {value}")?;
328                if let Some(acceptability) = acceptability {
329                    write!(f, " {acceptability}")?;
330                }
331                Ok(())
332            }
333            Self::Dialect {
334                operator,
335                aliases,
336                acceptability,
337            } => {
338                write!(f, "dialect {operator} ")?;
339                match aliases.as_slice() {
340                    [
341                        DialectAlias {
342                            alias,
343                            acceptability: None,
344                        },
345                    ] => f.write_str(alias)?,
346                    many => {
347                        f.write_str("(")?;
348                        join(f, many, " ")?;
349                        f.write_str(")")?;
350                    }
351                }
352                if let Some(acceptability) = acceptability {
353                    write!(f, " {acceptability}")?;
354                }
355                Ok(())
356            }
357            Self::Module { operator, value } => write!(f, "moduleId {operator} {value}"),
358            Self::EffectiveTime { operator, values } => {
359                write!(f, "effectiveTime {operator} ")?;
360                bare_or_set(f, values)
361            }
362            Self::Active { operator, value } => write!(f, "active {operator} {value}"),
363            Self::Id { operator, ids } => {
364                write!(f, "id {operator} ")?;
365                bare_or_set(f, ids)
366            }
367        }
368    }
369}
370
371impl Display for ConceptSet {
372    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
373        match self {
374            Self::Expression(sub) => write!(f, "{sub}"),
375            Self::Set(references) => {
376                f.write_str("(")?;
377                join(f, references, " ")?;
378                f.write_str(")")
379            }
380        }
381    }
382}
383
384impl Display for TypeToken {
385    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
386        f.write_str(match self {
387            Self::Synonym => "syn",
388            Self::FullySpecifiedName => "fsn",
389            Self::Definition => "def",
390        })
391    }
392}
393
394impl Display for DialectIdValue {
395    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
396        match self {
397            Self::Expression(sub) => write!(f, "{sub}"),
398            Self::Set(items) => {
399                f.write_str("(")?;
400                for (i, (reference, acceptability)) in items.iter().enumerate() {
401                    if i > 0 {
402                        f.write_str(" ")?;
403                    }
404                    write!(f, "{reference}")?;
405                    if let Some(acceptability) = acceptability {
406                        write!(f, " {acceptability}")?;
407                    }
408                }
409                f.write_str(")")
410            }
411        }
412    }
413}
414
415impl Display for DialectAlias {
416    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
417        f.write_str(&self.alias)?;
418        if let Some(acceptability) = &self.acceptability {
419            write!(f, " {acceptability}")?;
420        }
421        Ok(())
422    }
423}
424
425impl Display for AcceptabilitySet {
426    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
427        f.write_str("(")?;
428        match self {
429            Self::Concepts(references) => join(f, references, " ")?,
430            Self::Tokens(tokens) => join(f, tokens, " ")?,
431        }
432        f.write_str(")")
433    }
434}
435
436impl Display for Acceptability {
437    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
438        f.write_str(match self {
439            Self::Acceptable => "accept",
440            Self::Preferred => "prefer",
441        })
442    }
443}
444
445impl Display for TimeValue {
446    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
447        quoted(f, &self.0)
448    }
449}
450
451impl Display for ConceptFilter {
452    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
453        match self {
454            Self::DefinitionStatusId { operator, value } => {
455                write!(f, "definitionStatusId {operator} {value}")
456            }
457            Self::DefinitionStatus { operator, tokens } => {
458                write!(f, "definitionStatus {operator} ")?;
459                bare_or_set(f, tokens)
460            }
461            Self::Module { operator, value } => write!(f, "moduleId {operator} {value}"),
462            Self::EffectiveTime { operator, values } => {
463                write!(f, "effectiveTime {operator} ")?;
464                bare_or_set(f, values)
465            }
466            Self::Active { operator, value } => write!(f, "active {operator} {value}"),
467        }
468    }
469}
470
471impl Display for DefinitionStatus {
472    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
473        f.write_str(match self {
474            Self::Primitive => "primitive",
475            Self::Defined => "defined",
476        })
477    }
478}
479
480impl Display for MemberFilter {
481    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
482        match self {
483            Self::Module { operator, value } => write!(f, "moduleId {operator} {value}"),
484            Self::EffectiveTime { operator, values } => {
485                write!(f, "effectiveTime {operator} ")?;
486                bare_or_set(f, values)
487            }
488            Self::Active { operator, value } => write!(f, "active {operator} {value}"),
489            Self::Field { name, value } => write!(f, "{name} {value}"),
490        }
491    }
492}
493
494impl Display for FieldValue {
495    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
496        match self {
497            Self::Expression { operator, value } => write!(f, "{operator} {value}"),
498            Self::Numeric { operator, value } => write!(f, "{operator} {value}"),
499            Self::String { operator, terms } => {
500                write!(f, "{operator} ")?;
501                bare_or_set(f, terms)
502            }
503            Self::Boolean { operator, value } => write!(f, "{operator} {value}"),
504            Self::Time { operator, values } => {
505                write!(f, "{operator} ")?;
506                bare_or_set(f, values)
507            }
508        }
509    }
510}
511
512impl Display for HistorySupplement {
513    fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
514        match self {
515            Self::Default => f.write_str("{{ + HISTORY }}"),
516            Self::Minimum => f.write_str("{{ + HISTORY-MIN }}"),
517            Self::Moderate => f.write_str("{{ + HISTORY-MOD }}"),
518            Self::Maximum => f.write_str("{{ + HISTORY-MAX }}"),
519            Self::Subset(inner) => write!(f, "{{{{ + HISTORY ( {inner} ) }}}}"),
520        }
521    }
522}