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-05-13 00:56:22 +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
let unrecognized_type_constant name =
let title () = " unrecognized type constant " in
let content () = name in
error title content
2019-10-09 08:51:29 +04:00
let no_type_variable name =
let title () = " type variables can't be transpiled " in
let content () = name in
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
2019-10-28 07:24:21 +04:00
let not_found content =
let title () = " Not_found " in
let content () = content in
let data = [
] in
error ~ data title content
2019-06-04 12:21:13 +04:00
end
open Errors
2019-09-11 15:56:39 +04:00
let rec transpile_type ( t : AST . type_value ) : type_value result =
2019-05-13 00:56:22 +04:00
match t . type_value' with
2019-10-30 20:50:19 +04:00
| T_variable ( Type_name name ) -> fail @@ no_type_variable name
| T_constant ( Type_name " bool " , [] ) -> ok ( T_base Base_bool )
| T_constant ( Type_name " int " , [] ) -> ok ( T_base Base_int )
| T_constant ( Type_name " nat " , [] ) -> ok ( T_base Base_nat )
| T_constant ( Type_name " tez " , [] ) -> ok ( T_base Base_tez )
| T_constant ( Type_name " string " , [] ) -> ok ( T_base Base_string )
| T_constant ( Type_name " bytes " , [] ) -> ok ( T_base Base_bytes )
| T_constant ( Type_name " address " , [] ) -> ok ( T_base Base_address )
| T_constant ( Type_name " timestamp " , [] ) -> ok ( T_base Base_timestamp )
| T_constant ( Type_name " unit " , [] ) -> ok ( T_base Base_unit )
| T_constant ( Type_name " operation " , [] ) -> ok ( T_base Base_operation )
2019-11-01 01:18:09 +04:00
| T_constant ( Type_name " signature " , [] ) -> ok ( T_base Base_signature )
2019-11-19 18:12:58 +04:00
| T_constant ( Type_name " key " , [] ) -> ok ( T_base Base_key )
2019-11-20 18:01:04 +04:00
| T_constant ( Type_name " chain_id " , [] ) -> ok ( T_base Base_chain_id )
2019-10-30 20:50:19 +04:00
| T_constant ( Type_name " 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-10-30 20:50:19 +04:00
| T_constant ( Type_name " 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-10-30 20:50:19 +04:00
| T_constant ( Type_name " 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' )
2019-10-30 20:50:19 +04:00
| T_constant ( Type_name " 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-10-30 20:50:19 +04:00
| T_constant ( Type_name " 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-10-30 20:50:19 +04:00
| T_constant ( Type_name " 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-10-30 20:50:19 +04:00
| T_constant ( Type_name name , _ lst ) -> fail @@ unrecognized_type_constant name
2019-08-27 05:34:00 +04:00
(* TODO hmm *)
2019-05-13 00:56:22 +04:00
| T_sum m ->
2019-08-27 05:34:00 +04:00
let node = Append_tree . of_list @@ kv_list_of_map m in
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
( fun ( ann , a ) ->
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-08-27 05:34:00 +04:00
let node = Append_tree . of_list @@ kv_list_of_map m in
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
( fun ( ann , a ) ->
let % bind a = transpile_type a in
ok ( Some ann , a ) )
aux node in
ok @@ snd m'
2019-05-13 00:56:22 +04:00
| T_tuple lst ->
let node = Append_tree . of_list lst in
let aux a b : type_value result =
let % bind a = a in
let % bind b = b in
2019-08-27 05:34:00 +04:00
ok ( T_pair ( ( None , a ) , ( None , b ) ) )
2019-05-13 00:56:22 +04:00
in
2019-09-11 15:56:39 +04:00
Append_tree . fold_ne transpile_type aux node
2019-05-17 20:03:41 +04:00
| T_function ( param , result ) -> (
2019-09-11 15:56:39 +04:00
let % bind param' = transpile_type param in
let % bind result' = transpile_type result in
2019-05-13 00:56:22 +04:00
ok ( T_function ( param' , result' ) )
2019-05-17 20:03:41 +04:00
)
2019-05-13 00:56:22 +04:00
let tuple_access_to_lr : type_value -> type_value list -> int -> ( type_value * [ ` Left | ` Right ] ) list result = fun ty tys ind ->
let node_tv = Append_tree . of_list @@ List . mapi ( fun i a -> ( i , a ) ) tys in
let % bind path =
let aux ( i , _ ) = i = ind in
2019-06-05 10:43:33 +04:00
trace_option ( corner_case ~ loc : _ _ LOC__ " tuple 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 ->
let % bind ( a , b ) =
2019-06-05 10:43:33 +04:00
trace_strong ( corner_case ~ loc : _ _ LOC__ " tuple access pair " ) @@
2019-05-13 00:56:22 +04:00
Mini_c . get_t_pair ty' in
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
let record_access_to_lr : type_value -> type_value AST . type_name_map -> string -> ( type_value * [ ` Left | ` Right ] ) list result = fun ty tym ind ->
let tys = kv_list_of_map tym in
let node_tv = Append_tree . of_list tys in
let % bind path =
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 ) =
trace_strong ( corner_case ~ loc : _ _ LOC__ " recard access pair " ) @@
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-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-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
and tree_of_sum : AST . type_value -> ( type_name * AST . type_value ) Append_tree . t result = fun t ->
let % bind map_tv = get_t_sum t in
ok @@ Append_tree . of_list @@ kv_list_of_map map_tv
2019-09-11 15:56:39 +04:00
and transpile_annotated_expression ( ae : AST . annotated_expression ) : expression result =
let % bind tv = transpile_type ae . type_annotation in
2019-05-17 20:03:41 +04:00
let return ? ( tv = tv ) expr = ok @@ Combinators . Expression . make_tpl ( expr , tv ) in
2019-09-11 15:56:39 +04:00
let f = transpile_annotated_expression 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-05-13 00:56:22 +04:00
match ae . expression with
2019-05-17 21:00:08 +04:00
| E_let_in { binder ; rhs ; result } ->
2019-09-11 15:56:39 +04:00
let % bind rhs' = transpile_annotated_expression rhs in
let % bind result' = transpile_annotated_expression result in
2019-05-17 21:00:08 +04:00
return ( E_let_in ( ( binder , rhs' . type_value ) , 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-05-13 00:56:22 +04:00
return ~ tv @@ E_variable name
2019-05-17 20:03:41 +04:00
)
2019-05-13 00:56:22 +04:00
| E_application ( a , b ) ->
2019-09-11 15:56:39 +04:00
let % bind a = transpile_annotated_expression a in
let % bind b = transpile_annotated_expression b in
2019-10-17 19:18:10 +04:00
return @@ E_application ( a , b )
2019-06-04 12:21:13 +04:00
| E_constructor ( m , param ) -> (
2019-09-11 15:56:39 +04:00
let % bind param' = transpile_annotated_expression param 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 " ) @@
tree_of_sum ae . type_annotation in
2019-05-13 00:56:22 +04:00
let leaf ( k , tv ) : ( expression' option * type_value ) result =
if k = m then (
let % bind _ =
2019-06-04 12:21:13 +04:00
trace_strong ( corner_case ~ loc : _ _ LOC__ " wrong type for constructor parameter " )
2019-05-13 00:56:22 +04:00
@@ AST . assert_type_value_eq ( tv , param . type_annotation ) in
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-08-27 05:34:00 +04:00
| ( Some v , a ) , ( None , b ) -> ok ( Some ( E_constant ( " LEFT " , [ Combinators . Expression . make_tpl ( v , a ) ] ) ) , T_or ( ( None , a ) , ( None , b ) ) )
| ( None , a ) , ( Some v , b ) -> ok ( Some ( E_constant ( " RIGHT " , [ 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_tuple lst -> (
2019-05-13 00:56:22 +04:00
let node = Append_tree . of_list lst in
let aux ( a : expression result ) ( b : expression result ) : 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-05-13 00:56:22 +04:00
return ~ tv @@ E_constant ( " PAIR " , [ a ; b ] )
in
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
)
| E_tuple_accessor ( tpl , ind ) -> (
2019-09-11 15:56:39 +04:00
let % bind ty' = transpile_type tpl . type_annotation in
2019-06-04 12:21:13 +04:00
let % bind ty_lst =
trace_strong ( corner_case ~ loc : _ _ LOC__ " not a tuple " ) @@
get_t_tuple tpl . type_annotation in
2019-09-11 15:56:39 +04:00
let % bind ty'_lst = bind_map_list transpile_type ty_lst in
2019-06-04 12:21:13 +04:00
let % bind path =
trace_strong ( corner_case ~ loc : _ _ LOC__ " tuple access " ) @@
tuple_access_to_lr ty' ty'_lst ind in
2019-05-13 00:56:22 +04:00
let aux = fun pred ( ty , lr ) ->
let c = match lr with
| ` Left -> " CAR "
| ` Right -> " CDR " in
2019-05-15 22:16:28 +04:00
Combinators . Expression . make_tpl ( E_constant ( c , [ pred ] ) , ty ) in
2019-09-11 15:56:39 +04:00
let % bind tpl' = transpile_annotated_expression tpl in
2019-05-13 00:56:22 +04:00
let expr = List . fold_left aux tpl' path in
ok expr
2019-06-04 12:21:13 +04:00
)
| E_record m -> (
2019-05-13 00:56:22 +04:00
let node = Append_tree . of_list @@ list_of_map m in
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-05-13 00:56:22 +04:00
return ~ tv @@ E_constant ( " PAIR " , [ a ; b ] )
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
)
2019-05-13 00:56:22 +04:00
| E_record_accessor ( record , property ) ->
2019-09-11 15:56:39 +04:00
let % bind ty' = transpile_type ( get_type_annotation record ) in
2019-06-04 12:21:13 +04:00
let % bind ty_smap =
trace_strong ( corner_case ~ loc : _ _ LOC__ " not a record " ) @@
get_t_record ( get_type_annotation record ) in
2019-09-11 15:56:39 +04:00
let % bind ty'_smap = bind_map_smap transpile_type ty_smap in
2019-06-04 12:21:13 +04:00
let % bind path =
trace_strong ( corner_case ~ loc : _ _ LOC__ " record access " ) @@
record_access_to_lr ty' ty'_smap property in
2019-05-13 00:56:22 +04:00
let aux = fun pred ( ty , lr ) ->
let c = match lr with
| ` Left -> " CAR "
| ` Right -> " CDR " in
2019-05-15 22:16:28 +04:00
Combinators . Expression . make_tpl ( E_constant ( c , [ pred ] ) , ty ) in
2019-09-11 15:56:39 +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-07-20 15:46:42 +04:00
| E_constant ( name , lst ) -> (
2019-09-24 01:33:25 +04:00
let iterator_generator iterator_name =
let lambda_to_iterator_body ( f : AST . annotated_expression ) ( l : AST . lambda ) =
let % bind body' = transpile_annotated_expression l . body in
let % bind ( input , _ ) = AST . get_t_function f . type_annotation in
let % bind input' = transpile_type input in
ok ( ( l . binder , input' ) , body' )
in
let expression_to_iterator_body ( f : AST . annotated_expression ) =
match f . expression with
| 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
| ED_declaration ( f , _ ) -> (
match f . expression with
| 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-09-24 01:33:25 +04:00
fun ( lst : AST . annotated_expression list ) -> match ( lst , iterator_name ) with
2019-11-20 16:16:31 +04:00
| [ f ; i ] , " ITER " | [ f ; i ] , " 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-11-20 16:16:31 +04:00
| [ f ; collection ; initial ] , " 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' )
)
| _ -> fail @@ corner_case ~ loc : _ _ LOC__ ( " bad iterator arity: " ^ iterator_name )
in
let ( iter , map , fold ) = iterator_generator " ITER " , iterator_generator " MAP " , iterator_generator " FOLD " in
2019-07-20 15:46:42 +04:00
match ( name , lst ) with
| ( " SET_ITER " , lst ) -> iter lst
| ( " LIST_ITER " , lst ) -> iter lst
| ( " MAP_ITER " , lst ) -> iter lst
| ( " LIST_MAP " , lst ) -> map lst
| ( " MAP_MAP " , lst ) -> map lst
2019-09-24 01:33:25 +04:00
| ( " LIST_FOLD " , lst ) -> fold lst
2019-09-24 02:26:39 +04:00
| ( " SET_FOLD " , lst ) -> fold lst
2019-09-24 01:46:47 +04:00
| ( " 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-07-20 15:46:42 +04:00
return @@ E_constant ( name , lst' )
)
2019-06-04 12:21:13 +04:00
)
2019-05-17 20:03:41 +04:00
| E_lambda l ->
2019-09-19 03:34:37 +04:00
let % bind io = AST . get_t_function ae . type_annotation in
2019-10-25 10:01:45 +04:00
transpile_lambda l io
2019-06-04 12:21:13 +04:00
| E_list lst -> (
let % bind t =
trace_strong ( corner_case ~ loc : _ _ LOC__ " not a list " ) @@
2019-09-23 00:17:28 +04:00
get_t_list tv in
2019-09-11 15:56:39 +04:00
let % bind lst' = bind_map_list ( transpile_annotated_expression ) lst in
2019-05-13 00:56:22 +04:00
let aux : expression -> expression -> expression result = fun prev cur ->
return @@ E_constant ( " CONS " , [ cur ; prev ] ) in
2019-05-15 22:28:25 +04:00
let % bind ( init : expression ) = return @@ E_make_empty_list t in
2019-07-20 18:18:50 +04:00
bind_fold_right_list aux init lst'
2019-06-04 12:21:13 +04:00
)
2019-06-10 13:58:16 +04:00
| E_set lst -> (
let % bind t =
trace_strong ( corner_case ~ loc : _ _ LOC__ " not a set " ) @@
2019-09-23 00:17:28 +04:00
get_t_set tv in
2019-09-11 15:56:39 +04:00
let % bind lst' = bind_map_list ( transpile_annotated_expression ) lst in
2019-06-10 13:58:16 +04:00
let aux : expression -> expression -> expression result = fun prev cur ->
2019-07-19 16:35:47 +04:00
return @@ E_constant ( " SET_ADD " , [ cur ; prev ] ) in
2019-06-10 13:58:16 +04:00
let % bind ( init : expression ) = return @@ E_make_empty_set t in
bind_fold_list aux init lst'
)
2019-09-11 18:02:06 +04:00
| E_map m -> (
2019-06-04 12:21:13 +04:00
let % bind ( src , dst ) =
trace_strong ( corner_case ~ loc : _ _ LOC__ " not a map " ) @@
Mini_c . Combinators . get_t_map tv in
2019-05-13 00:56:22 +04:00
let aux : expression result -> ( AST . ae * AST . ae ) -> expression result = fun prev ( k , v ) ->
let % bind prev' = prev in
let % bind ( k' , v' ) =
let v' = e_a_some v ae . environment in
2019-09-11 15:56:39 +04:00
bind_map_pair ( transpile_annotated_expression ) ( k , v' ) in
2019-05-13 00:56:22 +04:00
return @@ E_constant ( " UPDATE " , [ k' ; v' ; prev' ] )
in
2019-05-15 22:28:25 +04:00
let init = return @@ E_make_empty_map ( src , dst ) in
2019-05-13 00:56:22 +04:00
List . fold_left aux init m
2019-06-04 12:21:13 +04:00
)
2019-09-11 18:02:06 +04:00
| E_big_map m -> (
let % bind ( src , dst ) =
trace_strong ( corner_case ~ loc : _ _ LOC__ " not a map " ) @@
Mini_c . Combinators . get_t_big_map tv in
let aux : expression result -> ( AST . ae * AST . ae ) -> expression result = fun prev ( k , v ) ->
let % bind prev' = prev in
let % bind ( k' , v' ) =
let v' = e_a_some v ae . environment in
2019-09-23 00:17:28 +04:00
bind_map_pair ( transpile_annotated_expression ) ( k , v' ) in
2019-09-11 18:02:06 +04:00
return @@ E_constant ( " UPDATE " , [ k' ; v' ; prev' ] )
in
2019-11-05 03:01:39 +04:00
let init = return @@ E_make_empty_big_map ( src , dst ) in
2019-09-11 18:02:06 +04:00
List . fold_left aux init m
)
2019-06-04 12:21:13 +04:00
| E_look_up dsi -> (
2019-05-13 00:56:22 +04:00
let % bind ( ds' , i' ) = bind_map_pair f dsi in
2019-05-23 16:16:12 +04:00
return @@ E_constant ( " MAP_GET " , [ i' ; ds' ] )
2019-06-04 12:21:13 +04:00
)
2019-05-17 21:36:57 +04:00
| E_sequence ( a , b ) -> (
2019-09-11 15:56:39 +04:00
let % bind a' = transpile_annotated_expression a in
let % bind b' = transpile_annotated_expression b in
2019-05-17 21:36:57 +04:00
return @@ E_sequence ( a' , b' )
)
| E_loop ( expr , body ) -> (
2019-09-11 15:56:39 +04:00
let % bind expr' = transpile_annotated_expression expr in
let % bind body' = transpile_annotated_expression body in
2019-05-17 21:36:57 +04:00
return @@ E_while ( expr' , body' )
)
| E_assign ( typed_name , path , expr ) -> (
let ty = typed_name . type_value in
let aux : ( ( AST . type_value * [ ` Left | ` Right ] list ) as ' a ) -> AST . access -> ' a result =
fun ( prev , acc ) cur ->
2019-09-11 15:56:39 +04:00
let % bind ty' = transpile_type prev in
2019-05-17 21:36:57 +04:00
match cur with
2019-06-04 12:21:13 +04:00
| Access_tuple ind -> (
let % bind ty_lst =
trace_strong ( corner_case ~ loc : _ _ LOC__ " not a tuple " ) @@
AST . Combinators . get_t_tuple prev in
2019-09-11 15:56:39 +04:00
let % bind ty'_lst = bind_map_list transpile_type ty_lst in
2019-05-17 21:36:57 +04:00
let % bind path = tuple_access_to_lr ty' ty'_lst ind in
let path' = List . map snd path in
ok ( List . nth ty_lst ind , acc @ path' )
2019-06-04 12:21:13 +04:00
)
| Access_record prop -> (
let % bind ty_map =
trace_strong ( corner_case ~ loc : _ _ LOC__ " not a record " ) @@
2019-05-17 21:36:57 +04:00
AST . Combinators . get_t_record prev in
2019-09-11 15:56:39 +04:00
let % bind ty'_map = bind_map_smap transpile_type ty_map in
2019-05-17 21:36:57 +04:00
let % bind path = record_access_to_lr ty' ty'_map prop in
let path' = List . map snd path in
2019-10-28 07:24:21 +04:00
let % bind prop_in_ty_map = trace_option
( Errors . not_found " acessing prop in ty_map [TODO: better error message] " )
( Map . String . find_opt prop ty_map ) in
ok ( prop_in_ty_map , acc @ path' )
2019-06-04 12:21:13 +04:00
)
2019-05-17 21:36:57 +04:00
in
let % bind ( _ , path ) = bind_fold_right_list aux ( ty , [] ) path in
2019-09-11 15:56:39 +04:00
let % bind expr' = transpile_annotated_expression expr in
2019-05-17 21:36:57 +04:00
return ( E_assignment ( typed_name . type_name , path , expr' ) )
)
2019-05-13 00:56:22 +04:00
| E_matching ( expr , 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-05-13 00:56:22 +04:00
| Match_option { match_none ; match_some = ( ( name , tv ) , s ) } ->
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-05-13 00:56:22 +04:00
return @@ E_if_none ( expr' , n , ( ( name , tv' ) , s' ) )
2019-09-21 11:12:00 +04:00
| Match_list {
match_nil ;
match_cons = ( ( ( hd_name , hd_ty ) , ( tl_name , tl_ty ) ) , match_cons ) ;
} -> (
let % bind nil = transpile_annotated_expression match_nil in
let % bind cons =
let % bind hd_ty' = transpile_type hd_ty in
let % bind tl_ty' = transpile_type tl_ty in
let % bind match_cons' = transpile_annotated_expression match_cons in
ok ( ( ( hd_name , hd_ty' ) , ( tl_name , tl_ty' ) ) , match_cons' )
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
2019-05-15 22:16:28 +04:00
return @@ E_let_in ( ( name , tv ) , 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
let a_var = " left " , a_ty in
2019-05-17 20:03:41 +04:00
let % bind e = aux ( ( ( Expression . make ( E_variable " left " ) a_ty ) ) ) a in
2019-05-13 00:56:22 +04:00
ok ( a_var , e )
in
let % bind b' =
let % bind b_ty = get_t_right tv in
let b_var = " right " , b_ty in
2019-05-17 20:03:41 +04:00
let % bind e = aux ( ( ( Expression . make ( E_variable " right " ) b_ty ) ) ) b in
2019-05-13 00:56:22 +04:00
ok ( b_var , e )
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-05-13 00:56:22 +04:00
)
2019-06-04 12:21:13 +04:00
| AST . Match_tuple _ -> fail @@ unsupported_pattern_matching " tuple " ae . location
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-09-11 15:56:39 +04:00
let { binder ; body } : AST . lambda = l in
2019-10-25 10:01:45 +04:00
let % bind result' = transpile_annotated_expression body in
let % bind input = transpile_type input_type in
let % bind output = transpile_type output_type in
let tv = Combinators . t_function input output in
let closure = E_closure { binder ; body = result' } in
ok @@ Combinators . Expression . make_tpl ( closure , tv )
2019-05-13 00:56:22 +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
| Declaration_constant ( { name ; annotated_expression } , _ ) ->
2019-09-11 15:56:39 +04:00
let % bind expression = transpile_annotated_expression annotated_expression in
2019-05-13 00:56:22 +04:00
let tv = Combinators . Expression . get_type expression in
let env' = Environment . add ( name , tv ) env in
ok @@ ( ( name , expression ) , environment_wrap env env' )
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-05-13 00:56:22 +04:00
let extract_constructor ( v : value ) ( tree : _ Append_tree . t' ) : ( string * value * AST . type_value ) result =
let open Append_tree in
let rec aux tv : ( string * value * AST . type_value ) result =
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 )
let extract_tuple ( v : value ) ( tree : AST . type_value Append_tree . t' ) : ( ( value * AST . type_value ) list ) result =
let open Append_tree in
let rec aux tv : ( ( value * AST . type_value ) list ) result =
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
let rec aux tv : ( ( string * ( value * AST . type_value ) ) list ) result =
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 )