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

Diff of /typing/typer.ml

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

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

Legend:
Removed from v.72  
changed lines
  Added in v.1401

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