rnix/
ast.rs

1//! Provides a type system for the AST, in some sense
2
3mod expr_ext;
4mod interpol;
5mod nodes;
6mod operators;
7mod path_util;
8mod str_util;
9mod tokens;
10
11use crate::{NixLanguage, SyntaxKind, SyntaxToken};
12
13pub use expr_ext::LiteralKind;
14pub use interpol::*;
15pub use nodes::*;
16pub use operators::{BinOpKind, UnaryOpKind};
17pub use tokens::*;
18
19pub trait AstNode: rowan::ast::AstNode<Language = NixLanguage> {}
20
21impl<T> AstNode for T where T: rowan::ast::AstNode<Language = NixLanguage> {}
22
23pub trait AstToken {
24    fn can_cast(from: SyntaxKind) -> bool
25    where
26        Self: Sized;
27
28    /// Cast an untyped token into this strongly-typed token. This will return
29    /// None if the type was not correct.
30    fn cast(from: SyntaxToken) -> Option<Self>
31    where
32        Self: Sized;
33
34    fn syntax(&self) -> &SyntaxToken;
35}
36
37mod support {
38    use rowan::ast::AstChildren;
39
40    use super::{AstNode, AstToken};
41    use crate::{SyntaxElement, SyntaxKind, SyntaxToken};
42
43    pub(super) fn nth<N: AstNode, NN: AstNode>(parent: &N, n: usize) -> Option<NN> {
44        parent.syntax().children().flat_map(NN::cast).nth(n)
45    }
46
47    pub(super) fn children<N: AstNode, NN: AstNode>(parent: &N) -> AstChildren<NN> {
48        rowan::ast::support::children(parent.syntax())
49    }
50
51    pub(super) fn token<N: AstNode, T: AstToken>(parent: &N) -> Option<T> {
52        children_tokens(parent).nth(0)
53    }
54
55    /// Token untyped
56    pub(super) fn token_u<N: AstNode>(parent: &N, kind: SyntaxKind) -> Option<SyntaxToken> {
57        children_tokens_u(parent).find(|it| it.kind() == kind)
58    }
59
60    pub(super) fn children_tokens<N: AstNode, T: AstToken>(parent: &N) -> impl Iterator<Item = T> {
61        parent
62            .syntax()
63            .children_with_tokens()
64            .filter_map(SyntaxElement::into_token)
65            .filter_map(T::cast)
66    }
67
68    pub(super) fn children_tokens_u<N: AstNode>(parent: &N) -> impl Iterator<Item = SyntaxToken> {
69        parent.syntax().children_with_tokens().filter_map(SyntaxElement::into_token)
70    }
71}