emmylua_parser/syntax/
traits.rs

1use std::marker::PhantomData;
2
3use rowan::{TextRange, TextSize, WalkEvent};
4
5use crate::kind::{LuaSyntaxKind, LuaTokenKind};
6
7use super::LuaSyntaxId;
8pub use super::{
9    node::*, LuaSyntaxElementChildren, LuaSyntaxNode, LuaSyntaxNodeChildren, LuaSyntaxToken,
10};
11
12pub trait LuaAstNode {
13    fn syntax(&self) -> &LuaSyntaxNode;
14
15    fn can_cast(kind: LuaSyntaxKind) -> bool
16    where
17        Self: Sized;
18
19    fn cast(syntax: LuaSyntaxNode) -> Option<Self>
20    where
21        Self: Sized;
22
23    fn child<N: LuaAstNode>(&self) -> Option<N> {
24        self.syntax().children().find_map(N::cast)
25    }
26
27    fn token<N: LuaAstToken>(&self) -> Option<N> {
28        self.syntax()
29            .children_with_tokens()
30            .find_map(|it| it.into_token().and_then(N::cast))
31    }
32
33    fn token_by_kind(&self, kind: LuaTokenKind) -> Option<LuaGeneralToken> {
34        let token = self
35            .syntax()
36            .children_with_tokens()
37            .filter_map(|it| it.into_token())
38            .find(|it| it.kind() == kind.into())?;
39
40        LuaGeneralToken::cast(token)
41    }
42
43    fn tokens<N: LuaAstToken>(&self) -> LuaAstTokenChildren<N> {
44        LuaAstTokenChildren::new(self.syntax())
45    }
46
47    fn children<N: LuaAstNode>(&self) -> LuaAstChildren<N> {
48        LuaAstChildren::new(self.syntax())
49    }
50
51    fn descendants<N: LuaAstNode>(&self) -> impl Iterator<Item = N> {
52        self.syntax().descendants().filter_map(N::cast)
53    }
54
55    fn walk_descendants<N: LuaAstNode>(&self) -> impl Iterator<Item = WalkEvent<N>> {
56        self.syntax().preorder().filter_map(|event| match event {
57            WalkEvent::Enter(node) => N::cast(node).map(WalkEvent::Enter),
58            WalkEvent::Leave(node) => N::cast(node).map(WalkEvent::Leave),
59        })
60    }
61
62    fn ancestors<N: LuaAstNode>(&self) -> impl Iterator<Item = N> {
63        self.syntax().ancestors().filter_map(N::cast)
64    }
65
66    fn get_root(&self) -> LuaSyntaxNode {
67        let syntax = self.syntax();
68        if syntax.kind() == LuaSyntaxKind::Chunk.into() {
69            syntax.clone()
70        } else {
71            syntax.ancestors().last().unwrap()
72        }
73    }
74
75    fn get_parent<N: LuaAstNode>(&self) -> Option<N> {
76        self.syntax().parent().and_then(N::cast)
77    }
78
79    fn get_position(&self) -> TextSize {
80        let range = self.syntax().text_range();
81        range.start()
82    }
83
84    fn get_range(&self) -> TextRange {
85        self.syntax().text_range()
86    }
87
88    fn get_syntax_id(&self) -> LuaSyntaxId {
89        LuaSyntaxId::from_node(self.syntax())
90    }
91
92    fn dump(&self) -> String {
93        format!("{:#?}", self.syntax())
94    }
95}
96
97/// An iterator over `SyntaxNode` children of a particular AST type.
98#[derive(Debug, Clone)]
99pub struct LuaAstChildren<N> {
100    inner: LuaSyntaxNodeChildren,
101    ph: PhantomData<N>,
102}
103
104impl<N> LuaAstChildren<N> {
105    pub fn new(parent: &LuaSyntaxNode) -> LuaAstChildren<N> {
106        LuaAstChildren {
107            inner: parent.children(),
108            ph: PhantomData,
109        }
110    }
111}
112
113impl<N: LuaAstNode> Iterator for LuaAstChildren<N> {
114    type Item = N;
115
116    fn next(&mut self) -> Option<N> {
117        self.inner.find_map(N::cast)
118    }
119}
120
121pub trait LuaAstToken {
122    fn syntax(&self) -> &LuaSyntaxToken;
123
124    fn can_cast(kind: LuaTokenKind) -> bool
125    where
126        Self: Sized;
127
128    fn cast(syntax: LuaSyntaxToken) -> Option<Self>
129    where
130        Self: Sized;
131
132    fn get_token_kind(&self) -> LuaTokenKind {
133        self.syntax().kind().into()
134    }
135
136    fn get_position(&self) -> TextSize {
137        let range = self.syntax().text_range();
138        range.start()
139    }
140
141    fn get_range(&self) -> TextRange {
142        self.syntax().text_range()
143    }
144
145    fn get_syntax_id(&self) -> LuaSyntaxId {
146        LuaSyntaxId::from_token(self.syntax())
147    }
148
149    fn get_text(&self) -> &str {
150        self.syntax().text()
151    }
152
153    fn get_parent<N: LuaAstNode>(&self) -> Option<N> {
154        self.syntax().parent().and_then(N::cast)
155    }
156
157    fn ancestors<N: LuaAstNode>(&self) -> impl Iterator<Item = N> {
158        self.syntax().parent_ancestors().filter_map(N::cast)
159    }
160
161    fn dump(&self) -> String {
162        format!("{:#?}", self.syntax())
163    }
164}
165
166#[derive(Debug, Clone)]
167pub struct LuaAstTokenChildren<N> {
168    inner: LuaSyntaxElementChildren,
169    ph: PhantomData<N>,
170}
171
172impl<N> LuaAstTokenChildren<N> {
173    pub fn new(parent: &LuaSyntaxNode) -> LuaAstTokenChildren<N> {
174        LuaAstTokenChildren {
175            inner: parent.children_with_tokens(),
176            ph: PhantomData,
177        }
178    }
179}
180
181impl<N: LuaAstToken> Iterator for LuaAstTokenChildren<N> {
182    type Item = N;
183
184    fn next(&mut self) -> Option<N> {
185        self.inner.find_map(|it| it.into_token().and_then(N::cast))
186    }
187}