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

Diff of /typing/typer.ml

Parent Directory Parent Directory | Revision Log Revision Log | View Patch Patch

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

Legend:
Removed from v.16  
changed lines
  Added in v.1294

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