Implement parsing of patterns
diff --git a/src/expr.rs b/src/expr.rs
index 796fe67..a52ef7d 100644
--- a/src/expr.rs
+++ b/src/expr.rs
@@ -2546,31 +2546,37 @@
#[cfg(feature = "full")]
impl Parse for Pat {
fn parse(input: ParseStream) -> Result<Self> {
- // TODO: better error messages
let lookahead = input.lookahead1();
if lookahead.peek(Token![_]) {
input.call(pat_wild).map(Pat::Wild)
} else if lookahead.peek(Token![box]) {
input.call(pat_box).map(Pat::Box)
- } else if input.fork().call(pat_range).is_ok() {
- // must be before Pat::Lit
- input.call(pat_range).map(Pat::Range)
- } else if input.fork().call(pat_tuple_struct).is_ok() {
- // must be before Pat::Ident
- input.call(pat_tuple_struct).map(Pat::TupleStruct)
- } else if input.fork().call(pat_struct).is_ok() {
- // must be before Pat::Ident
- input.call(pat_struct).map(Pat::Struct)
- } else if input.fork().call(pat_macro).is_ok() {
- // must be before Pat::Ident
- input.call(pat_macro).map(Pat::Macro)
- } else if input.fork().call(pat_lit).is_ok() {
- // must be before Pat::Ident
- input.call(pat_lit).map(Pat::Lit)
- } else if input.fork().call(pat_ident).is_ok() {
+ } else if lookahead.peek(Token![-]) || lookahead.peek(Lit) {
+ pat_lit_or_range(input)
+ } else if input.peek(Ident)
+ && ({
+ input.peek2(Token![::])
+ || input.peek2(Token![!])
+ || input.peek2(token::Brace)
+ || input.peek2(token::Paren)
+ || input.peek2(Token![..]) && !{
+ let ahead = input.fork();
+ ahead.parse::<Ident>()?;
+ ahead.parse::<RangeLimits>()?;
+ ahead.is_empty() || ahead.peek(Token![,])
+ }
+ })
+ || input.peek(Token![::])
+ || input.peek(Token![<])
+ || input.peek(Token![self])
+ || input.peek(Token![Self])
+ || input.peek(Token![super])
+ || input.peek(Token![extern])
+ || input.peek(Token![crate])
+ {
+ pat_path_or_macro_or_struct_or_range(input)
+ } else if input.peek(Token![ref]) || input.peek(Token![mut]) || input.peek(Ident) {
input.call(pat_ident).map(Pat::Ident)
- } else if input.fork().call(pat_path).is_ok() {
- input.call(pat_path).map(Pat::Path)
} else if lookahead.peek(token::Paren) {
input.call(pat_tuple).map(Pat::Tuple)
} else if lookahead.peek(Token![&]) {
@@ -2584,6 +2590,60 @@
}
#[cfg(feature = "full")]
+ fn pat_path_or_macro_or_struct_or_range(input: ParseStream) -> Result<Pat> {
+ let (qself, path) = path::parsing::qpath(input, true)?;
+
+ if input.peek(Token![..]) {
+ return pat_range(input, qself, path).map(Pat::Range);
+ }
+
+ if qself.is_some() {
+ return Ok(Pat::Path(PatPath {
+ qself: qself,
+ path: path,
+ }));
+ }
+
+ if input.peek(Token![!]) && !input.peek(Token![!=]) {
+ let mut contains_arguments = false;
+ for segment in &path.segments {
+ match segment.arguments {
+ PathArguments::None => {}
+ PathArguments::AngleBracketed(_) | PathArguments::Parenthesized(_) => {
+ contains_arguments = true;
+ }
+ }
+ }
+
+ if !contains_arguments {
+ let bang_token: Token![!] = input.parse()?;
+ let (delimiter, tts) = mac::parse_delimiter(input)?;
+ return Ok(Pat::Macro(PatMacro {
+ mac: Macro {
+ path: path,
+ bang_token: bang_token,
+ delimiter: delimiter,
+ tts: tts,
+ },
+ }));
+ }
+ }
+
+ if input.peek(token::Brace) {
+ pat_struct(input, path).map(Pat::Struct)
+ } else if input.peek(token::Paren) {
+ pat_tuple_struct(input, path).map(Pat::TupleStruct)
+ } else if input.peek(Token![..]) {
+ pat_range(input, qself, path).map(Pat::Range)
+ } else {
+ Ok(Pat::Path(PatPath {
+ qself: qself,
+ path: path,
+ }))
+ }
+ }
+
+ #[cfg(feature = "full")]
fn pat_wild(input: ParseStream) -> Result<PatWild> {
Ok(PatWild {
underscore_token: input.parse()?,
@@ -2603,17 +2663,7 @@
Ok(PatIdent {
by_ref: input.parse()?,
mutability: input.parse()?,
- ident: {
- let ident = if input.peek(Ident) || input.peek(Token![self]) {
- input.call(Ident::parse_any)?
- } else {
- return Err(input.error("expected identifier or `self`"));
- };
- if input.peek(Token![<]) || input.peek(Token![::]) {
- return Err(input.error("unexpected token"));
- }
- ident
- },
+ ident: input.call(Ident::parse_any)?,
subpat: {
if input.peek(Token![@]) {
let at_token: Token![@] = input.parse()?;
@@ -2627,17 +2677,15 @@
}
#[cfg(feature = "full")]
- fn pat_tuple_struct(input: ParseStream) -> Result<PatTupleStruct> {
+ fn pat_tuple_struct(input: ParseStream, path: Path) -> Result<PatTupleStruct> {
Ok(PatTupleStruct {
- path: input.parse()?,
+ path: path,
pat: input.call(pat_tuple)?,
})
}
#[cfg(feature = "full")]
- fn pat_struct(input: ParseStream) -> Result<PatStruct> {
- let path: Path = input.parse()?;
-
+ fn pat_struct(input: ParseStream, path: Path) -> Result<PatStruct> {
let content;
let brace_token = braced!(content in input);
@@ -2738,11 +2786,15 @@
}
#[cfg(feature = "full")]
- fn pat_path(input: ParseStream) -> Result<PatPath> {
- let p: ExprPath = input.parse()?;
- Ok(PatPath {
- qself: p.qself,
- path: p.path,
+ fn pat_range(input: ParseStream, qself: Option<QSelf>, path: Path) -> Result<PatRange> {
+ Ok(PatRange {
+ lo: Box::new(Expr::Path(ExprPath {
+ attrs: Vec::new(),
+ qself: qself,
+ path: path,
+ })),
+ limits: input.parse()?,
+ hi: input.call(pat_lit_expr)?,
})
}
@@ -2802,26 +2854,20 @@
}
#[cfg(feature = "full")]
- fn pat_lit(input: ParseStream) -> Result<PatLit> {
- if input.peek(Lit) || input.peek(Token![-]) && input.peek2(Lit) {
- Ok(PatLit {
- expr: input.call(pat_lit_expr)?,
- })
+ fn pat_lit_or_range(input: ParseStream) -> Result<Pat> {
+ let lo = input.call(pat_lit_expr)?;
+ if input.peek(Token![..]) {
+ Ok(Pat::Range(PatRange {
+ lo: lo,
+ limits: input.parse()?,
+ hi: input.call(pat_lit_expr)?,
+ }))
} else {
- Err(input.error("expected literal pattern"))
+ Ok(Pat::Lit(PatLit { expr: lo }))
}
}
#[cfg(feature = "full")]
- fn pat_range(input: ParseStream) -> Result<PatRange> {
- Ok(PatRange {
- lo: input.call(pat_lit_expr)?,
- limits: input.parse()?,
- hi: input.call(pat_lit_expr)?,
- })
- }
-
- #[cfg(feature = "full")]
fn pat_lit_expr(input: ParseStream) -> Result<Box<Expr>> {
let neg: Option<Token![-]> = input.parse()?;
@@ -2909,13 +2955,6 @@
}
#[cfg(feature = "full")]
- fn pat_macro(input: ParseStream) -> Result<PatMacro> {
- Ok(PatMacro {
- mac: input.parse()?,
- })
- }
-
- #[cfg(feature = "full")]
impl Member {
fn is_named(&self) -> bool {
match *self {