lang_util/node/
content.rs

1use std::fmt;
2
3use crate::position::{LexerPosition, NodeSpan};
4
5/// Trait for AST node contents.
6///
7/// All nodes which will be stored in a [Node] need to implement this.
8pub trait NodeContent: fmt::Debug + Clone + PartialEq + Sized {
9    /// Convert the contents into a node
10    fn into_node<T>(self) -> Node<T>
11    where
12        T: From<Self> + NodeContent,
13    {
14        Node::new(self.into(), None)
15    }
16
17    /// Add span information to a syntax node
18    fn spanned(self, start: LexerPosition, end: LexerPosition) -> Node<Self> {
19        assert_eq!(start.source_id, end.source_id);
20
21        Node {
22            content: self,
23            span: Some(NodeSpan::from_lexer(start, end)),
24        }
25    }
26}
27
28/// A syntax node with span information
29#[derive(Debug, Clone)]
30#[cfg_attr(feature = "serde", derive(rserde::Serialize, rserde::Deserialize))]
31#[cfg_attr(feature = "serde", serde(crate = "rserde"))]
32pub struct Node<T: NodeContent> {
33    /// Contents of this syntax node
34    pub content: T,
35    /// Span in the input this node was parsed from
36    pub span: Option<NodeSpan>,
37}
38
39impl<T: NodeContent> Node<T> {
40    /// Create a new syntax node with span information
41    pub fn new(content: T, span: Option<NodeSpan>) -> Self {
42        Self { content, span }
43    }
44
45    /// Return the wrapped syntax node, discarding the span information
46    pub fn into_inner(self) -> T {
47        self.content
48    }
49
50    /// Map this content of this node into a new node
51    pub fn map<U: NodeContent>(self, f: impl FnOnce(T) -> U) -> Node<U> {
52        Node {
53            content: f(self.content),
54            span: self.span,
55        }
56    }
57
58    /// Map this content of this node into a new node with the same span
59    pub fn map_spanned<U: NodeContent>(self, f: impl FnOnce(Self) -> U) -> Node<U> {
60        let span = self.span;
61
62        Node {
63            content: f(self),
64            span,
65        }
66    }
67}
68
69impl<T: NodeContent> std::ops::Deref for Node<T> {
70    type Target = T;
71
72    fn deref(&self) -> &Self::Target {
73        &self.content
74    }
75}
76
77impl<T: NodeContent> std::ops::DerefMut for Node<T> {
78    fn deref_mut(&mut self) -> &mut Self::Target {
79        &mut self.content
80    }
81}
82
83// Trivial copy for the node if the wrapped content are Copy
84impl<T: NodeContent + Copy> Copy for Node<T> {}
85
86// Display implementation for wrapped node
87impl<T: NodeContent + fmt::Display> fmt::Display for Node<T> {
88    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
89        <T as fmt::Display>::fmt(&self.content, f)
90    }
91}
92
93impl<T: NodeContent> From<T> for Node<T> {
94    fn from(inner: T) -> Self {
95        Node::new(inner, None)
96    }
97}
98
99impl NodeContent for &'static str {}
100
101impl<U, T: NodeContent + AsRef<U>> AsRef<U> for Node<T> {
102    fn as_ref(&self) -> &U {
103        self.content.as_ref()
104    }
105}
106
107impl<T: NodeContent + PartialEq> PartialEq for Node<T> {
108    fn eq(&self, other: &Self) -> bool {
109        self.content.eq(&other.content)
110    }
111}
112
113impl<T: NodeContent + Eq> Eq for Node<T> {}
114
115impl<T: NodeContent + PartialOrd> PartialOrd for Node<T> {
116    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
117        self.content.partial_cmp(&other.content)
118    }
119}
120
121impl<T: NodeContent + Ord> Ord for Node<T> {
122    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
123        self.content.cmp(&other.content)
124    }
125}
126
127impl<T: NodeContent + std::hash::Hash> std::hash::Hash for Node<T> {
128    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
129        self.content.hash(state)
130    }
131}