1use rowan::ast::AstNode;
4use smol_str::SmolStr;
5
6use super::syntax::{RdLanguage, SyntaxKind, SyntaxNode, SyntaxToken};
7
8macro_rules! wrapper {
9 ($name:ident, $kind:ident) => {
10 #[doc = concat!("A typed view of an Rd `", stringify!($kind), "` node.")]
11 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
12 pub struct $name(SyntaxNode);
13
14 impl AstNode for $name {
15 type Language = RdLanguage;
16 fn can_cast(kind: SyntaxKind) -> bool {
17 kind == SyntaxKind::$kind
18 }
19 fn cast(node: SyntaxNode) -> std::option::Option<Self> {
20 Self::can_cast(node.kind()).then_some(Self(node))
21 }
22 fn syntax(&self) -> &SyntaxNode {
23 &self.0
24 }
25 }
26 };
27}
28
29wrapper!(Document, ROOT);
30wrapper!(Macro, MACRO);
31wrapper!(Argument, ARGUMENT);
32wrapper!(Group, GROUP);
33wrapper!(Option, OPTION);
34wrapper!(Conditional, CONDITIONAL);
35
36fn token(node: &SyntaxNode, kind: SyntaxKind) -> std::option::Option<SyntaxToken> {
37 node.children_with_tokens()
38 .filter_map(|element| element.into_token())
39 .find(|token| token.kind() == kind)
40}
41
42impl Document {
43 pub fn macros(&self) -> impl Iterator<Item = Macro> + use<> {
45 self.0.children().filter_map(Macro::cast)
46 }
47}
48
49impl Macro {
50 pub fn name_token(&self) -> std::option::Option<SyntaxToken> {
52 token(&self.0, SyntaxKind::MACRO_NAME)
53 }
54
55 pub fn name(&self) -> SmolStr {
57 self.name_token()
58 .map(|token| SmolStr::new(token.text().trim_start_matches('\\')))
59 .unwrap_or_default()
60 }
61
62 pub fn arguments(&self) -> impl Iterator<Item = Argument> + use<> {
64 self.0.children().filter_map(Argument::cast)
65 }
66
67 pub fn option(&self) -> std::option::Option<Option> {
69 self.0.children().find_map(Option::cast)
70 }
71}
72
73impl Option {
74 pub fn text(&self) -> String {
76 self.0
77 .children_with_tokens()
78 .filter(|element| {
79 !matches!(element.kind(), SyntaxKind::LBRACKET | SyntaxKind::RBRACKET)
80 })
81 .map(|element| element.to_string())
82 .collect()
83 }
84}
85
86impl Conditional {
87 pub fn directive(&self) -> std::option::Option<SyntaxToken> {
89 token(&self.0, SyntaxKind::DIRECTIVE)
90 }
91
92 pub fn target(&self) -> std::option::Option<SyntaxToken> {
94 token(&self.0, SyntaxKind::TARGET)
95 }
96}