summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/curly_parser.mly51
-rw-r--r--src/vytree.ml7
-rw-r--r--src/vytree.mli2
3 files changed, 50 insertions, 10 deletions
diff --git a/src/curly_parser.mly b/src/curly_parser.mly
index 58c6067..7daa082 100644
--- a/src/curly_parser.mly
+++ b/src/curly_parser.mly
@@ -1,5 +1,25 @@
%{
open Config_tree
+
+ exception Duplicate_child of (string * string)
+
+ (* Used for checking if after merging immediate children,
+ any of them have duplicate children inside,
+ e.g. "interfaces { ethernet eth0 {...} ethernet eth0 {...} }" *)
+ let find_duplicate_children n =
+ let rec aux xs =
+ let xs = List.sort compare xs in
+ match xs with
+ | [] | [_] -> ()
+ | x :: x' :: xs ->
+ if x = x' then raise (Duplicate_child (Vytree.name_of_node n, x))
+ else aux (x' :: xs)
+ in
+ aux @@ Vytree.list_children n
+
+ (* When merging nodes with values, append values of subsequent nodes to the
+ first one *)
+ let merge_data l r = {l with values=(List.append l.values r.values)}
%}
%token <string> IDENTIFIER
@@ -43,7 +63,13 @@ node:
| comment = opt_comment; name = IDENTIFIER; LEFT_BRACE; children = list(node_content); RIGHT_BRACE
{
let node = Vytree.make_full {default_data with comment=comment} name [] in
- List.fold_left Vytree.adopt node (List.rev children) |> Vytree.merge_children
+ let node = List.fold_left Vytree.adopt node (List.rev children) |> Vytree.merge_children merge_data in
+ try
+ List.iter find_duplicate_children (Vytree.children_of_node node);
+ node
+ with
+ | Duplicate_child (child, dup) ->
+ failwith (Printf.sprintf "Node \"%s %s\" has two children named \"%s\"" name child dup)
}
;
@@ -52,15 +78,28 @@ tag_node:
{
let outer_node = Vytree.make_full default_data name [] in
let inner_node = Vytree.make_full {default_data with comment=comment} tag [] in
- let inner_node = List.fold_left Vytree.adopt inner_node (List.rev children) |> Vytree.merge_children
- in Vytree.adopt outer_node inner_node
+ let inner_node = List.fold_left Vytree.adopt inner_node (List.rev children) |> Vytree.merge_children merge_data in
+ let node = Vytree.adopt outer_node inner_node in
+ try
+ List.iter find_duplicate_children (Vytree.children_of_node inner_node);
+ node
+ with
+ | Duplicate_child (child, dup) ->
+ failwith (Printf.sprintf "Node \"%s %s %s\" has two children named \"%s\"" name tag child dup)
}
node_content: n = node { n } | n = leaf_node { n } | n = tag_node { n };
%public config:
- ns = list(node); EOF
- {
- let root = make "root" in List.fold_left Vytree.adopt root (List.rev ns) |> Vytree.merge_children
+ | ns = list(node); EOF
+ {
+ let root = make "root" in
+ let root = List.fold_left Vytree.adopt root (List.rev ns) |> Vytree.merge_children merge_data in
+ try
+ List.iter find_duplicate_children (Vytree.children_of_node root);
+ root
+ with
+ | Duplicate_child (child, dup) ->
+ failwith (Printf.sprintf "Node \"%s\" has two children named \"%s\"" child dup)
}
;
diff --git a/src/vytree.ml b/src/vytree.ml
index 74dbe45..156b326 100644
--- a/src/vytree.ml
+++ b/src/vytree.ml
@@ -92,16 +92,17 @@ let rec insert ?(position=Default) node path data =
may be normal and even expected, such as "ethernet eth0" and "ethernet eth1"
in the "curly" format.
*)
-let merge_children node =
+let merge_children merge_data node =
(* Given a node N and a list of nodes NS, find all nodes in NS that
have the same name as N and merge their children into N *)
- let rec merge_into n ns =
+ let rec merge_into n ns =
match ns with
| [] -> n
| n' :: ns' ->
if n.name = n'.name then
let children = List.append n.children n'.children in
- let n = {n with children=children} in
+ let data = merge_data n.data n'.data in
+ let n = {n with children=children; data=data} in
merge_into n ns'
else merge_into n ns'
in
diff --git a/src/vytree.mli b/src/vytree.mli
index 02d8edf..9bc8844 100644
--- a/src/vytree.mli
+++ b/src/vytree.mli
@@ -23,7 +23,7 @@ val insert : ?position:position -> 'a t -> string list -> 'a -> 'a t
val insert_multi_level : 'a -> 'a t -> string list -> string list -> 'a -> 'a t
-val merge_children : 'a t -> 'a t
+val merge_children : ('a -> 'a -> 'a) -> 'a t -> 'a t
val delete : 'a t -> string list -> 'a t