mirror of
https://github.com/c-cube/ocaml-containers.git
synced 2025-12-06 11:15:31 -05:00
Bij.{guard,fix} helpers
This commit is contained in:
parent
9774added9
commit
9d1843ecf8
3 changed files with 43 additions and 5 deletions
22
bij.ml
22
bij.ml
|
|
@ -36,6 +36,7 @@ type _ t =
|
||||||
| Opt : 'a t -> 'a option t
|
| Opt : 'a t -> 'a option t
|
||||||
| Pair : 'a t * 'b t -> ('a * 'b) t
|
| Pair : 'a t * 'b t -> ('a * 'b) t
|
||||||
| Triple : 'a t * 'b t * 'c t -> ('a * 'b * 'c) t
|
| Triple : 'a t * 'b t * 'c t -> ('a * 'b * 'c) t
|
||||||
|
| Guard : ('a -> bool) * 'a t -> 'a t
|
||||||
| Map : ('a -> 'b) * ('b -> 'a) * 'b t -> 'a t
|
| Map : ('a -> 'b) * ('b -> 'a) * 'b t -> 'a t
|
||||||
| Switch : ('a -> char * 'a inject_branch) * (char -> 'a extract_branch) -> 'a t
|
| Switch : ('a -> char * 'a inject_branch) * (char -> 'a extract_branch) -> 'a t
|
||||||
and _ inject_branch =
|
and _ inject_branch =
|
||||||
|
|
@ -57,10 +58,24 @@ let many l = Many l
|
||||||
let opt t = Opt t
|
let opt t = Opt t
|
||||||
let pair a b = Pair(a,b)
|
let pair a b = Pair(a,b)
|
||||||
let triple a b c = Triple (a,b,c)
|
let triple a b c = Triple (a,b,c)
|
||||||
|
let guard f t = Guard (f, t)
|
||||||
|
|
||||||
let map ~inject ~extract b = Map (inject, extract, b)
|
let map ~inject ~extract b = Map (inject, extract, b)
|
||||||
let switch ~inject ~extract = Switch (inject, extract)
|
let switch ~inject ~extract = Switch (inject, extract)
|
||||||
|
|
||||||
|
(** {2 Helpers} *)
|
||||||
|
|
||||||
|
let fix f =
|
||||||
|
let rec bij = lazy (f (fun () -> Lazy.force bij)) in
|
||||||
|
Lazy.force bij
|
||||||
|
|
||||||
|
type 'a versioned = string * 'a
|
||||||
|
|
||||||
|
let with_version v t =
|
||||||
|
pair (guard (fun v' -> v = v') string_) t
|
||||||
|
|
||||||
|
(** {2 Exceptions} *)
|
||||||
|
|
||||||
exception EOF
|
exception EOF
|
||||||
|
|
||||||
exception EncodingError of string
|
exception EncodingError of string
|
||||||
|
|
@ -263,6 +278,9 @@ module SexpEncode(Sink : SINK) = struct
|
||||||
Sink.write_char sink ' ';
|
Sink.write_char sink ' ';
|
||||||
encode bij_b b;
|
encode bij_b b;
|
||||||
Sink.write_char sink ')'
|
Sink.write_char sink ')'
|
||||||
|
| Guard (check, bij'), _ ->
|
||||||
|
(if not (check x) then raise (EncodingError ("check failed")));
|
||||||
|
encode bij' x
|
||||||
| Triple (bij_a, bij_b, bij_c), (a, b, c) ->
|
| Triple (bij_a, bij_b, bij_c), (a, b, c) ->
|
||||||
Sink.write_char sink '(';
|
Sink.write_char sink '(';
|
||||||
encode bij_a a;
|
encode bij_a a;
|
||||||
|
|
@ -344,6 +362,10 @@ module SexpDecode(Source : SOURCE) = struct
|
||||||
let c = decode bijc in
|
let c = decode bijc in
|
||||||
decode_close ();
|
decode_close ();
|
||||||
a, b, c
|
a, b, c
|
||||||
|
| Guard (check, bij') ->
|
||||||
|
let x = decode bij' in
|
||||||
|
(if not (check x) then raise (DecodingError "check failed"));
|
||||||
|
x
|
||||||
| Map (_, extract, bij') ->
|
| Map (_, extract, bij') ->
|
||||||
let x = decode bij' in
|
let x = decode bij' in
|
||||||
extract x
|
extract x
|
||||||
|
|
|
||||||
14
bij.mli
14
bij.mli
|
|
@ -40,6 +40,8 @@ val many : 'a t -> 'a list t (* non empty *)
|
||||||
val opt : 'a t -> 'a option t
|
val opt : 'a t -> 'a option t
|
||||||
val pair : 'a t -> 'b t -> ('a * 'b) t
|
val pair : 'a t -> 'b t -> ('a * 'b) t
|
||||||
val triple : 'a t -> 'b t -> 'c t -> ('a * 'b * 'c) t
|
val triple : 'a t -> 'b t -> 'c t -> ('a * 'b * 'c) t
|
||||||
|
val guard : ('a -> bool) -> 'a t -> 'a t
|
||||||
|
(** Validate values at encoding and decoding *)
|
||||||
|
|
||||||
val map : inject:('a -> 'b) -> extract:('b -> 'a) -> 'b t -> 'a t
|
val map : inject:('a -> 'b) -> extract:('b -> 'a) -> 'b t -> 'a t
|
||||||
|
|
||||||
|
|
@ -55,6 +57,18 @@ val switch : inject:('a -> char * 'a inject_branch) ->
|
||||||
type (the argument of the algebraic constructor);
|
type (the argument of the algebraic constructor);
|
||||||
[extract] retrieves which type to parse based on the character. *)
|
[extract] retrieves which type to parse based on the character. *)
|
||||||
|
|
||||||
|
(** {2 Helpers} *)
|
||||||
|
|
||||||
|
val fix : ((unit -> 'a t) -> 'a t) -> 'a t
|
||||||
|
(** Helper for recursive encodings *)
|
||||||
|
|
||||||
|
type 'a versioned = string * 'a
|
||||||
|
|
||||||
|
val with_version : string -> 'a t -> 'a versioned t
|
||||||
|
(** Guards the values with a given version *)
|
||||||
|
|
||||||
|
(** {2 Exceptions} *)
|
||||||
|
|
||||||
exception EOF
|
exception EOF
|
||||||
|
|
||||||
exception EncodingError of string
|
exception EncodingError of string
|
||||||
|
|
|
||||||
|
|
@ -32,18 +32,20 @@ type term =
|
||||||
| App of term list
|
| App of term list
|
||||||
|
|
||||||
let bij_term =
|
let bij_term =
|
||||||
let rec mk_bij () =
|
let bij = fix
|
||||||
|
(fun bij ->
|
||||||
switch
|
switch
|
||||||
~inject:(function
|
~inject:(function
|
||||||
| Const s -> 'c', BranchTo (string_, s)
|
| Const s -> 'c', BranchTo (string_, s)
|
||||||
| Int i -> 'i', BranchTo (int_, i)
|
| Int i -> 'i', BranchTo (int_, i)
|
||||||
| App l -> 'a', BranchTo (list_ (mk_bij ()), l))
|
| App l -> 'a', BranchTo (list_ (bij ()), l))
|
||||||
~extract:(function
|
~extract:(function
|
||||||
| 'c' -> BranchFrom (string_, fun x -> Const x)
|
| 'c' -> BranchFrom (string_, fun x -> Const x)
|
||||||
| 'i' -> BranchFrom (int_, fun x -> Int x)
|
| 'i' -> BranchFrom (int_, fun x -> Int x)
|
||||||
| 'a' -> BranchFrom (list_ (mk_bij ()), fun l -> App l)
|
| 'a' -> BranchFrom (list_ (bij ()), fun l -> App l)
|
||||||
| _ -> raise (DecodingError "unexpected case switch"))
|
| _ -> raise (DecodingError "unexpected case switch")))
|
||||||
in mk_bij ()
|
in
|
||||||
|
bij
|
||||||
|
|
||||||
let test_rec () =
|
let test_rec () =
|
||||||
let t = App [Const "foo"; App [Const "bar"; Int 1; Int 2]; Int 3; Const "hello"] in
|
let t = App [Const "foo"; App [Const "bar"; Int 1; Int 2]; Int 3; Const "hello"] in
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue