2019-10-03 22:47:09 +04:00
(* The Transpiler is a function that takes as input the Typed AST, and outputs expressions in a language that is basically a Michelson with named variables and first-class-environments.
2019-10-03 22:37:07 +04:00
For more info , see back - end . md : https : // gitlab . com / ligolang / ligo / blob / dev / gitlab - pages / docs / contributors / big - picture / back - end . md * )
2019-12-10 22:00:21 +04:00
open Trace
2019-09-11 15:56:39 +04:00
open Helpers
2019-05-13 00:56:22 +04:00
module AST = Ast_typed
module Append_tree = Tree . Append
open AST . Combinators
2019-05-20 12:38:38 +04:00
open Mini_c
2019-05-13 00:56:22 +04:00
2019-09-11 15:56:39 +04:00
let untranspile = Untranspiler . untranspile
2019-05-13 00:56:22 +04:00
let temp_unwrap_loc = Location . unwrap
let temp_unwrap_loc_list = List . map Location . unwrap
2019-06-04 12:21:13 +04:00
module Errors = struct
let corner_case ~ loc message =
let title () = " corner case " in
let content () = " we don't have a good error message for this case. we are
striving find ways to better report them and find the use - cases that generate
them . please report this to the developers . " in
let data = [
( " location " , fun () -> loc ) ;
( " message " , fun () -> message ) ;
] in
error ~ data title content
2019-10-09 08:51:29 +04:00
let no_type_variable name =
let title () = " type variables can't be transpiled " in
2019-12-04 15:40:58 +04:00
let content () = Format . asprintf " %a " Var . pp name in
2019-10-09 08:51:29 +04:00
error title content
2019-07-20 15:46:42 +04:00
let row_loc l = ( " location " , fun () -> Format . asprintf " %a " Location . pp l )
2019-06-04 12:21:13 +04:00
let unsupported_pattern_matching kind location =
let title () = " unsupported pattern-matching " in
let content () = Format . asprintf " %s patterns aren't supported yet " kind in
let data = [
2019-07-20 15:46:42 +04:00
row_loc location ;
] in
error ~ data title content
let unsupported_iterator location =
let title () = " unsupported iterator " in
let content () = " only lambda are supported as iterators " in
let data = [
row_loc location ;
] in
2019-06-04 12:21:13 +04:00
error ~ data title content
let not_functional_main location =
let title () = " not functional main " in
let content () = " main should be a function " in
let data = [
( " location " , fun () -> Format . asprintf " %a " Location . pp location ) ;
] in
error ~ data title content
2019-09-04 21:05:45 +04:00
let bad_big_map location =
let title () = " bad arguments for main " in
2019-09-26 18:53:25 +04:00
let content () = " only one big_map per program which must appear
2019-09-04 21:05:45 +04:00
on the left hand side of a pair in the contract's storage " in
let data = [
( " location " , fun () -> Format . asprintf " %a " Location . pp location ) ;
] in
error ~ data title content
2019-06-04 12:21:13 +04:00
let missing_entry_point name =
let title () = " missing entry point " in
let content () = " no entry point with the given name " in
let data = [
( " name " , fun () -> name ) ;
] in
error ~ data title content
let wrong_mini_c_value expected_type actual =
let title () = " illed typed intermediary value " in
let content () = " type of intermediary value doesn't match what was expected " in
let data = [
( " expected_type " , fun () -> expected_type ) ;
( " actual " , fun () -> Format . asprintf " %a " Mini_c . PP . value actual ) ;
] in
error ~ data title content
let bad_untranspile bad_type value =
let title () = " untranspiling bad value " in
let content () = Format . asprintf " can not untranspile %s " bad_type in
let data = [
( " bad_type " , fun () -> bad_type ) ;
( " value " , fun () -> Format . asprintf " %a " Mini_c . PP . value value ) ;
] in
error ~ data title content
let unknown_untranspile unknown_type value =
let title () = " untranspiling unknown value " in
let content () = Format . asprintf " can not untranspile %s " unknown_type in
let data = [
( " unknown_type " , fun () -> unknown_type ) ;
( " value " , fun () -> Format . asprintf " %a " Mini_c . PP . value value ) ;
] in
error ~ data title content
2020-03-09 03:13:07 +04:00
let unsupported_recursive_function expression_variable =
let title () = " unsupported recursive function yet " in
let content () = " only fuction with one variable are supported " in
let data = [
( " value " , fun () -> Format . asprintf " %a " AST . PP . expression_variable expression_variable ) ;
] in
error ~ data title content
2019-10-28 07:24:21 +04:00
2019-06-04 12:21:13 +04:00
end
open Errors
2019-12-04 21:30:52 +04:00
let rec transpile_type ( t : AST . type_expression ) : type_value result =
match t . type_content with
2019-12-04 15:40:58 +04:00
| T_variable ( name ) -> fail @@ no_type_variable @@ name
2019-12-04 21:30:52 +04:00
| T_constant ( TC_bool ) -> ok ( T_base TC_bool )
| T_constant ( TC_int ) -> ok ( T_base TC_int )
| T_constant ( TC_nat ) -> ok ( T_base TC_nat )
| T_constant ( TC_mutez ) -> ok ( T_base TC_mutez )
| T_constant ( TC_string ) -> ok ( T_base TC_string )
| T_constant ( TC_bytes ) -> ok ( T_base TC_bytes )
| T_constant ( TC_address ) -> ok ( T_base TC_address )
| T_constant ( TC_timestamp ) -> ok ( T_base TC_timestamp )
| T_constant ( TC_unit ) -> ok ( T_base TC_unit )
| T_constant ( TC_operation ) -> ok ( T_base TC_operation )
| T_constant ( TC_signature ) -> ok ( T_base TC_signature )
| T_constant ( TC_key ) -> ok ( T_base TC_key )
| T_constant ( TC_key_hash ) -> ok ( T_base TC_key_hash )
| T_constant ( TC_chain_id ) -> ok ( T_base TC_chain_id )
| T_constant ( TC_void ) -> ok ( T_base TC_void )
2019-12-04 15:40:58 +04:00
| T_operator ( TC_contract x ) ->
2019-09-11 15:56:39 +04:00
let % bind x' = transpile_type x in
2019-05-13 00:56:22 +04:00
ok ( T_contract x' )
2019-12-04 15:40:58 +04:00
| T_operator ( TC_map ( key , value ) ) ->
2019-09-11 15:56:39 +04:00
let % bind kv' = bind_map_pair transpile_type ( key , value ) in
2019-05-13 00:56:22 +04:00
ok ( T_map kv' )
2019-12-04 15:40:58 +04:00
| T_operator ( TC_big_map ( key , value ) ) ->
2019-09-23 00:17:28 +04:00
let % bind kv' = bind_map_pair transpile_type ( key , value ) in
2019-09-03 20:33:30 +04:00
ok ( T_big_map kv' )
2020-03-25 22:10:04 +04:00
| T_operator ( TC_map_or_big_map ( _ , _ ) ) ->
fail @@ corner_case ~ loc : " transpiler " " TC_map_or_big_map should be resolve before transpilation "
2019-12-04 15:40:58 +04:00
| T_operator ( TC_list t ) ->
2019-09-11 15:56:39 +04:00
let % bind t' = transpile_type t in
2019-05-13 00:56:22 +04:00
ok ( T_list t' )
2019-12-04 15:40:58 +04:00
| T_operator ( TC_set t ) ->
2019-09-11 15:56:39 +04:00
let % bind t' = transpile_type t in
2019-06-11 04:52:09 +04:00
ok ( T_set t' )
2019-12-04 15:40:58 +04:00
| T_operator ( TC_option o ) ->
2019-09-11 15:56:39 +04:00
let % bind o' = transpile_type o in
2019-05-13 00:56:22 +04:00
ok ( T_option o' )
2019-12-06 21:33:01 +04:00
| T_operator ( TC_arrow ( param , result ) ) -> (
let % bind param' = transpile_type param in
let % bind result' = transpile_type result in
ok ( T_function ( param' , result' ) )
)
2019-08-27 05:34:00 +04:00
(* TODO hmm *)
2019-05-13 00:56:22 +04:00
| T_sum m ->
2019-12-04 15:40:58 +04:00
let node = Append_tree . of_list @@ kv_list_of_cmap m in
2019-08-27 05:34:00 +04:00
let aux a b : type_value annotated result =
2019-05-13 00:56:22 +04:00
let % bind a = a in
let % bind b = b in
2019-08-27 05:34:00 +04:00
ok ( None , T_or ( a , b ) )
2019-05-13 00:56:22 +04:00
in
2019-08-27 05:34:00 +04:00
let % bind m' = Append_tree . fold_ne
2019-12-04 21:30:52 +04:00
( fun ( Stage_common . Types . Constructor ann , a ) ->
2019-08-27 05:34:00 +04:00
let % bind a = transpile_type a in
ok ( Some ( String . uncapitalize_ascii ann ) , a ) )
aux node in
ok @@ snd m'
2019-05-13 00:56:22 +04:00
| T_record m ->
2019-12-04 15:40:58 +04:00
let node = Append_tree . of_list @@ kv_list_of_lmap m in
2019-08-27 05:34:00 +04:00
let aux a b : type_value annotated result =
2019-05-13 00:56:22 +04:00
let % bind a = a in
let % bind b = b in
2019-08-27 05:34:00 +04:00
ok ( None , T_pair ( a , b ) )
2019-05-13 00:56:22 +04:00
in
2019-08-27 05:34:00 +04:00
let % bind m' = Append_tree . fold_ne
2019-12-04 21:30:52 +04:00
( fun ( Stage_common . Types . Label ann , a ) ->
2019-08-27 05:34:00 +04:00
let % bind a = transpile_type a in
ok ( Some ann , a ) )
aux node in
ok @@ snd m'
2019-12-04 21:30:52 +04:00
| T_arrow { type1 ; type2 } -> (
let % bind param' = transpile_type type1 in
let % bind result' = transpile_type type2 in
ok ( T_function ( param' , result' ) )
2019-05-17 20:03:41 +04:00
)
2019-05-13 00:56:22 +04:00
2019-12-04 21:30:52 +04:00
let record_access_to_lr : type_value -> type_value AST . label_map -> AST . label -> ( type_value * [ ` Left | ` Right ] ) list result = fun ty tym ind ->
2019-12-04 15:40:58 +04:00
let tys = kv_list_of_lmap tym in
2019-05-13 00:56:22 +04:00
let node_tv = Append_tree . of_list tys in
let % bind path =
2019-12-04 21:30:52 +04:00
let aux ( i , _ ) = i = ind in
2019-06-05 10:43:33 +04:00
trace_option ( corner_case ~ loc : _ _ LOC__ " record access leaf " ) @@
2019-05-13 00:56:22 +04:00
Append_tree . exists_path aux node_tv in
let lr_path = List . map ( fun b -> if b then ` Right else ` Left ) path in
let % bind ( _ , lst ) =
let aux = fun ( ty , acc ) cur ->
2019-06-05 10:43:33 +04:00
let % bind ( a , b ) =
2020-01-09 21:23:37 +04:00
trace_strong ( corner_case ~ loc : _ _ LOC__ " record access pair " ) @@
2019-06-05 10:43:33 +04:00
Mini_c . get_t_pair ty in
2019-05-13 00:56:22 +04:00
match cur with
| ` Left -> ok ( a , acc @ [ ( a , ` Left ) ] )
| ` Right -> ok ( b , acc @ [ ( b , ` Right ) ] ) in
bind_fold_list aux ( ty , [] ) lr_path in
ok lst
2019-09-11 15:56:39 +04:00
let rec transpile_literal : AST . literal -> value = fun l -> match l with
2019-05-13 00:56:22 +04:00
| Literal_bool b -> D_bool b
| Literal_int n -> D_int n
| Literal_nat n -> D_nat n
2019-06-10 13:58:16 +04:00
| Literal_timestamp n -> D_timestamp n
2019-09-24 16:29:18 +04:00
| Literal_mutez n -> D_mutez n
2019-05-13 00:56:22 +04:00
| Literal_bytes s -> D_bytes s
| Literal_string s -> D_string s
| Literal_address s -> D_string s
2019-11-19 18:12:58 +04:00
| Literal_signature s -> D_string s
| Literal_key s -> D_string s
2019-11-21 16:12:52 +04:00
| Literal_key_hash s -> D_string s
2019-11-20 18:01:04 +04:00
| Literal_chain_id s -> D_string s
2019-05-13 00:56:22 +04:00
| Literal_operation op -> D_operation op
| Literal_unit -> D_unit
2019-12-04 21:30:52 +04:00
| Literal_void -> D_none
2019-05-13 00:56:22 +04:00
2019-05-17 20:03:41 +04:00
and transpile_environment_element_type : AST . environment_element -> type_value result = fun ele ->
2019-10-25 10:01:45 +04:00
transpile_type ele . type_value
2019-05-13 00:56:22 +04:00
2019-12-04 21:30:52 +04:00
and tree_of_sum : AST . type_expression -> ( AST . constructor' * AST . type_expression ) Append_tree . t result = fun t ->
2019-05-13 00:56:22 +04:00
let % bind map_tv = get_t_sum t in
2019-12-04 15:40:58 +04:00
ok @@ Append_tree . of_list @@ kv_list_of_cmap map_tv
2019-05-13 00:56:22 +04:00
2019-12-04 21:30:52 +04:00
and transpile_annotated_expression ( ae : AST . expression ) : expression result =
let % bind tv = transpile_type ae . type_expression in
2019-05-17 20:03:41 +04:00
let return ? ( tv = tv ) expr = ok @@ Combinators . Expression . make_tpl ( expr , tv ) in
2019-06-04 12:21:13 +04:00
let info =
let title () = " translating expression " in
let content () = Format . asprintf " %a " Location . pp ae . location in
info title content in
trace info @@
2019-12-04 21:30:52 +04:00
match ae . expression_content with
| E_let_in { let_binder ; rhs ; let_result ; inline } ->
2019-09-11 15:56:39 +04:00
let % bind rhs' = transpile_annotated_expression rhs in
2019-12-04 21:30:52 +04:00
let % bind result' = transpile_annotated_expression let_result in
return ( E_let_in ( ( let_binder , rhs' . type_value ) , inline , rhs' , result' ) )
2019-09-11 15:56:39 +04:00
| E_literal l -> return @@ E_literal ( transpile_literal l )
2019-05-17 20:03:41 +04:00
| E_variable name -> (
let % bind ele =
2019-06-05 10:43:33 +04:00
trace_option ( corner_case ~ loc : _ _ LOC__ " name not in environment " ) @@
2019-05-17 20:03:41 +04:00
AST . Environment . get_opt name ae . environment in
let % bind tv = transpile_environment_element_type ele in
2019-12-04 15:40:58 +04:00
return ~ tv @@ E_variable ( name )
2019-05-17 20:03:41 +04:00
)
2020-03-18 20:27:27 +04:00
| E_application { lamb ; args } ->
let % bind a = transpile_annotated_expression lamb in
let % bind b = transpile_annotated_expression args in
2019-10-17 19:18:10 +04:00
return @@ E_application ( a , b )
2019-12-04 21:30:52 +04:00
| E_constructor { constructor ; element } -> (
let % bind param' = transpile_annotated_expression element in
2019-05-13 00:56:22 +04:00
let ( param'_expr , param'_tv ) = Combinators . Expression . ( get_content param' , get_type param' ) in
2019-06-04 12:21:13 +04:00
let % bind node_tv =
trace_strong ( corner_case ~ loc : _ _ LOC__ " getting lr tree " ) @@
2019-12-04 21:30:52 +04:00
tree_of_sum ae . type_expression in
2019-05-13 00:56:22 +04:00
let leaf ( k , tv ) : ( expression' option * type_value ) result =
2019-12-04 21:30:52 +04:00
if k = constructor then (
2019-05-13 00:56:22 +04:00
let % bind _ =
2019-06-04 12:21:13 +04:00
trace_strong ( corner_case ~ loc : _ _ LOC__ " wrong type for constructor parameter " )
2019-12-04 21:30:52 +04:00
@@ AST . assert_type_expression_eq ( tv , element . type_expression ) in
2019-05-13 00:56:22 +04:00
ok ( Some ( param'_expr ) , param'_tv )
) else (
2019-09-11 15:56:39 +04:00
let % bind tv = transpile_type tv in
2019-05-13 00:56:22 +04:00
ok ( None , tv )
) in
let node a b : ( expression' option * type_value ) result =
let % bind a = a in
let % bind b = b in
match ( a , b ) with
2019-08-27 05:34:00 +04:00
| ( None , a ) , ( None , b ) -> ok ( None , T_or ( ( None , a ) , ( None , b ) ) )
2019-06-04 12:21:13 +04:00
| ( Some _ , _ ) , ( Some _ , _ ) -> fail @@ corner_case ~ loc : _ _ LOC__ " multiple identical constructors in the same variant "
2019-12-04 21:30:52 +04:00
| ( Some v , a ) , ( None , b ) -> ok ( Some ( E_constant { cons_name = C_LEFT ; arguments = [ Combinators . Expression . make_tpl ( v , a ) ] } ) , T_or ( ( None , a ) , ( None , b ) ) )
| ( None , a ) , ( Some v , b ) -> ok ( Some ( E_constant { cons_name = C_RIGHT ; arguments = [ Combinators . Expression . make_tpl ( v , b ) ] } ) , T_or ( ( None , a ) , ( None , b ) ) )
2019-05-13 00:56:22 +04:00
in
let % bind ( ae_opt , tv ) = Append_tree . fold_ne leaf node node_tv in
let % bind ae =
2019-06-04 12:21:13 +04:00
trace_option ( corner_case ~ loc : _ _ LOC__ " inexistant constructor " )
2019-05-13 00:56:22 +04:00
ae_opt in
return ~ tv ae
2019-06-04 12:21:13 +04:00
)
| E_record m -> (
2019-12-04 15:40:58 +04:00
let node = Append_tree . of_list @@ list_of_lmap m in
2019-05-13 00:56:22 +04:00
let aux a b : expression result =
let % bind a = a in
let % bind b = b in
let a_ty = Combinators . Expression . get_type a in
let b_ty = Combinators . Expression . get_type b in
2019-08-27 05:34:00 +04:00
let tv = T_pair ( ( None , a_ty ) , ( None , b_ty ) ) in
2019-12-04 21:30:52 +04:00
return ~ tv @@ E_constant { cons_name = C_PAIR ; arguments = [ a ; b ] }
2019-05-13 00:56:22 +04:00
in
2019-06-04 12:21:13 +04:00
trace_strong ( corner_case ~ loc : _ _ LOC__ " record build " ) @@
2019-09-11 15:56:39 +04:00
Append_tree . fold_ne ( transpile_annotated_expression ) aux node
2019-06-04 12:21:13 +04:00
)
2020-03-23 19:00:50 +04:00
| E_record_accessor { record ; label } ->
let ty = get_type_expression record in
let % bind ty' = transpile_type ty in
2019-12-04 15:40:58 +04:00
let % bind ty_lmap =
2019-06-04 12:21:13 +04:00
trace_strong ( corner_case ~ loc : _ _ LOC__ " not a record " ) @@
2020-03-23 19:00:50 +04:00
get_t_record ty in
2019-12-04 21:30:52 +04:00
let % bind ty'_lmap = Stage_common . Helpers . bind_map_lmap transpile_type ty_lmap in
2019-06-04 12:21:13 +04:00
let % bind path =
trace_strong ( corner_case ~ loc : _ _ LOC__ " record access " ) @@
2019-12-04 21:30:52 +04:00
record_access_to_lr ty' ty'_lmap label in
2019-05-13 00:56:22 +04:00
let aux = fun pred ( ty , lr ) ->
let c = match lr with
2019-12-04 15:40:58 +04:00
| ` Left -> C_CAR
| ` Right -> C_CDR in
2019-12-04 21:30:52 +04:00
Combinators . Expression . make_tpl ( E_constant { cons_name = c ; arguments = [ pred ] } , ty ) in
2020-03-23 19:00:50 +04:00
let % bind record' = transpile_annotated_expression record in
2019-05-13 00:56:22 +04:00
let expr = List . fold_left aux record' path in
ok expr
2019-12-04 21:30:52 +04:00
| E_record_update { record ; path ; update } ->
let % bind ty' = transpile_type ( get_type_expression record ) in
2020-01-09 21:23:37 +04:00
let % bind ty_lmap =
trace_strong ( corner_case ~ loc : _ _ LOC__ " not a record " ) @@
2019-12-04 21:30:52 +04:00
get_t_record ( get_type_expression record ) in
let % bind ty'_lmap = Stage_common . Helpers . bind_map_lmap transpile_type ty_lmap in
2020-01-28 18:12:46 +04:00
let % bind path =
trace_strong ( corner_case ~ loc : _ _ LOC__ " record access " ) @@
2019-12-04 21:30:52 +04:00
record_access_to_lr ty' ty'_lmap path in
let path = List . map snd path in
let % bind update = transpile_annotated_expression update in
2020-01-09 21:23:37 +04:00
let % bind record = transpile_annotated_expression record in
2019-12-04 21:30:52 +04:00
return @@ E_record_update ( record , path , update )
| E_constant { cons_name = name ; arguments = lst } -> (
2019-09-24 01:33:25 +04:00
let iterator_generator iterator_name =
2019-12-04 21:30:52 +04:00
let lambda_to_iterator_body ( f : AST . expression ) ( l : AST . lambda ) =
let % bind body' = transpile_annotated_expression l . result in
let % bind ( input , _ ) = AST . get_t_function f . type_expression in
2019-09-24 01:33:25 +04:00
let % bind input' = transpile_type input in
2019-12-04 15:40:58 +04:00
ok ( ( l . binder , input' ) , body' )
2019-09-24 01:33:25 +04:00
in
2019-12-04 21:30:52 +04:00
let expression_to_iterator_body ( f : AST . expression ) =
match f . expression_content with
2019-09-24 01:33:25 +04:00
| E_lambda l -> lambda_to_iterator_body f l
| E_variable v -> (
let % bind elt =
trace_option ( corner_case ~ loc : _ _ LOC__ " missing var " ) @@
AST . Environment . get_opt v f . environment in
match elt . definition with
2020-02-17 21:09:35 +04:00
| ED_declaration { expr = f ; free_variables = _ } -> (
2019-12-04 21:30:52 +04:00
match f . expression_content with
2019-09-24 01:33:25 +04:00
| E_lambda l -> lambda_to_iterator_body f l
| _ -> fail @@ unsupported_iterator f . location
)
| _ -> fail @@ unsupported_iterator f . location
2019-07-20 15:46:42 +04:00
)
2019-09-24 01:33:25 +04:00
| _ -> fail @@ unsupported_iterator f . location
2019-07-20 15:46:42 +04:00
in
2019-12-04 21:30:52 +04:00
fun ( lst : AST . expression list ) -> match ( lst , iterator_name ) with
2019-12-04 15:40:58 +04:00
| [ f ; i ] , C_ITER | [ f ; i ] , C_MAP -> (
2019-09-24 01:33:25 +04:00
let % bind f' = expression_to_iterator_body f in
let % bind i' = transpile_annotated_expression i in
return @@ E_iterator ( iterator_name , f' , i' )
)
2019-12-04 15:40:58 +04:00
| [ f ; collection ; initial ] , C_FOLD -> (
2019-09-24 01:33:25 +04:00
let % bind f' = expression_to_iterator_body f in
let % bind initial' = transpile_annotated_expression initial in
let % bind collection' = transpile_annotated_expression collection in
return @@ E_fold ( f' , collection' , initial' )
)
2019-12-04 15:40:58 +04:00
| _ -> fail @@ corner_case ~ loc : _ _ LOC__ ( Format . asprintf " bad iterator arity: %a " Stage_common . PP . constant iterator_name )
2019-09-24 01:33:25 +04:00
in
2019-12-04 15:40:58 +04:00
let ( iter , map , fold ) = iterator_generator C_ITER , iterator_generator C_MAP , iterator_generator C_FOLD in
2019-07-20 15:46:42 +04:00
match ( name , lst ) with
2019-12-04 15:40:58 +04:00
| ( C_SET_ITER , lst ) -> iter lst
| ( C_LIST_ITER , lst ) -> iter lst
| ( C_MAP_ITER , lst ) -> iter lst
| ( C_LIST_MAP , lst ) -> map lst
| ( C_MAP_MAP , lst ) -> map lst
| ( C_LIST_FOLD , lst ) -> fold lst
| ( C_SET_FOLD , lst ) -> fold lst
| ( C_MAP_FOLD , lst ) -> fold lst
2019-07-20 15:46:42 +04:00
| _ -> (
2019-09-11 15:56:39 +04:00
let % bind lst' = bind_map_list ( transpile_annotated_expression ) lst in
2019-12-04 21:30:52 +04:00
return @@ E_constant { cons_name = name ; arguments = lst' }
2019-07-20 15:46:42 +04:00
)
2019-06-04 12:21:13 +04:00
)
2019-05-17 20:03:41 +04:00
| E_lambda l ->
2019-12-04 21:30:52 +04:00
let % bind io = AST . get_t_function ae . type_expression in
2019-10-25 10:01:45 +04:00
transpile_lambda l io
2020-02-28 21:58:53 +04:00
| E_recursive r ->
transpile_recursive r
2019-12-04 21:30:52 +04:00
| E_matching { matchee = expr ; cases = m } -> (
2019-09-11 15:56:39 +04:00
let % bind expr' = transpile_annotated_expression expr in
2019-05-13 00:56:22 +04:00
match m with
| Match_bool { match_true ; match_false } ->
2019-09-11 15:56:39 +04:00
let % bind ( t , f ) = bind_map_pair ( transpile_annotated_expression ) ( match_true , match_false ) in
2019-05-15 22:28:25 +04:00
return @@ E_if_bool ( expr' , t , f )
2019-12-04 15:40:58 +04:00
| Match_option { match_none ; match_some = ( name , s , tv ) } ->
2019-09-11 15:56:39 +04:00
let % bind n = transpile_annotated_expression match_none in
2019-05-13 00:56:22 +04:00
let % bind ( tv' , s' ) =
2019-09-11 15:56:39 +04:00
let % bind tv' = transpile_type tv in
let % bind s' = transpile_annotated_expression s in
2019-09-21 11:12:00 +04:00
ok ( tv' , s' )
in
2019-12-04 15:40:58 +04:00
return @@ E_if_none ( expr' , n , ( ( name , tv' ) , s' ) )
2019-09-21 11:12:00 +04:00
| Match_list {
match_nil ;
2019-12-04 15:40:58 +04:00
match_cons = ( ( hd_name ) , ( tl_name ) , match_cons , ty ) ;
2019-09-21 11:12:00 +04:00
} -> (
let % bind nil = transpile_annotated_expression match_nil in
let % bind cons =
2019-12-04 15:40:58 +04:00
let % bind ty' = transpile_type ty in
2019-09-21 11:12:00 +04:00
let % bind match_cons' = transpile_annotated_expression match_cons in
2019-12-04 15:40:58 +04:00
ok ( ( ( hd_name , ty' ) , ( tl_name , ty' ) ) , match_cons' )
2019-09-21 11:12:00 +04:00
in
return @@ E_if_cons ( expr' , nil , cons )
)
2019-05-13 00:56:22 +04:00
| Match_variant ( lst , variant ) -> (
2019-06-04 12:21:13 +04:00
let % bind tree =
trace_strong ( corner_case ~ loc : _ _ LOC__ " getting lr tree " ) @@
tree_of_sum variant in
2019-05-13 00:56:22 +04:00
let % bind tree' = match tree with
2019-06-04 12:21:13 +04:00
| Empty -> fail ( corner_case ~ loc : _ _ LOC__ " match empty variant " )
2019-05-13 00:56:22 +04:00
| Full x -> ok x in
let % bind tree'' =
let rec aux t =
match ( t : _ Append_tree . t' ) with
| Leaf ( name , tv ) ->
2019-09-11 15:56:39 +04:00
let % bind tv' = transpile_type tv in
2019-05-13 00:56:22 +04:00
ok ( ` Leaf name , tv' )
| Node { a ; b } ->
let % bind a' = aux a in
let % bind b' = aux b in
2019-08-27 05:34:00 +04:00
let tv' = Mini_c . t_union ( None , snd a' ) ( None , snd b' ) in
2019-05-13 00:56:22 +04:00
ok ( ` Node ( a' , b' ) , tv' )
in aux tree'
in
2019-05-17 20:03:41 +04:00
let rec aux top t =
2019-05-13 00:56:22 +04:00
match t with
| ( ( ` Leaf constructor_name ) , tv ) -> (
let % bind ( ( _ , name ) , body ) =
2019-06-04 12:21:13 +04:00
trace_option ( corner_case ~ loc : _ _ LOC__ " missing match clause " ) @@
2019-05-13 00:56:22 +04:00
List . find_opt ( fun ( ( constructor_name' , _ ) , _ ) -> constructor_name' = constructor_name ) lst in
2019-09-11 15:56:39 +04:00
let % bind body' = transpile_annotated_expression body in
2020-01-16 23:36:04 +04:00
return @@ E_let_in ( ( name , tv ) , false , top , body' )
2019-05-13 00:56:22 +04:00
)
| ( ( ` Node ( a , b ) ) , tv ) ->
let % bind a' =
let % bind a_ty = get_t_left tv in
2019-12-04 15:40:58 +04:00
let left_var = Var . fresh ~ name : " left " () in
let % bind e = aux ( ( ( Expression . make ( E_variable left_var ) a_ty ) ) ) a in
ok ( ( left_var , a_ty ) , e )
2019-05-13 00:56:22 +04:00
in
let % bind b' =
let % bind b_ty = get_t_right tv in
2019-12-04 15:40:58 +04:00
let right_var = Var . fresh ~ name : " right " () in
let % bind e = aux ( ( ( Expression . make ( E_variable right_var ) b_ty ) ) ) b in
ok ( ( right_var , b_ty ) , e )
2019-05-13 00:56:22 +04:00
in
2019-05-15 22:16:28 +04:00
return @@ E_if_left ( top , a' , b' )
2019-05-13 00:56:22 +04:00
in
2019-06-04 12:21:13 +04:00
trace_strong ( corner_case ~ loc : _ _ LOC__ " building constructor " ) @@
2019-05-17 20:03:41 +04:00
aux expr' tree''
2019-12-04 21:30:52 +04:00
)
2019-06-04 12:21:13 +04:00
| AST . Match_tuple _ -> fail @@ unsupported_pattern_matching " tuple " ae . location
2019-12-04 21:30:52 +04:00
)
2019-05-13 00:56:22 +04:00
2019-10-25 10:01:45 +04:00
and transpile_lambda l ( input_type , output_type ) =
2019-12-04 21:30:52 +04:00
let { binder ; result } : AST . lambda = l in
let % bind result' = transpile_annotated_expression result in
2019-10-25 10:01:45 +04:00
let % bind input = transpile_type input_type in
let % bind output = transpile_type output_type in
let tv = Combinators . t_function input output in
2019-12-04 21:30:52 +04:00
let binder = binder in
2019-12-04 15:40:58 +04:00
let closure = E_closure { binder ; body = result' } in
2019-10-25 10:01:45 +04:00
ok @@ Combinators . Expression . make_tpl ( closure , tv )
2019-05-13 00:56:22 +04:00
2020-02-28 21:58:53 +04:00
and transpile_recursive { fun_name ; fun_type ; lambda } =
2020-03-09 03:13:07 +04:00
let rec map_lambda : AST . expression_variable -> type_value -> AST . expression -> ( expression * expression_variable list ) result = fun fun_name loop_type e ->
2020-03-07 02:44:28 +04:00
match e . expression_content with
E_lambda { binder ; result } ->
2020-03-09 03:13:07 +04:00
let % bind ( body , l ) = map_lambda fun_name loop_type result in
ok @@ ( Expression . make ( E_closure { binder ; body } ) loop_type , binder :: l )
| _ ->
2020-03-12 18:41:26 +04:00
let % bind res = replace_callback fun_name loop_type false e in
2020-03-09 03:13:07 +04:00
ok @@ ( res , [] )
2020-03-07 02:44:28 +04:00
2020-03-12 18:41:26 +04:00
and replace_callback : AST . expression_variable -> type_value -> bool -> AST . expression -> expression result = fun fun_name loop_type shadowed e ->
2020-03-07 02:44:28 +04:00
match e . expression_content with
2020-03-12 18:41:26 +04:00
E_let_in li ->
let shadowed = shadowed | | Var . equal li . let_binder fun_name in
let % bind let_result = replace_callback fun_name loop_type shadowed li . let_result in
2020-03-07 02:44:28 +04:00
let % bind rhs = transpile_annotated_expression li . rhs in
let % bind ty = transpile_type e . type_expression in
ok @@ e_let_in li . let_binder ty li . inline rhs let_result |
E_matching m ->
let % bind ty = transpile_type e . type_expression in
2020-03-12 18:41:26 +04:00
matching fun_name loop_type shadowed m ty |
2020-03-18 20:27:27 +04:00
E_application { lamb ; args } -> (
match lamb . expression_content , shadowed with
2020-03-12 18:41:26 +04:00
E_variable name , false when Var . equal fun_name name ->
2020-03-18 20:27:27 +04:00
let % bind expr = transpile_annotated_expression args in
2020-03-07 02:44:28 +04:00
ok @@ Expression . make ( E_constant { cons_name = C_LOOP_CONTINUE ; arguments = [ expr ] } ) loop_type |
_ ->
let % bind expr = transpile_annotated_expression e in
ok @@ Expression . make ( E_constant { cons_name = C_LOOP_STOP ; arguments = [ expr ] } ) loop_type
) |
_ ->
let % bind expr = transpile_annotated_expression e in
ok @@ Expression . make ( E_constant { cons_name = C_LOOP_STOP ; arguments = [ expr ] } ) loop_type
2020-03-12 18:41:26 +04:00
and matching : AST . expression_variable -> type_value -> bool -> AST . matching -> type_value -> expression result = fun fun_name loop_type shadowed m ty ->
2020-03-07 02:44:28 +04:00
let return ret = ok @@ Expression . make ret @@ ty in
let % bind expr = transpile_annotated_expression m . matchee in
match m . cases with
Match_bool { match_true ; match_false } ->
2020-03-12 18:41:26 +04:00
let % bind ( t , f ) = bind_map_pair ( replace_callback fun_name loop_type shadowed ) ( match_true , match_false ) in
2020-03-07 02:44:28 +04:00
return @@ E_if_bool ( expr , t , f )
| Match_option { match_none ; match_some = ( name , s , tv ) } ->
2020-03-12 18:41:26 +04:00
let % bind n = replace_callback fun_name loop_type shadowed match_none in
2020-03-07 02:44:28 +04:00
let % bind ( tv' , s' ) =
let % bind tv' = transpile_type tv in
2020-03-12 18:41:26 +04:00
let % bind s' = replace_callback fun_name loop_type shadowed s in
2020-03-07 02:44:28 +04:00
ok ( tv' , s' )
in
return @@ E_if_none ( expr , n , ( ( name , tv' ) , s' ) )
| Match_list {
match_nil ;
match_cons = ( ( hd_name ) , ( tl_name ) , match_cons , ty ) ;
} -> (
2020-03-12 18:41:26 +04:00
let % bind nil = replace_callback fun_name loop_type shadowed match_nil in
2020-03-07 02:44:28 +04:00
let % bind cons =
let % bind ty' = transpile_type ty in
2020-03-12 18:41:26 +04:00
let % bind match_cons' = replace_callback fun_name loop_type shadowed match_cons in
2020-03-07 02:44:28 +04:00
ok ( ( ( hd_name , ty' ) , ( tl_name , ty' ) ) , match_cons' )
in
return @@ E_if_cons ( expr , nil , cons )
)
| Match_variant ( lst , variant ) -> (
let % bind tree =
trace_strong ( corner_case ~ loc : _ _ LOC__ " getting lr tree " ) @@
tree_of_sum variant in
let % bind tree' = match tree with
| Empty -> fail ( corner_case ~ loc : _ _ LOC__ " match empty variant " )
| Full x -> ok x in
let % bind tree'' =
let rec aux t =
match ( t : _ Append_tree . t' ) with
| Leaf ( name , tv ) ->
let % bind tv' = transpile_type tv in
ok ( ` Leaf name , tv' )
| Node { a ; b } ->
let % bind a' = aux a in
let % bind b' = aux b in
let tv' = Mini_c . t_union ( None , snd a' ) ( None , snd b' ) in
ok ( ` Node ( a' , b' ) , tv' )
in aux tree'
in
let rec aux top t =
match t with
| ( ( ` Leaf constructor_name ) , tv ) -> (
let % bind ( ( _ , name ) , body ) =
trace_option ( corner_case ~ loc : _ _ LOC__ " missing match clause " ) @@
List . find_opt ( fun ( ( constructor_name' , _ ) , _ ) -> constructor_name' = constructor_name ) lst in
2020-03-12 18:41:26 +04:00
let % bind body' = replace_callback fun_name loop_type shadowed body in
2020-03-07 02:44:28 +04:00
return @@ E_let_in ( ( name , tv ) , false , top , body' )
)
| ( ( ` Node ( a , b ) ) , tv ) ->
let % bind a' =
let % bind a_ty = get_t_left tv in
let left_var = Var . fresh ~ name : " left " () in
let % bind e = aux ( ( ( Expression . make ( E_variable left_var ) a_ty ) ) ) a in
ok ( ( left_var , a_ty ) , e )
in
let % bind b' =
let % bind b_ty = get_t_right tv in
let right_var = Var . fresh ~ name : " right " () in
let % bind e = aux ( ( ( Expression . make ( E_variable right_var ) b_ty ) ) ) b in
ok ( ( right_var , b_ty ) , e )
in
return @@ E_if_left ( top , a' , b' )
in
trace_strong ( corner_case ~ loc : _ _ LOC__ " building constructor " ) @@
aux expr tree''
)
| AST . Match_tuple _ -> failwith " match_tuple not supported "
in
let % bind fun_type = transpile_type fun_type in
let % bind ( input_type , output_type ) = get_t_function fun_type in
let loop_type = t_union ( None , input_type ) ( None , output_type ) in
2020-03-09 03:13:07 +04:00
let % bind ( body , binder ) = map_lambda fun_name loop_type lambda . result in
let binder = lambda . binder :: binder in
let % bind binder = match binder with hd :: [] -> ok @@ hd | _ -> fail @@ unsupported_recursive_function fun_name in
let expr = Expression . make_tpl ( E_variable binder , input_type ) in
2020-03-07 02:44:28 +04:00
let body = Expression . make ( E_iterator ( C_LOOP_LEFT , ( ( lambda . binder , loop_type ) , body ) , expr ) ) output_type in
2020-03-09 03:13:07 +04:00
ok @@ Expression . make ( E_closure { binder ; body } ) fun_type
2020-02-28 21:58:53 +04:00
2019-09-11 15:56:39 +04:00
let transpile_declaration env ( d : AST . declaration ) : toplevel_statement result =
2019-05-13 00:56:22 +04:00
match d with
2019-12-04 21:30:52 +04:00
| Declaration_constant ( name , expression , inline , _ ) ->
let name = name in
let % bind expression = transpile_annotated_expression expression in
2019-05-13 00:56:22 +04:00
let tv = Combinators . Expression . get_type expression in
2019-12-04 15:40:58 +04:00
let env' = Environment . add ( name , tv ) env in
2020-01-16 23:36:04 +04:00
ok @@ ( ( name , inline , expression ) , environment_wrap env env' )
2019-05-13 00:56:22 +04:00
2019-09-19 03:34:37 +04:00
let transpile_program ( lst : AST . program ) : program result =
2019-05-13 00:56:22 +04:00
let aux ( prev : ( toplevel_statement list * Environment . t ) result ) cur =
2019-09-19 14:59:07 +04:00
let % bind ( hds , env ) = prev in
2019-09-11 15:56:39 +04:00
let % bind ( ( _ , env' ) as cur' ) = transpile_declaration env cur in
2019-09-19 14:59:07 +04:00
ok ( hds @ [ cur' ] , env' . post_environment )
2019-05-13 00:56:22 +04:00
in
let % bind ( statements , _ ) = List . fold_left aux ( ok ( [] , Environment . empty ) ) ( temp_unwrap_loc_list lst ) in
ok statements
2019-09-04 21:05:45 +04:00
(* check whether the storage contains a big_map, if yes, check that
it appears on the left hand side of a pair * )
let check_storage f ty loc : ( anon_function * _ ) result =
let rec aux ( t : type_value ) on_big_map =
match t with
| T_big_map _ -> on_big_map
2019-09-26 18:53:25 +04:00
| T_pair ( a , b ) -> ( aux ( snd a ) true ) && ( aux ( snd b ) false )
| T_or ( a , b ) -> ( aux ( snd a ) false ) && ( aux ( snd b ) false )
2019-09-04 21:05:45 +04:00
| T_function ( a , b ) -> ( aux a false ) && ( aux b false )
| T_map ( a , b ) -> ( aux a false ) && ( aux b false )
| T_list a -> ( aux a false )
| T_set a -> ( aux a false )
| T_contract a -> ( aux a false )
| T_option a -> ( aux a false )
| _ -> true
in
2019-09-23 00:17:28 +04:00
match f . body . type_value with
2019-09-04 21:05:45 +04:00
| T_pair ( _ , storage ) ->
2019-09-26 18:53:25 +04:00
if aux ( snd storage ) false then ok ( f , ty ) else fail @@ bad_big_map loc
2019-09-04 21:05:45 +04:00
| _ -> ok ( f , ty )
2019-12-04 21:30:52 +04:00
let extract_constructor ( v : value ) ( tree : _ Append_tree . t' ) : ( string * value * AST . type_expression ) result =
2019-05-13 00:56:22 +04:00
let open Append_tree in
2019-12-04 21:30:52 +04:00
let rec aux tv : ( string * value * AST . type_expression ) result =
2019-05-13 00:56:22 +04:00
match tv with
| Leaf ( k , t ) , v -> ok ( k , v , t )
| Node { a } , D_left v -> aux ( a , v )
| Node { b } , D_right v -> aux ( b , v )
2019-06-05 16:26:01 +04:00
| _ -> fail @@ internal_assertion_failure " bad constructor path "
2019-05-13 00:56:22 +04:00
in
let % bind ( s , v , t ) = aux ( tree , v ) in
ok ( s , v , t )
2019-12-04 21:30:52 +04:00
let extract_tuple ( v : value ) ( tree : AST . type_expression Append_tree . t' ) : ( ( value * AST . type_expression ) list ) result =
2019-05-13 00:56:22 +04:00
let open Append_tree in
2019-12-04 21:30:52 +04:00
let rec aux tv : ( ( value * AST . type_expression ) list ) result =
2019-05-13 00:56:22 +04:00
match tv with
| Leaf t , v -> ok @@ [ v , t ]
| Node { a ; b } , D_pair ( va , vb ) ->
let % bind a' = aux ( a , va ) in
let % bind b' = aux ( b , vb ) in
ok ( a' @ b' )
2019-06-05 16:26:01 +04:00
| _ -> fail @@ internal_assertion_failure " bad tuple path "
2019-05-13 00:56:22 +04:00
in
aux ( tree , v )
let extract_record ( v : value ) ( tree : _ Append_tree . t' ) : ( _ list ) result =
let open Append_tree in
2019-12-04 21:30:52 +04:00
let rec aux tv : ( ( string * ( value * AST . type_expression ) ) list ) result =
2019-05-13 00:56:22 +04:00
match tv with
| Leaf ( s , t ) , v -> ok @@ [ s , ( v , t ) ]
| Node { a ; b } , D_pair ( va , vb ) ->
let % bind a' = aux ( a , va ) in
let % bind b' = aux ( b , vb ) in
ok ( a' @ b' )
2019-06-05 16:26:01 +04:00
| _ -> fail @@ internal_assertion_failure " bad record path "
2019-05-13 00:56:22 +04:00
in
aux ( tree , v )