plotnik_lib/parser/
ast.rs1use super::cst::{SyntaxKind, SyntaxNode, SyntaxToken};
16use rowan::TextRange;
17
18pub fn token_src<'q>(token: &SyntaxToken, source: &'q str) -> &'q str {
22 let range = token.text_range();
23 &source[range.start().into()..range.end().into()]
24}
25
26macro_rules! ast_node {
27 ($name:ident, $kind:ident) => {
28 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
29 pub struct $name(SyntaxNode);
30
31 impl $name {
32 pub fn cast(node: SyntaxNode) -> Option<Self> {
33 Self::can_cast(node.kind()).then(|| Self(node))
34 }
35
36 pub fn can_cast(kind: SyntaxKind) -> bool {
37 kind == SyntaxKind::$kind
38 }
39
40 pub fn as_cst(&self) -> &SyntaxNode {
41 &self.0
42 }
43
44 pub fn text_range(&self) -> TextRange {
45 self.0.text_range()
46 }
47 }
48 };
49}
50
51macro_rules! define_expr {
52 ($($variant:ident),+ $(,)?) => {
53 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
55 pub enum Expr {
56 $($variant($variant)),+
57 }
58
59 impl Expr {
60 pub fn cast(node: SyntaxNode) -> Option<Self> {
61 let kind = node.kind();
62 $(if $variant::can_cast(kind) { return Some(Expr::$variant($variant(node))); })+
63 None
64 }
65
66 pub fn as_cst(&self) -> &SyntaxNode {
67 match self { $(Expr::$variant(n) => n.as_cst()),+ }
68 }
69
70 pub fn text_range(&self) -> TextRange {
71 match self { $(Expr::$variant(n) => n.text_range()),+ }
72 }
73 }
74 };
75}
76
77impl Expr {
78 pub fn children(&self) -> Vec<Expr> {
80 match self {
81 Expr::NamedNode(n) => n.children().collect(),
82 Expr::SeqExpr(s) => s.children().collect(),
83 Expr::CapturedExpr(c) => c.inner().into_iter().collect(),
84 Expr::QuantifiedExpr(q) => q.inner().into_iter().collect(),
85 Expr::FieldExpr(f) => f.value().into_iter().collect(),
86 Expr::AltExpr(a) => a.branches().filter_map(|b| b.body()).collect(),
87 Expr::Ref(_) | Expr::AnonymousNode(_) => vec![],
88 }
89 }
90}
91
92ast_node!(Root, Root);
93ast_node!(Def, Def);
94ast_node!(NamedNode, Tree);
95ast_node!(Ref, Ref);
96ast_node!(AltExpr, Alt);
97ast_node!(Branch, Branch);
98ast_node!(SeqExpr, Seq);
99ast_node!(CapturedExpr, Capture);
100ast_node!(Type, Type);
101ast_node!(QuantifiedExpr, Quantifier);
102ast_node!(FieldExpr, Field);
103ast_node!(NegatedField, NegatedField);
104ast_node!(Anchor, Anchor);
105
106#[derive(Debug, Clone, PartialEq, Eq, Hash)]
108pub enum SeqItem {
109 Expr(Expr),
110 Anchor(Anchor),
111}
112
113impl SeqItem {
114 pub fn cast(node: SyntaxNode) -> Option<Self> {
115 if let Some(expr) = Expr::cast(node.clone()) {
116 return Some(SeqItem::Expr(expr));
117 }
118 if let Some(anchor) = Anchor::cast(node) {
119 return Some(SeqItem::Anchor(anchor));
120 }
121 None
122 }
123
124 pub fn as_anchor(&self) -> Option<&Anchor> {
125 match self {
126 SeqItem::Anchor(a) => Some(a),
127 _ => None,
128 }
129 }
130
131 pub fn as_expr(&self) -> Option<&Expr> {
132 match self {
133 SeqItem::Expr(e) => Some(e),
134 _ => None,
135 }
136 }
137}
138
139#[derive(Debug, Clone, PartialEq, Eq, Hash)]
142pub struct AnonymousNode(SyntaxNode);
143
144impl AnonymousNode {
145 pub fn cast(node: SyntaxNode) -> Option<Self> {
146 Self::can_cast(node.kind()).then(|| Self(node))
147 }
148
149 pub fn can_cast(kind: SyntaxKind) -> bool {
150 matches!(kind, SyntaxKind::Str | SyntaxKind::Wildcard)
151 }
152
153 pub fn as_cst(&self) -> &SyntaxNode {
154 &self.0
155 }
156
157 pub fn text_range(&self) -> TextRange {
158 self.0.text_range()
159 }
160
161 pub fn value(&self) -> Option<SyntaxToken> {
163 if self.0.kind() == SyntaxKind::Wildcard {
164 return None;
165 }
166 self.0
167 .children_with_tokens()
168 .filter_map(|it| it.into_token())
169 .find(|t| t.kind() == SyntaxKind::StrVal)
170 }
171
172 pub fn is_any(&self) -> bool {
174 self.0.kind() == SyntaxKind::Wildcard
175 }
176}
177
178#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
180pub enum AltKind {
181 Tagged,
183 Untagged,
185 Mixed,
187}
188
189define_expr!(
190 NamedNode,
191 Ref,
192 AnonymousNode,
193 AltExpr,
194 SeqExpr,
195 CapturedExpr,
196 QuantifiedExpr,
197 FieldExpr,
198);
199
200impl Root {
201 pub fn defs(&self) -> impl Iterator<Item = Def> + '_ {
202 self.0.children().filter_map(Def::cast)
203 }
204
205 pub fn exprs(&self) -> impl Iterator<Item = Expr> + '_ {
206 self.0.children().filter_map(Expr::cast)
207 }
208}
209
210impl Def {
211 pub fn name(&self) -> Option<SyntaxToken> {
212 self.0
213 .children_with_tokens()
214 .filter_map(|it| it.into_token())
215 .find(|t| t.kind() == SyntaxKind::Id)
216 }
217
218 pub fn body(&self) -> Option<Expr> {
219 self.0.children().find_map(Expr::cast)
220 }
221}
222
223impl NamedNode {
224 pub fn node_type(&self) -> Option<SyntaxToken> {
225 self.0
226 .children_with_tokens()
227 .filter_map(|it| it.into_token())
228 .find(|t| {
229 matches!(
230 t.kind(),
231 SyntaxKind::Id
232 | SyntaxKind::Underscore
233 | SyntaxKind::KwError
234 | SyntaxKind::KwMissing
235 )
236 })
237 }
238
239 pub fn is_any(&self) -> bool {
241 self.node_type()
242 .map(|t| t.kind() == SyntaxKind::Underscore)
243 .unwrap_or(false)
244 }
245
246 pub fn is_missing(&self) -> bool {
248 self.node_type()
249 .map(|t| t.kind() == SyntaxKind::KwMissing)
250 .unwrap_or(false)
251 }
252
253 pub fn missing_constraint(&self) -> Option<SyntaxToken> {
259 if !self.is_missing() {
260 return None;
261 }
262 let mut found_missing = false;
264 for child in self.0.children_with_tokens() {
265 if let Some(token) = child.into_token() {
266 if token.kind() == SyntaxKind::KwMissing {
267 found_missing = true;
268 } else if found_missing
269 && matches!(token.kind(), SyntaxKind::Id | SyntaxKind::StrVal)
270 {
271 return Some(token);
272 }
273 }
274 }
275 None
276 }
277
278 pub fn children(&self) -> impl Iterator<Item = Expr> + '_ {
279 self.0.children().filter_map(Expr::cast)
280 }
281
282 pub fn anchors(&self) -> impl Iterator<Item = Anchor> + '_ {
284 self.0.children().filter_map(Anchor::cast)
285 }
286
287 pub fn items(&self) -> impl Iterator<Item = SeqItem> + '_ {
289 self.0.children().filter_map(SeqItem::cast)
290 }
291}
292
293impl Ref {
294 pub fn name(&self) -> Option<SyntaxToken> {
295 self.0
296 .children_with_tokens()
297 .filter_map(|it| it.into_token())
298 .find(|t| t.kind() == SyntaxKind::Id)
299 }
300}
301
302impl AltExpr {
303 pub fn kind(&self) -> AltKind {
304 let mut tagged = false;
305 let mut untagged = false;
306
307 for child in self.0.children().filter(|c| c.kind() == SyntaxKind::Branch) {
308 let has_label = child
309 .children_with_tokens()
310 .filter_map(|it| it.into_token())
311 .any(|t| t.kind() == SyntaxKind::Id);
312
313 if has_label {
314 tagged = true;
315 } else {
316 untagged = true;
317 }
318 }
319
320 match (tagged, untagged) {
321 (true, true) => AltKind::Mixed,
322 (true, false) => AltKind::Tagged,
323 _ => AltKind::Untagged,
324 }
325 }
326
327 pub fn branches(&self) -> impl Iterator<Item = Branch> + '_ {
328 self.0.children().filter_map(Branch::cast)
329 }
330
331 pub fn exprs(&self) -> impl Iterator<Item = Expr> + '_ {
332 self.0.children().filter_map(Expr::cast)
333 }
334}
335
336impl Branch {
337 pub fn label(&self) -> Option<SyntaxToken> {
338 self.0
339 .children_with_tokens()
340 .filter_map(|it| it.into_token())
341 .find(|t| t.kind() == SyntaxKind::Id)
342 }
343
344 pub fn body(&self) -> Option<Expr> {
345 self.0.children().find_map(Expr::cast)
346 }
347}
348
349impl SeqExpr {
350 pub fn children(&self) -> impl Iterator<Item = Expr> + '_ {
351 self.0.children().filter_map(Expr::cast)
352 }
353
354 pub fn anchors(&self) -> impl Iterator<Item = Anchor> + '_ {
356 self.0.children().filter_map(Anchor::cast)
357 }
358
359 pub fn items(&self) -> impl Iterator<Item = SeqItem> + '_ {
361 self.0.children().filter_map(SeqItem::cast)
362 }
363}
364
365impl CapturedExpr {
366 pub fn name(&self) -> Option<SyntaxToken> {
369 self.0
370 .children_with_tokens()
371 .filter_map(|it| it.into_token())
372 .find(|t| {
373 matches!(
374 t.kind(),
375 SyntaxKind::CaptureToken | SyntaxKind::SuppressiveCapture
376 )
377 })
378 }
379
380 pub fn is_suppressive(&self) -> bool {
383 self.0
384 .children_with_tokens()
385 .filter_map(|it| it.into_token())
386 .any(|t| t.kind() == SyntaxKind::SuppressiveCapture)
387 }
388
389 pub fn inner(&self) -> Option<Expr> {
390 self.0.children().find_map(Expr::cast)
391 }
392
393 pub fn type_annotation(&self) -> Option<Type> {
394 self.0.children().find_map(Type::cast)
395 }
396
397 pub fn has_string_annotation(&self) -> bool {
399 self.type_annotation()
400 .is_some_and(|t| t.name().is_some_and(|n| n.text() == "string"))
401 }
402}
403
404impl Type {
405 pub fn name(&self) -> Option<SyntaxToken> {
406 self.0
407 .children_with_tokens()
408 .filter_map(|it| it.into_token())
409 .find(|t| t.kind() == SyntaxKind::Id)
410 }
411}
412
413impl QuantifiedExpr {
414 pub fn inner(&self) -> Option<Expr> {
415 self.0.children().find_map(Expr::cast)
416 }
417
418 pub fn operator(&self) -> Option<SyntaxToken> {
419 self.0
420 .children_with_tokens()
421 .filter_map(|it| it.into_token())
422 .find(|t| {
423 matches!(
424 t.kind(),
425 SyntaxKind::Star
426 | SyntaxKind::Plus
427 | SyntaxKind::Question
428 | SyntaxKind::StarQuestion
429 | SyntaxKind::PlusQuestion
430 | SyntaxKind::QuestionQuestion
431 )
432 })
433 }
434
435 pub fn is_optional(&self) -> bool {
437 self.operator()
438 .map(|op| {
439 matches!(
440 op.kind(),
441 SyntaxKind::Question
442 | SyntaxKind::Star
443 | SyntaxKind::QuestionQuestion
444 | SyntaxKind::StarQuestion
445 )
446 })
447 .unwrap_or(false)
448 }
449}
450
451impl FieldExpr {
452 pub fn name(&self) -> Option<SyntaxToken> {
453 self.0
454 .children_with_tokens()
455 .filter_map(|it| it.into_token())
456 .find(|t| t.kind() == SyntaxKind::Id)
457 }
458
459 pub fn value(&self) -> Option<Expr> {
460 self.0.children().find_map(Expr::cast)
461 }
462}
463
464impl NegatedField {
465 pub fn name(&self) -> Option<SyntaxToken> {
466 self.0
467 .children_with_tokens()
468 .filter_map(|it| it.into_token())
469 .find(|t| t.kind() == SyntaxKind::Id)
470 }
471}
472
473pub fn is_truly_empty_scope(inner: &Expr) -> bool {
476 match inner {
477 Expr::SeqExpr(seq) => seq.children().next().is_none(),
478 Expr::AltExpr(alt) => alt.branches().next().is_none(),
479 Expr::QuantifiedExpr(q) => q.inner().is_some_and(|i| is_truly_empty_scope(&i)),
480 _ => false,
481 }
482}