ligo/src/transpiler/transpiler.ml

833 lines
33 KiB
OCaml
Raw Normal View History

2019-05-13 00:56:22 +04:00
open! Trace
module AST = Ast_typed
module Append_tree = Tree.Append
open AST.Combinators
open Mini_c
open Combinators
2019-05-13 00:56:22 +04:00
let temp_unwrap_loc = Location.unwrap
let temp_unwrap_loc_list = List.map Location.unwrap
let list_of_map m = List.rev @@ Map.String.fold (fun _ v prev -> v :: prev) m []
let kv_list_of_map m = List.rev @@ Map.String.fold (fun k v prev -> (k, v) :: prev) m []
let map_of_kv_list lst =
let open AST.SMap in
List.fold_left (fun prev (k, v) -> add k v prev) empty lst
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-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
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
end
open Errors
2019-05-13 00:56:22 +04:00
let rec translate_type (t:AST.type_value) : type_value result =
match t.type_value' with
| T_constant ("bool", []) -> ok (T_base Base_bool)
| T_constant ("int", []) -> ok (T_base Base_int)
| T_constant ("nat", []) -> ok (T_base Base_nat)
| T_constant ("tez", []) -> ok (T_base Base_tez)
| T_constant ("string", []) -> ok (T_base Base_string)
| T_constant ("address", []) -> ok (T_base Base_address)
2019-06-07 00:49:36 +04:00
| T_constant ("timestamp", []) -> ok (T_base Base_timestamp)
2019-05-13 00:56:22 +04:00
| T_constant ("unit", []) -> ok (T_base Base_unit)
| T_constant ("operation", []) -> ok (T_base Base_operation)
| T_constant ("contract", [x]) ->
let%bind x' = translate_type x in
ok (T_contract x')
| T_constant ("map", [key;value]) ->
let%bind kv' = bind_map_pair translate_type (key, value) in
ok (T_map kv')
| T_constant ("list", [t]) ->
let%bind t' = translate_type t in
ok (T_list t')
2019-06-11 04:52:09 +04:00
| T_constant ("set", [t]) ->
let%bind t' = translate_type t in
ok (T_set t')
2019-05-13 00:56:22 +04:00
| T_constant ("option", [o]) ->
let%bind o' = translate_type o in
ok (T_option o')
2019-06-04 12:21:13 +04:00
| T_constant (name , _lst) -> fail @@ unrecognized_type_constant name
2019-05-13 00:56:22 +04:00
| T_sum m ->
let node = Append_tree.of_list @@ list_of_map m in
let aux a b : type_value result =
let%bind a = a in
let%bind b = b in
ok (T_or (a, b))
in
Append_tree.fold_ne translate_type aux node
| T_record m ->
let node = Append_tree.of_list @@ list_of_map m in
let aux a b : type_value result =
let%bind a = a in
let%bind b = b in
ok (T_pair (a, b))
in
Append_tree.fold_ne translate_type aux node
| 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
ok (T_pair (a, b))
in
Append_tree.fold_ne translate_type aux node
| T_function (param, result) -> (
2019-05-13 00:56:22 +04:00
let%bind param' = translate_type param in
let%bind result' = translate_type result in
ok (T_function (param', result'))
)
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
let rec translate_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
| Literal_timestamp n -> D_timestamp n
2019-05-13 00:56:22 +04:00
| Literal_tez n -> D_tez n
| Literal_bytes s -> D_bytes s
| Literal_string s -> D_string s
| Literal_address s -> D_string s
| Literal_operation op -> D_operation op
| Literal_unit -> D_unit
and transpile_environment_element_type : AST.environment_element -> type_value result = fun ele ->
match (AST.get_type' ele.type_value , ele.definition) with
| (AST.T_function (f , arg) , ED_declaration (ae , ((_ :: _) as captured_variables)) ) ->
let%bind f' = translate_type f in
let%bind arg' = translate_type arg in
let%bind env' = transpile_environment ae.environment in
let sub_env = Mini_c.Environment.select captured_variables env' in
ok @@ Combinators.t_deep_closure sub_env f' arg'
| _ -> translate_type ele.type_value
2019-05-13 00:56:22 +04:00
and transpile_small_environment : AST.small_environment -> Environment.t result = fun x ->
let x' = AST.Environment.Small.get_environment x in
let aux prec (name , (ele : AST.environment_element)) =
let%bind tv' = transpile_environment_element_type ele in
2019-05-13 00:56:22 +04:00
ok @@ Environment.add (name , tv') prec
in
let%bind result =
bind_fold_right_list aux Environment.empty x' in
ok result
2019-05-13 00:56:22 +04:00
and transpile_environment : AST.full_environment -> Environment.t result = fun x ->
let%bind nlst = bind_map_ne_list transpile_small_environment x in
ok @@ Environment.concat @@ List.Ne.to_list nlst
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
and translate_annotated_expression (ae:AST.annotated_expression) : expression result =
2019-05-13 00:56:22 +04:00
let%bind tv = translate_type ae.type_annotation in
let return ?(tv = tv) expr = ok @@ Combinators.Expression.make_tpl (expr, tv) in
let f = translate_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-05-17 20:18:03 +04:00
let%bind rhs' = translate_annotated_expression rhs in
let%bind result' = translate_annotated_expression result in
2019-05-17 21:00:08 +04:00
return (E_let_in ((binder, rhs'.type_value), rhs', result'))
2019-05-13 00:56:22 +04:00
| E_failwith ae -> (
let%bind ae' = translate_annotated_expression ae in
2019-05-13 00:56:22 +04:00
return @@ E_constant ("FAILWITH" , [ae'])
)
| E_literal l -> return @@ E_literal (translate_literal l)
| E_variable name -> (
let%bind ele =
2019-06-05 10:43:33 +04:00
trace_option (corner_case ~loc:__LOC__ "name not in environment") @@
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-13 00:56:22 +04:00
| E_application (a, b) ->
let%bind a = translate_annotated_expression a in
let%bind b = translate_annotated_expression b in
2019-05-13 00:56:22 +04:00
return @@ E_application (a, b)
2019-06-04 12:21:13 +04:00
| E_constructor (m, param) -> (
let%bind param' = translate_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 (
let%bind tv = translate_type tv in
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
| (None, a), (None, b) -> ok (None, T_or (a, b))
2019-06-04 12:21:13 +04:00
| (Some _, _), (Some _, _) -> fail @@ corner_case ~loc:__LOC__ "multiple identical constructors in the same variant"
2019-05-15 22:16:28 +04:00
| (Some v, a), (None, b) -> ok (Some (E_constant ("LEFT", [Combinators.Expression.make_tpl (v, a)])), T_or (a, b))
| (None, a), (Some v, b) -> ok (Some (E_constant ("RIGHT", [Combinators.Expression.make_tpl (v, b)])), T_or (a, 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
let tv = T_pair (a_ty , b_ty) in
return ~tv @@ E_constant ("PAIR", [a; b])
in
Append_tree.fold_ne (translate_annotated_expression) aux node
2019-06-04 12:21:13 +04:00
)
| E_tuple_accessor (tpl, ind) -> (
2019-05-13 00:56:22 +04:00
let%bind ty' = translate_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-05-13 00:56:22 +04:00
let%bind ty'_lst = bind_map_list translate_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
let%bind tpl' = translate_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
let tv = T_pair (a_ty , b_ty) in
return ~tv @@ E_constant ("PAIR", [a; b])
in
2019-06-04 12:21:13 +04:00
trace_strong (corner_case ~loc:__LOC__ "record build") @@
Append_tree.fold_ne (translate_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) ->
let%bind ty' = translate_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-05-13 00:56:22 +04:00
let%bind ty'_smap = bind_map_smap translate_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
let%bind record' = translate_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) -> (
let (iter , map) =
let iterator name = fun (lst : AST.annotated_expression list) -> match lst with
| [i ; f] -> (
let%bind f' = match f.expression with
| E_lambda l -> (
let%bind body' = translate_annotated_expression l.result in
let%bind input' = translate_type l.input_type in
ok ((l.binder , input') , body')
)
| 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 -> (
let%bind body' = translate_annotated_expression l.result in
let%bind input' = translate_type l.input_type in
ok ((l.binder , input') , body')
)
| _ -> fail @@ unsupported_iterator f.location
)
| _ -> fail @@ unsupported_iterator f.location
)
| _ -> fail @@ unsupported_iterator f.location
in
let%bind i' = translate_annotated_expression i in
return @@ E_iterator (name , f' , i')
)
| _ -> fail @@ corner_case ~loc:__LOC__ "bad iterator arity"
in
iterator "ITER" , iterator "MAP" in
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
| _ -> (
let%bind lst' = bind_map_list (translate_annotated_expression) lst in
return @@ E_constant (name , lst')
)
2019-06-04 12:21:13 +04:00
)
| E_lambda l ->
2019-06-04 12:21:13 +04:00
let%bind env =
trace_strong (corner_case ~loc:__LOC__ "environment") @@
transpile_environment ae.environment in
translate_lambda env l
2019-06-04 12:21:13 +04:00
| E_list lst -> (
let%bind t =
trace_strong (corner_case ~loc:__LOC__ "not a list") @@
Mini_c.Combinators.get_t_list tv in
let%bind lst' = bind_map_list (translate_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-05-13 00:56:22 +04:00
bind_fold_list aux init lst'
2019-06-04 12:21:13 +04:00
)
| E_set lst -> (
let%bind t =
trace_strong (corner_case ~loc:__LOC__ "not a set") @@
Mini_c.Combinators.get_t_set tv in
let%bind lst' = bind_map_list (translate_annotated_expression) lst in
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
let%bind (init : expression) = return @@ E_make_empty_set t in
bind_fold_list aux init lst'
)
2019-06-04 12:21:13 +04:00
| E_map m -> (
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-06-04 12:21:13 +04:00
bind_map_pair (translate_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
)
| 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) -> (
let%bind a' = translate_annotated_expression a in
let%bind b' = translate_annotated_expression b in
return @@ E_sequence (a' , b')
)
| E_loop (expr , body) -> (
let%bind expr' = translate_annotated_expression expr in
let%bind body' = translate_annotated_expression body in
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 ->
let%bind ty' = translate_type prev in
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-05-17 21:36:57 +04:00
let%bind ty'_lst = bind_map_list translate_type ty_lst in
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
let%bind ty'_map = bind_map_smap translate_type ty_map in
let%bind path = record_access_to_lr ty' ty'_map prop in
let path' = List.map snd path in
2019-06-04 12:21:13 +04:00
ok (Map.String.find prop ty_map, acc @ path')
)
| Access_map _k -> fail (corner_case ~loc:__LOC__ "no patch for map yet")
2019-05-17 21:36:57 +04:00
in
let%bind (_, path) = bind_fold_right_list aux (ty, []) path in
let%bind expr' = translate_annotated_expression expr in
return (E_assignment (typed_name.type_name, path, expr'))
)
2019-05-13 00:56:22 +04:00
| E_matching (expr, m) -> (
let%bind expr' = translate_annotated_expression expr in
2019-05-13 00:56:22 +04:00
match m with
| Match_bool {match_true ; match_false} ->
let%bind (t , f) = bind_map_pair (translate_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) } ->
let%bind n = translate_annotated_expression match_none in
2019-05-13 00:56:22 +04:00
let%bind (tv' , s') =
let%bind tv' = translate_type tv in
let%bind s' = translate_annotated_expression s in
2019-05-13 00:56:22 +04:00
ok (tv' , s') in
return @@ E_if_none (expr' , n , ((name , tv') , s'))
| 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) ->
let%bind tv' = translate_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 (snd a') (snd b') in
ok (`Node (a' , b') , tv')
in aux tree'
in
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
let%bind body' = translate_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
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
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") @@
aux expr' tree''
2019-05-13 00:56:22 +04:00
)
2019-06-04 12:21:13 +04:00
| AST.Match_list _ -> fail @@ unsupported_pattern_matching "list" ae.location
| AST.Match_tuple _ -> fail @@ unsupported_pattern_matching "tuple" ae.location
2019-05-13 00:56:22 +04:00
)
and translate_lambda_deep : Mini_c.Environment.t -> AST.lambda -> Mini_c.expression result = fun env l ->
let { binder ; input_type ; output_type ; result } : AST.lambda = l in
2019-05-13 00:56:22 +04:00
(* Deep capture. Capture the relevant part of the environment. *)
let%bind (fv , c_env , c_tv) =
let free_variables = Ast_typed.Free_variables.lambda [] l in
let sub_env = Mini_c.Environment.select free_variables env in
let tv = Environment.closure_representation sub_env in
ok (free_variables , sub_env , tv) in
let%bind (f_expr , input_tv , output_tv) =
let%bind raw_input = translate_type input_type in
let init_env = Environment.(add (binder , raw_input) c_env) in
let input = Environment.closure_representation init_env in
let%bind output = translate_type output_type in
let%bind result = translate_annotated_expression result in
let result =
let load_expr = Expression.make_tpl (E_variable binder , input) in
ez_e_return @@ ez_e_sequence (E_environment_load (load_expr , init_env)) result in
2019-05-13 00:56:22 +04:00
let tv = Mini_c.t_function input output in
2019-05-20 20:17:26 +04:00
let f_literal = D_function { binder ; input ; output ; result } in
2019-05-15 22:16:28 +04:00
let expr = Expression.make_tpl (E_literal f_literal , tv) in
2019-05-13 00:56:22 +04:00
ok (expr , raw_input , output) in
let%bind c_expr =
2019-05-16 01:05:09 +04:00
ok @@ Expression.make_tpl (E_environment_capture fv , c_tv) in
2019-05-13 00:56:22 +04:00
let expr = Expression.pair f_expr c_expr in
let tv = Mini_c.t_deep_closure c_env input_tv output_tv in
2019-05-15 22:16:28 +04:00
ok @@ Expression.make_tpl (expr , tv)
2019-05-13 00:56:22 +04:00
and translate_lambda env l =
let { binder ; input_type ; output_type ; result } : AST.lambda = l in
2019-05-13 00:56:22 +04:00
(* Try to translate it in an empty env, if it succeeds, transpiles it as a quote value, else, as a closure expression. *)
let fvs = AST.Free_variables.(annotated_expression (singleton binder) result) in
let%bind result =
match fvs with
| [] -> (
let%bind result' = translate_annotated_expression result in
let result' = ez_e_return result' in
2019-05-13 00:56:22 +04:00
let%bind input = translate_type input_type in
let%bind output = translate_type output_type in
let tv = Combinators.t_function input output in
let content = D_function {binder;input;output;result=result'} in
ok @@ Combinators.Expression.make_tpl (E_literal content , tv)
)
| _ -> (
translate_lambda_deep env l
) in
ok result
2019-05-13 00:56:22 +04:00
let translate_declaration env (d:AST.declaration) : toplevel_statement result =
match d with
| Declaration_constant ({name;annotated_expression} , _) ->
let%bind expression = translate_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')
let translate_program (lst:AST.program) : program result =
let aux (prev:(toplevel_statement list * Environment.t) result) cur =
let%bind (tl, env) = prev in
let%bind ((_, env') as cur') = translate_declaration env cur in
ok (cur' :: tl, env'.post_environment)
in
let%bind (statements, _) = List.fold_left aux (ok ([], Environment.empty)) (temp_unwrap_loc_list lst) in
ok statements
2019-06-04 12:21:13 +04:00
let translate_main (l:AST.lambda) loc : anon_function result =
2019-05-13 00:56:22 +04:00
let%bind expr = translate_lambda Environment.empty l in
match Combinators.Expression.get_content expr with
| E_literal (D_function f) -> ok f
2019-06-04 12:21:13 +04:00
| _ -> fail @@ not_functional_main loc
2019-05-13 00:56:22 +04:00
(* From an expression [expr], build the expression [fun () -> expr] *)
2019-05-13 00:56:22 +04:00
let functionalize (e:AST.annotated_expression) : AST.lambda * AST.type_value =
let t = e.type_annotation in
let open! AST in
{
binder = "_" ;
input_type = Combinators.t_unit () ;
output_type = t ;
result = e ;
}, Combinators.(t_function (t_unit ()) t ())
let translate_entry (lst:AST.program) (name:string) : anon_function result =
let rec aux acc (lst:AST.program) =
let%bind acc = acc in
match lst with
2019-06-04 12:21:13 +04:00
| [] -> fail @@ missing_entry_point name
| hd :: tl -> (
let (AST.Declaration_constant (an , (pre_env , _))) = temp_unwrap_loc hd in
match an.name = name with
| false -> (
let next = fun expr ->
let cur = e_a_let_in an.name an.annotated_expression expr pre_env in
acc cur in
aux (ok next) tl
)
| true -> (
match an.annotated_expression.expression with
| E_lambda l ->
let l' = { l with result = acc l.result } in
2019-06-04 12:21:13 +04:00
translate_main l' an.annotated_expression.location
| _ ->
let (l , _) = functionalize an.annotated_expression in
let l' = { l with result = acc l.result } in
2019-06-04 12:21:13 +04:00
translate_main l' an.annotated_expression.location
)
)
in
let%bind l = aux (ok (fun x -> x)) lst in
ok l
2019-05-13 00:56:22 +04:00
open Combinators
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)
let rec untranspile (v : value) (t : AST.type_value) : AST.annotated_expression result =
let open! AST in
let return e = ok (make_a_e_empty e t) in
match t.type_value' with
2019-06-04 12:21:13 +04:00
| T_constant ("unit", []) -> (
let%bind () =
trace_strong (wrong_mini_c_value "unit" v) @@
get_unit v in
2019-05-13 00:56:22 +04:00
return (E_literal Literal_unit)
2019-06-04 12:21:13 +04:00
)
| T_constant ("bool", []) -> (
let%bind b =
trace_strong (wrong_mini_c_value "bool" v) @@
get_bool v in
2019-05-13 00:56:22 +04:00
return (E_literal (Literal_bool b))
2019-06-04 12:21:13 +04:00
)
| T_constant ("int", []) -> (
let%bind n =
trace_strong (wrong_mini_c_value "int" v) @@
get_int v in
2019-05-13 00:56:22 +04:00
return (E_literal (Literal_int n))
2019-06-04 12:21:13 +04:00
)
| T_constant ("nat", []) -> (
let%bind n =
trace_strong (wrong_mini_c_value "nat" v) @@
2019-07-19 16:35:47 +04:00
get_nat v in
2019-05-13 00:56:22 +04:00
return (E_literal (Literal_nat n))
2019-06-04 12:21:13 +04:00
)
2019-06-11 04:52:09 +04:00
| T_constant ("timestamp", []) -> (
let%bind n =
trace_strong (wrong_mini_c_value "timestamp" v) @@
get_timestamp v in
return (E_literal (Literal_timestamp n))
)
2019-06-04 12:21:13 +04:00
| T_constant ("tez", []) -> (
let%bind n =
trace_strong (wrong_mini_c_value "tez" v) @@
get_nat v in
2019-05-13 00:56:22 +04:00
return (E_literal (Literal_tez n))
2019-06-04 12:21:13 +04:00
)
| T_constant ("string", []) -> (
let%bind n =
trace_strong (wrong_mini_c_value "string" v) @@
get_string v in
2019-05-13 00:56:22 +04:00
return (E_literal (Literal_string n))
2019-06-04 12:21:13 +04:00
)
| T_constant ("address", []) -> (
let%bind n =
trace_strong (wrong_mini_c_value "address" v) @@
get_string v in
2019-05-13 00:56:22 +04:00
return (E_literal (Literal_address n))
2019-06-04 12:21:13 +04:00
)
2019-05-13 00:56:22 +04:00
| T_constant ("option", [o]) -> (
2019-06-04 12:21:13 +04:00
let%bind opt =
trace_strong (wrong_mini_c_value "option" v) @@
get_option v in
match opt with
2019-05-13 00:56:22 +04:00
| None -> ok (e_a_empty_none o)
| Some s ->
let%bind s' = untranspile s o in
ok (e_a_empty_some s')
)
| T_constant ("map", [k_ty;v_ty]) -> (
2019-06-04 12:21:13 +04:00
let%bind lst =
trace_strong (wrong_mini_c_value "map" v) @@
get_map v in
2019-05-13 00:56:22 +04:00
let%bind lst' =
let aux = fun (k, v) ->
let%bind k' = untranspile k k_ty in
let%bind v' = untranspile v v_ty in
ok (k', v') in
bind_map_list aux lst in
return (E_map lst')
)
| T_constant ("list", [ty]) -> (
2019-06-04 12:21:13 +04:00
let%bind lst =
trace_strong (wrong_mini_c_value "list" v) @@
get_list v in
2019-05-13 00:56:22 +04:00
let%bind lst' =
let aux = fun e -> untranspile e ty in
bind_map_list aux lst in
return (E_list lst')
)
2019-06-11 04:52:09 +04:00
| T_constant ("set", [ty]) -> (
let%bind lst =
trace_strong (wrong_mini_c_value "set" v) @@
get_set v in
let%bind lst' =
let aux = fun e -> untranspile e ty in
bind_map_list aux lst in
return (E_set lst')
)
2019-05-13 00:56:22 +04:00
| T_constant ("contract" , [_ty]) ->
2019-06-04 12:21:13 +04:00
fail @@ bad_untranspile "contract" v
| T_constant ("operation" , []) -> (
let%bind op =
trace_strong (wrong_mini_c_value "operation" v) @@
get_operation v in
2019-05-13 00:56:22 +04:00
return (E_literal (Literal_operation op))
2019-06-04 12:21:13 +04:00
)
| T_constant (name , _lst) ->
fail @@ unknown_untranspile name v
2019-05-13 00:56:22 +04:00
| T_sum m ->
let lst = kv_list_of_map m in
let%bind node = match Append_tree.of_list lst with
2019-06-04 12:21:13 +04:00
| Empty -> fail @@ corner_case ~loc:__LOC__ "empty sum type"
2019-05-13 00:56:22 +04:00
| Full t -> ok t
in
2019-06-04 12:21:13 +04:00
let%bind (name, v, tv) =
trace_strong (corner_case ~loc:__LOC__ "sum extract constructor") @@
extract_constructor v node in
2019-05-13 00:56:22 +04:00
let%bind sub = untranspile v tv in
return (E_constructor (name, sub))
| T_tuple lst ->
let%bind node = match Append_tree.of_list lst with
2019-06-04 12:21:13 +04:00
| Empty -> fail @@ corner_case ~loc:__LOC__ "empty tuple"
2019-05-13 00:56:22 +04:00
| Full t -> ok t in
2019-06-04 12:21:13 +04:00
let%bind tpl =
trace_strong (corner_case ~loc:__LOC__ "tuple extract") @@
extract_tuple v node in
2019-05-13 00:56:22 +04:00
let%bind tpl' = bind_list
@@ List.map (fun (x, y) -> untranspile x y) tpl in
return (E_tuple tpl')
| T_record m ->
let lst = kv_list_of_map m in
let%bind node = match Append_tree.of_list lst with
2019-06-04 12:21:13 +04:00
| Empty -> fail @@ corner_case ~loc:__LOC__ "empty record"
2019-05-13 00:56:22 +04:00
| Full t -> ok t in
2019-06-04 12:21:13 +04:00
let%bind lst =
trace_strong (corner_case ~loc:__LOC__ "record extract") @@
extract_record v node in
2019-05-13 00:56:22 +04:00
let%bind lst = bind_list
@@ List.map (fun (x, (y, z)) -> let%bind yz = untranspile y z in ok (x, yz)) lst in
let m' = map_of_kv_list lst in
return (E_record m')
2019-06-04 12:21:13 +04:00
| T_function _ -> fail @@ bad_untranspile "function" v