]> git.lizzy.rs Git - rust.git/blobdiff - src/libsyntax/parse/parser.rs
Include unary operator to span for ExprKind::Unary
[rust.git] / src / libsyntax / parse / parser.rs
index 3301a7388c55bb04005cfe5c055dbe21cacb0a8f..3829be40a1e3facd424fcc8bc90208e3b5e938b2 100644 (file)
@@ -64,9 +64,9 @@
 use std::slice;
 
 bitflags! {
-    pub flags Restrictions: u8 {
-        const RESTRICTION_STMT_EXPR         = 1 << 0,
-        const RESTRICTION_NO_STRUCT_LITERAL = 1 << 1,
+    pub struct Restrictions: u8 {
+        const STMT_EXPR         = 1 << 0;
+        const NO_STRUCT_LITERAL = 1 << 1;
     }
 }
 
@@ -481,6 +481,12 @@ fn dummy_arg(span: Span) -> Arg {
     Arg { ty: P(ty), pat: pat, id: ast::DUMMY_NODE_ID }
 }
 
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+enum TokenExpectType {
+    Expect,
+    NoExpect,
+}
+
 impl<'a> Parser<'a> {
     pub fn new(sess: &'a ParseSess,
                tokens: TokenStream,
@@ -797,6 +803,23 @@ fn expect_and(&mut self) -> PResult<'a, ()> {
         }
     }
 
+    /// Expect and consume an `|`. If `||` is seen, replace it with a single
+    /// `|` and continue. If an `|` is not seen, signal an error.
+    fn expect_or(&mut self) -> PResult<'a, ()> {
+        self.expected_tokens.push(TokenType::Token(token::BinOp(token::Or)));
+        match self.token {
+            token::BinOp(token::Or) => {
+                self.bump();
+                Ok(())
+            }
+            token::OrOr => {
+                let span = self.span.with_lo(self.span.lo() + BytePos(1));
+                Ok(self.bump_with(token::BinOp(token::Or), span))
+            }
+            _ => self.unexpected()
+        }
+    }
+
     pub fn expect_no_suffix(&self, sp: Span, kind: &str, suffix: Option<ast::Name>) {
         match suffix {
             None => {/* everything ok */}
@@ -946,6 +969,7 @@ pub fn eat_to_tokens(&mut self, kets: &[&token::Token]) {
 
         self.parse_seq_to_before_tokens(kets,
                                         SeqSep::none(),
+                                        TokenExpectType::Expect,
                                         |p| Ok(p.parse_token_tree()),
                                         |mut e| handler.cancel(&mut e));
     }
@@ -975,13 +999,14 @@ pub fn parse_seq_to_before_end<T, F>(&mut self,
                                          -> Vec<T>
         where F: FnMut(&mut Parser<'a>) -> PResult<'a,  T>
     {
-        self.parse_seq_to_before_tokens(&[ket], sep, f, |mut e| e.emit())
+        self.parse_seq_to_before_tokens(&[ket], sep, TokenExpectType::Expect, f, |mut e| e.emit())
     }
 
     // `fe` is an error handler.
     fn parse_seq_to_before_tokens<T, F, Fe>(&mut self,
                                             kets: &[&token::Token],
                                             sep: SeqSep,
+                                            expect: TokenExpectType,
                                             mut f: F,
                                             mut fe: Fe)
                                             -> Vec<T>
@@ -1005,7 +1030,12 @@ fn parse_seq_to_before_tokens<T, F, Fe>(&mut self,
                     }
                 }
             }
-            if sep.trailing_sep_allowed && kets.iter().any(|k| self.check(k)) {
+            if sep.trailing_sep_allowed && kets.iter().any(|k| {
+                match expect {
+                    TokenExpectType::Expect => self.check(k),
+                    TokenExpectType::NoExpect => self.token == **k,
+                }
+            }) {
                 break;
             }
 
@@ -2210,7 +2240,7 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
                     let e = if self.token.can_begin_expr()
                                && !(self.token == token::OpenDelim(token::Brace)
                                     && self.restrictions.contains(
-                                           RESTRICTION_NO_STRUCT_LITERAL)) {
+                                           Restrictions::NO_STRUCT_LITERAL)) {
                         Some(self.parse_expr()?)
                     } else {
                         None
@@ -2245,7 +2275,7 @@ fn parse_bottom_expr(&mut self) -> PResult<'a, P<Expr>> {
                         // This is a struct literal, unless we're prohibited
                         // from parsing struct literals here.
                         let prohibited = self.restrictions.contains(
-                            RESTRICTION_NO_STRUCT_LITERAL
+                            Restrictions::NO_STRUCT_LITERAL
                         );
                         if !prohibited {
                             return self.parse_struct_expr(lo, pth, attrs);
@@ -2602,7 +2632,7 @@ pub fn parse_prefix_expr(&mut self,
                 self.bump();
                 let e = self.parse_prefix_expr(None);
                 let (span, e) = self.interpolated_or_expr_span(e)?;
-                (span, self.mk_unary(UnOp::Not, e))
+                (lo.to(span), self.mk_unary(UnOp::Not, e))
             }
             // Suggest `!` for bitwise negation when encountering a `~`
             token::Tilde => {
@@ -2615,43 +2645,43 @@ pub fn parse_prefix_expr(&mut self,
                 err.span_label(span_of_tilde, "did you mean `!`?");
                 err.help("use `!` instead of `~` if you meant to perform bitwise negation");
                 err.emit();
-                (span, self.mk_unary(UnOp::Not, e))
+                (lo.to(span), self.mk_unary(UnOp::Not, e))
             }
             token::BinOp(token::Minus) => {
                 self.bump();
                 let e = self.parse_prefix_expr(None);
                 let (span, e) = self.interpolated_or_expr_span(e)?;
-                (span, self.mk_unary(UnOp::Neg, e))
+                (lo.to(span), self.mk_unary(UnOp::Neg, e))
             }
             token::BinOp(token::Star) => {
                 self.bump();
                 let e = self.parse_prefix_expr(None);
                 let (span, e) = self.interpolated_or_expr_span(e)?;
-                (span, self.mk_unary(UnOp::Deref, e))
+                (lo.to(span), self.mk_unary(UnOp::Deref, e))
             }
             token::BinOp(token::And) | token::AndAnd => {
                 self.expect_and()?;
                 let m = self.parse_mutability();
                 let e = self.parse_prefix_expr(None);
                 let (span, e) = self.interpolated_or_expr_span(e)?;
-                (span, ExprKind::AddrOf(m, e))
+                (lo.to(span), ExprKind::AddrOf(m, e))
             }
             token::Ident(..) if self.token.is_keyword(keywords::In) => {
                 self.bump();
                 let place = self.parse_expr_res(
-                    RESTRICTION_NO_STRUCT_LITERAL,
+                    Restrictions::NO_STRUCT_LITERAL,
                     None,
                 )?;
                 let blk = self.parse_block()?;
                 let span = blk.span;
                 let blk_expr = self.mk_expr(span, ExprKind::Block(blk), ThinVec::new());
-                (span, ExprKind::InPlace(place, blk_expr))
+                (lo.to(span), ExprKind::InPlace(place, blk_expr))
             }
             token::Ident(..) if self.token.is_keyword(keywords::Box) => {
                 self.bump();
                 let e = self.parse_prefix_expr(None);
                 let (span, e) = self.interpolated_or_expr_span(e)?;
-                (span, ExprKind::Box(e))
+                (lo.to(span), ExprKind::Box(e))
             }
             _ => return self.parse_dot_or_call_expr(Some(attrs))
         };
@@ -2707,7 +2737,7 @@ pub fn parse_assoc_expr_with(&mut self,
 
             let cur_op_span = self.span;
             let restrictions = if op.is_assign_like() {
-                self.restrictions & RESTRICTION_NO_STRUCT_LITERAL
+                self.restrictions & Restrictions::NO_STRUCT_LITERAL
             } else {
                 self.restrictions
             };
@@ -2770,13 +2800,13 @@ pub fn parse_assoc_expr_with(&mut self,
 
             let rhs = match op.fixity() {
                 Fixity::Right => self.with_res(
-                    restrictions - RESTRICTION_STMT_EXPR,
+                    restrictions - Restrictions::STMT_EXPR,
                     |this| {
                         this.parse_assoc_expr_with(op.precedence(),
                             LhsExpr::NotYetParsed)
                 }),
                 Fixity::Left => self.with_res(
-                    restrictions - RESTRICTION_STMT_EXPR,
+                    restrictions - Restrictions::STMT_EXPR,
                     |this| {
                         this.parse_assoc_expr_with(op.precedence() + 1,
                             LhsExpr::NotYetParsed)
@@ -2784,7 +2814,7 @@ pub fn parse_assoc_expr_with(&mut self,
                 // We currently have no non-associative operators that are not handled above by
                 // the special cases. The code is here only for future convenience.
                 Fixity::None => self.with_res(
-                    restrictions - RESTRICTION_STMT_EXPR,
+                    restrictions - Restrictions::STMT_EXPR,
                     |this| {
                         this.parse_assoc_expr_with(op.precedence() + 1,
                             LhsExpr::NotYetParsed)
@@ -2959,7 +2989,7 @@ fn is_at_start_of_range_notation_rhs(&self) -> bool {
         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::NO_STRUCT_LITERAL);
             }
             true
         } else {
@@ -2973,7 +3003,7 @@ pub fn parse_if_expr(&mut self, attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr
             return self.parse_if_let_expr(attrs);
         }
         let lo = self.prev_span;
-        let cond = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL, None)?;
+        let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
 
         // Verify that the parsed `if` condition makes sense as a condition. If it is a block, then
         // verify that the last statement is either an implicit return (no `;`) or an explicit
@@ -3004,7 +3034,7 @@ pub fn parse_if_let_expr(&mut self, attrs: ThinVec<Attribute>)
         self.expect_keyword(keywords::Let)?;
         let pat = self.parse_pat()?;
         self.expect(&token::Eq)?;
-        let expr = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL, None)?;
+        let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
         let thn = self.parse_block()?;
         let (hi, els) = if self.eat_keyword(keywords::Else) {
             let expr = self.parse_else_expr()?;
@@ -3026,7 +3056,7 @@ pub fn parse_lambda_expr(&mut self,
         let decl_hi = self.prev_span;
         let body = match decl.output {
             FunctionRetTy::Default(_) => {
-                let restrictions = self.restrictions - RESTRICTION_STMT_EXPR;
+                let restrictions = self.restrictions - Restrictions::STMT_EXPR;
                 self.parse_expr_res(restrictions, None)?
             },
             _ => {
@@ -3061,7 +3091,7 @@ pub fn parse_for_expr(&mut self, opt_ident: Option<ast::SpannedIdent>,
 
         let pat = self.parse_pat()?;
         self.expect_keyword(keywords::In)?;
-        let expr = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL, None)?;
+        let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
         let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
 
@@ -3076,7 +3106,7 @@ pub fn parse_while_expr(&mut self, opt_ident: Option<ast::SpannedIdent>,
         if self.token.is_keyword(keywords::Let) {
             return self.parse_while_let_expr(opt_ident, span_lo, attrs);
         }
-        let cond = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL, None)?;
+        let cond = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
         let (iattrs, body) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
         let span = span_lo.to(body.span);
@@ -3090,7 +3120,7 @@ pub fn parse_while_let_expr(&mut self, opt_ident: Option<ast::SpannedIdent>,
         self.expect_keyword(keywords::Let)?;
         let pat = self.parse_pat()?;
         self.expect(&token::Eq)?;
-        let expr = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL, None)?;
+        let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?;
         let (iattrs, body) = self.parse_inner_attrs_and_block()?;
         attrs.extend(iattrs);
         let span = span_lo.to(body.span);
@@ -3120,7 +3150,7 @@ pub fn parse_catch_expr(&mut self, span_lo: Span, mut attrs: ThinVec<Attribute>)
     fn parse_match_expr(&mut self, mut attrs: ThinVec<Attribute>) -> PResult<'a, P<Expr>> {
         let match_span = self.prev_span;
         let lo = self.prev_span;
-        let discriminant = self.parse_expr_res(RESTRICTION_NO_STRUCT_LITERAL,
+        let discriminant = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL,
                                                None)?;
         if let Err(mut e) = self.expect(&token::OpenDelim(token::Brace)) {
             if self.token == token::Token::Semi {
@@ -3168,7 +3198,7 @@ pub fn parse_arm(&mut self) -> PResult<'a, Arm> {
             None
         };
         self.expect(&token::FatArrow)?;
-        let expr = self.parse_expr_res(RESTRICTION_STMT_EXPR, None)?;
+        let expr = self.parse_expr_res(Restrictions::STMT_EXPR, None)?;
 
         let require_comma = classify::expr_requires_semi_to_be_stmt(&expr)
             && self.token != token::CloseDelim(token::Brace);
@@ -3759,7 +3789,7 @@ fn is_catch_expr(&mut self) -> bool {
         self.look_ahead(2, |t| *t == token::OpenDelim(token::Brace)) &&
 
         // prevent `while catch {} {}`, `if catch {} {} else {}`, etc.
-        !self.restrictions.contains(RESTRICTION_NO_STRUCT_LITERAL)
+        !self.restrictions.contains(Restrictions::NO_STRUCT_LITERAL)
     }
 
     fn is_union_item(&self) -> bool {
@@ -3881,7 +3911,7 @@ fn parse_stmt_without_recovery(&mut self,
                     self.mk_expr(lo.to(hi), ExprKind::Path(None, pth), ThinVec::new())
                 };
 
-                let expr = self.with_res(RESTRICTION_STMT_EXPR, |this| {
+                let expr = self.with_res(Restrictions::STMT_EXPR, |this| {
                     let expr = this.parse_dot_or_call_expr_with(expr, lo, attrs.into())?;
                     this.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(expr))
                 })?;
@@ -4022,7 +4052,7 @@ fn parse_stmt_without_recovery(&mut self,
 
                     // Remainder are line-expr stmts.
                     let e = self.parse_expr_res(
-                        RESTRICTION_STMT_EXPR, Some(attrs.into()))?;
+                        Restrictions::STMT_EXPR, Some(attrs.into()))?;
                     Stmt {
                         id: ast::DUMMY_NODE_ID,
                         span: lo.to(e.span),
@@ -4035,7 +4065,7 @@ fn parse_stmt_without_recovery(&mut self,
 
     /// 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::STMT_EXPR) &&
             !classify::expr_requires_semi_to_be_stmt(e)
     }
 
@@ -4694,12 +4724,14 @@ fn parse_fn_block_decl(&mut self) -> PResult<'a, P<FnDecl>> {
                 Vec::new()
             } else {
                 self.expect(&token::BinOp(token::Or))?;
-                let args = self.parse_seq_to_before_end(
-                    &token::BinOp(token::Or),
+                let args = self.parse_seq_to_before_tokens(
+                    &[&token::BinOp(token::Or), &token::OrOr],
                     SeqSep::trailing_allowed(token::Comma),
-                    |p| p.parse_fn_block_arg()
+                    TokenExpectType::NoExpect,
+                    |p| p.parse_fn_block_arg(),
+                    |mut e| e.emit()
                 );
-                self.expect(&token::BinOp(token::Or))?;
+                self.expect_or()?;
                 args
             }
         };