diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2014-10-29 18:03:40 -0400 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2014-11-06 06:48:23 -0500 |
| commit | 4e352892c8ca76f49332fb74d9903677dea2c5fe (patch) | |
| tree | f8fef03732b8ed6c40fb031b72d8581cfcd10f96 /src/libsyntax/parse | |
| parent | e84e7a00ddec76570bbaa9afea385d544f616814 (diff) | |
| download | rust-4e352892c8ca76f49332fb74d9903677dea2c5fe.tar.gz rust-4e352892c8ca76f49332fb74d9903677dea2c5fe.zip | |
Restructure parsing of paths, which is quite tortured
Diffstat (limited to 'src/libsyntax/parse')
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 150 |
1 files changed, 108 insertions, 42 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 10bb9ef3625..fd244a443a8 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -1706,50 +1706,18 @@ impl<'a> Parser<'a> { // Parse any number of segments and bound sets. A segment is an // identifier followed by an optional lifetime and a set of types. // A bound set is a set of type parameter bounds. - let mut segments = Vec::new(); - loop { - // First, parse an identifier. - let identifier = self.parse_ident(); - - // Parse the '::' before type parameters if it's required. If - // it is required and wasn't present, then we're done. - if mode == LifetimeAndTypesWithColons && - !self.eat(&token::ModSep) { - segments.push(ast::PathSegment { - identifier: identifier, - lifetimes: Vec::new(), - types: OwnedSlice::empty(), - }); - break + let segments = match mode { + LifetimeAndTypesWithoutColons | + LifetimeAndTypesAndBounds => { + self.parse_path_segments_without_colons() } - - // Parse the `<` before the lifetime and types, if applicable. - let (any_lifetime_or_types, lifetimes, types) = { - if mode != NoTypesAllowed && self.eat_lt(false) { - let (lifetimes, types) = - self.parse_generic_values_after_lt(); - (true, lifetimes, OwnedSlice::from_vec(types)) - } else { - (false, Vec::new(), OwnedSlice::empty()) - } - }; - - // Assemble and push the result. - segments.push(ast::PathSegment { - identifier: identifier, - lifetimes: lifetimes, - types: types, - }); - - // We're done if we don't see a '::', unless the mode required - // a double colon to get here in the first place. - if !(mode == LifetimeAndTypesWithColons && - !any_lifetime_or_types) { - if !self.eat(&token::ModSep) { - break - } + LifetimeAndTypesWithColons => { + self.parse_path_segments_with_colons() } - } + NoTypesAllowed => { + self.parse_path_segments_without_types() + } + }; // Next, parse a plus and bounded type parameters, if // applicable. We need to remember whether the separate was @@ -1792,6 +1760,104 @@ impl<'a> Parser<'a> { } } + /// Examples: + /// - `a::b<T,U>::c<V,W>` + /// - `a::b<T,U>::c(V) -> W` + /// - `a::b<T,U>::c(V)` + pub fn parse_path_segments_without_colons(&mut self) -> Vec<ast::PathSegment> { + let mut segments = Vec::new(); + loop { + // First, parse an identifier. + let identifier = self.parse_ident(); + + // Parse types, optionally. + let (lifetimes, types) = if self.eat_lt(false) { + self.parse_generic_values_after_lt() + } else if false && self.eat(&token::LParen) { + let mut types = self.parse_seq_to_end( + &token::RParen, + seq_sep_trailing_allowed(token::Comma), + |p| p.parse_ty(true)); + + if self.eat(&token::RArrow) { + types.push(self.parse_ty(true)) + } + + (Vec::new(), types) + } else { + (Vec::new(), Vec::new()) + }; + + // Assemble and push the result. + segments.push(ast::PathSegment { identifier: identifier, + lifetimes: lifetimes, + types: OwnedSlice::from_vec(types), }); + + // Continue only if we see a `::` + if !self.eat(&token::ModSep) { + return segments; + } + } + } + + /// Examples: + /// - `a::b::<T,U>::c` + pub fn parse_path_segments_with_colons(&mut self) -> Vec<ast::PathSegment> { + let mut segments = Vec::new(); + loop { + // First, parse an identifier. + let identifier = self.parse_ident(); + + // If we do not see a `::`, stop. + if !self.eat(&token::ModSep) { + segments.push(ast::PathSegment { identifier: identifier, + lifetimes: Vec::new(), + types: OwnedSlice::empty() }); + return segments; + } + + // Check for a type segment. + if self.eat_lt(false) { + // Consumed `a::b::<`, go look for types + let (lifetimes, types) = self.parse_generic_values_after_lt(); + segments.push(ast::PathSegment { identifier: identifier, + lifetimes: lifetimes, + types: OwnedSlice::from_vec(types) }); + + // Consumed `a::b::<T,U>`, check for `::` before proceeding + if !self.eat(&token::ModSep) { + return segments; + } + } else { + // Consumed `a::`, go look for `b` + segments.push(ast::PathSegment { identifier: identifier, + lifetimes: Vec::new(), + types: OwnedSlice::empty() }); + } + } + } + + + /// Examples: + /// - `a::b::c` + pub fn parse_path_segments_without_types(&mut self) -> Vec<ast::PathSegment> { + let mut segments = Vec::new(); + loop { + // First, parse an identifier. + let identifier = self.parse_ident(); + + // Assemble and push the result. + segments.push(ast::PathSegment { identifier: identifier, + lifetimes: Vec::new(), + types: OwnedSlice::empty(), }); + + // If we do not see a `::`, stop. + if !self.eat(&token::ModSep) { + return segments; + } + } + } + /// parses 0 or 1 lifetime pub fn parse_opt_lifetime(&mut self) -> Option<ast::Lifetime> { match self.token { |
