1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
/// A macro used for defining the way a `struct` should be consumed.
/// It will implement [`Consumable`][crate::Consumable] for this `struct`.
///
/// # Examples
///
/// ```
/// use manger::consume_struct;
///
/// #[derive(PartialEq, Debug)]
/// struct Sum(i32);
/// consume_struct! (
/// Sum => [
/// // Now a list of sequential instruction
/// //
/// // Note: We have a comma after every instruction, but we end
/// // with a semicolon.
///
/// // Saving data looks as such `KEY: TYPE`
/// //
/// // Note: Optionally, we can suffix a type with `{ Fn(data) -> bool }` to add
/// // an extra condition for consuming. Therefore, if we could have suffixed
/// // `{ |data| data >= 5 }`, we would require the `num_of_bananas` to be at
/// // least 5.
/// left_hand: i32,
///
/// // Consuming arbitrary data from a certain type looks like `: TYPE`
/// //
/// // Here we use the build in Whitespace type of consume anytype
/// // whitespace character.
/// //
/// // Note: Optionally, we can suffix a type with `{ Fn(data) -> bool }` to add
/// // an extra condition for consuming. Therefore, if we would have wrote
/// // `: char { |c| c.is_whitespace() }`, it would create the `Whitespace` type.
/// : Vec<manger::common::Whitespace>,
///
/// // Consuming expression looks like `> EXPRESSION`
/// > "+",
///
/// // Consuming arbitrary data from a certain type looks like `: TYPE`
/// //
/// // Here we use the build in Whitespace type of consume anytype
/// // whitespace character.
/// //
/// // Note: Optionally, we can suffix a type with `{ Fn(data) -> bool }` to add
/// // an extra condition for consuming. Therefore, if we would have wrote
/// // `: char { |c| c.is_whitespace() }`, it would create the `Whitespace` type.
/// : Vec<manger::common::Whitespace>,
///
/// right_hand: i32;
///
/// // Now we can use all our saved data to define what to do
/// // with that data.
/// //
/// // Since `Sum` takes a (i32) we have to fill such a data structure.
/// (left_hand + right_hand)
/// ]
/// );
///
/// // Now we can consume `Sum` as normal.
/// use manger::Consumable;
///
/// let source = "5 + -10";
/// let (sum, _) = Sum::consume_from(source)?;
///
/// assert_eq!(sum, Sum(-5));
/// # Ok::<(), manger::ConsumeError>(())
/// ```
///
/// # Syntax
///
/// The syntax for the macro is not very complicated. Much of the intuition on the Rust primitive
/// and _std_ types can we reapplied and only a few new concepts have to be applied.
///
/// The ENBF syntax is as follows:
/// > Please note that the syntax ignores interproduction rule.
/// ```enbf
/// syntax = struct_name, "=>", "[",
/// {(instruction, ",")}*,
/// instruction, ";",
/// [ "(", RUST_EXPR*, ")" ], # RUST_EXPR is an arbitrary rust expression it can use all
/// # the RUST_IDENT defined in the previous section.
/// "]";
///
/// instruction = expr_instruction | type_instruction;
///
/// expr_instruction = ">", RUST_EXPR; # RUST_EXPR is an arbitrary rust expression. It should
/// # return a instance of a type that has the `Consumable`
/// # trait.
///
/// type_instruction = [ RUST_IDENT ], ":", RUST_TYPE; # RUST_IDENT is an arbitrary rust identity
/// # an it will assigned to that property if no
/// # tuple syntax is defined.
/// # RUST_TYPE is an arbitrary rust type that
/// # implements `Consumable`.
/// ```
///
/// # Note
///
/// 1. Although this macro works without importing any __manger__ traits, they will also not be
/// imported afterwards. Importing traits should still be done if methods of the trait
/// are supposed to be used afterwards.
///
/// 2. This macro assumed that we are in the same module as the `enum` mentioned
/// was defined. Some undefined behaviour might occur if this macro is called
/// outside of the module the `enum` was created.
else
}
)
)?
.map
.map_err?;
)?
$?
)+
Ok
}
}
};
=> ;
=> ;
}