diff options
Diffstat (limited to 'src/curly_parser.mly')
-rw-r--r-- | src/curly_parser.mly | 51 |
1 files changed, 45 insertions, 6 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) } ; |