ADT generator: Parser for OCaml ADTs, WIP on adding info

This commit is contained in:
Suzanne Dupéron 2020-03-03 22:02:55 +01:00
parent e92ba202cf
commit 20a51381bc
6 changed files with 171 additions and 90 deletions

View File

@ -1,2 +1,2 @@
module A = A module Amodule = Amodule
module Use_a_fold = Use_a_fold module Use_a_fold = Use_a_fold

View File

@ -0,0 +1,21 @@
type root =
| A of rootA
| B of rootB
| C of string
and a = {
a1 : ta1 ;
a2 : ta2 ;
}
and ta1 =
| X of root
| Y of ta2
and ta2 =
| Z of ta2
| W of unit
and rootA = a list
and rootB = int list

View File

@ -1,27 +1,3 @@
type root =
| A of rootA
| B of rootB
| C of string
and a = {
a1 : ta1 ;
a2 : ta2 ;
}
and ta1 =
| X of root
| Y of ta2
and ta2 =
| Z of ta2
| W of unit
and rootA =
a list
and rootB =
int list
let fold_list v state continue = let fold_list v state continue =
let aux = fun (lst', state) elt -> let aux = fun (lst', state) elt ->
let (elt', state) = continue elt state in let (elt', state) = continue elt state in

View File

