emmylua_parser/syntax/traits/
mod.rs

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