summary refs log tree commit diff
path: root/src/libsyntax
diff options
context:
space:
mode:
authorJeffrey Seyfried <jeffrey.seyfried@gmail.com>2016-07-02 09:01:21 +0000
committerJeffrey Seyfried <jeffrey.seyfried@gmail.com>2016-07-12 04:31:13 +0000
commit6189e6cdba6d12ab65baafd95c5f8a6e0cc37937 (patch)
tree68ce7a7ccc4d4ca3cc70c10f935a5ecb0055951b /src/libsyntax
parent3265bd54b5b3f32d038273afec7554f007a5ce1d (diff)
downloadrust-6189e6cdba6d12ab65baafd95c5f8a6e0cc37937.tar.gz
rust-6189e6cdba6d12ab65baafd95c5f8a6e0cc37937.zip
Clean up statement parsing without changing the semantics of `parse_stmt`.
Diffstat (limited to 'src/libsyntax')
-rw-r--r--src/libsyntax/ast.rs13
-rw-r--r--src/libsyntax/ext/expand.rs9
-rw-r--r--src/libsyntax/parse/parser.rs149
3 files changed, 59 insertions, 112 deletions
diff --git a/src/libsyntax/ast.rs b/src/libsyntax/ast.rs
index cc033cec8b8..99e37ec80c0 100644
--- a/src/libsyntax/ast.rs
+++ b/src/libsyntax/ast.rs
@@ -804,6 +804,19 @@ pub struct Stmt {
     pub span: Span,
 }
 
