Added JSON annotations on Ok values in the trace monad.
In some cases the values are dropped when converting values out of the monad or when converting the successful generation of an error message to an actual error. Look for `ignore annotations` in the source code for the places where these annotations are dropped.
This commit is contained in:
parent
ba1e605011
commit
0786edf3f3
@ -39,11 +39,14 @@ let mk_error ?(error_code : int option) ~(title : string) ?(message : string opt
|
|||||||
|
|
||||||
type error_thunk = unit -> error
|
type error_thunk = unit -> error
|
||||||
|
|
||||||
|
type annotation = J.t (* feel free to add different annotations here. *)
|
||||||
|
type annotation_thunk = unit -> annotation
|
||||||
|
|
||||||
type 'a result =
|
type 'a result =
|
||||||
Ok of 'a
|
Ok of 'a * annotation_thunk list
|
||||||
| Errors of error_thunk list
|
| Errors of error_thunk list
|
||||||
|
|
||||||
let ok x = Ok x
|
let ok x = Ok (x, [])
|
||||||
let fail err = Errors [err]
|
let fail err = Errors [err]
|
||||||
|
|
||||||
(* When passing a constant string where a thunk is expected, we wrap it with thunk, as follows:
|
(* When passing a constant string where a thunk is expected, we wrap it with thunk, as follows:
|
||||||
@ -64,11 +67,14 @@ let simple_fail str = fail @@ simple_error str
|
|||||||
let dummy_fail = simple_fail "dummy"
|
let dummy_fail = simple_fail "dummy"
|
||||||
|
|
||||||
let map f = function
|
let map f = function
|
||||||
| Ok x -> f x
|
| Ok (x, annotations) ->
|
||||||
|
(match f x with
|
||||||
|
Ok (x', annotations') -> Ok (x', annotations' @ annotations)
|
||||||
|
| Errors _ as e' -> ignore annotations; e')
|
||||||
| Errors _ as e -> e
|
| Errors _ as e -> e
|
||||||
|
|
||||||
let apply f = function
|
let apply f = function
|
||||||
| Ok x -> Ok (f x)
|
| Ok (x, annotations) -> Ok (f x, annotations)
|
||||||
| Errors _ as e -> e
|
| Errors _ as e -> e
|
||||||
|
|
||||||
let (>>?) x f = map f x
|
let (>>?) x f = map f x
|
||||||
@ -91,7 +97,7 @@ let trace_r err_thunk_may_fail = function
|
|||||||
| Ok _ as o -> o
|
| Ok _ as o -> o
|
||||||
| Errors errs ->
|
| Errors errs ->
|
||||||
match err_thunk_may_fail () with
|
match err_thunk_may_fail () with
|
||||||
| Ok err -> Errors (err :: errs)
|
| Ok (err, annotations) -> ignore annotations; Errors (err :: errs)
|
||||||
| Errors errors_while_generating_error ->
|
| Errors errors_while_generating_error ->
|
||||||
(* TODO: the complexity could be O(n*n) in the worst case,
|
(* TODO: the complexity could be O(n*n) in the worst case,
|
||||||
this should use some catenable lists. *)
|
this should use some catenable lists. *)
|
||||||
@ -111,7 +117,7 @@ let trace_f_2_ez f name =
|
|||||||
trace_f_2 f (error (thunk "in function") name)
|
trace_f_2 f (error (thunk "in function") name)
|
||||||
|
|
||||||
let to_option = function
|
let to_option = function
|
||||||
| Ok o -> Some o
|
| Ok (o, annotations) -> ignore annotations; Some o
|
||||||
| Errors _ -> None
|
| Errors _ -> None
|
||||||
|
|
||||||
let trace_option error = function
|
let trace_option error = function
|
||||||
@ -164,8 +170,8 @@ let bind_find_map_list error f lst =
|
|||||||
| [] -> fail error
|
| [] -> fail error
|
||||||
| hd :: tl -> (
|
| hd :: tl -> (
|
||||||
match f hd with
|
match f hd with
|
||||||
| Ok x -> ok x
|
|
||||||
| Errors _ -> aux tl
|
| Errors _ -> aux tl
|
||||||
|
| o -> o
|
||||||
)
|
)
|
||||||
in
|
in
|
||||||
aux lst
|
aux lst
|
||||||
@ -176,21 +182,21 @@ let bind_list_iter f lst =
|
|||||||
|
|
||||||
let bind_or (a, b) =
|
let bind_or (a, b) =
|
||||||
match a with
|
match a with
|
||||||
| Ok x -> ok x
|
| Ok _ as o -> o
|
||||||
| _ -> b
|
| _ -> b
|
||||||
|
|
||||||
let bind_lr (type a b) ((a : a result), (b:b result)) : [`Left of a | `Right of b] result =
|
let bind_lr (type a b) ((a : a result), (b:b result)) : [`Left of a | `Right of b] result =
|
||||||
match (a, b) with
|
match (a, b) with
|
||||||
| Ok x, _ -> ok @@ `Left x
|
| (Ok _ as o), _ -> apply (fun x -> `Left x) o
|
||||||
| _, Ok x -> ok @@ `Right x
|
| _, (Ok _ as o) -> apply (fun x -> `Right x) o
|
||||||
| _, Errors b -> Errors b
|
| _, Errors b -> Errors b
|
||||||
|
|
||||||
let bind_lr_lazy (type a b) ((a : a result), (b:unit -> b result)) : [`Left of a | `Right of b] result =
|
let bind_lr_lazy (type a b) ((a : a result), (b:unit -> b result)) : [`Left of a | `Right of b] result =
|
||||||
match a with
|
match a with
|
||||||
| Ok x -> ok @@ `Left x
|
| Ok _ as o -> apply (fun x -> `Left x) o
|
||||||
| _ -> (
|
| _ -> (
|
||||||
match b() with
|
match b() with
|
||||||
| Ok x -> ok @@ `Right x
|
| Ok _ as o -> apply (fun x -> `Right x) o
|
||||||
| Errors b -> Errors b
|
| Errors b -> Errors b
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -232,7 +238,7 @@ let trace_tzresult_r err_thunk_may_fail =
|
|||||||
| Error errs ->
|
| Error errs ->
|
||||||
let tz_errs = List.map of_tz_error errs in
|
let tz_errs = List.map of_tz_error errs in
|
||||||
match err_thunk_may_fail () with
|
match err_thunk_may_fail () with
|
||||||
| Ok err -> Errors (err :: tz_errs)
|
| Ok (err, annotations) -> ignore annotations; Errors (err :: tz_errs)
|
||||||
| Errors errors_while_generating_error ->
|
| Errors errors_while_generating_error ->
|
||||||
(* TODO: the complexity could be O(n*n) in the worst case,
|
(* TODO: the complexity could be O(n*n) in the worst case,
|
||||||
this should use some catenable lists. *)
|
this should use some catenable lists. *)
|
||||||
@ -268,13 +274,21 @@ let sys_command command =
|
|||||||
| n -> fail (fun () -> error (thunk "Nonzero return code") (fun () -> (string_of_int n)) ())
|
| n -> fail (fun () -> error (thunk "Nonzero return code") (fun () -> (string_of_int n)) ())
|
||||||
|
|
||||||
let sequence f lst =
|
let sequence f lst =
|
||||||
let rec aux acc = function
|
let lazy_map_force : 'a . (unit -> 'a) list -> (unit -> 'a list) = fun l ->
|
||||||
|
fun () ->
|
||||||
|
List.rev @@ List.rev_map (fun a -> a ()) l in
|
||||||
|
let rec aux acc_x acc_annotations = function
|
||||||
| hd :: tl -> (
|
| hd :: tl -> (
|
||||||
match f hd with
|
match f hd with
|
||||||
| Ok x -> aux (x :: acc) tl
|
(* TODO: what should we do with the annotations? *)
|
||||||
|
| Ok (x, annotations) -> aux (x :: acc_x) (lazy_map_force annotations :: acc_annotations) tl
|
||||||
| Errors _ as errs -> errs
|
| Errors _ as errs -> errs
|
||||||
)
|
)
|
||||||
| [] -> ok @@ List.rev acc in
|
| [] ->
|
||||||
|
let old_annotations () = List.map (fun a -> `List (a ())) @@ List.rev acc_annotations in
|
||||||
|
(* Builds a JSON annotation { "type": "list"; "content": [[…], …] } *)
|
||||||
|
let annotation = fun () -> `Assoc [("type", `String "list"); ("content", `List (old_annotations ()))]
|
||||||
|
in Ok (List.rev acc_x, [annotation]) in
|
||||||
aux [] lst
|
aux [] lst
|
||||||
|
|
||||||
let json_of_error = J.to_string
|
let json_of_error = J.to_string
|
||||||
|
@ -2,7 +2,7 @@ open Trace
|
|||||||
|
|
||||||
let toplevel x =
|
let toplevel x =
|
||||||
match x with
|
match x with
|
||||||
| Trace.Ok () -> ()
|
| Trace.Ok ((), annotations) -> ignore annotations; ()
|
||||||
| Errors ss ->
|
| Errors ss ->
|
||||||
Format.printf "Errors: %a\n%!" errors_pp @@ List.map (fun f -> f()) ss
|
Format.printf "Errors: %a\n%!" errors_pp @@ List.map (fun f -> f()) ss
|
||||||
|
|
||||||
|
@ -6,7 +6,7 @@ let test name f =
|
|||||||
trace (fun () -> error (thunk "running test") (fun () -> name) ()) @@
|
trace (fun () -> error (thunk "running test") (fun () -> name) ()) @@
|
||||||
f () in
|
f () in
|
||||||
match result with
|
match result with
|
||||||
| Ok () -> ()
|
| Ok ((), annotations) -> ignore annotations; ()
|
||||||
| Errors errs ->
|
| Errors errs ->
|
||||||
Format.printf "Errors : {\n%a}\n%!" errors_pp (List.rev (List.rev_map (fun f -> f ()) errs)) ;
|
Format.printf "Errors : {\n%a}\n%!" errors_pp (List.rev (List.rev_map (fun f -> f ()) errs)) ;
|
||||||
raise Alcotest.Test_error
|
raise Alcotest.Test_error
|
||||||
|
Loading…
Reference in New Issue
Block a user