implemented break for while-loop case

ast.ml - added break and cont statements
item.ml - added break and cont statements
lexer.mll - added break and cont statements
token.ml - added break and cont statements
trans.ml - implemented the break statement for the while-loop case
         - replaced hash table accesses with get_stmt_depth where needed
type.ml = added break and cont statements
typestate.ml - implemented the break statement for the while-loop case
             - added shorthand filter_live_block_slots
walk.ml - added break and cont statements
while-with-break.rs - code for testing while loops
This commit is contained in:
Or Brostovski 2010-08-31 06:07:32 +03:00 committed by Graydon Hoare
parent 74cb9508cd
commit 4a3404803b
10 changed files with 120 additions and 36 deletions

View file

@ -579,6 +579,7 @@ TEST_XFAILS_LLVM := $(TASK_XFAILS) \
vec-slice.rs \ vec-slice.rs \
vec.rs \ vec.rs \
while-flow-graph.rs \ while-flow-graph.rs \
while-with-break.rs \
writealias.rs \ writealias.rs \
yield.rs \ yield.rs \
yield2.rs \ yield2.rs \

View file

@ -207,6 +207,8 @@ and stmt' =
| STMT_put_each of (lval * (atom array)) | STMT_put_each of (lval * (atom array))
| STMT_ret of (atom option) | STMT_ret of (atom option)
| STMT_be of (lval * (atom array)) | STMT_be of (lval * (atom array))
| STMT_break
| STMT_cont
| STMT_alt_tag of stmt_alt_tag | STMT_alt_tag of stmt_alt_tag
| STMT_alt_type of stmt_alt_type | STMT_alt_type of stmt_alt_type
| STMT_alt_port of stmt_alt_port | STMT_alt_port of stmt_alt_port
@ -1228,6 +1230,10 @@ and fmt_stmt_body (ff:Format.formatter) (s:stmt) : unit =
fmt_atoms ff az; fmt_atoms ff az;
fmt ff ";"; fmt ff ";";
| STMT_break -> fmt ff "break;";
| STMT_cont -> fmt ff "cont;";
| STMT_block b -> fmt_block ff b.node | STMT_block b -> fmt_block ff b.node
| STMT_copy (lv, ex) -> | STMT_copy (lv, ex) ->

View file

@ -188,7 +188,14 @@ and parse_stmts_including_none (ps:pstate) : Ast.stmt array =
let (stmts, atom) = ctxt "stmts: log value" parse_expr_atom ps in let (stmts, atom) = ctxt "stmts: log value" parse_expr_atom ps in
expect ps SEMI; expect ps SEMI;
spans ps stmts apos (Ast.STMT_log atom) spans ps stmts apos (Ast.STMT_log atom)
| BREAK ->
bump ps;
expect ps SEMI;
[| span ps apos (lexpos ps) Ast.STMT_break |]
| CONT ->
bump ps;
expect ps SEMI;
[| span ps apos (lexpos ps) Ast.STMT_cont |]
| CHECK -> | CHECK ->
bump ps; bump ps;
begin begin

View file

@ -113,6 +113,8 @@
("const", CONST); ("const", CONST);
("log", LOG); ("log", LOG);
("break", BREAK);
("cont", CONT);
("spawn", SPAWN); ("spawn", SPAWN);
("thread", THREAD); ("thread", THREAD);
("yield", YIELD); ("yield", YIELD);

View file

@ -71,6 +71,8 @@ type token =
| PUT | PUT
| RET | RET
| BE | BE
| BREAK
| CONT
(* Type and type-state keywords *) (* Type and type-state keywords *)
| TYPE | TYPE
@ -226,6 +228,8 @@ let rec string_of_tok t =
| PUT -> "put" | PUT -> "put"
| RET -> "ret" | RET -> "ret"
| BE -> "be" | BE -> "be"
| BREAK -> "break"
| CONT -> "cont"
(* Type and type-state keywords *) (* Type and type-state keywords *)
| TYPE -> "type" | TYPE -> "type"

