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