@ -1,13 +1,7 @@
(rule
(target generator_fstrings.py)
(deps generator.py)
(action (with-stdout-to generator_fstrings.py (run sh -c "if python3 -c 'f\"\"' 2>/dev/null; then :; else echo '# -*- coding: future_fstrings -*-'; fi; cat generator.py")))
)
(rule (rule
(target generated_fold.ml) (target generated_fold.ml)
(deps generator_fstrings.py) (deps generator.raku)
(action (with-stdout-to generated_fold.ml (run python3 ./generator_fstrings.py))) (action (with-stdout-to generated_fold.ml (run perl6 ./generator.raku amodule.ml)))
(mode (promote (until-clean))) (mode (promote (until-clean)))
) )
; (library ; (library

View File

@ -4,56 +4,116 @@ use v6;
use v6.c; use v6.c;
use worries; use worries;
my $moduleName = @*ARGS[0].subst(/\.ml$/, '').samecase("A_");
my $moduleName = "A";
my $variant = "_ _variant"; my $variant = "_ _variant";
my $record = "_ _ record"; my $record = "_ _ record";
sub poly { $^type_name } sub poly { $^type_name }
my @adts_raw = [
# typename, kind, fields_or_ctors my $l = @*ARGS[0].IO.lines;
["root", $variant, [ $l = $l.map(*.subst: /^\s+/, "");
# ctor, builtin?, type $l = $l.cache.map(*.subst: /^type\s+/, "\nand ");
["A", False, "rootA"], $l = $l.join("\n").split(/\nand\s+/).grep(/./);
["B", False, "rootB"], $l = $l.map(*.split("\n"));
["C", True, "string"], $l = $l.map: {
]], my $ll = $_;
["a", $record, [ my ($name, $kind) = do given $_[0] {
# field, builtin?, type when /^(\w+)\s*\=$/ { "$/[0]", $variant }
["a1", False, "ta1"], when /^(\w+)\s*\=\s*\{$/ { "$/[0]", $record }
["a2", False, "ta2"], when /^(\w+)\s*\=\s*(\w+)\s+(\w+)$/ { "$/[0]", poly("$/[2]") }
]], default { die "Syntax error when parsing header:" ~ $ll.perl ~ "\n$_" }
["ta1", $variant, [ };
["X", False, "root"], my $ctorsOrFields = do {
["Y", False, "ta2"], when (/^(\w+)\s*\=\s*(\w+)\s+(\w+)$/ given $_[0]) { ((0, "$/[1]"),).Seq; }
]], default {
["ta2", $variant, [ $_[1..*].grep({ ! /^\}?$/ }).map: {
["Z", False, "ta2"], when /^\|\s*(\w+)\s*of\s+((\'|\w)+)$/ { "$/[0]", "$/[1]" }
["W", True, "unit"], when /^(\w+)\s*\:\s*((\'|\w)+)\s*\;$/ { "$/[0]", "$/[1]" }
]], default { die "Syntax error when parsing body:" ~ $ll.perl ~ "\n$_" }
# polymorphic type }
["rootA", poly("list"), };
[ }
# Position (0..n-1), builtin?, type argument %{
[0, False, "a"], "name" => $name ,
], "kind" => $kind ,
], "ctorsOrFields" => $ctorsOrFields
["rootB", poly("list"), }
[ # $_[0].subst: , '' }
# Position (0..n-1), builtin?, type argument };
[0, True, "int"], # $l.perl.say;
], # exit;
],
]; # ($cf, $isBuiltin, $type)
# {
# name => $cf ,
# newName => "$cf'" ,
# isBuiltin => $isBuiltin ,
# type => $type ,
# newType => $isBuiltin ?? $type !! "$type'"
# }
# say $adts_raw.perl; # my @adts_raw = [
my $adts = (map -> ($name , $kind, @ctorsOrFields) { # # typename, kind, fields_or_ctors
# ["root", $variant, [
# # ctor, builtin?, type
# ["A", False, "rootA"],
# ["B", False, "rootB"],
# ["C", True, "string"],
# ]],
# ["a", $record, [
# # field, builtin?, type
# ["a1", False, "ta1"],
# ["a2", False, "ta2"],
# ]],
# ["ta1", $variant, [
# ["X", False, "root"],
# ["Y", False, "ta2"],
# ]],
# ["ta2", $variant, [
# ["Z", False, "ta2"],
# ["W", True, "unit"],
# ]],
# # polymorphic type
# ["rootA", poly("list"),
# [
# # Position (0..n-1), builtin?, type argument
# [0, False, "a"],
# ],
# ],
# ["rootB", poly("list"),
# [
# # Position (0..n-1), builtin?, type argument
# [0, True, "int"],
# ],
# ],
# ];
# # say $adts_raw.perl;
# my $adts = (map -> ($name , $kind, @ctorsOrFields) {
# {
# "name" => $name ,
# "newName" => "$name'" ,
# "kind" => $kind ,
# "ctorsOrFields" => @(map -> ($cf, $isBuiltin, $type) {
# {
# name => $cf ,
# newName => "$cf'" ,
# isBuiltin => $isBuiltin ,
# type => $type ,
# newType => $isBuiltin ?? $type !! "$type'"
# }
# }, @ctorsOrFields),
# }
# }, @adts_raw).list;
my $adts = (map -> (:$name , :$kind, :@ctorsOrFields) {
{ {
"name" => $name , "name" => $name ,
"newName" => "$name'" , "newName" => "$name'" ,
"kind" => $kind , "kind" => $kind ,
"ctorsOrFields" => @(map -> ($cf, $isBuiltin, $type) { "ctorsOrFields" => @(map -> ($cf, $type) {
my $isBuiltin = ! $l.cache.first({ $_<name> eq $type });
{ {
name => $cf , name => $cf ,
newName => "$cf'" , newName => "$cf'" ,
@ -63,7 +123,9 @@ my $adts = (map -> ($name , $kind, @ctorsOrFields) {
} }
}, @ctorsOrFields), }, @ctorsOrFields),
} }
}, @adts_raw).list; }, @$l.cache).list;
# say $adts.perl;
# say $adts.perl ; # say $adts.perl ;
@ -71,6 +133,7 @@ say "(* This is an auto-generated file. Do not edit. *)";
say ""; say "";
say "open $moduleName"; say "open $moduleName";
say "open {$moduleName}_utils";
say ""; say "";
for $adts.kv -> $index, $t { for $adts.kv -> $index, $t {
@ -93,6 +156,33 @@ for $adts.kv -> $index, $t {
} }
} }
say "";
say "module Adt_info = struct";
say " type kind =";
say " | Record";
say " | Variant";
say " | Poly of string";
say "";
say " type ctor_or_field =";
say ' {';
say " name : string;";
say " isBuiltin : bool;";
say " type_ : string;";
say ' }';
say "";
say " type node =";
say ' {';
say " kind : kind;";
say " name : string;";
say " ctors_or_fields : ctor_or_field list;";
say ' }';
say "";
say " type adt = node list";
say " type node_info = unit -> adt * node";
say " type ctor_or_field_info = unit -> adt * node";
say "end";
say ""; say "";
say "type 'state continue_fold ="; say "type 'state continue_fold =";
say ' {'; say ' {';
@ -106,11 +196,11 @@ say "";
say "type 'state fold_config ="; say "type 'state fold_config =";
say ' {'; say ' {';
for $adts.list -> $t for $adts.list -> $t
{ say " $t<name> : $t<name> -> 'state -> ('state continue_fold) -> ($t<newName> * 'state) ;"; { say " $t<name> : $t<name> -> Adt_info.node_info -> 'state -> ('state continue_fold) -> ($t<newName> * 'state) ;";
say " $t<name>_pre_state : $t<name> -> 'state -> 'state ;"; say " $t<name>_pre_state : $t<name> -> Adt_info.node_info -> 'state -> 'state ;";
say " $t<name>_post_state : $t<name> -> $t<newName> -> 'state -> 'state ;"; say " $t<name>_post_state : $t<name> -> $t<newName> -> Adt_info.node_info -> 'state -> 'state ;";
for $t<ctorsOrFields>.list -> $c for $t<ctorsOrFields>.list -> $c
{ say " $t<name>_$c<name> : $c<type> -> 'state -> ('state continue_fold) -> ($c<newType> * 'state) ;"; { say " $t<name>_$c<name> : $c<type> -> Adt_info.ctor_or_field_info -> 'state -> ('state continue_fold) -> ($c<newType> * 'state) ;";
} } } }
say ' }'; say ' }';
@ -128,20 +218,20 @@ say "";
for $adts.list -> $t for $adts.list -> $t
{ say "and fold_$t<name> : type state . state fold_config -> $t<name> -> state -> ($t<newName> * state) = fun visitor x state ->"; { say "and fold_$t<name> : type state . state fold_config -> $t<name> -> state -> ($t<newName> * state) = fun visitor x state ->";
say " let continue_fold : state continue_fold = mk_continue_fold visitor in"; say " let continue_fold : state continue_fold = mk_continue_fold visitor in";
say " let state = visitor.$t<name>_pre_state x state in"; say " let state = visitor.$t<name>_pre_state x (fun () -> failwith \"todo\") state in";
say " let (new_x, state) = visitor.$t<name> x state continue_fold in"; say " let (new_x, state) = visitor.$t<name> x (fun () -> failwith \"todo\") state continue_fold in";
say " let state = visitor.$t<name>_post_state x new_x state in"; say " let state = visitor.$t<name>_post_state x new_x (fun () -> failwith \"todo\") state in";
say " (new_x, state)"; say " (new_x, state)";
say ""; say "";
for $t<ctorsOrFields>.list -> $c for $t<ctorsOrFields>.list -> $c
{ say "and fold_$t<name>_$c<name> : type state . state fold_config -> $c<type> -> state -> ($c<newType> * state) = fun visitor x state ->"; { say "and fold_$t<name>_$c<name> : type state . state fold_config -> $c<type> -> state -> ($c<newType> * state) = fun visitor x state ->";
say " let continue_fold : state continue_fold = mk_continue_fold visitor in"; say " let continue_fold : state continue_fold = mk_continue_fold visitor in";
say " visitor.$t<name>_$c<name> x state continue_fold"; say " visitor.$t<name>_$c<name> x (fun () -> failwith \"todo\") state continue_fold";
say ""; } } say ""; } }
say "let no_op : 'a fold_config = \{"; say "let no_op : 'a fold_config = \{";
for $adts.list -> $t for $adts.list -> $t
{ say " $t<name> = (fun v state continue ->"; { say " $t<name> = (fun v _info state continue ->";
say " match v with"; say " match v with";
if ($t<kind> eq $variant) { if ($t<kind> eq $variant) {
for $t<ctorsOrFields>.list -> $c for $t<ctorsOrFields>.list -> $c
@ -163,10 +253,10 @@ for $adts.list -> $t
say " )"; say " )";
} }
say " );"; say " );";
say " $t<name>_pre_state = (fun v state -> ignore v; state) ;"; say " $t<name>_pre_state = (fun v _info state -> ignore v; state) ;";
say " $t<name>_post_state = (fun v new_v state -> ignore (v, new_v); state) ;"; say " $t<name>_post_state = (fun v new_v _info state -> ignore (v, new_v); state) ;";
for $t<ctorsOrFields>.list -> $c for $t<ctorsOrFields>.list -> $c
{ print " $t<name>_$c<name> = (fun v state continue -> "; { print " $t<name>_$c<name> = (fun v _info state continue -> ";
if ($c<isBuiltin>) { if ($c<isBuiltin>) {
print "ignore continue; (v, state)"; print "ignore continue; (v, state)";
} else { } else {

View File

@ -1,4 +1,4 @@
open A open Amodule
open Fold open Fold
(* TODO: how should we plug these into our test framework? *) (* TODO: how should we plug these into our test framework? *)
@ -7,7 +7,7 @@ let () =
let some_root : root = A [{ a1 = X (A [{ a1 = X (B [1;2;3]) ; a2 = W () ; }]) ; a2 = Z (W ()) ; }] in let some_root : root = A [{ a1 = X (A [{ a1 = X (B [1;2;3]) ; a2 = W () ; }]) ; a2 = Z (W ()) ; }] in
let op = { let op = {
no_op with no_op with
a = fun the_a state continue_fold -> a = fun the_a _info state continue_fold ->
let (a1' , state') = continue_fold.ta1 the_a.a1 state in let (a1' , state') = continue_fold.ta1 the_a.a1 state in
let (a2' , state'') = continue_fold.ta2 the_a.a2 state' in let (a2' , state'') = continue_fold.ta2 the_a.a2 state' in
({ ({
@ -24,7 +24,7 @@ let () =
let () = let () =
let some_root : root = A [{ a1 = X (A [{ a1 = X (B [1;2;3]) ; a2 = W () ; }]) ; a2 = Z (W ()) ; }] in let some_root : root = A [{ a1 = X (A [{ a1 = X (B [1;2;3]) ; a2 = W () ; }]) ; a2 = Z (W ()) ; }] in
let op = { no_op with a_pre_state = fun _the_a state -> state + 1 } in let op = { no_op with a_pre_state = fun _the_a _info state -> state + 1 } in
let state = 0 in let state = 0 in
let (_, state) = fold_root op some_root state in let (_, state) = fold_root op some_root state in
if state != 2 then if state != 2 then
@ -34,7 +34,7 @@ let () =
let () = let () =
let some_root : root = A [{ a1 = X (A [{ a1 = X (B [1;2;3]) ; a2 = W () ; }]) ; a2 = Z (W ()) ; }] in let some_root : root = A [{ a1 = X (A [{ a1 = X (B [1;2;3]) ; a2 = W () ; }]) ; a2 = Z (W ()) ; }] in
let op = { no_op with a_post_state = fun _the_a _new_a state -> state + 1 } in let op = { no_op with a_post_state = fun _the_a _new_a _info state -> state + 1 } in
let state = 0 in let state = 0 in
let (_, state) = fold_root op some_root state in let (_, state) = fold_root op some_root state in
if state != 2 then if state != 2 then