auto-generated folds: have a distinct input and output type for the state

This commit is contained in:
Suzanne Dupéron 2020-05-22 19:27:10 +01:00
parent ee5e484bf4
commit 851132528d
5 changed files with 124 additions and 116 deletions

View File

@ -4,14 +4,16 @@ open Format
open PP_helpers
module M = struct
type no_state = NoState
let needs_parens = {
generic = (fun state info ->
generic = (fun NoState info ->
match info.node_instance.instance_kind with
| RecordInstance _ -> false
| VariantInstance _ -> true
| PolyInstance { poly =_; arguments=_; poly_continue } ->
(poly_continue state)
(poly_continue NoState)
);
generic_empty_ctor = (fun _ -> false) ;
type_variable = (fun _ _ _ -> true) ;
bool = (fun _ _ _ -> false) ;
int = (fun _ _ _ -> false) ;
@ -37,83 +39,81 @@ module M = struct
typeVariableMap = (fun _ _ _ _ -> false) ;
}
let op ppf = {
generic = (fun () info ->
let op ppf : (no_state, unit) fold_config = {
generic = (fun NoState info ->
match info.node_instance.instance_kind with
| RecordInstance { fields } ->
let aux ppf (fld : 'x Adt_info.ctor_or_field_instance) =
fprintf ppf "%s = %a" fld.cf.name (fun _ppf -> fld.cf_continue) () in
let aux ppf (fld : ('xi , 'xo) Adt_info.ctor_or_field_instance) =
fprintf ppf "%s = %a" fld.cf.name (fun _ppf -> fld.cf_continue) NoState in
fprintf ppf "{@,@[<hv 2> %a @]@,}" (list_sep aux (fun ppf () -> fprintf ppf " ;@ ")) fields
| VariantInstance { constructor ; _ } ->
if constructor.cf_new_fold needs_parens false
then fprintf ppf "%s (%a)" constructor.cf.name (fun _ppf -> constructor.cf_continue) ()
if constructor.cf_new_fold needs_parens NoState
then fprintf ppf "%s (%a)" constructor.cf.name (fun _ppf -> constructor.cf_continue) NoState
else let spc = if String.equal constructor.cf.type_ "" then "" else " " in
fprintf ppf "%s%s%a" constructor.cf.name spc (fun _ppf -> constructor.cf_continue) ()
fprintf ppf "%s%s%a" constructor.cf.name spc (fun _ppf -> constructor.cf_continue) NoState
| PolyInstance { poly=_; arguments=_; poly_continue } ->
(poly_continue ())
(poly_continue NoState)
);
int = (fun _visitor () i -> fprintf ppf "%i" i );
type_variable = (fun _visitor () type_variable -> fprintf ppf "Var %a" Var.pp type_variable) ;
bool = (fun _visitor () b -> fprintf ppf "%s" (if b then "true" else "false")) ;
z = (fun _visitor () i -> fprintf ppf "%a" Z.pp_print i) ;
string = (fun _visitor () str -> fprintf ppf "\"%s\"" str) ;
ligo_string = (fun _visitor () str -> fprintf ppf "%a" Ligo_string.pp str) ;
bytes = (fun _visitor () _bytes -> fprintf ppf "bytes...") ;
unit = (fun _visitor () () -> fprintf ppf "()") ;
packed_internal_operation = (fun _visitor () _op -> fprintf ppf "Operation(...bytes)") ;
expression_variable = (fun _visitor () ev -> fprintf ppf "%a" Var.pp ev) ;
constructor' = (fun _visitor () (Constructor c) -> fprintf ppf "Constructor %s" c) ;
location = (fun _visitor () loc -> fprintf ppf "%a" Location.pp loc) ;
label = (fun _visitor () (Label lbl) -> fprintf ppf "Label %s" lbl) ;
ast_core_type_expression = (fun _visitor () te -> fprintf ppf "%a" Ast_core.PP.type_expression te) ;
constructor_map = (fun _visitor continue () cmap ->
generic_empty_ctor = (fun NoState -> ()) ;
int = (fun _visitor NoState i -> fprintf ppf "%i" i );
type_variable = (fun _visitor NoState type_variable -> fprintf ppf "Var %a" Var.pp type_variable) ;
bool = (fun _visitor NoState b -> fprintf ppf "%s" (if b then "true" else "false")) ;
z = (fun _visitor NoState i -> fprintf ppf "%a" Z.pp_print i) ;
string = (fun _visitor NoState str -> fprintf ppf "\"%s\"" str) ;
ligo_string = (fun _visitor NoState str -> fprintf ppf "%a" Ligo_string.pp str) ;
bytes = (fun _visitor NoState _bytes -> fprintf ppf "bytes...") ;
unit = (fun _visitor NoState () -> fprintf ppf "()") ;
packed_internal_operation = (fun _visitor NoState _op -> fprintf ppf "Operation(...bytes)") ;
expression_variable = (fun _visitor NoState ev -> fprintf ppf "%a" Var.pp ev) ;
constructor' = (fun _visitor NoState (Constructor c) -> fprintf ppf "Constructor %s" c) ;
location = (fun _visitor NoState loc -> fprintf ppf "%a" Location.pp loc) ;
label = (fun _visitor NoState (Label lbl) -> fprintf ppf "Label %s" lbl) ;
ast_core_type_expression = (fun _visitor NoState te -> fprintf ppf "%a" Ast_core.PP.type_expression te) ;
constructor_map = (fun _visitor continue NoState cmap ->
let lst = List.sort (fun (Constructor a, _) (Constructor b, _) -> String.compare a b) (CMap.bindings cmap) in
let aux ppf (Constructor k, v) =
fprintf ppf "(Constructor %s, %a)" k (fun _ppf -> continue ()) v in
fprintf ppf "(Constructor %s, %a)" k (fun _ppf -> continue NoState) v in
fprintf ppf "CMap [@,@[<hv 2> %a @]@,]" (list_sep aux (fun ppf () -> fprintf ppf " ; ")) lst);
label_map = (fun _visitor continue () lmap ->
label_map = (fun _visitor continue NoState lmap ->
let lst = List.sort (fun (Label a, _) (Label b, _) -> String.compare a b) (LMap.bindings lmap) in
let aux ppf (Label k, v) =
fprintf ppf "(Constructor %s, %a)" k (fun _ppf -> continue ()) v in
fprintf ppf "(Constructor %s, %a)" k (fun _ppf -> continue NoState) v in
fprintf ppf "LMap [@,@[<hv 2> %a @]@,]" (list_sep aux (fun ppf () -> fprintf ppf " ; ")) lst);
list = (fun _visitor continue () lst ->
list = (fun _visitor continue NoState lst ->
let aux ppf elt =
fprintf ppf "%a" (fun _ppf -> continue ()) elt in
fprintf ppf "%a" (fun _ppf -> continue NoState) elt in
fprintf ppf "[@,@[<hv 2> %a @]@,]" (list_sep aux (fun ppf () -> fprintf ppf " ;@ ")) lst);
location_wrap = (fun _visitor continue () lwrap ->
location_wrap = (fun _visitor continue NoState lwrap ->
let ({ wrap_content; location } : _ Location.wrap) = lwrap in
fprintf ppf "{ wrap_content = %a ; location = %a }" (fun _ppf -> continue ()) wrap_content Location.pp location);
(* list_ne = (fun _visitor continue () (first, lst) ->
let aux ppf elt =
fprintf ppf "%a" (fun _ppf -> continue ()) elt in
fprintf ppf "[@,@[<hv 2> %a @]@,]" (list_sep aux (fun ppf () -> fprintf ppf " ;@ ")) (first::lst)); *)
option = (fun _visitor continue () o ->
fprintf ppf "{ wrap_content = %a ; location = %a }" (fun _ppf -> continue NoState) wrap_content Location.pp location);
option = (fun _visitor continue NoState o ->
match o with
| None -> fprintf ppf "None"
| Some v -> fprintf ppf "%a" (fun _ppf -> continue ()) v) ;
poly_unionfind = (fun _visitor continue () p ->
| Some v -> fprintf ppf "%a" (fun _ppf -> continue NoState) v) ;
poly_unionfind = (fun _visitor continue NoState p ->
let lst = (UnionFind.Poly2.partitions p) in
let aux1 l = fprintf ppf "[@,@[<hv 2> (*%a*) %a @]@,]"
(fun _ppf -> continue ()) (UnionFind.Poly2.repr (List.hd l) p)
(list_sep (fun _ppf -> continue ()) (fun ppf () -> fprintf ppf " ;@ ")) l in
(fun _ppf -> continue NoState) (UnionFind.Poly2.repr (List.hd l) p)
(list_sep (fun _ppf -> continue NoState) (fun ppf () -> fprintf ppf " ;@ ")) l in
let aux2 = list_sep (fun _ppf -> aux1) (fun ppf () -> fprintf ppf " ;@ ") in
fprintf ppf "UnionFind [@,@[<hv 2> %a @]@,]" aux2 lst);
poly_set = (fun _visitor continue () set ->
poly_set = (fun _visitor continue NoState set ->
let lst = (RedBlackTrees.PolySet.elements set) in
fprintf ppf "Set [@,@[<hv 2> %a @]@,]" (list_sep (fun _ppf -> continue ()) (fun ppf () -> fprintf ppf " ;@ ")) lst);
typeVariableMap = (fun _visitor continue () tvmap ->
fprintf ppf "Set [@,@[<hv 2> %a @]@,]" (list_sep (fun _ppf -> continue NoState) (fun ppf () -> fprintf ppf " ;@ ")) lst);
typeVariableMap = (fun _visitor continue NoState tvmap ->
let lst = List.sort (fun (a, _) (b, _) -> Var.compare a b) (RedBlackTrees.PolyMap.bindings tvmap) in
let aux ppf (k, v) =
fprintf ppf "(Var %a, %a)" Var.pp k (fun _ppf -> continue ()) v in
fprintf ppf "(Var %a, %a)" Var.pp k (fun _ppf -> continue NoState) v in
fprintf ppf "typeVariableMap [@,@[<hv 2> %a @]@,]" (list_sep aux (fun ppf () -> fprintf ppf " ;@ ")) lst);
}
let print : (unit fold_config -> unit -> 'a -> unit) -> formatter -> 'a -> unit = fun fold ppf v ->
fold (op ppf) () v
let print : ((no_state, unit) fold_config -> no_state -> 'a -> unit) -> formatter -> 'a -> unit = fun fold ppf v ->
fold (op ppf) NoState v
end
include Fold.Folds(struct
type state = unit ;;
type in_state = M.no_state ;;
type out_state = unit ;;
type 'a t = formatter -> 'a -> unit ;;
let f = M.print ;;
end)

View File

@ -5,7 +5,7 @@ module M = struct
let compare = () (* Hide Pervasives.compare to avoid calling it without explicit qualification. *)
type 'a lz = unit -> 'a (* Lazy values *)
type t =
| NoState
| EmptyCtor
| Record of string * (string * t lz) list
| VariantConstructor of string * string * t lz
| Bool of inline
@ -30,12 +30,14 @@ module M = struct
| Set of t lz list
| TypeVariableMap of (type_variable * t lz) list
type no_state = NoState
(* TODO: make these functions return a lazy stucture *)
let op : t fold_config = {
generic = (fun _state info ->
let op : (no_state, t) fold_config = {
generic = (fun NoState info ->
match info.node_instance.instance_kind with
| RecordInstance { fields } ->
let aux (fld : 'x Adt_info.ctor_or_field_instance) =
let aux (fld : ('xi, 'xo) Adt_info.ctor_or_field_instance) =
( fld.cf.name , fun () -> fld.cf_continue NoState ) in
Record ("name_of_the_record", List.map aux fields)
| VariantInstance { constructor ; _ } ->
@ -43,6 +45,7 @@ module M = struct
| PolyInstance { poly=_; arguments=_; poly_continue } ->
poly_continue NoState
);
generic_empty_ctor = (fun NoState -> EmptyCtor) ;
int = (fun _visitor _state i -> Int i );
type_variable = (fun _visitor _state type_variable -> Var type_variable) ;
bool = (fun _visitor _state b -> Bool b) ;
@ -72,7 +75,7 @@ module M = struct
(Location_wrap { wrap_content = (fun () -> continue NoState wrap_content) ; location}));
option = (fun _visitor continue _state o ->
match o with
| None -> VariantConstructor ("built-in:option", "None", fun () -> NoState)
| None -> VariantConstructor ("built-in:option", "None", fun () -> EmptyCtor)
| Some v -> VariantConstructor ("built-in:option", "Some", fun () -> continue NoState v));
poly_unionfind = (fun _visitor continue _state p ->
(* UnionFind.Poly2.partitions returns the partitions in a
@ -89,13 +92,17 @@ module M = struct
TypeVariableMap (List.map (fun (k, v) -> (k, fun () -> continue NoState v)) lst));
}
let serialize : (t fold_config -> t -> 'a -> t) -> 'a -> t = fun fold v ->
let serialize : ((no_state, t) fold_config -> no_state -> 'a -> t) -> 'a -> t = fun fold v ->
fold op NoState v
(* What follows should be roughly the same for all ASTs, so it
should be easy to share a single copy of that and of the t type
definition above. *)
(* Generate a unique tag for each case handled below. We can then
compare data by their tag and contents. *)
let tag = function
| NoState -> 0
| EmptyCtor -> 0
| Record _ -> 1
| VariantConstructor _ -> 2
| Bool _ -> 3
@ -129,7 +136,7 @@ module M = struct
and compare_lz_t a b = compare_t (a ()) (b ())
and compare_t (a : t) (b : t) =
match (a, b) with
| (NoState, NoState) -> failwith "Should not happen (unless for ctors with no args?)"
| (EmptyCtor, EmptyCtor) -> failwith "Should not happen (unless for ctors with no args?)"
| (Record (a, fa), Record (b, fb)) -> cmp2 String.compare a b (List.compare ~compare:compare_field) fa fb
| (VariantConstructor (va, ca, xa), VariantConstructor (vb, cb, xb)) ->
cmp3
@ -158,21 +165,22 @@ module M = struct
| (Set a, Set b) -> List.compare ~compare:compare_lz_t a b
| (TypeVariableMap a, TypeVariableMap b) -> List.compare ~compare:compare_tvmap_entry a b
| ((NoState | Record _ | VariantConstructor _ | Bool _ | Bytes _ | Constructor' _ | Expression_variable _ | Int _ | Label' _ | Ligo_string _ | Location _ | Operation _ | Str _ | Type_expression _ | Unit _ | Var _ | Z _ | List _ | Location_wrap _ | CMap _ | LMap _ | UnionFind _ | Set _ | TypeVariableMap _) as a),
((NoState | Record _ | VariantConstructor _ | Bool _ | Bytes _ | Constructor' _ | Expression_variable _ | Int _ | Label' _ | Ligo_string _ | Location _ | Operation _ | Str _ | Type_expression _ | Unit _ | Var _ | Z _ | List _ | Location_wrap _ | CMap _ | LMap _ | UnionFind _ | Set _ | TypeVariableMap _) as b) ->
| ((EmptyCtor | Record _ | VariantConstructor _ | Bool _ | Bytes _ | Constructor' _ | Expression_variable _ | Int _ | Label' _ | Ligo_string _ | Location _ | Operation _ | Str _ | Type_expression _ | Unit _ | Var _ | Z _ | List _ | Location_wrap _ | CMap _ | LMap _ | UnionFind _ | Set _ | TypeVariableMap _) as a),
((EmptyCtor | Record _ | VariantConstructor _ | Bool _ | Bytes _ | Constructor' _ | Expression_variable _ | Int _ | Label' _ | Ligo_string _ | Location _ | Operation _ | Str _ | Type_expression _ | Unit _ | Var _ | Z _ | List _ | Location_wrap _ | CMap _ | LMap _ | UnionFind _ | Set _ | TypeVariableMap _) as b) ->
Int.compare (tag a) (tag b)
let mk_compare : (t fold_config -> t -> 'a -> t) -> 'a -> 'a -> int = fun fold a b ->
let mk_compare : ((no_state , t) fold_config -> no_state -> 'a -> t) -> 'a -> 'a -> int = fun fold a b ->
compare_t (serialize fold a) (serialize fold b)
let mk_comparable : (t fold_config -> t -> 'a -> t) -> 'a extra_info__comparable = fun fold ->
let mk_comparable : ((no_state , t) fold_config -> no_state -> 'a -> t) -> 'a extra_info__comparable = fun fold ->
{ compare = mk_compare fold }
end
(* Generate a comparison function for each type, named like the type itself. *)
include Folds(struct
type state = M.t ;;
type in_state = M.no_state ;;
type out_state = M.t ;;
type 'a t = 'a -> 'a -> int ;;
let f = M.mk_compare ;;
end)
@ -180,7 +188,8 @@ end)
module Comparable = struct
(* Generate a comparator typeclass-like object for each type, named like the type itself. *)
include Folds(struct
type state = M.t ;;
type in_state = M.no_state ;;
type out_state = M.t ;;
type 'a t = 'a extra_info__comparable ;;
let f = M.mk_comparable ;;
end)

View File

@ -96,29 +96,30 @@ $*OUT = open $folder_filename, :w;
say "";
say " include Adt_generator.Generic.BlahBluh";
say " type ('state , 'adt_info_node_instance_info) _fold_config = \{";
say " generic : 'state -> 'adt_info_node_instance_info -> 'state;";
say " type ('in_state, 'out_state , 'adt_info_node_instance_info) _fold_config = \{";
say " generic : 'in_state -> 'adt_info_node_instance_info -> 'out_state;";
say " generic_empty_ctor : 'in_state -> 'out_state;";
# look for builtins, filtering out the "implicit unit-like fake argument of emtpy constructors" (represented by '')
for $adts.map({ $_<ctorsOrFields> })[*;*].grep({$_<isBuiltin> && $_<type> ne ''}).map({$_<type>}).unique -> $builtin
{ say " $builtin : ('state , 'adt_info_node_instance_info) _fold_config -> 'state -> $builtin -> 'state;"; }
{ say " $builtin : ('in_state , 'out_state , 'adt_info_node_instance_info) _fold_config -> 'in_state -> $builtin -> 'out_state;"; }
# look for built-in polymorphic types
for $adts.grep({$_<kind> ne $record && $_<kind> ne $variant}).map({$_<kind>}).unique -> $poly
{ say " $poly : 'a . ('state , 'adt_info_node_instance_info) _fold_config -> ('state -> 'a -> 'state) -> 'state -> 'a $poly -> 'state;"; }
{ say " $poly : 'a . ('in_state , 'out_state , 'adt_info_node_instance_info) _fold_config -> ('in_state -> 'a -> 'out_state) -> 'in_state -> 'a $poly -> 'out_state;"; }
say ' };;';
say "";
say " module Adt_info = Adt_generator.Generic.Adt_info (struct";
say " type nonrec ('state , 'adt_info_node_instance_info) fold_config = ('state , 'adt_info_node_instance_info) _fold_config;;";
say " type nonrec ('in_state , 'out_state , 'adt_info_node_instance_info) fold_config = ('in_state , 'out_state , 'adt_info_node_instance_info) _fold_config;;";
say " end);;";
say " include Adt_info;;";
say " type 'state fold_config = ('state , 'state Adt_info.node_instance_info) _fold_config;;";
say " type ('in_state, 'out_state) fold_config = ('in_state , 'out_state , ('in_state , 'out_state) Adt_info.node_instance_info) _fold_config;;";
say "";
say ' type the_folds = {';
for $adts.list -> $t
{ say " fold__$t<name> : 'state . the_folds -> 'state fold_config -> 'state -> $t<name> -> 'state;";
{ say " fold__$t<name> : 'in_state 'out_state . the_folds -> ('in_state , 'out_state) fold_config -> 'in_state -> $t<name> -> 'out_state;";
for $t<ctorsOrFields>.list -> $c
{ say " fold__$t<name>__$c<name> : 'state . the_folds -> 'state fold_config -> 'state -> { $c<type> || 'unit' } -> 'state;"; } }
{ say " fold__$t<name>__$c<name> : 'in_state 'out_state . the_folds -> ('in_state , 'out_state) fold_config -> 'in_state -> { $c<type> || 'unit' } -> 'out_state;"; } }
say ' };;';
# generic programming info about the nodes and fields
@ -132,7 +133,7 @@ $*OUT = open $folder_filename, :w;
say " type_ = \"$c<type>\";";
say ' };;';
# say "";
say " let continue_info__$t<name>__$c<name> : type qstate . the_folds -> qstate fold_config -> {$c<type> || 'unit'} -> qstate Adt_info.ctor_or_field_instance = fun the_folds visitor x -> \{";
say " let continue_info__$t<name>__$c<name> : type in_qstate out_qstate . the_folds -> (in_qstate , out_qstate) fold_config -> {$c<type> || 'unit'} -> (in_qstate, out_qstate) Adt_info.ctor_or_field_instance = fun the_folds visitor x -> \{";
say " cf = info__$t<name>__$c<name>;";
say " cf_continue = (fun state -> the_folds.fold__$t<name>__$c<name> the_folds visitor state x);";
say " cf_new_fold = (fun visitor state -> the_folds.fold__$t<name>__$c<name> the_folds visitor state x);";
@ -154,7 +155,7 @@ $*OUT = open $folder_filename, :w;
say ' };;';
# say "";
# TODO: factor out some of the common bits here.
say " let continue_info__$t<name> : type qstate . the_folds -> qstate fold_config -> $t<name> -> qstate Adt_info.instance = fun the_folds visitor x ->";
say " let continue_info__$t<name> : type in_qstate out_qstate . the_folds -> (in_qstate , out_qstate) fold_config -> $t<name> -> (in_qstate , out_qstate) Adt_info.instance = fun the_folds visitor x ->";
say ' {';
say " instance_declaration_name = \"$t<name>\";";
do given $t<kind> {
@ -208,9 +209,9 @@ $*OUT = open $folder_filename, :w;
# fold functions
say "";
for $adts.list -> $t
{ say " let fold__$t<name> : type qstate . the_folds -> qstate fold_config -> qstate -> $t<name> -> qstate = fun the_folds visitor state x ->";
{ say " let fold__$t<name> : type in_qstate out_qstate . the_folds -> (in_qstate , out_qstate) fold_config -> in_qstate -> $t<name> -> out_qstate = fun the_folds visitor state x ->";
# TODO: add a non-generic continue_fold.
say ' let node_instance_info : qstate Adt_info.node_instance_info = {';
say ' let node_instance_info : (in_qstate , out_qstate) Adt_info.node_instance_info = {';
say " adt = whole_adt_info () ;";
say " node_instance = continue_info__$t<name> the_folds visitor x";
say ' } in';
@ -218,11 +219,11 @@ $*OUT = open $folder_filename, :w;
say " visitor.generic state node_instance_info;;";
# say "";
for $t<ctorsOrFields>.list -> $c
{ say " let fold__$t<name>__$c<name> : type qstate . the_folds -> qstate fold_config -> qstate -> { $c<type> || 'unit' } -> qstate = fun the_folds { $c<type> ?? 'visitor' !! '_visitor' } state { $c<type> ?? 'x' !! '()' } ->";
# say " let ctor_or_field_instance_info : qstate Adt_info.ctor_or_field_instance_info = whole_adt_info (), info__$t<name>, continue_info__$t<name>__$c<name> visitor x in";
{ say " let fold__$t<name>__$c<name> : type in_qstate out_qstate . the_folds -> (in_qstate , out_qstate) fold_config -> in_qstate -> { $c<type> || 'unit' } -> out_qstate = fun the_folds visitor state { $c<type> ?? 'x' !! '()' } ->";
# say " let ctor_or_field_instance_info : (in_qstate , out_qstate) Adt_info.ctor_or_field_instance_info = whole_adt_info (), info__$t<name>, continue_info__$t<name>__$c<name> visitor x in";
if ($c<type> eq '') {
# nothing to do, this constructor has no arguments.
say " ignore the_folds; state;;";
say " ignore the_folds; visitor.generic_empty_ctor state;;";
} elsif ($c<isBuiltin>) {
say " ignore the_folds; visitor.$c<type> visitor state x;;"; # (*visitor.generic_ctor_or_field ctor_or_field_instance_info*)
} else {
@ -234,7 +235,7 @@ $*OUT = open $folder_filename, :w;
}
# look for builtins, filtering out the "implicit unit-like fake argument of emtpy constructors" (represented by '')
for $adts.map({ $_<ctorsOrFields> })[*;*].grep({$_<isBuiltin> && $_<type> ne ''}).map({$_<type>}).unique -> $builtin
{ say " let fold__$builtin : type qstate . the_folds -> qstate fold_config -> qstate -> $builtin -> qstate = fun the_folds visitor state x ->";
{ say " let fold__$builtin : type in_qstate out_qstate . the_folds -> (in_qstate , out_qstate) fold_config -> in_qstate -> $builtin -> out_qstate = fun the_folds visitor state x ->";
say " ignore the_folds; visitor.$builtin visitor state x;;"; } # (*visitor.generic_ctor_or_field ctor_or_field_instance_info*)
say "";
@ -248,15 +249,15 @@ $*OUT = open $folder_filename, :w;
# Tying the knot
say "";
for $adts.list -> $t
{ say " let fold__$t<name> : type qstate . qstate fold_config -> qstate -> $t<name> -> qstate = fun visitor state x -> fold__$t<name> the_folds visitor state x;;";
{ say " let fold__$t<name> : type in_qstate out_qstate . (in_qstate , out_qstate) fold_config -> in_qstate -> $t<name> -> out_qstate = fun visitor state x -> fold__$t<name> the_folds visitor state x;;";
for $t<ctorsOrFields>.list -> $c
{ say " let fold__$t<name>__$c<name> : type qstate . qstate fold_config -> qstate -> { $c<type> || 'unit' } -> qstate = fun visitor state x -> fold__$t<name>__$c<name> the_folds visitor state x;;" } }
{ say " let fold__$t<name>__$c<name> : type in_qstate out_qstate . (in_qstate , out_qstate) fold_config -> in_qstate -> { $c<type> || 'unit' } -> out_qstate = fun visitor state x -> fold__$t<name>__$c<name> the_folds visitor state x;;" } }
# look for builtins, filtering out the "implicit unit-like fake argument of emtpy constructors" (represented by '')
for $adts.map({ $_<ctorsOrFields> })[*;*].grep({$_<isBuiltin> && $_<type> ne ''}).map({$_<type>}).unique -> $builtin
{ say " let fold__$builtin : type qstate . qstate fold_config -> qstate -> $builtin -> qstate = fun visitor state x -> fold__$builtin the_folds visitor state x;;"; }
{ say " let fold__$builtin : type in_qstate out_qstate . (in_qstate , out_qstate) fold_config -> in_qstate -> $builtin -> out_qstate = fun visitor state x -> fold__$builtin the_folds visitor state x;;"; }
say "";
say " module Folds (M : sig type state type 'a t val f : (state fold_config -> state -> 'a -> state) -> 'a t end) = struct";
say " module Folds (M : sig type in_state type out_state type 'a t val f : ((in_state , out_state) fold_config -> in_state -> 'a -> out_state) -> 'a t end) = struct";
for $adts.list -> $t
{ say " let $t<name> = M.f fold__$t<name>;;"; }
# look for builtins, filtering out the "implicit unit-like fake argument of emtpy constructors" (represented by '')

View File

@ -10,35 +10,35 @@ module BlahBluh = struct
type 'state generic_continue_fold = ('state generic_continue_fold_node) StringMap.t;;
end
module Adt_info (M : sig type ('state , 'adt_info_node_instance_info) fold_config end) = struct
module Adt_info (M : sig type ('in_state , 'out_state , 'adt_info_node_instance_info) fold_config end) = struct
type kind =
| Record
| Variant
| Poly of string
type 'state record_instance = {
fields : 'state ctor_or_field_instance list;
type ('in_state , 'out_state) record_instance = {
fields : ('in_state , 'out_state) ctor_or_field_instance list;
}
and 'state constructor_instance = {
constructor : 'state ctor_or_field_instance ;
and ('in_state , 'out_state) constructor_instance = {
constructor : ('in_state , 'out_state) ctor_or_field_instance ;
variant : ctor_or_field list
}
and 'state poly_instance = {
and ('in_state , 'out_state) poly_instance = {
poly : string;
arguments : string list;
poly_continue : 'state -> 'state
poly_continue : 'in_state -> 'out_state
}
and 'state kind_instance =
| RecordInstance of 'state record_instance
| VariantInstance of 'state constructor_instance
| PolyInstance of 'state poly_instance
and ('in_state , 'out_state) kind_instance =
| RecordInstance of ('in_state , 'out_state) record_instance
| VariantInstance of ('in_state , 'out_state) constructor_instance
| PolyInstance of ('in_state , 'out_state) poly_instance
and 'state instance = {
and ('in_state , 'out_state) instance = {
instance_declaration_name : string;
instance_kind : 'state kind_instance;
instance_kind : ('in_state , 'out_state) kind_instance;
}
and ctor_or_field =
@ -48,11 +48,11 @@ module Adt_info (M : sig type ('state , 'adt_info_node_instance_info) fold_confi
type_ : string;
}
and 'state ctor_or_field_instance =
and ('in_state , 'out_state) ctor_or_field_instance =
{
cf : ctor_or_field;
cf_continue : 'state -> 'state;
cf_new_fold : 'state . ('state, ('state node_instance_info)) M.fold_config -> 'state -> 'state;
cf_continue : 'in_state -> 'out_state;
cf_new_fold : 'in_state 'out_state . ('in_state , 'out_state , (('in_state , 'out_state) node_instance_info)) M.fold_config -> 'in_state -> 'out_state;
}
and node =
@ -64,9 +64,9 @@ module Adt_info (M : sig type ('state , 'adt_info_node_instance_info) fold_confi
(* TODO: rename things a bit in this file. *)
and adt = node list
and 'state node_instance_info = {
and ('in_state , 'out_state) node_instance_info = {
adt : adt ;
node_instance : 'state instance ;
node_instance : ('in_state , 'out_state) instance ;
}
and 'state ctor_or_field_instance_info = adt * node * 'state ctor_or_field_instance
and ('in_state , 'out_state) ctor_or_field_instance_info = adt * node * ('in_state , 'out_state) ctor_or_field_instance
end

View File

@ -63,35 +63,33 @@ let () =
let _noi : (int, [> error]) fold_map_config__Amodule = no_op (* (fun _ -> ()) *)
let _nob : (bool, [> error]) fold_map_config__Amodule = no_op (* (fun _ -> ()) *)
type no_state = NoState
let () =
let some_root : root = A [ { a1 = X (A [ { a1 = X (B [ 1 ; 2 ; 3 ]) ; a2 = W () } ]) ; a2 = Z (W ()) } ] in
let assert_nostate (needs_parens, state) = assert (not needs_parens && String.equal state "") in
let nostate = false, "" in
let op = {
generic = (fun state info ->
assert_nostate state;
let op : ('i, 'o) Generated_fold.fold_config = {
generic = (fun NoState info ->
match info.node_instance.instance_kind with
| RecordInstance { fields } ->
false, "{ " ^ String.concat " ; " (List.map (fun (fld : 'x Adt_info.ctor_or_field_instance) -> fld.cf.name ^ " = " ^ snd (fld.cf_continue nostate)) fields) ^ " }"
false, "{ " ^ String.concat " ; " (List.map (fun (fld : ('xi , 'xo) Adt_info.ctor_or_field_instance) -> fld.cf.name ^ " = " ^ snd (fld.cf_continue NoState)) fields) ^ " }"
| VariantInstance { constructor={ cf = { name; is_builtin=_; type_=_ }; cf_continue; cf_new_fold=_ }; variant=_ } ->
(match cf_continue nostate with
(match cf_continue NoState with
| true, arg -> true, name ^ " (" ^ arg ^ ")"
| false, arg -> true, name ^ " " ^ arg)
| PolyInstance { poly=_; arguments=_; poly_continue } ->
(poly_continue nostate)
(poly_continue NoState)
) ;
string = (fun _visitor state str -> assert_nostate state; false , "\"" ^ str ^ "\"") ;
unit = (fun _visitor state () -> assert_nostate state; false , "()") ;
int = (fun _visitor state i -> assert_nostate state; false , string_of_int i) ;
list = (fun _visitor continue state lst ->
assert_nostate state;
false , "[ " ^ String.concat " ; " (List.map snd @@ List.map (continue nostate) lst) ^ " ]") ;
generic_empty_ctor = (fun NoState -> false, "") ;
string = (fun _visitor NoState str -> false , "\"" ^ str ^ "\"") ;
unit = (fun _visitor NoState () -> false , "()") ;
int = (fun _visitor NoState i -> false , string_of_int i) ;
list = (fun _visitor continue NoState lst ->
false , "[ " ^ String.concat " ; " (List.map snd @@ List.map (continue NoState) lst) ^ " ]") ;
(* generic_ctor_or_field = (fun _info state ->
* match _info () with
* (_, _, { name=_; isBuiltin=_; type_=_; continue }) -> state ^ "ctor_or_field [" ^ (continue "") ^ "]"
* ); *)
} in
let (_ , state) = fold__root op nostate some_root in
let (_ , state) = Generated_fold.fold__root op NoState some_root in
let expected = "A [ { a1 = X (A [ { a1 = X (B [ 1 ; 2 ; 3 ]) ; a2 = W () } ]) ; a2 = Z (W ()) } ]" in
if String.equal state expected; then
()