2 use space
::{skip_whitespace, word_break}
;
4 /// Parse a piece of punctuation like "+" or "+=".
6 /// See also `keyword!` for parsing keywords, which are subtly different from
9 /// - **Syntax:** `punct!("...")`
10 /// - **Output:** `&str`
14 /// #[macro_use] extern crate synom;
16 /// // Parse zero or more bangs.
17 /// named!(many_bangs -> Vec<&str>,
18 /// many0!(punct!("!"))
22 /// let input = "!! !";
23 /// let parsed = many_bangs(input).expect("bangs");
24 /// assert_eq!(parsed, ["!", "!", "!"]);
29 ($i
:expr
, $punct
:expr
) => {
30 $
crate::helper
::punct($i
, $punct
)
36 pub fn punct
<'a
>(input
: &'a
str, token
: &'
static str) -> IResult
<&'a
str, &'a
str> {
37 let input
= skip_whitespace(input
);
38 if input
.starts_with(token
) {
39 IResult
::Done(&input
[token
.len()..], token
)
45 /// Parse a keyword like "fn" or "struct".
47 /// See also `punct!` for parsing punctuation, which are subtly different from
50 /// - **Syntax:** `keyword!("...")`
51 /// - **Output:** `&str`
55 /// #[macro_use] extern crate synom;
57 /// use synom::IResult;
59 /// // Parse zero or more "bang" keywords.
60 /// named!(many_bangs -> Vec<&str>,
62 /// many0!(keyword!("bang")),
68 /// let input = "bang bang bang;";
69 /// let parsed = many_bangs(input).expect("bangs");
70 /// assert_eq!(parsed, ["bang", "bang", "bang"]);
72 /// let input = "bangbang;";
73 /// let err = many_bangs(input);
74 /// assert_eq!(err, IResult::Error);
78 macro_rules
! keyword
{
79 ($i
:expr
, $keyword
:expr
) => {
80 $
crate::helper
::keyword($i
, $keyword
)
86 pub fn keyword
<'a
>(input
: &'a
str, token
: &'
static str) -> IResult
<&'a
str, &'a
str> {
87 match punct(input
, token
) {
88 IResult
::Done(rest
, _
) => {
89 match word_break(rest
) {
90 IResult
::Done(_
, _
) => IResult
::Done(rest
, token
),
91 IResult
::Error
=> IResult
::Error
,
94 IResult
::Error
=> IResult
::Error
,
98 /// Turn a failed parse into `None` and a successful parse into `Some`.
100 /// - **Syntax:** `option!(THING)`
101 /// - **Output:** `Option<THING>`
104 /// extern crate syn;
105 /// #[macro_use] extern crate synom;
107 /// named!(maybe_bang -> Option<&str>, option!(punct!("!")));
111 /// let parsed = maybe_bang(input).expect("maybe bang");
112 /// assert_eq!(parsed, Some("!"));
115 /// let parsed = maybe_bang(input).expect("maybe bang");
116 /// assert_eq!(parsed, None);
120 macro_rules
! option
{
121 ($i
:expr
, $submac
:ident
!( $
($args
:tt
)* )) => {
122 match $submac
!($i
, $
($args
)*) {
123 $
crate::IResult
::Done(i
, o
) => $
crate::IResult
::Done(i
, Some(o
)),
124 $
crate::IResult
::Error
=> $
crate::IResult
::Done($i
, None
),
128 ($i
:expr
, $f
:expr
) => {
129 option
!($i
, call
!($f
));
133 /// Turn a failed parse into an empty vector. The argument parser must itself
136 /// This is often more convenient than `option!(...)` when the argument produces
139 /// - **Syntax:** `opt_vec!(THING)`
140 /// - **Output:** `THING`, which must be `Vec<T>`
143 /// extern crate syn;
144 /// #[macro_use] extern crate synom;
146 /// use syn::{Lifetime, Ty};
147 /// use syn::parse::{lifetime, ty};
149 /// named!(bound_lifetimes -> (Vec<Lifetime>, Ty), tuple!(
150 /// opt_vec!(do_parse!(
151 /// keyword!("for") >>
153 /// lifetimes: terminated_list!(punct!(","), lifetime) >>
161 /// let input = "for<'a, 'b> fn(&'a A) -> &'b B";
162 /// let parsed = bound_lifetimes(input).expect("bound lifetimes");
163 /// assert_eq!(parsed.0, [Lifetime::new("'a"), Lifetime::new("'b")]);
164 /// println!("{:?}", parsed);
166 /// let input = "From<String>";
167 /// let parsed = bound_lifetimes(input).expect("bound lifetimes");
168 /// assert!(parsed.0.is_empty());
169 /// println!("{:?}", parsed);
173 macro_rules
! opt_vec
{
174 ($i
:expr
, $submac
:ident
!( $
($args
:tt
)* )) => {
175 match $submac
!($i
, $
($args
)*) {
176 $
crate::IResult
::Done(i
, o
) => $
crate::IResult
::Done(i
, o
),
177 $
crate::IResult
::Error
=> $
crate::IResult
::Done($i
, Vec
::new()),
182 /// Parses nothing and always succeeds.
184 /// This can be useful as a fallthrough case in `alt!`.
186 /// - **Syntax:** `epsilon!()`
187 /// - **Output:** `()`
190 /// extern crate syn;
191 /// #[macro_use] extern crate synom;
193 /// use syn::Mutability;
195 /// named!(mutability -> Mutability, alt!(
196 /// keyword!("mut") => { |_| Mutability::Mutable }
198 /// epsilon!() => { |_| Mutability::Immutable }
202 /// let input = "mut";
203 /// let parsed = mutability(input).expect("mutability");
204 /// assert_eq!(parsed, Mutability::Mutable);
207 /// let parsed = mutability(input).expect("mutability");
208 /// assert_eq!(parsed, Mutability::Immutable);
212 macro_rules
! epsilon
{
214 $
crate::IResult
::Done($i
, ())
218 /// Run a parser, binding the result to a name, and then evaluating an
221 /// Discards the result of the expression and parser.
223 /// - **Syntax:** `tap!(NAME : THING => EXPR)`
224 /// - **Output:** `()`
227 /// extern crate syn;
228 /// #[macro_use] extern crate synom;
230 /// use syn::{Expr, ExprKind};
231 /// use syn::parse::expr;
233 /// named!(expr_with_arrow_call -> Expr, do_parse!(
235 /// many0!(tap!(arg: tuple!(punct!("=>"), expr) => {
237 /// node: ExprKind::Call(Box::new(e), vec![arg.1]),
238 /// attrs: Vec::new(),
245 /// let input = "something => argument1 => argument2";
247 /// let parsed = expr_with_arrow_call(input).expect("expr with arrow call");
249 /// println!("{:?}", parsed);
255 ($i
:expr
, $name
:ident
: $submac
:ident
!( $
($args
:tt
)* ) => $e
:expr
) => {
256 match $submac
!($i
, $
($args
)*) {
257 $
crate::IResult
::Done(i
, o
) => {
260 $
crate::IResult
::Done(i
, ())
262 $
crate::IResult
::Error
=> $
crate::IResult
::Error
,
266 ($i
:expr
, $name
:ident
: $f
:expr
=> $e
:expr
) => {
267 tap
!($i
, $name
: call
!($f
) => $e
);
271 /// Zero or more values separated by some separator. Does not allow a trailing
274 /// - **Syntax:** `separated_list!(punct!("..."), THING)`
275 /// - **Output:** `Vec<THING>`
277 /// You may also be looking for:
279 /// - `separated_nonempty_list!` - one or more values
280 /// - `terminated_list!` - zero or more, allows trailing separator
281 /// - `many0!` - zero or more, no separator
284 /// extern crate syn;
285 /// #[macro_use] extern crate synom;
288 /// use syn::parse::expr;
290 /// named!(expr_list -> Vec<Expr>,
291 /// separated_list!(punct!(","), expr)
295 /// let input = "1 + 1, things, Construct { this: thing }";
297 /// let parsed = expr_list(input).expect("expr list");
298 /// assert_eq!(parsed.len(), 3);
303 /// extern crate syn;
304 /// #[macro_use] extern crate synom;
307 /// use syn::parse::ident;
309 /// named!(run_on -> Vec<Ident>,
311 /// separated_list!(keyword!("and"), preceded!(punct!("$"), ident)),
317 /// let input = "$expr and $ident and $pat ...";
319 /// let parsed = run_on(input).expect("run-on sentence");
320 /// assert_eq!(parsed.len(), 3);
321 /// assert_eq!(parsed[0], "expr");
322 /// assert_eq!(parsed[1], "ident");
323 /// assert_eq!(parsed[2], "pat");
327 macro_rules
! separated_list
{
328 // Try to use this branch if possible - makes a difference in compile time.
329 ($i
:expr
, punct
!($sep
:expr
), $f
:ident
) => {
330 $
crate::helper
::separated_list($i
, $sep
, $f
, false)
333 ($i
:expr
, $sepmac
:ident
!( $
($separgs
:tt
)* ), $fmac
:ident
!( $
($fargs
:tt
)* )) => {{
334 let mut res
= ::std
::vec
::Vec
::new();
337 // get the first element
338 match $fmac
!(input
, $
($fargs
)*) {
339 $
crate::IResult
::Error
=> $
crate::IResult
::Done(input
, res
),
340 $
crate::IResult
::Done(i
, o
) => {
341 if i
.len() == input
.len() {
342 $
crate::IResult
::Error
347 // get the separator first
348 while let $
crate::IResult
::Done(i2
, _
) = $sepmac
!(input
, $
($separgs
)*) {
349 if i2
.len() == input
.len() {
353 // get the element next
354 if let $
crate::IResult
::Done(i3
, o3
) = $fmac
!(i2
, $
($fargs
)*) {
355 if i3
.len() == i2
.len() {
364 $
crate::IResult
::Done(input
, res
)
370 ($i
:expr
, $sepmac
:ident
!( $
($separgs
:tt
)* ), $f
:expr
) => {
371 separated_list
!($i
, $sepmac
!($
($separgs
)*), call
!($f
))
374 ($i
:expr
, $sep
:expr
, $fmac
:ident
!( $
($fargs
:tt
)* )) => {
375 separated_list
!($i
, call
!($sep
), $fmac
!($
($fargs
)*))
378 ($i
:expr
, $sep
:expr
, $f
:expr
) => {
379 separated_list
!($i
, call
!($sep
), call
!($f
))
383 /// Zero or more values separated by some separator. A trailing separator is
386 /// - **Syntax:** `terminated_list!(punct!("..."), THING)`
387 /// - **Output:** `Vec<THING>`
389 /// You may also be looking for:
391 /// - `separated_list!` - zero or more, allows trailing separator
392 /// - `separated_nonempty_list!` - one or more values
393 /// - `many0!` - zero or more, no separator
396 /// extern crate syn;
397 /// #[macro_use] extern crate synom;
400 /// use syn::parse::expr;
402 /// named!(expr_list -> Vec<Expr>,
403 /// terminated_list!(punct!(","), expr)
407 /// let input = "1 + 1, things, Construct { this: thing },";
409 /// let parsed = expr_list(input).expect("expr list");
410 /// assert_eq!(parsed.len(), 3);
415 /// extern crate syn;
416 /// #[macro_use] extern crate synom;
419 /// use syn::parse::ident;
421 /// named!(run_on -> Vec<Ident>,
423 /// terminated_list!(keyword!("and"), preceded!(punct!("$"), ident)),
429 /// let input = "$expr and $ident and $pat and ...";
431 /// let parsed = run_on(input).expect("run-on sentence");
432 /// assert_eq!(parsed.len(), 3);
433 /// assert_eq!(parsed[0], "expr");
434 /// assert_eq!(parsed[1], "ident");
435 /// assert_eq!(parsed[2], "pat");
439 macro_rules
! terminated_list
{
440 // Try to use this branch if possible - makes a difference in compile time.
441 ($i
:expr
, punct
!($sep
:expr
), $f
:ident
) => {
442 $
crate::helper
::separated_list($i
, $sep
, $f
, true)
445 ($i
:expr
, $sepmac
:ident
!( $
($separgs
:tt
)* ), $fmac
:ident
!( $
($fargs
:tt
)* )) => {{
446 let mut res
= ::std
::vec
::Vec
::new();
449 // get the first element
450 match $fmac
!(input
, $
($fargs
)*) {
451 $
crate::IResult
::Error
=> $
crate::IResult
::Done(input
, res
),
452 $
crate::IResult
::Done(i
, o
) => {
453 if i
.len() == input
.len() {
454 $
crate::IResult
::Error
459 // get the separator first
460 while let $
crate::IResult
::Done(i2
, _
) = $sepmac
!(input
, $
($separgs
)*) {
461 if i2
.len() == input
.len() {
465 // get the element next
466 if let $
crate::IResult
::Done(i3
, o3
) = $fmac
!(i2
, $
($fargs
)*) {
467 if i3
.len() == i2
.len() {
476 if let $
crate::IResult
::Done(after
, _
) = $sepmac
!(input
, $
($separgs
)*) {
479 $
crate::IResult
::Done(input
, res
)
485 ($i
:expr
, $sepmac
:ident
!( $
($separgs
:tt
)* ), $f
:expr
) => {
486 terminated_list
!($i
, $sepmac
!($
($separgs
)*), call
!($f
))
489 ($i
:expr
, $sep
:expr
, $fmac
:ident
!( $
($fargs
:tt
)* )) => {
490 terminated_list
!($i
, call
!($sep
), $fmac
!($
($fargs
)*))
493 ($i
:expr
, $sep
:expr
, $f
:expr
) => {
494 terminated_list
!($i
, call
!($sep
), call
!($f
))
500 pub fn separated_list
<'a
, T
>(mut input
: &'a
str,
502 f
: fn(&'a
str) -> IResult
<&'a
str, T
>,
504 -> IResult
<&'a
str, Vec
<T
>> {
505 let mut res
= Vec
::new();
507 // get the first element
509 IResult
::Error
=> IResult
::Done(input
, res
),
510 IResult
::Done(i
, o
) => {
511 if i
.len() == input
.len() {
517 // get the separator first
518 while let IResult
::Done(i2
, _
) = punct(input
, sep
) {
519 if i2
.len() == input
.len() {
523 // get the element next
524 if let IResult
::Done(i3
, o3
) = f(i2
) {
525 if i3
.len() == i2
.len() {
535 if let IResult
::Done(after
, _
) = punct(input
, sep
) {
539 IResult
::Done(input
, res
)