Legend:
Page
Library
Module
Module type
Parameter
Class
Class type
Source
Page
Library
Module
Module type
Parameter
Class
Class type
Source
simpleConfigOCaml.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 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277
(**************************************************************************) (* *) (* Typerex Libraries *) (* *) (* Copyright 2011-2017 OCamlPro SAS *) (* *) (* All rights reserved. This file is distributed under the terms of *) (* the GNU Lesser General Public License version 2.1, with the *) (* special exception on linking described in the file LICENSE. *) (* *) (**************************************************************************) open SimpleConfigTypes open Genlex let lexer = make_lexer ["="; "{"; "}"; "["; "]"; ";"; "("; ")"; ","; "."; "@"] let once_values = Hashtbl.create 13 let parse_config_file str = let rec parse_top options = match Stream.peek str with | Some (Ident s | String s) -> begin Stream.junk str; match Stream.next str with | Kwd "=" -> let v = parse_option () in parse_top ( (s,v) :: options) | _ -> failwith "Operator '=' expected" end | tok -> List.rev options, tok and parse_option () = match Stream.next str with | Ident s | String s -> StringValue s | Int i -> IntValue i | Float f -> FloatValue f | Char c -> StringValue (String.make 1 c) | Kwd "[" -> parse_list "]" [] | Kwd "(" -> parse_list ")" [] | Kwd "{" -> begin let (options, tok) = parse_top [] in match tok with | Some (Kwd "}") -> Stream.junk str; Module options | _ -> failwith "Symbol '}' expected" end | Kwd "@" -> begin match Stream.next str with | Int i -> let v = parse_once_value i in OnceValue v | _ -> failwith "expected int" end | _ -> failwith "expected value" and parse_once_value i = match Stream.next str with | Kwd "@" -> begin try Hashtbl.find once_values i with Not_found -> Printf.kprintf failwith "once value @%d@ is unknown" i end | Kwd "=" -> let v = parse_option () in Hashtbl.add once_values i v; v | _ -> failwith "operators '=' or '@' expected" and parse_list end_kwd values = match Stream.peek str with | None -> Printf.kprintf failwith "reached end of file before %s" end_kwd | Some (Kwd ( ";" | "," | ".") ) -> Stream.junk str; parse_list end_kwd values | Some (Kwd kwd) when kwd = end_kwd -> Stream.junk str; List (List.rev values) | _ -> let v = parse_option () in parse_list end_kwd (v :: values) in let (options, tok) = parse_top [] in match tok with | Some _ -> failwith "ident or string expected" | None -> options let parse filename ic = Hashtbl.clear once_values; let s = Stream.of_channel ic in let stream = lexer s in let list = try parse_config_file stream with | e -> raise (LoadError (filename, ParseError (Stream.count s, Printexc.to_string e))) in Hashtbl.clear once_values; list let exit_exn = Exit let once_values_counter = ref 0 let once_values_rev = Hashtbl.create 13 let reset () = once_values_counter := 0; Hashtbl.clear once_values_rev let safe_string s = if s = "" then "\"\"" else try match s.[0] with 'a'..'z' | 'A'..'Z' -> for i = 1 to String.length s - 1 do match s.[i] with 'a'..'z' | 'A'..'Z' | '_' | '0'..'9' -> () | _ -> raise exit_exn done; s | _ -> if Int64.to_string (Int64.of_string s) = s || string_of_float (float_of_string s) = s then s else raise exit_exn with _ -> Printf.sprintf "\"%s\"" (String.escaped s) let comment option_comment = let option_comment = Printf.sprintf "%s" option_comment in let lines = EzString.split option_comment '\n' in let max_length = ref 10 in List.iter (fun line -> let len = String.length line in if len > !max_length then max_length := len) lines; let max_length = if !max_length > 74 then 74 else !max_length in let spaces = String.make max_length ' ' in let lines = List.map (fun line -> let len = String.length line in if len < max_length then line ^ String.sub spaces 0 (max_length - len) else line) lines in Printf.sprintf "(* %s *)" (String.concat " *)\n(* " lines) let compact_string oc f = let b = Buffer.create 100 in f b; let s = Buffer.contents b in let b = Buffer.create 100 in let rec iter b i len s = if i < len then let c = s.[i] in if c = ' ' || c = '\n' || c = '\t' then begin iter_space b (i+1) len s end else begin Buffer.add_char b c; iter b (i+1) len s end and iter_space b i len s = if i < len then let c = s.[i] in if c = ' ' || c = '\n' || c = '\t' then begin iter_space b (i+1) len s end else begin Buffer.add_char b ' '; Buffer.add_char b c; iter b (i+1) len s end in iter b 0 (String.length s) s; let ss = Buffer.contents b in Buffer.add_string oc (if String.length ss < 80 then ss else s) let rec save_module with_help indent oc list = let subm = ref [] in List.iter (fun (name, help, value) -> match name with [] -> assert false | [name] -> if with_help && help <> "" then Printf.bprintf oc "\n%s\n" (comment help); Printf.bprintf oc "%s%s = " indent (safe_string name); save_value indent oc value; Printf.bprintf oc "\n" | m :: tail -> let p = try List.assoc m !subm with | Not_found -> let p = ref [] in subm := (m, p) :: !subm; p in p := (tail, help, value) :: !p) list; List.iter (fun (m, p) -> Printf.bprintf oc "%s%s = {\n" indent (safe_string m); save_module with_help (indent ^ " ") oc !p; Printf.bprintf oc "%s}\n" indent) !subm and save_list indent oc list = match list with [] -> () | [v] -> save_value indent oc v | v :: tail -> save_value indent oc v; Printf.bprintf oc ", "; save_list indent oc tail and save_list_nl indent oc list = match list with [] -> () | [v] -> Printf.bprintf oc "\n%s" indent; save_value indent oc v | v :: tail -> Printf.bprintf oc "\n%s" indent; save_value indent oc v; Printf.bprintf oc ";"; save_list_nl indent oc tail and save_value indent oc v = match v with StringValue s -> Printf.bprintf oc "%s" (safe_string s) | IntValue i -> Printf.bprintf oc "%d" i | FloatValue f -> Printf.bprintf oc "%F" f | List l -> compact_string oc (fun oc -> Printf.bprintf oc "["; save_list_nl (indent ^ " ") oc l; Printf.bprintf oc "\n%s]" indent) | DelayedValue f -> f oc indent | SmallList l -> Printf.bprintf oc "("; save_list (indent ^ " ") oc l; Printf.bprintf oc ")" | Module m -> compact_string oc (fun oc -> Printf.bprintf oc "{"; save_module_fields (indent ^ " ") oc m; Printf.bprintf oc "%s}" indent) | OnceValue v -> try let i = Hashtbl.find once_values_rev v in Printf.bprintf oc "@%Ld@" i with Not_found -> incr once_values_counter; let i = Int64.of_int !once_values_counter in Hashtbl.add once_values_rev v i; Printf.bprintf oc "@%Ld = " i; save_value indent oc v and save_module_fields indent oc m = match m with [] -> () | (name, v) :: tail -> Printf.bprintf oc "%s%s = " indent (safe_string name); save_value indent oc v; Printf.bprintf oc "\n"; save_module_fields indent oc tail let save_binding oc name value = Printf.bprintf oc "%s = " (safe_string name); save_value " " oc value; Printf.bprintf oc "\n" let save_module ~with_help ~indent buf list = save_module with_help indent buf list let save_value ~indent buf v = save_value indent buf v