Bij.{guard,fix} helpers

This commit is contained in:
Simon Cruanes 2013-05-15 15:11:54 +02:00
parent 9774added9
commit 9d1843ecf8
3 changed files with 43 additions and 5 deletions

22
bij.ml
View file

@ -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
View file

@ -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

View file

@ -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