package bcfg
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>
A boringly simpleconfiguration format
Install
dune-project
Dependency
Authors
Maintainers
Sources
bcfg-0.1.0.tbz
sha256=7c4862dc6f1bc77bf643881aaad4d59b718c8d5e8e206a63b6a2c532692f0d56
sha512=5c31155c41d6fb84133cbc9aa947a6a3e851acb562204412dd1310407e9b99c6d7619e5a0da77cc9f16268db2583daa5ede0f5db7e43a2057d31079d9fd4a17b
doc/src/bcfg.q/bcfgq.ml.html
Source file bcfgq.ml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155module Bcfg_query = Bcfg_query let error_msgf fmt = Format.kasprintf (fun msg -> Error (`Msg msg)) fmt (* An index ([foo[0]]) is lexed as a plain word: it is up to us to check that it is a valid number. The walk rejects the query upfront so that {!eval} never has to deal with an invalid (or overflowing) index. *) let rec validate_pattern = let open Bcfg_query in function | PWord _ | PAny -> Ok () | PEval e -> validate_expr e | PNot p -> validate_pattern p | PAnd (a, b) | POr (a, b) -> Result.bind (validate_pattern a) (fun () -> validate_pattern b) and validate_expr = let open Bcfg_query in function | EWord _ -> Ok () | EPattern p -> validate_pattern p | EGet_parameter (e, idx) -> begin match int_of_string_opt idx with | Some n when n >= 0 -> validate_expr e | _ -> Error (`Msg (Printf.sprintf "Invalid index %S in the query" idx)) end | EGet_subdirective (a, b) -> Result.bind (validate_expr a) (fun () -> validate_expr b) | EDirective (e, p) -> Result.bind (validate_expr e) (fun () -> validate_pattern p) | EParameter (p, e) | EChild (p, e) | ENot_parameter (p, e) | ENot_child (p, e) -> Result.bind (validate_pattern p) (fun () -> validate_expr e) let of_string str = let lexbuf = Lexing.from_string str in match Bcfg_query_parser.query Bcfg_query_lexer.token lexbuf with | query -> Result.bind (validate_expr query) (fun () -> Ok query) | exception Bcfg_query_parser.Error -> error_msgf "Invalid query: %S" str | exception Bcfg_query_lexer.Unexpected_character chr -> error_msgf "Invalid character %C in the query" chr | exception Bcfg_query_lexer.Unterminated_quote -> error_msgf "Unterminated quote in the query: %S" str let pp = Bcfg_query.pp_expr (* A query is [is_streamable] when it contains no [@(...)] substitution: such a query never looks outside the current directive's subtree, so it can be evaluated one top-level directive at a time (see {!Bcfg.Stream.to_directives}) without materialising the whole document. *) let rec eval_in_pattern = let open Bcfg_query in function | PWord _ | PAny -> false | PEval _ -> true | PNot p -> eval_in_pattern p | PAnd (a, b) | POr (a, b) -> eval_in_pattern a || eval_in_pattern b and eval_in_expr = let open Bcfg_query in function | EWord _ -> false | EPattern p -> eval_in_pattern p | EGet_parameter (e, _) -> eval_in_expr e | EGet_subdirective (a, b) -> eval_in_expr a || eval_in_expr b | EDirective (e, p) -> eval_in_expr e || eval_in_pattern p | EParameter (p, e) | EChild (p, e) | ENot_parameter (p, e) | ENot_child (p, e) -> eval_in_pattern p || eval_in_expr e let is_streamable query = not (eval_in_expr query) (* The string value of a directive, as used inside a [$(...)] substitution. As noted in the design, [$(foo.bar)] behaves like [foo.bar[0]]: the value is the first parameter, and falls back to the directive name when there is none (which is precisely what [\[0\]] produces). *) let value_of_directive { Bcfg.name; parameters; _ } = match parameters with p :: _ -> p | [] -> name (* [predicate] and [eval] are mutually recursive: a [$(...)] pattern evaluates an expression against [root] (the whole document, so it can reference any part of it) and matches a string against the resulting values. *) let rec predicate ~root pattern str = let open Bcfg_query in match pattern with | PWord word -> String.equal word str | PAny -> true | PEval expr -> let ds = eval ~root expr root in List.exists (fun d -> String.equal (value_of_directive d) str) ds | PNot p -> not (predicate ~root p str) | PAnd (a, b) -> predicate ~root a str && predicate ~root b str | POr (a, b) -> predicate ~root a str || predicate ~root b str and eval ~root query bcfg = let open Bcfg_query in match query with | EWord word -> let fn { Bcfg.name; _ } = name = word in List.filter fn bcfg | EGet_subdirective (a, b) -> let bcfg = eval ~root a bcfg in let fn { Bcfg.children; _ } = eval ~root b children in List.concat_map fn bcfg | EGet_parameter (a, idx) -> begin let bcfg = eval ~root a bcfg in (* [idx] was checked by [validate_expr]: it is a valid number. *) match int_of_string_opt idx with | None -> [] | Some idx -> let fn { Bcfg.parameters; children; _ } = match List.nth_opt parameters idx with | Some name -> Some { Bcfg.name; parameters = []; children } | None -> None in List.filter_map fn bcfg end | EDirective (a, p) -> let pred = predicate ~root p in let fn { Bcfg.name; _ } = pred name in let bcfg = eval ~root a bcfg in List.filter fn bcfg | EParameter (p, a) -> let pred = predicate ~root p in let fn { Bcfg.parameters; _ } = List.exists pred parameters in let bcfg = List.filter fn bcfg in eval ~root a bcfg | EChild (p, a) -> (* keep directives that contain a child whose name matches [p] *) let pred = predicate ~root p in let fn { Bcfg.children; _ } = List.exists (fun c -> pred c.Bcfg.name) children in let bcfg = List.filter fn bcfg in eval ~root a bcfg | ENot_parameter (p, a) -> (* anti-join: keep directives with NO parameter matching [p] *) let pred = predicate ~root p in let fn { Bcfg.parameters; _ } = not (List.exists pred parameters) in let bcfg = List.filter fn bcfg in eval ~root a bcfg | ENot_child (p, a) -> (* anti-join: keep directives with NO child matching [p] *) let pred = predicate ~root p in let fn { Bcfg.children; _ } = not (List.exists (fun c -> pred c.Bcfg.name) children) in let bcfg = List.filter fn bcfg in eval ~root a bcfg | EPattern p -> let pred = predicate ~root p in let fn { Bcfg.name; _ } = pred name in List.filter fn bcfg let eval query bcfg = eval ~root:bcfg query bcfg
sectionYPositions = computeSectionYPositions($el), 10)"
x-init="setTimeout(() => sectionYPositions = computeSectionYPositions($el), 10)"
>