View file

@ -234,6 +234,7 @@ let trans_visitor
in in
let epilogue_jumps = Stack.create() in let epilogue_jumps = Stack.create() in
let simple_break_jumps = Stack.create() in (* not used for for-each *)
let path_name (_:unit) : string = let path_name (_:unit) : string =
string_of_name (path_to_name path) string_of_name (path_to_name path)
@ -4717,7 +4718,7 @@ let trans_visitor
Some params -> params Some params -> params
| None -> [| |] | None -> [| |]
in in
let depth = Hashtbl.find cx.ctxt_stmt_loop_depths stmt_id in let depth = get_stmt_depth cx stmt_id in
let fc = { for_each_fixup = fix; for_each_depth = depth } in let fc = { for_each_fixup = fix; for_each_depth = depth } in
iflog (fun _ -> iflog (fun _ ->
log cx "for-each at depth %d\n" depth); log cx "for-each at depth %d\n" depth);
@ -5059,12 +5060,16 @@ let trans_visitor
let fwd_jmp = mark () in let fwd_jmp = mark () in
emit (Il.jmp Il.JMP Il.CodeNone); emit (Il.jmp Il.JMP Il.CodeNone);
let block_begin = mark () in let block_begin = mark () in
Stack.push (Stack.create()) simple_break_jumps;
trans_block sw.Ast.while_body; trans_block sw.Ast.while_body;
patch fwd_jmp; patch fwd_jmp;
Array.iter trans_stmt head_stmts; Array.iter trans_stmt head_stmts;
check_interrupt_flag (); check_interrupt_flag ();
let back_jmps = trans_cond false head_expr in begin
List.iter (fun j -> patch_existing j block_begin) back_jmps; let back_jmps = trans_cond false head_expr in
List.iter (fun j -> patch_existing j block_begin) back_jmps;
end;
Stack.iter patch (Stack.pop simple_break_jumps);
| Ast.STMT_if si -> | Ast.STMT_if si ->
let skip_thn_jmps = trans_cond true si.Ast.if_test in let skip_thn_jmps = trans_cond true si.Ast.if_test in
@ -5108,6 +5113,13 @@ let trans_visitor
let (dst_cell, _) = get_current_output_cell_and_slot () in let (dst_cell, _) = get_current_output_cell_and_slot () in
trans_be_fn cx dst_cell flv ty_params args trans_be_fn cx dst_cell flv ty_params args
| Ast.STMT_break ->
if get_stmt_depth cx stmt.id > 0
then unimpl (Some stmt.id) "break within iterator-block";
drop_slots_at_curr_stmt();
Stack.push (mark()) (Stack.top simple_break_jumps);
emit (Il.jmp Il.JMP Il.CodeNone);
| Ast.STMT_put atom_opt -> | Ast.STMT_put atom_opt ->
trans_put atom_opt trans_put atom_opt

View file

@ -945,7 +945,9 @@ let check_stmt (cx:Semant.ctxt) : (fn_ctx -> Ast.stmt -> unit) =
| Ast.STMT_alt_port _ -> () (* TODO *) | Ast.STMT_alt_port _ -> () (* TODO *)
| Ast.STMT_fail | Ast.STMT_yield -> () (* always well-typed *) (* always well-typed *)
| Ast.STMT_fail | Ast.STMT_yield
| Ast.STMT_break | Ast.STMT_cont -> ()
| Ast.STMT_join lval -> infer_lval Ast.TY_task lval | Ast.STMT_join lval -> infer_lval Ast.TY_task lval

View file

