objective categorical abstract machine language personal data server
at main 9.9 kB view raw
1(* parse lexicon json files into lexicon_types *) 2 3open Lexicon_types 4 5let get_string_opt key json = 6 match json with 7 | `Assoc pairs -> ( 8 match List.assoc_opt key pairs with Some (`String s) -> Some s | _ -> None ) 9 | _ -> 10 None 11 12let get_string key json = 13 match get_string_opt key json with 14 | Some s -> 15 s 16 | None -> 17 failwith ("missing required string field: " ^ key) 18 19let get_int_opt key json = 20 match json with 21 | `Assoc pairs -> ( 22 match List.assoc_opt key pairs with Some (`Int i) -> Some i | _ -> None ) 23 | _ -> 24 None 25 26let get_int key json = 27 match get_int_opt key json with 28 | Some i -> 29 i 30 | None -> 31 failwith ("missing required int field: " ^ key) 32 33let get_bool_opt key json = 34 match json with 35 | `Assoc pairs -> ( 36 match List.assoc_opt key pairs with Some (`Bool b) -> Some b | _ -> None ) 37 | _ -> 38 None 39 40let get_list_opt key json = 41 match json with 42 | `Assoc pairs -> ( 43 match List.assoc_opt key pairs with Some (`List l) -> Some l | _ -> None ) 44 | _ -> 45 None 46 47let get_string_list_opt key json = 48 match get_list_opt key json with 49 | Some l -> 50 Some (List.filter_map (function `String s -> Some s | _ -> None) l) 51 | None -> 52 None 53 54let get_int_list_opt key json = 55 match get_list_opt key json with 56 | Some l -> 57 Some (List.filter_map (function `Int i -> Some i | _ -> None) l) 58 | None -> 59 None 60 61let get_assoc key json = 62 match json with 63 | `Assoc pairs -> ( 64 match List.assoc_opt key pairs with 65 | Some (`Assoc _ as a) -> 66 Some a 67 | _ -> 68 None ) 69 | _ -> 70 None 71 72(* parse type definition from json *) 73let rec parse_type_def json : type_def = 74 let type_str = get_string "type" json in 75 match type_str with 76 | "string" -> 77 String 78 { format= get_string_opt "format" json 79 ; min_length= get_int_opt "minLength" json 80 ; max_length= get_int_opt "maxLength" json 81 ; min_graphemes= get_int_opt "minGraphemes" json 82 ; max_graphemes= get_int_opt "maxGraphemes" json 83 ; known_values= get_string_list_opt "knownValues" json 84 ; enum= get_string_list_opt "enum" json 85 ; const= get_string_opt "const" json 86 ; default= get_string_opt "default" json 87 ; description= get_string_opt "description" json } 88 | "integer" -> 89 Integer 90 { minimum= get_int_opt "minimum" json 91 ; maximum= get_int_opt "maximum" json 92 ; enum= get_int_list_opt "enum" json 93 ; const= get_int_opt "const" json 94 ; default= get_int_opt "default" json 95 ; description= get_string_opt "description" json } 96 | "boolean" -> 97 Boolean 98 { const= get_bool_opt "const" json 99 ; default= get_bool_opt "default" json 100 ; description= get_string_opt "description" json } 101 | "bytes" -> 102 Bytes 103 { min_length= get_int_opt "minLength" json 104 ; max_length= get_int_opt "maxLength" json 105 ; description= get_string_opt "description" json } 106 | "blob" -> 107 Blob 108 { accept= get_string_list_opt "accept" json 109 ; max_size= get_int_opt "maxSize" json 110 ; description= get_string_opt "description" json } 111 | "cid-link" -> 112 CidLink {description= get_string_opt "description" json} 113 | "array" -> 114 let items_json = 115 match get_assoc "items" json with 116 | Some j -> 117 j 118 | None -> 119 failwith "array type missing items" 120 in 121 Array 122 { items= parse_type_def items_json 123 ; min_length= get_int_opt "minLength" json 124 ; max_length= get_int_opt "maxLength" json 125 ; description= get_string_opt "description" json } 126 | "object" -> 127 Object (parse_object_spec json) 128 | "ref" -> 129 Ref 130 { ref_= get_string "ref" json 131 ; description= get_string_opt "description" json } 132 | "union" -> 133 Union 134 { refs= 135 ( match get_string_list_opt "refs" json with 136 | Some l -> 137 l 138 | None -> 139 [] ) 140 ; closed= get_bool_opt "closed" json 141 ; description= get_string_opt "description" json } 142 | "token" -> 143 Token {description= get_string_opt "description" json} 144 | "unknown" -> 145 Unknown {description= get_string_opt "description" json} 146 | "query" -> 147 Query (parse_query_spec json) 148 | "procedure" -> 149 Procedure (parse_procedure_spec json) 150 | "subscription" -> 151 Subscription (parse_subscription_spec json) 152 | "record" -> 153 Record (parse_record_spec json) 154 | t -> 155 failwith ("unknown type: " ^ t) 156 157and parse_object_spec json : object_spec = 158 let properties = 159 match get_assoc "properties" json with 160 | Some (`Assoc pairs) -> 161 List.map 162 (fun (name, prop_json) -> 163 let type_def = parse_type_def prop_json in 164 let description = get_string_opt "description" prop_json in 165 (name, {type_def; description}) ) 166 pairs 167 | _ -> 168 [] 169 in 170 { properties 171 ; required= get_string_list_opt "required" json 172 ; nullable= get_string_list_opt "nullable" json 173 ; description= get_string_opt "description" json } 174 175and parse_params_spec json : params_spec = 176 let properties = 177 match get_assoc "properties" json with 178 | Some (`Assoc pairs) -> 179 List.map 180 (fun (name, prop_json) -> 181 let type_def = parse_type_def prop_json in 182 let description = get_string_opt "description" prop_json in 183 (name, {type_def; description}) ) 184 pairs 185 | _ -> 186 [] 187 in 188 { properties 189 ; required= get_string_list_opt "required" json 190 ; description= get_string_opt "description" json } 191 192and parse_body_def json : body_def = 193 { encoding= get_string "encoding" json 194 ; schema= 195 ( match get_assoc "schema" json with 196 | Some j -> 197 Some (parse_type_def j) 198 | None -> 199 None ) 200 ; description= get_string_opt "description" json } 201 202and parse_error_def json : error_def = 203 {name= get_string "name" json; description= get_string_opt "description" json} 204 205and parse_query_spec json : query_spec = 206 let parameters = 207 match get_assoc "parameters" json with 208 | Some j -> 209 Some (parse_params_spec j) 210 | None -> 211 None 212 in 213 let output = 214 match get_assoc "output" json with 215 | Some j -> 216 Some (parse_body_def j) 217 | None -> 218 None 219 in 220 let errors = 221 match get_list_opt "errors" json with 222 | Some l -> 223 Some 224 (List.map 225 (function 226 | `Assoc _ as j -> 227 parse_error_def j 228 | _ -> 229 failwith "invalid error def" ) 230 l ) 231 | None -> 232 None 233 in 234 {parameters; output; errors; description= get_string_opt "description" json} 235 236and parse_procedure_spec json : procedure_spec = 237 let parameters = 238 match get_assoc "parameters" json with 239 | Some j -> 240 Some (parse_params_spec j) 241 | None -> 242 None 243 in 244 let input = 245 match get_assoc "input" json with 246 | Some j -> 247 Some (parse_body_def j) 248 | None -> 249 None 250 in 251 let output = 252 match get_assoc "output" json with 253 | Some j -> 254 Some (parse_body_def j) 255 | None -> 256 None 257 in 258 let errors = 259 match get_list_opt "errors" json with 260 | Some l -> 261 Some 262 (List.map 263 (function 264 | `Assoc _ as j -> 265 parse_error_def j 266 | _ -> 267 failwith "invalid error def" ) 268 l ) 269 | None -> 270 None 271 in 272 { parameters 273 ; input 274 ; output 275 ; errors 276 ; description= get_string_opt "description" json } 277 278and parse_subscription_spec json : subscription_spec = 279 let parameters = 280 match get_assoc "parameters" json with 281 | Some j -> 282 Some (parse_params_spec j) 283 | None -> 284 None 285 in 286 let message = 287 match get_assoc "message" json with 288 | Some j -> 289 Some (parse_body_def j) 290 | None -> 291 None 292 in 293 let errors = 294 match get_list_opt "errors" json with 295 | Some l -> 296 Some 297 (List.map 298 (function 299 | `Assoc _ as j -> 300 parse_error_def j 301 | _ -> 302 failwith "invalid error def" ) 303 l ) 304 | None -> 305 None 306 in 307 {parameters; message; errors; description= get_string_opt "description" json} 308 309and parse_record_spec json : record_spec = 310 let key = get_string "key" json in 311 let record_json = 312 match get_assoc "record" json with 313 | Some j -> 314 j 315 | None -> 316 failwith "record type missing record field" 317 in 318 { key 319 ; record= parse_object_spec record_json 320 ; description= get_string_opt "description" json } 321 322(* parse complete lexicon document *) 323let parse_lexicon_doc json : lexicon_doc = 324 let lexicon = get_int "lexicon" json in 325 let id = get_string "id" json in 326 let revision = get_int_opt "revision" json in 327 let description = get_string_opt "description" json in 328 let defs = 329 match get_assoc "defs" json with 330 | Some (`Assoc pairs) -> 331 List.map 332 (fun (name, def_json) -> {name; type_def= parse_type_def def_json}) 333 pairs 334 | _ -> 335 [] 336 in 337 {lexicon; id; revision; description; defs} 338 339(* parse lexicon file *) 340let parse_file path : parse_result = 341 try 342 let json = Yojson.Safe.from_file path in 343 Ok (parse_lexicon_doc json) 344 with 345 | Yojson.Json_error e -> 346 Error ("JSON parse error: " ^ e) 347 | Failure e -> 348 Error ("Parse error: " ^ e) 349 | e -> 350 Error ("Unexpected error: " ^ Printexc.to_string e) 351 352(* parse json string *) 353let parse_string content : parse_result = 354 try 355 let json = Yojson.Safe.from_string content in 356 Ok (parse_lexicon_doc json) 357 with 358 | Yojson.Json_error e -> 359 Error ("JSON parse error: " ^ e) 360 | Failure e -> 361 Error ("Parse error: " ^ e) 362 | e -> 363 Error ("Unexpected error: " ^ Printexc.to_string e)