Skip to main content

syntree/
macros.rs

1/// Helper macro for building a tree in place.
2///
3/// The tree is built with [`Builder::new`], so it uses the default flavor. Use
4/// [`tree_with!`] to build a tree of another flavor.
5///
6/// Each element is one of:
7/// * `value` a token with an empty span, see [`Builder::token_empty`].
8/// * `(value, len)` a token of length `len`, see [`Builder::token`].
9/// * `(value, (start, end))` a token with an explicit span, see
10///   [`Builder::token_with`].
11/// * `value => { .. }` a node whose span covers its children, see
12///   [`Builder::open`].
13/// * `(value, (start, end)) => { .. }` a node with an explicit span, see
14///   [`Builder::open_with`].
15///
16/// Elements are separated by commas. The macro expands to builder calls
17/// followed by `?`, so it can only be used in a function (or doctest) returning
18/// a `Result` whose error type implements `From<Error<F::Error>>`, where `F` is
19/// the flavor of the tree.
20///
21/// [`Builder::new`]: crate::Builder::new
22/// [`Builder::token_empty`]: crate::Builder::token_empty
23/// [`Builder::token`]: crate::Builder::token
24/// [`Builder::token_with`]: crate::Builder::token_with
25/// [`Builder::open`]: crate::Builder::open
26/// [`Builder::open_with`]: crate::Builder::open_with
27/// [`tree_with!`]: crate::tree_with
28///
29/// # Examples
30///
31/// ```
32/// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
33/// enum Syntax {
34///     Root,
35///     Number,
36///     Lit,
37///     Whitespace,
38/// }
39///
40/// let mut tree = syntree::Builder::new();
41///
42/// tree.open(Syntax::Root)?;
43///
44/// tree.open(Syntax::Number)?;
45/// tree.token(Syntax::Lit, 1)?;
46/// tree.close()?;
47///
48/// tree.token(Syntax::Whitespace, 3)?;
49///
50/// tree.open(Syntax::Number)?;
51/// tree.token(Syntax::Lit, 2)?;
52/// tree.token_empty(Syntax::Lit)?;
53/// tree.close()?;
54///
55/// tree.close()?;
56///
57/// let tree = tree.build()?;
58///
59/// let expected = syntree::tree! {
60///     Syntax::Root => {
61///         Syntax::Number => {
62///             (Syntax::Lit, 1)
63///         },
64///         (Syntax::Whitespace, 3),
65///         Syntax::Number => {
66///             (Syntax::Lit, 2),
67///             Syntax::Lit
68///         }
69///     }
70/// };
71///
72/// assert_eq!(expected, tree);
73/// # Ok::<_,  Box<dyn core::error::Error>>(())
74/// ```
75///
76/// Explicit spans:
77///
78/// ```
79/// use syntree::Span;
80///
81/// let tree = syntree::tree! {
82///     ("root", (0, 10)) => {
83///         ("token", (2, 5)),
84///     }
85/// };
86///
87/// let root = tree.first().ok_or("missing root")?;
88/// assert_eq!(root.span(), Span::new(0, 10));
89///
90/// let token = root.first().ok_or("missing token")?;
91/// assert_eq!(token.span(), Span::new(2, 5));
92/// # Ok::<_,  Box<dyn core::error::Error>>(())
93/// ```
94#[macro_export]
95macro_rules! tree {
96    (@o $b:ident,) => {};
97
98    (@o $b:ident, ($expr:expr, ($start:expr, $end:expr)) $(,)?) => {{
99        $b.token_with($expr, $crate::Span::new($start, $end))?;
100    }};
101
102    (@o $b:ident, ($expr:expr, $len:expr) $(,)?) => {{
103        $b.token($expr, $len)?;
104    }};
105
106    (@o $b:ident, ($expr:expr, ($start:expr, $end:expr)), $($rest:tt)*) => {{
107        $b.token_with($expr, $crate::Span::new($start, $end))?;
108        $crate::tree!(@o $b, $($rest)*);
109    }};
110
111    (@o $b:ident, ($expr:expr, $len:expr), $($rest:tt)*) => {{
112        $b.token($expr, $len)?;
113        $crate::tree!(@o $b, $($rest)*);
114    }};
115
116    (@o $b:ident, $expr:expr $(,)?) => {{
117        $b.token_empty($expr)?;
118    }};
119
120    (@o $b:ident, $expr:expr, $($rest:tt)*) => {{
121        $b.token_empty($expr)?;
122        $crate::tree!(@o $b, $($rest)*);
123    }};
124
125    (@o $b:ident, ($expr:expr, ($start:expr, $end:expr)) => { $($tt:tt)* } $(,)?) => {{
126        $b.open_with($expr, $crate::Span::new($start, $end))?;
127        $crate::tree!(@o $b, $($tt)*);
128        $b.close()?;
129    }};
130
131    (@o $b:ident, $expr:expr => { $($tt:tt)* } $(,)?) => {{
132        $b.open($expr)?;
133        $crate::tree!(@o $b, $($tt)*);
134        $b.close()?;
135    }};
136
137    (@o $b:ident, ($expr:expr, ($start:expr, $end:expr)) => { $($tt:tt)* }, $($rest:tt)*) => {{
138        $b.open_with($expr, $crate::Span::new($start, $end))?;
139        $crate::tree!(@o $b, $($tt)*);
140        $b.close()?;
141        $crate::tree!(@o $b, $($rest)*);
142    }};
143
144    (@o $b:ident, $expr:expr => { $($tt:tt)* }, $($rest:tt)*) => {{
145        $b.open($expr)?;
146        $crate::tree!(@o $b, $($tt)*);
147        $b.close()?;
148        $crate::tree!(@o $b, $($rest)*);
149    }};
150
151    ($($tt:tt)*) => {{
152        let mut b = $crate::Builder::new();
153        $crate::tree!(@o b, $($tt)*);
154        b.build()?
155    }};
156}
157
158/// Helper macro for building a tree in place with a custom flavor.
159///
160/// This takes the same input as [`tree!`], but builds the tree with
161/// [`Builder::new_with`]. The flavor is inferred from the type the result is
162/// used as, so it usually needs a type annotation such as
163/// `let tree: Tree<_, MyFlavor> = ..`.
164///
165/// Like [`tree!`], it expands to builder calls followed by `?`, so it can only
166/// be used in a function returning a `Result` whose error type implements
167/// `From<Error<F::Error>>`, where `F` is the flavor of the tree.
168///
169/// [`tree!`]: crate::tree
170/// [`Builder::new_with`]: crate::Builder::new_with
171///
172/// # Examples
173///
174/// ```
175/// use syntree::{Empty, EmptyVec, Tree, TreeIndex};
176///
177/// syntree::flavor! {
178///     struct FlavorEmpty {
179///         type Index = Empty;
180///         type Indexes = EmptyVec<TreeIndex<Self>>;
181///     }
182/// };
183///
184/// let tree: Tree<_, FlavorEmpty> = syntree::tree_with! {
185///     "root" => {
186///         "child" => {
187///             "token"
188///         },
189///         "child2"
190///     }
191/// };
192///
193/// let expected: Tree<_, FlavorEmpty> = syntree::tree_with! {
194///     "root" => {
195///         "child" => {
196///             ("token", Empty)
197///         },
198///         "child2"
199///     }
200/// };
201///
202/// assert_eq!(tree, expected);
203/// # Ok::<_,  Box<dyn core::error::Error>>(())
204/// ```
205#[macro_export]
206macro_rules! tree_with {
207    ($($tt:tt)*) => {{
208        let mut b = $crate::Builder::new_with();
209        $crate::tree!(@o b, $($tt)*);
210        b.build()?
211    }};
212}