diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/curly_parser.mly | 51 | ||||
-rw-r--r-- | src/vytree.ml | 7 | ||||
-rw-r--r-- | src/vytree.mli | 2 |
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 |