diff --git a/src/comp/front/ast.rs b/src/comp/front/ast.rs index f90f8df62c61a5bf64d298dda526331c135dc0f6..a1670c700ad26263d54809b3d5955f3df1e9abee 100644 --- a/src/comp/front/ast.rs +++ b/src/comp/front/ast.rs @@ -39,6 +39,7 @@ type block = spanned[block_]; type block_ = rec(vec[@stmt] stmts, + option.t[@expr] expr, hashmap[ident,uint] index); type pat = spanned[pat_]; diff --git a/src/comp/front/parser.rs b/src/comp/front/parser.rs index f0014f6b183c63f63c4b5df1215e32ec6f171b69..b23fa0aad72d2d98a35bc561dc674c7fa799eee5 100644 --- a/src/comp/front/parser.rs +++ b/src/comp/front/parser.rs @@ -761,7 +761,6 @@ fn spanned[T](&span lo, &span hi, &T node) -> ast.spanned[T] { expect (p, token.LPAREN); auto cond = parse_expr(p); expect(p, token.RPAREN); - expect(p, token.SEMI); hi = cond.span; ret @spanned(lo, hi, ast.expr_do_while(body, cond, ast.ann_none)); } @@ -891,7 +890,6 @@ fn spanned[T](&span lo, &span hi, &T node) -> ast.spanned[T] { auto init = parse_initializer(p); auto hi = p.get_span(); - expect(p, token.SEMI); let ast.local local = rec(ty = some(ty), infer = false, @@ -911,7 +909,6 @@ fn spanned[T](&span lo, &span hi, &T node) -> ast.spanned[T] { auto init = parse_initializer(p); auto hi = p.get_span(); - expect(p, token.SEMI); let ast.local local = rec(ty = none[@ast.ty], infer = true, @@ -931,7 +928,6 @@ fn spanned[T](&span lo, &span hi, &T node) -> ast.spanned[T] { p.bump(); auto e = parse_expr(p); auto hi = p.get_span(); - expect(p, token.SEMI); ret @spanned(lo, hi, ast.stmt_log(e)); } @@ -941,7 +937,6 @@ fn spanned[T](&span lo, &span hi, &T node) -> ast.spanned[T] { case (token.LPAREN) { auto e = parse_expr(p); auto hi = p.get_span(); - expect(p, token.SEMI); ret @spanned(lo, hi, ast.stmt_check_expr(e)); } case (_) { @@ -954,13 +949,11 @@ fn spanned[T](&span lo, &span hi, &T node) -> ast.spanned[T] { p.bump(); alt (p.peek()) { case (token.SEMI) { - p.bump(); ret @spanned(lo, p.get_span(), ast.stmt_ret(none[@ast.expr])); } case (_) { auto e = parse_expr(p); - expect(p, token.SEMI); ret @spanned(lo, e.span, ast.stmt_ret(some[@ast.expr](e))); } @@ -1012,7 +1005,6 @@ fn spanned[T](&span lo, &span hi, &T node) -> ast.spanned[T] { case (_) { auto e = parse_expr(p); auto hi = p.get_span(); - expect(p, token.SEMI); ret @spanned(lo, hi, ast.stmt_expr(e)); } } @@ -1020,16 +1012,10 @@ fn spanned[T](&span lo, &span hi, &T node) -> ast.spanned[T] { fail; } -impure fn parse_block(parser p) -> ast.block { - auto f = parse_stmt; - // FIXME: passing parse_stmt as an lval doesn't work at the moment. - auto stmts = parse_seq[@ast.stmt](token.LBRACE, - token.RBRACE, - none[token.token], - f, p); +fn index_block(vec[@ast.stmt] stmts, option.t[@ast.expr] expr) -> ast.block_ { auto index = new_str_hash[uint](); auto u = 0u; - for (@ast.stmt s in stmts.node) { + for (@ast.stmt s in stmts) { // FIXME: typestate bug requires we do this up top, not // down below loop. Sigh. u += 1u; @@ -1056,8 +1042,103 @@ fn spanned[T](&span lo, &span hi, &T node) -> ast.spanned[T] { } } } - let ast.block_ b = rec(stmts=stmts.node, index=index); - ret spanned(stmts.span, stmts.span, b); + ret rec(stmts=stmts, expr=expr, index=index); +} + +fn stmt_to_expr(@ast.stmt stmt) -> option.t[@ast.expr] { + alt (stmt.node) { + case (ast.stmt_expr(?e)) { ret some[@ast.expr](e); } + case (_) { /* fall through */ } + } + ret none[@ast.expr]; +} + +fn stmt_ends_with_semi(@ast.stmt stmt) -> bool { + alt (stmt.node) { + case (ast.stmt_decl(_)) { ret true; } // FIXME + case (ast.stmt_ret(_)) { ret true; } + case (ast.stmt_log(_)) { ret true; } + case (ast.stmt_check_expr(_)) { ret true; } + case (ast.stmt_expr(?e)) { + alt (e.node) { + case (ast.expr_vec(_,_)) { ret true; } + case (ast.expr_tup(_,_)) { ret true; } + case (ast.expr_rec(_,_)) { ret true; } + case (ast.expr_call(_,_,_)) { ret true; } + case (ast.expr_binary(_,_,_,_)) { ret true; } + case (ast.expr_unary(_,_,_)) { ret true; } + case (ast.expr_lit(_,_)) { ret true; } + case (ast.expr_cast(_,_,_)) { ret true; } + case (ast.expr_if(_,_,_,_)) { ret false; } + case (ast.expr_while(_,_,_)) { ret false; } + case (ast.expr_do_while(_,_,_)) { ret false; } + case (ast.expr_alt(_,_,_)) { ret false; } + case (ast.expr_block(_,_)) { ret false; } + case (ast.expr_assign(_,_,_)) { ret true; } + case (ast.expr_field(_,_,_)) { ret true; } + case (ast.expr_index(_,_,_)) { ret true; } + case (ast.expr_name(_,_,_)) { ret true; } + case (_) { fail; } + } + } + case (_) { fail; } + } +} + +impure fn parse_block(parser p) -> ast.block { + auto lo = p.get_span(); + + let vec[@ast.stmt] stmts = vec(); + let option.t[@ast.expr] expr = none[@ast.expr]; + + expect(p, token.LBRACE); + while (p.peek() != token.RBRACE) { + alt (p.peek()) { + case (token.RBRACE) { + // empty; fall through to next iteration + } + case (token.SEMI) { + p.bump(); + // empty + } + case (_) { + auto stmt = parse_stmt(p); + alt (stmt_to_expr(stmt)) { + case (some[@ast.expr](?e)) { + alt (p.peek()) { + case (token.SEMI) { + p.bump(); + stmts += vec(stmt); + } + case (token.RBRACE) { expr = some(e); } + case (?t) { + if (stmt_ends_with_semi(stmt)) { + p.err("expected ';' or '}' after " + + "expression but found " + + token.to_str(t)); + fail; + } + stmts += vec(stmt); + } + } + } + case (none[@ast.expr]) { + // Not an expression statement. + stmts += vec(stmt); + if (stmt_ends_with_semi(stmt)) { + expect(p, token.SEMI); + } + } + } + } + } + } + + p.bump(); + auto hi = p.get_span(); + + auto bloc = index_block(stmts, expr); + ret spanned[ast.block_](lo, hi, bloc); } impure fn parse_ty_param(parser p) -> ast.ty_param { diff --git a/src/comp/middle/fold.rs b/src/comp/middle/fold.rs index ff8f5505bab6c9a8eb92e25c3253a04b48986449..c97dceb4009c947c768008eaa84fc728e8d510d1 100644 --- a/src/comp/middle/fold.rs +++ b/src/comp/middle/fold.rs @@ -529,7 +529,19 @@ fn fold_block[ENV](&ENV env, ast_fold[ENV] fld, &block blk) -> block { for (@ast.stmt s in blk.node.stmts) { append[@ast.stmt](stmts, fold_stmt[ENV](env_, fld, s)); } - ret respan(blk.span, rec(stmts=stmts with blk.node)); + + auto expr = none[@ast.expr]; + alt (blk.node.expr) { + case (some[@ast.expr](?e)) { + expr = some[@ast.expr](fold_expr[ENV](env_, fld, e)); + } + case (none[@ast.expr]) { + // empty + } + } + + // FIXME: should we reindex? + ret respan(blk.span, rec(stmts=stmts, expr=expr, index=blk.node.index)); } fn fold_arg[ENV](&ENV env, ast_fold[ENV] fld, &arg a) -> arg { diff --git a/src/comp/middle/trans.rs b/src/comp/middle/trans.rs index 9aa367d5ae60eee04fd6760600587d967ecd23bd..8caaf5f73093f669495a4c96a1d9693144cc4864 100644 --- a/src/comp/middle/trans.rs +++ b/src/comp/middle/trans.rs @@ -1488,6 +1488,19 @@ fn trans_block_cleanups(@block_ctxt cx, } } + alt (b.node.expr) { + case (some[@ast.expr](?e)) { + r = trans_expr(bcx, e); + bcx = r.bcx; + if (is_terminated(bcx)) { + ret r; + } + } + case (none[@ast.expr]) { + r = res(bcx, C_nil()); + } + } + bcx = trans_block_cleanups(bcx, bcx); ret res(bcx, r.val); } diff --git a/src/comp/middle/typeck.rs b/src/comp/middle/typeck.rs index 0aabcac3833fb001f5ae17345ddc5ff30e21f0ea..58f723bd8a7a8feac681b9dd3f7607624713ed2e 100644 --- a/src/comp/middle/typeck.rs +++ b/src/comp/middle/typeck.rs @@ -398,19 +398,6 @@ fn trans_ty_item_to_ty(@hashmap[ast.def_id,@ast.item] id_to_ty_item, // Expression utilities -fn last_expr_of_block(&ast.block bloc) -> option.t[@ast.expr] { - auto len = _vec.len[@ast.stmt](bloc.node.stmts); - if (len == 0u) { - ret none[@ast.expr]; - } - auto last_stmt = bloc.node.stmts.(len - 1u); - alt (last_stmt.node) { - case (ast.stmt_expr(?e)) { ret some[@ast.expr](e); } - case (_) { ret none[@ast.expr]; } - } -} - - fn field_num(session.session sess, &span sp, &ast.ident id) -> uint { let uint accum = 0u; let uint i = 0u; @@ -546,7 +533,7 @@ fn stmt_ty(@ast.stmt s) -> @ty { } fn block_ty(&ast.block b) -> @ty { - alt (last_expr_of_block(b)) { + alt (b.node.expr) { case (some[@ast.expr](?e)) { ret expr_ty(e); } case (none[@ast.expr]) { ret plain_ty(ty_nil); } } @@ -965,18 +952,12 @@ fn demand_expr(&fn_ctxt fcx, @ty expected, @ast.expr e) -> @ast.expr { // Type unification over typed blocks. fn demand_block(&fn_ctxt fcx, @ty expected, &ast.block bloc) -> ast.block { - alt (last_expr_of_block(bloc)) { + alt (bloc.node.expr) { case (some[@ast.expr](?e_0)) { auto e_1 = demand_expr(fcx, expected, e_0); - - auto len = _vec.len[@ast.stmt](bloc.node.stmts); - auto last_stmt_0 = bloc.node.stmts.(len - 1u); - auto prev_stmts = _vec.pop[@ast.stmt](bloc.node.stmts); - auto last_stmt_1 = @fold.respan[ast.stmt_](last_stmt_0.span, - ast.stmt_expr(e_1)); - auto stmts_1 = prev_stmts + vec(last_stmt_1); - - auto block_ = rec(stmts=stmts_1, index=bloc.node.index); + auto block_ = rec(stmts=bloc.node.stmts, + expr=some[@ast.expr](e_1), + index=bloc.node.index); ret fold.respan[ast.block_](bloc.span, block_); } case (none[@ast.expr]) { @@ -1386,8 +1367,18 @@ fn check_block(&fn_ctxt fcx, &ast.block block) -> ast.block { for (@ast.stmt s in block.node.stmts) { append[@ast.stmt](stmts, check_stmt(fcx, s)); } + + auto expr = none[@ast.expr]; + alt (block.node.expr) { + case (none[@ast.expr]) { /* empty */ } + case (some[@ast.expr](?e)) { + expr = some[@ast.expr](check_expr(fcx, e)); + } + } + ret fold.respan[ast.block_](block.span, - rec(stmts=stmts, index=block.node.index)); + rec(stmts=stmts, expr=expr, + index=block.node.index)); } fn check_fn(&@crate_ctxt ccx, &span sp, ast.ident ident, &ast._fn f, @@ -1411,8 +1402,10 @@ fn check_fn(&@crate_ctxt ccx, &span sp, ast.ident ident, &ast._fn f, locals = local_ty_table, ccx = ccx); + // TODO: Make sure the type of the block agrees with the function type. auto block_t = check_block(fcx, f.body); auto block_wb = writeback(fcx, block_t); + auto fn_t = rec(inputs=f.inputs, output=f.output, body=block_wb); auto item = ast.item_fn(ident, fn_t, ty_params, id, fn_ann); ret @fold.respan[ast.item_](sp, item);