1use crate::{SyntaxKind, SyntaxNode, SyntaxToken};
7
8pub trait AstNode: Sized {
10 fn can_cast(kind: SyntaxKind) -> bool;
11 fn cast(node: SyntaxNode) -> Option<Self>;
12 fn syntax(&self) -> &SyntaxNode;
13}
14
15macro_rules! ast_node {
16 ($(#[$meta:meta])* $name:ident, $kind:ident) => {
17 $(#[$meta])*
18 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
19 pub struct $name(SyntaxNode);
20
21 impl AstNode for $name {
22 fn can_cast(kind: SyntaxKind) -> bool {
23 kind == SyntaxKind::$kind
24 }
25
26 fn cast(node: SyntaxNode) -> Option<Self> {
27 Self::can_cast(node.kind()).then(|| Self(node))
28 }
29
30 fn syntax(&self) -> &SyntaxNode {
31 &self.0
32 }
33 }
34 };
35}
36
37fn child<N: AstNode>(node: &SyntaxNode) -> Option<N> {
38 node.children().find_map(N::cast)
39}
40
41fn children<N: AstNode>(node: &SyntaxNode) -> impl Iterator<Item = N> + use<N> {
42 node.children().filter_map(N::cast)
43}
44
45fn tokens(node: &SyntaxNode) -> impl Iterator<Item = SyntaxToken> + use<> {
46 node.children_with_tokens()
47 .filter_map(|element| element.into_token())
48 .filter(|token| !token.kind().is_trivia())
49}
50
51fn name_after(node: &SyntaxNode, skip: &[&str]) -> Option<String> {
53 tokens(node)
54 .filter(|t| matches!(t.kind(), SyntaxKind::Ident | SyntaxKind::DelimitedIdent))
55 .find(|t| !skip.contains(&t.text()))
56 .map(|t| name_text(&t))
57}
58
59pub fn name_text(token: &SyntaxToken) -> String {
61 match token.kind() {
62 SyntaxKind::DelimitedIdent => unescape(token.text()),
63 _ => token.text().to_owned(),
64 }
65}
66
67pub fn unescape(text: &str) -> String {
69 let inner = if text.starts_with("\"\"\"") && text.len() >= 6 {
71 return text[3..text.len() - 3].to_owned();
72 } else if text.len() >= 2 {
73 &text[1..text.len() - 1]
74 } else {
75 text
76 };
77 let mut out = String::with_capacity(inner.len());
78 let mut chars = inner.chars();
79 while let Some(c) = chars.next() {
80 if c != '\\' {
81 out.push(c);
82 continue;
83 }
84 match chars.next() {
85 Some('n') => out.push('\n'),
86 Some('r') => out.push('\r'),
87 Some('t') => out.push('\t'),
88 Some('f') => out.push('\u{c}'),
89 Some('u') => {
90 let hex: String = chars.by_ref().take(4).collect();
91 match u32::from_str_radix(&hex, 16).ok().and_then(char::from_u32) {
92 Some(decoded) => out.push(decoded),
93 None => {
94 out.push_str("\\u");
95 out.push_str(&hex);
96 }
97 }
98 }
99 Some(other) => out.push(other),
100 None => out.push('\\'),
101 }
102 }
103 out
104}
105
106ast_node!(
109 SourceFile,
111 SourceFile
112);
113
114impl SourceFile {
115 pub fn metadata(&self) -> impl Iterator<Item = Metadata> + use<> {
116 children(&self.0)
117 }
118
119 pub fn concept_maps(&self) -> impl Iterator<Item = ConceptMap> + use<> {
120 children(&self.0)
121 }
122
123 pub fn map_declaration(&self) -> Option<MapDeclaration> {
124 child(&self.0)
125 }
126
127 pub fn uses(&self) -> impl Iterator<Item = UsesDeclaration> + use<> {
128 children(&self.0)
129 }
130
131 pub fn imports(&self) -> impl Iterator<Item = ImportsDeclaration> + use<> {
132 children(&self.0)
133 }
134
135 pub fn constants(&self) -> impl Iterator<Item = ConstantDeclaration> + use<> {
136 children(&self.0)
137 }
138
139 pub fn groups(&self) -> impl Iterator<Item = Group> + use<> {
140 children(&self.0)
141 }
142}
143
144ast_node!(
145 Metadata,
147 Metadata
148);
149
150impl Metadata {
151 pub fn key(&self) -> Option<QualifiedName> {
153 child(&self.0)
154 }
155
156 pub fn value(&self) -> Option<Literal> {
158 child(&self.0)
159 }
160}
161
162ast_node!(
163 Literal,
165 Literal
166);
167
168impl Literal {
169 pub fn token(&self) -> Option<SyntaxToken> {
170 tokens(&self.0).next()
171 }
172
173 pub fn value(&self) -> Option<String> {
175 let token = self.token()?;
176 Some(match token.kind() {
177 SyntaxKind::SingleQuotedString
178 | SyntaxKind::DoubleQuotedString
179 | SyntaxKind::TripleQuotedString
180 | SyntaxKind::DelimitedIdent => unescape(token.text()),
181 _ => token.text().to_owned(),
182 })
183 }
184
185 pub fn kind(&self) -> Option<SyntaxKind> {
186 self.token().map(|t| t.kind())
187 }
188}
189
190ast_node!(
191 ConceptMap,
193 ConceptMap
194);
195
196impl ConceptMap {
197 pub fn url(&self) -> Option<Literal> {
198 child(&self.0)
199 }
200
201 pub fn prefixes(&self) -> impl Iterator<Item = ConceptMapPrefix> + use<> {
202 children(&self.0)
203 }
204
205 pub fn entries(&self) -> impl Iterator<Item = ConceptMapEntry> + use<> {
206 children(&self.0)
207 }
208
209 pub fn unmapped(&self) -> impl Iterator<Item = ConceptMapUnmapped> + use<> {
210 children(&self.0)
211 }
212}
213
214ast_node!(
215 ConceptMapUnmapped,
217 ConceptMapUnmapped
218);
219
220impl ConceptMapUnmapped {
221 pub fn prefix(&self) -> Option<String> {
222 name_after(&self.0, &["unmapped", "for"])
223 }
224
225 pub fn mode(&self) -> Option<String> {
227 tokens(&self.0)
228 .filter(|t| t.kind() == SyntaxKind::Ident)
229 .last()
230 .map(|t| t.text().to_owned())
231 }
232}
233
234ast_node!(
235 ConceptMapPrefix,
237 ConceptMapPrefix
238);
239
240impl ConceptMapPrefix {
241 pub fn name(&self) -> Option<String> {
242 name_after(&self.0, &["prefix"])
243 }
244
245 pub fn url(&self) -> Option<Literal> {
246 child(&self.0)
247 }
248}
249
250ast_node!(
251 ConceptMapEntry,
253 ConceptMapEntry
254);
255
256impl ConceptMapEntry {
257 pub fn source(&self) -> Option<ConceptMapCode> {
258 children(&self.0).next()
259 }
260
261 pub fn target(&self) -> Option<ConceptMapCode> {
262 children(&self.0).nth(1)
263 }
264
265 pub fn relation(&self) -> Option<String> {
267 self.0
268 .children()
269 .find(|n| n.kind() == SyntaxKind::ConceptMapRelation)
270 .map(|n| tokens(&n).map(|t| t.text().to_owned()).collect())
271 }
272}
273
274ast_node!(
275 ConceptMapCode,
277 ConceptMapCode
278);
279
280impl ConceptMapCode {
281 pub fn prefix(&self) -> Option<String> {
282 tokens(&self.0).next().map(|t| t.text().to_owned())
283 }
284
285 pub fn code(&self) -> Option<String> {
286 let token = tokens(&self.0).nth(2)?;
287 Some(match token.kind() {
288 SyntaxKind::Ident | SyntaxKind::Integer | SyntaxKind::Decimal => {
289 token.text().to_owned()
290 }
291 _ => unescape(token.text()),
292 })
293 }
294}
295
296ast_node!(
297 MapDeclaration,
299 MapDeclaration
300);
301
302impl MapDeclaration {
303 pub fn url(&self) -> Option<Literal> {
304 children(&self.0).next()
305 }
306
307 pub fn name(&self) -> Option<Literal> {
308 children(&self.0).nth(1)
309 }
310}
311
312#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
314pub enum ModelMode {
315 Source,
316 Queried,
317 Target,
318 Produced,
319}
320
321impl ModelMode {
322 pub fn as_str(self) -> &'static str {
323 match self {
324 ModelMode::Source => "source",
325 ModelMode::Queried => "queried",
326 ModelMode::Target => "target",
327 ModelMode::Produced => "produced",
328 }
329 }
330}
331
332ast_node!(
333 UsesDeclaration,
335 UsesDeclaration
336);
337
338impl UsesDeclaration {
339 pub fn url(&self) -> Option<Literal> {
340 child(&self.0)
341 }
342
343 pub fn alias(&self) -> Option<String> {
344 let alias = self
345 .0
346 .children()
347 .find(|n| n.kind() == SyntaxKind::UsesAlias)?;
348 name_after(&alias, &["alias"])
349 }
350
351 pub fn mode(&self) -> Option<ModelMode> {
352 let mut words = tokens(&self.0).map(|t| t.text().to_owned());
353 words.find(|w| w == "as")?;
354 match words.next()?.as_str() {
355 "source" => Some(ModelMode::Source),
356 "queried" => Some(ModelMode::Queried),
357 "target" => Some(ModelMode::Target),
358 "produced" => Some(ModelMode::Produced),
359 _ => None,
360 }
361 }
362}
363
364ast_node!(
365 ImportsDeclaration,
367 ImportsDeclaration
368);
369
370impl ImportsDeclaration {
371 pub fn url(&self) -> Option<Literal> {
372 child(&self.0)
373 }
374}
375
376ast_node!(
377 ConstantDeclaration,
379 ConstantDeclaration
380);
381
382impl ConstantDeclaration {
383 pub fn name(&self) -> Option<String> {
384 name_after(&self.0, &["let"])
385 }
386
387 pub fn expression(&self) -> Option<Expr> {
388 child(&self.0)
389 }
390}
391
392ast_node!(
395 Group,
397 Group
398);
399
400#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
402pub enum GroupTypeMode {
403 Types,
405 TypeAndTypes,
407}
408
409impl Group {
410 pub fn name(&self) -> Option<String> {
411 name_after(&self.0, &["group"])
412 }
413
414 pub fn parameters(&self) -> impl Iterator<Item = Parameter> + use<> {
415 child::<ParameterList>(&self.0)
416 .into_iter()
417 .flat_map(|list| children::<Parameter>(&list.0).collect::<Vec<_>>())
418 }
419
420 pub fn extends(&self) -> Option<String> {
421 let clause = self
422 .0
423 .children()
424 .find(|n| n.kind() == SyntaxKind::ExtendsClause)?;
425 name_after(&clause, &["extends"])
426 }
427
428 pub fn type_mode(&self) -> Option<GroupTypeMode> {
429 let mode = self
430 .0
431 .children()
432 .find(|n| n.kind() == SyntaxKind::TypeMode)?;
433 let text: String = tokens(&mode).map(|t| t.text().to_owned()).collect();
434 match text.as_str() {
435 "<<types>>" => Some(GroupTypeMode::Types),
436 "<<type+>>" => Some(GroupTypeMode::TypeAndTypes),
437 _ => None,
438 }
439 }
440
441 pub fn body(&self) -> Option<RuleBlock> {
442 child(&self.0)
443 }
444
445 pub fn rules(&self) -> impl Iterator<Item = Rule> + use<> {
446 self.body()
447 .into_iter()
448 .flat_map(|block| block.rules().collect::<Vec<_>>())
449 }
450}
451
452ast_node!(ParameterList, ParameterList);
453
454ast_node!(
455 Parameter,
457 Parameter
458);
459
460#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
462pub enum ParameterMode {
463 Source,
464 Target,
465}
466
467impl Parameter {
468 pub fn mode(&self) -> Option<ParameterMode> {
469 match tokens(&self.0).next()?.text() {
470 "source" => Some(ParameterMode::Source),
471 "target" => Some(ParameterMode::Target),
472 _ => None,
473 }
474 }
475
476 pub fn name(&self) -> Option<String> {
477 tokens(&self.0)
478 .nth(1)
479 .filter(|t| matches!(t.kind(), SyntaxKind::Ident | SyntaxKind::DelimitedIdent))
480 .map(|t| name_text(&t))
481 }
482
483 pub fn type_annotation(&self) -> Option<TypeAnnotation> {
484 child(&self.0)
485 }
486}
487
488ast_node!(
489 TypeAnnotation,
491 TypeAnnotation
492);
493
494impl TypeAnnotation {
495 pub fn type_name(&self) -> Option<String> {
497 if let Some(name) = child::<QualifiedName>(&self.0) {
498 return Some(name.text());
499 }
500 child::<Literal>(&self.0).and_then(|l| l.value())
501 }
502}
503
504ast_node!(
505 RuleBlock,
507 RuleBlock
508);
509
510impl RuleBlock {
511 pub fn rules(&self) -> impl Iterator<Item = Rule> + use<> {
512 children(&self.0)
513 }
514}
515
516ast_node!(
519 Rule,
521 Rule
522);
523
524impl Rule {
525 pub fn sources(&self) -> impl Iterator<Item = Source> + use<> {
526 self.0
527 .children()
528 .find(|n| n.kind() == SyntaxKind::SourceList)
529 .into_iter()
530 .flat_map(|list| children::<Source>(&list).collect::<Vec<_>>())
531 }
532
533 pub fn targets(&self) -> impl Iterator<Item = Target> + use<> {
534 self.0
535 .children()
536 .find(|n| n.kind() == SyntaxKind::TargetList)
537 .into_iter()
538 .flat_map(|list| children::<Target>(&list).collect::<Vec<_>>())
539 }
540
541 pub fn dependent(&self) -> Option<DependentClause> {
542 child(&self.0)
543 }
544
545 pub fn identity_fields(&self) -> Vec<String> {
547 self.0
548 .children()
549 .find(|n| n.kind() == SyntaxKind::IdentityList)
550 .map(|list| {
551 tokens(&list)
552 .filter(|t| matches!(t.kind(), SyntaxKind::Ident | SyntaxKind::DelimitedIdent))
553 .map(|t| name_text(&t))
554 .collect()
555 })
556 .unwrap_or_default()
557 }
558
559 pub fn name(&self) -> Option<String> {
561 let name = self
562 .0
563 .children()
564 .find(|n| n.kind() == SyntaxKind::RuleName)?;
565 tokens(&name).next().map(|t| unescape(t.text()))
566 }
567}
568
569#[derive(Debug, Clone, PartialEq, Eq, Hash)]
571pub enum ListMode {
572 First,
573 NotFirst,
574 Last,
575 NotLast,
576 OnlyOne,
577 Single,
578 Collate,
579 Share(String),
581}
582
583impl ListMode {
584 fn from_word(word: &str) -> Option<Self> {
585 Some(match word {
586 "first" => ListMode::First,
587 "not_first" => ListMode::NotFirst,
588 "last" => ListMode::Last,
589 "not_last" => ListMode::NotLast,
590 "only_one" => ListMode::OnlyOne,
591 "single" => ListMode::Single,
592 "collate" => ListMode::Collate,
593 _ => return None,
594 })
595 }
596}
597
598ast_node!(
599 Source,
601 Source
602);
603
604impl Source {
605 pub fn path(&self) -> Option<QualifiedName> {
607 child(&self.0)
608 }
609
610 pub fn type_annotation(&self) -> Option<TypeAnnotation> {
611 child(&self.0)
612 }
613
614 pub fn cardinality(&self) -> Option<(String, String)> {
616 let node = self
617 .0
618 .children()
619 .find(|n| n.kind() == SyntaxKind::Cardinality)?;
620 let mut parts = tokens(&node);
621 let min = parts.next()?.text().to_owned();
622 parts.next()?;
623 let max = parts.next()?.text().to_owned();
624 Some((min, max))
625 }
626
627 pub fn default_value(&self) -> Option<DefaultClause> {
628 child(&self.0)
629 }
630
631 pub fn list_mode(&self) -> Option<ListMode> {
632 let node = self
633 .0
634 .children()
635 .find(|n| n.kind() == SyntaxKind::SourceListMode)?;
636 ListMode::from_word(tokens(&node).next()?.text())
637 }
638
639 pub fn alias(&self) -> Option<String> {
640 child::<Alias>(&self.0).and_then(|a| a.name())
641 }
642
643 pub fn where_clause(&self) -> Option<Expr> {
644 self.clause(SyntaxKind::WhereClause)
645 }
646
647 pub fn check_clause(&self) -> Option<Expr> {
648 self.clause(SyntaxKind::CheckClause)
649 }
650
651 pub fn log_clause(&self) -> Option<Expr> {
652 self.clause(SyntaxKind::LogClause)
653 }
654
655 fn clause(&self, kind: SyntaxKind) -> Option<Expr> {
656 let node = self.0.children().find(|n| n.kind() == kind)?;
657 child(&node)
658 }
659}
660
661ast_node!(
662 DefaultClause,
664 DefaultClause
665);
666
667impl DefaultClause {
668 pub fn expression(&self) -> Option<Expr> {
669 child(&self.0)
670 }
671}
672
673ast_node!(
674 Alias,
676 Alias
677);
678
679impl Alias {
680 pub fn name(&self) -> Option<String> {
681 name_after(&self.0, &["as"])
682 }
683}
684
685ast_node!(
686 Target,
688 Target
689);
690
691impl Target {
692 pub fn path(&self) -> Option<QualifiedName> {
695 child(&self.0)
696 }
697
698 pub fn transform(&self) -> Option<TransformValue> {
701 if let Some(transform) = self
702 .0
703 .children()
704 .find(|n| n.kind() == SyntaxKind::Transform)
705 {
706 return transform.children().find_map(TransformValue::cast);
707 }
708 self.0
709 .children()
710 .filter(|n| matches!(n.kind(), SyntaxKind::Invocation | SyntaxKind::ParenExpr))
711 .find_map(TransformValue::cast)
712 }
713
714 pub fn alias(&self) -> Option<String> {
715 child::<Alias>(&self.0).and_then(|a| a.name())
716 }
717
718 pub fn list_mode(&self) -> Option<ListMode> {
719 let node = self
720 .0
721 .children()
722 .find(|n| n.kind() == SyntaxKind::TargetListMode)?;
723 let mut words = tokens(&node);
724 let word = words.next()?;
725 if word.text() == "share" {
726 return Some(ListMode::Share(name_text(&words.next()?)));
727 }
728 ListMode::from_word(word.text())
729 }
730}
731
732#[derive(Debug, Clone, PartialEq, Eq, Hash)]
734pub enum TransformValue {
735 Literal(Literal),
737 Name(QualifiedName),
739 Invocation(Invocation),
741 Expression(Expr),
743}
744
745impl TransformValue {
746 fn cast(node: SyntaxNode) -> Option<Self> {
747 Some(match node.kind() {
748 SyntaxKind::Literal => TransformValue::Literal(Literal(node)),
749 SyntaxKind::QualifiedName => TransformValue::Name(QualifiedName(node)),
750 SyntaxKind::Invocation => TransformValue::Invocation(Invocation(node)),
751 SyntaxKind::ParenExpr => TransformValue::Expression(Expr(node)),
752 _ => return None,
753 })
754 }
755
756 pub fn syntax(&self) -> &SyntaxNode {
757 match self {
758 TransformValue::Literal(n) => n.syntax(),
759 TransformValue::Name(n) => n.syntax(),
760 TransformValue::Invocation(n) => n.syntax(),
761 TransformValue::Expression(n) => n.syntax(),
762 }
763 }
764}
765
766ast_node!(
767 Invocation,
769 Invocation
770);
771
772impl Invocation {
773 pub fn name(&self) -> Option<String> {
774 tokens(&self.0).next().map(|t| name_text(&t))
775 }
776
777 pub fn arguments(&self) -> impl Iterator<Item = Expr> + use<> {
778 child::<ArgumentList>(&self.0)
779 .into_iter()
780 .flat_map(|list| children::<Expr>(&list.0).collect::<Vec<_>>())
781 }
782}
783
784ast_node!(ArgumentList, ArgumentList);
785
786ast_node!(
787 DependentClause,
789 DependentClause
790);
791
792impl DependentClause {
793 pub fn invocations(&self) -> impl Iterator<Item = Invocation> + use<> {
794 children(&self.0)
795 }
796
797 pub fn rules(&self) -> Option<RuleBlock> {
798 child(&self.0)
799 }
800}
801
802ast_node!(
803 QualifiedName,
805 QualifiedName
806);
807
808impl QualifiedName {
809 pub fn segments(&self) -> Vec<String> {
811 let mut segments: Vec<String> = Vec::new();
812 let mut choice = false;
813 for token in tokens(&self.0) {
814 match token.kind() {
815 SyntaxKind::Ident | SyntaxKind::DelimitedIdent if choice => {}
816 SyntaxKind::Ident | SyntaxKind::DelimitedIdent => segments.push(name_text(&token)),
817 SyntaxKind::LBracket => choice = true,
818 SyntaxKind::RBracket => {
819 choice = false;
820 if let Some(last) = segments.last_mut() {
821 last.push_str("[x]");
822 }
823 }
824 _ => {}
825 }
826 }
827 segments
828 }
829
830 pub fn text(&self) -> String {
832 self.segments().join(".")
833 }
834}
835
836#[derive(Debug, Clone, PartialEq, Eq, Hash)]
840pub struct Expr(SyntaxNode);
841
842impl AstNode for Expr {
843 fn can_cast(kind: SyntaxKind) -> bool {
844 matches!(
845 kind,
846 SyntaxKind::Literal
847 | SyntaxKind::Quantity
848 | SyntaxKind::NameRef
849 | SyntaxKind::ExternalConstant
850 | SyntaxKind::ParenExpr
851 | SyntaxKind::MemberExpr
852 | SyntaxKind::CallExpr
853 | SyntaxKind::IndexExpr
854 | SyntaxKind::PrefixExpr
855 | SyntaxKind::BinaryExpr
856 | SyntaxKind::TypeExpr
857 | SyntaxKind::NullLiteral
858 )
859 }
860
861 fn cast(node: SyntaxNode) -> Option<Self> {
862 Self::can_cast(node.kind()).then(|| Self(node))
863 }
864
865 fn syntax(&self) -> &SyntaxNode {
866 &self.0
867 }
868}
869
870impl Expr {
871 pub fn unparenthesized(&self) -> Expr {
873 let mut expr = self.clone();
874 while expr.0.kind() == SyntaxKind::ParenExpr {
875 match child::<Expr>(&expr.0) {
876 Some(inner) => expr = inner,
877 None => break,
878 }
879 }
880 expr
881 }
882
883 pub fn canonical_text(&self) -> String {
886 crate::expression_text(&self.0)
887 }
888
889 pub fn text(&self) -> String {
891 self.0.text().to_string().trim().to_owned()
892 }
893}