1use crate::literal::DefaultValue;
2use crate::{term, IResult, Parse};
3
4pub(crate) fn is_alphanum_underscore_dash(token: char) -> bool {
5 nom::AsChar::is_alphanum(token) || matches!(token, '_' | '-')
6}
7
8fn marker<S>(i: &str) -> IResult<&str, S>
9where
10 S: ::std::default::Default,
11{
12 Ok((i, S::default()))
13}
14
15impl<'a, T: Parse<'a>> Parse<'a> for Option<T> {
16 parser!(nom::combinator::opt(weedle!(T)));
17}
18
19impl<'a, T: Parse<'a>> Parse<'a> for Box<T> {
20 parser!(nom::combinator::map(weedle!(T), Box::new));
21}
22
23impl<'a, T: Parse<'a>> Parse<'a> for Vec<T> {
25 parser!(nom::multi::many0(T::parse));
26}
27
28impl<'a, T: Parse<'a>, U: Parse<'a>> Parse<'a> for (T, U) {
29 parser!(nom::sequence::tuple((T::parse, U::parse)));
30}
31
32impl<'a, T: Parse<'a>, U: Parse<'a>, V: Parse<'a>> Parse<'a> for (T, U, V) {
33 parser!(nom::sequence::tuple((T::parse, U::parse, V::parse)));
34}
35
36ast_types! {
37 #[derive(Copy, Default)]
39 struct Parenthesized<T> where [T: Parse<'a>] {
40 open_paren: term::OpenParen,
41 body: T,
42 close_paren: term::CloseParen,
43 }
44
45 #[derive(Copy, Default)]
47 struct Bracketed<T> where [T: Parse<'a>] {
48 open_bracket: term::OpenBracket,
49 body: T,
50 close_bracket: term::CloseBracket,
51 }
52
53 #[derive(Copy, Default)]
55 struct Braced<T> where [T: Parse<'a>] {
56 open_brace: term::OpenBrace,
57 body: T,
58 close_brace: term::CloseBrace,
59 }
60
61 #[derive(Copy, Default)]
63 struct Generics<T> where [T: Parse<'a>] {
64 open_angle: term::LessThan,
65 body: T,
66 close_angle: term::GreaterThan,
67 }
68
69 struct Punctuated<T, S> where [T: Parse<'a>, S: Parse<'a> + ::std::default::Default] {
71 list: Vec<T> = nom::multi::separated_list0(weedle!(S), weedle!(T)),
72 separator: S = marker,
73 }
74
75 struct PunctuatedNonEmpty<T, S> where [T: Parse<'a>, S: Parse<'a> + ::std::default::Default] {
77 list: Vec<T> = nom::sequence::terminated(
78 nom::multi::separated_list1(weedle!(S), weedle!(T)),
79 nom::combinator::opt(weedle!(S))
80 ),
81 separator: S = marker,
82 }
83
84 #[derive(Copy)]
88 struct Identifier<'a>(
89 &'a str = crate::whitespace::ws(nom::sequence::preceded(
92 nom::combinator::opt(nom::character::complete::char('_')),
93 nom::combinator::recognize(nom::sequence::tuple((
94 nom::bytes::complete::take_while1(nom::AsChar::is_alphanum),
95 nom::bytes::complete::take_while(is_alphanum_underscore_dash),
96 )))
97 )),
98 )
99
100 #[derive(Copy)]
102 struct Default<'a> {
103 assign: term!(=),
104 value: DefaultValue<'a>,
105 }
106}
107
108#[cfg(test)]
109mod test {
110 use super::*;
111
112 test!(should_parse_optional_present { "one" =>
113 "";
114 Option<Identifier>;
115 is_some();
116 });
117
118 test!(should_parse_optional_not_present { "" =>
119 "";
120 Option<Identifier>;
121 is_none();
122 });
123
124 test!(should_parse_boxed { "one" =>
125 "";
126 Box<Identifier>;
127 });
128
129 test!(should_parse_vec { "one two three" =>
130 "";
131 Vec<Identifier>;
132 len() == 3;
133 });
134
135 test!(should_parse_parenthesized { "( one )" =>
136 "";
137 Parenthesized<Identifier>;
138 body.0 == "one";
139 });
140
141 test!(should_parse_bracketed { "[ one ]" =>
142 "";
143 Bracketed<Identifier>;
144 body.0 == "one";
145 });
146
147 test!(should_parse_braced { "{ one }" =>
148 "";
149 Braced<Identifier>;
150 body.0 == "one";
151 });
152
153 test!(should_parse_generics { "<one>" =>
154 "";
155 Generics<Identifier>;
156 body.0 == "one";
157 });
158
159 test!(should_parse_generics_two { "<one, two>" =>
160 "";
161 Generics<(Identifier, term!(,), Identifier)> =>
162 Generics {
163 open_angle: term!(<),
164 body: (Identifier("one"), term!(,), Identifier("two")),
165 close_angle: term!(>),
166 }
167 });
168
169 test!(should_parse_comma_separated_values { "one, two, three" =>
170 "";
171 Punctuated<Identifier, term!(,)>;
172 list.len() == 3;
173 });
174
175 test!(err should_not_parse_comma_separated_values_empty { "" =>
176 PunctuatedNonEmpty<Identifier, term!(,)>
177 });
178
179 test!(should_parse_identifier { "hello" =>
180 "";
181 Identifier;
182 0 == "hello";
183 });
184
185 test!(should_parse_numbered_identifier { "hello5" =>
186 "";
187 Identifier;
188 0 == "hello5";
189 });
190
191 test!(should_parse_underscored_identifier { "_hello_" =>
192 "";
193 Identifier;
194 0 == "hello_";
195 });
196
197 test!(should_parse_identifier_surrounding_with_spaces { " hello " =>
198 "";
199 Identifier;
200 0 == "hello";
201 });
202
203 test!(should_parse_identifier_preceding_others { "hello note" =>
204 "note";
205 Identifier;
206 0 == "hello";
207 });
208
209 test!(should_parse_identifier_attached_to_symbol { "hello=" =>
210 "=";
211 Identifier;
212 0 == "hello";
213 });
214}