blob: 4d82a4047853679c677a9788aad88a7f5f4f009e [file] [log] [blame]
David Tolnay35161ff2016-09-03 11:33:15 -07001#[macro_use]
2extern crate nom;
3
4use nom::IResult;
David Tolnayf3249962016-09-03 21:12:40 -07005use nom::{digit, multispace as space};
David Tolnay35161ff2016-09-03 11:33:15 -07006
7use std::str;
8
9#[derive(Debug, Clone, Eq, PartialEq)]
10pub struct Item {
11 pub ident: Ident,
12 pub vis: Visibility,
13 pub attrs: Vec<Attribute>,
14 pub generics: Generics,
15 pub body: Body,
16}
17
18pub type Ident = String;
19
20#[derive(Debug, Clone, Eq, PartialEq)]
21pub struct Attribute {
22 pub value: MetaItem,
23 pub is_sugared_doc: bool,
24}
25
26/// A compile-time attribute item.
27///
28/// E.g. `#[test]`, `#[derive(..)]` or `#[feature = "foo"]`
29#[derive(Debug, Clone, Eq, PartialEq)]
30pub enum MetaItem {
31 /// Word meta item.
32 ///
33 /// E.g. `test` as in `#[test]`
34 Word(Ident),
35 /// List meta item.
36 ///
37 /// E.g. `derive(..)` as in `#[derive(..)]`
38 List(Ident, Vec<MetaItem>),
39 /// Name value meta item.
40 ///
41 /// E.g. `feature = "foo"` as in `#[feature = "foo"]`
42 NameValue(Ident, String),
43}
44
45#[derive(Debug, Clone, Eq, PartialEq, Default)]
46pub struct Generics {
47 pub lifetimes: Vec<LifetimeDef>,
48 pub ty_params: Vec<TyParam>,
49 pub where_clause: Vec<WherePredicate>,
50}
51
52/// A single predicate in a `where` clause
53#[derive(Debug, Clone, Eq, PartialEq)]
54pub enum WherePredicate {
55 /// A type binding, e.g. `for<'c> Foo: Send+Clone+'c`
56 BoundPredicate(WhereBoundPredicate),
57 /// A lifetime predicate, e.g. `'a: 'b+'c`
58 RegionPredicate(WhereRegionPredicate),
59}
60
61/// A type bound.
62///
63/// E.g. `for<'c> Foo: Send+Clone+'c`
64#[derive(Debug, Clone, Eq, PartialEq)]
65pub struct WhereBoundPredicate {
66 /// Any lifetimes from a `for` binding
67 pub bound_lifetimes: Vec<LifetimeDef>,
68 /// The type being bounded
69 pub bounded_ty: Ty,
70 /// Trait and lifetime bounds (`Clone+Send+'static`)
71 pub bounds: Vec<TyParamBound>,
72}
73
74/// A lifetime predicate.
75///
76/// E.g. `'a: 'b+'c`
77#[derive(Debug, Clone, Eq, PartialEq)]
78pub struct WhereRegionPredicate {
79 pub lifetime: Lifetime,
80 pub bounds: Vec<Lifetime>,
81}
82
83#[derive(Debug, Clone, Eq, PartialEq)]
84pub struct LifetimeDef {
85 pub lifetime: Lifetime,
86 pub bounds: Vec<Lifetime>,
87}
88
89#[derive(Debug, Clone, Eq, PartialEq)]
90pub struct Lifetime {
91 pub ident: Ident,
92}
93
94#[derive(Debug, Clone, Eq, PartialEq)]
95pub struct TyParam {
96 pub ident: Ident,
97 pub bounds: Vec<TyParamBound>,
98 pub default: Option<Ty>,
99}
100
101#[derive(Debug, Clone, Eq, PartialEq)]
102pub enum TyParamBound {
103 MaybeSized,
104 Region(Lifetime),
105 Trait(PolyTraitRef),
106}
107
108#[derive(Debug, Clone, Eq, PartialEq)]
109pub struct PolyTraitRef {
110 /// The `'a` in `<'a> Foo<&'a T>`
111 pub bound_lifetimes: Vec<LifetimeDef>,
112 /// The `Foo<&'a T>` in `<'a> Foo<&'a T>`
113 pub trait_ref: Path,
114}
115
116#[derive(Debug, Clone, Eq, PartialEq)]
117pub struct Path {
118 pub global: bool,
119 pub segments: Vec<PathSegment>,
120}
121
122/// A segment of a path: an identifier, an optional lifetime, and a set of types.
123///
124/// E.g. `std`, `String` or `Box<T>`
125#[derive(Debug, Clone, Eq, PartialEq)]
126pub struct PathSegment {
127 pub ident: Ident,
128 pub parameters: PathParameters,
129}
130
131impl PathSegment {
132 pub fn ident(ident: Ident) -> Self {
133 PathSegment {
134 ident: ident,
135 parameters: PathParameters::none(),
136 }
137 }
138}
139
140/// Parameters of a path segment.
141///
142/// E.g. `<A, B>` as in `Foo<A, B>` or `(A, B)` as in `Foo(A, B)`
143#[derive(Debug, Clone, Eq, PartialEq)]
144pub enum PathParameters {
145 /// The `<'a, A, B, C>` in `foo::bar::baz::<'a, A, B, C>`
146 AngleBracketed(AngleBracketedParameterData),
147 /// The `(A, B)` and `C` in `Foo(A, B) -> C`
148 Parenthesized(ParenthesizedParameterData),
149}
150
151impl PathParameters {
152 pub fn none() -> Self {
153 PathParameters::AngleBracketed(AngleBracketedParameterData::default())
154 }
155}
156
157/// A path like `Foo<'a, T>`
158#[derive(Debug, Clone, Eq, PartialEq, Default)]
159pub struct AngleBracketedParameterData {
160 /// The lifetime parameters for this path segment.
161 pub lifetimes: Vec<Lifetime>,
162 /// The type parameters for this path segment, if present.
163 pub types: Vec<Ty>,
164 /// Bindings (equality constraints) on associated types, if present.
165 ///
166 /// E.g., `Foo<A=Bar>`.
167 pub bindings: Vec<TypeBinding>,
168}
169
170/// Bind a type to an associated type: `A=Foo`.
171#[derive(Debug, Clone, Eq, PartialEq)]
172pub struct TypeBinding {
173 pub ident: Ident,
174 pub ty: Ty,
175}
176
177/// A path like `Foo(A,B) -> C`
178#[derive(Debug, Clone, Eq, PartialEq)]
179pub struct ParenthesizedParameterData {
180 /// `(A, B)`
181 pub inputs: Vec<Ty>,
182 /// `C`
183 pub output: Option<Ty>,
184}
185
186#[derive(Debug, Clone, Eq, PartialEq)]
187pub enum Body {
188 Enum(Vec<Variant>),
189 Struct(Style, Vec<Field>),
190}
191
192#[derive(Debug, Clone, Eq, PartialEq)]
193pub struct Variant {
194 pub ident: Ident,
195 pub attrs: Vec<Attribute>,
196 pub style: Style,
197 pub fields: Vec<Field>,
198}
199
200#[derive(Debug, Clone, Eq, PartialEq)]
201pub enum Style {
202 Struct,
203 Tuple,
204 Unit,
205}
206
207#[derive(Debug, Clone, Eq, PartialEq)]
208pub struct Field {
209 pub ident: Option<Ident>,
210 pub vis: Visibility,
211 pub attrs: Vec<Attribute>,
212 pub ty: Ty,
213}
214
215#[derive(Debug, Clone, Eq, PartialEq)]
216pub enum Visibility {
217 Public,
218 Inherited,
219}
220
221#[derive(Debug, Clone, Eq, PartialEq)]
222pub enum Ty {
223 /// A variable-length array (`[T]`)
224 Vec(Box<Ty>),
225 /// A fixed length array (`[T; n]`)
226 FixedLengthVec(Box<Ty>, usize),
227 /// A raw pointer (`*const T` or `*mut T`)
228 Ptr(Box<MutTy>),
229 /// A reference (`&'a T` or `&'a mut T`)
230 Rptr(Option<Lifetime>, Box<MutTy>),
231 /// A bare function (e.g. `fn(usize) -> bool`)
232 BareFn(Box<BareFnTy>),
233 /// The never type (`!`)
234 Never,
235 /// A tuple (`(A, B, C, D, ...)`)
236 Tup(Vec<Ty>),
237 /// A path (`module::module::...::Type`), optionally
238 /// "qualified", e.g. `<Vec<T> as SomeTrait>::SomeType`.
239 ///
240 /// Type parameters are stored in the Path itself
241 Path(Option<QSelf>, Path),
242 /// Something like `A+B`. Note that `B` must always be a path.
243 ObjectSum(Box<Ty>, Vec<TyParamBound>),
244 /// A type like `for<'a> Foo<&'a Bar>`
245 PolyTraitRef(Vec<TyParamBound>),
246 /// An `impl TraitA+TraitB` type.
247 ImplTrait(Vec<TyParamBound>),
248 /// No-op; kept solely so that we can pretty-print faithfully
249 Paren(Box<Ty>),
250 /// TyKind::Infer means the type should be inferred instead of it having been
251 /// specified. This can appear anywhere in a type.
252 Infer,
253}
254
255#[derive(Debug, Clone, Eq, PartialEq)]
256pub struct MutTy {
257 pub ty: Ty,
David Tolnayf3249962016-09-03 21:12:40 -0700258 pub mutability: Mutability,
David Tolnay35161ff2016-09-03 11:33:15 -0700259}
260
261#[derive(Debug, Clone, Eq, PartialEq)]
262pub enum Mutability {
263 Mutable,
264 Immutable,
265}
266
267/// The explicit Self type in a "qualified path". The actual
268/// path, including the trait and the associated item, is stored
269/// separately. `position` represents the index of the associated
270/// item qualified with this Self type.
271///
272/// ```rust,ignore
273/// <Vec<T> as a::b::Trait>::AssociatedItem
274/// ^~~~~ ~~~~~~~~~~~~~~^
275/// ty position = 3
276///
277/// <Vec<T>>::AssociatedItem
278/// ^~~~~ ^
279/// ty position = 0
280/// ```
281#[derive(Debug, Clone, Eq, PartialEq)]
282pub struct QSelf {
283 pub ty: Box<Ty>,
284 pub position: usize
285}
286
287#[derive(Debug, Clone, Eq, PartialEq)]
288pub struct BareFnTy {
289 pub lifetimes: Vec<LifetimeDef>,
290 pub decl: FnDecl
291}
292
293/// Header (not the body) of a function declaration.
294///
295/// E.g. `fn foo(bar: baz)`
296#[derive(Debug, Clone, Eq, PartialEq)]
297pub struct FnDecl {
298 pub inputs: Vec<Arg>,
299 pub output: FunctionRetTy,
300}
301
302/// An argument in a function header.
303///
304/// E.g. `bar: usize` as in `fn foo(bar: usize)`
305#[derive(Debug, Clone, Eq, PartialEq)]
306pub struct Arg {
307 pub pat: Option<Ident>,
308 pub ty: Ty,
309}
310
311#[derive(Debug, Clone, Eq, PartialEq)]
312pub enum FunctionRetTy {
313 /// Return type is not specified.
314 ///
315 /// Functions default to `()` and
316 /// closures default to inference. Span points to where return
317 /// type would be inserted.
318 Default,
319 /// Everything else
320 Ty(Ty),
321}
322
David Tolnayf3249962016-09-03 21:12:40 -0700323pub fn epsilon<T>(input: T) -> IResult<T, ()> {
324 IResult::Done(input, ())
325}
326
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700327pub fn escaped_string(input: &str) -> IResult<&str, String> {
328 let mut s = String::new();
329 let mut chars = input.char_indices().peekable();
330 while let Some((byte_offset, ch)) = chars.next() {
331 match ch {
332 '"' => {
333 return IResult::Done(&input[byte_offset..], s);
334 }
335 '\\' => {
336 match chars.next() {
337 Some((_, 'x')) => unimplemented!(),
338 Some((_, 'u')) => unimplemented!(),
339 Some((_, 'n')) => s.push('\n'),
340 Some((_, 'r')) => s.push('\r'),
341 Some((_, 't')) => s.push('\t'),
342 Some((_, '0')) => s.push('\0'),
343 Some((_, '\\')) => s.push('\\'),
344 Some((_, '\n')) => {
345 while let Some(&(_, ch)) = chars.peek() {
346 if ch.is_whitespace() {
347 chars.next();
348 } else {
349 break;
350 }
351 }
352 }
353 _ => break,
354 }
355 }
356 ch => {
357 s.push(ch);
358 }
359 }
360 }
361 IResult::Error(nom::Err::Position(nom::ErrorKind::Escaped, input))
362}
363
David Tolnayf3249962016-09-03 21:12:40 -0700364macro_rules! punct {
365 ($i:expr, $ch:expr) => {
366 tuple!($i, opt!(space), tag_s!($ch))
367 };
368}
369
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700370named!(quoted<&str, String>, delimited!(
David Tolnayf3249962016-09-03 21:12:40 -0700371 punct!("\""),
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700372 escaped_string,
373 tag_s!("\"")
374));
375
David Tolnayf3249962016-09-03 21:12:40 -0700376named!(meta_item<&str, MetaItem>, alt!(
377 chain!(
378 ident: word ~
379 punct!("(") ~
380 inner: separated_list!(punct!(","), meta_item) ~
381 punct!(")"),
382 move || MetaItem::List(ident, inner)
383 )
384 |
385 chain!(
386 ident: word ~
387 punct!("=") ~
388 string: quoted,
389 move || MetaItem::NameValue(ident, string)
390 )
391 |
392 map!(word, MetaItem::Word)
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700393));
394
David Tolnay35161ff2016-09-03 11:33:15 -0700395named!(attribute<&str, Attribute>, chain!(
David Tolnayf3249962016-09-03 21:12:40 -0700396 punct!("#") ~
397 punct!("[") ~
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700398 meta_item: meta_item ~
David Tolnayf3249962016-09-03 21:12:40 -0700399 punct!("]"),
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700400 move || Attribute {
401 value: meta_item,
402 is_sugared_doc: false,
403 }
David Tolnay35161ff2016-09-03 11:33:15 -0700404));
405
David Tolnayf3249962016-09-03 21:12:40 -0700406named!(mutability<&str, Mutability>, preceded!(
407 opt!(space),
408 alt!(
409 terminated!(tag_s!("mut"), space) => { |_| Mutability::Mutable }
410 |
411 epsilon => { |_| Mutability::Immutable }
412 )
413));
414
415named!(visibility<&str, Visibility>, preceded!(
416 opt!(space),
417 alt!(
418 terminated!(tag_s!("pub"), space) => { |_| Visibility::Public }
419 |
420 epsilon => { |_| Visibility::Inherited }
421 )
422));
David Tolnay35161ff2016-09-03 11:33:15 -0700423
424fn ident_ch(ch: char) -> bool {
425 ch.is_alphanumeric() || ch == '_'
426}
427
David Tolnayf3249962016-09-03 21:12:40 -0700428named!(word<&str, Ident>, preceded!(
429 opt!(space),
430 map!(take_while1_s!(ident_ch), String::from)
431));
432
433macro_rules! opt_vec (
434 ($i:expr, $submac:ident!( $($args:tt)* )) => ({
435 match $submac!($i, $($args)*) {
436 IResult::Done(i, o) => IResult::Done(i, o),
437 IResult::Error(_) => IResult::Done($i, Vec::new()),
438 IResult::Incomplete(i) => IResult::Incomplete(i)
439 }
440 });
441);
442
443named!(type_binding<&str, TypeBinding>, chain!(
444 ident: word ~
445 punct!("=") ~
446 ty: ty,
447 move || TypeBinding {
448 ident: ident,
449 ty: ty,
450 }
451));
David Tolnay35161ff2016-09-03 11:33:15 -0700452
453named!(path_segment<&str, PathSegment>, alt!(
454 chain!(
455 ident: word ~
David Tolnayf3249962016-09-03 21:12:40 -0700456 punct!("<") ~
457 lifetimes: separated_list!(punct!(","), lifetime) ~
458 types: opt_vec!(preceded!(
459 cond!(!lifetimes.is_empty(), punct!(",")),
460 separated_nonempty_list!(
461 punct!(","),
462 terminated!(ty, not!(peek!(punct!("="))))
463 )
464 )) ~
465 bindings: opt_vec!(preceded!(
466 cond!(!lifetimes.is_empty() || !types.is_empty(), punct!(",")),
467 separated_nonempty_list!(punct!(","), type_binding)
468 )) ~
469 punct!(">"),
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700470 move || PathSegment {
471 ident: ident,
472 parameters: PathParameters::AngleBracketed(
473 AngleBracketedParameterData {
David Tolnayf3249962016-09-03 21:12:40 -0700474 lifetimes: lifetimes,
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700475 types: types,
David Tolnayf3249962016-09-03 21:12:40 -0700476 bindings: bindings,
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700477 }
478 ),
David Tolnay35161ff2016-09-03 11:33:15 -0700479 }
480 )
481 |
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700482 map!(word, PathSegment::ident)
David Tolnay35161ff2016-09-03 11:33:15 -0700483));
484
David Tolnayf3249962016-09-03 21:12:40 -0700485named!(path<&str, Path>, chain!(
486 global: punct!("::")? ~
487 segments: separated_nonempty_list!(punct!("::"), path_segment),
488 move || Path {
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700489 global: global.is_some(),
490 segments: segments,
David Tolnayf3249962016-09-03 21:12:40 -0700491 }
David Tolnay35161ff2016-09-03 11:33:15 -0700492));
493
David Tolnayf3249962016-09-03 21:12:40 -0700494named!(fn_arg<&str, Arg>, chain!(
495 pat: opt!(terminated!(word, punct!(":"))) ~
496 ty: ty,
497 move || Arg {
498 pat: pat,
499 ty: ty,
500 }
501));
502
503named!(ty<&str, Ty>, alt!(
504 delimited!(
505 punct!("["),
506 ty,
507 punct!("]")
508 ) => { |elem| Ty::Vec(Box::new(elem)) }
509 |
510 chain!(
511 punct!("[") ~
512 elem: ty ~
513 punct!(";") ~
514 space? ~
515 size: map_res!(digit, str::parse),
516 move || Ty::FixedLengthVec(Box::new(elem), size)
517 )
518 |
519 chain!(
520 punct!("*") ~
521 mutability: alt!(
522 punct!("const") => { |_| Mutability::Immutable }
523 |
524 punct!("mut") => { |_| Mutability::Mutable }
525 ) ~
526 target: ty,
527 move || Ty::Ptr(Box::new(MutTy {
528 ty: target,
529 mutability: mutability,
530 }))
531 )
532 |
533 chain!(
534 punct!("&") ~
535 life: lifetime? ~
536 mutability: mutability ~
537 target: ty,
538 move || Ty::Rptr(life, Box::new(MutTy {
539 ty: target,
540 mutability: mutability,
541 }))
542 )
543 |
544 chain!(
545 punct!("fn") ~
546 space ~
547 lifetimes: opt_vec!(delimited!(
548 punct!("<"),
549 separated_list!(punct!(","), lifetime_def),
550 punct!(">")
551 )) ~
552 punct!("(") ~
553 inputs: separated_list!(punct!(","), fn_arg) ~
554 punct!(")") ~
555 output: opt!(preceded!(
556 punct!("->"),
557 ty
558 )),
559 move || Ty::BareFn(Box::new(BareFnTy {
560 lifetimes: lifetimes,
561 decl: FnDecl {
562 inputs: inputs,
563 output: match output {
564 Some(ty) => FunctionRetTy::Ty(ty),
565 None => FunctionRetTy::Default,
566 },
567 },
568 }))
569 )
570 |
571 punct!("!") => { |_| Ty::Never }
572 |
573 delimited!(
574 punct!("("),
575 separated_list!(punct!(","), ty),
576 punct!(")")
577 ) => { Ty::Tup }
578 |
579 path => { |p| Ty::Path(None, p) }
580 |
581 chain!(
582 punct!("<") ~
583 this: map!(ty, Box::new) ~
584 path: opt!(preceded!(
585 tuple!(punct!("as"), space),
586 path
587 )) ~
588 punct!(">") ~
589 punct!("::") ~
590 rest: separated_nonempty_list!(punct!("::"), path_segment),
591 move || {
592 match path {
593 Some(mut path) => {
594 let pos = path.segments.len();
595 path.segments.extend(rest);
596 Ty::Path(Some(QSelf { ty: this, position: pos }), path)
597 }
598 None => {
599 Ty::Path(Some(QSelf { ty: this, position: 0 }), Path {
600 global: false,
601 segments: rest,
602 })
603 }
604 }
605 }
606 )
607 |
608 preceded!(
609 tuple!(punct!("impl"), space),
610 separated_nonempty_list!(punct!("+"), ty_param_bound)
611 ) => { Ty::ImplTrait }
612 |
613 delimited!(
614 punct!("("),
615 ty,
616 punct!(")")
617 ) => { |inner| Ty::Paren(Box::new(inner)) }
618));
David Tolnay35161ff2016-09-03 11:33:15 -0700619
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700620named!(struct_field<&str, Field>, chain!(
621 attrs: many0!(attribute) ~
David Tolnay35161ff2016-09-03 11:33:15 -0700622 vis: visibility ~
623 ident: word ~
David Tolnayf3249962016-09-03 21:12:40 -0700624 punct!(":") ~
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700625 ty: ty,
626 move || Field {
627 ident: Some(ident),
628 vis: vis,
629 attrs: attrs,
630 ty: ty,
David Tolnay35161ff2016-09-03 11:33:15 -0700631 }
632));
633
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700634named!(tuple_field<&str, Field>, chain!(
635 attrs: many0!(attribute) ~
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700636 vis: visibility ~
637 ty: ty,
638 move || Field {
639 ident: None,
640 vis: vis,
641 attrs: attrs,
642 ty: ty,
643 }
644));
645
David Tolnayf3249962016-09-03 21:12:40 -0700646named!(struct_like_body<&str, Vec<Field> >, chain!(
647 punct!("{") ~
648 fields: separated_list!(punct!(","), struct_field) ~
649 punct!(",")? ~
650 punct!("}"),
651 move || fields
652));
653
654named!(tuple_like_body<&str, Vec<Field> >, chain!(
655 punct!("(") ~
656 fields: separated_list!(punct!(","), tuple_field) ~
657 punct!(",")? ~
658 punct!(")"),
659 move || fields
660));
661
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700662named!(struct_body<&str, (Style, Vec<Field>)>, alt!(
David Tolnayf3249962016-09-03 21:12:40 -0700663 struct_like_body => { |fields| (Style::Struct, fields) }
David Tolnay35161ff2016-09-03 11:33:15 -0700664 |
David Tolnayf3249962016-09-03 21:12:40 -0700665 terminated!(tuple_like_body, punct!(";")) => { |fields| (Style::Tuple, fields) }
David Tolnay35161ff2016-09-03 11:33:15 -0700666 |
David Tolnayf3249962016-09-03 21:12:40 -0700667 punct!(";") => { |_| (Style::Unit, Vec::new()) }
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700668));
669
670named!(variant<&str, Variant>, chain!(
671 attrs: many0!(attribute) ~
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700672 ident: word ~
David Tolnayf3249962016-09-03 21:12:40 -0700673 body: alt!(
674 struct_like_body => { |fields| (Style::Struct, fields) }
675 |
676 tuple_like_body => { |fields| (Style::Tuple, fields) }
677 |
678 epsilon => { |_| (Style::Unit, Vec::new()) }
679 ),
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700680 move || Variant {
681 ident: ident,
682 attrs: attrs,
683 style: body.0,
684 fields: body.1,
685 }
686));
687
688named!(enum_body<&str, Body>, chain!(
David Tolnayf3249962016-09-03 21:12:40 -0700689 punct!("{") ~
690 variants: separated_list!(punct!(","), variant) ~
691 punct!(",")? ~
692 punct!("}"),
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700693 move || Body::Enum(variants)
694));
695
696named!(lifetime<&str, Lifetime>, preceded!(
David Tolnayf3249962016-09-03 21:12:40 -0700697 punct!("'"),
698 map!(word, |ident| Lifetime { ident: ident })
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700699));
700
David Tolnayf3249962016-09-03 21:12:40 -0700701named!(bound_lifetimes<&str, Vec<LifetimeDef> >, opt_vec!(chain!(
702 punct!("for") ~
703 punct!("<") ~
704 lifetimes: separated_list!(punct!(","), lifetime_def) ~
705 punct!(">"),
706 move || lifetimes
707)));
708
709named!(poly_trait_ref<&str, PolyTraitRef>, chain!(
710 bound_lifetimes: bound_lifetimes ~
711 trait_ref: path,
712 move || PolyTraitRef {
713 bound_lifetimes: bound_lifetimes,
714 trait_ref: trait_ref,
715 }
716));
717
718named!(ty_param_bound<&str, TyParamBound>, alt!(
719 tuple!(punct!("?"), punct!("Sized")) => { |_| TyParamBound::MaybeSized }
720 |
721 lifetime => { TyParamBound::Region }
722 |
723 poly_trait_ref => { TyParamBound::Trait }
724));
725
726named!(where_predicate<&str, WherePredicate>, alt!(
727 chain!(
728 ident: lifetime ~
729 punct!(":") ~
730 bounds: separated_nonempty_list!(punct!("+"), lifetime),
731 move || WherePredicate::RegionPredicate(WhereRegionPredicate {
732 lifetime: ident,
733 bounds: bounds,
734 })
735 )
736 |
737 chain!(
738 bound_lifetimes: bound_lifetimes ~
739 bounded_ty: ty ~
740 punct!(":") ~
741 bounds: separated_nonempty_list!(punct!("+"), ty_param_bound),
742 move || WherePredicate::BoundPredicate(WhereBoundPredicate {
743 bound_lifetimes: bound_lifetimes,
744 bounded_ty: bounded_ty,
745 bounds: bounds,
746 })
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700747 )
748));
749
750named!(lifetime_def<&str, LifetimeDef>, chain!(
David Tolnayf3249962016-09-03 21:12:40 -0700751 life: lifetime ~
752 bounds: opt_vec!(preceded!(
753 punct!(":"),
754 separated_nonempty_list!(punct!(","), lifetime)
755 )),
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700756 move || LifetimeDef {
David Tolnayf3249962016-09-03 21:12:40 -0700757 lifetime: life,
758 bounds: bounds,
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700759 }
760));
761
762named!(ty_param<&str, TyParam>, chain!(
David Tolnayf3249962016-09-03 21:12:40 -0700763 ident: word ~
764 bounds: opt_vec!(preceded!(
765 punct!(":"),
766 separated_nonempty_list!(punct!("+"), ty_param_bound)
767 )) ~
768 default: opt!(preceded!(
769 punct!("="),
770 ty
771 )) ~
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700772 move || TyParam {
773 ident: ident,
David Tolnayf3249962016-09-03 21:12:40 -0700774 bounds: bounds,
775 default: default,
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700776 }
777));
778
779named!(generics<&str, Generics>, chain!(
David Tolnayf3249962016-09-03 21:12:40 -0700780 bracketed: alt!(
781 chain!(
782 punct!("<") ~
783 lifetimes: separated_list!(punct!(","), lifetime_def) ~
784 ty_params: opt_vec!(preceded!(
785 cond!(!lifetimes.is_empty(), punct!(",")),
786 separated_nonempty_list!(punct!(","), ty_param)
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700787 )) ~
David Tolnayf3249962016-09-03 21:12:40 -0700788 punct!(">"),
789 move || (lifetimes, ty_params)
790 )
791 |
792 epsilon => { |_| (Vec::new(), Vec::new()) }
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700793 ) ~
David Tolnayf3249962016-09-03 21:12:40 -0700794 where_clause: opt_vec!(chain!(
795 punct!("where") ~
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700796 space ~
David Tolnayf3249962016-09-03 21:12:40 -0700797 predicates: separated_nonempty_list!(punct!(","), where_predicate) ~
798 punct!(",")? ~
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700799 move || predicates
800 )),
801 move || Generics {
802 lifetimes: bracketed.0,
803 ty_params: bracketed.1,
David Tolnayf3249962016-09-03 21:12:40 -0700804 where_clause: where_clause,
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700805 }
David Tolnay35161ff2016-09-03 11:33:15 -0700806));
807
808named!(item<&str, Item>, chain!(
809 attrs: many0!(attribute) ~
David Tolnay35161ff2016-09-03 11:33:15 -0700810 vis: visibility ~
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700811 which: alt!(tag_s!("struct") | tag_s!("enum")) ~
David Tolnay351ea992016-09-04 01:15:22 -0700812 space ~
David Tolnay35161ff2016-09-03 11:33:15 -0700813 ident: word ~
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700814 generics: generics ~
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700815 item: switch!(value!(which),
816 "struct" => map!(struct_body, move |(style, fields)| Item {
David Tolnay35161ff2016-09-03 11:33:15 -0700817 ident: ident,
818 vis: vis,
819 attrs: attrs,
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700820 generics: generics,
821 body: Body::Struct(style, fields),
822 })
823 |
824 "enum" => map!(enum_body, move |body| Item {
825 ident: ident,
826 vis: vis,
827 attrs: attrs,
828 generics: generics,
David Tolnay35161ff2016-09-03 11:33:15 -0700829 body: body,
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700830 })
831 ) ~
832 space?,
833 move || item
David Tolnay35161ff2016-09-03 11:33:15 -0700834));
835
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700836pub fn parse(input: &str) -> Item {
David Tolnay35161ff2016-09-03 11:33:15 -0700837 match item(input) {
838 IResult::Done(rest, ast) => {
839 if rest.is_empty() {
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700840 ast
David Tolnay35161ff2016-09-03 11:33:15 -0700841 } else {
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700842 panic!("more than a single input item: {:?}", rest)
David Tolnay35161ff2016-09-03 11:33:15 -0700843 }
844 }
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700845 IResult::Error(err) => raise(err),
846 IResult::Incomplete(_) => panic!("incomplete input item"),
847 }
848}
849
850fn raise(mut err: nom::Err<&str>) -> ! {
851 loop {
852 match err {
853 nom::Err::Code(kind) => {
854 panic!("failed to parse {:?}", kind)
855 }
856 nom::Err::Position(kind, pos) => {
857 panic!("failed to parse {:?}: {:?}", kind, pos)
858 }
859 nom::Err::Node(_, next) |
860 nom::Err::NodePosition(_, _, next) => {
861 err = *next;
862 }
David Tolnay35161ff2016-09-03 11:33:15 -0700863 }
David Tolnay35161ff2016-09-03 11:33:15 -0700864 }
865}