Skip to main content

brink_syntax/ast/
mod.rs

1//! Typed AST wrappers for the ink CST.
2//!
3//! Every struct is a zero-cost newtype around [`SyntaxNode`] that implements
4//! [`AstNode`]. Use [`crate::Parse::tree()`] to get a [`SourceFile`] from
5//! a parse result.
6
7mod nodes;
8mod ptr;
9mod support;
10
11pub use nodes::*;
12pub use ptr::{AstPtr, SyntaxNodePtr};
13
14use crate::SyntaxNode;
15
16/// A typed wrapper around a [`SyntaxNode`].
17///
18/// Implementations are generated by the [`ast_node!`] macro.
19pub trait AstNode: Sized {
20    /// Returns `true` if a node with the given kind can be cast to `Self`.
21    fn can_cast(kind: crate::SyntaxKind) -> bool;
22
23    /// Try to cast a generic `SyntaxNode` into this typed wrapper.
24    fn cast(node: SyntaxNode) -> Option<Self>;
25
26    /// Access the underlying `SyntaxNode`.
27    fn syntax(&self) -> &SyntaxNode;
28}
29
30/// Generates a zero-cost newtype struct implementing [`AstNode`].
31///
32/// ```text
33/// ast_node!(SourceFile, SOURCE_FILE);
34/// ```
35///
36/// expands to a struct wrapping `SyntaxNode` with `AstNode`, `Debug`,
37/// `Clone`, `PartialEq`, `Eq`, and `Hash` implementations.
38macro_rules! ast_node {
39    ($name:ident, $kind:ident) => {
40        #[derive(Clone, PartialEq, Eq, Hash)]
41        pub struct $name {
42            syntax: $crate::SyntaxNode,
43        }
44
45        impl std::fmt::Debug for $name {
46            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
47                std::fmt::Debug::fmt(&self.syntax, f)
48            }
49        }
50
51        impl std::fmt::Display for $name {
52            fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
53                std::fmt::Display::fmt(&self.syntax.text(), f)
54            }
55        }
56
57        impl $crate::ast::AstNode for $name {
58            fn can_cast(kind: $crate::SyntaxKind) -> bool {
59                kind == $crate::SyntaxKind::$kind
60            }
61
62            fn cast(node: $crate::SyntaxNode) -> Option<Self> {
63                if Self::can_cast(node.kind()) {
64                    Some(Self { syntax: node })
65                } else {
66                    None
67                }
68            }
69
70            fn syntax(&self) -> &$crate::SyntaxNode {
71                &self.syntax
72            }
73        }
74    };
75}
76
77pub(crate) use ast_node;
78
79#[cfg(test)]
80mod tests;