open Trace open Mini_c.Types open Tezos_utils.Memory_proto_alpha open Script_ir_translator module O = Tezos_utils.Micheline.Michelson module Contract_types = Meta_michelson.Types module Ty = struct let not_comparable name () = error (thunk "not a comparable type") (fun () -> name) () let comparable_type_base : type_base -> ex_comparable_ty result = fun tb -> let open Contract_types in let return x = ok @@ Ex_comparable_ty x in match tb with | Base_unit -> fail (not_comparable "unit") | Base_bool -> fail (not_comparable "bool") | Base_nat -> return nat_k | Base_tez -> return tez_k | Base_int -> return int_k | Base_string -> return string_k | Base_address -> return address_k | Base_bytes -> return bytes_k | Base_operation -> fail (not_comparable "operation") let comparable_type : type_value -> ex_comparable_ty result = fun tv -> match tv with | T_base b -> comparable_type_base b | T_deep_closure _ -> fail (not_comparable "deep closure") | T_function _ -> fail (not_comparable "function") | T_or _ -> fail (not_comparable "or") | T_pair _ -> fail (not_comparable "pair") | T_map _ -> fail (not_comparable "map") | T_list _ -> fail (not_comparable "list") | T_option _ -> fail (not_comparable "option") | T_contract _ -> fail (not_comparable "contract") let base_type : type_base -> ex_ty result = fun b -> let open Contract_types in let return x = ok @@ Ex_ty x in match b with | Base_unit -> return unit | Base_bool -> return bool | Base_int -> return int | Base_nat -> return nat | Base_tez -> return tez | Base_string -> return string | Base_address -> return address | Base_bytes -> return bytes | Base_operation -> return operation let rec type_ : type_value -> ex_ty result = function | T_base b -> base_type b | T_pair (t, t') -> ( type_ t >>? fun (Ex_ty t) -> type_ t' >>? fun (Ex_ty t') -> ok @@ Ex_ty (Contract_types.pair t t') ) | T_or (t, t') -> ( type_ t >>? fun (Ex_ty t) -> type_ t' >>? fun (Ex_ty t') -> ok @@ Ex_ty (Contract_types.union t t') ) | T_function (arg, ret) -> let%bind (Ex_ty arg) = type_ arg in let%bind (Ex_ty ret) = type_ ret in ok @@ Ex_ty (Contract_types.lambda arg ret) | T_deep_closure (c, arg, ret) -> let%bind (Ex_ty capture) = environment_representation c in let%bind (Ex_ty arg) = type_ arg in let%bind (Ex_ty ret) = type_ ret in ok @@ Ex_ty Contract_types.(pair (lambda (pair arg capture) ret) capture) | T_map (k, v) -> let%bind (Ex_comparable_ty k') = comparable_type k in let%bind (Ex_ty v') = type_ v in ok @@ Ex_ty Contract_types.(map k' v') | T_list t -> let%bind (Ex_ty t') = type_ t in ok @@ Ex_ty Contract_types.(list t') | T_option t -> let%bind (Ex_ty t') = type_ t in ok @@ Ex_ty Contract_types.(option t') | T_contract t -> let%bind (Ex_ty t') = type_ t in ok @@ Ex_ty Contract_types.(contract t') and environment_representation = function | [] -> ok @@ Ex_ty Contract_types.unit | [a] -> type_ @@ snd a | a::b -> let%bind (Ex_ty a) = type_ @@ snd a in let%bind (Ex_ty b) = environment_representation b in ok @@ Ex_ty (Contract_types.pair a b) and environment : environment -> Meta_michelson.Stack.ex_stack_ty result = fun env -> let open Meta_michelson in let%bind lst = bind_map_list type_ @@ List.map snd env in let aux (Stack.Ex_stack_ty st) (Ex_ty cur) = Stack.Ex_stack_ty (Stack.stack cur st) in ok @@ List.fold_right' aux (Ex_stack_ty Stack.nil) lst end let base_type : type_base -> O.michelson result = function | Base_unit -> ok @@ O.prim T_unit | Base_bool -> ok @@ O.prim T_bool | Base_int -> ok @@ O.prim T_int | Base_nat -> ok @@ O.prim T_nat | Base_tez -> ok @@ O.prim T_mutez | Base_string -> ok @@ O.prim T_string | Base_address -> ok @@ O.prim T_address | Base_bytes -> ok @@ O.prim T_bytes | Base_operation -> ok @@ O.prim T_operation let rec type_ : type_value -> O.michelson result = function | T_base b -> base_type b | T_pair (t, t') -> ( type_ t >>? fun t -> type_ t' >>? fun t' -> ok @@ O.prim ~children:[t;t'] O.T_pair ) | T_or (t, t') -> ( type_ t >>? fun t -> type_ t' >>? fun t' -> ok @@ O.prim ~children:[t;t'] O.T_or ) | T_map kv -> let%bind (k', v') = bind_map_pair type_ kv in ok @@ O.prim ~children:[k';v'] O.T_map | T_list t -> let%bind t' = type_ t in ok @@ O.prim ~children:[t'] O.T_list | T_option o -> let%bind o' = type_ o in ok @@ O.prim ~children:[o'] O.T_option | T_contract o -> let%bind o' = type_ o in ok @@ O.prim ~children:[o'] O.T_contract | T_function (arg, ret) -> let%bind arg = type_ arg in let%bind ret = type_ ret in ok @@ O.prim ~children:[arg;ret] T_lambda | T_deep_closure (c, arg, ret) -> let%bind capture = environment_closure c in let%bind arg = type_ arg in let%bind ret = type_ ret in ok @@ O.t_pair (O.t_lambda (O.t_pair arg capture) ret) capture and environment_element (name, tyv) = let%bind michelson_type = type_ tyv in ok @@ O.annotate ("@" ^ name) michelson_type and environment = fun env -> bind_map_list type_ @@ List.map snd env and environment_closure = function | [] -> simple_fail "Type of empty env" | [a] -> type_ @@ snd a | a :: b -> let%bind a = type_ @@ snd a in let%bind b = environment_closure b in ok @@ O.t_pair a b