+impl Stmt {
+    pub fn add_trailing_semicolon(mut self) -> Self {
+        self.node = match self.node {
+            StmtKind::Expr(expr) => StmtKind::Semi(expr),
+            StmtKind::Mac(mac) => StmtKind::Mac(mac.map(|(mac, _style, attrs)| {
+                (mac, MacStmtStyle::Semicolon, attrs)
+            })),
+            node @ _ => node,
+        };
+        self
+    }
+}
+
 impl fmt::Debug for Stmt {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         write!(f, "stmt({}: {})", self.id.to_string(), pprust::stmt_to_string(self))
diff --git a/src/libsyntax/ext/expand.rs b/src/libsyntax/ext/expand.rs
index b2b63d0dbb4..220e0a753c3 100644
--- a/src/libsyntax/ext/expand.rs
+++ b/src/libsyntax/ext/expand.rs
@@ -444,14 +444,7 @@ fn expand_stmt(stmt: Stmt, fld: &mut MacroExpander) -> SmallVector<Stmt> {
     // semicolon to the final statement produced by expansion.
     if style == MacStmtStyle::Semicolon {
         if let Some(stmt) = fully_expanded.pop() {
-            fully_expanded.push(Stmt {
-                id: stmt.id,
-                node: match stmt.node {
-                    StmtKind::Expr(expr) => StmtKind::Semi(expr),
-                    _ => stmt.node /* might already have a semi */
-                },
-                span: stmt.span,
-            });
+            fully_expanded.push(stmt.add_trailing_semicolon());
         }
     }
 
diff --git a/src/libsyntax/parse/parser.rs b/src/libsyntax/parse/parser.rs
index e4875b7c244..0dd8c199827 100644
--- a/src/libsyntax/parse/parser.rs
+++ b/src/libsyntax/parse/parser.rs
@@ -3789,7 +3789,13 @@ impl<'a> Parser<'a> {
         self.span_err(self.last_span, message);
     }
 
-    /// Parse a statement. may include decl.
+    /// Parse a statement. This stops just before trailing semicolons on everything but items.
+    /// e.g. a `StmtKind::Semi` parses to a `StmtKind::Expr`, leaving the trailing `;` unconsumed.
+    ///
+    /// Also, if a macro begins an expression statement, this only parses the macro. For example,
+    /// ```rust
+    /// vec![1].into_iter(); //< `parse_stmt` only parses the "vec![1]"
+    /// ```
     pub fn parse_stmt(&mut self) -> PResult<'a, Option<Stmt>> {
         Ok(self.parse_stmt_())
     }
@@ -4038,36 +4044,14 @@ impl<'a> Parser<'a> {
         let mut stmts = vec![];
 
         while !self.eat(&token::CloseDelim(token::Brace)) {
-            let Stmt {node, span, ..} = if let Some(s) = self.parse_stmt_() {
-                s
+            if let Some(stmt) = self.parse_stmt_() {
+                stmts.push(self.finish_parsing_statement(stmt)?);
             } else if self.token == token::Eof {
                 break;
             } else {
                 // Found only `;` or `}`.
                 continue;
             };
-
-            match node {
-                StmtKind::Expr(e) => {
-                    self.handle_expression_like_statement(e, span, &mut stmts)?;
-                }
-                StmtKind::Mac(mac) => {
-                    self.handle_macro_in_block(mac.unwrap(), span, &mut stmts)?;
-                }
-                _ => { // all other kinds of statements:
-                    let mut hi = span.hi;
-                    if classify::stmt_ends_with_semi(&node) {
-                        self.expect(&token::Semi)?;
-                        hi = self.last_span.hi;
-                    }
-
-                    stmts.push(Stmt {
-                        id: ast::DUMMY_NODE_ID,
-                        node: node,
-                        span: mk_sp(span.lo, hi)
-                    });
-                }
-            }
         }
 
         Ok(P(ast::Block {
@@ -4078,93 +4062,50 @@ impl<'a> Parser<'a> {
         }))
     }
 
-    fn handle_macro_in_block(&mut self,
-                             (mac, style, attrs): (ast::Mac, MacStmtStyle, ThinVec<Attribute>),
-                             span: Span,
-                             stmts: &mut Vec<Stmt>)
-                             -> PResult<'a, ()> {
-        if style == MacStmtStyle::NoBraces {
-            // statement macro without braces; might be an
-            // expr depending on whether a semicolon follows
-            match self.token {
-                token::Semi => {
-                    stmts.push(Stmt {
-                        id: ast::DUMMY_NODE_ID,
-                        node: StmtKind::Mac(P((mac, MacStmtStyle::Semicolon, attrs))),
-                        span: mk_sp(span.lo, self.span.hi),
-                    });
-                    self.bump();
-                }
-                _ => {
-                    let e = self.mk_mac_expr(span.lo, span.hi, mac.node, ThinVec::new());
-                    let lo = e.span.lo;
-                    let e = self.parse_dot_or_call_expr_with(e, lo, attrs)?;
-                    let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
-                    self.handle_expression_like_statement(e, span, stmts)?;
-                }
-            }
-        } else {
-            // statement macro; might be an expr
-            match self.token {
-                token::Semi => {
-                    stmts.push(Stmt {
-                        id: ast::DUMMY_NODE_ID,
-                        node: StmtKind::Mac(P((mac, MacStmtStyle::Semicolon, attrs))),
-                        span: mk_sp(span.lo, self.span.hi),
-                    });
-                    self.bump();
-                }
-                _ => {
-                    stmts.push(Stmt {
-                        id: ast::DUMMY_NODE_ID,
-                        node: StmtKind::Mac(P((mac, style, attrs))),
-                        span: span
-                    });
-                }
+    /// Finish parsing expressions that start with macros and handle trailing semicolons
+    /// (or the lack thereof) -- c.f. `parse_stmt`.
+    fn finish_parsing_statement(&mut self, mut stmt: Stmt) -> PResult<'a, Stmt> {
+        if let StmtKind::Mac(mac) = stmt.node {
+            if mac.1 != MacStmtStyle::NoBraces || self.token == token::Semi {
+                stmt.node = StmtKind::Mac(mac);
+            } else {
+                let (mac, _style, attrs) = mac.unwrap();
+                let e = self.mk_mac_expr(stmt.span.lo, stmt.span.hi, mac.node, ThinVec::new());
+                let e = self.parse_dot_or_call_expr_with(e, stmt.span.lo, attrs)?;
+                let e = self.parse_assoc_expr_with(0, LhsExpr::AlreadyParsed(e))?;
+                stmt.node = StmtKind::Expr(e);
             }
         }
-        Ok(())
+
+        self.handle_trailing_semicolon(stmt)
     }
 
-    fn handle_expression_like_statement(&mut self,
-                                        e: P<Expr>,
-                                        span: Span,
-                                        stmts: &mut Vec<Stmt>)
-                                        -> PResult<'a, ()> {
-        // expression without semicolon
-        if classify::expr_requires_semi_to_be_stmt(&e) {
-            // Just check for errors and recover; do not eat semicolon yet.
-            if let Err(mut e) =
-                self.expect_one_of(&[], &[token::Semi, token::CloseDelim(token::Brace)])
-            {
-                e.emit();
-                self.recover_stmt();
+    fn handle_trailing_semicolon(&mut self, mut stmt: Stmt) -> PResult<'a, Stmt> {
+        match stmt.node {
+            StmtKind::Expr(ref expr) => {
+                // expression without semicolon
+                if classify::expr_requires_semi_to_be_stmt(expr) {
+                    // Just check for errors and recover; do not eat semicolon yet.
+                    if let Err(mut e) =
+                        self.expect_one_of(&[], &[token::Semi, token::CloseDelim(token::Brace)])
+                    {
+                        e.emit();
+                        self.recover_stmt();
+                    }
+                }
             }
+            StmtKind::Local(..) => {
+                self.expect_one_of(&[token::Semi], &[])?;
+            }
+            _ => {}
         }
 
-        match self.token {
-            token::Semi => {
-                self.bump();
-                let span_with_semi = Span {
-                    lo: span.lo,
-                    hi: self.last_span.hi,
-                    expn_id: span.expn_id,
-                };
-                stmts.push(Stmt {
-                    id: ast::DUMMY_NODE_ID,
-                    node: StmtKind::Semi(e),
-                    span: span_with_semi,
-                });
-            }
-            _ => {
-                stmts.push(Stmt {
-                    id: ast::DUMMY_NODE_ID,
-                    node: StmtKind::Expr(e),
-                    span: span
-                });
-            }
+        if self.eat(&token::Semi) {
+            stmt = stmt.add_trailing_semicolon();
         }
-        Ok(())
+
+        stmt.span.hi = self.last_span.hi;
+        Ok(stmt)
     }
 
     // Parses a sequence of bounds if a `:` is found,