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:
parent
74cb9508cd
commit
4a3404803b
10 changed files with 120 additions and 36 deletions
|
@ -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 \
|
||||||
|
|
|
@ -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) ->
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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"
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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
|
||||||
|
|
||||||
|
|
|
@ -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)
|
||||||
|
@ -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 =
|
||||||
|
|
|
@ -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 ->
|
||||||
|
|
15
src/test/run-pass/while-with-break.rs
Normal file
15
src/test/run-pass/while-with-break.rs
Normal 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);
|
||||||
|
}
|
Loading…
Reference in a new issue