3
module Variant_and_record_intf = Variant_and_record_intf
5
module Helper (A : Variant_and_record_intf.S) (B : Variant_and_record_intf.S) = struct
7
type map = { map : 'a. 'a A.t -> 'a B.t }
9
let map_variant (type variant) { map } (variant : variant A.Variant.t) =
10
let map_create = function
11
| A.Tag.Args fct -> B.Tag_internal.Args fct
12
| A.Tag.Const k -> B.Tag_internal.Const k
16
| A.Variant.Tag tag ->
17
let label = A.Tag.label tag in
18
let rep = map (A.Tag.traverse tag) in
19
let arity = A.Tag.arity tag in
20
let index = A.Tag.index tag in
21
let ocaml_repr = A.Tag.ocaml_repr tag in
22
let tyid = A.Tag.tyid tag in
23
let create = map_create (A.Tag.create tag) in
24
B.Variant_internal.Tag (B.Tag.internal_use_only {
25
B.Tag_internal.label; rep; arity; index; ocaml_repr; tyid; create;
28
let typename = A.Variant.typename_of_t variant in
29
let polymorphic = A.Variant.is_polymorphic variant in
30
let tags = Array.init (A.Variant.length variant)
31
(fun index -> map_tag (A.Variant.tag variant index))
33
let value (a : variant) =
34
match A.Variant.value variant a with
35
| A.Variant.Value (atag, a) ->
36
(fun (type args) (atag : (variant, args) A.Tag.t) (a : args) ->
37
let (B.Variant_internal.Tag btag) = tags.(A.Tag.index atag) in
38
(fun (type ex) (btag : (variant, ex) B.Tag.t) ->
40
Typename.same_witness_exn (A.Tag.tyid atag) (B.Tag.tyid btag)
42
let btag = (btag : (variant, args) B.Tag.t) in
43
B.Variant_internal.Value (btag, a)
47
B.Variant.internal_use_only {
48
B.Variant_internal.typename; tags; polymorphic; value;
51
let map_record (type record) { map } (record : record A.Record.t) =
54
| A.Record.Field field ->
55
let label = A.Field.label field in
56
let rep = map (A.Field.traverse field) in
57
let index = A.Field.index field in
58
let tyid = A.Field.tyid field in
59
let get = A.Field.get field in
60
B.Record_internal.Field (B.Field.internal_use_only {
61
B.Field_internal.label; rep; index; tyid; get;
64
let typename = A.Record.typename_of_t record in
65
let has_double_array_tag = A.Record.has_double_array_tag record in
66
let fields = Array.init (A.Record.length record)
67
(fun index -> map_field (A.Record.field record index))
69
let create { B.Record_internal.get } =
70
let get (type a) (afield : (_, a) A.Field.t) =
71
match fields.(A.Field.index afield) with
72
| B.Record_internal.Field bfield ->
73
(fun (type ex) (bfield : (record, ex) B.Field.t) ->
75
Typename.same_witness_exn (A.Field.tyid afield) (B.Field.tyid bfield)
77
let bfield = (bfield : (record, a) B.Field.t) in
81
A.Record.create record { A.Record.get }
83
B.Record.internal_use_only {
84
B.Record_internal.typename; fields; has_double_array_tag; create;
88
module type Named = sig
92
val create : unit -> t
95
val init : Context.t -> 'a Typename.t -> 'a t
96
val get_wip_computation : 'a t -> 'a computation
97
val set_final_computation : 'a t -> 'a computation -> 'a computation
98
val share : _ Typerep.t -> bool
101
module type Computation = sig
104
include Variant_and_record_intf.S with type 'a t := 'a t
109
val nativeint : nativeint t
112
val string : string t
115
val option : 'a t -> 'a option t
116
val list : 'a t -> 'a list t
117
val array : 'a t -> 'a array t
118
val lazy_t : 'a t -> 'a lazy_t t
119
val ref_ : 'a t -> 'a ref t
120
val function_ : 'a t -> 'b t -> ('a -> 'b) t
121
val tuple2 : 'a t -> 'b t -> ('a * 'b) t
122
val tuple3 : 'a t -> 'b t -> 'c t -> ('a * 'b * 'c) t
123
val tuple4 : 'a t -> 'b t -> 'c t -> 'd t -> ('a * 'b * 'c * 'd) t
124
val tuple5 : 'a t -> 'b t -> 'c t -> 'd t -> 'e t -> ('a * 'b * 'c * 'd * 'e) t
125
val record : 'a Record.t -> 'a t
126
val variant : 'a Variant.t -> 'a t
128
module Named : Named with type 'a computation := 'a t
131
(* special functor application for computation as closure of the form [a -> b] *)
132
module Make_named_for_closure (X : sig
135
type 'a t = 'a input -> 'a output
138
module Context = struct
144
runtime_dereference : 'a X.t;
145
runtime_reference : 'a X.t ref;
146
compiletime_dereference : 'a X.t option ref;
149
exception Undefined of string
152
let path = Typename.Uid.name (Typename.uid name) in
153
let r = ref (fun _ -> raise (Undefined path)) in
155
runtime_dereference = (fun input -> !r input);
156
runtime_reference = r;
157
compiletime_dereference = ref None;
160
let get_wip_computation shared =
161
match shared.compiletime_dereference.contents with
163
| None -> shared.runtime_dereference
165
let set_final_computation shared computation =
166
let compiletime_dereference = shared.compiletime_dereference in
167
match compiletime_dereference.contents with
168
| Some _ -> assert false
170
if Pervasives.(==) shared.runtime_dereference computation then assert false;
171
compiletime_dereference := Some computation;
172
shared.runtime_reference := computation;
178
module Ident = struct
181
implements : Typename.Uid.t -> bool;
183
exception Broken_dependency of string
184
let check_dependencies name required =
186
| [] -> (fun _ -> ())
189
List.iter (fun { name = name'; implements } ->
190
if not (implements uid) then begin
191
(* something is wrong with the set up, this is an error during the
192
initialization of the program, we rather fail with a human
195
Printf.sprintf "Type_generic %S requires %S for uid %S\n"
196
name name' (Typename.Uid.name uid)
198
prerr_endline message;
199
raise (Broken_dependency message)
204
(* Extending an existing generic *)
205
module type Extending = sig
208
type 'a computation = 'a t
212
(* generic_ident * typename or info *)
213
exception Not_implemented of string * string
217
include Typerepable.S0 with type t := t
218
val compute : t computation
223
include Typerepable.S1 with type 'a t := 'a t
224
val compute : 'a computation -> 'a t computation
229
include Typerepable.S2 with type ('a, 'b) t := ('a, 'b) t
230
val compute : 'a computation -> 'b computation -> ('a, 'b) t computation
235
include Typerepable.S3 with type ('a, 'b, 'c) t := ('a, 'b, 'c) t
240
-> ('a, 'b, 'c) t computation
244
type ('a, 'b, 'c, 'd) t
245
include Typerepable.S4 with type ('a, 'b, 'c, 'd) t := ('a, 'b, 'c, 'd) t
251
-> ('a, 'b, 'c, 'd) t computation
255
type ('a, 'b, 'c, 'd, 'e) t
256
include Typerepable.S5 with type ('a, 'b, 'c, 'd, 'e) t := ('a, 'b, 'c, 'd, 'e) t
263
-> ('a, 'b, 'c, 'd, 'e) t computation
266
val register0 : (module S0) -> unit
267
val register1 : (module S1) -> unit
268
val register2 : (module S2) -> unit
269
val register3 : (module S3) -> unit
270
val register4 : (module S4) -> unit
271
val register5 : (module S5) -> unit
273
(* special less scary type when the type has no parameters *)
274
val register : 'a Typerep.t -> 'a computation -> unit
277
Essentially because we cannot talk about a variable of kind * -> k
278
val register1 : 'a 't Typerep.t -> ('a computation -> 'a 't computation) -> unit
283
(* Implementing a new generic *)
284
module type S_implementation = sig
288
(* raise using the current ident *)
289
val raise_not_implemented : string -> 'a
291
type implementation = {
292
generic : 'a. 'a Typerep.t -> 'a computation;
296
Standard case, find a extended_implementation, or look in the content
298
val _using_extended_implementation :
300
-> 'a Typerep.Named.t
301
-> 'a Typerep.t Lazy.t option
305
This function allows you more control on what you want to do
307
val find_extended_implementation :
308
implementation -> 'a Typerep.Named.t -> 'a computation option
313
val of_typerep : 'a Typerep.t -> [ `generic of 'a computation ]
314
module Computation : Computation with type 'a t = 'a t
317
module Make_S_implementation(X : sig
320
val required : Ident.t list
321
end) : S_implementation with type 'a t = 'a X.t = struct
323
type 'a computation = 'a t
325
include Type_generic_intf.M(struct type 'a t = 'a computation end)
327
(* we do not use core since we are earlier in the dependencies graph *)
328
module Uid_table = struct
329
include Hashtbl.Make(Typename.Uid)
331
if Lazy.lazy_is_val table then
332
let table = Lazy.force table in
333
try Some (find table key) with Not_found -> None
335
let check_dependencies = Ident.check_dependencies X.name X.required
336
let replace table key value =
337
check_dependencies key;
338
replace (Lazy.force table) key value
340
if Lazy.lazy_is_val table then
341
let table = Lazy.force table in
347
let table0 = lazy (Uid_table.create size)
348
let table1 = lazy (Uid_table.create size)
349
let table2 = lazy (Uid_table.create size)
350
let table3 = lazy (Uid_table.create size)
351
let table4 = lazy (Uid_table.create size)
352
let table5 = lazy (Uid_table.create size)
354
let is_registered uid =
355
Uid_table.mem table0 uid
356
|| Uid_table.mem table1 uid
357
|| Uid_table.mem table2 uid
358
|| Uid_table.mem table3 uid
359
|| Uid_table.mem table4 uid
360
|| Uid_table.mem table5 uid
364
implements = is_registered;
367
module Find0(T : Typerep.Named.T0) : sig
368
val compute : unit -> T.named computation option
371
match Uid_table.find table0 (Typename.uid T.typename_of_t) with
374
let module S0 = (val rep : S0) in
375
let witness = Typename.same_witness_exn S0.typename_of_t T.typename_of_named in
376
let module L = Type_equal.Lift(struct
377
type 'a t = 'a computation
379
Some (Type_equal.conv (L.lift witness) S0.compute)
382
module Find1(T : Typerep.Named.T1) : sig
383
val compute : unit -> (T.a computation -> T.a T.named computation) option
386
match Uid_table.find table1 (Typename.uid T.typename_of_t) with
389
let module S1 = (val rep : S1) in
390
let module Conv = Typename.Same_witness_exn_1(S1)(struct
391
type 'a t = 'a T.named
392
let typename_of_t = T.typename_of_named
394
let module L = Type_equal.Lift(struct
395
type 'a t = T.a computation -> 'a computation
397
Some (Type_equal.conv (L.lift Conv.(witness.eq)) S1.compute)
400
module Find2(T : Typerep.Named.T2) : sig
404
-> (T.a, T.b) T.named computation) option
407
match Uid_table.find table2 (Typename.uid T.typename_of_t) with
410
let module S2 = (val rep : S2) in
411
let module Conv = Typename.Same_witness_exn_2(S2)(struct
412
type ('a, 'b) t = ('a, 'b) T.named
413
let typename_of_t = T.typename_of_named
415
let module L = Type_equal.Lift(struct
421
Some (Type_equal.conv (L.lift Conv.(witness.eq)) S2.compute)
424
module Find3(T : Typerep.Named.T3) : sig
429
-> (T.a, T.b, T.c) T.named computation) option
432
match Uid_table.find table3 (Typename.uid T.typename_of_t) with
435
let module S3 = (val rep : S3) in
436
let module Conv = Typename.Same_witness_exn_3(S3)(struct
437
type ('a, 'b, 'c) t = ('a, 'b, 'c) T.named
438
let typename_of_t = T.typename_of_named
440
let module L = Type_equal.Lift(struct
447
Some (Type_equal.conv (L.lift Conv.(witness.eq)) S3.compute)
450
module Find4(T : Typerep.Named.T4) : sig
456
-> (T.a, T.b, T.c, T.d) T.named computation) option
459
match Uid_table.find table4 (Typename.uid T.typename_of_t) with
462
let module S4 = (val rep : S4) in
463
let module Conv = Typename.Same_witness_exn_4(S4)(struct
464
type ('a, 'b, 'c, 'd) t = ('a, 'b, 'c, 'd) T.named
465
let typename_of_t = T.typename_of_named
467
let module L = Type_equal.Lift(struct
475
Some (Type_equal.conv (L.lift Conv.(witness.eq)) S4.compute)
478
module Find5(T : Typerep.Named.T5) : sig
485
-> (T.a, T.b, T.c, T.d, T.e) T.named computation) option
488
match Uid_table.find table5 (Typename.uid T.typename_of_t) with
491
let module S5 = (val rep : S5) in
492
let module Conv = Typename.Same_witness_exn_5(S5)(struct
493
type ('a, 'b, 'c, 'd, 'e) t = ('a, 'b, 'c, 'd, 'e) T.named
494
let typename_of_t = T.typename_of_named
496
let module L = Type_equal.Lift(struct
505
Some (Type_equal.conv (L.lift Conv.(witness.eq)) S5.compute)
508
let unit = Typename.static
510
let register0 compute =
511
let module S0 = (val compute : S0) in
512
let uid = Typename.uid S0.typename_of_t in
513
Uid_table.replace table0 uid compute
515
let register1 compute =
516
let module S1 = (val compute : S1) in
517
let uid = Typename.uid (S1.typename_of_t unit) in
518
Uid_table.replace table1 uid compute
520
let register2 compute =
521
let module S2 = (val compute : S2) in
522
let uid = Typename.uid (S2.typename_of_t unit unit) in
523
Uid_table.replace table2 uid compute
525
let register3 compute =
526
let module S3 = (val compute : S3) in
527
let uid = Typename.uid (S3.typename_of_t unit unit unit) in
528
Uid_table.replace table3 uid compute
530
let register4 compute =
531
let module S4 = (val compute : S4) in
532
let uid = Typename.uid (S4.typename_of_t unit unit unit unit) in
533
Uid_table.replace table4 uid compute
535
let register5 compute =
536
let module S5 = (val compute : S5) in
537
let uid = Typename.uid (S5.typename_of_t unit unit unit unit unit) in
538
Uid_table.replace table5 uid compute
540
let register (type a) typerep_of_a compute =
541
let module S0 = struct
543
let typename_of_t = Typerep.typename_of_t typerep_of_a
544
let typerep_of_t = typerep_of_a
545
let compute = compute
547
register0 (module S0 : S0)
551
type implementation = {
552
generic : 'a. 'a Typerep.t -> 'a computation;
555
let find_extended_implementation (type a) aux = function
556
| Typerep.Named.T0 rep -> begin
557
let module T = (val rep : Typerep.Named.T0 with type t = a) in
558
let module Custom = Find0(T) in
559
match Custom.compute () with
561
let Type_equal.T = T.witness in
562
Some (custom : a computation)
566
| Typerep.Named.T1 rep -> begin
567
let module T = (val rep : Typerep.Named.T1 with type t = a) in
568
let module Custom = Find1(T) in
569
match Custom.compute () with
571
let custom = (custom (aux.generic T.a) : T.a T.named computation) in
572
let Type_equal.T = T.witness in
573
Some (custom : a computation)
577
| Typerep.Named.T2 rep -> begin
578
let module T = (val rep : Typerep.Named.T2 with type t = a) in
579
let module Custom = Find2(T) in
580
match Custom.compute () with
586
: (T.a, T.b) T.named computation) in
587
let Type_equal.T = T.witness in
588
Some (custom : a computation)
592
| Typerep.Named.T3 rep -> begin
593
let module T = (val rep : Typerep.Named.T3 with type t = a) in
594
let module Custom = Find3(T) in
595
match Custom.compute () with
602
: (T.a, T.b, T.c) T.named computation) in
603
let Type_equal.T = T.witness in
604
Some (custom : a computation)
608
| Typerep.Named.T4 rep -> begin
609
let module T = (val rep : Typerep.Named.T4 with type t = a) in
610
let module Custom = Find4(T) in
611
match Custom.compute () with
619
: (T.a, T.b, T.c, T.d) T.named computation) in
620
let Type_equal.T = T.witness in
621
Some (custom : a computation)
625
| Typerep.Named.T5 rep -> begin
626
let module T = (val rep : Typerep.Named.T5 with type t = a) in
627
let module Custom = Find5(T) in
628
match Custom.compute () with
637
: (T.a, T.b, T.c, T.d, T.e) T.named computation) in
638
let Type_equal.T = T.witness in
639
Some (custom : a computation)
643
exception Not_implemented of string * string
645
let raise_not_implemented string = raise (Not_implemented (X.name, string))
647
let _using_extended_implementation aux rep content =
648
match find_extended_implementation aux rep with
649
| Some computation -> computation
652
| Some (lazy content) -> aux.generic content
654
let typename = Typerep.Named.typename_of_t rep in
655
let name = Typename.Uid.name (Typename.uid typename) in
656
raise_not_implemented name
660
module Key_table = Hashtbl.Make(Typename.Key)
665
val required : Ident.t list
666
include Computation with type 'a t := 'a t
669
module Computation = X
671
include Make_S_implementation(X)
673
module Memo = Typename.Table(struct type 'a t = 'a X.Named.t end)
675
module Helper = Helper(Typerep)(Computation)
678
let context = X.Named.Context.create () in
679
let memo_table = Memo.create 32 in
680
let rec of_typerep : type a. a Typerep.t -> a t = function
681
| Typerep.Int -> X.int
682
| Typerep.Int32 -> X.int32
683
| Typerep.Int64 -> X.int64
684
| Typerep.Nativeint -> X.nativeint
685
| Typerep.Char -> X.char
686
| Typerep.Float -> X.float
687
| Typerep.String -> X.string
688
| Typerep.Bool -> X.bool
689
| Typerep.Unit -> X.unit
690
| Typerep.Option rep -> X.option (of_typerep rep)
691
| Typerep.List rep -> X.list (of_typerep rep)
692
| Typerep.Array rep -> X.array (of_typerep rep)
693
| Typerep.Lazy rep -> X.lazy_t (of_typerep rep)
694
| Typerep.Ref rep -> X.ref_ (of_typerep rep)
695
| Typerep.Function (dom, rng) ->
696
X.function_ (of_typerep dom) (of_typerep rng)
697
| Typerep.Tuple tuple -> begin
698
(* do NOT write [X.tuple2 (of_typerep a) (of_typerep b)]
699
because of_typerep can contain a side effect and [a] should be executed
702
| Typerep.Tuple.T2 (a, b) ->
703
let ra = of_typerep a in
704
let rb = of_typerep b in
706
| Typerep.Tuple.T3 (a, b, c) ->
707
let ra = of_typerep a in
708
let rb = of_typerep b in
709
let rc = of_typerep c in
711
| Typerep.Tuple.T4 (a, b, c, d) ->
712
let ra = of_typerep a in
713
let rb = of_typerep b in
714
let rc = of_typerep c in
715
let rd = of_typerep d in
717
| Typerep.Tuple.T5 (a, b, c, d, e) ->
718
let ra = of_typerep a in
719
let rb = of_typerep b in
720
let rc = of_typerep c in
721
let rd = of_typerep d in
722
let re = of_typerep e in
723
X.tuple5 ra rb rc rd re
725
| Typerep.Record record ->
726
X.record (Helper.map_record { Helper.map = of_typerep } record)
727
| Typerep.Variant variant ->
728
X.variant (Helper.map_variant { Helper.map = of_typerep } variant)
729
| Typerep.Named (named, content) -> begin
730
let typename = Typerep.Named.typename_of_t named in
731
match Memo.find memo_table typename with
733
X.Named.get_wip_computation shared
735
match find_extended_implementation { generic = of_typerep } named with
736
| Some computation -> computation
740
let name = Typename.Uid.name (Typename.uid typename) in
741
raise_not_implemented name
742
| Some (lazy content) ->
743
if X.Named.share content
745
let shared = X.Named.init context typename in
746
Memo.set memo_table typename shared;
747
let computation = of_typerep content in
748
X.Named.set_final_computation shared computation
755
let computation = of_typerep rep in