This commit is contained in:
swrup 2025-11-11 02:07:51 +01:00
parent aa2ff7b2f0
commit 2f3113f55d
11742 changed files with 1223940 additions and 0 deletions

View file

@ -0,0 +1,3 @@
(cram
(package ppxlib)
(deps ../../dev/gencopy/gencopy.exe))

View file

@ -0,0 +1,123 @@
gencopy is a dev utility tool that we use to generate migration functions
skeletons when adding support for new compiler versions.
We can run it on two empty .ml files:
$ touch in.ml
$ touch out.ml
$ ../../dev/gencopy/gencopy.exe in.ml out.ml
open Stdlib0
let copy_location x = x
It then simply generates the headers which are a global open to stdlib0 and a
default copy function for location that one could overwrite if needed.
================= Simple types =================
We can test it on a pair of simple types, note that all types are expected to be
defined in submodules and not at the root as the ast_X.ml files are laid out that
way:
$ cat > in.ml << EOF
> module X = struct
> type r = {a: int; b: string}
> end
>
> module Y = struct
> type s = A of int | B of string
> end
> EOF
$ ../../dev/gencopy/gencopy.exe in.ml out.ml
open Stdlib0
let copy_location x = x
let rec copy_r : In.X.r -> Out.X.r =
fun { In.X.a = a; In.X.b = b } -> { Out.X.a = a; Out.X.b = b }
and copy_s : In.Y.s -> Out.Y.s =
function | In.Y.A x0 -> Out.Y.A x0 | In.Y.B x0 -> Out.Y.B x0
Note that it just copies the base types (string, int, etc...) directly and does
not expect a copy_string function.
================= Recursive types ===============
Recursive types should be handled properly:
$ cat > in.ml << EOF
> module X = struct
> type a = b list
> and b = A of a | B
> end
> EOF
$ ../../dev/gencopy/gencopy.exe in.ml out.ml
open Stdlib0
let copy_location x = x
let rec copy_a : In.X.a -> Out.X.a = fun x -> List.map copy_b x
and copy_b : In.X.b -> Out.X.b =
function | In.X.A x0 -> Out.X.A (copy_a x0) | In.X.B -> Out.X.B
Any type it encounters a non base type, it assumes that a copy_ function
for this type will be defined. If the type is defined in the input file, it
should generate it itself, otherwise it will have to be added manually.
================= Parametrized types ===============
A copy_function for a parametrized type should be polymorphic and take
one extra argument per type parameter. It should also properly pass that
argument when copying instances of a parametrized type.
$ cat > in.ml << EOF
> module X = struct
> type 'a loc = { loc: location; txt: 'a }
> and u = A | B
> and v = { u : u loc; flags : int }
> end
> EOF
$ ../../dev/gencopy/gencopy.exe in.ml out.ml
open Stdlib0
let copy_location x = x
let rec copy_loc : 'f0 'g0 . ('f0 -> 'g0) -> 'f0 In.X.loc -> 'g0 Out.X.loc =
fun f0 { In.X.loc = loc; In.X.txt = txt } ->
{ Out.X.loc = (copy_location loc); Out.X.txt = (f0 txt) }
and copy_u : In.X.u -> Out.X.u =
function | In.X.A -> Out.X.A | In.X.B -> Out.X.B
and copy_v : In.X.v -> Out.X.v =
fun { In.X.u = u; In.X.flags = flags } ->
{ Out.X.u = (copy_loc copy_u u); Out.X.flags = flags }
=================== Inline records =================
Inline record fields should not be qualified (e.g. Modname.fiel_name) as this
would trigger a compile error. gencopy should properly handle this:
$ cat > in.ml << EOF
> module X = struct
> type x =
> | A of {i: int; s: string}
> end
> EOF
$ ../../dev/gencopy/gencopy.exe in.ml out.ml
open Stdlib0
let copy_location x = x
let rec copy_x : In.X.x -> Out.X.x =
function | In.X.A { i; s } -> Out.X.A { i; s }
====================== X.t as x ====================
For convenience, gencopy the copy function for X.t as copy_x:
$ cat > in.ml << EOF
> module X = struct
> type t = int
> end
> EOF
$ ../../dev/gencopy/gencopy.exe in.ml out.ml
open Stdlib0
let copy_location x = x
let rec copy_x : In.X.t -> Out.X.t = fun x -> x