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

Contents of /typing/typer.ml

Parent Directory Parent Directory | Revision Log Revision Log


Revision 677 - (show annotations)
Tue Jul 10 17:53:53 2007 UTC (5 years, 10 months ago) by abate
File size: 41873 byte(s)
[r2003-09-24 23:21:08 by cvscast] Cleaning

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

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