Parent Directory
|
Revision Log
[r2004-12-25 20:39:15 by afrisch] Default values for record fields Original author: afrisch Date: 2004-12-25 20:39:15+00:00
| 1 | abate | 237 | (* TODO: |
| 2 | abate | 276 | - rewrite type-checking of operators to propagate constraint |
| 3 | abate | 278 | - optimize computation of pattern free variables |
| 4 | - check whether it is worth using recursive hash-consing internally | ||
| 5 | abate | 276 | *) |
| 6 | abate | 237 | |
| 7 | abate | 677 | open Location |
| 8 | open Ast | ||
| 9 | open Ident | ||
| 10 | abate | 276 | |
| 11 | abate | 786 | let debug_schema = false |
| 12 | |||
| 13 | abate | 320 | let warning loc msg = |
| 14 | abate | 695 | Format.fprintf !Location.warning_ppf "Warning %a:@\n%a%s@." |
| 15 | abate | 522 | Location.print_loc (loc,`Full) |
| 16 | Location.html_hilight (loc,`Full) | ||
| 17 | abate | 320 | msg |
| 18 | |||
| 19 | abate | 1190 | exception NonExhaustive of Types.descr |
| 20 | exception Constraint of Types.descr * Types.descr | ||
| 21 | exception ShouldHave of Types.descr * string | ||
| 22 | exception ShouldHave2 of Types.descr * string * Types.descr | ||
| 23 | exception WrongLabel of Types.descr * label | ||
| 24 | exception UnboundId of id * bool | ||
| 25 | exception UnboundExtId of Types.CompUnit.t * id | ||
| 26 | exception Error of string | ||
| 27 | |||
| 28 | abate | 1238 | |
| 29 | exception Warning of string * Types.t | ||
| 30 | |||
| 31 | abate | 1190 | let raise_loc loc exn = raise (Location (loc,`Full,exn)) |
| 32 | let raise_loc_str loc ofs exn = raise (Location (loc,`Char ofs,exn)) | ||
| 33 | let error loc msg = raise_loc loc (Error msg) | ||
| 34 | |||
| 35 | abate | 686 | type item = |
| 36 | | Type of Types.t | ||
| 37 | abate | 691 | | Val of Types.t |
| 38 | abate | 686 | |
| 39 | abate | 1096 | module UEnv = Map.Make(U) |
| 40 | |||
| 41 | abate | 691 | type t = { |
| 42 | abate | 686 | ids : item Env.t; |
| 43 | abate | 713 | ns: Ns.table; |
| 44 | abate | 1096 | cu: Types.CompUnit.t UEnv.t; |
| 45 | abate | 1190 | schemas: string UEnv.t |
| 46 | abate | 677 | } |
| 47 | abate | 542 | |
| 48 | abate | 698 | let hash _ = failwith "Typer.hash" |
| 49 | let compare _ _ = failwith "Typer.compare" | ||
| 50 | let dump ppf _ = failwith "Typer.dump" | ||
| 51 | let equal _ _ = failwith "Typer.equal" | ||
| 52 | let check _ = failwith "Typer.check" | ||
| 53 | abate | 691 | |
| 54 | (* TODO: filter out builtin defs ? *) | ||
| 55 | abate | 705 | let serialize_item s = function |
| 56 | | Type t -> Serialize.Put.bits 1 s 0; Types.serialize s t | ||
| 57 | | Val t -> Serialize.Put.bits 1 s 1; Types.serialize s t | ||
| 58 | |||
| 59 | abate | 691 | let serialize s env = |
| 60 | abate | 705 | Serialize.Put.env Id.serialize serialize_item Env.iter s env.ids; |
| 61 | abate | 713 | Ns.serialize_table s env.ns |
| 62 | abate | 691 | |
| 63 | abate | 705 | let deserialize_item s = match Serialize.Get.bits 1 s with |
| 64 | | 0 -> Type (Types.deserialize s) | ||
| 65 | | 1 -> Val (Types.deserialize s) | ||
| 66 | | _ -> assert false | ||
| 67 | |||
| 68 | abate | 691 | let deserialize s = |
| 69 | abate | 1190 | let ids = Serialize.Get.env Id.deserialize deserialize_item Env.add Env.empty s in |
| 70 | abate | 691 | let ns = Ns.deserialize_table s in |
| 71 | abate | 1190 | { ids = ids; ns = ns; cu = UEnv.empty; schemas = UEnv.empty } |
| 72 | abate | 691 | |
| 73 | |||
| 74 | abate | 686 | let empty_env = { |
| 75 | ids = Env.empty; | ||
| 76 | abate | 713 | ns = Ns.empty_table; |
| 77 | abate | 1096 | cu = UEnv.empty; |
| 78 | abate | 1190 | schemas = UEnv.empty |
| 79 | abate | 686 | } |
| 80 | |||
| 81 | abate | 713 | let from_comp_unit = ref (fun cu -> assert false) |
| 82 | |||
| 83 | abate | 723 | let enter_cu x cu env = |
| 84 | abate | 1096 | { env with cu = UEnv.add x cu env.cu } |
| 85 | abate | 723 | |
| 86 | abate | 1096 | let find_cu x env = |
| 87 | try UEnv.find x env.cu | ||
| 88 | with Not_found -> Types.CompUnit.mk x | ||
| 89 | abate | 723 | |
| 90 | |||
| 91 | abate | 1190 | let enter_schema x uri env = |
| 92 | { env with schemas = UEnv.add x uri env.schemas } | ||
| 93 | let find_schema x env = | ||
| 94 | try UEnv.find x env.schemas | ||
| 95 | with Not_found -> raise (Error (Printf.sprintf "%s: no such schema" (U.get_str x))) | ||
| 96 | |||
| 97 | abate | 686 | let enter_type id t env = |
| 98 | { env with ids = Env.add id (Type t) env.ids } | ||
| 99 | let enter_types l env = | ||
| 100 | { env with ids = | ||
| 101 | List.fold_left (fun accu (id,t) -> Env.add id (Type t) accu) env.ids l } | ||
| 102 | let find_type id env = | ||
| 103 | match Env.find id env.ids with | ||
| 104 | | Type t -> t | ||
| 105 | abate | 691 | | Val _ -> raise Not_found |
| 106 | abate | 686 | |
| 107 | abate | 723 | let find_type_global loc cu id env = |
| 108 | abate | 1096 | let cu = find_cu cu env in |
| 109 | abate | 713 | let env = !from_comp_unit cu in |
| 110 | find_type id env | ||
| 111 | |||
| 112 | abate | 686 | let enter_value id t env = |
| 113 | abate | 691 | { env with ids = Env.add id (Val t) env.ids } |
| 114 | abate | 686 | let enter_values l env = |
| 115 | { env with ids = | ||
| 116 | abate | 691 | List.fold_left (fun accu (id,t) -> Env.add id (Val t) accu) env.ids l } |
| 117 | abate | 1238 | let enter_values_dummy l env = |
| 118 | { env with ids = | ||
| 119 | List.fold_left (fun accu id -> Env.add id (Val Types.empty) accu) env.ids l } | ||
| 120 | abate | 686 | let find_value id env = |
| 121 | match Env.find id env.ids with | ||
| 122 | abate | 691 | | Val t -> t |
| 123 | abate | 686 | | _ -> raise Not_found |
| 124 | abate | 713 | let find_value_global cu id env = |
| 125 | let env = !from_comp_unit cu in | ||
| 126 | find_value id env | ||
| 127 | abate | 686 | |
| 128 | abate | 692 | let value_name_ok id env = |
| 129 | try match Env.find id env.ids with | ||
| 130 | | Val t -> true | ||
| 131 | | _ -> false | ||
| 132 | with Not_found -> true | ||
| 133 | abate | 686 | |
| 134 | abate | 695 | let iter_values env f = |
| 135 | Env.iter (fun x -> | ||
| 136 | function Val t -> f x t; | ||
| 137 | | _ -> ()) env.ids | ||
| 138 | abate | 692 | |
| 139 | abate | 713 | |
| 140 | abate | 956 | let register_types cu env = |
| 141 | let prefix = U.concat (Types.CompUnit.value cu) (U.mk ":") in | ||
| 142 | Env.iter (fun x -> | ||
| 143 | function | ||
| 144 | | Type t -> | ||
| 145 | let n = U.concat prefix (Id.value x) in | ||
| 146 | Types.Print.register_global n t | ||
| 147 | | _ -> ()) env.ids | ||
| 148 | abate | 713 | |
| 149 | abate | 956 | |
| 150 | abate | 677 | (* Namespaces *) |
| 151 | abate | 542 | |
| 152 | abate | 686 | let set_ns_table_for_printer env = |
| 153 | abate | 713 | Ns.InternalPrinter.set_table env.ns |
| 154 | abate | 686 | |
| 155 | abate | 713 | let get_ns_table tenv = tenv.ns |
| 156 | abate | 542 | |
| 157 | abate | 686 | let enter_ns p ns env = |
| 158 | abate | 713 | { env with ns = Ns.add_prefix p ns env.ns } |
| 159 | abate | 686 | |
| 160 | abate | 677 | let protect_error_ns loc f x = |
| 161 | try f x | ||
| 162 | with Ns.UnknownPrefix ns -> | ||
| 163 | raise_loc_generic loc | ||
| 164 | ("Undefined namespace prefix " ^ (U.to_string ns)) | ||
| 165 | abate | 542 | |
| 166 | abate | 677 | let parse_atom env loc t = |
| 167 | abate | 713 | let (ns,l) = protect_error_ns loc (Ns.map_tag env.ns) t in |
| 168 | abate | 677 | Atoms.V.mk ns l |
| 169 | |||
| 170 | let parse_ns env loc ns = | ||
| 171 | abate | 713 | protect_error_ns loc (Ns.map_prefix env.ns) ns |
| 172 | abate | 5 | |
| 173 | abate | 677 | let parse_label env loc t = |
| 174 | abate | 713 | let (ns,l) = protect_error_ns loc (Ns.map_attr env.ns) t in |
| 175 | abate | 677 | LabelPool.mk (ns,l) |
| 176 | abate | 5 | |
| 177 | abate | 677 | let parse_record env loc f r = |
| 178 | let r = List.map (fun (l,x) -> (parse_label env loc l, f x)) r in | ||
| 179 | LabelMap.from_list (fun _ _ -> raise_loc_generic loc "Duplicated record field") r | ||
| 180 | abate | 140 | |
| 181 | abate | 677 | let rec const env loc = function |
| 182 | | LocatedExpr (loc,e) -> const env loc e | ||
| 183 | | Pair (x,y) -> Types.Pair (const env loc x, const env loc y) | ||
| 184 | | Xml (x,y) -> Types.Xml (const env loc x, const env loc y) | ||
| 185 | | RecordLitt x -> Types.Record (parse_record env loc (const env loc) x) | ||
| 186 | | String (i,j,s,c) -> Types.String (i,j,s,const env loc c) | ||
| 187 | | Atom t -> Types.Atom (parse_atom env loc t) | ||
| 188 | | Integer i -> Types.Integer i | ||
| 189 | | Char c -> Types.Char c | ||
| 190 | abate | 722 | | Const c -> c |
| 191 | abate | 677 | | _ -> raise_loc_generic loc "This should be a scalar or structured constant" |
| 192 | |||
| 193 | (* I. Transform the abstract syntax of types and patterns into | ||
| 194 | the internal form *) | ||
| 195 | |||
| 196 | abate | 5 | |
| 197 | abate | 1190 | (* Schema *) |
| 198 | abate | 9 | |
| 199 | abate | 1190 | let is_registered_schema env s = UEnv.mem s env.schemas |
| 200 | |||
| 201 | (* uri -> schema binding *) | ||
| 202 | abate | 786 | let schemas = State.ref "Typer.schemas" (Hashtbl.create 3) |
| 203 | abate | 508 | |
| 204 | abate | 501 | let schema_types = State.ref "Typer.schema_types" (Hashtbl.create 51) |
| 205 | let schema_elements = State.ref "Typer.schema_elements" (Hashtbl.create 51) | ||
| 206 | abate | 508 | let schema_attributes = State.ref "Typer.schema_attributes" (Hashtbl.create 51) |
| 207 | abate | 757 | let schema_attribute_groups = |
| 208 | State.ref "Typer.schema_attribute_groups" (Hashtbl.create 51) | ||
| 209 | let schema_model_groups = | ||
| 210 | State.ref "Typer.schema_model_groups" (Hashtbl.create 51) | ||
| 211 | abate | 501 | |
| 212 | abate | 1190 | |
| 213 | |||
| 214 | abate | 786 | (* raise Not_found *) |
| 215 | |||
| 216 | abate | 1190 | |
| 217 | let get_schema_fwd = ref (fun _ -> assert false) | ||
| 218 | |||
| 219 | let find_schema_descr_uri kind uri name = | ||
| 220 | abate | 786 | try |
| 221 | abate | 1190 | ignore (!get_schema_fwd uri); |
| 222 | let elt () = Hashtbl.find !schema_elements (uri, name) in | ||
| 223 | let typ () = Hashtbl.find !schema_types (uri, name) in | ||
| 224 | let att () = Hashtbl.find !schema_attributes (uri, name) in | ||
| 225 | let att_group () = Hashtbl.find !schema_attribute_groups (uri, name) in | ||
| 226 | let mod_group () = Hashtbl.find !schema_model_groups (uri, name) in | ||
| 227 | let rec do_try n = function | ||
| 228 | | [] -> raise Not_found | ||
| 229 | | f :: rem -> (try f () with Not_found -> do_try n rem) | ||
| 230 | in | ||
| 231 | match kind with | ||
| 232 | | Some `Element -> do_try "element" [ elt ] | ||
| 233 | | Some `Type -> do_try "type" [ typ ] | ||
| 234 | | Some `Attribute -> do_try "atttribute" [ att ] | ||
| 235 | | Some `Attribute_group -> do_try "attribute group" [ att_group ] | ||
| 236 | | Some `Model_group -> do_try "model group" [ mod_group ] | ||
| 237 | | None -> | ||
| 238 | (* policy for unqualified schema component resolution. This order should | ||
| 239 | * be consistent with Schema_component.get_component *) | ||
| 240 | do_try "component" [ elt; typ; att; att_group; mod_group ] | ||
| 241 | with Not_found -> | ||
| 242 | abate | 862 | raise (Error (Printf.sprintf "No %s named '%s' found in schema '%s'" |
| 243 | abate | 1190 | (Schema_common.string_of_component_kind kind) (U.get_str name) uri)) |
| 244 | abate | 786 | |
| 245 | abate | 1190 | let find_schema_descr env kind schema name = |
| 246 | let uri = find_schema schema env in | ||
| 247 | find_schema_descr_uri kind uri name | ||
| 248 | |||
| 249 | |||
| 250 | abate | 278 | (* Eliminate Recursion, propagate Sequence Capture Variables *) |
| 251 | abate | 5 | |
| 252 | abate | 278 | let rec seq_vars accu = function |
| 253 | abate | 1328 | | Epsilon | Elem _ | Guard _ -> accu |
| 254 | abate | 278 | | Seq (r1,r2) | Alt (r1,r2) -> seq_vars (seq_vars accu r1) r2 |
| 255 | | Star r | WeakStar r -> seq_vars accu r | ||
| 256 | | SeqCapture (v,r) -> seq_vars (IdSet.add v accu) r | ||
| 257 | abate | 71 | |
| 258 | abate | 677 | (* We use two intermediate representation from AST types/patterns |
| 259 | to internal ones: | ||
| 260 | |||
| 261 | AST -(1)-> derecurs -(2)-> slot -(3)-> internal | ||
| 262 | |||
| 263 | (1) eliminate recursion, schema, | ||
| 264 | propagate sequence capture variables, keep regexps | ||
| 265 | |||
| 266 | (2) stratify, detect ill-formed recursion, compile regexps | ||
| 267 | |||
| 268 | (3) check additional constraints on types / patterns; | ||
| 269 | deep (recursive) hash-consing | ||
| 270 | *) | ||
| 271 | |||
| 272 | abate | 278 | type derecurs_slot = { |
| 273 | ploc : Location.loc; | ||
| 274 | pid : int; | ||
| 275 | mutable ploop : bool; | ||
| 276 | abate | 677 | mutable pdescr : derecurs; |
| 277 | abate | 278 | } and derecurs = |
| 278 | abate | 677 | | PDummy |
| 279 | abate | 278 | | PAlias of derecurs_slot |
| 280 | | PType of Types.descr | ||
| 281 | | POr of derecurs * derecurs | ||
| 282 | | PAnd of derecurs * derecurs | ||
| 283 | | PDiff of derecurs * derecurs | ||
| 284 | | PTimes of derecurs * derecurs | ||
| 285 | | PXml of derecurs * derecurs | ||
| 286 | | PArrow of derecurs * derecurs | ||
| 287 | | POptional of derecurs | ||
| 288 | abate | 1368 | | PRecord of bool * (derecurs * derecurs option) label_map |
| 289 | abate | 278 | | PCapture of id |
| 290 | | PConstant of id * Types.const | ||
| 291 | | PRegexp of derecurs_regexp * derecurs | ||
| 292 | and derecurs_regexp = | ||
| 293 | | PEpsilon | ||
| 294 | | PElem of derecurs | ||
| 295 | abate | 1328 | | PGuard of derecurs |
| 296 | abate | 278 | | PSeq of derecurs_regexp * derecurs_regexp |
| 297 | | PAlt of derecurs_regexp * derecurs_regexp | ||
| 298 | | PStar of derecurs_regexp | ||
| 299 | | PWeakStar of derecurs_regexp | ||
| 300 | abate | 71 | |
| 301 | abate | 1328 | let pregexp r q = PRegexp (r,q) |
| 302 | abate | 677 | |
| 303 | abate | 1328 | |
| 304 | abate | 677 | type descr = |
| 305 | | IDummy | ||
| 306 | | IType of Types.descr | ||
| 307 | | IOr of descr * descr | ||
| 308 | | IAnd of descr * descr | ||
| 309 | | IDiff of descr * descr | ||
| 310 | | ITimes of slot * slot | ||
| 311 | | IXml of slot * slot | ||
| 312 | | IArrow of slot * slot | ||
| 313 | | IOptional of descr | ||
| 314 | abate | 1368 | | IRecord of bool * (slot * descr option) label_map |
| 315 | abate | 677 | | ICapture of id |
| 316 | | IConstant of id * Types.const | ||
| 317 | and slot = { | ||
| 318 | mutable fv : fv option; | ||
| 319 | mutable hash : int option; | ||
| 320 | mutable rank1: int; mutable rank2: int; | ||
| 321 | mutable gen1 : int; mutable gen2: int; | ||
| 322 | mutable d : descr; | ||
| 323 | abate | 529 | } |
| 324 | abate | 677 | |
| 325 | abate | 529 | |
| 326 | abate | 677 | let counter = ref 0 |
| 327 | let mk_derecurs_slot loc = | ||
| 328 | incr counter; | ||
| 329 | { ploop = false; ploc = loc; pid = !counter; pdescr = PDummy } | ||
| 330 | |||
| 331 | let mk_slot () = | ||
| 332 | { d=IDummy; fv=None; hash=None; rank1=0; rank2=0; gen1=0; gen2=0 } | ||
| 333 | |||
| 334 | |||
| 335 | (* This environment is used in phase (1) to eliminate recursion *) | ||
| 336 | type penv = { | ||
| 337 | abate | 691 | penv_tenv : t; |
| 338 | abate | 677 | penv_derec : derecurs_slot Env.t; |
| 339 | } | ||
| 340 | |||
| 341 | let penv tenv = { penv_tenv = tenv; penv_derec = Env.empty } | ||
| 342 | |||
| 343 | abate | 278 | let rec hash_derecurs = function |
| 344 | abate | 677 | | PDummy -> assert false |
| 345 | abate | 426 | | PAlias s -> |
| 346 | s.pid | ||
| 347 | | PType t -> | ||
| 348 | abate | 653 | 1 + 17 * (Types.hash t) |
| 349 | abate | 426 | | POr (p1,p2) -> |
| 350 | 2 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2) | ||
| 351 | | PAnd (p1,p2) -> | ||
| 352 | 3 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2) | ||
| 353 | | PDiff (p1,p2) -> | ||
| 354 | 4 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2) | ||
| 355 | | PTimes (p1,p2) -> | ||
| 356 | 5 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2) | ||
| 357 | | PXml (p1,p2) -> | ||
| 358 | 6 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2) | ||
| 359 | | PArrow (p1,p2) -> | ||
| 360 | 7 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2) | ||
| 361 | | POptional p -> | ||
| 362 | 8 + 17 * (hash_derecurs p) | ||
| 363 | | PRecord (o,r) -> | ||
| 364 | abate | 1368 | (if o then 9 else 10) + 17 * (LabelMap.hash hash_derecurs_field r) |
| 365 | abate | 426 | | PCapture x -> |
| 366 | 11 + 17 * (Id.hash x) | ||
| 367 | | PConstant (x,c) -> | ||
| 368 | abate | 691 | 12 + 17 * (Id.hash x) + 257 * (Types.Const.hash c) |
| 369 | abate | 426 | | PRegexp (p,q) -> |
| 370 | 13 + 17 * (hash_derecurs_regexp p) + 257 * (hash_derecurs q) | ||
| 371 | abate | 1368 | and hash_derecurs_field = function |
| 372 | | (p, Some e) -> 1 + 17 * hash_derecurs p + 257 * hash_derecurs e | ||
| 373 | | (p, None) -> 2 + 17 * hash_derecurs p | ||
| 374 | abate | 278 | and hash_derecurs_regexp = function |
| 375 | abate | 426 | | PEpsilon -> |
| 376 | 1 | ||
| 377 | | PElem p -> | ||
| 378 | 2 + 17 * (hash_derecurs p) | ||
| 379 | | PSeq (p1,p2) -> | ||
| 380 | 3 + 17 * (hash_derecurs_regexp p1) + 257 * (hash_derecurs_regexp p2) | ||
| 381 | | PAlt (p1,p2) -> | ||
| 382 | 4 + 17 * (hash_derecurs_regexp p1) + 257 * (hash_derecurs_regexp p2) | ||
| 383 | | PStar p -> | ||
| 384 | 5 + 17 * (hash_derecurs_regexp p) | ||
| 385 | | PWeakStar p -> | ||
| 386 | 6 + 17 * (hash_derecurs_regexp p) | ||
| 387 | abate | 1328 | | PGuard p -> |
| 388 | 7 + 17 * (hash_derecurs p) | ||
| 389 | abate | 107 | |
| 390 | abate | 278 | let rec equal_derecurs p1 p2 = (p1 == p2) || match p1,p2 with |
| 391 | abate | 426 | | PAlias s1, PAlias s2 -> |
| 392 | s1 == s2 | ||
| 393 | | PType t1, PType t2 -> | ||
| 394 | abate | 653 | Types.equal t1 t2 |
| 395 | abate | 278 | | POr (p1,q1), POr (p2,q2) |
| 396 | | PAnd (p1,q1), PAnd (p2,q2) | ||
| 397 | | PDiff (p1,q1), PDiff (p2,q2) | ||
| 398 | | PTimes (p1,q1), PTimes (p2,q2) | ||
| 399 | | PXml (p1,q1), PXml (p2,q2) | ||
| 400 | abate | 426 | | PArrow (p1,q1), PArrow (p2,q2) -> |
| 401 | (equal_derecurs p1 p2) && (equal_derecurs q1 q2) | ||
| 402 | | POptional p1, POptional p2 -> | ||
| 403 | equal_derecurs p1 p2 | ||
| 404 | | PRecord (o1,r1), PRecord (o2,r2) -> | ||
| 405 | abate | 1368 | (o1 == o2) && (LabelMap.equal equal_derecurs_field r1 r2) |
| 406 | abate | 426 | | PCapture x1, PCapture x2 -> |
| 407 | Id.equal x1 x2 | ||
| 408 | | PConstant (x1,c1), PConstant (x2,c2) -> | ||
| 409 | abate | 691 | (Id.equal x1 x2) && (Types.Const.equal c1 c2) |
| 410 | abate | 426 | | PRegexp (p1,q1), PRegexp (p2,q2) -> |
| 411 | (equal_derecurs_regexp p1 p2) && (equal_derecurs q1 q2) | ||
| 412 | abate | 278 | | _ -> false |
| 413 | abate | 1368 | and equal_derecurs_field r1 r2 = match (r1,r2) with |
| 414 | | (p1,None),(p2,None) -> equal_derecurs p1 p2 | ||
| 415 | | (p1, Some e1), (p2, Some e2) -> equal_derecurs p1 p2 && equal_derecurs e1 e2 | ||
| 416 | | _ -> false | ||
| 417 | abate | 278 | and equal_derecurs_regexp r1 r2 = match r1,r2 with |
| 418 | abate | 426 | | PEpsilon, PEpsilon -> |
| 419 | true | ||
| 420 | | PElem p1, PElem p2 -> | ||
| 421 | equal_derecurs p1 p2 | ||
| 422 | abate | 1328 | | PGuard p1, PGuard p2 -> |
| 423 | equal_derecurs p1 p2 | ||
| 424 | abate | 278 | | PSeq (p1,q1), PSeq (p2,q2) |
| 425 | abate | 426 | | PAlt (p1,q1), PAlt (p2,q2) -> |
| 426 | (equal_derecurs_regexp p1 p2) && (equal_derecurs_regexp q1 q2) | ||
| 427 | abate | 278 | | PStar p1, PStar p2 |
| 428 | abate | 426 | | PWeakStar p1, PWeakStar p2 -> |
| 429 | equal_derecurs_regexp p1 p2 | ||
| 430 | abate | 278 | | _ -> false |
| 431 | abate | 5 | |
| 432 | abate | 278 | module DerecursTable = Hashtbl.Make( |
| 433 | struct | ||
| 434 | type t = derecurs | ||
| 435 | let hash = hash_derecurs | ||
| 436 | let equal = equal_derecurs | ||
| 437 | end | ||
| 438 | ) | ||
| 439 | abate | 5 | |
| 440 | abate | 278 | module RE = Hashtbl.Make( |
| 441 | struct | ||
| 442 | type t = derecurs_regexp * derecurs | ||
| 443 | abate | 426 | let hash (p,q) = |
| 444 | (hash_derecurs_regexp p) + 17 * (hash_derecurs q) | ||
| 445 | let equal (p1,q1) (p2,q2) = | ||
| 446 | (equal_derecurs_regexp p1 p2) && (equal_derecurs q1 q2) | ||
| 447 | abate | 278 | end |
| 448 | ) | ||
| 449 | abate | 71 | |
| 450 | abate | 277 | let gen = ref 0 |
| 451 | let rank = ref 0 | ||
| 452 | |||
| 453 | let rec hash_descr = function | ||
| 454 | abate | 677 | | IDummy -> assert false |
| 455 | abate | 653 | | IType x -> Types.hash x |
| 456 | abate | 277 | | IOr (d1,d2) -> 1 + 17 * (hash_descr d1) + 257 * (hash_descr d2) |
| 457 | | IAnd (d1,d2) -> 2 + 17 * (hash_descr d1) + 257 * (hash_descr d2) | ||
| 458 | | IDiff (d1,d2) -> 3 + 17 * (hash_descr d1) + 257 * (hash_descr d2) | ||
| 459 | | IOptional d -> 4 + 17 * (hash_descr d) | ||
| 460 | | ITimes (s1,s2) -> 5 + 17 * (hash_slot s1) + 257 * (hash_slot s2) | ||
| 461 | | IXml (s1,s2) -> 6 + 17 * (hash_slot s1) + 257 * (hash_slot s2) | ||
| 462 | | IArrow (s1,s2) -> 7 + 17 * (hash_slot s1) + 257 * (hash_slot s2) | ||
| 463 | abate | 1368 | | IRecord (o,r) -> (if o then 8 else 9) + 17 * (LabelMap.hash hash_descr_field r) |
| 464 | abate | 277 | | ICapture x -> 10 + 17 * (Id.hash x) |
| 465 | abate | 691 | | IConstant (x,y) -> 11 + 17 * (Id.hash x) + 257 * (Types.Const.hash y) |
| 466 | abate | 1368 | and hash_descr_field = function |
| 467 | | (d, Some e) -> 1 + 17 * hash_slot d + 257 * hash_descr e | ||
| 468 | | (d, None) -> 2 + 17 * hash_slot d | ||
| 469 | abate | 277 | and hash_slot s = |
| 470 | if s.gen1 = !gen then 13 * s.rank1 | ||
| 471 | else ( | ||
| 472 | incr rank; | ||
| 473 | s.rank1 <- !rank; s.gen1 <- !gen; | ||
| 474 | abate | 677 | hash_descr s.d |
| 475 | abate | 277 | ) |
| 476 | |||
| 477 | let rec equal_descr d1 d2 = | ||
| 478 | match (d1,d2) with | ||
| 479 | abate | 653 | | IType x1, IType x2 -> Types.equal x1 x2 |
| 480 | abate | 277 | | IOr (x1,y1), IOr (x2,y2) |
| 481 | | IAnd (x1,y1), IAnd (x2,y2) | ||
| 482 | | IDiff (x1,y1), IDiff (x2,y2) -> (equal_descr x1 x2) && (equal_descr y1 y2) | ||
| 483 | | IOptional x1, IOptional x2 -> equal_descr x1 x2 | ||
| 484 | | ITimes (x1,y1), ITimes (x2,y2) | ||
| 485 | | IXml (x1,y1), IXml (x2,y2) | ||
| 486 | | IArrow (x1,y1), IArrow (x2,y2) -> (equal_slot x1 x2) && (equal_slot y1 y2) | ||
| 487 | abate | 426 | | IRecord (o1,r1), IRecord (o2,r2) -> |
| 488 | abate | 1368 | (o1 = o2) && (LabelMap.equal equal_descr_field r1 r2) |
| 489 | abate | 277 | | ICapture x1, ICapture x2 -> Id.equal x1 x2 |
| 490 | abate | 426 | | IConstant (x1,y1), IConstant (x2,y2) -> |
| 491 | abate | 691 | (Id.equal x1 x2) && (Types.Const.equal y1 y2) |
| 492 | abate | 277 | | _ -> false |
| 493 | abate | 1368 | and equal_descr_field d1 d2 = match (d1,d2) with |
| 494 | | (d1,None),(d2,None) -> equal_slot d1 d2 | ||
| 495 | | (d1, Some e1), (d2, Some e2) -> equal_slot d1 d2 && equal_descr e1 e2 | ||
| 496 | | _ -> false | ||
| 497 | abate | 277 | and equal_slot s1 s2 = |
| 498 | ((s1.gen1 = !gen) && (s2.gen2 = !gen) && (s1.rank1 = s2.rank2)) | ||
| 499 | || | ||
| 500 | ((s1.gen1 <> !gen) && (s2.gen2 <> !gen) && ( | ||
| 501 | incr rank; | ||
| 502 | s1.rank1 <- !rank; s1.gen1 <- !gen; | ||
| 503 | s2.rank2 <- !rank; s2.gen2 <- !gen; | ||
| 504 | abate | 677 | equal_descr s1.d s2.d |
| 505 | abate | 277 | )) |
| 506 | |||
| 507 | abate | 677 | module SlotTable = Hashtbl.Make( |
| 508 | struct | ||
| 509 | type t = slot | ||
| 510 | |||
| 511 | let hash s = | ||
| 512 | match s.hash with | ||
| 513 | | Some h -> h | ||
| 514 | | None -> | ||
| 515 | incr gen; rank := 0; | ||
| 516 | let h = hash_slot s in | ||
| 517 | s.hash <- Some h; | ||
| 518 | h | ||
| 519 | |||
| 520 | let equal s1 s2 = | ||
| 521 | (s1 == s2) || | ||
| 522 | (incr gen; rank := 0; | ||
| 523 | let e = equal_slot s1 s2 in | ||
| 524 | (* if e then Printf.eprintf "Recursive hash-consing: Equal\n"; *) | ||
| 525 | e) | ||
| 526 | end) | ||
| 527 | |||
| 528 | |||
| 529 | abate | 1328 | let pempty = PType Types.empty |
| 530 | |||
| 531 | let por p1 p2 = | ||
| 532 | if p1 == pempty then p2 else | ||
| 533 | if p2 == pempty then p1 else | ||
| 534 | POr (p1,p2) | ||
| 535 | |||
| 536 | let pand p1 p2 = | ||
| 537 | if (p1 == pempty) || (p2 == pempty) then pempty else PAnd (p1,p2) | ||
| 538 | |||
| 539 | let rec remove_regexp r q = match r with | ||
| 540 | | PEpsilon -> | ||
| 541 | q | ||
| 542 | | PElem p -> | ||
| 543 | PTimes (p, q) | ||
| 544 | | PGuard p -> | ||
| 545 | pand p q | ||
| 546 | | PSeq (r1,r2) -> | ||
| 547 | remove_regexp r1 (remove_regexp r2 q) | ||
| 548 | | PAlt (r1,r2) -> | ||
| 549 | por (remove_regexp r1 q) (remove_regexp r2 q) | ||
| 550 | | PStar r -> | ||
| 551 | let x = mk_derecurs_slot noloc in | ||
| 552 | let res = POr (PAlias x, q) in | ||
| 553 | x.pdescr <- remove_regexp2 r res pempty; | ||
| 554 | res | ||
| 555 | | PWeakStar r -> | ||
| 556 | let x = mk_derecurs_slot noloc in | ||
| 557 | let res = POr (q, PAlias x) in | ||
| 558 | x.pdescr <- remove_regexp2 r res pempty; | ||
| 559 | res | ||
| 560 | |||
| 561 | and remove_regexp2 r q_nonempty q_empty = | ||
| 562 | if q_nonempty == q_empty then remove_regexp r q_empty | ||
| 563 | else match r with | ||
| 564 | | PEpsilon -> | ||
| 565 | q_empty | ||
| 566 | | PElem p -> | ||
| 567 | PTimes (p, q_nonempty) | ||
| 568 | | PGuard p -> | ||
| 569 | pand p q_empty | ||
| 570 | | PSeq (r1,r2) -> | ||
| 571 | remove_regexp2 r1 | ||
| 572 | (remove_regexp2 r2 q_nonempty q_nonempty) | ||
| 573 | (remove_regexp2 r2 q_nonempty q_empty) | ||
| 574 | | PAlt (r1,r2) -> | ||
| 575 | por | ||
| 576 | (remove_regexp2 r1 q_nonempty q_empty) | ||
| 577 | (remove_regexp2 r2 q_nonempty q_empty) | ||
| 578 | | PStar r -> | ||
| 579 | let x = mk_derecurs_slot noloc in | ||
| 580 | x.pdescr <- remove_regexp2 r (POr (PAlias x, q_nonempty)) pempty; | ||
| 581 | por (PAlias x) q_empty | ||
| 582 | | PWeakStar r -> | ||
| 583 | let x = mk_derecurs_slot noloc in | ||
| 584 | x.pdescr <- remove_regexp2 r (POr (q_nonempty, PAlias x)) pempty; | ||
| 585 | por q_empty (PAlias x) | ||
| 586 | |||
| 587 | abate | 677 | let rec derecurs env p = match p.descr with |
| 588 | abate | 1215 | | PatVar v -> derecurs_var env p.loc v |
| 589 | abate | 786 | | SchemaVar (kind, schema_name, component_name) -> |
| 590 | abate | 1190 | PType (find_schema_descr env.penv_tenv kind schema_name component_name) |
| 591 | abate | 677 | | Recurs (p,b) -> derecurs (derecurs_def env b) p |
| 592 | | Internal t -> PType t | ||
| 593 | | NsT ns -> PType (Types.atom (Atoms.any_in_ns (parse_ns env.penv_tenv p.loc ns))) | ||
| 594 | | Or (p1,p2) -> POr (derecurs env p1, derecurs env p2) | ||
| 595 | | And (p1,p2) -> PAnd (derecurs env p1, derecurs env p2) | ||
| 596 | | Diff (p1,p2) -> PDiff (derecurs env p1, derecurs env p2) | ||
| 597 | | Prod (p1,p2) -> PTimes (derecurs env p1, derecurs env p2) | ||
| 598 | | XmlT (p1,p2) -> PXml (derecurs env p1, derecurs env p2) | ||
| 599 | | Arrow (p1,p2) -> PArrow (derecurs env p1, derecurs env p2) | ||
| 600 | | Optional p -> POptional (derecurs env p) | ||
| 601 | abate | 1368 | | Record (o,r) -> |
| 602 | let aux = function | ||
| 603 | | (p,Some e) -> (derecurs env p, Some (derecurs env e)) | ||
| 604 | | (p,None) -> derecurs env p, None in | ||
| 605 | PRecord (o, parse_record env.penv_tenv p.loc aux r) | ||
| 606 | abate | 677 | | Constant (x,c) -> PConstant (x,const env.penv_tenv p.loc c) |
| 607 | | Cst c -> PType (Types.constant (const env.penv_tenv p.loc c)) | ||
| 608 | | Regexp (r,q) -> | ||
| 609 | let constant_nil t v = | ||
| 610 | PAnd (t, PConstant (v, Types.Atom Sequence.nil_atom)) in | ||
| 611 | let vars = seq_vars IdSet.empty r in | ||
| 612 | let q = IdSet.fold constant_nil (derecurs env q) vars in | ||
| 613 | let r = derecurs_regexp (fun p -> p) env r in | ||
| 614 | PRegexp (r, q) | ||
| 615 | abate | 1328 | (* Note: computing remove_regexp here is slower (because |
| 616 | of caching ?) *) | ||
| 617 | |||
| 618 | abate | 677 | and derecurs_regexp vars env = function |
| 619 | | Epsilon -> | ||
| 620 | PEpsilon | ||
| 621 | | Elem p -> | ||
| 622 | PElem (vars (derecurs env p)) | ||
| 623 | abate | 1328 | | Guard p -> |
| 624 | PGuard (vars (derecurs env p)) | ||
| 625 | abate | 677 | | Seq (p1,p2) -> |
| 626 | PSeq (derecurs_regexp vars env p1, derecurs_regexp vars env p2) | ||
| 627 | | Alt (p1,p2) -> | ||
| 628 | PAlt (derecurs_regexp vars env p1, derecurs_regexp vars env p2) | ||
| 629 | | Star p -> | ||
| 630 | PStar (derecurs_regexp vars env p) | ||
| 631 | | WeakStar p -> | ||
| 632 | PWeakStar (derecurs_regexp vars env p) | ||
| 633 | | SeqCapture (x,p) -> | ||
| 634 | derecurs_regexp (fun p -> PAnd (vars p, PCapture x)) env p | ||
| 635 | |||
| 636 | abate | 1215 | and derecurs_var env loc v = |
| 637 | match Ns.split_qname v with | ||
| 638 | | "", v -> | ||
| 639 | let v = ident v in | ||
| 640 | (try PAlias (Env.find v env.penv_derec) | ||
| 641 | with Not_found -> | ||
| 642 | try PType (find_type v env.penv_tenv) | ||
| 643 | with Not_found -> PCapture v) | ||
| 644 | | cu, v -> | ||
| 645 | try | ||
| 646 | let cu = U.mk cu in | ||
| 647 | PType (find_type_global loc cu (ident v) env.penv_tenv) | ||
| 648 | with Not_found -> | ||
| 649 | raise_loc_generic loc | ||
| 650 | ("Unbound external type " ^ cu ^ ":" ^ (U.to_string v)) | ||
| 651 | abate | 677 | |
| 652 | and derecurs_def env b = | ||
| 653 | let b = List.map (fun (v,p) -> (v,p,mk_derecurs_slot p.loc)) b in | ||
| 654 | let n = | ||
| 655 | List.fold_left (fun env (v,p,s) -> Env.add v s env) env.penv_derec b in | ||
| 656 | let env = { env with penv_derec = n } in | ||
| 657 | List.iter (fun (v,p,s) -> s.pdescr <- derecurs env p) b; | ||
| 658 | env | ||
| 659 | |||
| 660 | abate | 1328 | |
| 661 | abate | 277 | let rec fv_slot s = |
| 662 | match s.fv with | ||
| 663 | | Some x -> x | ||
| 664 | | None -> | ||
| 665 | if s.gen1 = !gen then IdSet.empty | ||
| 666 | abate | 677 | else (s.gen1 <- !gen; fv_descr s.d) |
| 667 | abate | 277 | and fv_descr = function |
| 668 | abate | 677 | | IDummy -> assert false |
| 669 | abate | 278 | | IType _ -> IdSet.empty |
| 670 | abate | 277 | | IOr (d1,d2) |
| 671 | | IAnd (d1,d2) | ||
| 672 | | IDiff (d1,d2) -> IdSet.cup (fv_descr d1) (fv_descr d2) | ||
| 673 | | IOptional d -> fv_descr d | ||
| 674 | | ITimes (s1,s2) | ||
| 675 | | IXml (s1,s2) | ||
| 676 | | IArrow (s1,s2) -> IdSet.cup (fv_slot s1) (fv_slot s2) | ||
| 677 | abate | 426 | | IRecord (o,r) -> |
| 678 | abate | 1368 | List.fold_left IdSet.cup IdSet.empty (LabelMap.map_to_list fv_field r) |
| 679 | abate | 277 | | ICapture x | IConstant (x,_) -> IdSet.singleton x |
| 680 | abate | 1368 | and fv_field = function |
| 681 | | (d,Some e) -> IdSet.cup (fv_slot d) (fv_descr e) | ||
| 682 | | (d,None) -> fv_slot d | ||
| 683 | abate | 278 | |
| 684 | abate | 1368 | |
| 685 | abate | 277 | let compute_fv s = |
| 686 | match s.fv with | ||
| 687 | | Some x -> () | ||
| 688 | | None -> | ||
| 689 | incr gen; | ||
| 690 | let x = fv_slot s in | ||
| 691 | s.fv <- Some x | ||
| 692 | |||
| 693 | abate | 656 | let check_no_capture loc s = |
| 694 | match IdSet.pick s with | ||
| 695 | | Some x -> | ||
| 696 | abate | 694 | raise_loc_generic loc ("Capture variable not allowed: " ^ (Ident.to_string x)) |
| 697 | abate | 656 | | None -> () |
| 698 | abate | 277 | |
| 699 | abate | 278 | let compile_slot_hash = DerecursTable.create 67 |
| 700 | let compile_hash = DerecursTable.create 67 | ||
| 701 | |||
| 702 | abate | 677 | let todo_defs = ref [] |
| 703 | let todo_fv = ref [] | ||
| 704 | abate | 278 | |
| 705 | let rec compile p = | ||
| 706 | try DerecursTable.find compile_hash p | ||
| 707 | abate | 277 | with Not_found -> |
| 708 | abate | 278 | let c = real_compile p in |
| 709 | DerecursTable.replace compile_hash p c; | ||
| 710 | c | ||
| 711 | and real_compile = function | ||
| 712 | abate | 677 | | PDummy -> assert false |
| 713 | abate | 278 | | PAlias v -> |
| 714 | if v.ploop then | ||
| 715 | raise_loc_generic v.ploc ("Unguarded recursion on type/pattern"); | ||
| 716 | v.ploop <- true; | ||
| 717 | abate | 677 | let r = compile v.pdescr in |
| 718 | abate | 278 | v.ploop <- false; |
| 719 | r | ||
| 720 | | PType t -> IType t | ||
| 721 | | POr (t1,t2) -> IOr (compile t1, compile t2) | ||
| 722 | | PAnd (t1,t2) -> IAnd (compile t1, compile t2) | ||
| 723 | | PDiff (t1,t2) -> IDiff (compile t1, compile t2) | ||
| 724 | | PTimes (t1,t2) -> ITimes (compile_slot t1, compile_slot t2) | ||
| 725 | | PXml (t1,t2) -> IXml (compile_slot t1, compile_slot t2) | ||
| 726 | | PArrow (t1,t2) -> IArrow (compile_slot t1, compile_slot t2) | ||
| 727 | | POptional t -> IOptional (compile t) | ||
| 728 | abate | 1368 | | PRecord (o,r) -> IRecord (o, LabelMap.map compile_field r) |
| 729 | abate | 278 | | PConstant (x,v) -> IConstant (x,v) |
| 730 | | PCapture x -> ICapture x | ||
| 731 | abate | 1328 | | PRegexp (r,q) -> compile (remove_regexp r q) |
| 732 | |||
| 733 | abate | 1368 | and compile_field = function |
| 734 | | (p, Some e) -> (compile_slot p, Some (compile e)) | ||
| 735 | | (p, None) -> (compile_slot p, None) | ||
| 736 | |||
| 737 | abate | 278 | and compile_slot p = |
| 738 | try DerecursTable.find compile_slot_hash p | ||
| 739 | with Not_found -> | ||
| 740 | abate | 677 | let s = mk_slot () in |
| 741 | todo_defs := (s,p) :: !todo_defs; | ||
| 742 | todo_fv := s :: !todo_fv; | ||
| 743 | abate | 278 | DerecursTable.add compile_slot_hash p s; |
| 744 | abate | 277 | s |
| 745 | abate | 278 | |
| 746 | abate | 277 | |
| 747 | abate | 677 | let timer_fv = Stats.Timer.create "Typer.fv" |
| 748 | abate | 277 | let rec flush_defs () = |
| 749 | abate | 677 | match !todo_defs with |
| 750 | | [] -> | ||
| 751 | Stats.Timer.start timer_fv; | ||
| 752 | List.iter compute_fv !todo_fv; | ||
| 753 | abate | 691 | todo_fv := []; |
| 754 | Stats.Timer.stop timer_fv () | ||
| 755 | abate | 677 | | (s,p)::t -> |
| 756 | todo_defs := t; | ||
| 757 | s.d <- compile p; | ||
| 758 | flush_defs () | ||
| 759 | abate | 277 | |
| 760 | let typ_nodes = SlotTable.create 67 | ||
| 761 | let pat_nodes = SlotTable.create 67 | ||
| 762 | |||
| 763 | let rec typ = function | ||
| 764 | | IType t -> t | ||
| 765 | | IOr (s1,s2) -> Types.cup (typ s1) (typ s2) | ||
| 766 | | IAnd (s1,s2) -> Types.cap (typ s1) (typ s2) | ||
| 767 | | IDiff (s1,s2) -> Types.diff (typ s1) (typ s2) | ||
| 768 | | ITimes (s1,s2) -> Types.times (typ_node s1) (typ_node s2) | ||
| 769 | | IXml (s1,s2) -> Types.xml (typ_node s1) (typ_node s2) | ||
| 770 | | IArrow (s1,s2) -> Types.arrow (typ_node s1) (typ_node s2) | ||
| 771 | | IOptional s -> Types.Record.or_absent (typ s) | ||
| 772 | abate | 1368 | | IRecord (o,r) -> Types.record' (o, LabelMap.map typ_field r) |
| 773 | abate | 677 | | IDummy | ICapture _ | IConstant (_,_) -> assert false |
| 774 | abate | 277 | |
| 775 | abate | 1368 | and typ_field = function |
| 776 | | (s, None) -> typ_node s | ||
| 777 | | (s, Some _) -> | ||
| 778 | raise (Patterns.Error "Or-else clauses are not allowed in types") | ||
| 779 | |||
| 780 | abate | 653 | and typ_node s : Types.Node.t = |
| 781 | abate | 277 | try SlotTable.find typ_nodes s |
| 782 | with Not_found -> | ||
| 783 | let x = Types.make () in | ||
| 784 | SlotTable.add typ_nodes s x; | ||
| 785 | abate | 677 | Types.define x (typ s.d); |
| 786 | abate | 277 | x |
| 787 | |||
| 788 | let rec pat d : Patterns.descr = | ||
| 789 | if IdSet.is_empty (fv_descr d) | ||
| 790 | then Patterns.constr (typ d) | ||
| 791 | else pat_aux d | ||
| 792 | |||
| 793 | and pat_aux = function | ||
| 794 | abate | 677 | | IDummy -> assert false |
| 795 | abate | 277 | | IOr (s1,s2) -> Patterns.cup (pat s1) (pat s2) |
| 796 | | IAnd (s1,s2) -> Patterns.cap (pat s1) (pat s2) | ||
| 797 | | IDiff (s1,s2) when IdSet.is_empty (fv_descr s2) -> | ||
| 798 | let s2 = Types.neg (typ s2) in | ||
| 799 | Patterns.cap (pat s1) (Patterns.constr s2) | ||
| 800 | | IDiff _ -> | ||
| 801 | abate | 677 | raise (Patterns.Error "Differences are not allowed in patterns") |
| 802 | abate | 277 | | ITimes (s1,s2) -> Patterns.times (pat_node s1) (pat_node s2) |
| 803 | | IXml (s1,s2) -> Patterns.xml (pat_node s1) (pat_node s2) | ||
| 804 | | IOptional _ -> | ||
| 805 | abate | 677 | raise (Patterns.Error "Optional fields are not allowed in record patterns") |
| 806 | abate | 277 | | IRecord (o,r) -> |
| 807 | let pats = ref [] in | ||
| 808 | abate | 1368 | let aux l = function |
| 809 | | (s,None) -> | ||
| 810 | if IdSet.is_empty (fv_slot s) then typ_node s | ||
| 811 | else | ||
| 812 | ( pats := Patterns.record l (pat_node s) :: !pats; | ||
| 813 | Types.any_node ) | ||
| 814 | | (s,Some e) -> | ||
| 815 | if IdSet.is_empty (fv_slot s) then | ||
| 816 | raise (Patterns.Error "Or-else clauses are not allowed in types") | ||
| 817 | else | ||
| 818 | ( pats := Patterns.cup | ||
| 819 | (Patterns.record l (pat_node s)) | ||
| 820 | (pat e) :: !pats; | ||
| 821 | Types.Record.any_or_absent_node ) | ||
| 822 | abate | 277 | in |
| 823 | let constr = Types.record' (o,LabelMap.mapi aux r) in | ||
| 824 | List.fold_left Patterns.cap (Patterns.constr constr) !pats | ||
| 825 | (* TODO: can avoid constr when o=true, and all fields have fv *) | ||
| 826 | | ICapture x -> Patterns.capture x | ||
| 827 | | IConstant (x,c) -> Patterns.constant x c | ||
| 828 | | IArrow _ -> | ||
| 829 | abate | 677 | raise (Patterns.Error "Arrows are not allowed in patterns") |
| 830 | abate | 277 | | IType _ -> assert false |
| 831 | |||
| 832 | and pat_node s : Patterns.node = | ||
| 833 | try SlotTable.find pat_nodes s | ||
| 834 | with Not_found -> | ||
| 835 | let x = Patterns.make (fv_slot s) in | ||
| 836 | abate | 640 | try |
| 837 | SlotTable.add pat_nodes s x; | ||
| 838 | abate | 677 | Patterns.define x (pat s.d); |
| 839 | abate | 640 | x |
| 840 | with exn -> SlotTable.remove pat_nodes s; raise exn | ||
| 841 | (* For the toplevel ... *) | ||
| 842 | abate | 431 | |
| 843 | abate | 677 | |
| 844 | abate | 1102 | module Ids = Set.Make(Id) |
| 845 | abate | 686 | let type_defs env b = |
| 846 | abate | 1102 | ignore |
| 847 | (List.fold_left | ||
| 848 | (fun seen (v,p) -> | ||
| 849 | if Ids.mem v seen then | ||
| 850 | raise_loc_generic p.loc | ||
| 851 | ("Multiple definitions for the type identifer " ^ | ||
| 852 | (Ident.to_string v)); | ||
| 853 | Ids.add v seen | ||
| 854 | ) Ids.empty b); | ||
| 855 | |||
| 856 | abate | 686 | let penv = derecurs_def (penv env) b in |
| 857 | let b = List.map (fun (v,p) -> (v,p,compile (derecurs penv p))) b in | ||
| 858 | abate | 529 | flush_defs (); |
| 859 | let b = | ||
| 860 | List.map | ||
| 861 | (fun (v,p,s) -> | ||
| 862 | abate | 656 | check_no_capture p.loc (fv_descr s); |
| 863 | abate | 529 | let t = typ s in |
| 864 | if (p.loc <> noloc) && (Types.is_empty t) then | ||
| 865 | warning p.loc | ||
| 866 | abate | 677 | ("This definition yields an empty type for " ^ (Ident.to_string v)); |
| 867 | abate | 529 | (v,t)) b in |
| 868 | abate | 677 | List.iter (fun (v,t) -> Types.Print.register_global (Id.value v) t) b; |
| 869 | abate | 686 | b |
| 870 | abate | 278 | |
| 871 | abate | 505 | |
| 872 | abate | 686 | let dump_types ppf env = |
| 873 | Env.iter (fun v -> | ||
| 874 | function | ||
| 875 | (Type _) -> Format.fprintf ppf " %a" Ident.print v | ||
| 876 | | _ -> ()) env.ids | ||
| 877 | abate | 786 | let dump_type ppf env name = |
| 878 | try | ||
| 879 | abate | 812 | (match Env.find (Ident.ident name) env.ids with |
| 880 | abate | 786 | | Type t -> Types.Print.print ppf t |
| 881 | | _ -> raise Not_found) | ||
| 882 | abate | 812 | with Not_found -> |
| 883 | raise (Error (Printf.sprintf "Type %s not found" (U.get_str name))) | ||
| 884 | abate | 529 | |
| 885 | abate | 1190 | let dump_schema_type ppf env (k, s, n) = |
| 886 | let uri = find_schema s env in | ||
| 887 | let descr = find_schema_descr_uri k uri n in | ||
| 888 | abate | 786 | Types.Print.print ppf descr |
| 889 | |||
| 890 | abate | 686 | let dump_ns ppf env = |
| 891 | abate | 713 | Ns.dump_table ppf env.ns |
| 892 | abate | 552 | |
| 893 | abate | 656 | |
| 894 | abate | 505 | let do_typ loc r = |
| 895 | let s = compile_slot r in | ||
| 896 | abate | 277 | flush_defs (); |
| 897 | abate | 656 | check_no_capture loc (fv_slot s); |
| 898 | typ_node s | ||
| 899 | abate | 505 | |
| 900 | abate | 686 | let typ env p = |
| 901 | do_typ p.loc (derecurs (penv env) p) | ||
| 902 | abate | 277 | |
| 903 | abate | 686 | let pat env p = |
| 904 | let s = compile_slot (derecurs (penv env) p) in | ||
| 905 | abate | 277 | flush_defs (); |
| 906 | try pat_node s | ||
| 907 | with Patterns.Error e -> raise_loc_generic p.loc e | ||
| 908 | abate | 522 | | Location (loc,_,exn) when loc = noloc -> raise (Location (p.loc, `Full, exn)) |
| 909 | abate | 5 | |
| 910 | |||
| 911 | (* II. Build skeleton *) | ||
| 912 | |||
| 913 | abate | 542 | |
| 914 | abate | 691 | type type_fun = Types.t -> bool -> Types.t |
| 915 | abate | 542 | |
| 916 | abate | 225 | module Fv = IdSet |
| 917 | abate | 6 | |
| 918 | abate | 427 | type branch = Branch of Typed.branch * branch list |
| 919 | abate | 314 | |
| 920 | abate | 427 | let cur_branch : branch list ref = ref [] |
| 921 | |||
| 922 | abate | 316 | let exp loc fv e = |
| 923 | abate | 6 | fv, |
| 924 | { Typed.exp_loc = loc; | ||
| 925 | abate | 5 | Typed.exp_typ = Types.empty; |
| 926 | abate | 316 | Typed.exp_descr = e; |
| 927 | abate | 5 | } |
| 928 | abate | 316 | |
| 929 | abate | 1237 | let ops = Hashtbl.create 13 |
| 930 | abate | 1238 | let register_op op arity f = Hashtbl.add ops op (arity,f) |
| 931 | let typ_op op = snd (Hashtbl.find ops op) | ||
| 932 | abate | 316 | |
| 933 | abate | 1238 | let is_op env s = |
| 934 | if (Env.mem (ident s) env.ids) then None | ||
| 935 | else | ||
| 936 | try let s = U.get_str s in Some (s, fst (Hashtbl.find ops s)) | ||
| 937 | with Not_found -> None | ||
| 938 | abate | 1237 | |
| 939 | abate | 686 | let rec expr env loc = function |
| 940 | | LocatedExpr (loc,e) -> expr env loc e | ||
| 941 | abate | 316 | | Forget (e,t) -> |
| 942 | abate | 686 | let (fv,e) = expr env loc e and t = typ env t in |
| 943 | abate | 316 | exp loc fv (Typed.Forget (e,t)) |
| 944 | abate | 1215 | | Var s -> var env loc s |
| 945 | abate | 316 | | Apply (e1,e2) -> |
| 946 | abate | 1238 | let (fv1,e1) = expr env loc e1 and (fv2,e2) = expr env loc e2 in |
| 947 | let fv = Fv.cup fv1 fv2 in | ||
| 948 | (match e1.Typed.exp_descr with | ||
| 949 | | Typed.Op (op,arity,args) when arity > 0 -> | ||
| 950 | exp loc fv (Typed.Op (op,arity - 1,args @ [e2])) | ||
| 951 | | _ -> | ||
| 952 | exp loc fv (Typed.Apply (e1,e2))) | ||
| 953 | | Abstraction a -> abstraction env loc a | ||
| 954 | abate | 722 | | (Integer _ | Char _ | Atom _ | Const _) as c -> |
| 955 | abate | 686 | exp loc Fv.empty (Typed.Cst (const env loc c)) |
| 956 | abate | 316 | | Pair (e1,e2) -> |
| 957 | abate | 686 | let (fv1,e1) = expr env loc e1 and (fv2,e2) = expr env loc e2 in |
| 958 | abate | 316 | exp loc (Fv.cup fv1 fv2) (Typed.Pair (e1,e2)) |
| 959 | | Xml (e1,e2) -> | ||
| 960 | abate | 686 | let (fv1,e1) = expr env loc e1 and (fv2,e2) = expr env loc e2 in |
| 961 | abate | 316 | exp loc (Fv.cup fv1 fv2) (Typed.Xml (e1,e2)) |
| 962 | | Dot (e,l) -> | ||
| 963 | abate | 686 | let (fv,e) = expr env loc e in |
| 964 | exp loc fv (Typed.Dot (e,parse_label env loc l)) | ||
| 965 | abate | 316 | | RemoveField (e,l) -> |
| 966 | abate | 686 | let (fv,e) = expr env loc e in |
| 967 | exp loc fv (Typed.RemoveField (e,parse_label env loc l)) | ||
| 968 | abate | 316 | | RecordLitt r -> |
| 969 | let fv = ref Fv.empty in | ||
| 970 | abate | 686 | let r = parse_record env loc |
| 971 | abate | 316 | (fun e -> |
| 972 | abate | 686 | let (fv2,e) = expr env loc e |
| 973 | abate | 316 | in fv := Fv.cup !fv fv2; e) |
| 974 | r in | ||
| 975 | exp loc !fv (Typed.RecordLitt r) | ||
| 976 | abate | 522 | | String (i,j,s,e) -> |
| 977 | abate | 686 | let (fv,e) = expr env loc e in |
| 978 | abate | 522 | exp loc fv (Typed.String (i,j,s,e)) |
| 979 | abate | 316 | | Match (e,b) -> |
| 980 | abate | 686 | let (fv1,e) = expr env loc e |
| 981 | and (fv2,b) = branches env b in | ||
| 982 | abate | 316 | exp loc (Fv.cup fv1 fv2) (Typed.Match (e, b)) |
| 983 | abate | 421 | | Map (e,b) -> |
| 984 | abate | 686 | let (fv1,e) = expr env loc e |
| 985 | and (fv2,b) = branches env b in | ||
| 986 | abate | 421 | exp loc (Fv.cup fv1 fv2) (Typed.Map (e, b)) |
| 987 | | Transform (e,b) -> | ||
| 988 | abate | 686 | let (fv1,e) = expr env loc e |
| 989 | and (fv2,b) = branches env b in | ||
| 990 | abate | 421 | exp loc (Fv.cup fv1 fv2) (Typed.Transform (e, b)) |
| 991 | abate | 331 | | Xtrans (e,b) -> |
| 992 | abate | 686 | let (fv1,e) = expr env loc e |
| 993 | and (fv2,b) = branches env b in | ||
| 994 | abate | 331 | exp loc (Fv.cup fv1 fv2) (Typed.Xtrans (e, b)) |
| 995 | abate | 786 | | Validate (e,kind,schema,elt) -> |
| 996 | abate | 686 | let (fv,e) = expr env loc e in |
| 997 | abate | 1190 | let uri = find_schema schema env in |
| 998 | exp loc fv (Typed.Validate (e, kind, uri, elt)) | ||
| 999 | abate | 316 | | Try (e,b) -> |
| 1000 | abate | 686 | let (fv1,e) = expr env loc e |
| 1001 | and (fv2,b) = branches env b in | ||
| 1002 | abate | 316 | exp loc (Fv.cup fv1 fv2) (Typed.Try (e, b)) |
| 1003 | abate | 530 | | NamespaceIn (pr,ns,e) -> |
| 1004 | abate | 686 | let env = enter_ns pr ns env in |
| 1005 | expr env loc e | ||
| 1006 | abate | 623 | | Ref (e,t) -> |
| 1007 | abate | 686 | let (fv,e) = expr env loc e and t = typ env t in |
| 1008 | abate | 623 | exp loc fv (Typed.Ref (e,t)) |
| 1009 | abate | 1177 | | External (s,args) -> |
| 1010 | abate | 1178 | extern loc env s args |
| 1011 | abate | 1238 | |
| 1012 | and extern loc env s args = | ||
| 1013 | let args = List.map (typ env) args in | ||
| 1014 | try | ||
| 1015 | let (i,t) = Externals.resolve s args in | ||
| 1016 | exp loc Fv.empty (Typed.External (t,i)) | ||
| 1017 | with exn -> raise_loc loc exn | ||
| 1018 | |||
| 1019 | and var env loc s = | ||
| 1020 | match is_op env s with | ||
| 1021 | abate | 1239 | | Some (s,arity) -> |
| 1022 | let need_ns = s = "print_xml" || s = "print_xml_utf8" in | ||
| 1023 | let e = Typed.Op (s, arity, []) in | ||
| 1024 | let e = if need_ns then Typed.NsTable (env.ns,e) else e in | ||
| 1025 | exp loc Fv.empty e | ||
| 1026 | abate | 1238 | | None -> |
| 1027 | match Ns.split_qname s with | ||
| 1028 | | "", id -> | ||
| 1029 | let s = U.get_str id in | ||
| 1030 | if String.contains s '.' then | ||
| 1031 | extern loc env s [] | ||
| 1032 | else | ||
| 1033 | let id = ident id in | ||
| 1034 | (try ignore (find_value id env) | ||
| 1035 | with Not_found -> raise_loc loc (UnboundId (id, Env.mem id env.ids))); | ||
| 1036 | exp loc (Fv.singleton id) (Typed.Var id) | ||
| 1037 | | cu, id -> | ||
| 1038 | let cu = find_cu (U.mk cu) env in | ||
| 1039 | let id = ident id in | ||
| 1040 | let t = | ||
| 1041 | try find_value_global cu id env | ||
| 1042 | with Not_found -> | ||
| 1043 | raise_loc loc (UnboundExtId (cu,id) ) in | ||
| 1044 | exp loc Fv.empty (Typed.ExtVar (cu, id, t)) | ||
| 1045 | abate | 1178 | |
| 1046 | abate | 1238 | and abstraction env loc a = |
| 1047 | let iface = | ||
| 1048 | List.map | ||
| 1049 | (fun (t1,t2) -> (typ env t1, typ env t2)) a.fun_iface in | ||
| 1050 | let t = | ||
| 1051 | List.fold_left | ||
| 1052 | (fun accu (t1,t2) -> Types.cap accu (Types.arrow t1 t2)) | ||
| 1053 | Types.any iface in | ||
| 1054 | let iface = | ||
| 1055 | List.map | ||
| 1056 | (fun (t1,t2) -> (Types.descr t1, Types.descr t2)) | ||
| 1057 | iface in | ||
| 1058 | let env' = | ||
| 1059 | match a.fun_name with | ||
| 1060 | | None -> env | ||
| 1061 | | Some f -> enter_values_dummy [ f ] env | ||
| 1062 | in | ||
| 1063 | let (fv0,body) = branches env' a.fun_body in | ||
| 1064 | let fv = match a.fun_name with | ||
| 1065 | | None -> fv0 | ||
| 1066 | | Some f -> Fv.remove f fv0 in | ||
| 1067 | let e = Typed.Abstraction | ||
| 1068 | { Typed.fun_name = a.fun_name; | ||
| 1069 | Typed.fun_iface = iface; | ||
| 1070 | Typed.fun_body = body; | ||
| 1071 | Typed.fun_typ = t; | ||
| 1072 | Typed.fun_fv = fv | ||
| 1073 | } in | ||
| 1074 | exp loc fv e | ||
| 1075 | |||
| 1076 | and branches env b = | ||
| 1077 | let fv = ref Fv.empty in | ||
| 1078 | let accept = ref Types.empty in | ||
| 1079 | let branch (p,e) = | ||
| 1080 | let cur_br = !cur_branch in | ||
| 1081 | cur_branch := []; | ||
| 1082 | let p' = pat env p in | ||
| 1083 | let fvp = Patterns.fv p' in | ||
| 1084 | let env' = enter_values_dummy fvp env in | ||
| 1085 | let (fv2,e) = expr env' noloc e in | ||
| 1086 | let br_loc = merge_loc p.loc e.Typed.exp_loc in | ||
| 1087 | (match Fv.pick (Fv.diff fvp fv2) with | ||
| 1088 | | None -> () | ||
| 1089 | | Some x -> | ||
| 1090 | let x = U.to_string (Id.value x) in | ||
| 1091 | warning br_loc | ||
| 1092 | ("The capture variable " ^ x ^ | ||
| 1093 | " is declared in the pattern but not used in the body of this branch. It might be a misspelled or undeclared type or name (if it isn't, use _ instead).")); | ||
| 1094 | let fv2 = Fv.diff fv2 fvp in | ||
| 1095 | fv := Fv.cup !fv fv2; | ||
| 1096 | accept := Types.cup !accept (Types.descr (Patterns.accept p')); | ||
| 1097 | let br = | ||
| 1098 | { | ||
| 1099 | Typed.br_loc = br_loc; | ||
| 1100 | Typed.br_used = br_loc = noloc; | ||
| 1101 | Typed.br_pat = p'; | ||
| 1102 | Typed.br_body = e } in | ||
| 1103 | cur_branch := Branch (br, !cur_branch) :: cur_br; | ||
| 1104 | br in | ||
| 1105 | let b = List.map branch b in | ||
| 1106 | (!fv, | ||
| 1107 | { | ||
| 1108 | Typed.br_typ = Types.empty; | ||
| 1109 | Typed.br_branches = b; | ||
| 1110 | Typed.br_accept = !accept; | ||
| 1111 | Typed.br_compiled = None; | ||
| 1112 | } | ||
| 1113 | ) | ||
| 1114 | abate | 1215 | |
| 1115 | abate | 695 | let expr env e = snd (expr env noloc e) |
| 1116 | abate | 122 | |
| 1117 | abate | 686 | let let_decl env p e = |
| 1118 | { Typed.let_pat = pat env p; | ||
| 1119 | abate | 695 | Typed.let_body = expr env e; |
| 1120 | abate | 66 | Typed.let_compiled = None } |
| 1121 | |||
| 1122 | abate | 529 | |
| 1123 | (* Hide global "typing/parsing" environment *) | ||
| 1124 | |||
| 1125 | |||
| 1126 | abate | 66 | (* III. Type-checks *) |
| 1127 | |||
| 1128 | abate | 6 | open Typed |
| 1129 | |||
| 1130 | abate | 1238 | let localize loc f x = |
| 1131 | try f x | ||
| 1132 | with | ||
| 1133 | | (Error _ | Constraint (_,_)) as exn -> raise (Location.Location (loc,`Full,exn)) | ||
| 1134 | | Warning (s,t) -> warning loc s; t | ||
| 1135 | |||
| 1136 | abate | 421 | let require loc t s = |
| 1137 | if not (Types.subtype t s) then raise_loc loc (Constraint (t, s)) | ||
| 1138 | abate | 17 | |
| 1139 | abate | 691 | let verify loc t s = |
| 1140 | abate | 421 | require loc t s; t |
| 1141 | abate | 17 | |
| 1142 | abate | 1238 | let verify_noloc t s = |
| 1143 | if not (Types.subtype t s) then raise (Constraint (t, s)); | ||
| 1144 | t | ||
| 1145 | |||
| 1146 | abate | 522 | let check_str loc ofs t s = |
| 1147 | if not (Types.subtype t s) then raise_loc_str loc ofs (Constraint (t, s)); | ||
| 1148 | t | ||
| 1149 | |||
| 1150 | let should_have loc constr s = | ||
| 1151 | abate | 421 | raise_loc loc (ShouldHave (constr,s)) |
| 1152 | |||
| 1153 | abate | 522 | let should_have_str loc ofs constr s = |
| 1154 | raise_loc_str loc ofs (ShouldHave (constr,s)) | ||
| 1155 | |||
| 1156 | abate | 1238 | let flatten arg constr precise = |
| 1157 | abate | 421 | let constr' = Sequence.star |
| 1158 | (Sequence.approx (Types.cap Sequence.any constr)) in | ||
| 1159 | let sconstr' = Sequence.star constr' in | ||
| 1160 | let exact = Types.subtype constr' constr in | ||
| 1161 | if exact then | ||
| 1162 | let t = arg sconstr' precise in | ||
| 1163 | if precise then Sequence.flatten t else constr | ||
| 1164 | else | ||
| 1165 | let t = arg sconstr' true in | ||
| 1166 | abate | 1238 | verify_noloc (Sequence.flatten t) constr |
| 1167 | abate | 421 | |
| 1168 | abate | 19 | let rec type_check env e constr precise = |
| 1169 | let d = type_check' e.exp_loc env e.exp_descr constr precise in | ||
| 1170 | abate | 421 | let d = if precise then d else constr in |
| 1171 | abate | 6 | e.exp_typ <- Types.cup e.exp_typ d; |
| 1172 | d | ||
| 1173 | |||
| 1174 | abate | 19 | and type_check' loc env e constr precise = match e with |
| 1175 | abate | 54 | | Forget (e,t) -> |
| 1176 | let t = Types.descr t in | ||
| 1177 | ignore (type_check env e t false); | ||
| 1178 | abate | 691 | verify loc t constr |
| 1179 | abate | 421 | |
| 1180 | abate | 19 | | Abstraction a -> |
| 1181 | let t = | ||
| 1182 | try Types.Arrow.check_strenghten a.fun_typ constr | ||
| 1183 | with Not_found -> | ||
| 1184 | abate | 421 | should_have loc constr |
| 1185 | "but the interface of the abstraction is not compatible" | ||
| 1186 | abate | 19 | in |
| 1187 | let env = match a.fun_name with | ||
| 1188 | | None -> env | ||
| 1189 | abate | 686 | | Some f -> enter_value f a.fun_typ env in |
| 1190 | abate | 19 | List.iter |
| 1191 | (fun (t1,t2) -> | ||
| 1192 | abate | 374 | let acc = a.fun_body.br_accept in |
| 1193 | if not (Types.subtype t1 acc) then | ||
| 1194 | raise_loc loc (NonExhaustive (Types.diff t1 acc)); | ||
| 1195 | abate | 65 | ignore (type_check_branches loc env t1 a.fun_body t2 false) |
| 1196 | abate | 19 | ) a.fun_iface; |
| 1197 | t | ||
| 1198 | abate | 64 | |
| 1199 | abate | 19 | | Match (e,b) -> |
| 1200 | let t = type_check env e b.br_accept true in | ||
| 1201 | abate | 65 | type_check_branches loc env t b constr precise |
| 1202 | abate | 30 | |
| 1203 | abate | 64 | | Try (e,b) -> |
| 1204 | let te = type_check env e constr precise in | ||
| 1205 | abate | 65 | let tb = type_check_branches loc env Types.any b constr precise in |
| 1206 | abate | 64 | Types.cup te tb |
| 1207 | |||
| 1208 | abate | 110 | | Pair (e1,e2) -> |
| 1209 | type_check_pair loc env e1 e2 constr precise | ||
| 1210 | abate | 421 | |
| 1211 | abate | 110 | | Xml (e1,e2) -> |
| 1212 | type_check_pair ~kind:`XML loc env e1 e2 constr precise | ||
| 1213 | abate | 159 | |
| 1214 | abate | 29 | | RecordLitt r -> |
| 1215 | abate | 421 | type_record loc env r constr precise |
| 1216 | abate | 31 | |
| 1217 | abate | 421 | | Map (e,b) -> |
| 1218 | type_map loc env false e b constr precise | ||
| 1219 | |||
| 1220 | | Transform (e,b) -> | ||
| 1221 | abate | 1238 | localize loc (flatten (type_map loc env true e b) constr) precise |
| 1222 | abate | 421 | |
| 1223 | abate | 86 | | Apply (e1,e2) -> |
| 1224 | let t1 = type_check env e1 Types.Arrow.any true in | ||
| 1225 | let t1 = Types.Arrow.get t1 in | ||
| 1226 | let dom = Types.Arrow.domain t1 in | ||
| 1227 | abate | 110 | let res = |
| 1228 | if Types.Arrow.need_arg t1 then | ||
| 1229 | let t2 = type_check env e2 dom true in | ||
| 1230 | Types.Arrow.apply t1 t2 | ||
| 1231 | else | ||
| 1232 | (ignore (type_check env e2 dom false); Types.Arrow.apply_noarg t1) | ||
| 1233 | in | ||
| 1234 | abate | 691 | verify loc res constr |
| 1235 | abate | 19 | |
| 1236 | abate | 421 | | Var s -> |
| 1237 | abate | 1238 | verify loc (find_value s env) constr |
| 1238 | abate | 713 | |
| 1239 | abate | 1238 | | ExtVar (cu,s,t) -> |
| 1240 | abate | 713 | verify loc t constr |
| 1241 | abate | 421 | | Cst c -> |
| 1242 | abate | 691 | verify loc (Types.constant c) constr |
| 1243 | abate | 421 | |
| 1244 | abate | 522 | | String (i,j,s,e) -> |
| 1245 | type_check_string loc env 0 s i j e constr precise | ||
| 1246 | |||
| 1247 | abate | 421 | | Dot (e,l) -> |
| 1248 | let t = type_check env e Types.Record.any true in | ||
| 1249 | let t = | ||
| 1250 | try (Types.Record.project t l) | ||
| 1251 | with Not_found -> raise_loc loc (WrongLabel(t,l)) | ||
| 1252 | in | ||
| 1253 | abate | 691 | verify loc t constr |
| 1254 | abate | 421 | |
| 1255 | | RemoveField (e,l) -> | ||
| 1256 | let t = type_check env e Types.Record.any true in | ||
| 1257 | let t = Types.Record.remove_field t l in | ||
| 1258 | abate | 691 | verify loc t constr |
| 1259 | abate | 421 | |
| 1260 | | Xtrans (e,b) -> | ||
| 1261 | let t = type_check env e Sequence.any true in | ||
| 1262 | let t = | ||
| 1263 | Sequence.map_tree | ||
| 1264 | (fun t -> | ||
| 1265 | let resid = Types.diff t b.br_accept in | ||
| 1266 | let res = type_check_branches loc env t b Sequence.any true in | ||
| 1267 | (res,resid) | ||
| 1268 | ) t in | ||
| 1269 | abate | 691 | verify loc t constr |
| 1270 | abate | 421 | |
| 1271 | abate | 1190 | | Validate (e, kind, uri, name) -> |
| 1272 | abate | 501 | ignore (type_check env e Types.any false); |
| 1273 | abate | 1190 | let t = find_schema_descr_uri kind uri name in |
| 1274 | abate | 691 | verify loc t constr |
| 1275 | abate | 421 | |
| 1276 | abate | 623 | | Ref (e,t) -> |
| 1277 | ignore (type_check env e (Types.descr t) false); | ||
| 1278 | abate | 691 | verify loc (Builtin_defs.ref_type t) constr |
| 1279 | abate | 623 | |
| 1280 | abate | 1156 | | External (t,i) -> |
| 1281 | verify loc t constr | ||
| 1282 | |||
| 1283 | abate | 1238 | | Op (op,_,args) -> |
| 1284 | abate | 1237 | let args = List.map (type_check env) args in |
| 1285 | abate | 1238 | let t = localize loc (typ_op op args constr) precise in |
| 1286 | abate | 1237 | verify loc t constr |
| 1287 | |||
| 1288 | abate | 1239 | | NsTable (ns,e) -> |
| 1289 | type_check' loc env e constr precise | ||
| 1290 | |||
| 1291 | abate | 110 | and type_check_pair ?(kind=`Normal) loc env e1 e2 constr precise = |
| 1292 | abate | 361 | let rects = Types.Product.normal ~kind constr in |
| 1293 | abate | 110 | if Types.Product.is_empty rects then |
| 1294 | (match kind with | ||
| 1295 | abate | 421 | | `Normal -> should_have loc constr "but it is a pair" |
| 1296 | | `XML -> should_have loc constr "but it is an XML element"); | ||
| 1297 | abate | 334 | let need_s = Types.Product.need_second rects in |
| 1298 | abate | 355 | let t1 = type_check env e1 (Types.Product.pi1 rects) (precise || need_s) in |
| 1299 | let c2 = Types.Product.constraint_on_2 rects t1 in | ||
| 1300 | if Types.is_empty c2 then | ||
| 1301 | raise_loc loc (ShouldHave2 (constr,"but the first component has type",t1)); | ||
| 1302 | let t2 = type_check env e2 c2 precise in | ||
| 1303 | abate | 334 | |
| 1304 | abate | 110 | if precise then |
| 1305 | abate | 355 | match kind with |
| 1306 | | `Normal -> Types.times (Types.cons t1) (Types.cons t2) | ||
| 1307 | | `XML -> Types.xml (Types.cons t1) (Types.cons t2) | ||
| 1308 | abate | 110 | else |
| 1309 | constr | ||
| 1310 | |||
| 1311 | abate | 522 | and type_check_string loc env ofs s i j e constr precise = |
| 1312 | if U.equal_index i j then type_check env e constr precise | ||
| 1313 | else | ||
| 1314 | let rects = Types.Product.normal constr in | ||
| 1315 | if Types.Product.is_empty rects | ||
| 1316 | then should_have_str loc ofs constr "but it is a string" | ||
| 1317 | else | ||
| 1318 | let need_s = Types.Product.need_second rects in | ||
| 1319 | let (ch,i') = U.next s i in | ||
| 1320 | abate | 656 | let ch = Chars.V.mk_int ch in |
| 1321 | abate | 522 | let tch = Types.constant (Types.Char ch) in |
| 1322 | let t1 = check_str loc ofs tch (Types.Product.pi1 rects) in | ||
| 1323 | let c2 = Types.Product.constraint_on_2 rects t1 in | ||
| 1324 | let t2 = type_check_string loc env (ofs + 1) s i' j e c2 precise in | ||
| 1325 | if precise then Types.times (Types.cons t1) (Types.cons t2) | ||
| 1326 | else constr | ||
| 1327 | |||
| 1328 | abate | 421 | and type_record loc env r constr precise = |
| 1329 | (* try to get rid of precise = true for values of fields *) | ||
| 1330 | (* also: the use equivalent of need_second to optimize... *) | ||
| 1331 | if not (Types.Record.has_record constr) then | ||
| 1332 | should_have loc constr "but it is a record"; | ||
| 1333 | let (rconstr,res) = | ||
| 1334 | List.fold_left | ||
| 1335 | (fun (rconstr,res) (l,e) -> | ||
| 1336 | (* could compute (split l e) once... *) | ||
| 1337 | let pi = Types.Record.project_opt rconstr l in | ||
| 1338 | if Types.is_empty pi then | ||
| 1339 | abate | 542 | (let l = Label.to_string (LabelPool.value l) in |
| 1340 | abate | 421 | should_have loc constr |
| 1341 | (Printf.sprintf "Field %s is not allowed here." l)); | ||
| 1342 | let t = type_check env e pi true in | ||
| 1343 | let rconstr = Types.Record.condition rconstr l t in | ||
| 1344 | let res = (l,Types.cons t) :: res in | ||
| 1345 | (rconstr,res) | ||
| 1346 | ) (constr, []) (LabelMap.get r) | ||
| 1347 | in | ||
| 1348 | if not (Types.Record.has_empty_record rconstr) then | ||
| 1349 | should_have loc constr "More fields should be present"; | ||
| 1350 | let t = | ||
| 1351 | Types.record' (false, LabelMap.from_list (fun _ _ -> assert false) res) | ||
| 1352 | in | ||
| 1353 | abate | 691 | verify loc t constr |
| 1354 | abate | 110 | |
| 1355 | abate | 19 | |
| 1356 | abate | 65 | and type_check_branches loc env targ brs constr precise = |
| 1357 | abate | 374 | if Types.is_empty targ then Types.empty |
| 1358 | abate | 9 | else ( |
| 1359 | brs.br_typ <- Types.cup brs.br_typ targ; | ||
| 1360 | abate | 65 | branches_aux loc env targ |
| 1361 | abate | 19 | (if precise then Types.empty else constr) |
| 1362 | constr precise brs.br_branches | ||
| 1363 | abate | 9 | ) |
| 1364 | abate | 6 | |
| 1365 | abate | 65 | and branches_aux loc env targ tres constr precise = function |
| 1366 | abate | 374 | | [] -> tres |
| 1367 | abate | 6 | | b :: rem -> |
| 1368 | let p = b.br_pat in | ||
| 1369 | let acc = Types.descr (Patterns.accept p) in | ||
| 1370 | |||
| 1371 | let targ' = Types.cap targ acc in | ||
| 1372 | if Types.is_empty targ' | ||
| 1373 | abate | 65 | then branches_aux loc env targ tres constr precise rem |
| 1374 | abate | 6 | else |
| 1375 | ( b.br_used <- true; | ||
| 1376 | let res = Patterns.filter targ' p in | ||
| 1377 | abate | 686 | let res = List.map (fun (x,t) -> (x,Types.descr t)) res in |
| 1378 | let env' = enter_values res env in | ||
| 1379 | abate | 19 | let t = type_check env' b.br_body constr precise in |
| 1380 | let tres = if precise then Types.cup t tres else tres in | ||
| 1381 | abate | 9 | let targ'' = Types.diff targ acc in |
| 1382 | if (Types.non_empty targ'') then | ||
| 1383 | abate | 65 | branches_aux loc env targ'' tres constr precise rem |
| 1384 | abate | 9 | else |
| 1385 | tres | ||
| 1386 | abate | 6 | ) |
| 1387 | abate | 16 | |
| 1388 | abate | 421 | and type_map loc env def e b constr precise = |
| 1389 | let acc = if def then Sequence.any else Sequence.star b.br_accept in | ||
| 1390 | let t = type_check env e acc true in | ||
| 1391 | |||
| 1392 | let constr' = Sequence.approx (Types.cap Sequence.any constr) in | ||
| 1393 | let exact = Types.subtype (Sequence.star constr') constr in | ||
| 1394 | (* Note: | ||
| 1395 | - could be more precise by integrating the decomposition | ||
| 1396 | of constr inside Sequence.map. | ||
| 1397 | *) | ||
| 1398 | let res = | ||
| 1399 | Sequence.map | ||
| 1400 | (fun t -> | ||
| 1401 | let res = | ||
| 1402 | type_check_branches loc env t b constr' (precise || (not exact)) in | ||
| 1403 | if def && not (Types.subtype t b.br_accept) | ||
| 1404 | abate | 969 | then (require loc Sequence.nil_type constr'; Types.cup res Sequence.nil_type) |
| 1405 | abate | 421 | else res) |
| 1406 | t in | ||
| 1407 | abate | 691 | if exact then res else verify loc res constr |
| 1408 | abate | 421 | |
| 1409 | abate | 66 | and type_let_decl env l = |
| 1410 | let acc = Types.descr (Patterns.accept l.let_pat) in | ||
| 1411 | let t = type_check env l.let_body acc true in | ||
| 1412 | let res = Patterns.filter t l.let_pat in | ||
| 1413 | List.map (fun (x,t) -> (x, Types.descr t)) res | ||
| 1414 | |||
| 1415 | and type_rec_funs env l = | ||
| 1416 | abate | 698 | let typs = |
| 1417 | abate | 66 | List.fold_left |
| 1418 | abate | 431 | (fun accu -> function |
| 1419 | abate | 656 | | { exp_descr=Abstraction { fun_typ = t; fun_name = Some f }; |
| 1420 | exp_loc=loc } -> | ||
| 1421 | abate | 692 | if not (value_name_ok f env) then |
| 1422 | abate | 656 | error loc "This function name clashes with a type name"; |
| 1423 | abate | 698 | (f,t)::accu |
| 1424 | abate | 431 | | _ -> assert false |
| 1425 | ) [] l | ||
| 1426 | abate | 66 | in |
| 1427 | abate | 698 | let env = enter_values typs env in |
| 1428 | List.iter (fun e -> ignore (type_check env e Types.any false)) l; | ||
| 1429 | typs | ||
| 1430 | abate | 66 | |
| 1431 | abate | 427 | let rec unused_branches b = |
| 1432 | abate | 314 | List.iter |
| 1433 | abate | 427 | (fun (Branch (br,s)) -> |
| 1434 | if not br.br_used | ||
| 1435 | then warning br.br_loc "This branch is not used" | ||
| 1436 | else unused_branches s | ||
| 1437 | ) | ||
| 1438 | b | ||
| 1439 | abate | 314 | |
| 1440 | abate | 427 | let report_unused_branches () = |
| 1441 | unused_branches !cur_branch; | ||
| 1442 | cur_branch := [] | ||
| 1443 | abate | 637 | |
| 1444 | let clear_unused_branches () = | ||
| 1445 | cur_branch := [] | ||
| 1446 | abate | 427 | |
| 1447 | abate | 698 | |
| 1448 | |||
| 1449 | (* API *) | ||
| 1450 | |||
| 1451 | let type_expr env e = | ||
| 1452 | clear_unused_branches (); | ||
| 1453 | let e = expr env e in | ||
| 1454 | let t = type_check env e Types.any true in | ||
| 1455 | report_unused_branches (); | ||
| 1456 | (e,t) | ||
| 1457 | |||
| 1458 | let type_let_decl env p e = | ||
| 1459 | clear_unused_branches (); | ||
| 1460 | let decl = let_decl env p e in | ||
| 1461 | let typs = type_let_decl env decl in | ||
| 1462 | report_unused_branches (); | ||
| 1463 | let env = enter_values typs env in | ||
| 1464 | (env,decl,typs) | ||
| 1465 | |||
| 1466 | let type_let_funs env funs = | ||
| 1467 | clear_unused_branches (); | ||
| 1468 | abate | 1238 | let rec id = function |
| 1469 | | Ast.LocatedExpr (_,e) -> id e | ||
| 1470 | | Ast.Abstraction a -> a.Ast.fun_name | ||
| 1471 | | _ -> assert false | ||
| 1472 | in | ||
| 1473 | let ids = | ||
| 1474 | List.fold_left (fun accu f -> match id f with Some x -> x::accu | None -> accu) | ||
| 1475 | [] funs in | ||
| 1476 | let env' = enter_values_dummy ids env in | ||
| 1477 | let funs = List.map (expr env') funs in | ||
| 1478 | abate | 698 | let typs = type_rec_funs env funs in |
| 1479 | report_unused_branches (); | ||
| 1480 | let env = enter_values typs env in | ||
| 1481 | (env,funs,typs) | ||
| 1482 | |||
| 1483 | |||
| 1484 | abate | 501 | (* Schema stuff from now on ... *) |
| 1485 | |||
| 1486 | (** convertion from XML Schema types (including global elements and | ||
| 1487 | attributes) to CDuce Types.descr *) | ||
| 1488 | module Schema_converter = | ||
| 1489 | struct | ||
| 1490 | |||
| 1491 | abate | 508 | open Printf |
| 1492 | open Schema_types | ||
| 1493 | abate | 501 | |
| 1494 | (* auxiliary functions *) | ||
| 1495 | |||
| 1496 | abate | 757 | let nil_type = PType Sequence.nil_type |
| 1497 | abate | 501 | |
| 1498 | abate | 757 | let mk_len_regexp ?min ?max base = |
| 1499 | let rec repeat_regexp re = function | ||
| 1500 | | z when Intervals.V.is_zero z -> PEpsilon | ||
| 1501 | | n when Intervals.V.gt n Intervals.V.zero -> | ||
| 1502 | PSeq (re, repeat_regexp re (Intervals.V.pred n)) | ||
| 1503 | | _ -> assert false | ||
| 1504 | in | ||
| 1505 | let min = match min with Some min -> min | _ -> Intervals.V.one in | ||
| 1506 | let min_regexp = repeat_regexp base min in | ||
| 1507 | match max with | ||
| 1508 | | Some max -> | ||
| 1509 | abate | 1292 | (* assert (max >= min); Need to use Bigint comparison ! -- AF *) |
| 1510 | let rec aux acc = function | ||
| 1511 | abate | 757 | | z when Intervals.V.is_zero z -> acc |
| 1512 | | n -> | ||
| 1513 | aux (PAlt (PEpsilon, (PSeq (base, acc)))) (Intervals.V.pred n) | ||
| 1514 | in | ||
| 1515 | PSeq (min_regexp, aux PEpsilon (Intervals.V.sub max min)) | ||
| 1516 | | None -> PSeq (min_regexp, PStar base) | ||
| 1517 | |||
| 1518 | (* given a base derecurs create a derecurs value representing a sequence | ||
| 1519 | * type according to length constraints members of facets *) | ||
| 1520 | let mk_seq_derecurs ~base facets = | ||
| 1521 | match facets with | ||
| 1522 | | { length = Some (v, _) } -> | ||
| 1523 | abate | 1328 | pregexp (mk_len_regexp ~min:v ~max:v base) nil_type |
| 1524 | abate | 757 | | { minLength = Some (v, _); maxLength = None } -> |
| 1525 | abate | 1328 | pregexp (mk_len_regexp ~min:v base) nil_type |
| 1526 | abate | 757 | | { minLength = None; maxLength = Some (v, _) } -> |
| 1527 | abate | 1328 | pregexp (mk_len_regexp ~max:v base) nil_type |
| 1528 | | _ -> pregexp base nil_type | ||
| 1529 | abate | 757 | |
| 1530 | abate | 812 | let mix_regexp = |
| 1531 | let pcdata = PStar (PElem (PType Builtin_defs.string)) in | ||
| 1532 | let rec aux = function | ||
| 1533 | | PEpsilon -> PEpsilon | ||
| 1534 | | PElem re -> PElem re | ||
| 1535 | abate | 1328 | | PGuard re -> PGuard re |
| 1536 | abate | 812 | | PSeq (re1, re2) -> PSeq (aux re1, PSeq (pcdata, aux re2)) |
| 1537 | | PAlt (re1, re2) -> PAlt (aux re1, aux re2) | ||
| 1538 | | PStar re -> PStar (aux re) | ||
| 1539 | | PWeakStar re -> PWeakStar (aux re) | ||
| 1540 | in | ||
| 1541 | let rec simplify = function | ||
| 1542 | | PSeq (x1, PSeq (x2, y)) when x1 = pcdata && x2 = pcdata -> | ||
| 1543 | simplify (PSeq (x2, y)) | ||
| 1544 | | re -> re | ||
| 1545 | in | ||
| 1546 | fun regexp -> simplify (PSeq (pcdata, aux regexp)) | ||
| 1547 | |||
| 1548 | abate | 501 | (* conversion functions *) |
| 1549 | |||
| 1550 | abate | 803 | let rec cd_type_of_simple_type ~schema = function |
| 1551 | abate | 757 | | Primitive name | Derived (Some name, _, _, _) |
| 1552 | when Schema_builtin.is_builtin name -> | ||
| 1553 | PType (Schema_builtin.cd_type_of_builtin name) | ||
| 1554 | | Primitive _ -> assert false (* all primitives are built-in *) | ||
| 1555 | | Derived (_, _, { enumeration = Some values }, _) -> (* enumeration *) | ||
| 1556 | PType (Types.choice_of_list | ||
| 1557 | (List.map (fun c -> Types.constant (Value.inv_const c)) | ||
| 1558 | (Value.ValueSet.elements values))) | ||
| 1559 | | Derived (_, _, ({ maxInclusive = Some _ } as facets), _)(* boundaries *) | ||
| 1560 | | Derived (_, _, ({ maxExclusive = Some _ } as facets), _) | ||
| 1561 | | Derived (_, _, ({ minInclusive = Some _ } as facets), _) | ||
| 1562 | | Derived (_, _, ({ minExclusive = Some _ } as facets), |