@ -445,6 +445,15 @@ let bitmap_assigning_visitor
Walk.visit_block_pre = visit_block_pre } Walk.visit_block_pre = visit_block_pre }
;; ;;
type slots_stack = node_id Stack.t;;
type block_slots_stack = slots_stack Stack.t;;
type frame_block_slots_stack = block_slots_stack Stack.t;;
type loop_block_slots_stack = block_slots_stack option Stack.t;;
(* like ret drops slots from all blocks in the frame
* break from a simple loo drops slots from all block in a loop *)
let (loop_blocks:loop_block_slots_stack) =
let s = Stack.create() in Stack.push None s; s
let condition_assigning_visitor let condition_assigning_visitor
(cx:ctxt) (cx:ctxt)
(tables_stack:typestate_tables Stack.t) (tables_stack:typestate_tables Stack.t)
@ -574,7 +583,7 @@ let condition_assigning_visitor
let precond = slot_inits (lval_slots cx lval) in let precond = slot_inits (lval_slots cx lval) in
raise_precondition sid precond; raise_precondition sid precond;
in in
let visit_stmt_pre s = let visit_stmt_pre s =
begin begin
match s.node with match s.node with
@ -694,7 +703,6 @@ let condition_assigning_visitor
| Ast.STMT_check_expr expr -> | Ast.STMT_check_expr expr ->
let precond = slot_inits (expr_slots cx expr) in let precond = slot_inits (expr_slots cx expr) in
raise_pre_post_cond s.id precond raise_pre_post_cond s.id precond
| Ast.STMT_while sw -> | Ast.STMT_while sw ->
let (_, expr) = sw.Ast.while_lval in let (_, expr) = sw.Ast.while_lval in
let precond = slot_inits (expr_slots cx expr) in let precond = slot_inits (expr_slots cx expr) in
@ -1275,9 +1283,6 @@ let typestate_verify_visitor
Walk.visit_block_pre = visit_block_pre } Walk.visit_block_pre = visit_block_pre }
;; ;;
type slots_stack = node_id Stack.t;;
type block_slots_stack = slots_stack Stack.t;;
type frame_block_slots_stack = block_slots_stack Stack.t;;
let lifecycle_visitor let lifecycle_visitor
(cx:ctxt) (cx:ctxt)
@ -1312,18 +1317,24 @@ let lifecycle_visitor
let visit_block_pre b = let visit_block_pre b =
Stack.push (Stack.create()) (Stack.top frame_blocks);
begin let s = Stack.create() in
match htab_search implicit_init_block_slots b.id with begin
None -> () match Stack.top loop_blocks with
| Some slots -> Some loop -> Stack.push s loop | None -> ()
end;
Stack.push s (Stack.top frame_blocks);
begin
match htab_search implicit_init_block_slots b.id with
None -> ()
| Some slots ->
List.iter List.iter
(fun slot -> (fun slot ->
push_slot slot; push_slot slot;
mark_slot_live slot) mark_slot_live slot)
slots slots
end; end;
inner.Walk.visit_block_pre b inner.Walk.visit_block_pre b
in in
let note_drops stmt slots = let note_drops stmt slots =
@ -1341,8 +1352,20 @@ let lifecycle_visitor
htab_put cx.ctxt_post_stmt_slot_drops stmt.id slots htab_put cx.ctxt_post_stmt_slot_drops stmt.id slots
in in
let filter_live_block_slots slots =
List.filter (fun i -> Hashtbl.mem live_block_slots i) slots
in
let visit_block_post b = let visit_block_post b =
inner.Walk.visit_block_post b; inner.Walk.visit_block_post b;
begin
match Stack.top loop_blocks with
Some loop ->
ignore(Stack.pop loop);
if Stack.is_empty loop then
ignore(Stack.pop loop_blocks);
| None -> ()
end;
let block_slots = Stack.pop (Stack.top frame_blocks) in let block_slots = Stack.pop (Stack.top frame_blocks) in
let stmts = b.node in let stmts = b.node in
let len = Array.length stmts in let len = Array.length stmts in
@ -1352,7 +1375,8 @@ let lifecycle_visitor
let s = stmts.(len-1) in let s = stmts.(len-1) in
match s.node with match s.node with
Ast.STMT_ret _ Ast.STMT_ret _
| Ast.STMT_be _ -> | Ast.STMT_be _
| Ast.STMT_break ->
() (* Taken care of in visit_stmt_post below. *) () (* Taken care of in visit_stmt_post below. *)
| _ -> | _ ->
(* The blk_slots stack we have has accumulated slots in (* The blk_slots stack we have has accumulated slots in
@ -1364,11 +1388,7 @@ let lifecycle_visitor
* point in the block. * point in the block.
*) *)
let slots = stk_elts_from_top block_slots in let slots = stk_elts_from_top block_slots in
let live = let live = filter_live_block_slots slots in
List.filter
(fun i -> Hashtbl.mem live_block_slots i)
slots
in
note_drops s live note_drops s live
end; end;
in in
@ -1440,6 +1460,10 @@ let lifecycle_visitor
f.Ast.for_each_body.id f.Ast.for_each_body.id
[ (fst f.Ast.for_each_slot).id ] [ (fst f.Ast.for_each_slot).id ]
| Ast.STMT_while _ ->
iflog cx (fun _ -> log cx "entering a loop");
Stack.push (Some (Stack.create ())) loop_blocks;
| Ast.STMT_alt_tag { Ast.alt_tag_arms = arms } -> | Ast.STMT_alt_tag { Ast.alt_tag_arms = arms } ->
let note_slot block slot_id = let note_slot block slot_id =
log cx log cx
@ -1475,26 +1499,38 @@ let lifecycle_visitor
let visit_stmt_post s = let visit_stmt_post s =
inner.Walk.visit_stmt_post s; inner.Walk.visit_stmt_post s;
let handle_ret_like_stmt block_stack =
let blocks = stk_elts_from_top block_stack in
let slots = List.concat (List.map stk_elts_from_top blocks) in
let live = filter_live_block_slots slots in
note_drops s live
in
match s.node with match s.node with
Ast.STMT_ret _ Ast.STMT_ret _
| Ast.STMT_be _ -> | Ast.STMT_be _ ->
let blocks = stk_elts_from_top (Stack.top frame_blocks) in handle_ret_like_stmt (Stack.top frame_blocks)
let slots = List.concat (List.map stk_elts_from_top blocks) in | Ast.STMT_break ->
let live = begin
List.filter match (Stack.top loop_blocks) with
(fun i -> Hashtbl.mem live_block_slots i) Some loop -> handle_ret_like_stmt loop
slots | None ->
in iflog cx (fun _ ->
note_drops s live log cx "break statement outside of a loop");
err (Some s.id) "break statement outside of a loop"
end
| _ -> () | _ -> ()
in in
let enter_frame _ = let enter_frame _ =
Stack.push (Stack.create()) frame_blocks Stack.push (Stack.create()) frame_blocks;
Stack.push None loop_blocks
in in
let leave_frame _ = let leave_frame _ =
ignore (Stack.pop frame_blocks) ignore (Stack.pop frame_blocks);
match Stack.pop loop_blocks with
Some _ -> bug () "leave_frame should not end a loop"
| None -> ()
in in
let visit_mod_item_pre n p i = let visit_mod_item_pre n p i =

View file

@ -481,8 +481,7 @@ and walk_stmt
| Ast.STMT_decl (Ast.DECL_slot (_, slot)) -> | Ast.STMT_decl (Ast.DECL_slot (_, slot)) ->
walk_slot_identified v slot walk_slot_identified v slot
| Ast.STMT_yield | Ast.STMT_break | Ast.STMT_cont | Ast.STMT_yield | Ast.STMT_fail ->
| Ast.STMT_fail ->
() ()
| Ast.STMT_join task -> | Ast.STMT_join task ->

View file

@ -0,0 +1,15 @@
// -*- rust -*-
fn main() {
let int i = 90;
while (i < 100) {
log i;
i = i + 1;
if (i == 95) {
let vec[int] v = vec(1,2,3,4,5); // we check that it is freed by break
log "breaking";
break;
}
}
check(i == 95);
}