/[svn]/typing/typer.ml
ViewVC logotype

Contents of /typing/typer.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 516 - (show annotations)
Tue Jul 10 17:40:48 2007 UTC (5 years, 10 months ago) by abate
File size: 36748 byte(s)
[r2003-06-15 21:46:12 by cvscast] - added support for xsd:all term

- bugfix: empty content model now supported

- bugfix: reference to global attributes works zack

Original author: cvscast
Date: 2003-06-15 21:46:12+00:00
1 (* TODO:
2 - rewrite type-checking of operators to propagate constraint
3 - optimize computation of pattern free variables
4 - check whether it is worth using recursive hash-consing internally
5 *)
6
7
8 let warning loc msg =
9 Format.fprintf !Location.warning_ppf "Warning %a:@\n%a%s@\n"
10 Location.print_loc loc
11 Location.html_hilight loc
12 msg
13
14 (* I. Transform the abstract syntax of types and patterns into
15 the internal form *)
16
17 open Location
18 open Ast
19 open Ident
20
21 module S = struct type t = string let compare = compare end
22 module TypeEnv = Map.Make(S)
23
24 exception NonExhaustive of Types.descr
25 exception Constraint of Types.descr * Types.descr
26 exception ShouldHave of Types.descr * string
27 exception ShouldHave2 of Types.descr * string * Types.descr
28 exception WrongLabel of Types.descr * label
29 exception UnboundId of id
30 exception Error of string
31
32 let raise_loc loc exn = raise (Location (loc,exn))
33 let error loc msg = raise_loc loc (Error msg)
34
35 (* Schema datastructures *)
36
37 module StringSet = Set.Make (String)
38
39 (* just to remember imported schemas *)
40 let schemas = State.ref "Typer.schemas" StringSet.empty
41
42 let schema_types = State.ref "Typer.schema_types" (Hashtbl.create 51)
43 let schema_elements = State.ref "Typer.schema_elements" (Hashtbl.create 51)
44 let schema_attributes = State.ref "Typer.schema_attributes" (Hashtbl.create 51)
45
46 (* Eliminate Recursion, propagate Sequence Capture Variables *)
47
48 let rec seq_vars accu = function
49 | Epsilon | Elem _ -> accu
50 | Seq (r1,r2) | Alt (r1,r2) -> seq_vars (seq_vars accu r1) r2
51 | Star r | WeakStar r -> seq_vars accu r
52 | SeqCapture (v,r) -> seq_vars (IdSet.add v accu) r
53
54 type derecurs_slot = {
55 ploc : Location.loc;
56 pid : int;
57 mutable ploop : bool;
58 mutable pdescr : derecurs option
59 } and derecurs =
60 | PAlias of derecurs_slot
61 | PType of Types.descr
62 | POr of derecurs * derecurs
63 | PAnd of derecurs * derecurs
64 | PDiff of derecurs * derecurs
65 | PTimes of derecurs * derecurs
66 | PXml of derecurs * derecurs
67 | PArrow of derecurs * derecurs
68 | POptional of derecurs
69 | PRecord of bool * derecurs label_map
70 | PCapture of id
71 | PConstant of id * Types.const
72 | PRegexp of derecurs_regexp * derecurs
73 and derecurs_regexp =
74 | PEpsilon
75 | PElem of derecurs
76 | PSeq of derecurs_regexp * derecurs_regexp
77 | PAlt of derecurs_regexp * derecurs_regexp
78 | PStar of derecurs_regexp
79 | PWeakStar of derecurs_regexp
80
81 let rec hash_derecurs = function
82 | PAlias s ->
83 s.pid
84 | PType t ->
85 1 + 17 * (Types.hash_descr t)
86 | POr (p1,p2) ->
87 2 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2)
88 | PAnd (p1,p2) ->
89 3 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2)
90 | PDiff (p1,p2) ->
91 4 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2)
92 | PTimes (p1,p2) ->
93 5 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2)
94 | PXml (p1,p2) ->
95 6 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2)
96 | PArrow (p1,p2) ->
97 7 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2)
98 | POptional p ->
99 8 + 17 * (hash_derecurs p)
100 | PRecord (o,r) ->
101 (if o then 9 else 10) + 17 * (LabelMap.hash hash_derecurs r)
102 | PCapture x ->
103 11 + 17 * (Id.hash x)
104 | PConstant (x,c) ->
105 12 + 17 * (Id.hash x) + 257 * (Types.hash_const c)
106 | PRegexp (p,q) ->
107 13 + 17 * (hash_derecurs_regexp p) + 257 * (hash_derecurs q)
108 and hash_derecurs_regexp = function
109 | PEpsilon ->
110 1
111 | PElem p ->
112 2 + 17 * (hash_derecurs p)
113 | PSeq (p1,p2) ->
114 3 + 17 * (hash_derecurs_regexp p1) + 257 * (hash_derecurs_regexp p2)
115 | PAlt (p1,p2) ->
116 4 + 17 * (hash_derecurs_regexp p1) + 257 * (hash_derecurs_regexp p2)
117 | PStar p ->
118 5 + 17 * (hash_derecurs_regexp p)
119 | PWeakStar p ->
120 6 + 17 * (hash_derecurs_regexp p)
121
122 let rec equal_derecurs p1 p2 = (p1 == p2) || match p1,p2 with
123 | PAlias s1, PAlias s2 ->
124 s1 == s2
125 | PType t1, PType t2 ->
126 Types.equal_descr t1 t2
127 | POr (p1,q1), POr (p2,q2)
128 | PAnd (p1,q1), PAnd (p2,q2)
129 | PDiff (p1,q1), PDiff (p2,q2)
130 | PTimes (p1,q1), PTimes (p2,q2)
131 | PXml (p1,q1), PXml (p2,q2)
132 | PArrow (p1,q1), PArrow (p2,q2) ->
133 (equal_derecurs p1 p2) && (equal_derecurs q1 q2)
134 | POptional p1, POptional p2 ->
135 equal_derecurs p1 p2
136 | PRecord (o1,r1), PRecord (o2,r2) ->
137 (o1 == o2) && (LabelMap.equal equal_derecurs r1 r2)
138 | PCapture x1, PCapture x2 ->
139 Id.equal x1 x2
140 | PConstant (x1,c1), PConstant (x2,c2) ->
141 (Id.equal x1 x2) && (Types.equal_const c1 c2)
142 | PRegexp (p1,q1), PRegexp (p2,q2) ->
143 (equal_derecurs_regexp p1 p2) && (equal_derecurs q1 q2)
144 | _ -> false
145 and equal_derecurs_regexp r1 r2 = match r1,r2 with
146 | PEpsilon, PEpsilon ->
147 true
148 | PElem p1, PElem p2 ->
149 equal_derecurs p1 p2
150 | PSeq (p1,q1), PSeq (p2,q2)
151 | PAlt (p1,q1), PAlt (p2,q2) ->
152 (equal_derecurs_regexp p1 p2) && (equal_derecurs_regexp q1 q2)
153 | PStar p1, PStar p2
154 | PWeakStar p1, PWeakStar p2 ->
155 equal_derecurs_regexp p1 p2
156 | _ -> false
157
158 module DerecursTable = Hashtbl.Make(
159 struct
160 type t = derecurs
161 let hash = hash_derecurs
162 let equal = equal_derecurs
163 end
164 )
165
166 module RE = Hashtbl.Make(
167 struct
168 type t = derecurs_regexp * derecurs
169 let hash (p,q) =
170 (hash_derecurs_regexp p) + 17 * (hash_derecurs q)
171 let equal (p1,q1) (p2,q2) =
172 (equal_derecurs_regexp p1 p2) && (equal_derecurs q1 q2)
173 end
174 )
175
176
177 let counter = State.ref "Typer.counter - derecurs" 0
178 let mk_slot loc =
179 incr counter;
180 { ploop = false; ploc = loc; pid = !counter; pdescr = None }
181
182 let rec derecurs env p = match p.descr with
183 | PatVar v ->
184 (try PAlias (TypeEnv.find v env)
185 with Not_found ->
186 raise_loc_generic p.loc ("Undefined type/pattern " ^ v))
187 | SchemaVar (kind, schema, item) ->
188 let try_elt () = fst (Hashtbl.find !schema_elements (schema, item)) in
189 let try_typ () = Hashtbl.find !schema_types (schema, item) in
190 let try_att () = Hashtbl.find !schema_attributes (schema, item) in
191 (match kind with
192 | `Element ->
193 (try
194 PType (try_elt ())
195 with Not_found ->
196 failwith (Printf.sprintf
197 "No element named '%s' found in schema '%s'" item schema))
198 | `Type ->
199 (try
200 PType (try_typ ())
201 with Not_found ->
202 failwith (Printf.sprintf
203 "No type named '%s' found in schema '%s'" item schema))
204 | `Attribute ->
205 (try
206 PType (try_att ())
207 with Not_found ->
208 failwith (Printf.sprintf
209 "No attribute named '%s' found in schema '%s'" item schema))
210 | `Any ->
211 PType
212 (try try_elt () with Not_found ->
213 (try try_typ () with Not_found ->
214 (try try_att () with Not_found ->
215 failwith (Printf.sprintf
216 "No item named '%s' found in schema '%s'" item schema)))))
217 | Recurs (p,b) -> derecurs (derecurs_def env b) p
218 | Internal t -> PType t
219 | Or (p1,p2) -> POr (derecurs env p1, derecurs env p2)
220 | And (p1,p2) -> PAnd (derecurs env p1, derecurs env p2)
221 | Diff (p1,p2) -> PDiff (derecurs env p1, derecurs env p2)
222 | Prod (p1,p2) -> PTimes (derecurs env p1, derecurs env p2)
223 | XmlT (p1,p2) -> PXml (derecurs env p1, derecurs env p2)
224 | Arrow (p1,p2) -> PArrow (derecurs env p1, derecurs env p2)
225 | Optional p -> POptional (derecurs env p)
226 | Record (o,r) -> PRecord (o, LabelMap.map (derecurs env) r)
227 | Capture x -> PCapture x
228 | Constant (x,c) -> PConstant (x,c)
229 | Regexp (r,q) ->
230 let constant_nil t v =
231 PAnd (t, PConstant (v, Types.Atom Sequence.nil_atom)) in
232 let vars = seq_vars IdSet.empty r in
233 let q = IdSet.fold constant_nil (derecurs env q) vars in
234 let r = derecurs_regexp (fun p -> p) env r in
235 PRegexp (r, q)
236 and derecurs_regexp vars env = function
237 | Epsilon ->
238 PEpsilon
239 | Elem p ->
240 PElem (vars (derecurs env p))
241 | Seq (p1,p2) ->
242 PSeq (derecurs_regexp vars env p1, derecurs_regexp vars env p2)
243 | Alt (p1,p2) ->
244 PAlt (derecurs_regexp vars env p1, derecurs_regexp vars env p2)
245 | Star p ->
246 PStar (derecurs_regexp vars env p)
247 | WeakStar p ->
248 PWeakStar (derecurs_regexp vars env p)
249 | SeqCapture (x,p) ->
250 derecurs_regexp (fun p -> PAnd (vars p, PCapture x)) env p
251
252
253 and derecurs_def env b =
254 let b = List.map (fun (v,p) -> (v,p,mk_slot p.loc)) b in
255 let env = List.fold_left (fun env (v,p,s) -> TypeEnv.add v s env) env b in
256 List.iter (fun (v,p,s) -> s.pdescr <- Some (derecurs env p)) b;
257 env
258
259 (* Stratification and recursive hash-consing *)
260
261 type descr =
262 | IType of Types.descr
263 | IOr of descr * descr
264 | IAnd of descr * descr
265 | IDiff of descr * descr
266 | ITimes of slot * slot
267 | IXml of slot * slot
268 | IArrow of slot * slot
269 | IOptional of descr
270 | IRecord of bool * slot label_map
271 | ICapture of id
272 | IConstant of id * Types.const
273 and slot = {
274 mutable fv : fv option;
275 mutable hash : int option;
276 mutable rank1: int; mutable rank2: int;
277 mutable gen1 : int; mutable gen2: int;
278 mutable d : descr option
279 }
280
281 let descr s =
282 match s.d with
283 | Some d -> d
284 | None -> assert false
285
286 let gen = ref 0
287 let rank = ref 0
288
289 let rec hash_descr = function
290 | IType x -> Types.hash_descr x
291 | IOr (d1,d2) -> 1 + 17 * (hash_descr d1) + 257 * (hash_descr d2)
292 | IAnd (d1,d2) -> 2 + 17 * (hash_descr d1) + 257 * (hash_descr d2)
293 | IDiff (d1,d2) -> 3 + 17 * (hash_descr d1) + 257 * (hash_descr d2)
294 | IOptional d -> 4 + 17 * (hash_descr d)
295 | ITimes (s1,s2) -> 5 + 17 * (hash_slot s1) + 257 * (hash_slot s2)
296 | IXml (s1,s2) -> 6 + 17 * (hash_slot s1) + 257 * (hash_slot s2)
297 | IArrow (s1,s2) -> 7 + 17 * (hash_slot s1) + 257 * (hash_slot s2)
298 | IRecord (o,r) -> (if o then 8 else 9) + 17 * (LabelMap.hash hash_slot r)
299 | ICapture x -> 10 + 17 * (Id.hash x)
300 | IConstant (x,y) -> 11 + 17 * (Id.hash x) + 257 * (Types.hash_const y)
301 and hash_slot s =
302 if s.gen1 = !gen then 13 * s.rank1
303 else (
304 incr rank;
305 s.rank1 <- !rank; s.gen1 <- !gen;
306 hash_descr (descr s)
307 )
308
309 let rec equal_descr d1 d2 =
310 match (d1,d2) with
311 | IType x1, IType x2 -> Types.equal_descr x1 x2
312 | IOr (x1,y1), IOr (x2,y2)
313 | IAnd (x1,y1), IAnd (x2,y2)
314 | IDiff (x1,y1), IDiff (x2,y2) -> (equal_descr x1 x2) && (equal_descr y1 y2)
315 | IOptional x1, IOptional x2 -> equal_descr x1 x2
316 | ITimes (x1,y1), ITimes (x2,y2)
317 | IXml (x1,y1), IXml (x2,y2)
318 | IArrow (x1,y1), IArrow (x2,y2) -> (equal_slot x1 x2) && (equal_slot y1 y2)
319 | IRecord (o1,r1), IRecord (o2,r2) ->
320 (o1 = o2) && (LabelMap.equal equal_slot r1 r2)
321 | ICapture x1, ICapture x2 -> Id.equal x1 x2
322 | IConstant (x1,y1), IConstant (x2,y2) ->
323 (Id.equal x1 x2) && (Types.equal_const y1 y2)
324 | _ -> false
325 and equal_slot s1 s2 =
326 ((s1.gen1 = !gen) && (s2.gen2 = !gen) && (s1.rank1 = s2.rank2))
327 ||
328 ((s1.gen1 <> !gen) && (s2.gen2 <> !gen) && (
329 incr rank;
330 s1.rank1 <- !rank; s1.gen1 <- !gen;
331 s2.rank2 <- !rank; s2.gen2 <- !gen;
332 equal_descr (descr s1) (descr s2)
333 ))
334
335 module Arg = struct
336 type t = slot
337
338 let hash s =
339 match s.hash with
340 | Some h -> h
341 | None ->
342 incr gen; rank := 0;
343 let h = hash_slot s in
344 s.hash <- Some h;
345 h
346
347 let equal s1 s2 =
348 (s1 == s2) ||
349 (incr gen; rank := 0;
350 let e = equal_slot s1 s2 in
351 (* if e then Printf.eprintf "Recursive hash-consig: Equal\n"; *)
352 e)
353 end
354 module SlotTable = Hashtbl.Make(Arg)
355
356 let rec fv_slot s =
357 match s.fv with
358 | Some x -> x
359 | None ->
360 if s.gen1 = !gen then IdSet.empty
361 else (s.gen1 <- !gen; fv_descr (descr s))
362 and fv_descr = function
363 | IType _ -> IdSet.empty
364 | IOr (d1,d2)
365 | IAnd (d1,d2)
366 | IDiff (d1,d2) -> IdSet.cup (fv_descr d1) (fv_descr d2)
367 | IOptional d -> fv_descr d
368 | ITimes (s1,s2)
369 | IXml (s1,s2)
370 | IArrow (s1,s2) -> IdSet.cup (fv_slot s1) (fv_slot s2)
371 | IRecord (o,r) ->
372 List.fold_left IdSet.cup IdSet.empty (LabelMap.map_to_list fv_slot r)
373 | ICapture x | IConstant (x,_) -> IdSet.singleton x
374
375
376 let compute_fv s =
377 match s.fv with
378 | Some x -> ()
379 | None ->
380 incr gen;
381 let x = fv_slot s in
382 s.fv <- Some x
383
384
385 let todo_fv = ref []
386
387 let mk () =
388 let s =
389 { d = None;
390 fv = None;
391 hash = None;
392 rank1 = 0; rank2 = 0;
393 gen1 = 0; gen2 = 0 } in
394 todo_fv := s :: !todo_fv;
395 s
396
397 let flush_fv () =
398 List.iter compute_fv !todo_fv;
399 todo_fv := []
400
401 let compile_slot_hash = DerecursTable.create 67
402 let compile_hash = DerecursTable.create 67
403
404 let defs = ref []
405
406 let rec compile p =
407 try DerecursTable.find compile_hash p
408 with Not_found ->
409 let c = real_compile p in
410 DerecursTable.replace compile_hash p c;
411 c
412 and real_compile = function
413 | PAlias v ->
414 if v.ploop then
415 raise_loc_generic v.ploc ("Unguarded recursion on type/pattern");
416 v.ploop <- true;
417 let r = match v.pdescr with Some x -> compile x | _ -> assert false in
418 v.ploop <- false;
419 r
420 | PType t -> IType t
421 | POr (t1,t2) -> IOr (compile t1, compile t2)
422 | PAnd (t1,t2) -> IAnd (compile t1, compile t2)
423 | PDiff (t1,t2) -> IDiff (compile t1, compile t2)
424 | PTimes (t1,t2) -> ITimes (compile_slot t1, compile_slot t2)
425 | PXml (t1,t2) -> IXml (compile_slot t1, compile_slot t2)
426 | PArrow (t1,t2) -> IArrow (compile_slot t1, compile_slot t2)
427 | POptional t -> IOptional (compile t)
428 | PRecord (o,r) -> IRecord (o, LabelMap.map compile_slot r)
429 | PConstant (x,v) -> IConstant (x,v)
430 | PCapture x -> ICapture x
431 | PRegexp (r,q) -> compile_regexp r q
432 and compile_regexp r q =
433 let memo = RE.create 17 in
434 let rec aux accu r q =
435 if RE.mem memo (r,q) then accu
436 else (
437 RE.add memo (r,q) ();
438 match r with
439 | PEpsilon ->
440 (match q with
441 | PRegexp (r,q) -> aux accu r q
442 | _ -> (compile q) :: accu)
443 | PElem p -> ITimes (compile_slot p, compile_slot q) :: accu
444 | PSeq (r1,r2) -> aux accu r1 (PRegexp (r2,q))
445 | PAlt (r1,r2) -> aux (aux accu r1 q) r2 q
446 | PStar r1 -> aux (aux accu r1 (PRegexp (r,q))) PEpsilon q
447 | PWeakStar r1 -> aux (aux accu PEpsilon q) r1 (PRegexp (r,q))
448 )
449 in
450 let accu = aux [] r q in
451 match accu with
452 | [] -> assert false
453 | p::l -> List.fold_left (fun acc p -> IOr (p,acc)) p l
454 and compile_slot p =
455 try DerecursTable.find compile_slot_hash p
456 with Not_found ->
457 let s = mk () in
458 defs := (s,p) :: !defs;
459 DerecursTable.add compile_slot_hash p s;
460 s
461
462
463 let rec flush_defs () =
464 match !defs with
465 | [] -> ()
466 | (s,p)::t -> defs := t; s.d <- Some (compile p); flush_defs ()
467
468 let typ_nodes = SlotTable.create 67
469 let pat_nodes = SlotTable.create 67
470
471 let rec typ = function
472 | IType t -> t
473 | IOr (s1,s2) -> Types.cup (typ s1) (typ s2)
474 | IAnd (s1,s2) -> Types.cap (typ s1) (typ s2)
475 | IDiff (s1,s2) -> Types.diff (typ s1) (typ s2)
476 | ITimes (s1,s2) -> Types.times (typ_node s1) (typ_node s2)
477 | IXml (s1,s2) -> Types.xml (typ_node s1) (typ_node s2)
478 | IArrow (s1,s2) -> Types.arrow (typ_node s1) (typ_node s2)
479 | IOptional s -> Types.Record.or_absent (typ s)
480 | IRecord (o,r) -> Types.record' (o, LabelMap.map typ_node r)
481 | ICapture x | IConstant (x,_) -> assert false
482
483 and typ_node s : Types.node =
484 try SlotTable.find typ_nodes s
485 with Not_found ->
486 let x = Types.make () in
487 SlotTable.add typ_nodes s x;
488 Types.define x (typ (descr s));
489 x
490
491 let rec pat d : Patterns.descr =
492 if IdSet.is_empty (fv_descr d)
493 then Patterns.constr (typ d)
494 else pat_aux d
495
496
497 and pat_aux = function
498 | IOr (s1,s2) -> Patterns.cup (pat s1) (pat s2)
499 | IAnd (s1,s2) -> Patterns.cap (pat s1) (pat s2)
500 | IDiff (s1,s2) when IdSet.is_empty (fv_descr s2) ->
501 let s2 = Types.neg (typ s2) in
502 Patterns.cap (pat s1) (Patterns.constr s2)
503 | IDiff _ ->
504 raise (Patterns.Error "Difference not allowed in patterns")
505 | ITimes (s1,s2) -> Patterns.times (pat_node s1) (pat_node s2)
506 | IXml (s1,s2) -> Patterns.xml (pat_node s1) (pat_node s2)
507 | IOptional _ ->
508 raise (Patterns.Error "Optional field not allowed in record patterns")
509 | IRecord (o,r) ->
510 let pats = ref [] in
511 let aux l s =
512 if IdSet.is_empty (fv_slot s) then typ_node s
513 else
514 ( pats := Patterns.record l (pat_node s) :: !pats;
515 Types.any_node )
516 in
517 let constr = Types.record' (o,LabelMap.mapi aux r) in
518 List.fold_left Patterns.cap (Patterns.constr constr) !pats
519 (* TODO: can avoid constr when o=true, and all fields have fv *)
520 | ICapture x -> Patterns.capture x
521 | IConstant (x,c) -> Patterns.constant x c
522 | IArrow _ ->
523 raise (Patterns.Error "Arrow not allowed in patterns")
524 | IType _ -> assert false
525
526 and pat_node s : Patterns.node =
527 try SlotTable.find pat_nodes s
528 with Not_found ->
529 let x = Patterns.make (fv_slot s) in
530 SlotTable.add pat_nodes s x;
531 Patterns.define x (pat (descr s));
532 x
533
534 let glb = State.ref "Typer.glb_env" TypeEnv.empty
535
536 let register_global_types b =
537 List.iter
538 (fun (v,p) ->
539 if TypeEnv.mem v !glb
540 then raise_loc_generic p.loc ("Multiple definition for type " ^ v)
541 ) b;
542 let old_glb = !glb in
543 try
544 glb := derecurs_def !glb b;
545 let b = List.map (fun (v,p) -> (v,p,compile (derecurs !glb p))) b in
546 flush_defs ();
547 flush_fv ();
548 let b =
549 List.map
550 (fun (v,p,s) ->
551 if not (IdSet.is_empty (fv_descr s)) then
552 raise_loc_generic p.loc
553 "Capture variables are not allowed in types";
554 let t = typ s in
555 if (p.loc <> noloc) && (Types.is_empty t) then
556 warning p.loc
557 ("This definition yields an empty type for " ^ v);
558 (v,t)) b in
559 List.iter (fun (v,t) -> Types.Print.register_global v t) b
560 with e ->
561 glb := old_glb;
562 raise e
563
564 let dump_global_types ppf =
565 TypeEnv.iter (fun v _ -> Format.fprintf ppf " %s" v) !glb
566
567 let do_typ loc r =
568 let s = compile_slot r in
569 flush_defs ();
570 flush_fv ();
571 if IdSet.is_empty (fv_slot s) then typ_node s
572 else raise_loc_generic loc "Capture variables are not allowed in types"
573
574 let typ p =
575 do_typ p.loc (derecurs !glb p)
576
577 let pat p =
578 let s = compile_slot (derecurs !glb p) in
579 flush_defs ();
580 flush_fv ();
581 try pat_node s
582 with Patterns.Error e -> raise_loc_generic p.loc e
583 | Location (loc,exn) when loc = noloc -> raise (Location (p.loc, exn))
584
585
586 (* II. Build skeleton *)
587
588 module Fv = IdSet
589
590 type branch = Branch of Typed.branch * branch list
591
592 let cur_branch : branch list ref = ref []
593
594 let exp loc fv e =
595 fv,
596 { Typed.exp_loc = loc;
597 Typed.exp_typ = Types.empty;
598 Typed.exp_descr = e;
599 }
600
601
602 let rec expr loc = function
603 | LocatedExpr (loc,e) -> expr loc e
604 | Forget (e,t) ->
605 let (fv,e) = expr loc e and t = typ t in
606 exp loc fv (Typed.Forget (e,t))
607 | Var s ->
608 exp loc (Fv.singleton s) (Typed.Var s)
609 | Apply (e1,e2) ->
610 let (fv1,e1) = expr loc e1 and (fv2,e2) = expr loc e2 in
611 exp loc (Fv.cup fv1 fv2) (Typed.Apply (e1,e2))
612 | Abstraction a ->
613 let iface = List.map (fun (t1,t2) -> (typ t1, typ t2))
614 a.fun_iface in
615 let t = List.fold_left
616 (fun accu (t1,t2) -> Types.cap accu (Types.arrow t1 t2))
617 Types.any iface in
618 let iface = List.map
619 (fun (t1,t2) -> (Types.descr t1, Types.descr t2))
620 iface in
621 let (fv0,body) = branches a.fun_body in
622 let fv = match a.fun_name with
623 | None -> fv0
624 | Some f -> Fv.remove f fv0 in
625 let e = Typed.Abstraction
626 { Typed.fun_name = a.fun_name;
627 Typed.fun_iface = iface;
628 Typed.fun_body = body;
629 Typed.fun_typ = t;
630 Typed.fun_fv = fv
631 } in
632 exp loc fv e
633 | Cst c ->
634 exp loc Fv.empty (Typed.Cst c)
635 | Pair (e1,e2) ->
636 let (fv1,e1) = expr loc e1 and (fv2,e2) = expr loc e2 in
637 exp loc (Fv.cup fv1 fv2) (Typed.Pair (e1,e2))
638 | Xml (e1,e2) ->
639 let (fv1,e1) = expr loc e1 and (fv2,e2) = expr loc e2 in
640 exp loc (Fv.cup fv1 fv2) (Typed.Xml (e1,e2))
641 | Dot (e,l) ->
642 let (fv,e) = expr loc e in
643 exp loc fv (Typed.Dot (e,l))
644 | RemoveField (e,l) ->
645 let (fv,e) = expr loc e in
646 exp loc fv (Typed.RemoveField (e,l))
647 | RecordLitt r ->
648 let fv = ref Fv.empty in
649 let r = LabelMap.map
650 (fun e ->
651 let (fv2,e) = expr loc e
652 in fv := Fv.cup !fv fv2; e)
653 r in
654 exp loc !fv (Typed.RecordLitt r)
655 | Op (op,le) ->
656 let (fvs,ltes) = List.split (List.map (expr loc) le) in
657 let fv = List.fold_left Fv.cup Fv.empty fvs in
658 (try
659 (match (ltes,Typed.find_op op) with
660 | [e], `Unary op -> exp loc fv (Typed.UnaryOp (op, e))
661 | [e1;e2], `Binary op -> exp loc fv (Typed.BinaryOp (op, e1,e2))
662 | _ -> assert false)
663 with Not_found -> assert false)
664
665 | Match (e,b) ->
666 let (fv1,e) = expr loc e
667 and (fv2,b) = branches b in
668 exp loc (Fv.cup fv1 fv2) (Typed.Match (e, b))
669 | Map (e,b) ->
670 let (fv1,e) = expr loc e
671 and (fv2,b) = branches b in
672 exp loc (Fv.cup fv1 fv2) (Typed.Map (e, b))
673 | Transform (e,b) ->
674 let (fv1,e) = expr loc e
675 and (fv2,b) = branches b in
676 exp loc (Fv.cup fv1 fv2) (Typed.Transform (e, b))
677 | Xtrans (e,b) ->
678 let (fv1,e) = expr loc e
679 and (fv2,b) = branches b in
680 exp loc (Fv.cup fv1 fv2) (Typed.Xtrans (e, b))
681 | Validate (e,schema,elt) ->
682 let (fv,e) = expr loc e in
683 exp loc fv (Typed.Validate (e, schema, elt))
684 | Try (e,b) ->
685 let (fv1,e) = expr loc e
686 and (fv2,b) = branches b in
687 exp loc (Fv.cup fv1 fv2) (Typed.Try (e, b))
688
689
690 and branches b =
691 let fv = ref Fv.empty in
692 let accept = ref Types.empty in
693 let branch (p,e) =
694 let cur_br = !cur_branch in
695 cur_branch := [];
696 let (fv2,e) = expr noloc e in
697 let br_loc = merge_loc p.loc e.Typed.exp_loc in
698 let p = pat p in
699 let fv2 = Fv.diff fv2 (Patterns.fv p) in
700 fv := Fv.cup !fv fv2;
701 accept := Types.cup !accept (Types.descr (Patterns.accept p));
702 let br =
703 {
704 Typed.br_loc = br_loc;
705 Typed.br_used = br_loc = noloc;
706 Typed.br_pat = p;
707 Typed.br_body = e } in
708 cur_branch := Branch (br, !cur_branch) :: cur_br;
709 br in
710 let b = List.map branch b in
711 (!fv,
712 {
713 Typed.br_typ = Types.empty;
714 Typed.br_branches = b;
715 Typed.br_accept = !accept;
716 Typed.br_compiled = None;
717 }
718 )
719
720 let expr = expr noloc
721
722 let let_decl p e =
723 let (_,e) = expr e in
724 { Typed.let_pat = pat p;
725 Typed.let_body = e;
726 Typed.let_compiled = None }
727
728 (* III. Type-checks *)
729
730 type env = Types.descr Env.t
731
732 open Typed
733
734 let require loc t s =
735 if not (Types.subtype t s) then raise_loc loc (Constraint (t, s))
736
737 let check loc t s =
738 require loc t s; t
739
740 let should_have loc constr s =
741 raise_loc loc (ShouldHave (constr,s))
742
743 let flatten loc arg constr precise =
744 let constr' = Sequence.star
745 (Sequence.approx (Types.cap Sequence.any constr)) in
746 let sconstr' = Sequence.star constr' in
747 let exact = Types.subtype constr' constr in
748 if exact then
749 let t = arg sconstr' precise in
750 if precise then Sequence.flatten t else constr
751 else
752 let t = arg sconstr' true in
753 Sequence.flatten t
754
755 let rec type_check env e constr precise =
756 let d = type_check' e.exp_loc env e.exp_descr constr precise in
757 let d = if precise then d else constr in
758 e.exp_typ <- Types.cup e.exp_typ d;
759 d
760
761 and type_check' loc env e constr precise = match e with
762 | Forget (e,t) ->
763 let t = Types.descr t in
764 ignore (type_check env e t false);
765 check loc t constr
766
767 | Abstraction a ->
768 let t =
769 try Types.Arrow.check_strenghten a.fun_typ constr
770 with Not_found ->
771 should_have loc constr
772 "but the interface of the abstraction is not compatible"
773 in
774 let env = match a.fun_name with
775 | None -> env
776 | Some f -> Env.add f a.fun_typ env in
777 List.iter
778 (fun (t1,t2) ->
779 let acc = a.fun_body.br_accept in
780 if not (Types.subtype t1 acc) then
781 raise_loc loc (NonExhaustive (Types.diff t1 acc));
782 ignore (type_check_branches loc env t1 a.fun_body t2 false)
783 ) a.fun_iface;
784 t
785
786 | Match (e,b) ->
787 let t = type_check env e b.br_accept true in
788 type_check_branches loc env t b constr precise
789
790 | Try (e,b) ->
791 let te = type_check env e constr precise in
792 let tb = type_check_branches loc env Types.any b constr precise in
793 Types.cup te tb
794
795 | Pair (e1,e2) ->
796 type_check_pair loc env e1 e2 constr precise
797
798 | Xml (e1,e2) ->
799 type_check_pair ~kind:`XML loc env e1 e2 constr precise
800
801 | RecordLitt r ->
802 type_record loc env r constr precise
803
804 | Map (e,b) ->
805 type_map loc env false e b constr precise
806
807 | Transform (e,b) ->
808 flatten loc (type_map loc env true e b) constr precise
809
810 | Apply (e1,e2) ->
811 let t1 = type_check env e1 Types.Arrow.any true in
812 let t1 = Types.Arrow.get t1 in
813 let dom = Types.Arrow.domain t1 in
814 let res =
815 if Types.Arrow.need_arg t1 then
816 let t2 = type_check env e2 dom true in
817 Types.Arrow.apply t1 t2
818 else
819 (ignore (type_check env e2 dom false); Types.Arrow.apply_noarg t1)
820 in
821 check loc res constr
822
823 | UnaryOp (o,e) ->
824 let t = o.un_op_typer loc
825 (type_check env e) constr precise in
826 check loc t constr
827
828 | BinaryOp (o,e1,e2) ->
829 let t = o.bin_op_typer loc
830 (type_check env e1)
831 (type_check env e2) constr precise in
832 check loc t constr
833
834 | Var s ->
835 let t =
836 try Env.find s env
837 with Not_found -> raise_loc loc (UnboundId s) in
838 check loc t constr
839
840 | Cst c ->
841 check loc (Types.constant c) constr
842
843 | Dot (e,l) ->
844 let t = type_check env e Types.Record.any true in
845 let t =
846 try (Types.Record.project t l)
847 with Not_found -> raise_loc loc (WrongLabel(t,l))
848 in
849 check loc t constr
850
851 | RemoveField (e,l) ->
852 let t = type_check env e Types.Record.any true in
853 let t = Types.Record.remove_field t l in
854 check loc t constr
855
856 | Xtrans (e,b) ->
857 let t = type_check env e Sequence.any true in
858 let t =
859 Sequence.map_tree
860 (fun t ->
861 let resid = Types.diff t b.br_accept in
862 let res = type_check_branches loc env t b Sequence.any true in
863 (res,resid)
864 ) t in
865 check loc t constr
866
867 | Validate (e, schema_name, elt_name) ->
868 ignore (type_check env e Types.any false);
869 let t = fst (Hashtbl.find !schema_elements (schema_name, elt_name)) in
870 check loc t constr
871
872 and type_check_pair ?(kind=`Normal) loc env e1 e2 constr precise =
873 let rects = Types.Product.normal ~kind constr in
874 if Types.Product.is_empty rects then
875 (match kind with
876 | `Normal -> should_have loc constr "but it is a pair"
877 | `XML -> should_have loc constr "but it is an XML element");
878 let need_s = Types.Product.need_second rects in
879 let t1 = type_check env e1 (Types.Product.pi1 rects) (precise || need_s) in
880 let c2 = Types.Product.constraint_on_2 rects t1 in
881 if Types.is_empty c2 then
882 raise_loc loc (ShouldHave2 (constr,"but the first component has type",t1));
883 let t2 = type_check env e2 c2 precise in
884
885 if precise then
886 match kind with
887 | `Normal -> Types.times (Types.cons t1) (Types.cons t2)
888 | `XML -> Types.xml (Types.cons t1) (Types.cons t2)
889 else
890 constr
891
892 and type_record loc env r constr precise =
893 (* try to get rid of precise = true for values of fields *)
894 (* also: the use equivalent of need_second to optimize... *)
895 if not (Types.Record.has_record constr) then
896 should_have loc constr "but it is a record";
897 let (rconstr,res) =
898 List.fold_left
899 (fun (rconstr,res) (l,e) ->
900 (* could compute (split l e) once... *)
901 let pi = Types.Record.project_opt rconstr l in
902 if Types.is_empty pi then
903 (let l = U.to_string (LabelPool.value l) in
904 should_have loc constr
905 (Printf.sprintf "Field %s is not allowed here." l));
906 let t = type_check env e pi true in
907 let rconstr = Types.Record.condition rconstr l t in
908 let res = (l,Types.cons t) :: res in
909 (rconstr,res)
910 ) (constr, []) (LabelMap.get r)
911 in
912 if not (Types.Record.has_empty_record rconstr) then
913 should_have loc constr "More fields should be present";
914 let t =
915 Types.record' (false, LabelMap.from_list (fun _ _ -> assert false) res)
916 in
917 check loc t constr
918
919
920 and type_check_branches loc env targ brs constr precise =
921 if Types.is_empty targ then Types.empty
922 else (
923 brs.br_typ <- Types.cup brs.br_typ targ;
924 branches_aux loc env targ
925 (if precise then Types.empty else constr)
926 constr precise brs.br_branches
927 )
928
929 and branches_aux loc env targ tres constr precise = function
930 | [] -> tres
931 | b :: rem ->
932 let p = b.br_pat in
933 let acc = Types.descr (Patterns.accept p) in
934
935 let targ' = Types.cap targ acc in
936 if Types.is_empty targ'
937 then branches_aux loc env targ tres constr precise rem
938 else
939 ( b.br_used <- true;
940 let res = Patterns.filter targ' p in
941 let env' = List.fold_left
942 (fun env (x,t) -> Env.add x (Types.descr t) env)
943 env res in
944 let t = type_check env' b.br_body constr precise in
945 let tres = if precise then Types.cup t tres else tres in
946 let targ'' = Types.diff targ acc in
947 if (Types.non_empty targ'') then
948 branches_aux loc env targ'' tres constr precise rem
949 else
950 tres
951 )
952
953 and type_map loc env def e b constr precise =
954 let acc = if def then Sequence.any else Sequence.star b.br_accept in
955 let t = type_check env e acc true in
956
957 let constr' = Sequence.approx (Types.cap Sequence.any constr) in
958 let exact = Types.subtype (Sequence.star constr') constr in
959 (* Note:
960 - could be more precise by integrating the decomposition
961 of constr inside Sequence.map.
962 *)
963 let res =
964 Sequence.map
965 (fun t ->
966 let res =
967 type_check_branches loc env t b constr' (precise || (not exact)) in
968 if def && not (Types.subtype t b.br_accept)
969 then Types.cup res Sequence.nil_type
970 else res)
971 t in
972 if exact then res else check loc res constr
973
974 and type_let_decl env l =
975 let acc = Types.descr (Patterns.accept l.let_pat) in
976 let t = type_check env l.let_body acc true in
977 let res = Patterns.filter t l.let_pat in
978 List.map (fun (x,t) -> (x, Types.descr t)) res
979
980 and type_rec_funs env l =
981 let types =
982 List.fold_left
983 (fun accu -> function
984 | { exp_descr=Abstraction { fun_typ = t; fun_name = Some f } } ->
985 (f,t) :: accu
986 | _ -> assert false
987 ) [] l
988 in
989 let env' = List.fold_left (fun env (x,t) -> Env.add x t env) env types in
990 List.iter (fun e -> ignore (type_check env' e Types.any false)) l;
991 types
992
993
994 let rec unused_branches b =
995 List.iter
996 (fun (Branch (br,s)) ->
997 if not br.br_used
998 then warning br.br_loc "This branch is not used"
999 else unused_branches s
1000 )
1001 b
1002
1003 let report_unused_branches () =
1004 unused_branches !cur_branch;
1005 cur_branch := []
1006
1007 (* Schema stuff from now on ... *)
1008
1009 let debug = true
1010
1011 (** convertion from XML Schema types (including global elements and
1012 attributes) to CDuce Types.descr *)
1013 module Schema_converter =
1014 struct
1015
1016 open Printf
1017 open Schema_types
1018
1019 (* auxiliary functions *)
1020
1021 (* build a regexp Elem from a Types.descr *)
1022 let mk_re_elt descr = PElem descr
1023
1024 (* conversion functions *)
1025
1026 let cd_type_of_simple_type = function
1027 | SBuilt_in name -> PType (Schema_builtin.cd_type_of_builtin name)
1028 | SUser_defined (_, _, _, _) -> assert false (* TODO *)
1029
1030 let complex_memo = Hashtbl.create 213
1031
1032 let rec regexp_of_term = function
1033 | All [] | Choice [] | Sequence [] -> PEpsilon
1034 | Choice (hd :: tl) ->
1035 List.fold_left
1036 (fun acc particle -> PAlt (acc, regexp_of_particle particle))
1037 (regexp_of_particle hd) tl
1038 | All (hd :: tl) | Sequence (hd :: tl) ->
1039 List.fold_left
1040 (fun acc particle -> PSeq (acc, regexp_of_particle particle))
1041 (regexp_of_particle hd) tl
1042 | Elt decl -> mk_re_elt (cd_type_of_elt_decl !decl)
1043
1044 and regexp_of_content_type = function
1045 | CT_empty -> PEpsilon
1046 | CT_simple st -> mk_re_elt (cd_type_of_simple_type st)
1047 | CT_model (particle, mixed) ->
1048 assert (not mixed); (* TODO mixed support *)
1049 regexp_of_particle particle
1050
1051 and regexp_of_particle =
1052 (* given a regexp re and a (non negative) integer n create a regexp
1053 matching exactly n times re *)
1054 let rec repeat_regexp re = function
1055 | 0 -> PEpsilon
1056 | n when n > 0 -> PSeq (re, repeat_regexp re (n - 1))
1057 | _ -> assert false
1058 in
1059 fun (min, max, term) ->
1060 let term_regexp = regexp_of_term term in
1061 let min_regexp = repeat_regexp term_regexp min in
1062 match max with
1063 | Some max ->
1064 assert (max >= min);
1065 let rec aux acc = function
1066 | 0 -> acc
1067 | n ->
1068 aux
1069 (PAlt (PEpsilon, (PSeq (term_regexp, acc))))
1070 (n - 1)
1071 in
1072 PSeq (min_regexp, aux PEpsilon (max - min))
1073 | None -> PSeq (min_regexp, PStar term_regexp)
1074
1075 (** @return a pair composed by a type for the attributes (a record) and a
1076 type for the content model (a sequence) *)
1077 and cd_type_of_complex_type' = function
1078 | CBuilt_in name -> assert false
1079 | CUser_defined (id, name, _, _, attr_uses, content) ->
1080 try PAlias (Hashtbl.find complex_memo id)
1081 with Not_found ->
1082 let slot = mk_slot noloc in
1083 Hashtbl.add complex_memo id slot;
1084 let content_re = regexp_of_content_type content in
1085 let content_ast_node = PRegexp (content_re, PType Sequence.nil_type) in
1086 slot.pdescr <- Some
1087 (PTimes (cd_type_of_attr_uses attr_uses, content_ast_node));
1088 PAlias slot
1089
1090
1091 (* TODO if constraint is Fixed we can give a more precise CDuce type *)
1092
1093 (** @return a closed record *)
1094 and cd_type_of_attr_uses attr_uses =
1095 let fields =
1096 List.map
1097 (fun (required, (name, st, _), _) ->
1098 let r = cd_type_of_simple_type st in
1099 let r = if required then r else POptional r in
1100 (LabelPool.mk (U.mk name), r)
1101 ) attr_uses in
1102 PRecord (false, LabelMap.from_list_disj fields)
1103
1104 and cd_type_of_att_decl (name, st, _) =
1105 let r = cd_type_of_simple_type st in
1106 PRecord (false, LabelMap.from_list_disj [(LabelPool.mk (U.mk name), r)])
1107
1108 and cd_type_of_elt_decl (name, typ, _) =
1109 let atom_type = PType (Types.atom (Atoms.atom (Atoms.mk (U.mk name)))) in
1110 let content = match !typ with
1111 | S st ->
1112 PTimes (PType Types.empty_closed_record, cd_type_of_simple_type st)
1113 | C ct -> cd_type_of_complex_type' ct
1114 in
1115 PXml (atom_type, content)
1116
1117 let typ r = Types.descr (do_typ noloc r)
1118
1119 let cd_type_of_complex_type = function
1120 | CBuilt_in name -> Schema_builtin.cd_type_of_builtin name
1121 | ct -> typ (PXml (PType Types.any, cd_type_of_complex_type' ct))
1122
1123 let cd_type_of_type_def = function
1124 | S st -> typ (cd_type_of_simple_type st)
1125 | C ct -> cd_type_of_complex_type ct
1126
1127 let cd_type_of_elt_decl x = typ (cd_type_of_elt_decl x)
1128 let cd_type_of_att_decl x = typ (cd_type_of_att_decl x)
1129
1130 end
1131
1132 let get_schema_validator (schema_name, elt_name) =
1133 snd (Hashtbl.find !schema_elements (schema_name, elt_name))
1134
1135 let register_schema schema_name schema =
1136 if StringSet.mem schema_name !schemas then
1137 failwith ("Redefinition of schema " ^ schema_name)
1138 else begin
1139 schemas := StringSet.add schema_name !schemas;
1140 List.iter (* Schema types -> CDuce types *)
1141 (fun type_def ->
1142 let cd_type = Schema_converter.cd_type_of_type_def type_def in
1143 Hashtbl.add !schema_types
1144 (schema_name, Schema_types.name_of_type_def type_def)
1145 cd_type)
1146 schema.Schema_types.type_defs;
1147 List.iter (* Schema attributes -> CDuce types *)
1148 (fun (att_name, _, _) as att_decl ->
1149 let cd_type = Schema_converter.cd_type_of_att_decl att_decl in
1150 Hashtbl.add !schema_attributes (schema_name, att_name) cd_type)
1151 schema.Schema_types.att_decls;
1152 List.iter (* Schema elements -> CDuce types * validators *)
1153 (fun elt_decl ->
1154 let cd_type = Schema_converter.cd_type_of_elt_decl elt_decl in
1155 if debug then
1156 (Types.Print.print Format.std_formatter cd_type;
1157 Format.fprintf Format.std_formatter "\n";
1158 Format.pp_print_flush Format.std_formatter ());
1159 let validator = Schema_validator.validator_of_elt_decl elt_decl in
1160 Hashtbl.add !schema_elements
1161 (schema_name, Schema_types.name_of_elt_decl elt_decl)
1162 (cd_type, validator))
1163 schema.Schema_types.elt_decls
1164 end
1165
1166 (* DEBUGGING ONLY *)
1167
1168 let get_schema_type x = fst (Hashtbl.find !schema_elements x)

CVS Admin">CVS Admin
ViewVC Help
Powered by ViewVC 1.1.5