ligo/src/passes/2-abstracter/pascaligo.ml

1388 lines
53 KiB
OCaml
Raw Normal View History

open Trace
2020-03-12 23:20:39 +01:00
open Ast_imperative
2019-05-12 20:56:22 +00:00
module Raw = Parser.Pascaligo.AST
module SMap = Map.String
module ParserLog = Parser_pascaligo.ParserLog
2019-05-12 20:56:22 +00:00
open Combinators
let nseq_to_list (hd, tl) = hd :: tl
let npseq_to_list (hd, tl) = hd :: (List.map snd tl)
let pseq_to_list = function
None -> []
| Some lst -> npseq_to_list lst
2019-05-12 20:56:22 +00:00
let get_value : 'a Raw.reg -> 'a = fun x -> x.value
and repair_mutable_variable_in_matching (for_body : expression) (element_names : expression_variable list) (env : expression_variable) =
2020-03-12 23:20:39 +01:00
let%bind captured_names = Self_ast_imperative.fold_map_expression
2019-12-04 18:30:52 +01:00
(* TODO : these should use Variables sets *)
(fun (decl_var,free_var : expression_variable list * expression_variable list) (ass_exp : expression) ->
match ass_exp.expression_content with
| E_let_in {let_binder;mut=false;rhs;let_result} ->
let (name,_) = let_binder in
ok (true,(name::decl_var, free_var),e_let_in let_binder false false rhs let_result)
| E_let_in {let_binder;mut=true; rhs;let_result} ->
let (name,_) = let_binder in
if List.mem name decl_var then
ok (true,(decl_var, free_var), e_let_in let_binder false false rhs let_result)
else(
let free_var = if (List.mem name free_var) then free_var else name::free_var in
2020-02-18 14:19:11 +01:00
let expr = e_let_in (env,None) false false (e_update (e_variable env) (Var.to_name name) (e_variable name)) let_result in
2019-12-04 18:30:52 +01:00
ok (true,(decl_var, free_var), e_let_in let_binder false false rhs expr)
)
| E_variable name ->
if List.mem name decl_var || List.mem name free_var || Var.equal name env then
ok (true,(decl_var, free_var), e_variable name)
else
ok (true, (decl_var, name::free_var), e_variable name)
| E_constant {cons_name=C_MAP_FOLD;arguments= _}
| E_constant {cons_name=C_SET_FOLD;arguments= _}
| E_constant {cons_name=C_LIST_FOLD;arguments= _}
| E_matching _ -> ok @@ (false, (decl_var,free_var),ass_exp)
| _ -> ok (true, (decl_var, free_var),ass_exp)
)
(element_names,[])
for_body in
ok @@ captured_names
and repair_mutable_variable_in_loops (for_body : expression) (element_names : expression_variable list) (env : expression_variable) =
2020-03-12 23:20:39 +01:00
let%bind captured_names = Self_ast_imperative.fold_map_expression
2019-12-04 18:30:52 +01:00
(* TODO : these should use Variables sets *)
(fun (decl_var,free_var : expression_variable list * expression_variable list) (ass_exp : expression) ->
match ass_exp.expression_content with
| E_let_in {let_binder;mut=false;rhs;let_result} ->
let (name,_) = let_binder in
ok (true,(name::decl_var, free_var),e_let_in let_binder false false rhs let_result)
| E_let_in {let_binder;mut=true; rhs;let_result} ->
let (name,_) = let_binder in
if List.mem name decl_var then
ok (true,(decl_var, free_var), e_let_in let_binder false false rhs let_result)
else(
let free_var = if (List.mem name free_var) then free_var else name::free_var in
let expr = e_let_in (env,None) false false (
e_update (e_variable env) ("0")
2020-02-18 14:19:11 +01:00
(e_update (e_accessor (e_variable env) "0") (Var.to_name name) (e_variable name))
2019-12-04 18:30:52 +01:00
)
let_result in
ok (true,(decl_var, free_var), e_let_in let_binder false false rhs expr)
)
| E_variable name ->
if List.mem name decl_var || List.mem name free_var || Var.equal name env then
ok (true,(decl_var, free_var), e_variable name)
else
ok (true,(decl_var, name::free_var), e_variable name)
| E_constant {cons_name=C_MAP_FOLD;arguments= _}
| E_constant {cons_name=C_SET_FOLD;arguments= _}
| E_constant {cons_name=C_LIST_FOLD;arguments= _}
| E_matching _ -> ok @@ (false,(decl_var,free_var),ass_exp)
| _ -> ok (true,(decl_var, free_var),ass_exp)
)
(element_names,[])
for_body in
ok @@ captured_names
and store_mutable_variable (free_vars : expression_variable list) =
if (List.length free_vars == 0) then
e_unit ()
else
2020-02-18 14:19:11 +01:00
let aux var = (Var.to_name var, e_variable var) in
2019-12-04 18:30:52 +01:00
e_record_ez (List.map aux free_vars)
and restore_mutable_variable (expr : expression->expression) (free_vars : expression_variable list) (env :expression_variable) =
2019-12-04 18:30:52 +01:00
let aux (f:expression -> expression) (ev:expression_variable) =
2020-02-18 14:19:11 +01:00
ok @@ fun expr -> f (e_let_in (ev,None) true false (e_accessor (e_variable env) (Var.to_name ev)) expr)
2019-12-04 18:30:52 +01:00
in
let%bind ef = bind_fold_list aux (fun e -> e) free_vars in
ok @@ fun expr'_opt -> match expr'_opt with
| None -> ok @@ expr (ef (e_skip ()))
| Some expr' -> ok @@ expr (ef expr')
2019-12-04 18:30:52 +01:00
module Errors = struct
let unsupported_cst_constr p =
let title () = "" in
let message () =
Format.asprintf "\nConstant constructors are not supported yet.\n" in
let pattern_loc = Raw.pattern_to_region p in
let data = [
("location",
fun () -> Format.asprintf "%a" Location.pp_lift @@ pattern_loc)
] in
error ~data title message
let unknown_predefined_type name =
let title () = "\nType constants" in
let message () =
Format.asprintf "Unknown predefined type \"%s\".\n" name.Region.value in
let data = [
("location",
fun () -> Format.asprintf "%a" Location.pp_lift @@ name.Region.region)
] in
error ~data title message
let unsupported_non_var_pattern p =
let title () = "" in
let message () =
Format.asprintf "\nNon-variable patterns in constructors \
are not supported yet.\n" in
let pattern_loc = Raw.pattern_to_region p in
let data = [
("location",
fun () -> Format.asprintf "%a" Location.pp_lift @@ pattern_loc)
] in
error ~data title message
let only_constructors p =
let title () = "" in
let message () =
Format.asprintf "\nCurrently, only constructors \
are supported in patterns.\n" in
let pattern_loc = Raw.pattern_to_region p in
let data = [
("location",
fun () -> Format.asprintf "%a" Location.pp_lift @@ pattern_loc)
] in
error ~data title message
let unsupported_tuple_pattern p =
let title () = "" in
let message () =
Format.asprintf "\nTuple patterns are not supported yet.\n" in
let pattern_loc = Raw.pattern_to_region p in
let data = [
("location",
2019-09-21 11:30:41 +02:00
fun () -> Format.asprintf "%a" Location.pp_lift @@ pattern_loc) ;
Refactoring of comments (for [dune build @doc]). Refactoring of parsing command-line arguments * The type [options] is now abstract and implemented as an object type to avoid struggling with scoping and type inference when record types share some common field names. Refactoring of ParserLog for PascaLIGO and CameLIGO * The immediate motivation behind that refactoring was to remove the use of a couple of global references. A consequence is that we have a nicer and more compact code, by threading a state. The files [pascaligo/Tests/pp.ligo] and [ligodity/Tests/pp.mligo]. * Another consequence is that the choice of making strings from AST nodes depends on the CLI (offsets? mode?). After this refactoring, that choice is hardcoded in the simplifiers in a few places (TODO), waiting for a general solution that would have all CL options flow through the compiler. * I removed the use of vendors [x_option.ml], [x_map.ml] and [x_list.ml] when handling optional values. (Less dependencies this way.) Refactoring of the ASTs * I removed the node [local_decl], which was set to [[]] already in a previous commit (which removed local declarations as being redundant, as statements could already be instructions or declarations). * I changed [StrLit] to [String] in the AST of CameLIGO and ReasonLIGO. * I also changed the type [fun_expr] so now either a block is present, and therefore followed by the [with] keyword, or it is not. (Before, the presence of a block was not enforced in the type with the presence of the keyword.) Notes * [LexerMain.ml] and [ParserMain.ml] for CameLIGO and PascaLIGO are almost identical and differ in the same way (language name and file extension), which suggests that they should be in the [shared] folder and instanciated as a functor in the future (TODO). * I removed the blank characters at the end of many lines in the parser of ReasonLIGO.
2019-12-13 12:21:52 +01:00
(** TODO: The labelled arguments should be flowing from the CLI. *)
2019-09-21 11:30:41 +02:00
("pattern",
fun () -> ParserLog.pattern_to_string
Refactoring of comments (for [dune build @doc]). Refactoring of parsing command-line arguments * The type [options] is now abstract and implemented as an object type to avoid struggling with scoping and type inference when record types share some common field names. Refactoring of ParserLog for PascaLIGO and CameLIGO * The immediate motivation behind that refactoring was to remove the use of a couple of global references. A consequence is that we have a nicer and more compact code, by threading a state. The files [pascaligo/Tests/pp.ligo] and [ligodity/Tests/pp.mligo]. * Another consequence is that the choice of making strings from AST nodes depends on the CLI (offsets? mode?). After this refactoring, that choice is hardcoded in the simplifiers in a few places (TODO), waiting for a general solution that would have all CL options flow through the compiler. * I removed the use of vendors [x_option.ml], [x_map.ml] and [x_list.ml] when handling optional values. (Less dependencies this way.) Refactoring of the ASTs * I removed the node [local_decl], which was set to [[]] already in a previous commit (which removed local declarations as being redundant, as statements could already be instructions or declarations). * I changed [StrLit] to [String] in the AST of CameLIGO and ReasonLIGO. * I also changed the type [fun_expr] so now either a block is present, and therefore followed by the [with] keyword, or it is not. (Before, the presence of a block was not enforced in the type with the presence of the keyword.) Notes * [LexerMain.ml] and [ParserMain.ml] for CameLIGO and PascaLIGO are almost identical and differ in the same way (language name and file extension), which suggests that they should be in the [shared] folder and instanciated as a functor in the future (TODO). * I removed the blank characters at the end of many lines in the parser of ReasonLIGO.
2019-12-13 12:21:52 +01:00
~offsets:true ~mode:`Point p)
] in
error ~data title message
let unsupported_deep_Some_patterns pattern =
let title () = "" in
let message () =
Format.asprintf "\nCurrently, only variables in constructors \
\"Some\" in patterns are supported.\n" in
let pattern_loc = Raw.pattern_to_region pattern in
let data = [
("location",
fun () -> Format.asprintf "%a" Location.pp_lift @@ pattern_loc)
] in
error ~data title message
let unsupported_deep_list_patterns cons =
let title () = "" in
let message () =
Format.asprintf "\nCurrently, only empty lists and x::y \
are supported in patterns.\n" in
let data = [
("location",
fun () -> Format.asprintf "%a" Location.pp_lift @@ cons.Region.region)
] in
error ~data title message
(* Logging *)
2020-03-12 23:20:39 +01:00
let abstracting_instruction t =
let title () = "\nSimplifiying instruction" in
let message () = "" in
Refactoring of comments (for [dune build @doc]). Refactoring of parsing command-line arguments * The type [options] is now abstract and implemented as an object type to avoid struggling with scoping and type inference when record types share some common field names. Refactoring of ParserLog for PascaLIGO and CameLIGO * The immediate motivation behind that refactoring was to remove the use of a couple of global references. A consequence is that we have a nicer and more compact code, by threading a state. The files [pascaligo/Tests/pp.ligo] and [ligodity/Tests/pp.mligo]. * Another consequence is that the choice of making strings from AST nodes depends on the CLI (offsets? mode?). After this refactoring, that choice is hardcoded in the simplifiers in a few places (TODO), waiting for a general solution that would have all CL options flow through the compiler. * I removed the use of vendors [x_option.ml], [x_map.ml] and [x_list.ml] when handling optional values. (Less dependencies this way.) Refactoring of the ASTs * I removed the node [local_decl], which was set to [[]] already in a previous commit (which removed local declarations as being redundant, as statements could already be instructions or declarations). * I changed [StrLit] to [String] in the AST of CameLIGO and ReasonLIGO. * I also changed the type [fun_expr] so now either a block is present, and therefore followed by the [with] keyword, or it is not. (Before, the presence of a block was not enforced in the type with the presence of the keyword.) Notes * [LexerMain.ml] and [ParserMain.ml] for CameLIGO and PascaLIGO are almost identical and differ in the same way (language name and file extension), which suggests that they should be in the [shared] folder and instanciated as a functor in the future (TODO). * I removed the blank characters at the end of many lines in the parser of ReasonLIGO.
2019-12-13 12:21:52 +01:00
(** TODO: The labelled arguments should be flowing from the CLI. *)
let data = [
("instruction",
fun () -> ParserLog.instruction_to_string
Refactoring of comments (for [dune build @doc]). Refactoring of parsing command-line arguments * The type [options] is now abstract and implemented as an object type to avoid struggling with scoping and type inference when record types share some common field names. Refactoring of ParserLog for PascaLIGO and CameLIGO * The immediate motivation behind that refactoring was to remove the use of a couple of global references. A consequence is that we have a nicer and more compact code, by threading a state. The files [pascaligo/Tests/pp.ligo] and [ligodity/Tests/pp.mligo]. * Another consequence is that the choice of making strings from AST nodes depends on the CLI (offsets? mode?). After this refactoring, that choice is hardcoded in the simplifiers in a few places (TODO), waiting for a general solution that would have all CL options flow through the compiler. * I removed the use of vendors [x_option.ml], [x_map.ml] and [x_list.ml] when handling optional values. (Less dependencies this way.) Refactoring of the ASTs * I removed the node [local_decl], which was set to [[]] already in a previous commit (which removed local declarations as being redundant, as statements could already be instructions or declarations). * I changed [StrLit] to [String] in the AST of CameLIGO and ReasonLIGO. * I also changed the type [fun_expr] so now either a block is present, and therefore followed by the [with] keyword, or it is not. (Before, the presence of a block was not enforced in the type with the presence of the keyword.) Notes * [LexerMain.ml] and [ParserMain.ml] for CameLIGO and PascaLIGO are almost identical and differ in the same way (language name and file extension), which suggests that they should be in the [shared] folder and instanciated as a functor in the future (TODO). * I removed the blank characters at the end of many lines in the parser of ReasonLIGO.
2019-12-13 12:21:52 +01:00
~offsets:true ~mode:`Point t)
] in
error ~data title message
end
open Errors
2020-03-12 23:20:39 +01:00
open Operators.Abstracter.Pascaligo
2019-05-12 20:56:22 +00:00
2019-05-28 15:36:14 +00:00
let r_split = Location.r_split
(* Statements can't be simplified in isolation. [a ; b ; c] can get
simplified either as [let x = expr in (b ; c)] if [a] is a [const x
= expr] declaration or as [sequence(a, sequence(b, c))] for
2020-03-12 23:20:39 +01:00
everything else. Because of this, abstracting sequences depend on
their contents. To avoid peeking in their contents, we instead
simplify sequences elements as functions from their next elements
to the actual result.
For [return_let_in], if there is no follow-up element, an error is
triggered, as you can't have [let x = expr in ...] with no [...]. A
cleaner option might be to add a [unit] instead of failing.
2019-09-10 12:42:49 +02:00
[return_statement] is used for non-let-in statements.
*)
2019-09-10 12:42:49 +02:00
2019-12-04 18:30:52 +01:00
let return_let_in ?loc binder mut inline rhs = ok @@ fun expr'_opt ->
match expr'_opt with
2019-12-04 18:30:52 +01:00
| None -> ok @@ e_let_in ?loc binder mut inline rhs (e_skip ())
| Some expr' -> ok @@ e_let_in ?loc binder mut inline rhs expr'
2019-09-10 12:42:49 +02:00
let return_statement expr = ok @@ fun expr'_opt ->
match expr'_opt with
| None -> ok @@ expr
| Some expr' -> ok @@ e_sequence expr expr'
2019-12-04 18:30:52 +01:00
2020-03-12 23:20:39 +01:00
let rec abstr_type_expression (t:Raw.type_expr) : type_expression result =
2019-05-12 20:56:22 +00:00
match t with
2020-03-12 23:20:39 +01:00
TPar x -> abstr_type_expression x.value.inside
2019-11-06 17:23:49 +01:00
| TVar v -> (
match type_constants v.value with
| Ok (s,_) -> ok @@ make_t @@ T_constant s
| Error _ -> ok @@ make_t @@ T_variable (Var.of_name v.value)
2019-05-12 20:56:22 +00:00
)
| TFun x -> (
let%bind (a , b) =
let (a , _ , b) = x.value in
2020-03-12 23:20:39 +01:00
bind_map_pair abstr_type_expression (a , b) in
2019-12-04 18:30:52 +01:00
ok @@ make_t @@ T_arrow {type1=a;type2=b}
2019-05-12 20:56:22 +00:00
)
| TApp x ->
let (name, tuple) = x.value in
let lst = npseq_to_list tuple.value.inside in
let%bind lst =
2020-03-12 23:20:39 +01:00
bind_list @@ List.map abstr_type_expression lst in (** TODO: fix constant and operator*)
2019-05-23 12:16:12 +00:00
let%bind cst =
trace (unknown_predefined_type name) @@
type_operators name.value in
2019-12-24 12:20:39 +01:00
t_operator cst lst
2019-05-12 20:56:22 +00:00
| TProd p ->
2020-03-12 23:20:39 +01:00
let%bind tpl = abstr_list_type_expression
2019-09-10 12:42:49 +02:00
@@ npseq_to_list p.value in
2019-05-12 20:56:22 +00:00
ok tpl
| TRecord r ->
2019-09-10 12:42:49 +02:00
let aux = fun (x, y) ->
2020-03-12 23:20:39 +01:00
let%bind y = abstr_type_expression y in
2019-09-10 12:42:49 +02:00
ok (x, y)
in
let apply =
fun (x:Raw.field_decl Raw.reg) -> (x.value.field_name.value, x.value.field_type) in
2019-05-12 20:56:22 +00:00
let%bind lst = bind_list
@@ List.map aux
@@ List.map apply
@@ npseq_to_list r.value.ne_elements in
let m = List.fold_left (fun m (x, y) -> LMap.add (Label x) y m) LMap.empty lst in
ok @@ make_t @@ T_record m
2019-05-12 20:56:22 +00:00
| TSum s ->
let aux (v:Raw.variant Raw.reg) =
let args =
2019-11-06 17:23:49 +01:00
match v.value.arg with
None -> []
2019-11-06 17:23:49 +01:00
| Some (_, TProd product) -> npseq_to_list product.value
| Some (_, t_expr) -> [t_expr] in
2020-03-12 23:20:39 +01:00
let%bind te = abstr_list_type_expression @@ args in
2019-05-12 20:56:22 +00:00
ok (v.value.constr.value, te)
in
let%bind lst = bind_list
@@ List.map aux
@@ npseq_to_list s.value in
let m = List.fold_left (fun m (x, y) -> CMap.add (Constructor x) y m) CMap.empty lst in
ok @@ make_t @@ T_sum m
2019-05-12 20:56:22 +00:00
2020-03-12 23:20:39 +01:00
and abstr_list_type_expression (lst:Raw.type_expr list) : type_expression result =
2019-05-12 20:56:22 +00:00
match lst with
2019-06-06 20:49:36 +00:00
| [] -> ok @@ t_unit
2020-03-12 23:20:39 +01:00
| [hd] -> abstr_type_expression hd
2019-05-12 20:56:22 +00:00
| lst ->
2020-03-12 23:20:39 +01:00
let%bind lst = bind_list @@ List.map abstr_type_expression lst in
2019-12-04 18:30:52 +01:00
ok @@ t_tuple lst
2019-05-12 20:56:22 +00:00
2020-03-12 23:20:39 +01:00
let abstr_projection : Raw.projection Region.reg -> _ = fun p ->
2019-09-10 12:42:49 +02:00
let (p' , loc) = r_split p in
let var =
let name = Var.of_name p'.struct_name.value in
2019-09-10 12:42:49 +02:00
e_variable name in
let path = p'.field_path in
let path' =
2019-09-10 12:42:49 +02:00
let aux (s:Raw.selection) =
match s with
| FieldName property -> property.value
| Component index -> (Z.to_string (snd index.value))
2019-09-10 12:42:49 +02:00
in
List.map aux @@ npseq_to_list path in
2019-12-04 18:30:52 +01:00
ok @@ List.fold_left (e_accessor ~loc) var path'
2019-09-10 12:42:49 +02:00
2020-03-12 23:20:39 +01:00
let rec abstr_expression (t:Raw.expr) : expr result =
let return x = ok x in
2019-05-12 20:56:22 +00:00
match t with
| EAnnot a -> (
2019-05-28 15:36:14 +00:00
let ((expr , type_expr) , loc) = r_split a in
2020-03-12 23:20:39 +01:00
let%bind expr' = abstr_expression expr in
let%bind type_expr' = abstr_type_expression type_expr in
2019-05-28 15:36:14 +00:00
return @@ e_annotation ~loc expr' type_expr'
2019-05-12 20:56:22 +00:00
)
| EVar c -> (
2019-05-28 15:36:14 +00:00
let (c' , loc) = r_split c in
match constants c' with
| Error _ -> return @@ e_variable ~loc (Var.of_name c.value)
| Ok (s,_) -> return @@ e_constant ~loc s []
2019-05-12 20:56:22 +00:00
)
| ECall x -> (
let ((f, args) , loc) = r_split x in
2019-05-28 15:36:14 +00:00
let (args , args_loc) = r_split args in
let args' = npseq_to_list args.inside in
match f with
| EVar name -> (
let (f_name , f_loc) = r_split name in
match constants f_name with
| Error _ ->
2020-03-12 23:20:39 +01:00
let%bind arg = abstr_tuple_expression ~loc:args_loc args' in
return @@ e_application ~loc (e_variable ~loc:f_loc (Var.of_name f_name)) arg
| Ok (s,_) ->
2020-03-12 23:20:39 +01:00
let%bind lst = bind_map_list abstr_expression args' in
return @@ e_constant ~loc s lst
)
| f -> (
2020-03-12 23:20:39 +01:00
let%bind f' = abstr_expression f in
let%bind arg = abstr_tuple_expression ~loc:args_loc args' in
return @@ e_application ~loc f' arg
)
2019-05-12 20:56:22 +00:00
)
2020-03-12 23:20:39 +01:00
| EPar x -> abstr_expression x.value.inside
2019-05-28 15:36:14 +00:00
| EUnit reg ->
let loc = Location.lift reg in
return @@ e_literal ~loc Literal_unit
| EBytes x ->
let (x' , loc) = r_split x in
2020-01-09 16:50:27 -06:00
return @@ e_literal ~loc (Literal_bytes (Hex.to_bytes @@ snd x'))
2019-05-12 20:56:22 +00:00
| ETuple tpl ->
let (tpl' , loc) = r_split tpl in
2020-03-12 23:20:39 +01:00
abstr_tuple_expression ~loc @@ npseq_to_list tpl'.inside
2019-05-12 20:56:22 +00:00
| ERecord r ->
let%bind fields = bind_list
2020-03-12 23:20:39 +01:00
@@ List.map (fun ((k : _ Raw.reg), v) -> let%bind v = abstr_expression v in ok (k.value, v))
2019-05-12 20:56:22 +00:00
@@ List.map (fun (x:Raw.field_assign Raw.reg) -> (x.value.field_name, x.value.field_expr))
2019-11-06 17:23:49 +01:00
@@ npseq_to_list r.value.ne_elements in
2019-05-12 20:56:22 +00:00
let aux prev (k, v) = SMap.add k v prev in
2019-05-28 15:36:14 +00:00
return @@ e_record (List.fold_left aux SMap.empty fields)
2020-03-12 23:20:39 +01:00
| EProj p -> abstr_projection p
| EUpdate u -> abstr_update u
2019-05-28 15:36:14 +00:00
| EConstr (ConstrApp c) -> (
let ((c, args) , loc) = r_split c in
match args with
2020-02-24 17:29:45 +01:00
None ->
return @@ e_constructor ~loc c.value (e_unit ())
| Some args ->
let args, args_loc = r_split args in
let%bind arg =
2020-03-12 23:20:39 +01:00
abstr_tuple_expression ~loc:args_loc
@@ npseq_to_list args.inside in
return @@ e_constructor ~loc c.value arg
2019-05-28 15:36:14 +00:00
)
2019-05-12 20:56:22 +00:00
| EConstr (SomeApp a) ->
2019-05-28 15:36:14 +00:00
let ((_, args) , loc) = r_split a in
let (args , args_loc) = r_split args in
2019-05-12 20:56:22 +00:00
let%bind arg =
2020-03-12 23:20:39 +01:00
abstr_tuple_expression ~loc:args_loc
2019-05-28 15:36:14 +00:00
@@ npseq_to_list args.inside in
return @@ e_constant ~loc C_SOME [arg]
2019-05-28 15:36:14 +00:00
| EConstr (NoneExpr reg) -> (
let loc = Location.lift reg in
return @@ e_none ~loc ()
)
2019-05-12 20:56:22 +00:00
| EArith (Add c) ->
2020-03-12 23:20:39 +01:00
abstr_binop "ADD" c
2019-05-12 20:56:22 +00:00
| EArith (Sub c) ->
2020-03-12 23:20:39 +01:00
abstr_binop "SUB" c
2019-05-12 20:56:22 +00:00
| EArith (Mult c) ->
2020-03-12 23:20:39 +01:00
abstr_binop "TIMES" c
2019-05-12 20:56:22 +00:00
| EArith (Div c) ->
2020-03-12 23:20:39 +01:00
abstr_binop "DIV" c
2019-05-12 20:56:22 +00:00
| EArith (Mod c) ->
2020-03-12 23:20:39 +01:00
abstr_binop "MOD" c
2019-05-28 15:36:14 +00:00
| EArith (Int n) -> (
let (n , loc) = r_split n in
let n = Z.to_int @@ snd n in
return @@ e_literal ~loc (Literal_int n)
)
| EArith (Nat n) -> (
let (n , loc) = r_split n in
let n = Z.to_int @@ snd @@ n in
return @@ e_literal ~loc (Literal_nat n)
)
2019-10-27 11:50:24 -05:00
| EArith (Mutez n) -> (
2019-07-19 12:13:09 +02:00
let (n , loc) = r_split n in
let n = Z.to_int @@ snd @@ n in
2019-09-24 14:29:18 +02:00
return @@ e_literal ~loc (Literal_mutez n)
2019-07-19 12:13:09 +02:00
)
2020-03-12 23:20:39 +01:00
| EArith (Neg e) -> abstr_unop "NEG" e
2019-05-12 20:56:22 +00:00
| EString (String s) ->
2019-05-28 15:36:14 +00:00
let (s , loc) = r_split s in
2019-05-12 20:56:22 +00:00
let s' =
2019-05-28 15:36:14 +00:00
(* S contains quotes *)
String.(sub s 1 (length s - 2))
2019-05-12 20:56:22 +00:00
in
2019-05-28 15:36:14 +00:00
return @@ e_literal ~loc (Literal_string s')
2019-10-07 17:16:03 +02:00
| EString (Cat bo) ->
let (bo , loc) = r_split bo in
2020-03-12 23:20:39 +01:00
let%bind sl = abstr_expression bo.arg1 in
let%bind sr = abstr_expression bo.arg2 in
2019-10-07 17:16:03 +02:00
return @@ e_string_cat ~loc sl sr
2020-03-12 23:20:39 +01:00
| ELogic l -> abstr_logic_expression l
| EList l -> abstr_list_expression l
| ESet s -> abstr_set_expression s
2019-10-18 14:47:04 +02:00
| ECond c ->
let (c , loc) = r_split c in
2020-03-12 23:20:39 +01:00
let%bind expr = abstr_expression c.test in
let%bind match_true = abstr_expression c.ifso in
let%bind match_false = abstr_expression c.ifnot in
2019-12-04 18:30:52 +01:00
let match_expr = e_matching expr ~loc (Match_bool {match_true; match_false}) in
let env = Var.fresh () in
let%bind (_, match_expr) = repair_mutable_variable_in_matching match_expr [] env in
2019-12-04 18:30:52 +01:00
return @@ match_expr
2019-05-28 15:36:14 +00:00
| ECase c -> (
let (c , loc) = r_split c in
2020-03-12 23:20:39 +01:00
let%bind e = abstr_expression c.expr in
2019-05-12 20:56:22 +00:00
let%bind lst =
let aux (x : Raw.expr Raw.case_clause) =
2020-03-12 23:20:39 +01:00
let%bind expr = abstr_expression x.rhs in
2019-05-12 20:56:22 +00:00
ok (x.pattern, expr) in
bind_list
@@ List.map aux
@@ List.map get_value
2019-05-28 15:36:14 +00:00
@@ npseq_to_list c.cases.value in
2020-03-12 23:20:39 +01:00
let%bind cases = abstr_cases lst in
2019-12-04 18:30:52 +01:00
let match_expr = e_matching ~loc e cases in
let env = Var.fresh () in
let%bind (_, match_expr) = repair_mutable_variable_in_matching match_expr [] env in
2019-12-04 18:30:52 +01:00
return @@ match_expr
2019-05-28 15:36:14 +00:00
)
2019-10-21 13:04:28 +02:00
| EMap (MapInj mi) -> (
2019-05-28 15:36:14 +00:00
let (mi , loc) = r_split mi in
2019-05-12 20:56:22 +00:00
let%bind lst =
2019-05-28 15:36:14 +00:00
let lst = List.map get_value @@ pseq_to_list mi.elements in
let aux : Raw.binding -> (expression * expression) result =
fun b ->
2020-03-12 23:20:39 +01:00
let%bind src = abstr_expression b.source in
let%bind dst = abstr_expression b.image in
ok (src, dst) in
2019-05-12 20:56:22 +00:00
bind_map_list aux lst in
2019-05-28 15:36:14 +00:00
return @@ e_map ~loc lst
)
2019-10-21 13:04:28 +02:00
| EMap (BigMapInj mi) -> (
let (mi , loc) = r_split mi in
let%bind lst =
let lst = List.map get_value @@ pseq_to_list mi.elements in
let aux : Raw.binding -> (expression * expression) result =
fun b ->
2020-03-12 23:20:39 +01:00
let%bind src = abstr_expression b.source in
let%bind dst = abstr_expression b.image in
2019-10-21 13:04:28 +02:00
ok (src, dst) in
bind_map_list aux lst in
return @@ e_big_map ~loc lst
)
2019-05-28 15:36:14 +00:00
| EMap (MapLookUp lu) -> (
let (lu , loc) = r_split lu in
let%bind path = match lu.path with
| Name v -> (
let (v , loc) = r_split v in
return @@ e_variable ~loc (Var.of_name v)
2019-05-28 15:36:14 +00:00
)
2020-03-12 23:20:39 +01:00
| Path p -> abstr_projection p
2019-05-12 20:56:22 +00:00
in
2020-03-12 23:20:39 +01:00
let%bind index = abstr_expression lu.index.value.inside in
2019-05-28 15:36:14 +00:00
return @@ e_look_up ~loc path index
)
| EFun f ->
let (f , loc) = r_split f in
2020-03-12 23:20:39 +01:00
let%bind (_ty_opt, f') = abstr_fun_expression ~loc f
in return @@ f'
2019-05-12 20:56:22 +00:00
2020-01-09 18:23:37 +01:00
2020-03-12 23:20:39 +01:00
and abstr_update = fun (u:Raw.update Region.reg) ->
2020-01-09 18:23:37 +01:00
let (u, loc) = r_split u in
2020-03-12 23:20:39 +01:00
let (name, path) = abstr_path u.record in
let record = match path with
2020-01-09 18:23:37 +01:00
| [] -> e_variable (Var.of_name name)
2019-12-04 18:30:52 +01:00
| _ -> e_accessor_list (e_variable (Var.of_name name)) path in
2020-01-09 18:23:37 +01:00
let updates = u.updates.value.ne_elements in
let%bind updates' =
let aux (f:Raw.field_path_assign Raw.reg) =
2020-01-09 18:23:37 +01:00
let (f,_) = r_split f in
2020-03-12 23:20:39 +01:00
let%bind expr = abstr_expression f.field_expr in
ok ( List.map (fun (x: _ Raw.reg) -> x.value) (npseq_to_list f.field_path), expr)
2020-01-09 18:23:37 +01:00
in
bind_map_list aux @@ npseq_to_list updates
2020-01-09 18:23:37 +01:00
in
let aux ur (path, expr) =
let rec aux record = function
| [] -> failwith "error in parsing"
| hd :: [] -> ok @@ e_update ~loc record hd expr
| hd :: tl ->
2019-12-04 18:30:52 +01:00
let%bind expr = (aux (e_accessor ~loc record hd) tl) in
ok @@ e_update ~loc record hd expr
in
aux ur path in
bind_fold_list aux record updates'
2020-01-09 18:23:37 +01:00
2020-03-12 23:20:39 +01:00
and abstr_logic_expression (t:Raw.logic_expr) : expression result =
let return x = ok x in
2019-05-12 20:56:22 +00:00
match t with
2019-05-28 15:36:14 +00:00
| BoolExpr (False reg) -> (
let loc = Location.lift reg in
return @@ e_literal ~loc (Literal_bool false)
)
| BoolExpr (True reg) -> (
let loc = Location.lift reg in
return @@ e_literal ~loc (Literal_bool true)
)
2019-05-12 20:56:22 +00:00
| BoolExpr (Or b) ->
2020-03-12 23:20:39 +01:00
abstr_binop "OR" b
2019-05-12 20:56:22 +00:00
| BoolExpr (And b) ->
2020-03-12 23:20:39 +01:00
abstr_binop "AND" b
2019-05-12 20:56:22 +00:00
| BoolExpr (Not b) ->
2020-03-12 23:20:39 +01:00
abstr_unop "NOT" b
2019-05-12 20:56:22 +00:00
| CompExpr (Lt c) ->
2020-03-12 23:20:39 +01:00
abstr_binop "LT" c
2019-05-12 20:56:22 +00:00
| CompExpr (Gt c) ->
2020-03-12 23:20:39 +01:00
abstr_binop "GT" c
2019-05-12 20:56:22 +00:00
| CompExpr (Leq c) ->
2020-03-12 23:20:39 +01:00
abstr_binop "LE" c
2019-05-12 20:56:22 +00:00
| CompExpr (Geq c) ->
2020-03-12 23:20:39 +01:00
abstr_binop "GE" c
2019-05-12 20:56:22 +00:00
| CompExpr (Equal c) ->
2020-03-12 23:20:39 +01:00
abstr_binop "EQ" c
2019-05-12 20:56:22 +00:00
| CompExpr (Neq c) ->
2020-03-12 23:20:39 +01:00
abstr_binop "NEQ" c
2019-05-12 20:56:22 +00:00
2020-03-12 23:20:39 +01:00
and abstr_list_expression (t:Raw.list_expr) : expression result =
let return x = ok x in
2019-05-12 20:56:22 +00:00
match t with
2019-11-06 17:23:49 +01:00
ECons c ->
2020-03-12 23:20:39 +01:00
abstr_binop "CONS" c
2019-11-06 17:23:49 +01:00
| EListComp lst ->
2019-05-28 15:36:14 +00:00
let (lst , loc) = r_split lst in
2019-05-12 20:56:22 +00:00
let%bind lst' =
2020-03-12 23:20:39 +01:00
bind_map_list abstr_expression @@
2019-05-28 15:36:14 +00:00
pseq_to_list lst.elements in
return @@ e_list ~loc lst'
2019-11-06 17:23:49 +01:00
| ENil reg ->
2019-05-28 15:36:14 +00:00
let loc = Location.lift reg in
return @@ e_list ~loc []
2019-05-12 20:56:22 +00:00
2020-03-12 23:20:39 +01:00
and abstr_set_expression (t:Raw.set_expr) : expression result =
2019-07-19 14:35:47 +02:00
match t with
| SetMem x -> (
let (x' , loc) = r_split x in
2020-03-12 23:20:39 +01:00
let%bind set' = abstr_expression x'.set in
let%bind element' = abstr_expression x'.element in
ok @@ e_constant ~loc C_SET_MEM [ element' ; set' ]
2019-07-19 14:35:47 +02:00
)
| SetInj x -> (
let (x' , loc) = r_split x in
let elements = pseq_to_list x'.elements in
2020-03-12 23:20:39 +01:00
let%bind elements' = bind_map_list abstr_expression elements in
2019-07-19 14:35:47 +02:00
ok @@ e_set ~loc elements'
)
2020-03-12 23:20:39 +01:00
and abstr_binop (name:string) (t:_ Raw.bin_op Region.reg) : expression result =
let return x = ok x in
2019-05-28 15:36:14 +00:00
let (t , loc) = r_split t in
2020-03-12 23:20:39 +01:00
let%bind a = abstr_expression t.arg1 in
let%bind b = abstr_expression t.arg2 in
let%bind name = constants name in
2019-05-28 15:36:14 +00:00
return @@ e_constant ~loc name [ a ; b ]
2019-05-12 20:56:22 +00:00
2020-03-12 23:20:39 +01:00
and abstr_unop (name:string) (t:_ Raw.un_op Region.reg) : expression result =
let return x = ok x in
2019-05-28 15:36:14 +00:00
let (t , loc) = r_split t in
2020-03-12 23:20:39 +01:00
let%bind a = abstr_expression t.arg in
let%bind name = constants name in
2019-05-28 15:36:14 +00:00
return @@ e_constant ~loc name [ a ]
2019-05-12 20:56:22 +00:00
2020-03-12 23:20:39 +01:00
and abstr_tuple_expression ?loc (lst:Raw.expr list) : expression result =
let return x = ok x in
2019-05-12 20:56:22 +00:00
match lst with
2019-05-28 15:36:14 +00:00
| [] -> return @@ e_literal Literal_unit
2020-03-12 23:20:39 +01:00
| [hd] -> abstr_expression hd
| lst ->
2020-03-12 23:20:39 +01:00
let%bind lst = bind_list @@ List.map abstr_expression lst
in return @@ e_tuple ?loc lst
2019-05-12 20:56:22 +00:00
2020-03-12 23:20:39 +01:00
and abstr_data_declaration : Raw.data_decl -> _ result =
fun t ->
2019-05-12 20:56:22 +00:00
match t with
| LocalVar x ->
2019-05-28 15:36:14 +00:00
let (x , loc) = r_split x in
2019-05-12 20:56:22 +00:00
let name = x.name.value in
2020-03-12 23:20:39 +01:00
let%bind t = abstr_type_expression x.var_type in
let%bind expression = abstr_expression x.init in
2019-12-04 18:30:52 +01:00
return_let_in ~loc (Var.of_name name, Some t) false false expression
2019-05-12 20:56:22 +00:00
| LocalConst x ->
2019-05-28 15:36:14 +00:00
let (x , loc) = r_split x in
2019-05-12 20:56:22 +00:00
let name = x.name.value in
2020-03-12 23:20:39 +01:00
let%bind t = abstr_type_expression x.const_type in
let%bind expression = abstr_expression x.init in
let inline =
match x.attributes with
None -> false
| Some {value; _} ->
npseq_to_list value.ne_elements
|> List.exists (fun Region.{value; _} -> value = "\"inline\"")
2019-12-04 18:30:52 +01:00
in return_let_in ~loc (Var.of_name name, Some t) false inline expression
| LocalFun f ->
let (f , loc) = r_split f in
2020-03-12 23:20:39 +01:00
let%bind (binder, expr) = abstr_fun_decl ~loc f in
let inline =
match f.attributes with
None -> false
| Some {value; _} ->
npseq_to_list value.ne_elements
|> List.exists (fun Region.{value; _} -> value = "\"inline\"")
2019-12-04 18:30:52 +01:00
in return_let_in ~loc binder false inline expr
2020-03-12 23:20:39 +01:00
and abstr_param :
2019-12-04 18:30:52 +01:00
Raw.param_decl -> (string * type_expression) result =
fun t ->
2019-05-12 20:56:22 +00:00
match t with
| ParamConst c ->
let c = c.value in
2019-12-04 18:30:52 +01:00
let param_name = c.var.value in
2020-03-12 23:20:39 +01:00
let%bind type_expression = abstr_type_expression c.param_type in
2019-12-04 18:30:52 +01:00
ok (param_name , type_expression)
2019-05-12 20:56:22 +00:00
| ParamVar v ->
let c = v.value in
2019-12-04 18:30:52 +01:00
let param_name = c.var.value in
2020-03-12 23:20:39 +01:00
let%bind type_expression = abstr_type_expression c.param_type in
2019-12-04 18:30:52 +01:00
ok (param_name , type_expression)
2019-05-12 20:56:22 +00:00
2020-03-12 23:20:39 +01:00
and abstr_fun_decl :
loc:_ -> Raw.fun_decl ->
((expression_variable * type_expression option) * expression) result =
fun ~loc x ->
2019-05-12 20:56:22 +00:00
let open! Raw in
2020-03-07 01:19:22 +01:00
let {kwd_recursive;fun_name; param; ret_type; block_with;
return; attributes} : fun_decl = x in
let inline =
match attributes with
None -> false
| Some {value; _} ->
npseq_to_list value.ne_elements
|> List.exists (fun Region.{value; _} -> value = "\"inline\"") in
let statements =
Refactoring of comments (for [dune build @doc]). Refactoring of parsing command-line arguments * The type [options] is now abstract and implemented as an object type to avoid struggling with scoping and type inference when record types share some common field names. Refactoring of ParserLog for PascaLIGO and CameLIGO * The immediate motivation behind that refactoring was to remove the use of a couple of global references. A consequence is that we have a nicer and more compact code, by threading a state. The files [pascaligo/Tests/pp.ligo] and [ligodity/Tests/pp.mligo]. * Another consequence is that the choice of making strings from AST nodes depends on the CLI (offsets? mode?). After this refactoring, that choice is hardcoded in the simplifiers in a few places (TODO), waiting for a general solution that would have all CL options flow through the compiler. * I removed the use of vendors [x_option.ml], [x_map.ml] and [x_list.ml] when handling optional values. (Less dependencies this way.) Refactoring of the ASTs * I removed the node [local_decl], which was set to [[]] already in a previous commit (which removed local declarations as being redundant, as statements could already be instructions or declarations). * I changed [StrLit] to [String] in the AST of CameLIGO and ReasonLIGO. * I also changed the type [fun_expr] so now either a block is present, and therefore followed by the [with] keyword, or it is not. (Before, the presence of a block was not enforced in the type with the presence of the keyword.) Notes * [LexerMain.ml] and [ParserMain.ml] for CameLIGO and PascaLIGO are almost identical and differ in the same way (language name and file extension), which suggests that they should be in the [shared] folder and instanciated as a functor in the future (TODO). * I removed the blank characters at the end of many lines in the parser of ReasonLIGO.
2019-12-13 12:21:52 +01:00
match block_with with
| Some (block,_) -> npseq_to_list block.value.statements
| None -> []
2019-10-19 09:11:18 -07:00
in
(match param.value.inside with
a, [] -> (
2020-03-12 23:20:39 +01:00
let%bind input = abstr_param a in
let (binder , input_type) = input in
2020-03-12 23:20:39 +01:00
let%bind instructions = abstr_statement_list statements in
let%bind result = abstr_expression return in
let%bind output_type = abstr_type_expression ret_type in
Refactoring of comments (for [dune build @doc]). Refactoring of parsing command-line arguments * The type [options] is now abstract and implemented as an object type to avoid struggling with scoping and type inference when record types share some common field names. Refactoring of ParserLog for PascaLIGO and CameLIGO * The immediate motivation behind that refactoring was to remove the use of a couple of global references. A consequence is that we have a nicer and more compact code, by threading a state. The files [pascaligo/Tests/pp.ligo] and [ligodity/Tests/pp.mligo]. * Another consequence is that the choice of making strings from AST nodes depends on the CLI (offsets? mode?). After this refactoring, that choice is hardcoded in the simplifiers in a few places (TODO), waiting for a general solution that would have all CL options flow through the compiler. * I removed the use of vendors [x_option.ml], [x_map.ml] and [x_list.ml] when handling optional values. (Less dependencies this way.) Refactoring of the ASTs * I removed the node [local_decl], which was set to [[]] already in a previous commit (which removed local declarations as being redundant, as statements could already be instructions or declarations). * I changed [StrLit] to [String] in the AST of CameLIGO and ReasonLIGO. * I also changed the type [fun_expr] so now either a block is present, and therefore followed by the [with] keyword, or it is not. (Before, the presence of a block was not enforced in the type with the presence of the keyword.) Notes * [LexerMain.ml] and [ParserMain.ml] for CameLIGO and PascaLIGO are almost identical and differ in the same way (language name and file extension), which suggests that they should be in the [shared] folder and instanciated as a functor in the future (TODO). * I removed the blank characters at the end of many lines in the parser of ReasonLIGO.
2019-12-13 12:21:52 +01:00
let body = instructions in
let%bind result =
let aux prec cur = cur (Some prec) in
bind_fold_right_list aux result body in
2020-03-07 01:19:22 +01:00
let binder = Var.of_name binder in
let fun_name = Var.of_name fun_name.value in
let fun_type = t_function input_type output_type in
let expression : expression =
e_lambda ~loc binder (Some input_type)(Some output_type) result in
let%bind expression = match kwd_recursive with
None -> ok @@ expression |
Some _ -> ok @@ e_recursive ~loc fun_name fun_type
@@ {binder;input_type=Some input_type; output_type= Some output_type; result}
in
ok ((fun_name, Some fun_type), expression)
2019-05-12 20:56:22 +00:00
)
| lst -> (
let lst = npseq_to_list lst in
(* TODO wrong, should be fresh? *)
let arguments_name = Var.of_name "arguments" in
2020-03-12 23:20:39 +01:00
let%bind params = bind_map_list abstr_param lst in
let (binder , input_type) =
let type_expression = t_tuple (List.map snd params) in
(arguments_name , type_expression) in
let%bind tpl_declarations =
2019-12-04 18:30:52 +01:00
let aux = fun i (param, type_expr) ->
let expr =
2019-12-04 18:30:52 +01:00
e_accessor (e_variable arguments_name) (string_of_int i) in
let type_variable = Some type_expr in
let ass = return_let_in (Var.of_name param , type_variable) false inline expr in
2019-05-12 20:56:22 +00:00
ass
in
bind_list @@ List.mapi aux params in
2020-03-12 23:20:39 +01:00
let%bind instructions = abstr_statement_list statements in
let%bind result = abstr_expression return in
let%bind output_type = abstr_type_expression ret_type in
Refactoring of comments (for [dune build @doc]). Refactoring of parsing command-line arguments * The type [options] is now abstract and implemented as an object type to avoid struggling with scoping and type inference when record types share some common field names. Refactoring of ParserLog for PascaLIGO and CameLIGO * The immediate motivation behind that refactoring was to remove the use of a couple of global references. A consequence is that we have a nicer and more compact code, by threading a state. The files [pascaligo/Tests/pp.ligo] and [ligodity/Tests/pp.mligo]. * Another consequence is that the choice of making strings from AST nodes depends on the CLI (offsets? mode?). After this refactoring, that choice is hardcoded in the simplifiers in a few places (TODO), waiting for a general solution that would have all CL options flow through the compiler. * I removed the use of vendors [x_option.ml], [x_map.ml] and [x_list.ml] when handling optional values. (Less dependencies this way.) Refactoring of the ASTs * I removed the node [local_decl], which was set to [[]] already in a previous commit (which removed local declarations as being redundant, as statements could already be instructions or declarations). * I changed [StrLit] to [String] in the AST of CameLIGO and ReasonLIGO. * I also changed the type [fun_expr] so now either a block is present, and therefore followed by the [with] keyword, or it is not. (Before, the presence of a block was not enforced in the type with the presence of the keyword.) Notes * [LexerMain.ml] and [ParserMain.ml] for CameLIGO and PascaLIGO are almost identical and differ in the same way (language name and file extension), which suggests that they should be in the [shared] folder and instanciated as a functor in the future (TODO). * I removed the blank characters at the end of many lines in the parser of ReasonLIGO.
2019-12-13 12:21:52 +01:00
let body = tpl_declarations @ instructions in
let%bind result =
let aux prec cur = cur (Some prec) in
bind_fold_right_list aux result body in
2020-03-07 01:19:22 +01:00
let fun_name = Var.of_name fun_name.value in
let fun_type = t_function input_type output_type in
let expression : expression =
e_lambda ~loc binder (Some input_type)(Some output_type) result in
let%bind expression = match kwd_recursive with
None -> ok @@ expression |
Some _ -> ok @@ e_recursive ~loc fun_name fun_type
@@ {binder;input_type=Some input_type; output_type= Some output_type; result}
in
ok ((fun_name, Some fun_type), expression)
2019-05-12 20:56:22 +00:00
)
)
2020-03-12 23:20:39 +01:00
and abstr_fun_expression :
loc:_ -> Raw.fun_expr -> (type_expression option * expression) result =
fun ~loc x ->
let open! Raw in
2020-03-07 01:19:22 +01:00
let {kwd_recursive;param;ret_type;return} : fun_expr = x in
let statements = [] in
(match param.value.inside with
2020-03-07 01:19:22 +01:00
a, [] -> (
2020-03-12 23:20:39 +01:00
let%bind input = abstr_param a in
2020-03-11 17:04:49 +01:00
let (binder , input_type) = input in
2020-03-12 23:20:39 +01:00
let%bind instructions = abstr_statement_list statements in
let%bind result = abstr_expression return in
let%bind output_type = abstr_type_expression ret_type in
2020-03-11 17:04:49 +01:00
let body = instructions in
let%bind result =
let aux prec cur = cur (Some prec) in
bind_fold_right_list aux result body in
let binder = Var.of_name binder in
let fun_type = t_function input_type output_type in
let expression = match kwd_recursive with
| None -> e_lambda ~loc binder (Some input_type)(Some output_type) result
| Some _ -> e_recursive ~loc binder fun_type
@@ {binder;input_type=Some input_type; output_type= Some output_type; result}
in
ok (Some fun_type , expression)
)
| lst -> (
let lst = npseq_to_list lst in
(* TODO wrong, should be fresh? *)
let arguments_name = Var.of_name "arguments" in
2020-03-12 23:20:39 +01:00
let%bind params = bind_map_list abstr_param lst in
let (binder , input_type) =
let type_expression = t_tuple (List.map snd params) in
(arguments_name , type_expression) in
let%bind tpl_declarations =
2019-12-04 18:30:52 +01:00
let aux = fun i (param, param_type) ->
let expr = e_accessor (e_variable arguments_name) (string_of_int i) in
let type_variable = Some param_type in
let ass = return_let_in (Var.of_name param , type_variable) false false expr in
ass
in
bind_list @@ List.mapi aux params in
2020-03-12 23:20:39 +01:00
let%bind instructions = abstr_statement_list statements in
let%bind result = abstr_expression return in
let%bind output_type = abstr_type_expression ret_type in
let body = tpl_declarations @ instructions in
let%bind result =
let aux prec cur = cur (Some prec) in
bind_fold_right_list aux result body in
2020-03-07 01:19:22 +01:00
let fun_type = t_function input_type output_type in
2020-03-11 17:04:49 +01:00
let expression = match kwd_recursive with
| None -> e_lambda ~loc binder (Some input_type)(Some output_type) result
| Some _ -> e_recursive ~loc binder fun_type
2020-03-07 01:19:22 +01:00
@@ {binder;input_type=Some input_type; output_type= Some output_type; result}
in
ok (Some fun_type , expression)
)
)
2020-03-12 23:20:39 +01:00
and abstr_statement_list statements =
let open Raw in
let rec hook acc = function
[] -> acc
| [Attr _] ->
(* Detached attributes are erased. TODO: Warning. *)
acc
| Attr _ :: (Attr _ :: _ as statements) ->
(* Detached attributes are erased. TODO: Warning. *)
hook acc statements
| Attr decl :: Data (LocalConst {value; region}) :: statements ->
let new_const =
Data (LocalConst {value = {value with attributes = Some decl}; region})
in hook acc (new_const :: statements)
| Attr decl :: Data (LocalFun {value; region}) :: statements ->
let new_fun =
Data (LocalFun {value = {value with attributes = Some decl}; region})
in hook acc (new_fun :: statements)
| Attr _ :: statements ->
(* Detached attributes are erased. TODO: Warning. *)
hook acc statements
| Instr i :: statements ->
2020-03-12 23:20:39 +01:00
hook (abstr_instruction i :: acc) statements
| Data d :: statements ->
2020-03-12 23:20:39 +01:00
hook (abstr_data_declaration d :: acc) statements
in bind_list @@ hook [] (List.rev statements)
2019-05-12 20:56:22 +00:00
2019-12-04 18:30:52 +01:00
and get_case_variables (t:Raw.pattern) : expression_variable list result =
match t with
| PConstr PFalse _
| PConstr PTrue _
| PConstr PNone _ -> ok @@ []
| PConstr PSomeApp v -> (let (_,v) = v.value in get_case_variables (v.value.inside))
| PConstr PConstrApp v -> (
match v.value with
| constr, None -> ok @@ [ Var.of_name constr.value]
| constr, pat_opt ->
let%bind pat =
trace_option (unsupported_cst_constr t) @@
pat_opt in
let pat = npseq_to_list pat.value.inside in
let%bind var = bind_map_list get_case_variables pat in
ok @@ [Var.of_name constr.value ] @ (List.concat var)
)
| PList PNil _ -> ok @@ []
| PList PCons c -> (
match c.value with
| a, [(_, b)] ->
let%bind a = get_case_variables a in
let%bind b = get_case_variables b in
ok @@ a@b
| _ -> fail @@ unsupported_deep_list_patterns c
)
| PVar v -> ok @@ [Var.of_name v.value]
| p -> fail @@ unsupported_cst_constr p
2020-03-12 23:20:39 +01:00
and abstr_single_instruction : Raw.instruction -> (_ -> expression result) result =
fun t ->
2019-05-12 20:56:22 +00:00
match t with
2019-07-20 13:46:42 +02:00
| ProcCall x -> (
let (f, args) , loc = r_split x in
let args, args_loc = r_split args in
let args' = npseq_to_list args.inside in
match f with
| EVar name -> (
let (f_name , f_loc) = r_split name in
match constants f_name with
| Error _ ->
2020-03-12 23:20:39 +01:00
let%bind arg = abstr_tuple_expression ~loc:args_loc args' in
return_statement @@ e_application ~loc (e_variable ~loc:f_loc (Var.of_name f_name)) arg
| Ok (s,_) ->
2020-03-12 23:20:39 +01:00
let%bind lst = bind_map_list abstr_expression args' in
return_statement @@ e_constant ~loc s lst
)
| f -> (
2020-03-12 23:20:39 +01:00
let%bind f' = abstr_expression f in
let%bind arg = abstr_tuple_expression ~loc:args_loc args' in
return_statement @@ e_application ~loc f' arg
2019-07-20 13:46:42 +02:00
)
)
2019-05-28 15:36:14 +00:00
| Skip reg -> (
let loc = Location.lift reg in
2019-09-10 12:42:49 +02:00
return_statement @@ e_skip ~loc ()
2019-05-28 15:36:14 +00:00
)
2019-05-12 20:56:22 +00:00
| Loop (While l) ->
2020-03-12 23:20:39 +01:00
abstr_while_loop l.value
2019-12-04 18:30:52 +01:00
| Loop (For (ForInt fi)) -> (
2020-03-12 23:20:39 +01:00
let%bind loop = abstr_for_int fi.value in
2019-12-04 18:30:52 +01:00
ok loop
)
2019-10-15 13:14:00 +02:00
| Loop (For (ForCollect fc)) ->
2020-03-12 23:20:39 +01:00
let%bind loop = abstr_for_collect fc.value in
2019-12-04 18:30:52 +01:00
ok loop
2019-05-28 15:36:14 +00:00
| Cond c -> (
let (c , loc) = r_split c in
2020-03-12 23:20:39 +01:00
let%bind expr = abstr_expression c.test in
2019-05-12 20:56:22 +00:00
let%bind match_true = match c.ifso with
2019-10-17 18:33:58 +02:00
ClauseInstr i ->
2020-03-12 23:20:39 +01:00
abstr_single_instruction i
2019-10-17 18:33:58 +02:00
| ClauseBlock b ->
match b with
LongBlock {value; _} ->
2020-03-12 23:20:39 +01:00
abstr_block value
2019-10-17 18:33:58 +02:00
| ShortBlock {value; _} ->
2020-03-12 23:20:39 +01:00
abstr_statements @@ fst value.inside in
2019-05-12 20:56:22 +00:00
let%bind match_false = match c.ifnot with
2019-10-17 18:33:58 +02:00
ClauseInstr i ->
2020-03-12 23:20:39 +01:00
abstr_single_instruction i
2019-10-17 18:33:58 +02:00
| ClauseBlock b ->
match b with
LongBlock {value; _} ->
2020-03-12 23:20:39 +01:00
abstr_block value
2019-10-17 18:33:58 +02:00
| ShortBlock {value; _} ->
2020-03-12 23:20:39 +01:00
abstr_statements @@ fst value.inside in
2019-12-04 18:30:52 +01:00
let env = Var.fresh () in
let%bind match_true' = match_true None in
let%bind match_false' = match_false None in
let%bind match_true = match_true @@ Some (e_variable env) in
let%bind match_false = match_false @@ Some (e_variable env) in
let%bind ((_,free_vars_true), match_true) = repair_mutable_variable_in_matching match_true [] env in
let%bind ((_,free_vars_false), match_false) = repair_mutable_variable_in_matching match_false [] env in
2019-12-04 18:30:52 +01:00
let free_vars = free_vars_true @ free_vars_false in
if (List.length free_vars != 0) then
let match_expr = e_matching expr ~loc (Match_bool {match_true; match_false}) in
let return_expr = fun expr ->
e_let_in (env,None) false false (store_mutable_variable free_vars) @@
e_let_in (env,None) false false match_expr @@
expr
in
2019-12-04 18:30:52 +01:00
restore_mutable_variable return_expr free_vars env
else
return_statement @@ e_matching expr ~loc (Match_bool {match_true=match_true'; match_false=match_false'})
2019-05-28 15:36:14 +00:00
)
2019-05-12 20:56:22 +00:00
| Assign a -> (
2019-05-28 15:36:14 +00:00
let (a , loc) = r_split a in
2020-03-12 23:20:39 +01:00
let%bind value_expr = abstr_expression a.rhs in
2019-05-12 20:56:22 +00:00
match a.lhs with
| Path path -> (
2020-03-12 23:20:39 +01:00
let (name , path') = abstr_path path in
2019-12-04 18:30:52 +01:00
let (let_binder, mut, rhs, inline) = e_assign_with_let ~loc name path' value_expr in
return_let_in let_binder mut inline rhs
2019-05-12 20:56:22 +00:00
)
| MapPath v -> (
let v' = v.value in
let%bind (varname,map,path) = match v'.path with
| Name name -> ok (name.value , e_variable (Var.of_name name.value), [])
| Path p ->
2020-03-12 23:20:39 +01:00
let (name,p') = abstr_path v'.path in
let%bind accessor = abstr_projection p in
ok @@ (name , accessor , p')
in
2020-03-12 23:20:39 +01:00
let%bind key_expr = abstr_expression v'.index.value.inside in
let expr' = e_map_add key_expr value_expr map in
2019-12-04 18:30:52 +01:00
let (let_binder, mut, rhs, inline) = e_assign_with_let ~loc varname path expr' in
return_let_in let_binder mut inline rhs
2019-05-12 20:56:22 +00:00
)
)
| CaseInstr c -> (
2019-05-28 15:36:14 +00:00
let (c , loc) = r_split c in
2020-03-12 23:20:39 +01:00
let%bind expr = abstr_expression c.expr in
2019-12-04 18:30:52 +01:00
let env = Var.fresh () in
let%bind (fv,cases) =
let aux fv (x : Raw.if_clause Raw.case_clause Raw.reg) =
let%bind case_clause =
match x.value.rhs with
ClauseInstr i ->
2020-03-12 23:20:39 +01:00
abstr_single_instruction i
| ClauseBlock b ->
match b with
LongBlock {value; _} ->
2020-03-12 23:20:39 +01:00
abstr_block value
| ShortBlock {value; _} ->
2020-03-12 23:20:39 +01:00
abstr_statements @@ fst value.inside in
2019-12-04 18:30:52 +01:00
let%bind case_clause'= case_clause @@ None in
let%bind case_clause = case_clause @@ Some(e_variable env) in
let%bind case_vars = get_case_variables x.value.pattern in
let%bind ((_,free_vars), case_clause) = repair_mutable_variable_in_matching case_clause case_vars env in
2019-12-04 18:30:52 +01:00
ok (free_vars::fv,(x.value.pattern, case_clause, case_clause')) in
bind_fold_map_list aux [] (npseq_to_list c.cases.value) in
let free_vars = List.concat fv in
if (List.length free_vars == 0) then (
let cases = List.map (fun case -> let (a,_,b) = case in (a,b)) cases in
2020-03-12 23:20:39 +01:00
let%bind m = abstr_cases cases in
2019-12-04 18:30:52 +01:00
return_statement @@ e_matching ~loc expr m
) else (
let cases = List.map (fun case -> let (a,b,_) = case in (a,b)) cases in
2020-03-12 23:20:39 +01:00
let%bind m = abstr_cases cases in
2019-12-04 18:30:52 +01:00
let match_expr = e_matching ~loc expr m in
let return_expr = fun expr ->
e_let_in (env,None) false false (store_mutable_variable free_vars) @@
e_let_in (env,None) false false match_expr @@
expr
in
2019-12-04 18:30:52 +01:00
restore_mutable_variable return_expr free_vars env
)
)
2019-05-12 20:56:22 +00:00
| RecordPatch r -> (
2019-12-04 18:30:52 +01:00
let reg = r.region in
let (r,loc) = r_split r in
let aux (fa :Raw.field_assign Raw.reg) : Raw.field_path_assign Raw.reg=
{value = {field_path = (fa.value.field_name, []); equal=fa.value.equal; field_expr = fa.value.field_expr};
region = fa.region}
in
let update : Raw.field_path_assign Raw.reg Raw.ne_injection Raw.reg = {
value = Raw.map_ne_injection aux r.record_inj.value;
region=r.record_inj.region
} in
let u : Raw.update = {record=r.path;kwd_with=r.kwd_with; updates=update} in
2020-03-12 23:20:39 +01:00
let%bind expr = abstr_update {value=u;region=reg} in
let (name , access_path) = abstr_path r.path in
2019-12-04 18:30:52 +01:00
let loc = Some loc in
let (binder, mut, rhs, inline) = e_assign_with_let ?loc name access_path expr in
return_let_in binder mut inline rhs
)
| MapPatch patch -> (
let (map_p, loc) = r_split patch in
2020-03-12 23:20:39 +01:00
let (name, access_path) = abstr_path map_p.path in
let%bind inj = bind_list
@@ List.map (fun (x:Raw.binding Region.reg) ->
let x = x.value in
let (key, value) = x.source, x.image in
2020-03-12 23:20:39 +01:00
let%bind key' = abstr_expression key in
let%bind value' = abstr_expression value
in ok @@ (key', value')
)
@@ npseq_to_list map_p.map_inj.value.ne_elements in
2019-12-04 18:30:52 +01:00
match inj with
| [] -> return_statement @@ e_skip ~loc ()
| _ :: _ ->
let assigns = List.fold_right
(fun (key, value) map -> (e_map_add key value map))
inj
(e_accessor_list ~loc (e_variable (Var.of_name name)) access_path)
in
let (binder, mut, rhs, inline) = e_assign_with_let ~loc name access_path assigns in
return_let_in binder mut inline rhs
)
| SetPatch patch -> (
let (setp, loc) = r_split patch in
2020-03-12 23:20:39 +01:00
let (name , access_path) = abstr_path setp.path in
2019-10-11 15:10:08 -05:00
let%bind inj =
bind_list @@
2020-03-12 23:20:39 +01:00
List.map abstr_expression @@
npseq_to_list setp.set_inj.value.ne_elements in
2019-12-04 18:30:52 +01:00
match inj with
| [] -> return_statement @@ e_skip ~loc ()
| _ :: _ ->
let assigns = List.fold_right
(fun hd s -> e_constant C_SET_ADD [hd ; s])
inj (e_accessor_list ~loc (e_variable (Var.of_name name)) access_path) in
let (binder, mut, rhs, inline) = e_assign_with_let ~loc name access_path assigns in
return_let_in binder mut inline rhs
)
2019-05-28 15:36:14 +00:00
| MapRemove r -> (
let (v , loc) = r_split r in
2019-05-12 20:56:22 +00:00
let key = v.key in
let%bind (varname,map,path) = match v.map with
| Name v -> ok (v.value , e_variable (Var.of_name v.value) , [])
| Path p ->
2020-03-12 23:20:39 +01:00
let (name,p') = abstr_path v.map in
let%bind accessor = abstr_projection p in
ok @@ (name , accessor , p')
in
2020-03-12 23:20:39 +01:00
let%bind key' = abstr_expression key in
let expr = e_constant ~loc C_MAP_REMOVE [key' ; map] in
2019-12-04 18:30:52 +01:00
let (binder, mut, rhs, inline) = e_assign_with_let ~loc varname path expr in
return_let_in binder mut inline rhs
2019-05-28 15:36:14 +00:00
)
| SetRemove r -> (
let (set_rm, loc) = r_split r in
let%bind (varname, set, path) = match set_rm.set with
| Name v -> ok (v.value, e_variable (Var.of_name v.value), [])
| Path path ->
2020-03-12 23:20:39 +01:00
let(name, p') = abstr_path set_rm.set in
let%bind accessor = abstr_projection path in
ok @@ (name, accessor, p')
in
2020-03-12 23:20:39 +01:00
let%bind removed' = abstr_expression set_rm.element in
let expr = e_constant ~loc C_SET_REMOVE [removed' ; set] in
2019-12-04 18:30:52 +01:00
let (binder, mut, rhs, inline) = e_assign_with_let ~loc varname path expr in
return_let_in binder mut inline rhs
)
2019-05-12 20:56:22 +00:00
2020-03-12 23:20:39 +01:00
and abstr_path : Raw.path -> string * string list = fun p ->
2019-05-12 20:56:22 +00:00
match p with
| Raw.Name v -> (v.value , [])
2019-05-12 20:56:22 +00:00
| Raw.Path p -> (
let p' = p.value in
let var = p'.struct_name.value in
let path = p'.field_path in
let path' =
2019-05-12 20:56:22 +00:00
let aux (s:Raw.selection) =
match s with
| FieldName property -> property.value
| Component index -> (Z.to_string (snd index.value))
2019-05-12 20:56:22 +00:00
in
List.map aux @@ npseq_to_list path in
(var , path')
2019-05-12 20:56:22 +00:00
)
2020-03-12 23:20:39 +01:00
and abstr_cases : (Raw.pattern * expression) list -> matching_expr result = fun t ->
2019-05-12 20:56:22 +00:00
let open Raw in
let get_var (t:Raw.pattern) =
match t with
2019-05-12 20:56:22 +00:00
| PVar v -> ok v.value
| p -> fail @@ unsupported_non_var_pattern p in
let get_tuple (t: Raw.pattern) =
match t with
2019-05-12 20:56:22 +00:00
| PTuple v -> npseq_to_list v.value.inside
| x -> [ x ] in
let get_single (t: Raw.pattern) =
2019-05-12 20:56:22 +00:00
let t' = get_tuple t in
let%bind () =
trace_strong (unsupported_tuple_pattern t) @@
2019-05-12 20:56:22 +00:00
Assert.assert_list_size t' 1 in
ok (List.hd t') in
2019-09-21 11:30:41 +02:00
let get_toplevel (t : Raw.pattern) =
match t with
2019-11-06 17:23:49 +01:00
| PList PCons x -> (
2019-09-21 11:30:41 +02:00
let (x' , lst) = x.value in
match lst with
| [] -> ok x'
| _ -> ok t
)
| pattern -> ok pattern in
let get_constr (t: Raw.pattern) =
match t with
2019-11-06 17:23:49 +01:00
| PConstr (PConstrApp v) -> (
2020-01-03 13:01:13 +00:00
let value = v.value in
match value with
| constr, None ->
ok (constr.value, "unit")
| _ ->
2019-11-06 17:23:49 +01:00
let const, pat_opt = v.value in
let%bind pat =
trace_option (unsupported_cst_constr t) @@
pat_opt in
let%bind single_pat = get_single (PTuple pat) in
let%bind var = get_var single_pat in
ok (const.value , var)
)
| _ -> fail @@ only_constructors t in
2019-05-12 20:56:22 +00:00
let%bind patterns =
let aux (x , y) =
2019-09-21 11:30:41 +02:00
let%bind x' = get_toplevel x in
ok (x' , y)
in bind_map_list aux t in
2019-05-12 20:56:22 +00:00
match patterns with
2019-11-06 17:23:49 +01:00
| [(PConstr PFalse _ , f) ; (PConstr PTrue _ , t)]
| [(PConstr PTrue _ , t) ; (PConstr PFalse _ , f)] ->
ok @@ Match_bool {match_true = t ; match_false = f}
2019-11-06 17:23:49 +01:00
| [(PConstr PSomeApp v , some) ; (PConstr PNone _ , none)]
| [(PConstr PNone _ , none) ; (PConstr PSomeApp v , some)] -> (
2019-05-12 20:56:22 +00:00
let (_, v) = v.value in
let%bind v = match v.value.inside with
| PVar v -> ok v.value
| p -> fail @@ unsupported_deep_Some_patterns p in
ok @@ Match_option {match_none = none ; match_some = (Var.of_name v, some, ()) }
2019-05-12 20:56:22 +00:00
)
2019-11-06 17:23:49 +01:00
| [(PList PCons c, cons) ; (PList (PNil _), nil)]
| [(PList (PNil _), nil) ; (PList PCons c, cons)] ->
2019-05-12 20:56:22 +00:00
let%bind (a, b) =
match c.value with
| a, [(_, b)] ->
let%bind a = get_var a in
let%bind b = get_var b in
ok (a, b)
| _ -> fail @@ unsupported_deep_list_patterns c
2019-05-12 20:56:22 +00:00
in
ok @@ Match_list {match_cons = (Var.of_name a, Var.of_name b, cons,()) ; match_nil = nil}
2019-05-12 20:56:22 +00:00
| lst ->
trace (simple_info "currently, only booleans, options, lists and \
user-defined constructors are supported in patterns") @@
2019-05-12 20:56:22 +00:00
let%bind constrs =
let aux (x , y) =
let error =
let title () = "Pattern" in
(* TODO: The labelled arguments should be flowing from the CLI. *)
2019-05-12 20:56:22 +00:00
let content () =
Printf.sprintf "Pattern : %s"
(ParserLog.pattern_to_string
Refactoring of comments (for [dune build @doc]). Refactoring of parsing command-line arguments * The type [options] is now abstract and implemented as an object type to avoid struggling with scoping and type inference when record types share some common field names. Refactoring of ParserLog for PascaLIGO and CameLIGO * The immediate motivation behind that refactoring was to remove the use of a couple of global references. A consequence is that we have a nicer and more compact code, by threading a state. The files [pascaligo/Tests/pp.ligo] and [ligodity/Tests/pp.mligo]. * Another consequence is that the choice of making strings from AST nodes depends on the CLI (offsets? mode?). After this refactoring, that choice is hardcoded in the simplifiers in a few places (TODO), waiting for a general solution that would have all CL options flow through the compiler. * I removed the use of vendors [x_option.ml], [x_map.ml] and [x_list.ml] when handling optional values. (Less dependencies this way.) Refactoring of the ASTs * I removed the node [local_decl], which was set to [[]] already in a previous commit (which removed local declarations as being redundant, as statements could already be instructions or declarations). * I changed [StrLit] to [String] in the AST of CameLIGO and ReasonLIGO. * I also changed the type [fun_expr] so now either a block is present, and therefore followed by the [with] keyword, or it is not. (Before, the presence of a block was not enforced in the type with the presence of the keyword.) Notes * [LexerMain.ml] and [ParserMain.ml] for CameLIGO and PascaLIGO are almost identical and differ in the same way (language name and file extension), which suggests that they should be in the [shared] folder and instanciated as a functor in the future (TODO). * I removed the blank characters at the end of many lines in the parser of ReasonLIGO.
2019-12-13 12:21:52 +01:00
~offsets:true ~mode:`Point x) in
2019-05-12 20:56:22 +00:00
error title content in
let%bind x' =
trace error @@
get_constr x in
ok (x' , y) in
bind_map_list aux lst in
ok @@ ez_match_variant constrs
2019-05-12 20:56:22 +00:00
2020-03-12 23:20:39 +01:00
and abstr_instruction : Raw.instruction -> (_ -> expression result) result =
fun t -> trace (abstracting_instruction t) @@ abstr_single_instruction t
2019-05-12 20:56:22 +00:00
2020-03-12 23:20:39 +01:00
and abstr_statements : Raw.statements -> (_ -> expression result) result =
fun statements ->
let lst = npseq_to_list statements in
2020-03-12 23:20:39 +01:00
let%bind fs = abstr_statement_list lst in
let aux : _ -> (expression option -> expression result) -> _ =
fun prec cur ->
let%bind res = cur prec
in ok @@ Some res in
ok @@ fun (expr' : _ option) ->
let%bind ret = bind_fold_right_list aux expr' fs in
ok @@ Option.unopt_exn ret
2020-03-12 23:20:39 +01:00
and abstr_block : Raw.block -> (_ -> expression result) result =
fun t -> abstr_statements t.statements
2019-05-12 20:56:22 +00:00
2020-03-12 23:20:39 +01:00
and abstr_while_loop : Raw.while_loop -> (_ -> expression result) result = fun wl ->
2019-12-04 18:30:52 +01:00
let env_rec = Var.fresh () in
let binder = Var.fresh () in
2020-03-12 23:20:39 +01:00
let%bind cond = abstr_expression wl.cond in
2019-12-04 18:30:52 +01:00
let ctrl =
(e_variable binder)
in
2020-03-12 23:20:39 +01:00
let%bind for_body = abstr_block wl.block.value in
2019-12-04 18:30:52 +01:00
let%bind for_body = for_body @@ Some( ctrl ) in
let%bind ((_,captured_name_list),for_body) = repair_mutable_variable_in_loops for_body [] binder in
2019-12-04 18:30:52 +01:00
let aux name expr=
e_let_in (name,None) false false (e_accessor (e_accessor (e_variable binder) "0") (Var.to_name name)) expr
2019-12-04 18:30:52 +01:00
in
let init_rec = e_tuple [store_mutable_variable @@ captured_name_list] in
2019-12-04 18:30:52 +01:00
let restore = fun expr -> List.fold_right aux captured_name_list expr in
2020-03-06 23:44:28 +01:00
let continue_expr = e_constant C_FOLD_CONTINUE [for_body] in
let stop_expr = e_constant C_FOLD_STOP [e_variable binder] in
let aux_func =
e_lambda binder None None @@
restore @@
e_cond cond continue_expr stop_expr in
2019-12-04 18:30:52 +01:00
let loop = e_constant C_FOLD_WHILE [aux_func; e_variable env_rec] in
let return_expr = fun expr ->
e_let_in (env_rec,None) false false init_rec @@
e_let_in (env_rec,None) false false loop @@
e_let_in (env_rec,None) false false (e_accessor (e_variable env_rec) "0") @@
expr
in
2019-12-04 18:30:52 +01:00
restore_mutable_variable return_expr captured_name_list env_rec
2020-03-12 23:20:39 +01:00
and abstr_for_int : Raw.for_int -> (_ -> expression result) result = fun fi ->
2019-12-04 18:30:52 +01:00
let env_rec = Var.fresh () in
let binder = Var.fresh () in
let name = fi.assign.value.name.value in
let it = Var.of_name name in
let var = e_variable it in
(*Make the cond and the step *)
2020-03-12 23:20:39 +01:00
let%bind value = abstr_expression fi.assign.value.expr in
let%bind bound = abstr_expression fi.bound in
2019-12-04 18:30:52 +01:00
let cond = e_annotation (e_constant C_LE [var ; bound]) t_bool in
2019-10-22 12:12:19 +02:00
let step = e_int 1 in
let continue_expr = e_constant C_FOLD_CONTINUE [(e_variable binder)] in
2019-12-04 18:30:52 +01:00
let ctrl =
e_let_in (it,Some t_int) false false (e_constant C_ADD [ var ; step ]) @@
e_let_in (binder, None) false false (e_update (e_variable binder) "1" var)@@
continue_expr
in
2019-12-04 18:30:52 +01:00
(* Modify the body loop*)
2020-03-12 23:20:39 +01:00
let%bind for_body = abstr_block fi.block.value in
let%bind for_body = for_body @@ Some ctrl in
let%bind ((_,captured_name_list),for_body) = repair_mutable_variable_in_loops for_body [it] binder in
2019-12-04 18:30:52 +01:00
let aux name expr=
e_let_in (name,None) false false (e_accessor (e_accessor (e_variable binder) "0") (Var.to_name name)) expr
2019-12-04 18:30:52 +01:00
in
(* restores the initial value of the free_var*)
let restore = fun expr -> List.fold_right aux captured_name_list expr in
(*Prep the lambda for the fold*)
2020-03-06 23:44:28 +01:00
let stop_expr = e_constant C_FOLD_STOP [e_variable binder] in
let aux_func = e_lambda binder None None @@
e_let_in (it,Some t_int) false false (e_accessor (e_variable binder) "1") @@
e_cond cond (restore for_body) (stop_expr) in
2019-12-04 18:30:52 +01:00
(* Make the fold_while en precharge the vakye *)
let loop = e_constant C_FOLD_WHILE [aux_func; e_variable env_rec] in
let init_rec = e_pair (store_mutable_variable @@ captured_name_list) var in
let return_expr = fun expr ->
e_let_in (it, Some t_int) false false value @@
e_let_in (env_rec,None) false false init_rec @@
e_let_in (env_rec,None) false false loop @@
e_let_in (env_rec,None) false false (e_accessor (e_variable env_rec) "0") @@
expr
in
2019-12-04 18:30:52 +01:00
restore_mutable_variable return_expr captured_name_list env_rec
2020-03-12 23:20:39 +01:00
and abstr_for_collect : Raw.for_collect -> (_ -> expression result) result = fun fc ->
2019-12-04 18:30:52 +01:00
let binder = Var.of_name "arguments" in
let%bind element_names = ok @@ match fc.bind_to with
| Some v -> [Var.of_name fc.var.value;Var.of_name (snd v).value]
| None -> [Var.of_name fc.var.value] in
2019-12-04 18:30:52 +01:00
let env = Var.fresh () in
2020-03-12 23:20:39 +01:00
let%bind for_body = abstr_block fc.block.value in
2019-12-04 18:30:52 +01:00
let%bind for_body = for_body @@ Some (e_accessor (e_variable binder) "0") in
let%bind ((_,free_vars), for_body) = repair_mutable_variable_in_loops for_body element_names binder in
2019-12-04 18:30:52 +01:00
let init_record = store_mutable_variable free_vars in
2020-03-12 23:20:39 +01:00
let%bind collect = abstr_expression fc.expr in
2019-12-04 18:30:52 +01:00
let aux name expr=
e_let_in (name,None) false false (e_accessor (e_accessor (e_variable binder) "0") (Var.to_name name)) expr
in
let restore = fun expr -> List.fold_right aux free_vars expr in
let restore = match fc.collection with
| Map _ -> (match fc.bind_to with
| Some v -> fun expr -> restore (e_let_in (Var.of_name fc.var.value, None) false false (e_accessor (e_accessor (e_variable binder) "1") "0")
(e_let_in (Var.of_name (snd v).value, None) false false (e_accessor (e_accessor (e_variable binder) "1") "1") expr))
| None -> fun expr -> restore (e_let_in (Var.of_name fc.var.value, None) false false (e_accessor (e_accessor (e_variable binder) "1") "0") expr)
)
| _ -> fun expr -> restore (e_let_in (Var.of_name fc.var.value, None) false false (e_accessor (e_variable binder) "1") expr)
in
let lambda = e_lambda binder None None (restore for_body) in
let op_name = match fc.collection with
| Map _ -> C_MAP_FOLD | Set _ -> C_SET_FOLD | List _ -> C_LIST_FOLD in
let fold = fun expr ->
e_let_in (env,None) false false (e_constant op_name [lambda; collect ; init_record]) @@
expr
in
2019-12-04 18:30:52 +01:00
restore_mutable_variable fold free_vars env
2020-03-12 23:20:39 +01:00
and abstr_declaration_list declarations : declaration Location.wrap list result =
let open Raw in
let rec hook acc = function
[] -> acc
| [AttrDecl _] ->
(* Detached attributes are erased. TODO: Warning. *)
acc
| AttrDecl _ :: (AttrDecl _ :: _ as declarations) ->
(* Detached attributes are erased. TODO: Warning. *)
hook acc declarations
| AttrDecl decl :: ConstDecl {value; region} :: declarations ->
let new_const =
ConstDecl {value = {value with attributes = Some decl}; region}
in hook acc (new_const :: declarations)
| AttrDecl decl :: FunDecl {value; region} :: declarations ->
let new_fun =
FunDecl {value = {value with attributes = Some decl}; region}
in hook acc (new_fun :: declarations)
| AttrDecl _ :: declarations ->
(* Detached attributes are erased. TODO: Warning. *)
hook acc declarations
| TypeDecl decl :: declarations ->
let decl, loc = r_split decl in
let {name; type_expr} : Raw.type_decl = decl in
2020-03-12 23:20:39 +01:00
let%bind type_expression = abstr_type_expression type_expr in
let new_decl =
Declaration_type (Var.of_name name.value, type_expression) in
2020-01-21 19:04:51 +01:00
let res = Location.wrap ~loc new_decl in
hook (bind_list_cons res acc) declarations
| ConstDecl decl :: declarations ->
2020-03-12 23:20:39 +01:00
let abstr_const_decl =
fun {name;const_type; init; attributes} ->
2020-03-12 23:20:39 +01:00
let%bind expression = abstr_expression init in
let%bind t = abstr_type_expression const_type in
let type_annotation = Some t in
let inline =
match attributes with
None -> false
| Some {value; _} ->
npseq_to_list value.ne_elements
|> List.exists (fun Region.{value; _} -> value = "\"inline\"") in
let new_decl =
Declaration_constant
(Var.of_name name.value, type_annotation, inline, expression)
in ok new_decl in
2020-01-21 19:04:51 +01:00
let%bind res =
2020-03-12 23:20:39 +01:00
bind_map_location abstr_const_decl (Location.lift_region decl)
2020-01-21 19:04:51 +01:00
in hook (bind_list_cons res acc) declarations
| FunDecl fun_decl :: declarations ->
let decl, loc = r_split fun_decl in
2020-03-12 23:20:39 +01:00
let%bind ((name, ty_opt), expr) = abstr_fun_decl ~loc decl in
let inline =
match fun_decl.value.attributes with
None -> false
| Some {value; _} ->
npseq_to_list value.ne_elements
|> List.exists (fun Region.{value; _} -> value = "\"inline\"") in
let new_decl =
Declaration_constant (name, ty_opt, inline, expr) in
2020-01-21 19:04:51 +01:00
let res = Location.wrap ~loc new_decl in
hook (bind_list_cons res acc) declarations
2020-01-24 12:56:05 +01:00
in hook (ok @@ []) (List.rev declarations)
2020-03-12 23:20:39 +01:00
let abstr_program : Raw.ast -> program result =
fun t -> abstr_declaration_list @@ nseq_to_list t.decl