emmylua_parser/syntax/
traits.rs1use 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#[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}