diff options
| author | Nick Cameron <ncameron@mozilla.com> | 2015-04-30 22:30:50 +1200 |
|---|---|---|
| committer | Nick Cameron <ncameron@mozilla.com> | 2015-04-30 22:30:50 +1200 |
| commit | b2ddd937b20d8fc26132cb7ec665784422d92926 (patch) | |
| tree | cf257df60ded1b45616d797b8feb71178cab0142 /src/libsyntax/parse/parser.rs | |
| parent | c0a42aecbc85298fb6351253c4cd1824567b7a42 (diff) | |
| parent | f0bd14f7b15b978f8bf32bb368f63faa0f26c02e (diff) | |
| download | rust-b2ddd937b20d8fc26132cb7ec665784422d92926.tar.gz rust-b2ddd937b20d8fc26132cb7ec665784422d92926.zip | |
Merge branch 'master' into mulit-decor
Diffstat (limited to 'src/libsyntax/parse/parser.rs')
| -rw-r--r-- | src/libsyntax/parse/parser.rs | 292 |
1 files changed, 192 insertions, 100 deletions
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs index 68006a8979a..5f76c214927 100644 --- a/src/libsyntax/parse/parser.rs +++ b/src/libsyntax/parse/parser.rs @@ -17,8 +17,8 @@ use ast::{Public, Unsafety}; use ast::{Mod, BiAdd, Arg, Arm, Attribute, BindByRef, BindByValue}; use ast::{BiBitAnd, BiBitOr, BiBitXor, BiRem, BiLt, BiGt, Block}; use ast::{BlockCheckMode, CaptureByRef, CaptureByValue, CaptureClause}; -use ast::{Crate, CrateConfig, Decl, DeclItem}; -use ast::{DeclLocal, DefaultBlock, DefaultReturn}; +use ast::{ConstImplItem, ConstTraitItem, Crate, CrateConfig}; +use ast::{Decl, DeclItem, DeclLocal, DefaultBlock, DefaultReturn}; use ast::{UnDeref, BiDiv, EMPTY_CTXT, EnumDef, ExplicitSelf}; use ast::{Expr, Expr_, ExprAddrOf, ExprMatch, ExprAgain}; use ast::{ExprAssign, ExprAssignOp, ExprBinary, ExprBlock, ExprBox}; @@ -40,8 +40,9 @@ use ast::{MacStmtWithBraces, MacStmtWithSemicolon, MacStmtWithoutBraces}; use ast::{MutImmutable, MutMutable, Mac_, MacInvocTT, MatchSource}; use ast::{MutTy, BiMul, Mutability}; use ast::{MethodImplItem, NamedField, UnNeg, NoReturn, UnNot}; -use ast::{Pat, PatBox, PatEnum, PatIdent, PatLit, PatMac, PatRange, PatRegion}; -use ast::{PatStruct, PatTup, PatVec, PatWild, PatWildMulti, PatWildSingle}; +use ast::{Pat, PatBox, PatEnum, PatIdent, PatLit, PatQPath, PatMac, PatRange}; +use ast::{PatRegion, PatStruct, PatTup, PatVec, PatWild, PatWildMulti}; +use ast::PatWildSingle; use ast::{PolyTraitRef, QSelf}; use ast::{Return, BiShl, BiShr, Stmt, StmtDecl}; use ast::{StmtExpr, StmtSemi, StmtMac, StructDef, StructField}; @@ -87,9 +88,9 @@ use std::slice; bitflags! { flags Restrictions: u8 { - const UNRESTRICTED = 0b0000, - const RESTRICTION_STMT_EXPR = 0b0001, - const RESTRICTION_NO_STRUCT_LITERAL = 0b0010, + const UNRESTRICTED = 0, + const RESTRICTION_STMT_EXPR = 1 << 0, + const RESTRICTION_NO_STRUCT_LITERAL = 1 << 1, } } @@ -109,6 +110,15 @@ pub enum PathParsingMode { LifetimeAndTypesWithColons, } +/// How to parse a qualified path, whether to allow trailing parameters. +#[derive(Copy, Clone, PartialEq)] +pub enum QPathParsingMode { + /// No trailing parameters, e.g. `<T as Trait>::Item` + NoParameters, + /// Optional parameters, e.g. `<T as Trait>::item::<'a, U>` + MaybeParameters, +} + /// How to parse a bound, whether to allow bound modifiers such as `?`. #[derive(Copy, Clone, PartialEq)] pub enum BoundParsingMode { @@ -329,7 +339,7 @@ impl<'a> Parser<'a> { buffer_start: 0, buffer_end: 0, tokens_consumed: 0, - restrictions: UNRESTRICTED, + restrictions: Restrictions::UNRESTRICTED, quote_depth: 0, obsolete_set: HashSet::new(), mod_path_stack: Vec::new(), @@ -902,7 +912,9 @@ impl<'a> Parser<'a> { pub fn bump(&mut self) -> PResult<()> { self.last_span = self.span; // Stash token for error recovery (sometimes; clone is not necessarily cheap). - self.last_token = if self.token.is_ident() || self.token.is_path() { + self.last_token = if self.token.is_ident() || + self.token.is_path() || + self.token == token::Comma { Some(Box::new(self.token.clone())) } else { None @@ -1150,7 +1162,8 @@ impl<'a> Parser<'a> { &token::OpenDelim(token::Brace), &token::CloseDelim(token::Brace), seq_sep_none(), - |p| { + |p| -> PResult<P<TraitItem>> { + maybe_whole!(no_clone p, NtTraitItem); let mut attrs = p.parse_outer_attributes(); let lo = p.span.lo; @@ -1158,6 +1171,20 @@ impl<'a> Parser<'a> { let TyParam {ident, bounds, default, ..} = try!(p.parse_ty_param()); try!(p.expect(&token::Semi)); (ident, TypeTraitItem(bounds, default)) + } else if try!(p.eat_keyword(keywords::Const)) { + let ident = try!(p.parse_ident()); + try!(p.expect(&token::Colon)); + let ty = try!(p.parse_ty_sum()); + let default = if p.check(&token::Eq) { + try!(p.bump()); + let expr = try!(p.parse_expr_nopanic()); + try!(p.commit_expr_expecting(&expr, token::Semi)); + Some(expr) + } else { + try!(p.expect(&token::Semi)); + None + }; + (ident, ConstTraitItem(ty, default)) } else { let style = try!(p.parse_unsafety()); let abi = if try!(p.eat_keyword(keywords::Extern)) { @@ -1331,36 +1358,9 @@ impl<'a> Parser<'a> { try!(self.expect(&token::CloseDelim(token::Paren))); TyTypeof(e) } else if try!(self.eat_lt()) { - // QUALIFIED PATH `<TYPE as TRAIT_REF>::item` - let self_type = try!(self.parse_ty_sum()); - - let mut path = if try!(self.eat_keyword(keywords::As) ){ - try!(self.parse_path(LifetimeAndTypesWithoutColons)) - } else { - ast::Path { - span: self.span, - global: false, - segments: vec![] - } - }; - - let qself = QSelf { - ty: self_type, - position: path.segments.len() - }; - try!(self.expect(&token::Gt)); - try!(self.expect(&token::ModSep)); - - path.segments.push(ast::PathSegment { - identifier: try!(self.parse_ident()), - parameters: ast::PathParameters::none() - }); - - if path.segments.len() == 1 { - path.span.lo = self.last_span.lo; - } - path.span.hi = self.last_span.hi; + let (qself, path) = + try!(self.parse_qualified_path(QPathParsingMode::NoParameters)); TyPath(Some(qself), path) } else if self.check(&token::ModSep) || @@ -1577,6 +1577,61 @@ impl<'a> Parser<'a> { } } + // QUALIFIED PATH `<TYPE [as TRAIT_REF]>::IDENT[::<PARAMS>]` + // Assumes that the leading `<` has been parsed already. + pub fn parse_qualified_path(&mut self, mode: QPathParsingMode) + -> PResult<(QSelf, ast::Path)> { + let self_type = try!(self.parse_ty_sum()); + let mut path = if try!(self.eat_keyword(keywords::As)) { + try!(self.parse_path(LifetimeAndTypesWithoutColons)) + } else { + ast::Path { + span: self.span, + global: false, + segments: vec![] + } + }; + + let qself = QSelf { + ty: self_type, + position: path.segments.len() + }; + + try!(self.expect(&token::Gt)); + try!(self.expect(&token::ModSep)); + + let item_name = try!(self.parse_ident()); + let parameters = match mode { + QPathParsingMode::NoParameters => ast::PathParameters::none(), + QPathParsingMode::MaybeParameters => { + if try!(self.eat(&token::ModSep)) { + try!(self.expect_lt()); + // Consumed `item::<`, go look for types + let (lifetimes, types, bindings) = + try!(self.parse_generic_values_after_lt()); + ast::AngleBracketedParameters(ast::AngleBracketedParameterData { + lifetimes: lifetimes, + types: OwnedSlice::from_vec(types), + bindings: OwnedSlice::from_vec(bindings), + }) + } else { + ast::PathParameters::none() + } + } + }; + path.segments.push(ast::PathSegment { + identifier: item_name, + parameters: parameters + }); + + if path.segments.len() == 1 { + path.span.lo = self.last_span.lo; + } + path.span.hi = self.last_span.hi; + + Ok((qself, path)) + } + /// Parses a path and optional type parameter bounds, depending on the /// mode. The `mode` parameter determines whether lifetimes, types, and/or /// bounds are permitted and whether `::` must precede type parameter @@ -2040,49 +2095,10 @@ impl<'a> Parser<'a> { } _ => { if try!(self.eat_lt()){ - // QUALIFIED PATH `<TYPE as TRAIT_REF>::item::<'a, T>` - let self_type = try!(self.parse_ty_sum()); - let mut path = if try!(self.eat_keyword(keywords::As) ){ - try!(self.parse_path(LifetimeAndTypesWithoutColons)) - } else { - ast::Path { - span: self.span, - global: false, - segments: vec![] - } - }; - let qself = QSelf { - ty: self_type, - position: path.segments.len() - }; - try!(self.expect(&token::Gt)); - try!(self.expect(&token::ModSep)); - let item_name = try!(self.parse_ident()); - let parameters = if try!(self.eat(&token::ModSep) ){ - try!(self.expect_lt()); - // Consumed `item::<`, go look for types - let (lifetimes, types, bindings) = - try!(self.parse_generic_values_after_lt()); - ast::AngleBracketedParameters(ast::AngleBracketedParameterData { - lifetimes: lifetimes, - types: OwnedSlice::from_vec(types), - bindings: OwnedSlice::from_vec(bindings), - }) - } else { - ast::PathParameters::none() - }; - path.segments.push(ast::PathSegment { - identifier: item_name, - parameters: parameters - }); - - if path.segments.len() == 1 { - path.span.lo = self.last_span.lo; - } - path.span.hi = self.last_span.hi; + let (qself, path) = + try!(self.parse_qualified_path(QPathParsingMode::MaybeParameters)); - let hi = self.span.hi; return Ok(self.mk_expr(lo, hi, ExprPath(Some(qself), path))); } if try!(self.eat_keyword(keywords::Move) ){ @@ -2182,7 +2198,10 @@ impl<'a> Parser<'a> { if self.check(&token::OpenDelim(token::Brace)) { // This is a struct literal, unless we're prohibited // from parsing struct literals here. - if !self.restrictions.contains(RESTRICTION_NO_STRUCT_LITERAL) { + let prohibited = self.restrictions.contains( + Restrictions::RESTRICTION_NO_STRUCT_LITERAL + ); + if !prohibited { // It's a struct literal. try!(self.bump()); let mut fields = Vec::new(); @@ -2743,7 +2762,7 @@ impl<'a> Parser<'a> { } pub fn parse_assign_expr_with(&mut self, lhs: P<Expr>) -> PResult<P<Expr>> { - let restrictions = self.restrictions & RESTRICTION_NO_STRUCT_LITERAL; + let restrictions = self.restrictions & Restrictions::RESTRICTION_NO_STRUCT_LITERAL; let op_span = self.span; match self.token { token::Eq => { @@ -2798,7 +2817,7 @@ impl<'a> Parser<'a> { if self.token.can_begin_expr() { // parse `for i in 1.. { }` as infinite loop, not as `for i in (1..{})`. if self.token == token::OpenDelim(token::Brace) { - return !self.restrictions.contains(RESTRICTION_NO_STRUCT_LITERAL); + return !self.restrictions.contains(Restrictions::RESTRICTION_NO_STRUCT_LITERAL); } true } else { @@ -2812,7 +2831,7 @@ impl<'a> Parser<'a> { return self.parse_if_let_expr(); } let lo = self.last_span.lo; - let cond = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL)); + let cond = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL)); let thn = try!(self.parse_block()); let mut els: Option<P<Expr>> = None; let mut hi = thn.span.hi; @@ -2830,7 +2849,7 @@ impl<'a> Parser<'a> { try!(self.expect_keyword(keywords::Let)); let pat = try!(self.parse_pat_nopanic()); try!(self.expect(&token::Eq)); - let expr = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL)); + let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL)); let thn = try!(self.parse_block()); let (hi, els) = if try!(self.eat_keyword(keywords::Else) ){ let expr = try!(self.parse_else_expr()); @@ -2889,7 +2908,7 @@ impl<'a> Parser<'a> { let lo = self.last_span.lo; let pat = try!(self.parse_pat_nopanic()); try!(self.expect_keyword(keywords::In)); - let expr = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL)); + let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL)); let loop_block = try!(self.parse_block()); let hi = self.last_span.hi; @@ -2902,7 +2921,7 @@ impl<'a> Parser<'a> { return self.parse_while_let_expr(opt_ident); } let lo = self.last_span.lo; - let cond = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL)); + let cond = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL)); let body = try!(self.parse_block()); let hi = body.span.hi; return Ok(self.mk_expr(lo, hi, ExprWhile(cond, body, opt_ident))); @@ -2914,7 +2933,7 @@ impl<'a> Parser<'a> { try!(self.expect_keyword(keywords::Let)); let pat = try!(self.parse_pat_nopanic()); try!(self.expect(&token::Eq)); - let expr = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL)); + let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL)); let body = try!(self.parse_block()); let hi = body.span.hi; return Ok(self.mk_expr(lo, hi, ExprWhileLet(pat, expr, body, opt_ident))); @@ -2929,7 +2948,7 @@ impl<'a> Parser<'a> { fn parse_match_expr(&mut self) -> PResult<P<Expr>> { let lo = self.last_span.lo; - let discriminant = try!(self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL)); + let discriminant = try!(self.parse_expr_res(Restrictions::RESTRICTION_NO_STRUCT_LITERAL)); try!(self.commit_expr_expecting(&*discriminant, token::OpenDelim(token::Brace))); let mut arms: Vec<Arm> = Vec::new(); while self.token != token::CloseDelim(token::Brace) { @@ -2941,6 +2960,8 @@ impl<'a> Parser<'a> { } pub fn parse_arm_nopanic(&mut self) -> PResult<Arm> { + maybe_whole!(no_clone self, NtArm); + let attrs = self.parse_outer_attributes(); let pats = try!(self.parse_pats()); let mut guard = None; @@ -2948,7 +2969,7 @@ impl<'a> Parser<'a> { guard = Some(try!(self.parse_expr_nopanic())); } try!(self.expect(&token::FatArrow)); - let expr = try!(self.parse_expr_res(RESTRICTION_STMT_EXPR)); + let expr = try!(self.parse_expr_res(Restrictions::RESTRICTION_STMT_EXPR)); let require_comma = !classify::expr_is_simple_block(&*expr) @@ -2970,7 +2991,7 @@ impl<'a> Parser<'a> { /// Parse an expression pub fn parse_expr_nopanic(&mut self) -> PResult<P<Expr>> { - return self.parse_expr_res(UNRESTRICTED); + return self.parse_expr_res(Restrictions::UNRESTRICTED); } /// Parse an expression, subject to the given restrictions @@ -3153,16 +3174,25 @@ impl<'a> Parser<'a> { fn parse_pat_range_end(&mut self) -> PResult<P<Expr>> { if self.is_path_start() { let lo = self.span.lo; - let path = try!(self.parse_path(LifetimeAndTypesWithColons)); + let (qself, path) = if try!(self.eat_lt()) { + // Parse a qualified path + let (qself, path) = + try!(self.parse_qualified_path(QPathParsingMode::NoParameters)); + (Some(qself), path) + } else { + // Parse an unqualified path + (None, try!(self.parse_path(LifetimeAndTypesWithColons))) + }; let hi = self.last_span.hi; - Ok(self.mk_expr(lo, hi, ExprPath(None, path))) + Ok(self.mk_expr(lo, hi, ExprPath(qself, path))) } else { self.parse_literal_maybe_minus() } } fn is_path_start(&self) -> bool { - (self.token == token::ModSep || self.token.is_ident() || self.token.is_path()) + (self.token == token::Lt || self.token == token::ModSep + || self.token.is_ident() || self.token.is_path()) && !self.token.is_keyword(keywords::True) && !self.token.is_keyword(keywords::False) } @@ -3238,25 +3268,44 @@ impl<'a> Parser<'a> { pat = try!(self.parse_pat_ident(BindByValue(MutImmutable))); } } else { - // Parse as a general path - let path = try!(self.parse_path(LifetimeAndTypesWithColons)); + let (qself, path) = if try!(self.eat_lt()) { + // Parse a qualified path + let (qself, path) = + try!(self.parse_qualified_path(QPathParsingMode::NoParameters)); + (Some(qself), path) + } else { + // Parse an unqualified path + (None, try!(self.parse_path(LifetimeAndTypesWithColons))) + }; match self.token { token::DotDotDot => { // Parse range let hi = self.last_span.hi; - let begin = self.mk_expr(lo, hi, ExprPath(None, path)); + let begin = self.mk_expr(lo, hi, ExprPath(qself, path)); try!(self.bump()); let end = try!(self.parse_pat_range_end()); pat = PatRange(begin, end); } token::OpenDelim(token::Brace) => { - // Parse struct pattern + if qself.is_some() { + let span = self.span; + self.span_err(span, + "unexpected `{` after qualified path"); + self.abort_if_errors(); + } + // Parse struct pattern try!(self.bump()); let (fields, etc) = try!(self.parse_pat_fields()); try!(self.bump()); pat = PatStruct(path, fields, etc); } token::OpenDelim(token::Paren) => { + if qself.is_some() { + let span = self.span; + self.span_err(span, + "unexpected `(` after qualified path"); + self.abort_if_errors(); + } // Parse tuple struct or enum pattern if self.look_ahead(1, |t| *t == token::DotDot) { // This is a "top constructor only" pat @@ -3273,6 +3322,10 @@ impl<'a> Parser<'a> { pat = PatEnum(path, Some(args)); } } + _ if qself.is_some() => { + // Parse qualified path + pat = PatQPath(qself.unwrap(), path); + } _ => { // Parse nullary enum pat = PatEnum(path, Some(vec![])); @@ -3514,7 +3567,7 @@ impl<'a> Parser<'a> { } // Remainder are line-expr stmts. - let e = try!(self.parse_expr_res(RESTRICTION_STMT_EXPR)); + let e = try!(self.parse_expr_res(Restrictions::RESTRICTION_STMT_EXPR)); spanned(lo, e.span.hi, StmtExpr(e, ast::DUMMY_NODE_ID)) } } @@ -3523,7 +3576,7 @@ impl<'a> Parser<'a> { /// Is this expression a successfully-parsed statement? fn expr_is_complete(&mut self, e: &Expr) -> bool { - self.restrictions.contains(RESTRICTION_STMT_EXPR) && + self.restrictions.contains(Restrictions::RESTRICTION_STMT_EXPR) && !classify::expr_requires_semi_to_be_stmt(e) } @@ -3807,8 +3860,37 @@ impl<'a> Parser<'a> { fn parse_generic_values_after_lt(&mut self) -> PResult<(Vec<ast::Lifetime>, Vec<P<Ty>>, Vec<P<TypeBinding>>)> { + let span_lo = self.span.lo; let lifetimes = try!(self.parse_lifetimes(token::Comma)); + let missing_comma = !lifetimes.is_empty() && + !self.token.is_like_gt() && + self.last_token + .as_ref().map_or(true, + |x| &**x != &token::Comma); + + if missing_comma { + + let msg = format!("expected `,` or `>` after lifetime \ + name, found `{}`", + self.this_token_to_string()); + self.span_err(self.span, &msg); + + let span_hi = self.span.hi; + let span_hi = if self.parse_ty_nopanic().is_ok() { + self.span.hi + } else { + span_hi + }; + + let msg = format!("did you mean a single argument type &'a Type, \ + or did you mean the comma-separated arguments \ + 'a, Type?"); + self.span_note(mk_sp(span_lo, span_hi), &msg); + + self.abort_if_errors() + } + // First parse types. let (types, returned) = try!(self.parse_seq_to_gt_or_return( Some(token::Comma), @@ -4304,6 +4386,8 @@ impl<'a> Parser<'a> { /// Parse an impl item. pub fn parse_impl_item(&mut self) -> PResult<P<ImplItem>> { + maybe_whole!(no_clone self, NtImplItem); + let mut attrs = self.parse_outer_attributes(); let lo = self.span.lo; let vis = try!(self.parse_visibility()); @@ -4313,6 +4397,14 @@ impl<'a> Parser<'a> { let typ = try!(self.parse_ty_sum()); try!(self.expect(&token::Semi)); (name, TypeImplItem(typ)) + } else if try!(self.eat_keyword(keywords::Const)) { + let name = try!(self.parse_ident()); + try!(self.expect(&token::Colon)); + let typ = try!(self.parse_ty_sum()); + try!(self.expect(&token::Eq)); + let expr = try!(self.parse_expr_nopanic()); + try!(self.commit_expr_expecting(&expr, token::Semi)); + (name, ConstImplItem(typ, expr)) } else { let (name, inner_attrs, node) = try!(self.parse_impl_method(vis)); attrs.extend(inner_attrs.into_iter()); |
