| 1 |
(* TODO: |
(* TODO: |
| 2 |
- rewrite type-checking of operators to propagate constraint |
- rewrite type-checking of operators to propagate constraint |
| 3 |
- rewrite translation of types and patterns -> hash cons |
- optimize computation of pattern free variables |
| 4 |
CONTINUE THIS... |
- check whether it is worth using recursive hash-consing internally |
|
Problem with same name for recursive binders in different |
|
|
recursive type/patterns definitions because of hash-consing |
|
| 5 |
*) |
*) |
| 6 |
|
|
| 7 |
|
|
| 15 |
module S = struct type t = string let compare = compare end |
module S = struct type t = string let compare = compare end |
| 16 |
module StringSet = Set.Make(S) |
module StringSet = Set.Make(S) |
| 17 |
module TypeEnv = Map.Make(S) |
module TypeEnv = Map.Make(S) |
| 18 |
module Env = Map.Make(Ident.Id) |
module Env = Map.Make(Id) |
| 19 |
|
|
| 20 |
|
|
| 21 |
exception NonExhaustive of Types.descr |
exception NonExhaustive of Types.descr |
| 26 |
|
|
| 27 |
let raise_loc loc exn = raise (Location (loc,exn)) |
let raise_loc loc exn = raise (Location (loc,exn)) |
| 28 |
|
|
|
(* 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) |
|
| 29 |
|
|
| 30 |
It would be possible (and a little more efficient) to produce |
(* Eliminate Recursion, propagate Sequence Capture Variables *) |
|
directly ti nodes. |
|
|
*) |
|
|
|
|
|
module Regexp = struct |
|
|
let defs = ref [] |
|
|
let name = |
|
|
let c = ref 0 in |
|
|
fun () -> |
|
|
incr c; |
|
|
"#" ^ (string_of_int !c) |
|
| 31 |
|
|
| 32 |
let rec seq_vars accu = function |
let rec seq_vars accu = function |
| 33 |
| Epsilon | Elem _ -> accu |
| Epsilon | Elem _ -> accu |
| 35 |
| Star r | WeakStar r -> seq_vars accu r |
| Star r | WeakStar r -> seq_vars accu r |
| 36 |
| SeqCapture (v,r) -> seq_vars (IdSet.add v accu) r |
| SeqCapture (v,r) -> seq_vars (IdSet.add v accu) r |
| 37 |
|
|
| 38 |
let uniq_id = let r = ref 0 in fun () -> incr r; !r |
type derecurs_slot = { |
| 39 |
|
ploc : Location.loc; |
| 40 |
type flat = |
pid : int; |
| 41 |
| REpsilon |
mutable ploop : bool; |
| 42 |
| RElem of int * Ast.ppat (* the int arg is used |
mutable pdescr : derecurs option |
| 43 |
to stop generic comparison *) |
} and derecurs = |
| 44 |
| RSeq of flat * flat |
| PAlias of derecurs_slot |
| 45 |
| RAlt of flat * flat |
| PType of Types.descr |
| 46 |
| RStar of flat |
| POr of derecurs * derecurs |
| 47 |
| RWeakStar of flat |
| PAnd of derecurs * derecurs |
| 48 |
|
| PDiff of derecurs * derecurs |
| 49 |
let re_loc = ref noloc |
| PTimes of derecurs * derecurs |
| 50 |
|
| PXml of derecurs * derecurs |
| 51 |
let rec propagate vars : regexp -> flat = function |
| PArrow of derecurs * derecurs |
| 52 |
| Epsilon -> REpsilon |
| POptional of derecurs |
| 53 |
| Elem x -> let p = vars x in RElem (uniq_id (),p) |
| PRecord of bool * derecurs label_map |
| 54 |
| Seq (r1,r2) -> RSeq (propagate vars r1,propagate vars r2) |
| PCapture of id |
| 55 |
| Alt (r1,r2) -> RAlt (propagate vars r1, propagate vars r2) |
| PConstant of id * Types.const |
| 56 |
| Star r -> RStar (propagate vars r) |
| PRegexp of derecurs_regexp * derecurs |
| 57 |
| WeakStar r -> RWeakStar (propagate vars r) |
and derecurs_regexp = |
| 58 |
| SeqCapture (v,x) -> |
| PEpsilon |
| 59 |
let v= mk_loc !re_loc (Capture v) in |
| PElem of derecurs |
| 60 |
propagate (fun p -> mk_loc !re_loc (And (vars p,v))) x |
| PSeq of derecurs_regexp * derecurs_regexp |
| 61 |
|
| PAlt of derecurs_regexp * derecurs_regexp |
| 62 |
let dummy_pat = mknoloc (PatVar "DUMMY") |
| PStar of derecurs_regexp |
| 63 |
let cup r1 r2 = |
| PWeakStar of derecurs_regexp |
| 64 |
if r1 == dummy_pat then r2 else |
|
| 65 |
if r2 == dummy_pat then r1 else |
let rec hash_derecurs = function |
| 66 |
mk_loc !re_loc (Or (r1,r2)) |
| PAlias s -> s.pid |
| 67 |
|
| PType t -> 1 + 17 * (Types.hash_descr t) |
| 68 |
(*TODO: review this compilation schema to avoid explosion when |
| POr (p1,p2) -> 2 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2) |
| 69 |
coding (Optional x) by (Or(Epsilon,x)); memoization ... *) |
| PAnd (p1,p2) -> 3 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2) |
| 70 |
|
| PDiff (p1,p2) -> 4 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2) |
| 71 |
module Memo = Map.Make(struct type t = flat list let compare = compare end) |
| PTimes (p1,p2) -> 5 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2) |
| 72 |
module Coind = Set.Make(struct type t = flat list let compare = compare end) |
| PXml (p1,p2) -> 6 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2) |
| 73 |
let memo = ref Memo.empty |
| PArrow (p1,p2) -> 7 + 17 * (hash_derecurs p1) + 257 * (hash_derecurs p2) |
| 74 |
|
| POptional p -> 8 + 17 * (hash_derecurs p) |
| 75 |
|
| PRecord (o,r) -> (if o then 9 else 10) + 17 * (LabelMap.hash hash_derecurs r) |
| 76 |
|
| PCapture x -> 11 + 17 * (Id.hash x) |
| 77 |
|
| PConstant (x,c) -> 12 + 17 * (Id.hash x) + 257 * (Types.hash_const c) |
| 78 |
|
| PRegexp (p,q) -> 13 + 17 * (hash_derecurs_regexp p) + 257 * (hash_derecurs q) |
| 79 |
|
and hash_derecurs_regexp = function |
| 80 |
|
| PEpsilon -> 1 |
| 81 |
|
| PElem p -> 2 + 17 * (hash_derecurs p) |
| 82 |
|
| PSeq (p1,p2) -> 3 + 17 * (hash_derecurs_regexp p1) + 257 * (hash_derecurs_regexp p2) |
| 83 |
|
| PAlt (p1,p2) -> 4 + 17 * (hash_derecurs_regexp p1) + 257 * (hash_derecurs_regexp p2) |
| 84 |
|
| PStar p -> 5 + 17 * (hash_derecurs_regexp p) |
| 85 |
|
| PWeakStar p -> 6 + 17 * (hash_derecurs_regexp p) |
| 86 |
|
|
| 87 |
|
let rec equal_derecurs p1 p2 = (p1 == p2) || match p1,p2 with |
| 88 |
|
| PAlias s1, PAlias s2 -> s1 == s2 |
| 89 |
|
| PType t1, PType t2 -> Types.equal_descr t1 t2 |
| 90 |
|
| POr (p1,q1), POr (p2,q2) |
| 91 |
|
| PAnd (p1,q1), PAnd (p2,q2) |
| 92 |
|
| PDiff (p1,q1), PDiff (p2,q2) |
| 93 |
|
| PTimes (p1,q1), PTimes (p2,q2) |
| 94 |
|
| PXml (p1,q1), PXml (p2,q2) |
| 95 |
|
| PArrow (p1,q1), PArrow (p2,q2) -> (equal_derecurs p1 p2) && (equal_derecurs q1 q2) |
| 96 |
|
| POptional p1, POptional p2 -> equal_derecurs p1 p2 |
| 97 |
|
| PRecord (o1,r1), PRecord (o2,r2) -> (o1 == o2) && (LabelMap.equal equal_derecurs r1 r2) |
| 98 |
|
| PCapture x1, PCapture x2 -> Id.equal x1 x2 |
| 99 |
|
| PConstant (x1,c1), PConstant (x2,c2) -> (Id.equal x1 x2) && (Types.equal_const c1 c2) |
| 100 |
|
| PRegexp (p1,q1), PRegexp (p2,q2) -> (equal_derecurs_regexp p1 p2) && (equal_derecurs q1 q2) |
| 101 |
|
| _ -> false |
| 102 |
|
and equal_derecurs_regexp r1 r2 = match r1,r2 with |
| 103 |
|
| PEpsilon, PEpsilon -> true |
| 104 |
|
| PElem p1, PElem p2 -> equal_derecurs p1 p2 |
| 105 |
|
| PSeq (p1,q1), PSeq (p2,q2) |
| 106 |
|
| PAlt (p1,q1), PAlt (p2,q2) -> (equal_derecurs_regexp p1 p2) && (equal_derecurs_regexp q1 q2) |
| 107 |
|
| PStar p1, PStar p2 |
| 108 |
|
| PWeakStar p1, PWeakStar p2 -> equal_derecurs_regexp p1 p2 |
| 109 |
|
| _ -> false |
| 110 |
|
|
| 111 |
let rec compile fin e seq : Ast.ppat = |
module DerecursTable = Hashtbl.Make( |
| 112 |
if Coind.mem seq !e then dummy_pat |
struct |
| 113 |
else ( |
type t = derecurs |
| 114 |
e := Coind.add seq !e; |
let hash = hash_derecurs |
| 115 |
match seq with |
let equal = equal_derecurs |
| 116 |
| [] -> |
end |
|
fin |
|
|
| REpsilon :: rest -> |
|
|
compile fin e rest |
|
|
| RElem (_,p) :: rest -> |
|
|
mk_loc !re_loc (Prod (p, guard_compile fin rest)) |
|
|
| RSeq (r1,r2) :: rest -> |
|
|
compile fin e (r1 :: r2 :: rest) |
|
|
| RAlt (r1,r2) :: rest -> |
|
|
cup (compile fin e (r1::rest)) (compile fin e (r2::rest)) |
|
|
| RStar r :: rest -> |
|
|
cup (compile fin e (r::seq)) (compile fin e rest) |
|
|
| RWeakStar r :: rest -> |
|
|
cup (compile fin e rest) (compile fin e (r::seq)) |
|
| 117 |
) |
) |
|
and guard_compile fin seq = |
|
|
try Memo.find seq !memo |
|
|
with |
|
|
Not_found -> |
|
|
let n = name () in |
|
|
let v = mk_loc !re_loc (PatVar n) in |
|
|
memo := Memo.add seq v !memo; |
|
|
let d = compile fin (ref Coind.empty) seq in |
|
|
assert (d != dummy_pat); |
|
|
defs := (n,d) :: !defs; |
|
|
v |
|
|
|
|
|
let constant_nil t v = |
|
|
mk_loc !re_loc |
|
|
(And (t, (mk_loc !re_loc (Constant (v, Types.Atom Sequence.nil_atom))))) |
|
|
|
|
|
let compile loc regexp queue : ppat = |
|
|
re_loc := loc; |
|
|
let vars = seq_vars IdSet.empty regexp in |
|
|
let fin = IdSet.fold constant_nil queue vars in |
|
|
let re = propagate (fun p -> p) regexp in |
|
|
let n = guard_compile fin [re] in |
|
|
memo := Memo.empty; |
|
|
let d = !defs in |
|
|
defs := []; |
|
|
mk_loc !re_loc (Recurs (n,d)) |
|
| 118 |
|
|
| 119 |
(* |
module RE = Hashtbl.Make( |
|
module H = Hashtbl.Make( |
|
| 120 |
struct |
struct |
| 121 |
type t = Ast.regexp * Ast.ppat |
type t = derecurs_regexp * derecurs |
| 122 |
let equal (r1,p1) (r2,p2) = |
let hash (p,q) = (hash_derecurs_regexp p) + 17 * (hash_derecurs q) |
| 123 |
(Ast.equal_regexp r1 r2) && |
let equal (p1,q1) (p2,q2) = (equal_derecurs_regexp p1 p2) && (equal_derecurs q1 q2) |
|
(Ast.equal_ppat p1 p2) |
|
|
let hash (r,p) = |
|
|
(Ast.hash_regexp r) + 16637 * (Ast.hash_ppat p) |
|
|
end) |
|
|
let hash = H.create 67 |
|
|
|
|
|
let compile loc regexp queue : ppat = |
|
|
try |
|
|
let c = H.find hash (regexp,queue) in |
|
|
(* Printf.eprintf "regexp cached\n"; flush stderr; *) |
|
|
c |
|
|
with |
|
|
Not_found -> |
|
|
let c = compile loc regexp queue in |
|
|
H.add hash (regexp,queue) c; |
|
|
c |
|
|
*) |
|
| 124 |
end |
end |
| 125 |
|
) |
| 126 |
|
|
| 127 |
|
|
| 128 |
|
let counter = State.ref "Typer.counter - derecurs" 0 |
| 129 |
|
let mk_slot loc = |
| 130 |
|
incr counter; |
| 131 |
|
{ ploop = false; ploc = loc; pid = !counter; pdescr = None } |
| 132 |
|
|
| 133 |
|
let rec derecurs env p = match p.descr with |
| 134 |
|
| PatVar v -> |
| 135 |
|
(try PAlias (TypeEnv.find v env) |
| 136 |
|
with Not_found -> raise_loc_generic p.loc ("Undefined type/pattern " ^ v)) |
| 137 |
|
| Recurs (p,b) -> derecurs (derecurs_def env b) p |
| 138 |
|
| Internal t -> PType t |
| 139 |
|
| Or (p1,p2) -> POr (derecurs env p1, derecurs env p2) |
| 140 |
|
| And (p1,p2) -> PAnd (derecurs env p1, derecurs env p2) |
| 141 |
|
| Diff (p1,p2) -> PDiff (derecurs env p1, derecurs env p2) |
| 142 |
|
| Prod (p1,p2) -> PTimes (derecurs env p1, derecurs env p2) |
| 143 |
|
| XmlT (p1,p2) -> PXml (derecurs env p1, derecurs env p2) |
| 144 |
|
| Arrow (p1,p2) -> PArrow (derecurs env p1, derecurs env p2) |
| 145 |
|
| Optional p -> POptional (derecurs env p) |
| 146 |
|
| Record (o,r) -> PRecord (o, LabelMap.map (derecurs env) r) |
| 147 |
|
| Capture x -> PCapture x |
| 148 |
|
| Constant (x,c) -> PConstant (x,c) |
| 149 |
|
| Regexp (r,q) -> |
| 150 |
|
let constant_nil t v = PAnd (t, PConstant (v, Types.Atom Sequence.nil_atom)) in |
| 151 |
|
let vars = seq_vars IdSet.empty r in |
| 152 |
|
let q = IdSet.fold constant_nil (derecurs env q) vars in |
| 153 |
|
let r = derecurs_regexp (fun p -> p) env r in |
| 154 |
|
PRegexp (r, q) |
| 155 |
|
and derecurs_regexp vars env = function |
| 156 |
|
| Epsilon -> PEpsilon |
| 157 |
|
| Elem p -> PElem (vars (derecurs env p)) |
| 158 |
|
| Seq (p1,p2) -> PSeq (derecurs_regexp vars env p1, derecurs_regexp vars env p2) |
| 159 |
|
| Alt (p1,p2) -> PAlt (derecurs_regexp vars env p1, derecurs_regexp vars env p2) |
| 160 |
|
| Star p -> PStar (derecurs_regexp vars env p) |
| 161 |
|
| WeakStar p -> PStar (derecurs_regexp vars env p) |
| 162 |
|
| SeqCapture (x,p) -> derecurs_regexp (fun p -> PAnd (vars p, PCapture x)) env p |
| 163 |
|
|
| 164 |
|
|
| 165 |
|
and derecurs_def env b = |
| 166 |
|
let b = List.map (fun (v,p) -> (v,p,mk_slot p.loc)) b in |
| 167 |
|
let env = List.fold_left (fun env (v,p,s) -> TypeEnv.add v s env) env b in |
| 168 |
|
List.iter (fun (v,p,s) -> s.pdescr <- Some (derecurs env p)) b; |
| 169 |
|
env |
| 170 |
|
|
| 171 |
|
(* Stratification and recursive hash-consing *) |
| 172 |
|
|
|
(* |
|
| 173 |
type descr = |
type descr = |
| 174 |
| IType of Types.descr |
| IType of Types.descr |
| 175 |
| IOr of descr * descr |
| IOr of descr * descr |
| 178 |
| ITimes of slot * slot |
| ITimes of slot * slot |
| 179 |
| IXml of slot * slot |
| IXml of slot * slot |
| 180 |
| IArrow of slot * slot |
| IArrow of slot * slot |
| 181 |
| IOptional of slot descr |
| IOptional of descr |
| 182 |
| IRecord of bool * slot label_map |
| IRecord of bool * slot label_map |
| 183 |
| ICapture of id |
| ICapture of id |
| 184 |
| IConstant of id * Types.const |
| IConstant of id * Types.const |
| 187 |
mutable hash : int option; |
mutable hash : int option; |
| 188 |
mutable rank1: int; mutable rank2: int; |
mutable rank1: int; mutable rank2: int; |
| 189 |
mutable gen1 : int; mutable gen2: int; |
mutable gen1 : int; mutable gen2: int; |
| 190 |
mutable d : slot descr option |
mutable d : descr option |
| 191 |
} |
} |
| 192 |
|
|
| 193 |
let descr s = |
let descr s = |
| 219 |
) |
) |
| 220 |
|
|
| 221 |
let rec equal_descr d1 d2 = |
let rec equal_descr d1 d2 = |
|
(d1 == d2) || |
|
| 222 |
match (d1,d2) with |
match (d1,d2) with |
| 223 |
| IType x1, IType x2 -> Types.equal_descr x1 x2 |
| IType x1, IType x2 -> Types.equal_descr x1 x2 |
| 224 |
| IOr (x1,y1), IOr (x2,y2) |
| IOr (x1,y1), IOr (x2,y2) |
| 254 |
s.hash <- Some h; |
s.hash <- Some h; |
| 255 |
h |
h |
| 256 |
|
|
| 257 |
let equal s1 s2 = incr gen; rank := 0; equal_slot s1 s2 |
let equal s1 s2 = |
| 258 |
|
(s1 == s2) || |
| 259 |
|
(incr gen; rank := 0; |
| 260 |
|
let e = equal_slot s1 s2 in |
| 261 |
|
(* if e then Printf.eprintf "Equal\n"; *) |
| 262 |
|
e) |
| 263 |
end |
end |
| 264 |
module SlotTable = Hashtbl.Make(Arg) |
module SlotTable = Hashtbl.Make(Arg) |
| 265 |
|
|
| 270 |
if s.gen1 = !gen then IdSet.empty |
if s.gen1 = !gen then IdSet.empty |
| 271 |
else (s.gen1 <- !gen; fv_descr (descr s)) |
else (s.gen1 <- !gen; fv_descr (descr s)) |
| 272 |
and fv_descr = function |
and fv_descr = function |
| 273 |
|
| IType _ -> IdSet.empty |
| 274 |
| IOr (d1,d2) |
| IOr (d1,d2) |
| 275 |
| IAnd (d1,d2) |
| IAnd (d1,d2) |
| 276 |
| IDiff (d1,d2) -> IdSet.cup (fv_descr d1) (fv_descr d2) |
| IDiff (d1,d2) -> IdSet.cup (fv_descr d1) (fv_descr d2) |
| 280 |
| IArrow (s1,s2) -> IdSet.cup (fv_slot s1) (fv_slot s2) |
| IArrow (s1,s2) -> IdSet.cup (fv_slot s1) (fv_slot s2) |
| 281 |
| IRecord (o,r) -> List.fold_left IdSet.cup IdSet.empty (LabelMap.map_to_list fv_slot r) |
| IRecord (o,r) -> List.fold_left IdSet.cup IdSet.empty (LabelMap.map_to_list fv_slot r) |
| 282 |
| ICapture x | IConstant (x,_) -> IdSet.singleton x |
| ICapture x | IConstant (x,_) -> IdSet.singleton x |
| 283 |
| _ -> IdSet.empty |
|
| 284 |
|
|
| 285 |
let compute_fv s = |
let compute_fv s = |
| 286 |
match s.fv with |
match s.fv with |
| 291 |
s.fv <- Some x |
s.fv <- Some x |
| 292 |
|
|
| 293 |
|
|
| 294 |
let counter = ref 0 |
let todo_fv = ref [] |
|
let todo = ref [] |
|
|
let rec flush_fv () = |
|
|
List.iter compute_fv !todo; |
|
|
todo := [] |
|
| 295 |
|
|
| 296 |
let mk () = |
let mk () = |
| 297 |
let s = |
let s = |
| 300 |
hash = None; |
hash = None; |
| 301 |
rank1 = 0; rank2 = 0; |
rank1 = 0; rank2 = 0; |
| 302 |
gen1 = 0; gen2 = 0 } in |
gen1 = 0; gen2 = 0 } in |
| 303 |
todo := s :: !todo; |
todo_fv := s :: !todo_fv; |
| 304 |
s |
s |
| 305 |
|
|
| 306 |
let compile_hash = Ast.PpatTable.create 65 |
let flush_fv () = |
| 307 |
|
List.iter compute_fv !todo_fv; |
| 308 |
|
todo_fv := [] |
| 309 |
|
|
| 310 |
|
let compile_slot_hash = DerecursTable.create 67 |
| 311 |
|
let compile_hash = DerecursTable.create 67 |
| 312 |
|
|
| 313 |
let defs = ref [] |
let defs = ref [] |
| 314 |
let rec compile env { loc = loc; descr = d } = |
|
| 315 |
match (d : Ast.ppat') with |
let rec compile p = |
| 316 |
| PatVar v -> |
try DerecursTable.find compile_hash p |
|
let (d,loop) = |
|
|
try TypeEnv.find v env |
|
| 317 |
with Not_found -> |
with Not_found -> |
| 318 |
raise_loc_generic loc ("Undefined type variable " ^ v) in |
let c = real_compile p in |
| 319 |
if !loop then |
DerecursTable.replace compile_hash p c; |
| 320 |
raise_loc_generic loc ("Unguarded recursion on type/pattern variable " ^ v); |
c |
| 321 |
loop := true; |
and real_compile = function |
| 322 |
let r = compile env d in |
| PAlias v -> |
| 323 |
loop := false; |
if v.ploop then |
| 324 |
|
raise_loc_generic v.ploc ("Unguarded recursion on type/pattern"); |
| 325 |
|
v.ploop <- true; |
| 326 |
|
let r = match v.pdescr with Some x -> compile x | _ -> assert false in |
| 327 |
|
v.ploop <- false; |
| 328 |
r |
r |
| 329 |
| Recurs (t, b) -> compile (compile_many env b) t |
| PType t -> IType t |
| 330 |
| Regexp (r,q) -> compile env (Regexp.compile loc r q) |
| POr (t1,t2) -> IOr (compile t1, compile t2) |
| 331 |
| Internal t -> IType t |
| PAnd (t1,t2) -> IAnd (compile t1, compile t2) |
| 332 |
| Or (t1,t2) -> IOr (compile env t1, compile env t2) |
| PDiff (t1,t2) -> IDiff (compile t1, compile t2) |
| 333 |
| And (t1,t2) -> IAnd (compile env t1, compile env t2) |
| PTimes (t1,t2) -> ITimes (compile_slot t1, compile_slot t2) |
| 334 |
| Diff (t1,t2) -> IDiff (compile env t1, compile env t2) |
| PXml (t1,t2) -> IXml (compile_slot t1, compile_slot t2) |
| 335 |
| Prod (t1,t2) -> ITimes (compile_slot env t1, compile_slot env t2) |
| PArrow (t1,t2) -> IArrow (compile_slot t1, compile_slot t2) |
| 336 |
| XmlT (t1,t2) -> IXml (compile_slot env t1, compile_slot env t2) |
| POptional t -> IOptional (compile t) |
| 337 |
| Arrow (t1,t2) -> IArrow (compile_slot env t1, compile_slot env t2) |
| PRecord (o,r) -> IRecord (o, LabelMap.map compile_slot r) |
| 338 |
| Optional t -> IOptional (compile env t) |
| PConstant (x,v) -> IConstant (x,v) |
| 339 |
| Record (o,r) -> IRecord (o, LabelMap.map (compile_slot env) r) |
| PCapture x -> ICapture x |
| 340 |
| Constant (x,v) -> IConstant (x,v) |
| PRegexp (r,q) -> compile_regexp r q |
| 341 |
| Capture x -> ICapture x |
and compile_regexp r q = |
| 342 |
and compile_slot env ({ loc = loc; descr = d } as p) = |
let memo = RE.create 17 in |
| 343 |
try Ast.PpatTable.find compile_hash p |
let rec aux accu r q = |
| 344 |
|
if RE.mem memo (r,q) then accu |
| 345 |
|
else ( |
| 346 |
|
RE.add memo (r,q) (); |
| 347 |
|
match r with |
| 348 |
|
| PEpsilon -> (match q with PRegexp (r,q) -> aux accu r q | _ -> (compile q) :: accu) |
| 349 |
|
| PElem p -> ITimes (compile_slot p, compile_slot q) :: accu |
| 350 |
|
| PSeq (r1,r2) -> aux accu r1 (PRegexp (r2,q)) |
| 351 |
|
| PAlt (r1,r2) -> aux (aux accu r1 q) r2 q |
| 352 |
|
| PStar r1 -> aux (aux accu r1 (PRegexp (r,q))) PEpsilon q |
| 353 |
|
| PWeakStar r1 -> aux (aux accu PEpsilon q) r1 (PRegexp (r,q)) |
| 354 |
|
) |
| 355 |
|
in |
| 356 |
|
let accu = aux [] r q in |
| 357 |
|
match accu with |
| 358 |
|
| [] -> assert false |
| 359 |
|
| p::l -> List.fold_left (fun acc p -> IOr (p,acc)) p l |
| 360 |
|
and compile_slot p = |
| 361 |
|
try DerecursTable.find compile_slot_hash p |
| 362 |
with Not_found -> |
with Not_found -> |
| 363 |
let s = mk () in |
let s = mk () in |
| 364 |
defs := (s,p,env) :: !defs; |
defs := (s,p) :: !defs; |
| 365 |
Ast.PpatTable.add compile_hash p s; |
DerecursTable.add compile_slot_hash p s; |
| 366 |
s |
s |
| 367 |
|
|
|
and compile_many env b = |
|
|
List.fold_left (fun env (v,p) -> TypeEnv.add v (p,ref false) env) env b |
|
| 368 |
|
|
| 369 |
let rec flush_defs () = |
let rec flush_defs () = |
| 370 |
match !defs with |
match !defs with |
| 371 |
| [] -> () |
| [] -> () |
| 372 |
| (s,p,env)::t -> defs := t; s.d <- Some (compile env p); flush_defs () |
| (s,p)::t -> defs := t; s.d <- Some (compile p); flush_defs () |
| 373 |
|
|
| 374 |
let typ_nodes = SlotTable.create 67 |
let typ_nodes = SlotTable.create 67 |
| 375 |
let pat_nodes = SlotTable.create 67 |
let pat_nodes = SlotTable.create 67 |
| 441 |
|
|
| 442 |
|
|
| 443 |
let register_global_types b = |
let register_global_types b = |
| 444 |
List.iter (fun (v, { loc = loc }) -> |
List.iter |
| 445 |
|
(fun (v,p) -> |
| 446 |
if TypeEnv.mem v !glb |
if TypeEnv.mem v !glb |
| 447 |
then raise_loc_generic loc ("Multiple definition for type " ^ v) |
then raise_loc_generic p.loc ("Multiple definition for type " ^ v) |
| 448 |
) b; |
) b; |
| 449 |
glb := compile_many !glb b; |
glb := derecurs_def !glb b; |
| 450 |
let b = List.map (fun (v,p) -> (v,p,compile !glb p)) b in |
let b = List.map (fun (v,p) -> (v,p,compile (derecurs !glb p))) b in |
| 451 |
flush_defs (); |
flush_defs (); |
| 452 |
flush_fv (); |
flush_fv (); |
| 453 |
List.iter (fun (v,p,s) -> |
List.iter (fun (v,p,s) -> |
| 455 |
raise_loc_generic p.loc "Capture variables are not allowed in types"; |
raise_loc_generic p.loc "Capture variables are not allowed in types"; |
| 456 |
Types.Print.register_global v (typ s)) b |
Types.Print.register_global v (typ s)) b |
| 457 |
|
|
| 458 |
|
let dump_global_types ppf = |
| 459 |
|
TypeEnv.iter (fun v _ -> Format.fprintf ppf " %s" v) !glb |
| 460 |
|
|
| 461 |
|
|
| 462 |
let typ p = |
let typ p = |
| 463 |
let s = compile_slot !glb p in |
let s = compile_slot (derecurs !glb p) in |
| 464 |
flush_defs (); |
flush_defs (); |
| 465 |
flush_fv (); |
flush_fv (); |
| 466 |
if IdSet.is_empty (fv_slot s) then typ_node s |
if IdSet.is_empty (fv_slot s) then typ_node s |
| 467 |
else raise_loc_generic p.loc "Capture variables are not allowed in types" |
else raise_loc_generic p.loc "Capture variables are not allowed in types" |
| 468 |
|
|
| 469 |
let pat p = |
let pat p = |
| 470 |
let s = compile_slot !glb p in |
let s = compile_slot (derecurs !glb p) in |
| 471 |
flush_defs (); |
flush_defs (); |
| 472 |
flush_fv (); |
flush_fv (); |
| 473 |
try pat_node s |
try pat_node s |
| 475 |
| Location (loc,exn) when loc = noloc -> raise (Location (p.loc, exn)) |
| Location (loc,exn) when loc = noloc -> raise (Location (p.loc, exn)) |
| 476 |
|
|
| 477 |
|
|
|
*) |
|
|
|
|
|
(* Internal representation as a graph (desugar recursive types and regexp), |
|
|
to compute freevars, etc... *) |
|
|
|
|
|
type ti = { |
|
|
id : int; |
|
|
mutable seen : bool; |
|
|
mutable loc' : loc; |
|
|
mutable fv : fv option; |
|
|
mutable descr': descr; |
|
|
mutable type_node: Types.node option; |
|
|
mutable pat_node: Patterns.node option |
|
|
} |
|
|
and descr = |
|
|
| IAlias of string * ti |
|
|
| IType of Types.descr |
|
|
| IOr of ti * ti |
|
|
| IAnd of ti * ti |
|
|
| IDiff of ti * ti |
|
|
| ITimes of ti * ti |
|
|
| IXml of ti * ti |
|
|
| IArrow of ti * ti |
|
|
| IOptional of ti |
|
|
| IRecord of bool * ti label_map |
|
|
| ICapture of id |
|
|
| IConstant of id * Types.const |
|
|
|
|
|
|
|
|
|
|
|
type glb = ti TypeEnv.t |
|
|
|
|
|
let mk' = |
|
|
let counter = ref 0 in |
|
|
fun loc -> |
|
|
incr counter; |
|
|
let rec x = { |
|
|
id = !counter; |
|
|
seen = false; |
|
|
loc' = loc; |
|
|
fv = None; |
|
|
descr' = IAlias ("__dummy__", x); |
|
|
type_node = None; |
|
|
pat_node = None |
|
|
} in |
|
|
x |
|
|
|
|
|
let cons loc d = |
|
|
let x = mk' loc in |
|
|
x.descr' <- d; |
|
|
x |
|
|
|
|
|
|
|
|
|
|
|
let rec compile env { loc = loc; descr = d } : ti = |
|
|
match (d : Ast.ppat') with |
|
|
| PatVar s -> |
|
|
(try TypeEnv.find s env |
|
|
with Not_found -> |
|
|
raise_loc_generic loc ("Undefined type variable " ^ s) |
|
|
) |
|
|
| Recurs (t, b) -> compile (compile_many env b) t |
|
|
| Regexp (r,q) -> compile env (Regexp.compile loc r q) |
|
|
| Internal t -> cons loc (IType t) |
|
|
| Or (t1,t2) -> cons loc (IOr (compile env t1, compile env t2)) |
|
|
| And (t1,t2) -> cons loc (IAnd (compile env t1, compile env t2)) |
|
|
| Diff (t1,t2) -> cons loc (IDiff (compile env t1, compile env t2)) |
|
|
| Prod (t1,t2) -> cons loc (ITimes (compile env t1, compile env t2)) |
|
|
| XmlT (t1,t2) -> cons loc (IXml (compile env t1, compile env t2)) |
|
|
| Arrow (t1,t2) -> cons loc (IArrow (compile env t1, compile env t2)) |
|
|
| Optional t -> cons loc (IOptional (compile env t)) |
|
|
| Record (o,r) -> cons loc (IRecord (o, LabelMap.map (compile env) r)) |
|
|
| Constant (x,v) -> cons loc (IConstant (x,v)) |
|
|
| Capture x -> cons loc (ICapture 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) -> TypeEnv.add v x env) env b in |
|
|
List.iter (fun (v,t,x) -> x.descr' <- IAlias (v, compile env t)) b; |
|
|
env |
|
|
|
|
|
module IntSet = |
|
|
Set.Make(struct type t = int let compare (x:int) y = compare x y end) |
|
|
|
|
|
let comp_fv_seen = ref [] |
|
|
let comp_fv_res = ref IdSet.empty |
|
|
let rec comp_fv s = |
|
|
match s.fv with |
|
|
| Some fv -> comp_fv_res := IdSet.cup fv !comp_fv_res |
|
|
| None -> |
|
|
(match s.descr' with |
|
|
| IAlias (_,x) -> |
|
|
if x.seen then () |
|
|
else ( |
|
|
x.seen <- true; |
|
|
comp_fv_seen := x :: !comp_fv_seen; |
|
|
comp_fv x |
|
|
) |
|
|
| IOr (s1,s2) |
|
|
| IAnd (s1,s2) |
|
|
| IDiff (s1,s2) |
|
|
| ITimes (s1,s2) | IXml (s1,s2) |
|
|
| IArrow (s1,s2) -> comp_fv s1; comp_fv s2 |
|
|
| IOptional r -> comp_fv r |
|
|
| IRecord (_,r) -> LabelMap.iter comp_fv r |
|
|
| IType _ -> () |
|
|
| ICapture x |
|
|
| IConstant (x,_) -> comp_fv_res := IdSet.add x !comp_fv_res |
|
|
) |
|
|
|
|
|
|
|
|
let fv s = |
|
|
match s.fv with |
|
|
| Some l -> l |
|
|
| None -> |
|
|
comp_fv s; |
|
|
let l = !comp_fv_res in |
|
|
comp_fv_res := IdSet.empty; |
|
|
List.iter (fun n -> n.seen <- false) !comp_fv_seen; |
|
|
comp_fv_seen := []; |
|
|
s.fv <- Some l; |
|
|
l |
|
|
|
|
|
let rec typ seen s : Types.descr = |
|
|
match s.descr' with |
|
|
| IAlias (v,x) -> |
|
|
if IntSet.mem s.id seen then |
|
|
raise_loc_generic s.loc' |
|
|
("Unguarded recursion on variable " ^ v ^ " in this type") |
|
|
else typ (IntSet.add s.id seen) x |
|
|
| IType t -> t |
|
|
| IOr (s1,s2) -> Types.cup (typ seen s1) (typ seen s2) |
|
|
| IAnd (s1,s2) -> Types.cap (typ seen s1) (typ seen s2) |
|
|
| IDiff (s1,s2) -> Types.diff (typ seen s1) (typ seen s2) |
|
|
| ITimes (s1,s2) -> Types.times (typ_node s1) (typ_node s2) |
|
|
| IXml (s1,s2) -> Types.xml (typ_node s1) (typ_node s2) |
|
|
| IArrow (s1,s2) -> Types.arrow (typ_node s1) (typ_node s2) |
|
|
| IOptional s -> Types.Record.or_absent (typ seen s) |
|
|
| IRecord (o,r) -> |
|
|
Types.record' |
|
|
(o, LabelMap.map typ_node r) |
|
|
| ICapture x | IConstant (x,_) -> assert false |
|
|
|
|
|
and typ_node s : Types.node = |
|
|
match s.type_node with |
|
|
| Some x -> x |
|
|
| None -> |
|
|
let x = Types.make () in |
|
|
s.type_node <- Some x; |
|
|
let t = typ IntSet.empty s in |
|
|
Types.define x t; |
|
|
x |
|
|
|
|
|
let type_node s = |
|
|
let s = typ_node s in |
|
|
let s = Types.internalize s in |
|
|
(* Types.define s (Types.normalize (Types.descr s)); *) |
|
|
s |
|
|
|
|
|
let rec pat seen s : Patterns.descr = |
|
|
if IdSet.is_empty (fv s) |
|
|
then Patterns.constr (Types.descr (type_node s)) |
|
|
else |
|
|
try pat_aux seen s |
|
|
with Patterns.Error e -> raise_loc_generic s.loc' e |
|
|
| Location (loc,exn) when loc = noloc -> raise (Location (s.loc', exn)) |
|
|
|
|
|
|
|
|
and pat_aux seen s = match s.descr' with |
|
|
| IAlias (v,x) -> |
|
|
if IntSet.mem s.id seen |
|
|
then raise |
|
|
(Patterns.Error |
|
|
("Unguarded recursion on variable " ^ v ^ " in this pattern")); |
|
|
pat (IntSet.add s.id seen) x |
|
|
| IOr (s1,s2) -> Patterns.cup (pat seen s1) (pat seen s2) |
|
|
| IAnd (s1,s2) -> Patterns.cap (pat seen s1) (pat seen s2) |
|
|
| IDiff (s1,s2) when IdSet.is_empty (fv s2) -> |
|
|
let s2 = Types.neg (Types.descr (type_node s2)) in |
|
|
Patterns.cap (pat seen s1) (Patterns.constr s2) |
|
|
| IDiff _ -> |
|
|
raise (Patterns.Error "Difference not allowed in patterns") |
|
|
| ITimes (s1,s2) -> Patterns.times (pat_node s1) (pat_node s2) |
|
|
| IXml (s1,s2) -> Patterns.xml (pat_node s1) (pat_node s2) |
|
|
| IOptional _ -> |
|
|
raise |
|
|
(Patterns.Error |
|
|
"Optional field not allowed in record patterns") |
|
|
| IRecord (o,r) -> |
|
|
let pats = ref [] in |
|
|
let aux l s = |
|
|
if IdSet.is_empty (fv s) then type_node s |
|
|
else |
|
|
( pats := Patterns.record l (pat_node s) :: !pats; |
|
|
Types.any_node ) |
|
|
in |
|
|
let constr = Types.record' (o,LabelMap.mapi aux r) in |
|
|
List.fold_left Patterns.cap (Patterns.constr constr) !pats |
|
|
(* TODO: can avoid constr when o=true, and all fields have fv *) |
|
|
| ICapture x -> Patterns.capture x |
|
|
| IConstant (x,c) -> Patterns.constant x c |
|
|
| IArrow _ -> |
|
|
raise (Patterns.Error "Arrow not allowed in patterns") |
|
|
| IType _ -> assert false |
|
|
|
|
|
and pat_node s : Patterns.node = |
|
|
match s.pat_node with |
|
|
| Some x -> x |
|
|
| None -> |
|
|
let x = Patterns.make (fv s) in |
|
|
s.pat_node <- Some x; |
|
|
let t = pat IntSet.empty s in |
|
|
Patterns.define x t; |
|
|
x |
|
|
|
|
|
let mk_typ e = |
|
|
if IdSet.is_empty (fv e) then type_node e |
|
|
else raise_loc_generic e.loc' "Capture variables are not allowed in types" |
|
|
|
|
|
|
|
|
let glb = State.ref "Typer.glb_env" TypeEnv.empty |
|
|
|
|
|
let typ e = |
|
|
mk_typ (compile !glb e) |
|
|
|
|
|
let pat e = |
|
|
pat_node (compile !glb e) |
|
|
|
|
|
let register_global_types b = |
|
|
let env' = compile_many !glb b in |
|
|
List.iter |
|
|
(fun (v,{ loc = loc }) -> |
|
|
let t = TypeEnv.find v env' in |
|
|
let d = Types.descr (mk_typ t) in |
|
|
(* let d = Types.normalize d in*) |
|
|
Types.Print.register_global v d; |
|
|
if TypeEnv.mem v !glb |
|
|
then raise_loc_generic loc ("Multiple definition for type " ^ v); |
|
|
glb := TypeEnv.add v t !glb |
|
|
) b |
|
|
|
|
|
|
|
|
|
|
| 478 |
(* II. Build skeleton *) |
(* II. Build skeleton *) |
| 479 |
|
|
| 480 |
module Fv = IdSet |
module Fv = IdSet |