Skip to content

Commit

Permalink
Handle breaks from foreach loops
Browse files Browse the repository at this point in the history
Summary:
- property handle breaks from foreach loops
- handle breaks with specified breakout-level

Reviewed By: oulgen

Differential Revision: D5151834

fbshipit-source-id: feafdbe461cf7a0251d822eeda6146c5ffc4065d
  • Loading branch information
vladima authored and hhvm-bot committed May 31, 2017
1 parent b1d3062 commit c383b94
Show file tree
Hide file tree
Showing 20 changed files with 87 additions and 86 deletions.
8 changes: 7 additions & 1 deletion hphp/hack/src/hhbc/Hhas_parser_actions.ml
Expand Up @@ -324,6 +324,7 @@ type iarg =
| IAArrayno of adata_id
| IAMemberkey of string*iarg (* these are not seriously recursive *)
| IAArglist of iarg list
| IAIteratorid of string*int64

let class_id_of_iarg arg =
match arg with
Expand Down Expand Up @@ -519,6 +520,11 @@ let labelofiarg arg =

let iterofiarg arg = Iterator.Id (intofiarg arg)

let iterwithkindofiarg arg =
match arg with
| IAIteratorid (kind, id) -> kind = "MIter", Iterator.Id (Int64.to_int id)
| _ -> report_error "bad iterator"

let memberopmodeofiarg arg =
match stringofiarg arg with
| "None" -> MemberOpMode.ModeNone
Expand All @@ -529,7 +535,7 @@ let memberopmodeofiarg arg =

let listofiteratorsofiarg arg =
match arg with
| IAArglist l -> List.map iterofiarg l
| IAArglist l -> List.map iterwithkindofiarg l
| _ -> report_error "bad list of iterators"

let listoflabelsofiarg arg =
Expand Down
4 changes: 2 additions & 2 deletions hphp/hack/src/hhbc/continue_break_rewriter.ml
Expand Up @@ -96,7 +96,7 @@ unconditional jumps to the right place. *)

