summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorJohn Estabrook <jestabro@vyos.io>2025-10-27 22:42:37 -0500
committerJohn Estabrook <jestabro@vyos.io>2025-11-03 08:11:05 -0600
commit2aea7ddbc092b03dbf07dce385786b9c5c16a881 (patch)
tree3c837d8e16cb52d1d7bb85ea4afc5ffb913a81d0 /src
parent6ced0e36b3f98675d82007f8c77193e2836c4b60 (diff)
downloadvyos1x-config-2aea7ddbc092b03dbf07dce385786b9c5c16a881.tar.gz
vyos1x-config-2aea7ddbc092b03dbf07dce385786b9c5c16a881.zip
T7915: add compiler alerts and annotations
Diffstat (limited to 'src')
-rw-r--r--src/config_diff.ml134
-rw-r--r--src/config_diff.mli18
-rw-r--r--src/config_file.ml5
-rw-r--r--src/config_tree.ml210
-rw-r--r--src/config_tree.mli36
-rw-r--r--src/generate.ml82
-rw-r--r--src/generate.mli13
-rw-r--r--src/internal.ml13
-rw-r--r--src/internal.mli15
-rw-r--r--src/parser.ml3
-rw-r--r--src/parser.mli2
-rw-r--r--src/reference_tree.ml208
-rw-r--r--src/reference_tree.mli37
-rw-r--r--src/tree_alg.ml24
-rw-r--r--src/tree_alg.mli217
-rw-r--r--src/value_checker.ml7
-rw-r--r--src/value_checker.mli1
-rw-r--r--src/vylist.mli10
-rw-r--r--src/vytree.ml86
-rw-r--r--src/vytree.mli38
20 files changed, 1046 insertions, 113 deletions
diff --git a/src/config_diff.ml b/src/config_diff.ml
index 73c379b..b0e48d3 100644
--- a/src/config_diff.ml
+++ b/src/config_diff.ml
@@ -154,26 +154,40 @@ let rec diff (path : string list) (f : 'a diff_func) (res: 'a result) ((left_nod
(* copy node paths between trees *)
let rec clone_path ?(recurse=true) ?(set_values=None) old_root new_root path_done path_remaining =
+ (* raises:
+ [Vytree.Nonexistent_path]
+ alert exn Vytree.get:
+ [Vytree.Empty_path] not possible as clone_path called by clone with non-empty path
+ [Vytree.Nonexistent_path] allow raise
+ alert exn Vytree.insert:
+ [Vytree.Empty_path] not possible as clone_path called by clone with non-empty path
+ [Not_found] not possible for postion=Lexical
+ [Vytree.Duplicate_child] not possible as calls are on path complement
+ [Vytree.Insert_error] not possible as calls are on path_existing @ [name]
+ *)
match path_remaining with
| [] | [_] ->
let path_total = path_done @ path_remaining in
- let old_node = Vytree.get old_root path_total in
+ let old_node = (Vytree.get[@alert "-exn"]) old_root path_total in
let data =
match set_values with
| Some v -> { (data_of old_node) with Config_tree.values = v }
| None -> data_of old_node
in
if recurse then
- Vytree.insert ~position:Lexical ~children:(children_of old_node) new_root path_total data
+ (Vytree.insert[@alert "-exn"]) ~position:Lexical ~children:(children_of old_node) new_root path_total data
else
- Vytree.insert ~position:Lexical new_root path_total data
+ (Vytree.insert[@alert "-exn"]) ~position:Lexical new_root path_total data
| name :: names ->
let path_done = path_done @ [name] in
- let old_node = Vytree.get old_root path_done in
- let new_root = Vytree.insert ~position:Lexical new_root path_done (data_of old_node) in
+ let old_node = (Vytree.get[@alert "-exn"]) old_root path_done in
+ let new_root = (Vytree.insert[@alert "-exn"]) ~position:Lexical new_root path_done (data_of old_node) in
clone_path ~recurse:recurse ~set_values:set_values old_root new_root path_done names
let clone ?(recurse=true) ?(set_values=None) old_root new_root path =
+ (* raises:
+ [Vytree.Nonexistent_path] from clone_path
+ *)
match path with
| [] -> if recurse then old_root else new_root
| _ ->
@@ -183,6 +197,12 @@ let clone ?(recurse=true) ?(set_values=None) old_root new_root path =
(* define the diff_func *)
let decorate_trees ?(recurse=true) (path : string list) (Diff_tree res) (m : change) =
+ (* raises no exception:
+ clone will always be called on extant path of left or right
+ alert exn Vytree.get_values:
+ [Vytree.Empty_path] not possible as pattern Updated implies non-empty path
+ [Vytree.Nonexistent_path] not possible as pattern Updated implies path exists
+ *)
match m with
| Added -> Diff_tree {res with add = clone res.right res.add path; }
| Subtracted ->
@@ -192,7 +212,7 @@ let decorate_trees ?(recurse=true) (path : string list) (Diff_tree res) (m : cha
Diff_tree {res with inter = clone ~recurse:recurse res.left res.inter path; }
| Updated v ->
(* if in this case, node at path is guaranteed to exist *)
- let ov = Config_tree.get_values res.left path in
+ let ov = (Config_tree.get_values[@alert "-exn"]) res.left path in
match ov, v with
| [_], [_] -> Diff_tree {res with sub = clone res.left res.sub path;
del = clone res.left res.del path;
@@ -236,13 +256,24 @@ let decorate_trees ?(recurse=true) (path : string list) (Diff_tree res) (m : cha
(* get sub trees for path-relative comparison *)
let tree_at_path path node =
+ (* raises:
+ [Vytree.Empty_path]
+ [Empty_comparison]
+ alert exn Vytree.get:
+ [Vytree.Empty_path] allow raise
+ [Vytree.Nonexistent_path] catch and raise Empty_comparison
+ *)
try
- let node = Vytree.get node path in
+ let node = (Vytree.get[@alert "-exn"]) node path in
make Config_tree.default_data "" [node]
with Vytree.Nonexistent_path -> raise Empty_comparison
(* call recursive diff on config_trees with decorate_trees as the diff_func *)
let compare path left right =
+ (* raises:
+ [Empty_comparison] from tree_at_path
+ [Incommensurable]
+ *)
if (name_of left) <> (name_of right) then
raise Incommensurable
else
@@ -254,6 +285,10 @@ let compare path left right =
(* wrapper to return diff trees *)
let diff_tree path left right =
+ (* raises:
+ [Incommensurable],
+ [Empty_comparison] from compare
+ *)
let trees = compare path left right in
let add_node = make Config_tree.default_data "add" (children_of (trees.add)) in
let sub_node = make Config_tree.default_data "sub" (children_of (trees.sub)) in
@@ -266,9 +301,23 @@ let diff_tree path left right =
we need a hybrid tree between the 'del' tree and the 'sub' tree, namely:
in case the del tree has a terminal tag node (== all tag values have
been removed) add tag node values for proper removal in commit execution
- *)
+ *)
let get_tagged_delete_tree dt =
+ (* alert exn Config_tree.is_tag:
+ [Vytree.Empty_path] not possible in pattern non-empty path
+ [Vytree.Nonexistent_path] not possible in fold_tree_with_path
+ alert exn Vytree.is_terminal_path:
+ [Vytree.Empty_path] not possible in pattern non-empty path
+ alert exn Vytree.children_of_path:
+ [Vytree.Empty_path] not possible in pattern non-empty path
+ [Vytree.Nonexistent_path] not possible in super-tree of fold_tree_with_path arg
+ alert exn Vytree.insert:
+ [Vytree.Empty_path]: not possible since called on pattern path non-empty
+ [Not_found]: not possible for postion=Lexical
+ [Vytree.Duplicate_child]: not possible by condition is_terminal_path
+ [Vytree.Insert_error]: not possible since constructed iteratively from existing path
+ *)
let del_tree = Config_tree.get_subtree dt ["del"] in
let sub_tree = Config_tree.get_subtree dt ["sub"] in
let f (p, a) _t =
@@ -276,10 +325,10 @@ let get_tagged_delete_tree dt =
match q with
| [] -> (p, a)
| _ ->
- if Config_tree.is_tag a q && Vytree.is_terminal_path a q then
- let children = Vytree.children_of_path sub_tree q in
+ if (Config_tree.is_tag[@alert "-exn"]) a q && (Vytree.is_terminal_path[@alert "-exn"]) a q then
+ let children = (Vytree.children_of_path[@alert "-exn"]) sub_tree q in
let insert_child path node name =
- Vytree.insert ~position:Lexical node (path @ [name]) Config_tree.default_data
+ (Vytree.insert[@alert "-exn"]) ~position:Lexical node (path @ [name]) Config_tree.default_data
in
let a' = List.fold_left (insert_child q) a children in
(p, a')
@@ -307,14 +356,20 @@ let marked_render mark node =
String.concat "\n" m
let added_lines ?(cmds=false) node path =
+ (* alert exn Config_tree.render_commands:
+ [Vytree.Nonexistent_path] not possible on root path
+ *)
if not cmds then marked_render "+ " (tree_at_path path node)
else
- (Config_tree.render_commands ~op:Set node []) ^ "\n"
+ ((Config_tree.render_commands[@alert "-exn"]) ~op:Set node []) ^ "\n"
let removed_lines ?(cmds=false) node path =
+ (* alert exn Config_tree.render_commands:
+ [Vytree.Nonexistent_path] not possible on root path
+ *)
if not cmds then marked_render "- " (tree_at_path path node)
else
- (Config_tree.render_commands ~op:Delete node []) ^ "\n"
+ ((Config_tree.render_commands[@alert "-exn"]) ~op:Delete node []) ^ "\n"
let order_commands (strl: string) =
let l = String.split_on_char '\n' strl in
@@ -323,6 +378,12 @@ let order_commands (strl: string) =
(String.concat "\n" del) ^ "\n" ^ (String.concat "\n" set) ^ "\n"
let unified_diff ?(cmds=false) ?recurse:_ (path : string list) (Diff_string res) (m : change) =
+ (* raises no exception:
+ clone will always be called on extant path of left or right
+ alert exn Vytree.get_values:
+ [Vytree.Empty_path] not possible as pattern Updated implies non-empty path
+ [Vytree.Nonexistent_path] not possible as pattern Updated implies path exists
+ *)
let ppath_l = list_but_last path
in
let ppath_s =
@@ -348,7 +409,7 @@ let unified_diff ?(cmds=false) ?recurse:_ (path : string list) (Diff_string res)
Diff_string { res with ppath = ppath_l; udiff = str_diff; }
| Unchanged -> Diff_string (res)
| Updated v ->
- let ov = Config_tree.get_values res.left path in
+ let ov = (Config_tree.get_values[@alert "-exn"]) res.left path in
match ov, v with
| [_], [_] ->
let str_diff =
@@ -405,6 +466,10 @@ let compare_at_path_maybe_empty left right path =
in (left, right)
let show_diff ?(cmds=false) path left right =
+ (* raises:
+ [Incommensurable],
+ [Empty_comparison] from compare_at_path_maybe_empty
+ *)
if (name_of left) <> (name_of right) then
raise Incommensurable
else
@@ -425,19 +490,34 @@ let show_diff ?(cmds=false) path left right =
(* mask function; mask applied on right *)
let mask_func ?recurse:_ (path : string list) (Diff_tree res) (m : change) =
+ (* alert exn Vytree.delete:
+ [Vytree.Empty_path] not possible since Unchanged pattern is only empty path
+ [Vytree.Nonexistent_path] not possible as called on existing config paths (res.left)
+ alert exn Vytree.is_terminal_path:
+ [Vytree.Empty_path] not possible since Unchanged pattern is only empty path
+ *)
match m with
| Added -> Diff_tree (res)
| Subtracted ->
(match path with
- | [_] -> Diff_tree {res with left = Vytree.delete res.left path}
- | _ -> if not (Vytree.is_terminal_path res.right (list_but_last path)) then
- Diff_tree {res with left = Vytree.delete res.left path}
- else Diff_tree (res))
+ | [_] ->
+ Diff_tree {res with left = (Vytree.delete[@alert "-exn"]) res.left path}
+ | _ ->
+ if not ((Vytree.is_terminal_path[@alert "-exn"]) res.right (list_but_last path)) then
+ Diff_tree {res with left = (Vytree.delete[@alert "-exn"]) res.left path}
+ else Diff_tree (res))
| Unchanged -> Diff_tree (res)
| Updated _ -> Diff_tree (res)
(* call recursive diff with mask_func; mask applied on right *)
let mask_tree left right =
+ (* raises:
+ [Empty_comparison] from diff
+ [Incommensurable]
+ *)
+ if (name_of left) <> (name_of right) then
+ raise Incommensurable
+ else
let trees = make_diff_trees left right in
let d = diff [] mask_func trees (Option.some left, Option.some right)
in
@@ -450,14 +530,28 @@ let union_of_values (n : Config_tree.t) (m : Config_tree.t) =
ValueS.elements (ValueS.union set_n set_m)
let tree_union s t =
+ (* raises:
+ [Tree_alg.Incompatible_union]
+ [Tree_alg.Nonexistent_child] should not be reachable
+ alert exn Tree_alg.ConfigAlg.tree_union:
+ [Tree_alg.Incompatible_union] allow raise
+ [Tree_alg.Nonexistent_child] allow raise; should not be reachable
+ *)
let f u v =
let values = union_of_values u v in
let data = {(data_of v) with Config_tree.values = values} in
Vytree.make_full data (name_of v) (children_of v)
in
- Tree_alg.ConfigAlg.tree_union s t f
+ (Tree_alg.ConfigAlg.tree_union[@alert "-exn"]) s t f
let tree_merge ?(destructive=false) s t =
+ (* raises:
+ [Tree_alg.Incompatible_union]
+ [Tree_alg.Nonexistent_child] should not be reachable
+ alert exn Tree_alg.ConfigAlg.tree_union:
+ [Tree_alg.Incompatible_union] allow raise
+ [Tree_alg.Nonexistent_child] allow raise; should not be reachable
+ *)
let f u v =
let data =
match destructive with
@@ -465,4 +559,4 @@ let tree_merge ?(destructive=false) s t =
| true -> data_of v
in Vytree.make_full data (name_of v) (children_of v)
in
- Tree_alg.ConfigAlg.tree_union s t f
+ (Tree_alg.ConfigAlg.tree_union[@alert "-exn"]) s t f
diff --git a/src/config_diff.mli b/src/config_diff.mli
index fdc662c..98e0ee3 100644
--- a/src/config_diff.mli
+++ b/src/config_diff.mli
@@ -42,10 +42,28 @@ exception Empty_comparison
exception Nonexistent_child
val clone : ?recurse:bool -> ?set_values:string list option -> Config_tree.t -> Config_tree.t ->string list -> Config_tree.t
+[@@alert exn "Vytree.Nonexistent_path"]
+
val diff_tree : string list -> Config_tree.t -> Config_tree.t -> Config_tree.t
+[@@alert exn "Config_diff.Incommensurable"]
+[@@alert exn "Config_diff.Empty_comparison"]
+
val show_diff : ?cmds:bool -> string list -> Config_tree.t -> Config_tree.t -> string
+[@@alert exn "Config_diff.Incommensurable"]
+[@@alert exn "Config_diff.Empty_comparison"]
+
val tree_union : Config_tree.t -> Config_tree.t -> Config_tree.t
+[@@alert exn "Tree_alg.Incompatible_union"]
+[@@alert exn "Tree_alg.Nonexistent_child"]
+
val tree_merge : ?destructive:bool -> Config_tree.t -> Config_tree.t -> Config_tree.t
+[@@alert exn "Tree_alg.Incompatible_union"]
+[@@alert exn "Tree_alg.Nonexistent_child"]
+
val mask_tree : Config_tree.t -> Config_tree.t -> Config_tree.t
+[@@alert exn "Config_diff.Incommensurable"]
+[@@alert exn "Config_diff.Empty_comparison"]
+
val make_diff_cstore : Config_tree.t -> Config_tree.t -> int -> Diff_cstore.t result
+
val get_tagged_delete_tree : Config_tree.t -> Config_tree.t
diff --git a/src/config_file.ml b/src/config_file.ml
index abf08ef..548f03a 100644
--- a/src/config_file.ml
+++ b/src/config_file.ml
@@ -27,6 +27,9 @@ let strip_version s =
| [] -> Error "Failure stripping version string from config"
let load_config file =
+ (* alert exn Parser.from_string:
+ [Util.Syntax_error] caught
+ *)
try
let chan = open_in file in
let s = really_input_string chan (in_channel_length chan) in
@@ -36,7 +39,7 @@ let load_config file =
| Ok t -> escape_backslash t
| Error msg -> raise (Sys_error msg)
in
- let config = Parser.from_string s in
+ let config = (Parser.from_string[@alert "-exn"]) s in
Ok config
with
| Sys_error msg -> Error msg
diff --git a/src/config_tree.ml b/src/config_tree.ml
index 8c9e783..425ddf1 100644
--- a/src/config_tree.ml
+++ b/src/config_tree.ml
@@ -32,38 +32,84 @@ let op_to_string op =
| Delete -> "delete"
let replace_value node path value =
- let data = {default_data with values=[value]; leaf=true} in
- Vytree.update node path data
+ (* alert exn Vytree.update:
+ [Vytree.Empty_path] allow raise
+ [Vytree.Nonexistent_path] allow raise
+ *)
+ let data = {default_data with values=[value]; leaf=true} in
+ (Vytree.update[@alert "-exn"]) node path data
let add_value node path value =
- let node' = Vytree.get node path in
- let data = Vytree.data_of_node node' in
- let values = data.values in
- match (Vylist.find (fun x -> x = value) values) with
- | Some _ -> raise Duplicate_value
- | None ->
+ (* alert exn Vytree.get; Vytree.update:
+ [Vytree.Empty_path] allow raise
+ [Vytree.Nonexistent_path] allow raise
+ *)
+ let node' = (Vytree.get[@alert "-exn"]) node path in
+ let data = Vytree.data_of_node node' in
+ let values = data.values in
+ match (Vylist.find (fun x -> x = value) values) with
+ | Some _ -> raise Duplicate_value
+ | None ->
let values = values @ [value] in
- Vytree.update node path ({data with values=values; leaf=true})
+ (Vytree.update[@alert "-exn"]) node path ({data with values=values; leaf=true})
let delete_value node path value =
- let data = Vytree.data_of_node @@ Vytree.get node path in
+ (* alert exn Vytree.update:
+ [Vytree.Empty_path] allow raise
+ [Vytree.Nonexistent_path] allow raise
+ *)
+ let data = Vytree.data_of_node @@ (Vytree.get[@alert "-exn"]) node path in
let values = Vylist.remove (fun x -> x = value) data.values in
- Vytree.update node path {data with values=values; leaf=true}
+ (Vytree.update[@alert "-exn"]) node path {data with values=values; leaf=true}
let set_value node path value behaviour =
+ (* raises
+ [Config_tree.Duplicate_value] from add_value
+ [Vytree.Empty_path],
+ [Vytree.Nonexistent_path] from add_value; replace_value
+ *)
match behaviour with
| AddValue -> add_value node path value
| ReplaceValue -> replace_value node path value
let create_node node path =
- if (Vytree.exists node path) then raise Useless_set
+ (* raises
+ [Vytree.Empty_path]
+ [Useless_set]
+ alert exn Vytree.exists:
+ [Vytree.Empty_path] check and raise
+ alert exn Vytree.insert_multi_level
+ [Vytree.Empty_path] check and raise
+ [Not_found] not possible since position=Default
+ [Vytree.Duplicate_child] not possible since path_remaining is complement
+ [Vytree.Insert_error] not possible since path_existing exists
+ *)
+ if Util.is_empty path then raise Vytree.Empty_path
+ else
+ if ((Vytree.exists[@alert "-exn"]) node path) then raise Useless_set
else
let path_existing = Vytree.get_existent_path node path in
let path_remaining = Vylist.complement path path_existing in
- Vytree.insert_multi_level default_data node path_existing path_remaining default_data
+ (Vytree.insert_multi_level[@alert "-exn"]) default_data node path_existing path_remaining default_data
let set node path value behaviour =
- if (Vytree.exists node path) then
+ (* raises:
+ [Config_tree.Duplicate_value],
+ [Vytree.Empty_path]
+ [Useless_set]
+ avoids:
+ [Vytree.Nonexistent_path] from set_value, since called if Vytree.exists
+ alert exn Vytree.exists:
+ [Vytree.Empty_path] check and raise
+ alert exn Vytree.insert_muilt_level:
+ [Vytree.Empty_path] check and raise
+ [Not_found] not possible since position=Default
+ [Vytree.Duplicate_child] not possible since path_remaining is complement
+ [Vytree.Insert_error] not possible since path_existing exists
+ *)
+ if Util.is_empty path then raise Vytree.Empty_path
+ else
+ if ((Vytree.exists[@alert "-exn"]) node path) then
(match value with
| None -> raise Useless_set
| Some v -> set_value node path v behaviour)
@@ -72,69 +118,134 @@ let set node path value behaviour =
let path_remaining = Vylist.complement path path_existing in
let values = match value with None -> [] | Some v -> [v] in
let end_data = {default_data with values=values; leaf=true} in
- Vytree.insert_multi_level ~position:Lexical default_data node path_existing path_remaining end_data
+ (* alert exn Vytree.insert_muilt_level:
+ [Vytree.Empty_path] allow raise of Vytree.Empty_path
+ [Not_found] not possible since position=Default
+ [Vytree.Duplicate_child] not possible since path_remaining is complement
+ [Vytree.Insert_error] not possible since path_existing exists
+ *)
+ (Vytree.insert_multi_level[@alert "-exn"]) ~position:Lexical default_data node path_existing path_remaining end_data
let get_values node path =
- let node' = Vytree.get node path in
+ (* alert exn Vytree.get:
+ [Vytree.Empty_path] allow raise
+ [Vytree.Nonexistent_path] allow raise
+ *)
+ let node' = (Vytree.get[@alert "-exn"]) node path in
let data = Vytree.data_of_node node' in
data.values
let get_value node path =
+ (* raises
+ [Vytree.Empty_path],
+ [Vytree.Nonexistent_path] from get_values
+ [Node_has_no_value]
+ *)
let values = get_values node path in
match values with
| [] -> raise Node_has_no_value
| x :: _ -> x
let value_exists node path value =
- if not (Vytree.exists node path) then false
- else let node' = Vytree.get node path in
+ (* alert exn Vytree.get:
+ [Vytree.Empty_path] allow raise
+ [Vytree.Nonexistent_path] checked
+ *)
+ if not ((Vytree.exists[@alert "-exn"]) node path) then false
+ else let node' = (Vytree.get[@alert "-exn"]) node path in
let data = Vytree.data_of_node node' in
Vylist.in_list data.values value
let delete node path value =
+ (* raises:
+ [Vytree.Nonexistent_path] from get_values; delete_value
+ [Vytree.Empty_path]
+ [No_such_value]
+
+ alert exn Vytree.delete
+ [Vytree.Empty_path] check and raise
+ [Vytree.Nonexistent_path] allow raise
+ *)
+ if Util.is_empty path then raise Vytree.Empty_path
+ else
match value with
| Some v ->
(let values = get_values node path in
if Vylist.in_list values v then
(match values with
- | [_] -> Vytree.delete node path
+ | [_] -> (Vytree.delete[@alert "-exn"]) node path
| _ -> delete_value node path v)
else raise No_such_value)
| None ->
- Vytree.delete node path
+ (Vytree.delete[@alert "-exn"]) node path
let set_comment node path comment =
- let data = Vytree.get_data node path in
- Vytree.update node path {data with comment=comment}
+ (* alert exn Vytree.get_data; Vytree.update:
+ [Vytree.Empty_path] allow raise
+ [Vytree.Nonexistent_path] allow raise
+ *)
+ let data = (Vytree.get_data[@alert "-exn"]) node path in
+ (Vytree.update[@alert "-exn"]) node path {data with comment=comment}
let get_comment node path =
- let data = Vytree.get_data node path in
+ (* alert exn Vytree.get_data:
+ [Vytree.Empty_path] allow raise
+ [Vytree.Nonexistent_path] allow raise
+ *)
+ let data = (Vytree.get_data[@alert "-exn"]) node path in
data.comment
let set_tag node path tag =
- let data = Vytree.get_data node path in
- Vytree.update node path {data with tag=tag}
+ (* alert exn Vytree.get_data; Vytree.update:
+ [Vytree.Empty_path] allow raise
+ [Vytree.Nonexistent_path] allow raise
+ *)
+ let data = (Vytree.get_data[@alert "-exn"]) node path in
+ (Vytree.update[@alert "-exn"]) node path {data with tag=tag}
let is_tag node path =
- let data = Vytree.get_data node path in
+ (* alert exn Vytree.get_data:
+ [Vytree.Empty_path] allow raise
+ [Vytree.Nonexistent_path] allow raise
+ *)
+ let data = (Vytree.get_data[@alert "-exn"]) node path in
data.tag
let is_tag_value node path =
+ (* raises
+ [Vytree.Empty_path],
+ [Vytree.Nonexistent_path] from is_tag
+ *)
match path with
| [] | [_] -> false
| _ -> is_tag node (Util.drop_last path)
let set_leaf node path leaf =
- let data = Vytree.get_data node path in
- Vytree.update node path {data with leaf=leaf}
+ (* alert exn Vytree.get_data; Vytree.update:
+ [Vytree.Empty_path] allow raise
+ [Vytree.Nonexistent_path] allow raise
+ *)
+ let data = (Vytree.get_data[@alert "-exn"]) node path in
+ (Vytree.update[@alert "-exn"]) node path {data with leaf=leaf}
let is_leaf node path =
- let data = Vytree.get_data node path in
+ (* alert exn Vytree.get_data:
+ [Vytree.Empty_path] allow raise
+ [Vytree.Nonexistent_path] allow raise
+ *)
+ let data = (Vytree.get_data[@alert "-exn"]) node path in
data.leaf
let get_subtree ?(with_node=false) node path =
+ (* alert exn Vytree.get:
+ [Vytree.Empty_path] checked
+ [Vytree.Nonexistent_path] caught
+ *)
+ match path with
+ | [] -> node
+ | _ ->
try
- let n = Vytree.get node path in
+ let n = (Vytree.get[@alert "-exn"]) node path in
if with_node then
Vytree.make_full default_data "" [n]
else
@@ -142,12 +253,15 @@ let get_subtree ?(with_node=false) node path =
with Vytree.Nonexistent_path -> make ""
let value_paths_of_tree node =
+ (* alert exn Vytree.is_terminal_path:
+ [Vytree.Empty_path] not possible in pattern path non-empty
+ *)
let func ct (p, a) _t =
match p with
| [] -> (p, a)
| _ ->
let q = List.rev p in
- if not (Vytree.is_terminal_path ct q) then
+ if not ((Vytree.is_terminal_path[@alert "-exn"]) ct q) then
(p, a)
else
let vals = get_values ct q in
@@ -163,9 +277,17 @@ let value_paths_of_tree node =
in List.rev (snd (Vytree.fold_tree_with_path (func node) ([], []) node))
let prune_delete node path =
+ (* raises:
+ [Vytree.Nonexistent_path] from is_tag_value; delete
+ [Vytree.Empty_path]
+ alert exn Vytree.is_terminal_path:
+ [Vytree.Empty_path] check and raise
+ *)
+ if Util.is_empty path then raise Vytree.Empty_path
+ else
if is_tag_value node path then
let tag_path = Util.drop_last path in
- let terminal = Vytree.is_terminal_path node tag_path in
+ let terminal = (Vytree.is_terminal_path[@alert "-exn"]) node tag_path in
match terminal with
| true -> delete node tag_path None
| false -> node
@@ -180,6 +302,10 @@ struct
List.append path [v] |> String.concat " " |> Printf.sprintf "%s %s" (op_to_string op)
let rec render_commands ?(op=Set) path ct =
+ (* alert exn Vytree.get:
+ [Vytree.Empty_path] not possible as called on non-empty children
+ [Vytree.Nonexistent_path] not possible as called on non-empty children
+ *)
let new_path = List.append path [Vytree.name_of_node ct] in
let new_path_str = String.concat " " new_path in
let data = Vytree.data_of_node ct in
@@ -211,7 +337,9 @@ struct
in
if comment_cmd = "" then cmds else Printf.sprintf "%s\n%s" cmds comment_cmd
| _ :: _ ->
- let children = List.map (fun n -> Vytree.get ct [n]) child_names in
+ let children =
+ List.map (fun n -> (Vytree.get[@alert "-exn"]) ct [n]) child_names
+ in
let rendered_children = List.map (render_commands ~op:op new_path) children in
let cmds = String.concat "\n" rendered_children in
if comment_cmd = "" then cmds else Printf.sprintf "%s\n%s" cmds comment_cmd
@@ -320,10 +448,16 @@ module JSONRenderer = struct
end (* JSONRenderer *)
let render_commands ?(op=Set) node path =
+ (* raises:
+ [Vytree.Nonexistent_path]
+ alert exn Vytree.get:
+ [Vytree.Empty_path] not possible as called on pattern non-empty path
+ [Vytree.Nonexistent_path] allow raise
+ *)
let node =
match path with
| [] -> node
- | _ -> Vytree.get node path
+ | _ -> (Vytree.get[@alert "-exn"]) node path
in
let children = Vytree.children_of_node node in
let commands = List.map (Renderer.render_commands ~op:op path) children in
@@ -332,10 +466,14 @@ let render_commands ?(op=Set) node path =
let render_config ?(ord_val=false) = Renderer.render_config ~ord_val:ord_val
let render_at_level node path =
- let node =
+ (* alert exn Vytree.get:
+ [Vytree.Empty_path] not possible as called on pattern non-empty path
+ [Vytree.Nonexistent_path] allow raise
+ *)
+ let node =
match path with
| [] -> node
- | _ -> Vytree.get node path
+ | _ -> (Vytree.get[@alert "-exn"]) node path
in
render_config node
diff --git a/src/config_tree.mli b/src/config_tree.mli
index 5d3db3c..c320186 100644
--- a/src/config_tree.mli
+++ b/src/config_tree.mli
@@ -22,38 +22,73 @@ val default : t
val make : string -> t
val create_node : t -> string list -> t
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Config_tree.Useless_set"]
val set : t -> string list -> string option -> value_behaviour -> t
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Config_tree.Useless_set"]
+[@@alert exn "Config_tree.Duplicate_value"]
val delete : t -> string list -> string option -> t
+[@@alert exn "Vytree.Nonexistent_path"]
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Config_tree.No_such_value"]
+
+val replace_value : t -> string list -> string -> t
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val prune_delete : t -> string list -> t
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val get_values : t -> string list -> string list
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val get_value : t -> string list -> string
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
+[@@alert exn "Config_tree.Node_has_no_value"]
val value_exists : t -> string list -> string -> bool
+[@@alert exn "Vytree.Empty_path"]
val set_comment : t -> string list -> string option -> t
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val get_comment : t -> string list -> string option
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val set_tag : t -> string list -> bool -> t
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val is_tag : t -> string list -> bool
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val is_tag_value : t -> string list -> bool
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val set_leaf : t -> string list -> bool -> t
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val is_leaf : t -> string list -> bool
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val get_subtree : ?with_node:bool -> t -> string list -> t
val value_paths_of_tree : t -> string list list
val render_commands : ?op:command -> t -> string list -> string
+[@@alert exn "Vytree.Nonexistent_path"]
val render_config : ?ord_val:bool -> t -> string
@@ -62,3 +97,4 @@ val render_json : t -> string
val render_json_ast : t -> string
val render_at_level : t -> string list -> string
+[@@alert exn "Vytree.Nonexistent_path"]
diff --git a/src/generate.ml b/src/generate.ml
index 28f0be1..d4d3f0e 100644
--- a/src/generate.ml
+++ b/src/generate.ml
@@ -1,10 +1,14 @@
(* Load interface definitions from a directory into a reference tree *)
+
exception Load_error of string
exception Write_error of string
module I = Internal.Make(Reference_tree)
let load_interface_definitions dir =
+ (* alert exn Reference_tree.load_from_xml:
+ [Reference_tree.Bad_interface_definition] caught
+ *)
let open Reference_tree in
let dir_paths = FileUtil.ls dir in
let relative_paths =
@@ -15,7 +19,7 @@ let load_interface_definitions dir =
with Sys_error no_dir_msg -> Error no_dir_msg
in
let load_aux tree file =
- load_from_xml tree file
+ (load_from_xml[@alert "-exn"]) tree file
in
try begin match absolute_paths with
| Ok paths -> Ok (List.fold_left load_aux default paths)
@@ -23,6 +27,11 @@ let load_interface_definitions dir =
with Bad_interface_definition msg -> Error msg
let interface_definitions_to_cache from_dir cache_path =
+ (* raises:
+ [Write_error]
+ alert exn Internal.write_internal:
+ [Internecl.Write_error] caught
+ *)
let ref_tree_result =
load_interface_definitions from_dir
in
@@ -31,11 +40,21 @@ let interface_definitions_to_cache from_dir cache_path =
| Ok ref -> ref
| Error msg -> raise (Load_error msg)
in
- I.write_internal ref_tree cache_path
+ try
+ (I.write_internal[@alert "-exn"]) ref_tree cache_path
+ with Internal.Write_error msg -> raise (Write_error msg)
let reference_tree_cache_to_json cache_path render_file =
+ (* raises:
+ [Load_error]
+ [Write_error]
+ alert exn Internal.read_internal:
+ [Internal.Read_error] caught
+ *)
let ref_tree =
- I.read_internal cache_path
+ try
+ (I.read_internal[@alert "-exn"]) cache_path
+ with Internal.Read_error msg -> raise (Load_error msg)
in
let out = Reference_tree.render_json ref_tree in
let oc =
@@ -47,23 +66,65 @@ let reference_tree_cache_to_json cache_path render_file =
close_out oc
let merge_reference_tree_cache cache_dir primary_name result_name =
+ (* raises:
+ [Tree_alg.Incompatible_union],
+ [Tree_alg.Nonexistent_child] from Tree_alg.RefAlg.tree_union
+ [Load_error]
+ [Write_error]
+ alert exn Internal.read_internal:
+ [Internal.Read_error] caught
+ alert exn Internal.write_internal:
+ [Internal.Write_error] caught
+ alert exn Tree_alg.RefAlg.tree_union:
+ [Tree_alg.Incompatible_union] allow raise
+ [Tree_alg.Nonexistent_child] allow raise
+ *)
let file_arr = Sys.readdir cache_dir in
let file_list' = Array.to_list file_arr in
let file_list =
List.filter (fun x -> x <> primary_name && x <> result_name) file_list' in
let file_path_list =
List.map (FilePath.concat cache_dir) file_list in
- let primary_tree = I.read_internal (FilePath.concat cache_dir primary_name) in
- let ref_trees = List.map I.read_internal file_path_list in
+ let primary_tree =
+ try
+ (I.read_internal[@alert "-exn"]) (FilePath.concat cache_dir primary_name)
+ with Internal.Read_error msg -> raise (Load_error msg)
+ in
+ let ref_trees =
+ try
+ List.map (I.read_internal[@alert "-exn"]) file_path_list
+ with Internal.Read_error msg -> raise (Load_error msg)
+ in
match ref_trees with
| [] ->
- I.write_internal primary_tree (FilePath.concat cache_dir result_name)
+ begin
+ try
+ (I.write_internal[@alert "-exn"])
+ primary_tree
+ (FilePath.concat cache_dir result_name)
+ with Internal.Write_error msg -> raise (Write_error msg)
+ end
| _ ->
let f _ v = v in
- let res = List.fold_left (fun p r -> Tree_alg.RefAlg.tree_union r p f) primary_tree ref_trees in
- I.write_internal res (FilePath.concat cache_dir result_name)
+ let res =
+ List.fold_left
+ (fun p r -> (Tree_alg.RefAlg.tree_union[@alert "-exn"]) r p f)
+ primary_tree
+ ref_trees
+ in
+ try
+ (I.write_internal[@alert "-exn"])
+ res
+ (FilePath.concat cache_dir result_name)
+ with Internal.Write_error msg -> raise (Write_error msg)
let reference_tree_to_json ?(internal_cache="") from_dir to_file =
+ (* raises:
+ [Load_error]
+ [Write_error]
+ alert exn Internal.write_internal:
+ [Internal.Write_error] caught
+ *)
let ref_tree_result =
load_interface_definitions from_dir
in
@@ -82,4 +143,7 @@ let reference_tree_to_json ?(internal_cache="") from_dir to_file =
close_out oc;
match internal_cache with
| "" -> ()
- | _ -> I.write_internal ref_tree internal_cache
+ | _ ->
+ try
+ (I.write_internal[@alert "-exn"]) ref_tree internal_cache
+ with Internal.Write_error msg -> raise (Write_error msg)
diff --git a/src/generate.mli b/src/generate.mli
index 4243ef0..3fe0c60 100644
--- a/src/generate.mli
+++ b/src/generate.mli
@@ -2,7 +2,20 @@ exception Load_error of string
exception Write_error of string
val load_interface_definitions : string -> (Reference_tree.t, string) result
+
val reference_tree_to_json : ?internal_cache:string -> string -> string -> unit
+[@@alert exn "Generate.Load_error"]
+[@@alert exn "Generate.Write_error"]
+
val interface_definitions_to_cache : string -> string -> unit
+[@@alert exn "Generate.Write_error"]
+
val reference_tree_cache_to_json : string -> string -> unit
+[@@alert exn "Generate.Load_error"]
+[@@alert exn "Generate.Write_error"]
+
val merge_reference_tree_cache : string -> string -> string -> unit
+[@@alert exn "Generate.Load_error"]
+[@@alert exn "Generate.Write_error"]
+[@@alert exn "Tree_alg.Incompatible_union"]
+[@@alert exn "Tree_alg.Nonexistent_child"]
diff --git a/src/internal.ml b/src/internal.ml
index cd7e968..bb3ab66 100644
--- a/src/internal.ml
+++ b/src/internal.ml
@@ -17,16 +17,27 @@ module type T =
module type FI = functor (M: T) ->
sig
val write_internal : M.t -> string -> unit
+ [@@alert exn "Internal.Write_error"]
val write_internal_atomic : M.t -> string -> unit
+ [@@alert exn "Internal.Write_error"]
val read_internal : string -> M.t
+ [@@alert exn "Internal.Read_error"]
val replace_internal : string -> string -> unit
+ [@@alert exn "Internal.Write_error"]
end
module Make : FI = functor (M: T) -> struct
let write_internal x file_name =
let yt = M.to_yojson x in
let ys = Yojson.Safe.to_string yt in
- let fd = Unix.openfile file_name [Unix.O_CREAT;Unix.O_WRONLY] 0o664 in
+ let fd =
+ try
+ Unix.openfile file_name [Unix.O_CREAT;Unix.O_WRONLY] 0o664
+ with Unix.Unix_error (e,f,p) ->
+ let out =
+ Printf.sprintf "%s %s: %s" (Unix.error_message e) f p
+ in raise (Write_error out)
+ in
let oc = Unix.out_channel_of_descr fd in
let () = Unix.ftruncate fd 0 in
let () = Printf.fprintf oc "%s" ys in
diff --git a/src/internal.mli b/src/internal.mli
index 4fc9b10..030bdaf 100644
--- a/src/internal.mli
+++ b/src/internal.mli
@@ -11,10 +11,17 @@ module type T =
module type FI = functor (M : T) ->
sig
- val write_internal : M.t -> string -> unit
- val write_internal_atomic : M.t -> string -> unit
- val read_internal : string -> M.t
- val replace_internal : string -> string -> unit
+ val write_internal : M.t -> string -> unit
+ [@@alert exn "Internal.Write_error"]
+
+ val write_internal_atomic : M.t -> string -> unit
+ [@@alert exn "Internal.Write_error"]
+
+ val read_internal : string -> M.t
+ [@@alert exn "Internal.Read_error"]
+
+ val replace_internal : string -> string -> unit
+ [@@alert exn "Internal.Write_error"]
end
module Make : FI
diff --git a/src/parser.ml b/src/parser.ml
index f659b34..e1c86e6 100644
--- a/src/parser.ml
+++ b/src/parser.ml
@@ -23,6 +23,9 @@ let rec parse vy_inside_node lexbuf (checkpoint : Config_tree.t I.checkpoint) =
raise (Syntax_error (None, "invalid syntax (parser rejected the input)"))
let from_string s =
+ (* raises:
+ [Syntax_error] from parse
+ *)
let vy_inside_node = false in
let lexbuf = Lexing.from_string s in
parse vy_inside_node lexbuf (Vyos1x_parser.Incremental.config lexbuf.lex_curr_p)
diff --git a/src/parser.mli b/src/parser.mli
new file mode 100644
index 0000000..15813a4
--- /dev/null
+++ b/src/parser.mli
@@ -0,0 +1,2 @@
+val from_string : string -> Config_tree.t
+[@@alert exn "Util.Syntax_error"]
diff --git a/src/reference_tree.ml b/src/reference_tree.ml
index 794fe8f..5107eb8 100644
--- a/src/reference_tree.ml
+++ b/src/reference_tree.ml
@@ -224,6 +224,13 @@ let data_from_xml d x =
in Xml.fold aux d x
let rec insert_from_xml basepath reftree xml =
+ (* raises:
+ [Bad_interface_definition]
+ alert exn Vytree.insert_or_update; Vytree.insert_maybe:
+ [Vytree.Empty_path] not possible as all nodes have nodeNameAttr by schema
+ [Not_found] not possible for position=Default
+ [Vytree.Insert_error] not possible for recursive fold over children
+ *)
match xml with
| Xml.Element ("syntaxVersion", _, _) -> reftree
| Xml.Element (_, _, _) ->
@@ -248,9 +255,9 @@ let rec insert_from_xml basepath reftree xml =
let path = basepath @ [name] in
let new_tree =
if data <> default_data then
- Vytree.insert_or_update reftree path data
+ (Vytree.insert_or_update[@alert "-exn"]) reftree path data
else
- Vytree.insert_maybe reftree path data
+ (Vytree.insert_maybe[@alert "-exn"]) reftree path data
in
(match node_type with
| Leaf -> new_tree
@@ -262,6 +269,9 @@ let rec insert_from_xml basepath reftree xml =
| _ -> raise (Bad_interface_definition "PCData not allowed here")
let load_from_xml reftree file =
+ (* raises:
+ [Bad_interface_definition] from insert_from_xml and explicit
+ *)
let xml_to_reftree xml reftree =
match xml with
| Xml.Element ("interfaceDefinition", _, children) ->
@@ -306,6 +316,9 @@ let format_out l =
doesn't exist in the reference tree
*)
let validate_path validators_dir node path =
+ (* raises:
+ [Validation_error]
+ *)
let show_path p =
Printf.sprintf "[%s]" @@ Util.string_of_list (List.rev p)
in
@@ -452,57 +465,139 @@ let split_path node path =
in aux node path []
let is_multi reftree path =
- let data = Vytree.get_data reftree path in
+ (* raises:
+ [Vytree.Empty_path]
+ [Vytree.Nonexistent_path]
+ alert exn Vytree.get_data:
+ [Vytree.Empty_path] allow raise
+ [Vytree.Nonexistent_path] allow raise
+ *)
+ let data = (Vytree.get_data[@alert "-exn"]) reftree path in
data.multi
let is_hidden reftree path =
- let data = Vytree.get_data reftree path in
+ (* raises:
+ [Vytree.Empty_path]
+ [Vytree.Nonexistent_path]
+ alert exn Vytree.get_data:
+ [Vytree.Empty_path] allow raise
+ [Vytree.Nonexistent_path] allow raise
+ *)
+ let data = (Vytree.get_data[@alert "-exn"]) reftree path in
data.hidden
let is_secret reftree path =
- let data = Vytree.get_data reftree path in
+ (* raises:
+ [Vytree.Empty_path]
+ [Vytree.Nonexistent_path]
+ alert exn Vytree.get_data:
+ [Vytree.Empty_path] allow raise
+ [Vytree.Nonexistent_path] allow raise
+ *)
+ let data = (Vytree.get_data[@alert "-exn"]) reftree path in
data.secret
let is_tag reftree path =
- let data = Vytree.get_data reftree path in
+ (* raises:
+ [Vytree.Empty_path]
+ [Vytree.Nonexistent_path]
+ alert exn Vytree.get_data:
+ [Vytree.Empty_path] allow raise
+ [Vytree.Nonexistent_path] allow raise
+ *)
+ let data = (Vytree.get_data[@alert "-exn"]) reftree path in
match data.node_type with
| Tag -> true
| _ -> false
let is_leaf reftree path =
- let data = Vytree.get_data reftree path in
+ (* raises:
+ [Vytree.Empty_path]
+ [Vytree.Nonexistent_path]
+ alert exn Vytree.get_data:
+ [Vytree.Empty_path] allow raise
+ [Vytree.Nonexistent_path] allow raise
+ *)
+ let data = (Vytree.get_data[@alert "-exn"]) reftree path in
match data.node_type with
| Leaf -> true
| _ -> false
let is_valueless reftree path =
- let data = Vytree.get_data reftree path in
+ (* raises:
+ [Vytree.Empty_path]
+ [Vytree.Nonexistent_path]
+ alert exn Vytree.get_data:
+ [Vytree.Empty_path] allow raise
+ [Vytree.Nonexistent_path] allow raise
+ *)
+ let data = (Vytree.get_data[@alert "-exn"]) reftree path in
data.valueless
let get_owner reftree path =
- let data = Vytree.get_data reftree path in
+ (* raises:
+ [Vytree.Empty_path]
+ [Vytree.Nonexistent_path]
+ alert exn Vytree.get_data:
+ [Vytree.Empty_path] allow raise
+ [Vytree.Nonexistent_path] allow raise
+ *)
+ let data = (Vytree.get_data[@alert "-exn"]) reftree path in
data.owner
let get_priority reftree path =
- let data = Vytree.get_data reftree path in
+ (* raises:
+ [Vytree.Empty_path]
+ [Vytree.Nonexistent_path]
+ alert exn Vytree.get_data:
+ [Vytree.Empty_path] allow raise
+ [Vytree.Nonexistent_path] allow raise
+ *)
+ let data = (Vytree.get_data[@alert "-exn"]) reftree path in
data.priority
let get_help_string reftree path =
- let data = Vytree.get_data reftree path in
+ (* raises:
+ [Vytree.Empty_path]
+ [Vytree.Nonexistent_path]
+ alert exn Vytree.get_data:
+ [Vytree.Empty_path] allow raise
+ [Vytree.Nonexistent_path] allow raise
+ *)
+ let data = (Vytree.get_data[@alert "-exn"]) reftree path in
data.help
let get_value_help reftree path =
- let data = Vytree.get_data reftree path in
+ (* raises:
+ [Vytree.Empty_path]
+ [Vytree.Nonexistent_path]
+ alert exn Vytree.get_data:
+ [Vytree.Empty_path] allow raise
+ [Vytree.Nonexistent_path] allow raise
+ *)
+ let data = (Vytree.get_data[@alert "-exn"]) reftree path in
data.value_help
let get_completion_data reftree path =
+ (* raises:
+ [Vytree.Empty_path]
+ [Vytree.Nonexistent_path]
+ alert exn Vytree.get:
+ [Vytree.Empty_path] allow raise
+ [Vytree.Nonexistent_path] allow raise
+ *)
let aux node =
let data = Vytree.data_of_node node in
(data.node_type, data.multi, data.help)
- in List.map aux (Vytree.children_of_node @@ Vytree.get reftree path)
+ in
+ List.map aux (Vytree.children_of_node @@ (Vytree.get[@alert "-exn"]) reftree path)
(* Convert from config path to reference tree path *)
let refpath reftree path =
+ (* raises:
+ [Vytree.Empty_path],
+ [Vytree.Nonexistent_path] from is_tag
+ *)
let rec aux acc p =
match acc, p with
| [], h :: tl -> aux (acc @ [h]) tl
@@ -520,30 +615,55 @@ let flag path =
List.mapi (fun k _ -> aux path k) path
let set_tag_data rtree ctree path =
- let ext = Vytree.exists ctree path in
+ (* raises:
+ [Vytree.Empty_path],
+ [Vytree.Nonexistent_path] from refpath; is_tag; and
+ alert exn Vytree.exists:
+ [Vytree.Empty_path] allow raise
+ alert exn Config_tree.is_tag_value; Config_tree.set_tag:
+ [Vytree.Empty_path] allow raise
+ [Vytree.Nonexistent_path] allow raise
+ *)
+ let ext = (Vytree.exists[@alert "-exn"]) ctree path in
match ext with
| false -> ctree
| true ->
let set_tag rt ct p =
let refp = refpath rt p in
- if is_tag rt refp && not (Config_tree.is_tag_value ct p)
- then Config_tree.set_tag ct p true
+ if is_tag rt refp && not ((Config_tree.is_tag_value[@alert "-exn"]) ct p)
+ then (Config_tree.set_tag[@alert "-exn"]) ct p true
else ct
in
List.fold_left (set_tag rtree) ctree (flag path)
let set_leaf_data rtree ctree path =
- let ext = Vytree.exists ctree path in
+ (* raises:
+ [Vytree.Empty_path],
+ [Vytree.Nonexistent_path] from refpath; is_leaf; and
+ alert exn Vytree.exists:
+ [Vytree.Empty_path] allow raise
+ alert exn Config_tree.set_leaf:
+ [Vytree.Empty_path] allow raise
+ [Vytree.Nonexistent_path] allow raise
+ *)
+ let ext = (Vytree.exists[@alert "-exn"]) ctree path in
match ext with
| false -> ctree
| true ->
let refp = refpath rtree path in
- if is_leaf rtree refp then Config_tree.set_leaf ctree path true
+ if is_leaf rtree refp then (Config_tree.set_leaf[@alert "-exn"]) ctree path true
else ctree
let get_ceil_data f reftree path =
+ (* raises:
+ [Vytree.Empty_path]
+ [Vytree.Nonexistent_path]
+ alert exn Vytree.get_data:
+ [Vytree.Empty_path] allow raise
+ [Vytree.Nonexistent_path] allow raise
+ *)
let data_of_path d p =
- let data = Vytree.get_data reftree p in
+ let data = (Vytree.get_data[@alert "-exn"]) reftree p in
match (f data) with
| Some d' -> Some d'
| None -> d
@@ -561,6 +681,20 @@ let get_ceil_data f reftree path =
Numbered comments list constraints as described above validate_path.
*)
let validate_tree_at_path validators_dir rt ct path value =
+ (* raises:
+ [Validation_error]
+ alert exn Vytree.exists:
+ [Vytree.Empty_path] ruled out in branch
+ alert exn Vytree.get:
+ [Vytree.Empty_path] ruled out in branch
+ [Vytree.Nonexistent_path] catch and raise Validation_error
+ alert exn Config_tree.is_tag;
+ Config_tree.is_tag_value;
+ Vytree.get_data;
+ Config_tree.is_leaf:
+ [Vytree.Empty_path] ruled out
+ [Vytree.Nonexistent_path] ruled out
+ *)
if Util.is_empty path then ()
else
let show_path p =
@@ -570,13 +704,13 @@ let validate_tree_at_path validators_dir rt ct path value =
(* 6. It's a node that is neither leaf nor tag value with a name that
doesn't exist in the reference tree
*)
- if not (Vytree.exists rt refp) then
+ if not ((Vytree.exists[@alert "-exn"]) rt refp) then
let msg = Printf.sprintf "Path %s is not in reference tree\n" (show_path path)
in raise (Validation_error msg)
else
let node =
try
- Vytree.get ct path
+ (Vytree.get[@alert "-exn"]) ct path
with Vytree.Nonexistent_path ->
let msg = Printf.sprintf "Path %s is not in config file\n" (show_path path)
in raise (Validation_error msg)
@@ -586,7 +720,7 @@ let validate_tree_at_path validators_dir rt ct path value =
let ct_data = Vytree.data_of_node node in
let values = ct_data.Config_tree.values in
let values_empty = Util.is_empty values in
- if Config_tree.is_tag ct path then
+ if (Config_tree.is_tag[@alert "-exn"]) ct path then
(* 1. It's a tag node without a child *)
if childless then
let msg =
@@ -594,8 +728,8 @@ let validate_tree_at_path validators_dir rt ct path value =
in raise (Validation_error msg)
else ()
else
- if (Config_tree.is_tag_value ct path) then
- let rt_data = Vytree.get_data rt (refpath rt (Util.drop_last path)) in
+ if ((Config_tree.is_tag_value[@alert "-exn"]) ct path) then
+ let rt_data = (Vytree.get_data[@alert "-exn"]) rt (refpath rt (Util.drop_last path)) in
let tag_value =
match (Util.get_last path) with
| Some v -> v
@@ -613,8 +747,8 @@ let validate_tree_at_path validators_dir rt ct path value =
let ret = format_out [show_path path; out; rt_data.constraint_error_message]
in raise (Validation_error ret)
else
- if Config_tree.is_leaf ct path then
- let rt_data = Vytree.get_data rt (refpath rt path) in
+ if (Config_tree.is_leaf[@alert "-exn"]) ct path then
+ let rt_data = (Vytree.get_data[@alert "-exn"]) rt (refpath rt path) in
(* 4. It's a valueless leaf node with a value *)
if is_valueless rt refp then
if not values_empty then
@@ -656,6 +790,17 @@ let validate_tree_at_path validators_dir rt ct path value =
let validate_tree_filter dir rt ct =
(* validate and filter invalid paths *)
+ (* catches:
+ [Validation_error] from validate_tree_at_path
+ alert exn Config_tree.delete; Config_tree.prune_delete:
+ [Vytree.Empty_path] not possible as validate_tree_at_path ignores
+ [Vytree.Nonexistent_path] not possible as extant in tree
+ alert exn Vytree.exists:
+ [Vytree.Empty_path] not possible as non-empty in branch
+ alert exn Vytree.get_data:
+ [Vytree.Empty_path] not possible as non-empty in branch
+ [Vytree.Nonexistent_path] not possible in fold_tree_with_path
+ *)
let try_validate (p, (ctree, out)) value =
let q = List.rev p in
try
@@ -663,8 +808,8 @@ let validate_tree_filter dir rt ct =
(p, (ctree, out))
with Validation_error x ->
let ct' =
- Config_tree.delete ctree q value |>
- (fun c -> Config_tree.prune_delete c q)
+ (Config_tree.delete[@alert "-exn"]) ctree q value |>
+ (fun c -> (Config_tree.prune_delete[@alert "-exn"]) c q)
in
(p, (ct', out ^ x))
in
@@ -674,10 +819,10 @@ let validate_tree_filter dir rt ct =
else
let q = List.rev p in
(* the path may have been removed in previous iteration *)
- if not (Vytree.exists ctree q) then
+ if not ((Vytree.exists[@alert "-exn"]) ctree q) then
(p, (ctree, out))
else
- let data = Vytree.get_data ct q in
+ let data = (Vytree.get_data[@alert "-exn"]) ct q in
let values = data.Config_tree.values in
match values with
| [] ->
@@ -692,6 +837,9 @@ let validate_tree_filter dir rt ct =
tree, out
let validate_tree dir rt ct =
+ (* raises:
+ [Validation_error] from validate_tree_at_path
+ *)
let _, out = validate_tree_filter dir rt ct in
out
diff --git a/src/reference_tree.mli b/src/reference_tree.mli
index 1a72ad9..42d9021 100644
--- a/src/reference_tree.mli
+++ b/src/reference_tree.mli
@@ -50,45 +50,78 @@ val default_data : ref_node_data
val default : t
val load_from_xml : t -> string -> t
+[@@alert exn "Reference_tree.Bad_interface_definition"]
val find_xml_child : string -> Xml_light_types.xml -> Xml_light_types.xml option
val validate_path : string -> t -> string list -> unit
+[@@alert exn "Reference_tree.Validation_error"]
val validate_tree_filter : string -> t -> Config_tree.t -> Config_tree.t * string
val validate_tree : string -> t -> Config_tree.t -> string
+[@@alert exn "Reference_tree.Validation_error"]
val split_path : t -> string list -> string list * string option
val is_multi : t -> string list -> bool
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val is_hidden : t -> string list -> bool
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val is_secret : t -> string list -> bool
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val is_tag : t -> string list -> bool
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val is_leaf : t -> string list -> bool
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val is_valueless : t -> string list -> bool
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val get_owner : t -> string list -> string option
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val get_priority : t -> string list -> string option
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val get_help_string : t -> string list -> string
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val get_value_help : t -> string list -> (string * string) list
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val get_completion_data : t -> string list -> (node_type * bool * string) list
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val refpath : t -> string list -> string list
-
-val get_ceil_data : (ref_node_data -> string option) -> t -> string list -> string option
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val set_tag_data : t -> Config_tree.t -> string list -> Config_tree.t
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val set_leaf_data : t -> Config_tree.t -> string list -> Config_tree.t
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
+
+val get_ceil_data : (ref_node_data -> string option) -> t -> string list -> string option
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val render_json : t -> string
diff --git a/src/tree_alg.ml b/src/tree_alg.ml
index 23af99d..a734285 100644
--- a/src/tree_alg.ml
+++ b/src/tree_alg.ml
@@ -30,12 +30,26 @@ module Alg (D: Data) (T: Tree with module D = D) = struct
let find_child n c = Vytree.find n (Vytree.name_of_node c)
- let insert_child n c = Vytree.insert ~position:Vytree.Lexical ~children:(Vytree.children_of_node c) n [(Vytree.name_of_node c)] (Vytree.data_of_node c)
+ let insert_child n c =
+ (* alert exn Vytree.insert:
+ [Vytree.Empty_path] not possible as called on name_of_node for existing child
+ [Not_found] not possible for postion=Lexical
+ [Vytree.Duplicate_child] not possible as find_child is None
+ [Vytree.Insert_error] not possible as no intermediary nodes
+ *)
+ (Vytree.insert[@alert "-exn"]) ~position:Vytree.Lexical ~children:(Vytree.children_of_node c) n [(Vytree.name_of_node c)] (Vytree.data_of_node c)
let replace_child n c =
- Vytree.replace n c
+ (* alert exn Vytree.replace:
+ [Not_found] not possible as child name already present
+ *)
+ (Vytree.replace[@alert "-exn"]) n c
let rec tree_union s t f =
+ (* raises:
+ [Incompatible_union]
+ [Nonexistent_child]
+ *)
if (Vytree.name_of_node s) <> (Vytree.name_of_node t) then
raise Incompatible_union
else
@@ -44,14 +58,16 @@ module Alg (D: Data) (T: Tree with module D = D) = struct
let t_c = find_child t c in
match s_c, t_c with
| Some child, None ->
- insert_child t child
+ insert_child t child
| None, Some _ -> t
| Some u, Some v ->
if (Vytree.data_of_node u <> Vytree.data_of_node v) then
replace_child t (tree_union u (f u v) f)
else
replace_child t (tree_union u v f)
- | None, None -> raise Nonexistent_child
+ | None, None ->
+ (* Not possible in fold over union_of_children *)
+ raise Nonexistent_child
in
List.fold_left (fun x c -> child_of_union s x c) t (union_of_children s t)
end
diff --git a/src/tree_alg.mli b/src/tree_alg.mli
new file mode 100644
index 0000000..6a59fc0
--- /dev/null
+++ b/src/tree_alg.mli
@@ -0,0 +1,217 @@
+exception Incompatible_union
+exception Nonexistent_child
+
+module type Data = sig type t end
+
+module type Tree = sig module D : Data type t = D.t Vytree.t end
+
+module Tree_impl :
+ functor (D : Data) ->
+ sig module D : sig type t = D.t end type t = D.t Vytree.t end
+
+module Alg :
+ functor (D : Data)
+ (T : sig module D : sig type t = D.t end type t = D.t Vytree.t end) ->
+ sig
+ module TreeOrd :
+ sig
+ type t = T.t
+ val compare : 'a Vytree.t -> 'b Vytree.t -> int
+ end
+ module SetT :
+ sig
+ type elt = TreeOrd.t
+ type t = Set.Make(TreeOrd).t
+ val empty : t
+ val is_empty : t -> bool
+ val mem : elt -> t -> bool
+ val add : elt -> t -> t
+ val singleton : elt -> t
+ val remove : elt -> t -> t
+ val union : t -> t -> t
+ val inter : t -> t -> t
+ val disjoint : t -> t -> bool
+ val diff : t -> t -> t
+ val compare : t -> t -> int
+ val equal : t -> t -> bool
+ val subset : t -> t -> bool
+ val iter : (elt -> unit) -> t -> unit
+ val map : (elt -> elt) -> t -> t
+ val fold : (elt -> 'a -> 'a) -> t -> 'a -> 'a
+ val for_all : (elt -> bool) -> t -> bool
+ val exists : (elt -> bool) -> t -> bool
+ val filter : (elt -> bool) -> t -> t
+ val filter_map : (elt -> elt option) -> t -> t
+ val partition : (elt -> bool) -> t -> t * t
+ val cardinal : t -> int
+ val elements : t -> elt list
+ val min_elt : t -> elt
+ val min_elt_opt : t -> elt option
+ val max_elt : t -> elt
+ val max_elt_opt : t -> elt option
+ val choose : t -> elt
+ val choose_opt : t -> elt option
+ val split : elt -> t -> t * bool * t
+ val find : elt -> t -> elt
+ val find_opt : elt -> t -> elt option
+ val find_first : (elt -> bool) -> t -> elt
+ val find_first_opt : (elt -> bool) -> t -> elt option
+ val find_last : (elt -> bool) -> t -> elt
+ val find_last_opt : (elt -> bool) -> t -> elt option
+ val of_list : elt list -> t
+ val to_seq_from : elt -> t -> elt Seq.t
+ val to_seq : t -> elt Seq.t
+ val to_rev_seq : t -> elt Seq.t
+ val add_seq : elt Seq.t -> t -> t
+ val of_seq : elt Seq.t -> t
+ end
+ val union_of_children : D.t Vytree.t -> D.t Vytree.t -> SetT.elt list
+ val find_child : 'a Vytree.t -> 'b Vytree.t -> 'a Vytree.t option
+ val insert_child : 'a Vytree.t -> 'a Vytree.t -> 'a Vytree.t
+ val replace_child : 'a Vytree.t -> 'a Vytree.t -> 'a Vytree.t
+ val tree_union :
+ D.t Vytree.t ->
+ D.t Vytree.t ->
+ (D.t Vytree.t -> D.t Vytree.t -> D.t Vytree.t) -> D.t Vytree.t
+ end
+
+module ConfigData : sig type t = Config_tree.config_node_data end
+
+module RefData : sig type t = Reference_tree.ref_node_data end
+
+module ConfigAlg :
+ sig
+ module TreeOrd :
+ sig
+ type t = Tree_impl(ConfigData).t
+ val compare : 'a Vytree.t -> 'b Vytree.t -> int
+ end
+ module SetT :
+ sig
+ type elt = TreeOrd.t
+ type t = Set.Make(TreeOrd).t
+ val empty : t
+ val is_empty : t -> bool
+ val mem : elt -> t -> bool
+ val add : elt -> t -> t
+ val singleton : elt -> t
+ val remove : elt -> t -> t
+ val union : t -> t -> t
+ val inter : t -> t -> t
+ val disjoint : t -> t -> bool
+ val diff : t -> t -> t
+ val compare : t -> t -> int
+ val equal : t -> t -> bool
+ val subset : t -> t -> bool
+ val iter : (elt -> unit) -> t -> unit
+ val map : (elt -> elt) -> t -> t
+ val fold : (elt -> 'a -> 'a) -> t -> 'a -> 'a
+ val for_all : (elt -> bool) -> t -> bool
+ val exists : (elt -> bool) -> t -> bool
+ val filter : (elt -> bool) -> t -> t
+ val filter_map : (elt -> elt option) -> t -> t
+ val partition : (elt -> bool) -> t -> t * t
+ val cardinal : t -> int
+ val elements : t -> elt list
+ val min_elt : t -> elt
+ val min_elt_opt : t -> elt option
+ val max_elt : t -> elt
+ val max_elt_opt : t -> elt option
+ val choose : t -> elt
+ val choose_opt : t -> elt option
+ val split : elt -> t -> t * bool * t
+ val find : elt -> t -> elt
+ val find_opt : elt -> t -> elt option
+ val find_first : (elt -> bool) -> t -> elt
+ val find_first_opt : (elt -> bool) -> t -> elt option
+ val find_last : (elt -> bool) -> t -> elt
+ val find_last_opt : (elt -> bool) -> t -> elt option
+ val of_list : elt list -> t
+ val to_seq_from : elt -> t -> elt Seq.t
+ val to_seq : t -> elt Seq.t
+ val to_rev_seq : t -> elt Seq.t
+ val add_seq : elt Seq.t -> t -> t
+ val of_seq : elt Seq.t -> t
+ end
+ val union_of_children :
+ ConfigData.t Vytree.t -> ConfigData.t Vytree.t -> TreeOrd.t list
+ val find_child : 'a Vytree.t -> 'b Vytree.t -> 'a Vytree.t option
+ val insert_child : 'a Vytree.t -> 'a Vytree.t -> 'a Vytree.t
+ val replace_child : 'a Vytree.t -> 'a Vytree.t -> 'a Vytree.t
+ val tree_union :
+ ConfigData.t Vytree.t ->
+ ConfigData.t Vytree.t ->
+ (ConfigData.t Vytree.t ->
+ ConfigData.t Vytree.t -> ConfigData.t Vytree.t) ->
+ ConfigData.t Vytree.t
+ [@@alert exn "Tree_alg.Incompatible_union"]
+ [@@alert exn "Tree_alg.Nonexistent_child"]
+ end
+
+module RefAlg :
+ sig
+ module TreeOrd :
+ sig
+ type t = Tree_impl(RefData).t
+ val compare : 'a Vytree.t -> 'b Vytree.t -> int
+ end
+ module SetT :
+ sig
+ type elt = TreeOrd.t
+ type t = Set.Make(TreeOrd).t
+ val empty : t
+ val is_empty : t -> bool
+ val mem : elt -> t -> bool
+ val add : elt -> t -> t
+ val singleton : elt -> t
+ val remove : elt -> t -> t
+ val union : t -> t -> t
+ val inter : t -> t -> t
+ val disjoint : t -> t -> bool
+ val diff : t -> t -> t
+ val compare : t -> t -> int
+ val equal : t -> t -> bool
+ val subset : t -> t -> bool
+ val iter : (elt -> unit) -> t -> unit
+ val map : (elt -> elt) -> t -> t
+ val fold : (elt -> 'a -> 'a) -> t -> 'a -> 'a
+ val for_all : (elt -> bool) -> t -> bool
+ val exists : (elt -> bool) -> t -> bool
+ val filter : (elt -> bool) -> t -> t
+ val filter_map : (elt -> elt option) -> t -> t
+ val partition : (elt -> bool) -> t -> t * t
+ val cardinal : t -> int
+ val elements : t -> elt list
+ val min_elt : t -> elt
+ val min_elt_opt : t -> elt option
+ val max_elt : t -> elt
+ val max_elt_opt : t -> elt option
+ val choose : t -> elt
+ val choose_opt : t -> elt option
+ val split : elt -> t -> t * bool * t
+ val find : elt -> t -> elt
+ val find_opt : elt -> t -> elt option
+ val find_first : (elt -> bool) -> t -> elt
+ val find_first_opt : (elt -> bool) -> t -> elt option
+ val find_last : (elt -> bool) -> t -> elt
+ val find_last_opt : (elt -> bool) -> t -> elt option
+ val of_list : elt list -> t
+ val to_seq_from : elt -> t -> elt Seq.t
+ val to_seq : t -> elt Seq.t
+ val to_rev_seq : t -> elt Seq.t
+ val add_seq : elt Seq.t -> t -> t
+ val of_seq : elt Seq.t -> t
+ end
+ val union_of_children :
+ RefData.t Vytree.t -> RefData.t Vytree.t -> TreeOrd.t list
+ val find_child : 'a Vytree.t -> 'b Vytree.t -> 'a Vytree.t option
+ val insert_child : 'a Vytree.t -> 'a Vytree.t -> 'a Vytree.t
+ val replace_child : 'a Vytree.t -> 'a Vytree.t -> 'a Vytree.t
+ val tree_union :
+ RefData.t Vytree.t ->
+ RefData.t Vytree.t ->
+ (RefData.t Vytree.t -> RefData.t Vytree.t -> RefData.t Vytree.t) ->
+ RefData.t Vytree.t
+ [@@alert exn "Tree_alg.Incompatible_union"]
+ [@@alert exn "Tree_alg.Nonexistent_child"]
+ end
diff --git a/src/value_checker.ml b/src/value_checker.ml
index c066088..c07d760 100644
--- a/src/value_checker.ml
+++ b/src/value_checker.ml
@@ -9,6 +9,9 @@ type value_constraint =
exception Bad_validator of string
let validate_value dir buf value_constraint value =
+ (* raises:
+ [Bad_validator]
+ *)
match value_constraint with
| Regex s ->
(try
@@ -44,6 +47,8 @@ let validate_value dir buf value_constraint value =
(* If no constraints given, consider it valid.
Otherwise consider it valid if it satisfies at least one constraint *)
let validate_any validators constraints value =
+ (* raises no error; catches [Bad_validator] from validate_value
+ *)
let buf = Buffer.create 4096 in
let validate_exists validators constraints value =
match constraints with
@@ -65,6 +70,8 @@ let validate_any validators constraints value =
(* If no constraints given, consider it valid.
Otherwise consider it valid if it satisfies all constraints *)
let validate_all validators constraints value =
+ (* raises no error; catches [Bad_validator] from validate_value
+ *)
let buf = Buffer.create 4096 in
let validate_forall validators constraints value =
match constraints with
diff --git a/src/value_checker.mli b/src/value_checker.mli
index d4ae516..8d888fd 100644
--- a/src/value_checker.mli
+++ b/src/value_checker.mli
@@ -8,6 +8,7 @@ type value_constraint =
exception Bad_validator of string
val validate_value : string -> Buffer.t -> value_constraint -> string -> bool
+[@@alert exn "Value_checker.Bad_validator"]
val validate_any : string -> value_constraint list -> string -> string option
diff --git a/src/vylist.mli b/src/vylist.mli
index 54c0806..76ec5ed 100644
--- a/src/vylist.mli
+++ b/src/vylist.mli
@@ -1,8 +1,18 @@
val find : ('a -> bool) -> 'a list -> 'a option
+
val remove : ('a -> bool) -> 'a list -> 'a list
+
val replace : ?force:bool -> ('a -> bool) -> 'a -> 'a list -> 'a list
+[@@alert exn "Not_found"]
+
val insert_before : ('a -> bool) -> 'a -> 'a list -> 'a list
+[@@alert exn "Not_found"]
+
val insert_after : ('a -> bool) -> 'a -> 'a list -> 'a list
+[@@alert exn "Not_found"]
+
val insert_compare : ('a -> 'a -> int) -> 'a -> 'a list -> 'a list
+
val complement : 'a list -> 'a list -> 'a list
+
val in_list : 'a list -> 'a -> bool
diff --git a/src/vytree.ml b/src/vytree.ml
index 0f6e24a..a65fe6f 100644
--- a/src/vytree.ml
+++ b/src/vytree.ml
@@ -20,13 +20,20 @@ let data_of_node node = node.data
let children_of_node node = node.children
let insert_immediate ?(position=Default) node name data children =
+ (* alert exn Vylist.insert_before; Vylist.insert_after:
+ [Not_found] allow raise
+ *)
let new_node = make_full data name children in
let children' =
match position with
| Default -> new_node :: node.children
| End -> node.children @ [new_node]
- | Before s -> Vylist.insert_before (fun x -> x.name = s) new_node node.children
- | After s -> Vylist.insert_after (fun x -> x.name = s) new_node node.children
+ | Before s ->
+ (* allow raise of Not_found *)
+ (Vylist.insert_before[@alert "-exn"]) (fun x -> x.name = s) new_node node.children
+ | After s ->
+ (* allow raise of Not_found *)
+ (Vylist.insert_after[@alert "-exn"]) (fun x -> x.name = s) new_node node.children
| Lexical ->
Vylist.insert_compare (fun x y -> Util.lexical_numeric_compare x.name y.name) new_node node.children
in { node with children = children' }
@@ -39,20 +46,35 @@ let adopt node child =
{ node with children = child :: node.children }
let replace node child =
+ (* alert exn Vylist.replace:
+ [Not_found] allow raise
+ *)
let children = node.children in
let name = child.name in
- let children' = Vylist.replace (fun x -> x.name = name) child children in
+ let children' =
+ (* allow raise of Not_found *)
+ (Vylist.replace[@alert "-exn"]) (fun x -> x.name = name) child children
+ in
{ node with children = children' }
let replace_full node child name =
+ (* alert exn Vylist.replace:
+ [Not_found] allow raise
+ *)
let children = node.children in
- let children' = Vylist.replace (fun x -> x.name = name) child children in
+ let children' =
+ (* allow raise of Not_found *)
+ (Vylist.replace[@alert "-exn"]) (fun x -> x.name = name) child children
+ in
{ node with children = children' }
let find node name =
Vylist.find (fun x -> x.name = name) node.children
let find_or_fail node name =
+ (* raises
+ [Nonexistent_path]
+ *)
let child = find node name in
match child with
| None -> raise Nonexistent_path
@@ -62,6 +84,10 @@ let list_children node =
List.map (fun x -> x.name) node.children
let rec do_with_child fn node path =
+ (* raises
+ [Nonexistent_path] from find_or_fail
+ [Empty_path]
+ *)
match path with
| [] -> raise Empty_path
| [name] -> fn node name
@@ -71,6 +97,12 @@ let rec do_with_child fn node path =
replace node new_node
let rec insert ?(position=Default) ?(children=[]) node path data =
+ (* raises
+ [Not_found] from insert_immediate
+ [Empty_path]
+ [Duplicate_child]
+ [Insert_error]
+ *)
match path with
| [] -> raise Empty_path
| [name] ->
@@ -89,10 +121,17 @@ let rec insert ?(position=Default) ?(children=[]) node path data =
raise (Insert_error s)
let insert_maybe ?(position=Default) node path data =
+ (* raises
+ [Empty_path],
+ [Not_found],
+ [Insert_error] from insert
+ *)
try insert ~position:position node path data
with Duplicate_child -> node
let sorted_children_of_node cmp node =
+ (* raises no exn, as find_or_fail cannot fail
+ *)
let names = list_children node in
let names = List.sort cmp names in
List.map (find_or_fail node) names
@@ -154,6 +193,13 @@ let delete node path =
do_with_child delete_immediate node path
let rename node path newname =
+ (* raises
+ [Not_found] from replace_full
+ [Nonexistent_child] from find_or_fail; do_with_child
+ [Empty_path]
+ *)
+ if Util.is_empty path then raise Empty_path
+ else
let rename_immediate newname' node' name' =
let child = find_or_fail node' name' in
let child = { child with name=newname' } in
@@ -172,14 +218,26 @@ let insert_or_update ?(position=Default) node path data =
with Duplicate_child -> update node path data
let rec get node path =
+ (* raises
+ [Empty_path],
+ [Nonexistent_path] from find_or_fail
+ *)
match path with
| [] -> raise Empty_path
| [name] -> find_or_fail node name
| name :: names -> get (find_or_fail node name) names
-let get_data node path = data_of_node @@ get node path
+let get_data node path =
+ (* raises
+ [Empty_path],
+ [Nonexistent_path] from get
+ *)
+ data_of_node @@ get node path
let exists node path =
+ (* raises
+ [Empty_path] from get
+ *)
try ignore (get node path); true
with Nonexistent_path -> false
@@ -195,20 +253,38 @@ let get_existent_path node path =
in List.rev (aux node path [])
let children_of_path node path =
+ (* raises
+ [Empty_path],
+ [Nonexistent_path] from get
+ *)
let node' = get node path in
list_children node'
let copy node old_path new_path =
+ (* raises
+ [Empty_path] from exists
+ [Nonexistent_path] from get
+ [Insert_error] from insert
+ *)
if exists node new_path then raise Duplicate_child else
let child = get node old_path in
insert ~position:End ~children:child.children node new_path child.data
let move node path position =
+ (* raises
+ [Empty_path],
+ [Nonexistent_path] from get; delete
+ [Not_found],
+ [Insert_error] from insert
+ *)
let child = get node path in
let node = delete node path in
insert ~position:position ~children:child.children node path child.data
let is_terminal_path node path =
+ (* raises
+ [Empty_path] from get
+ *)
try
let n = get node path in
match (children_of_node n) with
diff --git a/src/vytree.mli b/src/vytree.mli
index cce169c..c23f1a7 100644
--- a/src/vytree.mli
+++ b/src/vytree.mli
@@ -15,48 +15,84 @@ val data_of_node : 'a t -> 'a
val children_of_node : 'a t -> 'a t list
val find : 'a t -> string -> 'a t option
-val find_or_fail : 'a t -> string -> 'a t
val adopt : 'a t -> 'a t -> 'a t
val replace : 'a t -> 'a t -> 'a t
+[@@alert exn "Not_found"]
val insert : ?position:position -> ?children:('a t list) -> 'a t -> string list -> 'a -> 'a t
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Not_found possible if position Before/After"]
+[@@alert exn "Vytree.Duplicate_child"]
+[@@alert exn "Vytree.Insert_error"]
val insert_maybe : ?position:position -> 'a t -> string list -> 'a -> 'a t
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Not_found possible if position Before/After"]
+[@@alert exn "Vytree.Insert_error"]
val insert_or_update : ?position:position -> 'a t -> string list -> 'a -> 'a t
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Not_found possible if position Before/After"]
+[@@alert exn "Vytree.Insert_error"]
val insert_multi_level : ?position:position -> 'a -> 'a t -> string list -> string list -> 'a -> 'a t
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Not_found possible if position Before/After"]
+[@@alert exn "Vytree.Duplicate_child possible if path_remaining not complement"]
+[@@alert exn "Vytree.Insert_error possible if path_done existence not guaranteed"]
val merge_children : ('a -> 'a -> 'a) -> (string -> string -> int) -> 'a t -> 'a t
val delete : 'a t -> string list -> 'a t
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val update : 'a t -> string list -> 'a -> 'a t
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val rename : 'a t -> string list -> string -> 'a t
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Not_found"]
+[@@alert exn "Vytree.Nonexistent_path"]
val list_children : 'a t -> string list
val get : 'a t -> string list -> 'a t
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val get_existent_path : 'a t -> string list -> string list
val get_data : 'a t -> string list -> 'a
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val exists : 'a t -> string list -> bool
+[@@alert exn "Vytree.Empty_path"]
val children_of_path : 'a t -> string list -> string list
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
val sorted_children_of_node : (string -> string -> int) -> 'a t -> ('a t) list
val sort_children : (string -> string -> int) -> 'a t -> 'a t
val copy : 'a t -> string list -> string list -> 'a t
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
+[@@alert exn "Vytree.Insert_error"]
val move : 'a t -> string list -> position -> 'a t
+[@@alert exn "Vytree.Empty_path"]
+[@@alert exn "Vytree.Nonexistent_path"]
+[@@alert exn "Not_found possible if position Before/After"]
+[@@alert exn "Vytree.Insert_error"]
val is_terminal_path : 'a t -> string list -> bool
+[@@alert exn "Vytree.Empty_path"]
val fold_tree_with_path: (string list * 'acc -> 'b t -> string list * 'acc) -> string list * 'acc -> 'b t -> string list * 'acc