@ -153,6 +153,8 @@ let sequence_blocks ~(continue : block -> Procdesc.Node.t) ~(stop : block -> Pro
( first_block . start , continue_node , new_stop )
( first_block . start , continue_node , new_stop )
(* * Chain a list of blocks together in a conjunctive style: a failure in any block leads to a global
failure , and successes lead to the next block . * )
let all_blocks env ( blocks : block list ) : block =
let all_blocks env ( blocks : block list ) : block =
match blocks with
match blocks with
| [] ->
| [] ->
@ -164,6 +166,8 @@ let all_blocks env (blocks : block list) : block =
{ start ; exit_success ; exit_failure }
{ start ; exit_success ; exit_failure }
(* * Chain a list of blocks together in a disjunctive style: a success in any block leads to a global
success , and failures lead to the next block . * )
let any_block env ( blocks : block list ) : block =
let any_block env ( blocks : block list ) : block =
match blocks with
match blocks with
| [] ->
| [] ->
@ -248,12 +252,23 @@ let rec translate_pattern env (value : Ident.t) {Ast.line; simple_expression} =
{ start = exit_success ; exit_success ; exit_failure }
{ start = exit_success ; exit_success ; exit_failure }
| e ->
| e ->
(* TODO: Cover all cases. *)
(* TODO: Cover all cases. *)
L . debug Capture Verbose " @[todo ErlangTranslat e .translate_pattern %s@."
L . debug Capture Verbose " @[todo ErlangTranslat or .translate_pattern %s@."
( Sexp . to_string ( Ast . sexp_of_simple_expression e ) ) ;
( Sexp . to_string ( Ast . sexp_of_simple_expression e ) ) ;
make_block_failure env
make_block_failure env
let rec instructions_of_expression env { Ast . line ; simple_expression } : Sil . instr list =
let make_instruction_block env instructions =
let exit_success = Node . make_stmt env ~ kind : ErlangExpression instructions in
let exit_failure = Node . make_nop env in
{ start = exit_success ; exit_success ; exit_failure }
let make_load_block env id e typ =
let instruction = Sil . Load { id ; e ; root_typ = typ ; typ ; loc = env . location } in
make_instruction_block env [ instruction ]
let rec translate_expression env { Ast . line ; simple_expression } =
let env = update_location line env in
let env = update_location line env in
let any = typ_of_name Any in
let any = typ_of_name Any in
let procdesc = Option . value_exn env . procdesc in
let procdesc = Option . value_exn env . procdesc in
@ -261,7 +276,7 @@ let rec instructions_of_expression env {Ast.line; simple_expression} : Sil.instr
let ret_var =
let ret_var =
match env . result with Some ( Var ret_var ) -> ret_var | _ -> Ident . create_fresh Ident . knormal
match env . result with Some ( Var ret_var ) -> ret_var | _ -> Ident . create_fresh Ident . knormal
in
in
let instructions =
let expression_block =
match simple_expression with
match simple_expression with
| Call
| Call
{ module_ = None
{ module_ = None
@ -280,32 +295,33 @@ let rec instructions_of_expression env {Ast.line; simple_expression} : Sil.instr
Procname . make_erlang ~ module_name ~ function_name ~ arity
Procname . make_erlang ~ module_name ~ function_name ~ arity
in
in
let args_with_ids = List . map ~ f : ( fun a -> ( a , Ident . create_fresh Ident . knormal ) ) args in
let args_with_ids = List . map ~ f : ( fun a -> ( a , Ident . create_fresh Ident . knormal ) ) args in
let args_ instruction s =
let args_ block s =
let f ( one_arg_expression , one_arg_ret_var ) =
let f ( one_arg_expression , one_arg_ret_var ) =
let result = Some ( Exp . Var one_arg_ret_var ) in
let result = Some ( Exp . Var one_arg_ret_var ) in
instructions_of _expression { env with result } one_arg_expression
translate _expression { env with result } one_arg_expression
in
in
List . concat_ map ~ f args_with_ids
List . map ~ f args_with_ids
in
in
let fun_exp = Exp . Const ( Cfun callee_procname ) in
let fun_exp = Exp . Const ( Cfun callee_procname ) in
let args_ids_and_types =
let args_ids_and_types =
List . map ~ f : ( function _ , id -> ( Exp . Var id , any ) ) args_with_ids
List . map ~ f : ( function _ , id -> ( Exp . Var id , any ) ) args_with_ids
in
in
args_instructions
let call_instruction =
@ [ Sil . Call ( ( ret_var , any ) , fun_exp , args_ids_and_types , env . location , CallFlags . default ) ]
Sil . Call ( ( ret_var , any ) , fun_exp , args_ids_and_types , env . location , CallFlags . default )
in
let call_block = make_instruction_block env [ call_instruction ] in
all_blocks env ( args_blocks @ [ call_block ] )
| Cons { head ; tail } ->
| Cons { head ; tail } ->
let head_var = Ident . create_fresh Ident . knormal in
let head_var = Ident . create_fresh Ident . knormal in
let tail_var = Ident . create_fresh Ident . knormal in
let tail_var = Ident . create_fresh Ident . knormal in
let head_instructions =
let head_block = translate_expression { env with result = Some ( Var head_var ) } head in
instructions_of_expression { env with result = Some ( Var head_var ) } head
let tail_block = translate_expression { env with result = Some ( Var tail_var ) } tail in
in
let tail_instructions =
instructions_of_expression { env with result = Some ( Var tail_var ) } tail
in
let fun_exp = Exp . Const ( Cfun BuiltinDecl . __erlang_make_cons ) in
let fun_exp = Exp . Const ( Cfun BuiltinDecl . __erlang_make_cons ) in
let args : ( Exp . t * Typ . t ) list = [ ( Var head_var , any ) ; ( Var tail_var , any ) ] in
let args : ( Exp . t * Typ . t ) list = [ ( Var head_var , any ) ; ( Var tail_var , any ) ] in
head_instructions @ tail_instructions
let call_instruction =
@ [ Sil . Call ( ( ret_var , any ) , fun_exp , args , env . location , CallFlags . default ) ]
Sil . Call ( ( ret_var , any ) , fun_exp , args , env . location , CallFlags . default )
in
all_blocks env [ head_block ; tail_block ; make_instruction_block env [ call_instruction ] ]
| Literal ( Atom atom ) ->
| Literal ( Atom atom ) ->
let hash =
let hash =
(* With this hack, an atom may accidentaly be considered equal to an unrelated integer.
(* With this hack, an atom may accidentaly be considered equal to an unrelated integer.
@ -313,34 +329,32 @@ let rec instructions_of_expression env {Ast.line; simple_expression} : Sil.instr
String . hash atom lsl 16
String . hash atom lsl 16
in
in
let e = Exp . Const ( Cint ( IntLit . of_int hash ) ) in
let e = Exp . Const ( Cint ( IntLit . of_int hash ) ) in
[ Sil . Load { id = ret_var ; e ; root_typ = any ; typ = any ; loc = env . location } ]
make_load_block env ret_var e any
| Literal ( String s ) ->
| Literal ( String s ) ->
let e = Exp . Const ( Cstr s ) in
let e = Exp . Const ( Cstr s ) in
[ Sil . Load { id = ret_var ; e ; root_typ = any ; typ = any ; loc = env . location } ]
make_load_block env ret_var e any
| Nil ->
| Nil ->
let fun_exp = Exp . Const ( Cfun BuiltinDecl . __erlang_make_nil ) in
let fun_exp = Exp . Const ( Cfun BuiltinDecl . __erlang_make_nil ) in
[ Sil . Call ( ( ret_var , any ) , fun_exp , [] , env . location , CallFlags . default ) ]
let instruction = Sil . Call ( ( ret_var , any ) , fun_exp , [] , env . location , CallFlags . default ) in
make_instruction_block env [ instruction ]
| Variable vname ->
| Variable vname ->
let e = Exp . Lvar ( Pvar . mk ( Mangled . from_string vname ) procname ) in
let e = Exp . Lvar ( Pvar . mk ( Mangled . from_string vname ) procname ) in
[ Sil . Load { id = ret_var ; e ; root_typ = any ; typ = any ; loc = env . location } ]
make_load_block env ret_var e any
| todo ->
| todo ->
L . debug Capture Verbose " @[todo ErlangTranslat e.instructions_of _expression %s@."
L . debug Capture Verbose " @[todo ErlangTranslat or.translate _expression %s@."
( Sexp . to_string ( Ast . sexp_of_simple_expression todo ) ) ;
( Sexp . to_string ( Ast . sexp_of_simple_expression todo ) ) ;
[]
make_block_success env
in
in
(* Add extra nodes/instructions to store return value if needed *)
match env . result with
match env . result with
| None | Some ( Var _ ) ->
| None | Some ( Var _ ) ->
instructions
expression_block
| Some result ->
| Some result ->
instructions
let store_instr =
@ [ Sil . Store { e1 = result ; root_typ = any ; typ = any ; e2 = Var ret_var ; loc = env . location } ]
Sil . Store { e1 = result ; root_typ = any ; typ = any ; e2 = Var ret_var ; loc = env . location }
in
let store_block = make_instruction_block env [ store_instr ] in
let translate_expression env expression =
all_blocks env [ expression_block ; store_block ]
let instructions = instructions_of_expression env expression in
let exit_success = Node . make_stmt env ~ kind : ErlangExpression instructions in
let exit_failure = Node . make_nop env in
{ start = exit_success ; exit_success ; exit_failure }
let translate_body env body : block =
let translate_body env body : block =