Skip to main content

brink_syntax_native/ast/
mod.rs

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