syntree/macros.rs
1/// Helper macro for building a tree in place.
2///
3/// # Examples
4///
5/// ```
6/// #[derive(Debug, Clone, Copy, PartialEq, Eq)]
7/// enum Syntax {
8/// Root,
9/// Number,
10/// Lit,
11/// Whitespace,
12/// }
13///
14/// let mut tree = syntree::Builder::new();
15///
16/// tree.open(Syntax::Root)?;
17///
18/// tree.open(Syntax::Number)?;
19/// tree.token(Syntax::Lit, 1)?;
20/// tree.close()?;
21///
22/// tree.token(Syntax::Whitespace, 3)?;
23///
24/// tree.open(Syntax::Number)?;
25/// tree.token(Syntax::Lit, 2)?;
26/// tree.token_empty(Syntax::Lit)?;
27/// tree.close()?;
28///
29/// tree.close()?;
30///
31/// let tree = tree.build()?;
32///
33/// let expected = syntree::tree! {
34/// Syntax::Root => {
35/// Syntax::Number => {
36/// (Syntax::Lit, 1)
37/// },
38/// (Syntax::Whitespace, 3),
39/// Syntax::Number => {
40/// (Syntax::Lit, 2),
41/// Syntax::Lit
42/// }
43/// }
44/// };
45///
46/// assert_eq!(expected, tree);
47/// # Ok::<_, Box<dyn core::error::Error>>(())
48/// ```
49#[macro_export]
50macro_rules! tree {
51 (@o $b:ident,) => {};
52
53 (@o $b:ident, ($expr:expr, ($start:expr, $end:expr)) $(,)?) => {{
54 $b.token_with($expr, $crate::Span::new($start, $end))?;
55 }};
56
57 (@o $b:ident, ($expr:expr, $len:expr) $(,)?) => {{
58 $b.token($expr, $len)?;
59 }};
60
61 (@o $b:ident, ($expr:expr, ($start:expr, $end:expr)), $($rest:tt)*) => {{
62 $b.token_with($expr, $crate::Span::new($start, $end))?;
63 $crate::tree!(@o $b, $($rest)*);
64 }};
65
66 (@o $b:ident, ($expr:expr, $len:expr), $($rest:tt)*) => {{
67 $b.token($expr, $len)?;
68 $crate::tree!(@o $b, $($rest)*);
69 }};
70
71 (@o $b:ident, $expr:expr $(,)?) => {{
72 $b.token_empty($expr)?;
73 }};
74
75 (@o $b:ident, $expr:expr, $($rest:tt)*) => {{
76 $b.token_empty($expr)?;
77 $crate::tree!(@o $b, $($rest)*);
78 }};
79
80 (@o $b:ident, ($expr:expr, ($start:expr, $end:expr)) => { $($tt:tt)* } $(,)?) => {{
81 $b.open_with($expr, $crate::Span::new($start, $end))?;
82 $crate::tree!(@o $b, $($tt)*);
83 $b.close()?;
84 }};
85
86 (@o $b:ident, $expr:expr => { $($tt:tt)* } $(,)?) => {{
87 $b.open($expr)?;
88 $crate::tree!(@o $b, $($tt)*);
89 $b.close()?;
90 }};
91
92 (@o $b:ident, ($expr:expr, ($start:expr, $end:expr)) => { $($tt:tt)* }, $($rest:tt)*) => {{
93 $b.open_with($expr, $crate::Span::new($start, $end))?;
94 $crate::tree!(@o $b, $($tt)*);
95 $b.close()?;
96 $crate::tree!(@o $b, $($rest)*);
97 }};
98
99 (@o $b:ident, $expr:expr => { $($tt:tt)* }, $($rest:tt)*) => {{
100 $b.open($expr)?;
101 $crate::tree!(@o $b, $($tt)*);
102 $b.close()?;
103 $crate::tree!(@o $b, $($rest)*);
104 }};
105
106 ($($tt:tt)*) => {{
107 let mut b = $crate::Builder::new();
108 $crate::tree!(@o b, $($tt)*);
109 b.build()?
110 }};
111}
112
113/// Helper macro for building a tree in place with a custom span.
114///
115/// # Examples
116///
117/// ```
118/// use syntree::{Empty, EmptyVec, Tree, TreeIndex};
119///
120/// syntree::flavor! {
121/// struct FlavorEmpty {
122/// type Index = Empty;
123/// type Indexes = EmptyVec<TreeIndex<Self>>;
124/// }
125/// };
126///
127/// let tree: Tree<_, FlavorEmpty> = syntree::tree_with! {
128/// "root" => {
129/// "child" => {
130/// "token"
131/// },
132/// "child2"
133/// }
134/// };
135///
136/// let expected: Tree<_, FlavorEmpty> = syntree::tree_with! {
137/// "root" => {
138/// "child" => {
139/// ("token", Empty)
140/// },
141/// "child2"
142/// }
143/// };
144///
145/// assert_eq!(tree, expected);
146/// # Ok::<_, Box<dyn core::error::Error>>(())
147/// ```
148#[macro_export]
149macro_rules! tree_with {
150 ($($tt:tt)*) => {{
151 let mut b = $crate::Builder::new_with();
152 $crate::tree!(@o b, $($tt)*);
153 b.build()?
154 }};
155}