about summary refs log tree commit diff
path: root/src/comp/syntax/parse
diff options
context:
space:
mode:
authorMarijn Haverbeke <marijnh@gmail.com>2011-09-13 15:50:03 +0200
committerMarijn Haverbeke <marijnh@gmail.com>2011-09-13 15:50:03 +0200
commitbe5537e95fbe80d4564982a44d73c4053ee29ee9 (patch)
treed1b1ecf1db70af167cded484703ddba4097f9b39 /src/comp/syntax/parse
parente9451648798dc85a5971e98046cf62dca7a2cb23 (diff)
downloadrust-be5537e95fbe80d4564982a44d73c4053ee29ee9.tar.gz
rust-be5537e95fbe80d4564982a44d73c4053ee29ee9.zip
Be more strict about what constitutes a block expression
Blocks (or statements involving blocks) that end in a semicolon are no
longer considered the block-expression of their outer block. This used
to be an expression block, but now is a statement block:

    { if foo { ret 1; } else { ret 10; } }

This helps clear up some ambiguities in our grammar.
Diffstat (limited to 'src/comp/syntax/parse')
-rw-r--r--src/comp/syntax/parse/parser.rs41
1 files changed, 35 insertions, 6 deletions
diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs
index be54b38a68a..5006277ec6b 100644
--- a/src/comp/syntax/parse/parser.rs
+++ b/src/comp/syntax/parse/parser.rs
@@ -1571,8 +1571,42 @@ fn parse_source_stmt(p: parser) -> @ast::stmt {
     }
 }
 
+fn stmt_is_expr(stmt: @ast::stmt) -> bool {
+    fn expr_is_expr(e: @ast::expr) -> bool {
+        alt e.node {
+          ast::expr_if(_, th, els) | ast::expr_if_check(_, th, els) {
+            if option::is_none(els) { false }
+            else { !option::is_none(th.node.expr) ||
+                       expr_is_expr(option::get(els)) }
+          }
+          ast::expr_alt(_, arms) {
+            let found_expr = false;
+            for arm in arms {
+                if !option::is_none(arm.body.node.expr) { found_expr = true; }
+            }
+            found_expr
+          }
+          ast::expr_block(blk) | ast::expr_while(_, blk) |
+          ast::expr_for(_, _, blk) | ast::expr_for_each(_, _, blk) |
+          ast::expr_do_while(blk, _) {
+            !option::is_none(blk.node.expr)
+          }
+          _ { true }
+        }
+    }
+
+    ret alt stmt.node {
+      ast::stmt_expr(e, _) { expr_is_expr(e) }
+      _ { false }
+    };
+}
+
 fn stmt_to_expr(stmt: @ast::stmt) -> option::t<@ast::expr> {
-    ret alt stmt.node { ast::stmt_expr(e, _) { some(e) } _ { none } };
+    ret if stmt_is_expr(stmt) {
+        alt stmt.node {
+          ast::stmt_expr(e, _) { some(e) }
+        }
+    } else { none };
 }
 
 fn stmt_ends_with_semi(stmt: ast::stmt) -> bool {
@@ -1627,10 +1661,6 @@ fn stmt_ends_with_semi(stmt: ast::stmt) -> bool {
             }
       }
 
-
-
-
-
       // We should not be calling this on a cdir.
       ast::stmt_crate_directive(cdir) {
         fail;
@@ -1681,7 +1711,6 @@ fn parse_block_tail(p: parser, lo: uint, s: ast::check_mode) -> ast::blk {
                 // Not an expression statement.
                 stmts += [stmt];
 
-
                 if p.get_file_type() == SOURCE_FILE &&
                        stmt_ends_with_semi(*stmt) {
                     expect(p, token::SEMI);