blob: c9e6e52b324c26068d361ddff631f62caddd9215 [file] [log] [blame]
David Tolnay35161ff2016-09-03 11:33:15 -07001#[macro_use]
2extern crate nom;
3
4use nom::IResult;
5use nom::multispace as space;
6
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,
258 pub mutbl: Mutability,
259}
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 Tolnay7ebb9fb2016-09-03 12:07:47 -0700323pub fn escaped_string(input: &str) -> IResult<&str, String> {
324 let mut s = String::new();
325 let mut chars = input.char_indices().peekable();
326 while let Some((byte_offset, ch)) = chars.next() {
327 match ch {
328 '"' => {
329 return IResult::Done(&input[byte_offset..], s);
330 }
331 '\\' => {
332 match chars.next() {
333 Some((_, 'x')) => unimplemented!(),
334 Some((_, 'u')) => unimplemented!(),
335 Some((_, 'n')) => s.push('\n'),
336 Some((_, 'r')) => s.push('\r'),
337 Some((_, 't')) => s.push('\t'),
338 Some((_, '0')) => s.push('\0'),
339 Some((_, '\\')) => s.push('\\'),
340 Some((_, '\n')) => {
341 while let Some(&(_, ch)) = chars.peek() {
342 if ch.is_whitespace() {
343 chars.next();
344 } else {
345 break;
346 }
347 }
348 }
349 _ => break,
350 }
351 }
352 ch => {
353 s.push(ch);
354 }
355 }
356 }
357 IResult::Error(nom::Err::Position(nom::ErrorKind::Escaped, input))
358}
359
360named!(quoted<&str, String>, delimited!(
361 tag_s!("\""),
362 escaped_string,
363 tag_s!("\"")
364));
365
366named!(meta_item<&str, MetaItem>, chain!(
367 space? ~
368 meta_item: alt!(
369 chain!(
370 ident: word ~
371 space? ~
372 tag_s!("(") ~
373 inner: separated_list!(tag_s!(","), meta_item) ~
374 space? ~
375 tag_s!(")"),
376 move || MetaItem::List(ident, inner)
377 )
378 |
379 chain!(
380 ident: word ~
381 space? ~
382 tag_s!("=") ~
383 space? ~
384 string: quoted,
385 move || MetaItem::NameValue(ident, string)
386 )
387 |
388 map!(word, MetaItem::Word)
389 ),
390 move || meta_item
391));
392
David Tolnay35161ff2016-09-03 11:33:15 -0700393named!(attribute<&str, Attribute>, chain!(
394 space? ~
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700395 tag_s!("#") ~
David Tolnay35161ff2016-09-03 11:33:15 -0700396 space? ~
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700397 tag_s!("[") ~
398 meta_item: meta_item ~
David Tolnay35161ff2016-09-03 11:33:15 -0700399 space? ~
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700400 tag_s!("]"),
401 move || Attribute {
402 value: meta_item,
403 is_sugared_doc: false,
404 }
David Tolnay35161ff2016-09-03 11:33:15 -0700405));
406
407named!(visibility<&str, Visibility>,
408 map!(opt!(terminated!(tag_s!("pub"), space)), |tag| match tag {
409 Some(_) => Visibility::Public,
410 None => Visibility::Inherited,
411 })
412);
413
414fn ident_ch(ch: char) -> bool {
415 ch.is_alphanumeric() || ch == '_'
416}
417
418named!(word<&str, Ident>, map!(take_while1_s!(ident_ch), String::from));
419
420named!(path_segment<&str, PathSegment>, alt!(
421 chain!(
422 ident: word ~
423 space? ~
424 tag_s!("<") ~
425 types: many0!(ty) ~
426 space? ~
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700427 tag_s!(">"),
428 move || PathSegment {
429 ident: ident,
430 parameters: PathParameters::AngleBracketed(
431 AngleBracketedParameterData {
432 lifetimes: Vec::new(),
433 types: types,
434 bindings: Vec::new(),
435 }
436 ),
David Tolnay35161ff2016-09-03 11:33:15 -0700437 }
438 )
439 |
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700440 map!(word, PathSegment::ident)
David Tolnay35161ff2016-09-03 11:33:15 -0700441));
442
443named!(ty<&str, Ty>, chain!(
444 global: tag_s!("::")? ~
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700445 segments: separated_nonempty_list!(tag_s!("::"), path_segment),
446 move || Ty::Path(None, Path {
447 global: global.is_some(),
448 segments: segments,
449 })
David Tolnay35161ff2016-09-03 11:33:15 -0700450));
451
452/*
453 /// A variable-length array (`[T]`)
454 Vec(Box<Ty>),
455 /// A fixed length array (`[T; n]`)
456 FixedLengthVec(Box<Ty>, usize),
457 /// A raw pointer (`*const T` or `*mut T`)
458 Ptr(Box<MutTy>),
459 /// A reference (`&'a T` or `&'a mut T`)
460 Rptr(Option<Lifetime>, Box<MutTy>),
461 /// A bare function (e.g. `fn(usize) -> bool`)
462 BareFn(Box<BareFnTy>),
463 /// The never type (`!`)
464 Never,
465 /// A tuple (`(A, B, C, D, ...)`)
466 Tup(Vec<Ty>),
467 /// A path (`module::module::...::Type`), optionally
468 /// "qualified", e.g. `<Vec<T> as SomeTrait>::SomeType`.
469 ///
470 /// Type parameters are stored in the Path itself
471 Path(Option<QSelf>, Path),
472 /// Something like `A+B`. Note that `B` must always be a path.
473 ObjectSum(Box<Ty>, Vec<TyParamBound>),
474 /// A type like `for<'a> Foo<&'a Bar>`
475 PolyTraitRef(Vec<TyParamBound>),
476 /// An `impl TraitA+TraitB` type.
477 ImplTrait(Vec<TyParamBound>),
478 /// No-op; kept solely so that we can pretty-print faithfully
479 Paren(Box<Ty>),
480 /// TyKind::Infer means the type should be inferred instead of it having been
481 /// specified. This can appear anywhere in a type.
482 Infer,
483*/
484
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700485named!(struct_field<&str, Field>, chain!(
486 attrs: many0!(attribute) ~
David Tolnay35161ff2016-09-03 11:33:15 -0700487 space? ~
488 vis: visibility ~
489 ident: word ~
490 space? ~
491 tag_s!(":") ~
492 space? ~
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700493 ty: ty,
494 move || Field {
495 ident: Some(ident),
496 vis: vis,
497 attrs: attrs,
498 ty: ty,
David Tolnay35161ff2016-09-03 11:33:15 -0700499 }
500));
501
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700502named!(tuple_field<&str, Field>, chain!(
503 attrs: many0!(attribute) ~
504 space? ~
505 vis: visibility ~
506 ty: ty,
507 move || Field {
508 ident: None,
509 vis: vis,
510 attrs: attrs,
511 ty: ty,
512 }
513));
514
515named!(struct_body<&str, (Style, Vec<Field>)>, alt!(
David Tolnay35161ff2016-09-03 11:33:15 -0700516 chain!(
517 tag_s!("{") ~
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700518 fields: separated_list!(tag_s!(","), struct_field) ~
David Tolnay35161ff2016-09-03 11:33:15 -0700519 space? ~
520 tag_s!(",")? ~
521 space? ~
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700522 tag_s!("}"),
523 move || (Style::Struct, fields)
David Tolnay35161ff2016-09-03 11:33:15 -0700524 )
525 |
526 chain!(
527 tag_s!("(") ~
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700528 fields: separated_list!(tag_s!(","), tuple_field) ~
David Tolnay35161ff2016-09-03 11:33:15 -0700529 space? ~
530 tag_s!(",")? ~
531 space? ~
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700532 tag_s!(")"),
533 move || (Style::Tuple, fields)
David Tolnay35161ff2016-09-03 11:33:15 -0700534 )
535 |
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700536 map!(tag_s!(";"), |_| (Style::Unit, Vec::new()))
537));
538
539named!(variant<&str, Variant>, chain!(
540 attrs: many0!(attribute) ~
541 space? ~
542 ident: word ~
543 space? ~
544 body: struct_body,
545 move || Variant {
546 ident: ident,
547 attrs: attrs,
548 style: body.0,
549 fields: body.1,
550 }
551));
552
553named!(enum_body<&str, Body>, chain!(
554 tag_s!("{") ~
555 variants: separated_list!(tag_s!(","), variant) ~
556 space? ~
557 tag_s!(",")? ~
558 space? ~
559 tag_s!("}"),
560 move || Body::Enum(variants)
561));
562
563named!(lifetime<&str, Lifetime>, preceded!(
564 tag_s!("'"),
565 map!(word, |n| Lifetime { ident: n })
566));
567
568named!(where_predicate<&str, WherePredicate>, preceded!(
569 opt!(space),
570 alt!(
571 map!(lifetime, |_| unimplemented!())
572 |
573 map!(word, |_| unimplemented!())
574 )
575));
576
577named!(lifetime_def<&str, LifetimeDef>, chain!(
578 lifetime: lifetime,
579 move || LifetimeDef {
580 lifetime: lifetime,
581 bounds: Vec::new(),
582 }
583));
584
585named!(ty_param<&str, TyParam>, chain!(
586 space? ~
587 ident: word,
588 move || TyParam {
589 ident: ident,
590 bounds: Vec::new(),
591 default: None,
592 }
593));
594
595named!(generics<&str, Generics>, chain!(
596 bracketed: map!(
597 opt!(chain!(
598 space? ~
599 tag_s!("<") ~
600 lifetimes: separated_list!(tag_s!(","), lifetime_def) ~
601 ty_params: opt!(chain!(
602 space? ~
603 cond!(!lifetimes.is_empty(), tag_s!(",")) ~
604 ty_params: separated_nonempty_list!(tag_s!(","), ty_param),
605 move || ty_params
606 )) ~
607 space? ~
608 tag_s!(">"),
609 move || (lifetimes, ty_params.unwrap_or_else(Vec::new))
610 )),
611 |opt: Option<_>| opt.unwrap_or_else(|| (Vec::new(), Vec::new()))
612 ) ~
613 where_clause: opt!(chain!(
614 tag_s!("where") ~
615 space ~
616 predicates: separated_nonempty_list!(tag_s!(","), where_predicate) ~
617 space? ~
618 tag_s!(",")?,
619 move || predicates
620 )),
621 move || Generics {
622 lifetimes: bracketed.0,
623 ty_params: bracketed.1,
624 where_clause: where_clause.unwrap_or_else(Vec::new),
625 }
David Tolnay35161ff2016-09-03 11:33:15 -0700626));
627
628named!(item<&str, Item>, chain!(
629 attrs: many0!(attribute) ~
630 space? ~
631 vis: visibility ~
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700632 which: alt!(tag_s!("struct") | tag_s!("enum")) ~
David Tolnay35161ff2016-09-03 11:33:15 -0700633 space ~
634 ident: word ~
635 space? ~
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700636 generics: generics ~
637 space? ~
638 item: switch!(value!(which),
639 "struct" => map!(struct_body, move |(style, fields)| Item {
David Tolnay35161ff2016-09-03 11:33:15 -0700640 ident: ident,
641 vis: vis,
642 attrs: attrs,
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700643 generics: generics,
644 body: Body::Struct(style, fields),
645 })
646 |
647 "enum" => map!(enum_body, move |body| Item {
648 ident: ident,
649 vis: vis,
650 attrs: attrs,
651 generics: generics,
David Tolnay35161ff2016-09-03 11:33:15 -0700652 body: body,
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700653 })
654 ) ~
655 space?,
656 move || item
David Tolnay35161ff2016-09-03 11:33:15 -0700657));
658
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700659pub fn parse(input: &str) -> Item {
David Tolnay35161ff2016-09-03 11:33:15 -0700660 match item(input) {
661 IResult::Done(rest, ast) => {
662 if rest.is_empty() {
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700663 ast
David Tolnay35161ff2016-09-03 11:33:15 -0700664 } else {
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700665 panic!("more than a single input item: {:?}", rest)
David Tolnay35161ff2016-09-03 11:33:15 -0700666 }
667 }
David Tolnay7ebb9fb2016-09-03 12:07:47 -0700668 IResult::Error(err) => raise(err),
669 IResult::Incomplete(_) => panic!("incomplete input item"),
670 }
671}
672
673fn raise(mut err: nom::Err<&str>) -> ! {
674 loop {
675 match err {
676 nom::Err::Code(kind) => {
677 panic!("failed to parse {:?}", kind)
678 }
679 nom::Err::Position(kind, pos) => {
680 panic!("failed to parse {:?}: {:?}", kind, pos)
681 }
682 nom::Err::Node(_, next) |
683 nom::Err::NodePosition(_, _, next) => {
684 err = *next;
685 }
David Tolnay35161ff2016-09-03 11:33:15 -0700686 }
David Tolnay35161ff2016-09-03 11:33:15 -0700687 }
688}