pegmd/ast/
macros.rs

1/// Sometimes, we need to extract the singleton child from a [`pest::iterator::Pair`] and fail if it's
2/// missing. This is normally to make the rule processing less verbose. For example, we can match on
3/// the `link` rule, then extract the specific link variant for processing, and since we know that
4/// there must be a link variant as the only child of the node, we can raise an error if it's missing.
5///
6/// # Parameters
7///
8/// - `$value`: A [`pest::iterator::Pair`]. This value is consumed in the macro.
9///
10/// # Returns
11///
12/// A Result<pest::iterator::Pair, ParseError>. Will be the Err variant only if the value was missing.
13#[macro_export]
14macro_rules! first_child {
15    ($value: expr) => {
16        $value.next().ok_or(ParseError::SyntaxError(format!(
17            "Missing required child in expression"
18        )))
19    };
20}
21
22/// Creates a struct to represent a container node, along with some trait implementations.
23/// Always requires an identifier for the name of the generated struct, and optionally accepts
24/// one more more tuples of (identifier, type) to add additional fields to the struct.
25///
26/// This macro will always define the [`AsRef<Vec<Node<'input>>>`] trait for the generated struct,
27/// but will only create an implementation for [`TryFrom<Pair<'input, Rule>>`] if no extra fields
28/// are specified since there's no general way to parse those fields from the Pair.
29///
30/// If extra fields are provided, the macro will create a non-mutating getter method for each field.
31#[macro_export]
32macro_rules! container_type {
33    ($name:ident) => {
34        #[derive(std::fmt::Debug, PartialEq)]
35        #[cfg_attr(feature = "serde_support", derive(serde::Serialize, serde::Deserialize))]
36        pub struct $name<'input> {
37            children: Children<'input>,
38            #[cfg_attr(feature = "serde_support", serde(skip_serializing))]
39            span: &'input str,
40        }
41
42        impl <'input> TryFrom<Pair<'input, Rule>> for $name<'input> {
43            type Error = ParseError;
44
45            fn try_from(value: Pair<'input, Rule>) -> Result<Self, Self::Error> {
46                let span = value.as_str();
47                let children = Children::try_from(value)?;
48                Ok (Self { span, children })
49            }
50        }
51
52        impl <'input> $name<'input> {
53            #[allow(dead_code)]
54            pub fn new(children: Children<'input>, span: &'input str) -> Self {
55                Self {
56                    children,
57                    span,
58                }
59            }
60
61            pub fn children(&self) -> &Children {
62                &self.children
63            }
64
65            pub fn children_mut(&'input mut self) -> &mut Children {
66                &mut self.children
67            }
68
69            pub fn as_span(&self) -> &str {
70                self.span
71            }
72        }
73    };
74
75    ($name: ident $(, ($field_name: ident, $ty: ty))+) => {
76        #[derive(std::fmt::Debug, PartialEq)]
77        #[cfg_attr(feature = "serde_support", derive(serde::Serialize, serde::Deserialize))]
78        pub struct $name<'input> {
79            children: Children<'input>,
80            #[cfg_attr(feature = "serde_support", serde(skip_serializing))]
81            span: &'input str,
82            $($field_name: $ty,)+
83        }
84
85        impl <'input> $name<'input> {
86
87            #[allow(dead_code)]
88            pub fn new(
89                children: Children<'input>,
90                span: &'input str
91                $(, $field_name: $ty)+
92            ) -> Self {
93                Self {
94                    children,
95                    span,
96                    $($field_name,)+
97                }
98            }
99
100            pub fn as_span(&self) -> &str {
101                self.span
102            }
103
104            pub fn children(&self) -> &Children {
105                &self.children
106            }
107
108            pub fn children_mut(&'input mut self) -> &mut Children {
109                &mut self.children
110            }
111
112            $(pub fn $field_name(&self) -> $ty {
113                self.$field_name
114            })+
115        }
116    };
117}
118
119/// Creates a struct to represent a leaf node, along with some trait implementations.
120/// Always requires an identifier for the name of the generated struct, and optionally accepts
121/// one more more tuples of (identifier, type) to add additional fields to the struct.
122///
123/// This macro will always define the [`AsRef<str>`] trait for the generated struct,
124/// but will only create an implementation for [`TryFrom<Pair<'input, Rule>>`] if no extra fields
125/// are specified since there's no general way to parse those fields from the Pair.
126///
127/// If extra fields are provided, the macro will create a non-mutating getter method for each field.
128#[macro_export]
129macro_rules! leaf_type {
130    ($name: ident) => {
131
132        #[derive(std::fmt::Debug, PartialEq)]
133        #[cfg_attr(feature = "serde_support", derive(serde::Serialize, serde::Deserialize))]
134        pub struct $name<'input> {
135            literal: &'input str,
136        }
137
138        impl <'input> From<Pair<'input, Rule>> for $name<'input> {
139            fn from(value: Pair<'input, Rule>) -> Self {
140                Self { literal: value.as_str() }
141            }
142        }
143
144        impl <'input> AsRef<str> for $name<'input> {
145            fn as_ref(&self) -> &str {
146                &self.literal
147            }
148        }
149
150        impl <'input> $name<'input> {
151            pub fn as_span(&self) -> &'input str {
152                &self.literal
153            }
154        }
155    };
156
157    ($name: ident $(, ($field_name: ident, $ty: ty))+) => {
158
159        #[derive(std::fmt::Debug, PartialEq)]
160        #[cfg_attr(feature = "serde_support", derive(serde::Serialize, serde::Deserialize))]
161        pub struct $name<'input> {
162            literal: &'input str,
163            $($field_name: $ty,)+
164        }
165
166        impl <'input> AsRef<str> for $name<'input> {
167            fn as_ref(&self) -> &str {
168                &self.literal
169            }
170        }
171
172        impl <'input> $name<'input> {
173            pub fn as_span(&self) -> &'input str {
174                &self.literal
175            }
176
177            $(
178                pub fn $field_name(&self) -> $ty {
179                    self.$field_name
180                }
181            )+
182        }
183    };
184}