diff options
| author | Marijn Haverbeke <marijnh@gmail.com> | 2011-09-15 09:39:24 +0200 |
|---|---|---|
| committer | Marijn Haverbeke <marijnh@gmail.com> | 2011-09-15 09:49:00 +0200 |
| commit | 0b34e0e60bb605ac00a3c2a00a687c92675092c7 (patch) | |
| tree | 89c28c3861aa8295df0d6d223f13cf15ae167b44 /src/comp/syntax | |
| parent | 7298b8f4bac7687824ef41f6e3f9f114aa070417 (diff) | |
| download | rust-0b34e0e60bb605ac00a3c2a00a687c92675092c7.tar.gz rust-0b34e0e60bb605ac00a3c2a00a687c92675092c7.zip | |
Introduce new semicolon rules
- Loop bodies and resource constructors aren't allowed to have trailing expressions anymore. - An expression that ends* in a block without trailing expression can can not be called, indexed, or subscripted. - Only expression-statements that end* in a block without trailing expression can omit their semicolon. *) 'Ending in a trailing expression' is defined as being a block or construct-ending-in-a-block (if, alt) that either ends in an expression itself, or ends in another block-like expression that has a trailing expression (by these same rules).
Diffstat (limited to 'src/comp/syntax')
| -rw-r--r-- | src/comp/syntax/parse/parser.rs | 115 |
1 files changed, 44 insertions, 71 deletions
diff --git a/src/comp/syntax/parse/parser.rs b/src/comp/syntax/parse/parser.rs index 543f2e65383..1ea3ddbec67 100644 --- a/src/comp/syntax/parse/parser.rs +++ b/src/comp/syntax/parse/parser.rs @@ -853,14 +853,14 @@ fn parse_bottom_expr(p: parser) -> @ast::expr { expect(p, token::GT); /* hack: early return to take advantage of specialized function */ - ret mk_mac_expr(p, lo, p.get_hi_pos(), ast::mac_embed_type(ty)) + ret mk_mac_expr(p, lo, p.get_hi_pos(), ast::mac_embed_type(ty)); } else if p.peek() == token::POUND_LBRACE { p.bump(); let blk = ast::mac_embed_block(parse_block_tail(p, lo, ast::checked)); ret mk_mac_expr(p, lo, p.get_hi_pos(), blk); } else if p.peek() == token::ELLIPSIS { p.bump(); - ret mk_mac_expr(p, lo, p.get_hi_pos(), ast::mac_ellipsis) + ret mk_mac_expr(p, lo, p.get_hi_pos(), ast::mac_ellipsis); } else if p.peek() == token::TILDE { p.bump(); ex = ast::expr_uniq(parse_expr(p)); @@ -1033,7 +1033,9 @@ fn parse_self_method(p: parser) -> @ast::expr { } fn parse_dot_or_call_expr(p: parser) -> @ast::expr { - ret parse_dot_or_call_expr_with(p, parse_bottom_expr(p)); + let b = parse_bottom_expr(p); + if expr_has_value(b) { parse_dot_or_call_expr_with(p, b) } + else { b } } fn parse_dot_or_call_expr_with(p: parser, e: @ast::expr) -> @ast::expr { @@ -1296,7 +1298,7 @@ fn parse_for_expr(p: parser) -> @ast::expr { let decl = parse_local(p, false); expect_word(p, "in"); let seq = parse_expr(p); - let body = parse_block(p); + let body = parse_block_no_value(p); let hi = body.span.hi; if is_each { ret mk_expr(p, lo, hi, ast::expr_for_each(decl, seq, body)); @@ -1306,14 +1308,14 @@ fn parse_for_expr(p: parser) -> @ast::expr { fn parse_while_expr(p: parser) -> @ast::expr { let lo = p.get_last_lo_pos(); let cond = parse_expr(p); - let body = parse_block(p); + let body = parse_block_no_value(p); let hi = body.span.hi; ret mk_expr(p, lo, hi, ast::expr_while(cond, body)); } fn parse_do_while_expr(p: parser) -> @ast::expr { let lo = p.get_last_lo_pos(); - let body = parse_block(p); + let body = parse_block_no_value(p); expect_word(p, "while"); let cond = parse_expr(p); let hi = cond.span.hi; @@ -1567,32 +1569,32 @@ 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 } +fn expr_has_value(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_has_value(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 } } +} +fn stmt_is_expr(stmt: @ast::stmt) -> bool { ret alt stmt.node { - ast::stmt_expr(e, _) { expr_is_expr(e) } + ast::stmt_expr(e, _) { expr_has_value(e) } _ { false } }; } @@ -1614,49 +1616,8 @@ fn stmt_ends_with_semi(stmt: ast::stmt) -> bool { } } ast::stmt_expr(e, _) { - ret alt e.node { - ast::expr_vec(_, _) { true } - ast::expr_rec(_, _) { true } - ast::expr_tup(_) { true } - ast::expr_call(_, _) { true } - ast::expr_self_method(_) { false } - ast::expr_bind(_, _) { true } - ast::expr_binary(_, _, _) { true } - ast::expr_unary(_, _) { true } - ast::expr_lit(_) { true } - ast::expr_cast(_, _) { true } - ast::expr_if(_, _, _) { false } - ast::expr_ternary(_, _, _) { true } - ast::expr_for(_, _, _) { false } - ast::expr_for_each(_, _, _) { false } - ast::expr_while(_, _) { false } - ast::expr_do_while(_, _) { false } - ast::expr_alt(_, _) { false } - ast::expr_fn(_) { false } - ast::expr_block(_) { false } - ast::expr_copy(_) { true } - ast::expr_move(_, _) { true } - ast::expr_assign(_, _) { true } - ast::expr_swap(_, _) { true } - ast::expr_assign_op(_, _, _) { true } - ast::expr_field(_, _) { true } - ast::expr_index(_, _) { true } - ast::expr_path(_) { true } - ast::expr_mac(_) { true } - ast::expr_fail(_) { true } - ast::expr_break. { true } - ast::expr_cont. { true } - ast::expr_ret(_) { true } - ast::expr_put(_) { true } - ast::expr_be(_) { true } - ast::expr_log(_, _) { true } - ast::expr_check(_, _) { true } - ast::expr_if_check(_, _, _) { false } - ast::expr_anon_obj(_) { false } - ast::expr_assert(_) { true } - } + ret expr_has_value(e); } - // We should not be calling this on a cdir. ast::stmt_crate_directive(cdir) { fail; @@ -1674,6 +1635,18 @@ fn parse_block(p: parser) -> ast::blk { } } +fn parse_block_no_value(p: parser) -> ast::blk { + let blk = parse_block(p); + if !option::is_none(blk.node.expr) { + let sp = option::get(blk.node.expr).span; + codemap::emit_error(some(sp), + "this block must not return a value", + p.get_sess().cm); + fail; + } + ret blk; +} + // Precondition: already parsed the '{' or '#{' // I guess that also means "already parsed the 'impure'" if // necessary, and this should take a qualifier. @@ -1870,7 +1843,7 @@ fn parse_item_res(p: parser, attrs: [ast::attribute]) -> @ast::item { expect(p, token::COLON); let t = parse_ty(p, false); expect(p, token::RPAREN); - let dtor = parse_block(p); + let dtor = parse_block_no_value(p); let decl = {inputs: [{mode: ast::by_ref, ty: t, ident: arg_ident, id: p.get_id()}], |