let add_iterator lst =
match opt_iterator with
| Some (_, it) -> it :: lst
| Some x -> x :: lst
| None -> lst in
let wrap_return ret =
match opt_iterator with
Expand All @@ -113,7 +113,7 @@ unconditional jumps to the right place. *)
| ISpecialFlow (Break (level, original, itrs)) when level > 1 ->
instr (ISpecialFlow (Break ((level - 1), original, add_iterator itrs)))
| ISpecialFlow (Break (_, _, itrs)) ->
(match itrs with
(match add_iterator itrs with
| [] -> instr (IContFlow (Jmp break_label))
| itrs -> instr (IIterator (IterBreak (break_label, itrs))))
| IContFlow (RetC) -> wrap_return (IContFlow (RetC))
Expand Down
8 changes: 4 additions & 4 deletions hphp/hack/src/hhbc/emit_statement.ml
Expand Up @@ -86,10 +86,10 @@ let rec emit_stmt env st =
emit_if env condition (A.Block consequence) (A.Block alternative)
| A.While (e, b) ->
emit_while env e (A.Block b)
| A.Break _ ->
instr_break 1 (* TODO: Break takes an argument *)
| A.Continue _ ->
instr_continue 1 (* TODO: Continue takes an argument *)
| A.Break (_, level_opt) ->
instr_break (Option.value level_opt ~default:1)
| A.Continue (_, level_opt) ->
instr_continue (Option.value level_opt ~default:1)
| A.Do (b, e) ->
emit_do env (A.Block b) e
| A.For (e1, e2, e3, b) ->
Expand Down
2 changes: 2 additions & 0 deletions hphp/hack/src/hhbc/hhas_parser.mly
Expand Up @@ -413,10 +413,12 @@ iarg:
| AT ID {IAArrayno $2}
| ID COLON iarg {IAMemberkey ($1,$3)}
| LANGLE iarglist RANGLE {IAArglist $2}
| LPAR ID RPAR INT {IAIteratorid ($2,$4)}
;
iarglist:
| /* empty */ {[]}
| iarg iarglist {$1 :: $2}
| iarg COMMA iarglist {$1 :: $3}
;
decllist:
/* empty */ { [] }
Expand Down
4 changes: 2 additions & 2 deletions hphp/hack/src/hhbc/hhbc_ast.ml
Expand Up @@ -239,7 +239,7 @@ type instruct_control_flow =

type instruct_special_flow =
| Continue of int * int (* This will be rewritten *)
| Break of int * int * Iterator.t list (* This will be rewritten *)
| Break of int * int * (bool * Iterator.t) list (* This will be rewritten *)

type instruct_get =
| CGetL of local_id
Expand Down Expand Up @@ -423,7 +423,7 @@ type instruct_iterator =
| IterFree of Iterator.t
| MIterFree of Iterator.t
| CIterFree of Iterator.t
| IterBreak of Label.t * Iterator.t list
| IterBreak of Label.t * (bool * Iterator.t) list

type instruct_include_eval_define =
| Incl
Expand Down
14 changes: 7 additions & 7 deletions hphp/hack/src/hhbc/hhbc_hhas.ml
Expand Up @@ -593,13 +593,13 @@ let string_of_iterator instruction =
(iterator_instruction_name_prefix instruction) ^
(string_of_iterator_id id)
| IterBreak (label, iterlist) ->
"IterBreak " ^
(string_of_label label) ^
"<" ^
(let list_item = (fun id -> "(Iter) " ^ (string_of_iterator_id id)) in
let mapped_list = List.map list_item iterlist in
String.concat ", " mapped_list) ^
">"
let map_item (is_mutable, id) =
(if is_mutable then "(MIter) " else "(Iter) ") ^
(string_of_iterator_id id)
in
let values =
String.concat ", " (List.rev_map map_item iterlist) in
"IterBreak " ^ (string_of_label label) ^ " <" ^ values ^ ">"
| _ -> "### string_of_iterator instruction not implemented"

let string_of_try instruction =
Expand Down
4 changes: 2 additions & 2 deletions hphp/hack/src/naming/naming.ml
Expand Up @@ -1682,8 +1682,8 @@ module Make (GetLocals : GetLocals) = struct
| Unsafe -> assert false
| Fallthrough -> N.Fallthrough
| Noop -> N.Noop
| Break p -> N.Break p
| Continue p -> N.Continue p
| Break (p, _) -> N.Break p
| Continue (p, _) -> N.Continue p
| Throw e -> let terminal = not (fst env).in_try in
N.Throw (terminal, expr env e)
| Return (p, e) -> N.Return (p, oexpr env e)
Expand Down
4 changes: 2 additions & 2 deletions hphp/hack/src/parser/ast.ml
Expand Up @@ -254,8 +254,8 @@ and stmt =
| Fallthrough
| Expr of expr
| Block of block
| Break of Pos.t
| Continue of Pos.t
| Break of Pos.t * int option
| Continue of Pos.t * int option
| Throw of expr
| Return of Pos.t * expr option
| GotoLabel of pstring
Expand Down
12 changes: 6 additions & 6 deletions hphp/hack/src/parser/ast_visitor.ml
Expand Up @@ -30,7 +30,7 @@ class type ['a] ast_visitor_type = object
method on_binop : 'a -> bop -> expr -> expr -> 'a
method on_pipe : 'a -> expr -> expr -> 'a
method on_block : 'a -> block -> 'a
method on_break : 'a -> Pos.t -> 'a
method on_break : 'a -> Pos.t -> int option -> 'a
method on_call : 'a -> expr -> expr list -> expr list -> 'a
method on_case : 'a -> case -> 'a
method on_cast : 'a -> hint -> expr -> 'a
Expand All @@ -39,7 +39,7 @@ class type ['a] ast_visitor_type = object
method on_class_get : 'a -> id -> pstring -> 'a
method on_clone : 'a -> expr -> 'a
method on_collection: 'a -> id -> afield list -> 'a
method on_continue : 'a -> Pos.t -> 'a
method on_continue : 'a -> Pos.t -> int option -> 'a
method on_darray : 'a -> (expr * expr) list -> 'a
method on_def_inline : 'a -> def -> 'a
method on_do : 'a -> block -> expr -> 'a
Expand Down Expand Up @@ -138,8 +138,8 @@ end

class virtual ['a] ast_visitor: ['a] ast_visitor_type = object(this)

method on_break acc _ = acc
method on_continue acc _ = acc
method on_break acc _ _ = acc
method on_continue acc _ _ = acc
method on_noop acc = acc
method on_fallthrough acc = acc
method on_unsafe acc = acc
Expand Down Expand Up @@ -233,9 +233,9 @@ class virtual ['a] ast_visitor: ['a] ast_visitor_type = object(this)
method on_stmt acc = function
| Unsafe -> this#on_unsafe acc
| Expr e -> this#on_expr acc e
| Break p -> this#on_break acc p
| Break (p, level_opt) -> this#on_break acc p level_opt
| Block b -> this#on_block acc b
| Continue p -> this#on_continue acc p
| Continue (p, level_opt) -> this#on_continue acc p level_opt
| Throw (e) -> this#on_throw acc e
| Return (p, eopt) -> this#on_return acc p eopt
| GotoLabel label -> this#on_goto_label acc label
Expand Down
12 changes: 6 additions & 6 deletions hphp/hack/src/parser/ast_visitors_endo.ml
Expand Up @@ -668,12 +668,12 @@ class virtual ['self] endo =
method on_Block env this c0 =
let r0 = self#on_block env c0 in
if c0 == r0 then this else Block r0
method on_Break env this c0 =
method on_Break env this c0 level_opt =
let r0 = self#on_Pos_t env c0 in
if c0 == r0 then this else Break r0
method on_Continue env this c0 =
if c0 == r0 then this else Break (r0, level_opt)
method on_Continue env this c0 level_opt =
let r0 = self#on_Pos_t env c0 in
if c0 == r0 then this else Continue r0
if c0 == r0 then this else Continue(r0, level_opt)
method on_Throw env this c0 =
let r0 = self#on_expr env c0 in
if c0 == r0 then this else Throw r0
Expand Down Expand Up @@ -745,8 +745,8 @@ class virtual ['self] endo =
| Fallthrough -> self#on_Fallthrough env this
| Expr c0 -> self#on_Expr env this c0
| Block c0 -> self#on_Block env this c0
| Break c0 -> self#on_Break env this c0
| Continue c0 -> self#on_Continue env this c0
| Break (c0, level_opt) -> self#on_Break env this c0 level_opt
| Continue (c0, level_opt) -> self#on_Continue env this c0 level_opt
| Throw c0 -> self#on_Throw env this c0
| Return (c0, c1) -> self#on_Return env this c0 c1
| GotoLabel c0 -> self#on_GotoLabel env this c0
Expand Down
8 changes: 6 additions & 2 deletions hphp/hack/src/parser/ast_visitors_endo.mli
Expand Up @@ -94,6 +94,7 @@ class virtual ['b] endo :
on_Break : 'c ->
Ast_visitors_ancestors.stmt ->
Ast_visitors_ancestors.pos_t ->
int option ->
Ast_visitors_ancestors.stmt;
on_CA_enum : 'c ->
Ast_visitors_ancestors.ca_type ->
Expand Down Expand Up @@ -197,6 +198,7 @@ class virtual ['b] endo :
on_Continue : 'c ->
Ast_visitors_ancestors.stmt ->
Ast_visitors_ancestors.pos_t ->
int option ->
Ast_visitors_ancestors.stmt;
on_Contravariant : 'c ->
Ast_visitors_ancestors.variance ->
Expand Down Expand Up @@ -912,7 +914,8 @@ class virtual ['b] endo :
method on_Break :
'c ->
Ast_visitors_ancestors.stmt ->
Ast_visitors_ancestors.pos_t -> Ast_visitors_ancestors.stmt
Ast_visitors_ancestors.pos_t ->
int option -> Ast_visitors_ancestors.stmt
method on_CA_enum :
'c ->
Ast_visitors_ancestors.ca_type ->
Expand Down Expand Up @@ -1023,7 +1026,8 @@ class virtual ['b] endo :
method on_Continue :
'c ->
Ast_visitors_ancestors.stmt ->
Ast_visitors_ancestors.pos_t -> Ast_visitors_ancestors.stmt
Ast_visitors_ancestors.pos_t ->
int option -> Ast_visitors_ancestors.stmt
method on_Contravariant :
'c ->
Ast_visitors_ancestors.variance -> Ast_visitors_ancestors.variance
Expand Down
8 changes: 4 additions & 4 deletions hphp/hack/src/parser/ast_visitors_iter.ml
Expand Up @@ -356,8 +356,8 @@ class virtual ['self] iter =
method on_Fallthrough env = ()
method on_Expr = self#on_expr
method on_Block = self#on_block
method on_Break = self#on_Pos_t
method on_Continue = self#on_Pos_t
method on_Break env pos level_opt = self#on_Pos_t env pos
method on_Continue env pos level_opt = self#on_Pos_t env pos
method on_Throw = self#on_expr
method on_Return env c0 c1 =
self#on_Pos_t env c0;
Expand Down Expand Up @@ -398,8 +398,8 @@ class virtual ['self] iter =
| Fallthrough -> self#on_Fallthrough env
| Expr c0 -> self#on_Expr env c0
| Block c0 -> self#on_Block env c0
| Break c0 -> self#on_Break env c0
| Continue c0 -> self#on_Continue env c0
| Break (c0, level_opt) -> self#on_Break env c0 level_opt
| Continue (c0, level_opt) -> self#on_Continue env c0 level_opt
| Throw c0 -> self#on_Throw env c0
| Return (c0, c1) -> self#on_Return env c0 c1
| GotoLabel c0 -> self#on_GotoLabel env c0
Expand Down
11 changes: 7 additions & 4 deletions hphp/hack/src/parser/ast_visitors_iter.mli
Expand Up @@ -38,7 +38,7 @@ class virtual ['b] iter :
Ast_visitors_ancestors.expr ->
Ast_visitors_ancestors.expr -> unit;
on_Block : 'c -> Ast_visitors_ancestors.block -> unit;
on_Break : 'c -> Ast_visitors_ancestors.pos_t -> unit;
on_Break : 'c -> Ast_visitors_ancestors.pos_t -> int option -> unit;
on_CA_enum : 'c -> string list -> unit;
on_CA_field : 'c -> Ast_visitors_ancestors.ca_field -> unit;
on_CA_hint : 'c -> Ast_visitors_ancestors.hint -> unit;
Expand Down Expand Up @@ -82,7 +82,7 @@ class virtual ['b] iter :
on_Constant : 'c -> Ast_visitors_ancestors.gconst -> unit;
on_Constraint_as : 'c -> unit; on_Constraint_eq : 'c -> unit;
on_Constraint_super : 'c -> unit;
on_Continue : 'c -> Ast_visitors_ancestors.pos_t -> unit;
on_Continue : 'c -> Ast_visitors_ancestors.pos_t -> int option -> unit;
on_Contravariant : 'c -> unit; on_Covariant : 'c -> unit;
on_Cst_const : 'c -> unit; on_Cst_define : 'c -> unit;
on_Ctrait : 'c -> unit;
Expand Down Expand Up @@ -369,7 +369,7 @@ class virtual ['b] iter :
Ast_visitors_ancestors.bop ->
Ast_visitors_ancestors.expr -> Ast_visitors_ancestors.expr -> unit
method on_Block : 'c -> Ast_visitors_ancestors.block -> unit
method on_Break : 'c -> Ast_visitors_ancestors.pos_t -> unit
method on_Break : 'c -> Ast_visitors_ancestors.pos_t -> int option -> unit
method on_CA_enum : 'c -> string list -> unit
method on_CA_field : 'c -> Ast_visitors_ancestors.ca_field -> unit
method on_CA_hint : 'c -> Ast_visitors_ancestors.hint -> unit
Expand Down Expand Up @@ -419,7 +419,10 @@ class virtual ['b] iter :
method on_Constraint_as : 'c -> unit
method on_Constraint_eq : 'c -> unit
method on_Constraint_super : 'c -> unit
method on_Continue : 'c -> Ast_visitors_ancestors.pos_t -> unit
method on_Continue :
'c ->
Ast_visitors_ancestors.pos_t ->
int option -> unit
method on_Contravariant : 'c -> unit
method on_Covariant : 'c -> unit
method on_Cst_const : 'c -> unit
Expand Down
12 changes: 6 additions & 6 deletions hphp/hack/src/parser/ast_visitors_map.ml
Expand Up @@ -504,10 +504,10 @@ class virtual ['self] map =
let r0 = self#on_expr env c0 in Expr r0
method on_Block env c0 =
let r0 = self#on_block env c0 in Block r0
method on_Break env c0 =
let r0 = self#on_Pos_t env c0 in Break r0
method on_Continue env c0 =
let r0 = self#on_Pos_t env c0 in Continue r0
method on_Break env c0 level_opt =
let r0 = self#on_Pos_t env c0 in Break (r0, level_opt)
method on_Continue env c0 level_opt =
let r0 = self#on_Pos_t env c0 in Continue (r0, level_opt)
method on_Throw env c0 =
let r0 = self#on_expr env c0 in Throw r0
method on_Return env c0 c1 =
Expand Down Expand Up @@ -555,8 +555,8 @@ class virtual ['self] map =
| Fallthrough -> self#on_Fallthrough env
| Expr c0 -> self#on_Expr env c0
| Block c0 -> self#on_Block env c0
| Break c0 -> self#on_Break env c0
| Continue c0 -> self#on_Continue env c0
| Break (c0, level_opt) -> self#on_Break env c0 level_opt
| Continue (c0, level_opt) -> self#on_Continue env c0 level_opt
| Throw c0 -> self#on_Throw env c0
| Return (c0, c1) -> self#on_Return env c0 c1
| GotoLabel c0 -> self#on_GotoLabel env c0
Expand Down
6 changes: 4 additions & 2 deletions hphp/hack/src/parser/ast_visitors_map.mli
Expand Up @@ -70,6 +70,7 @@ class virtual ['c] map :
Ast_visitors_ancestors.stmt;
on_Break : 'd ->
Ast_visitors_ancestors.pos_t ->
int option ->
Ast_visitors_ancestors.stmt;
on_CA_enum : 'd -> string list -> Ast_visitors_ancestors.ca_type;
on_CA_field : 'd ->
Expand Down Expand Up @@ -139,6 +140,7 @@ class virtual ['c] map :
on_Constraint_super : 'd -> Ast_visitors_ancestors.constraint_kind;
on_Continue : 'd ->
Ast_visitors_ancestors.pos_t ->
int option ->
Ast_visitors_ancestors.stmt;
on_Contravariant : 'd -> Ast_visitors_ancestors.variance;
on_Covariant : 'd -> Ast_visitors_ancestors.variance;
Expand Down Expand Up @@ -682,7 +684,7 @@ class virtual ['c] map :
method on_Block :
'd -> Ast_visitors_ancestors.block -> Ast_visitors_ancestors.stmt
method on_Break :
'd -> Ast_visitors_ancestors.pos_t -> Ast_visitors_ancestors.stmt
'd -> Ast_visitors_ancestors.pos_t -> int option -> Ast_visitors_ancestors.stmt
method on_CA_enum : 'd -> string list -> Ast_visitors_ancestors.ca_type
method on_CA_field :
'd ->
Expand Down Expand Up @@ -748,7 +750,7 @@ class virtual ['c] map :
method on_Constraint_eq : 'd -> Ast_visitors_ancestors.constraint_kind
method on_Constraint_super : 'd -> Ast_visitors_ancestors.constraint_kind
method on_Continue :
'd -> Ast_visitors_ancestors.pos_t -> Ast_visitors_ancestors.stmt
'd -> Ast_visitors_ancestors.pos_t -> int option -> Ast_visitors_ancestors.stmt
method on_Contravariant : 'd -> Ast_visitors_ancestors.variance
method on_Covariant : 'd -> Ast_visitors_ancestors.variance
method on_Cst_const : 'd -> Ast_visitors_ancestors.cst_kind
Expand Down
8 changes: 4 additions & 4 deletions hphp/hack/src/parser/ast_visitors_reduce.ml
Expand Up @@ -390,8 +390,8 @@ class virtual ['self] reduce =
method on_Fallthrough _ = self#e
method on_Expr = self#on_expr
method on_Block = self#on_block
method on_Break = self#on_Pos_t
method on_Continue = self#on_Pos_t
method on_Break env pos level_opt = self#on_Pos_t env pos
method on_Continue env pos level_opt = self#on_Pos_t env pos
method on_Throw = self#on_expr
method on_Return env c0 c1 =
let r0 = self#on_Pos_t env c0 in
Expand Down Expand Up @@ -440,8 +440,8 @@ class virtual ['self] reduce =
| Fallthrough -> self#on_Fallthrough env
| Expr c0 -> self#on_Expr env c0
| Block c0 -> self#on_Block env c0
| Break c0 -> self#on_Break env c0
| Continue c0 -> self#on_Continue env c0
| Break (c0, level_opt) -> self#on_Break env c0 level_opt
| Continue (c0, level_opt) -> self#on_Continue env c0 level_opt
| Throw c0 -> self#on_Throw env c0
| Return (c0, c1) -> self#on_Return env c0 c1
| GotoLabel c0 -> self#on_GotoLabel env c0
Expand Down

0 comments on commit c383b94

Please sign in to comment.