| 18 |
open Ast |
open Ast |
| 19 |
open Ident |
open Ident |
| 20 |
|
|
| 21 |
module S = struct type t = string let compare = compare end |
module TypeEnv = Map.Make(U) |
|
module TypeEnv = Map.Make(S) |
|
| 22 |
|
|
| 23 |
exception NonExhaustive of Types.descr |
exception NonExhaustive of Types.descr |
| 24 |
exception Constraint of Types.descr * Types.descr |
exception Constraint of Types.descr * Types.descr |
| 78 |
| PStar of derecurs_regexp |
| PStar of derecurs_regexp |
| 79 |
| PWeakStar of derecurs_regexp |
| PWeakStar of derecurs_regexp |
| 80 |
|
|
| 81 |
|
type tenv = { |
| 82 |
|
tenv_names : derecurs_slot TypeEnv.t; |
| 83 |
|
tenv_nspref: Atoms.Ns.t TypeEnv.t; |
| 84 |
|
tenv_loc : Location.loc |
| 85 |
|
} |
| 86 |
|
|
| 87 |
let rec hash_derecurs = function |
let rec hash_derecurs = function |
| 88 |
| PAlias s -> |
| PAlias s -> |
| 89 |
s.pid |
s.pid |
| 185 |
incr counter; |
incr counter; |
| 186 |
{ ploop = false; ploc = loc; pid = !counter; pdescr = None } |
{ ploop = false; ploc = loc; pid = !counter; pdescr = None } |
| 187 |
|
|
| 188 |
|
let ns_from_prefix env loc ns = |
| 189 |
|
try TypeEnv.find ns env.tenv_nspref |
| 190 |
|
with Not_found -> |
| 191 |
|
raise_loc_generic loc |
| 192 |
|
("Undefined namespace prefix " ^ (U.to_string ns)) |
| 193 |
|
|
| 194 |
|
let const env loc = function |
| 195 |
|
| Const_internal c -> c |
| 196 |
|
| Const_atom (ns,l) -> |
| 197 |
|
let ns = ns_from_prefix env loc ns in |
| 198 |
|
Types.Atom (Atoms.mk ns l) |
| 199 |
|
|
| 200 |
let rec derecurs env p = match p.descr with |
let rec derecurs env p = match p.descr with |
| 201 |
| PatVar v -> |
| PatVar v -> |
| 202 |
(try PAlias (TypeEnv.find v env) |
(try PAlias (TypeEnv.find v env.tenv_names) |
| 203 |
with Not_found -> |
with Not_found -> |
| 204 |
raise_loc_generic p.loc ("Undefined type/pattern " ^ v)) |
raise_loc_generic p.loc ("Undefined type/pattern " ^ (U.to_string v))) |
| 205 |
| SchemaVar (kind, schema, item) -> |
| SchemaVar (kind, schema, item) -> |
| 206 |
let try_elt () = fst (Hashtbl.find !schema_elements (schema, item)) in |
let try_elt () = fst (Hashtbl.find !schema_elements (schema, item)) in |
| 207 |
let try_typ () = Hashtbl.find !schema_types (schema, item) in |
let try_typ () = Hashtbl.find !schema_types (schema, item) in |
| 234 |
"No item named '%s' found in schema '%s'" item schema))))) |
"No item named '%s' found in schema '%s'" item schema))))) |
| 235 |
| Recurs (p,b) -> derecurs (derecurs_def env b) p |
| Recurs (p,b) -> derecurs (derecurs_def env b) p |
| 236 |
| Internal t -> PType t |
| Internal t -> PType t |
| 237 |
|
| AtomT (ns,a) -> |
| 238 |
|
let ns = ns_from_prefix env p.loc ns in |
| 239 |
|
let a = match a with |
| 240 |
|
| Some a -> Atoms.atom (Atoms.mk ns a) |
| 241 |
|
| None -> Atoms.any_in_ns ns in |
| 242 |
|
PType (Types.atom a) |
| 243 |
| Or (p1,p2) -> POr (derecurs env p1, derecurs env p2) |
| Or (p1,p2) -> POr (derecurs env p1, derecurs env p2) |
| 244 |
| And (p1,p2) -> PAnd (derecurs env p1, derecurs env p2) |
| And (p1,p2) -> PAnd (derecurs env p1, derecurs env p2) |
| 245 |
| Diff (p1,p2) -> PDiff (derecurs env p1, derecurs env p2) |
| Diff (p1,p2) -> PDiff (derecurs env p1, derecurs env p2) |
| 249 |
| Optional p -> POptional (derecurs env p) |
| Optional p -> POptional (derecurs env p) |
| 250 |
| Record (o,r) -> PRecord (o, LabelMap.map (derecurs env) r) |
| Record (o,r) -> PRecord (o, LabelMap.map (derecurs env) r) |
| 251 |
| Capture x -> PCapture x |
| Capture x -> PCapture x |
| 252 |
| Constant (x,c) -> PConstant (x,c) |
| Constant (x,c) -> PConstant (x,const env p.loc c) |
| 253 |
| Regexp (r,q) -> |
| Regexp (r,q) -> |
| 254 |
let constant_nil t v = |
let constant_nil t v = |
| 255 |
PAnd (t, PConstant (v, Types.Atom Sequence.nil_atom)) in |
PAnd (t, PConstant (v, Types.Atom Sequence.nil_atom)) in |
| 276 |
|
|
| 277 |
and derecurs_def env b = |
and derecurs_def env b = |
| 278 |
let b = List.map (fun (v,p) -> (v,p,mk_slot p.loc)) b in |
let b = List.map (fun (v,p) -> (v,p,mk_slot p.loc)) b in |
| 279 |
let env = List.fold_left (fun env (v,p,s) -> TypeEnv.add v s env) env b in |
let n = |
| 280 |
|
List.fold_left (fun env (v,p,s) -> TypeEnv.add v s env) env.tenv_names b in |
| 281 |
|
let env = { env with tenv_names = n } in |
| 282 |
List.iter (fun (v,p,s) -> s.pdescr <- Some (derecurs env p)) b; |
List.iter (fun (v,p,s) -> s.pdescr <- Some (derecurs env p)) b; |
| 283 |
env |
env |
| 284 |
|
|
| 557 |
Patterns.define x (pat (descr s)); |
Patterns.define x (pat (descr s)); |
| 558 |
x |
x |
| 559 |
|
|
| 560 |
let glb = State.ref "Typer.glb_env" TypeEnv.empty |
let register_global_types glb b = |
|
|
|
|
let register_global_types b = |
|
| 561 |
List.iter |
List.iter |
| 562 |
(fun (v,p) -> |
(fun (v,p) -> |
| 563 |
if TypeEnv.mem v !glb |
if TypeEnv.mem v glb.tenv_names |
| 564 |
then raise_loc_generic p.loc ("Multiple definition for type " ^ v) |
then raise_loc_generic p.loc ("Multiple definition for type " ^ (U.to_string v)) |
| 565 |
) b; |
) b; |
| 566 |
let old_glb = !glb in |
let glb = derecurs_def glb b in |
| 567 |
try |
let b = List.map (fun (v,p) -> (v,p,compile (derecurs glb p))) b in |
|
glb := derecurs_def !glb b; |
|
|
let b = List.map (fun (v,p) -> (v,p,compile (derecurs !glb p))) b in |
|
| 568 |
flush_defs (); |
flush_defs (); |
| 569 |
flush_fv (); |
flush_fv (); |
| 570 |
let b = |
let b = |
| 576 |
let t = typ s in |
let t = typ s in |
| 577 |
if (p.loc <> noloc) && (Types.is_empty t) then |
if (p.loc <> noloc) && (Types.is_empty t) then |
| 578 |
warning p.loc |
warning p.loc |
| 579 |
("This definition yields an empty type for " ^ v); |
("This definition yields an empty type for " ^ (U.to_string v)); |
| 580 |
(v,t)) b in |
(v,t)) b in |
| 581 |
List.iter (fun (v,t) -> Types.Print.register_global v t) b |
List.iter (fun (v,t) -> Types.Print.register_global v t) b; |
| 582 |
with e -> |
glb |
|
glb := old_glb; |
|
|
raise e |
|
| 583 |
|
|
| 584 |
let dump_global_types ppf = |
let register_ns_prefix glb p ns = |
| 585 |
TypeEnv.iter (fun v _ -> Format.fprintf ppf " %s" v) !glb |
{ glb with tenv_nspref = TypeEnv.add p ns glb.tenv_nspref } |
| 586 |
|
|
| 587 |
|
let dump_global_types ppf glb = |
| 588 |
|
TypeEnv.iter (fun v _ -> Format.fprintf ppf " %a" U.print v) glb.tenv_names |
| 589 |
|
|
| 590 |
let do_typ loc r = |
let do_typ loc r = |
| 591 |
let s = compile_slot r in |
let s = compile_slot r in |
| 594 |
if IdSet.is_empty (fv_slot s) then typ_node s |
if IdSet.is_empty (fv_slot s) then typ_node s |
| 595 |
else raise_loc_generic loc "Capture variables are not allowed in types" |
else raise_loc_generic loc "Capture variables are not allowed in types" |
| 596 |
|
|
| 597 |
let typ p = |
let typ glb p = |
| 598 |
do_typ p.loc (derecurs !glb p) |
do_typ p.loc (derecurs glb p) |
| 599 |
|
|
| 600 |
let pat p = |
let pat glb p = |
| 601 |
let s = compile_slot (derecurs !glb p) in |
let s = compile_slot (derecurs glb p) in |
| 602 |
flush_defs (); |
flush_defs (); |
| 603 |
flush_fv (); |
flush_fv (); |
| 604 |
try pat_node s |
try pat_node s |
| 622 |
} |
} |
| 623 |
|
|
| 624 |
|
|
| 625 |
let rec expr loc = function |
let rec expr glb loc = function |
| 626 |
| LocatedExpr (loc,e) -> expr loc e |
| LocatedExpr (loc,e) -> expr glb loc e |
| 627 |
| Forget (e,t) -> |
| Forget (e,t) -> |
| 628 |
let (fv,e) = expr loc e and t = typ t in |
let (fv,e) = expr glb loc e and t = typ glb t in |
| 629 |
exp loc fv (Typed.Forget (e,t)) |
exp loc fv (Typed.Forget (e,t)) |
| 630 |
| Var s -> |
| Var s -> |
| 631 |
exp loc (Fv.singleton s) (Typed.Var s) |
exp loc (Fv.singleton s) (Typed.Var s) |
| 632 |
| Apply (e1,e2) -> |
| Apply (e1,e2) -> |
| 633 |
let (fv1,e1) = expr loc e1 and (fv2,e2) = expr loc e2 in |
let (fv1,e1) = expr glb loc e1 and (fv2,e2) = expr glb loc e2 in |
| 634 |
exp loc (Fv.cup fv1 fv2) (Typed.Apply (e1,e2)) |
exp loc (Fv.cup fv1 fv2) (Typed.Apply (e1,e2)) |
| 635 |
| Abstraction a -> |
| Abstraction a -> |
| 636 |
let iface = List.map (fun (t1,t2) -> (typ t1, typ t2)) |
let iface = List.map (fun (t1,t2) -> (typ glb t1, typ glb t2)) |
| 637 |
a.fun_iface in |
a.fun_iface in |
| 638 |
let t = List.fold_left |
let t = List.fold_left |
| 639 |
(fun accu (t1,t2) -> Types.cap accu (Types.arrow t1 t2)) |
(fun accu (t1,t2) -> Types.cap accu (Types.arrow t1 t2)) |
| 641 |
let iface = List.map |
let iface = List.map |
| 642 |
(fun (t1,t2) -> (Types.descr t1, Types.descr t2)) |
(fun (t1,t2) -> (Types.descr t1, Types.descr t2)) |
| 643 |
iface in |
iface in |
| 644 |
let (fv0,body) = branches a.fun_body in |
let (fv0,body) = branches glb a.fun_body in |
| 645 |
let fv = match a.fun_name with |
let fv = match a.fun_name with |
| 646 |
| None -> fv0 |
| None -> fv0 |
| 647 |
| Some f -> Fv.remove f fv0 in |
| Some f -> Fv.remove f fv0 in |
| 654 |
} in |
} in |
| 655 |
exp loc fv e |
exp loc fv e |
| 656 |
| Cst c -> |
| Cst c -> |
| 657 |
exp loc Fv.empty (Typed.Cst c) |
exp loc Fv.empty (Typed.Cst (const glb loc c)) |
| 658 |
| Pair (e1,e2) -> |
| Pair (e1,e2) -> |
| 659 |
let (fv1,e1) = expr loc e1 and (fv2,e2) = expr loc e2 in |
let (fv1,e1) = expr glb loc e1 and (fv2,e2) = expr glb loc e2 in |
| 660 |
exp loc (Fv.cup fv1 fv2) (Typed.Pair (e1,e2)) |
exp loc (Fv.cup fv1 fv2) (Typed.Pair (e1,e2)) |
| 661 |
| Xml (e1,e2) -> |
| Xml (e1,e2) -> |
| 662 |
let (fv1,e1) = expr loc e1 and (fv2,e2) = expr loc e2 in |
let (fv1,e1) = expr glb loc e1 and (fv2,e2) = expr glb loc e2 in |
| 663 |
exp loc (Fv.cup fv1 fv2) (Typed.Xml (e1,e2)) |
exp loc (Fv.cup fv1 fv2) (Typed.Xml (e1,e2)) |
| 664 |
| Dot (e,l) -> |
| Dot (e,l) -> |
| 665 |
let (fv,e) = expr loc e in |
let (fv,e) = expr glb loc e in |
| 666 |
exp loc fv (Typed.Dot (e,l)) |
exp loc fv (Typed.Dot (e,l)) |
| 667 |
| RemoveField (e,l) -> |
| RemoveField (e,l) -> |
| 668 |
let (fv,e) = expr loc e in |
let (fv,e) = expr glb loc e in |
| 669 |
exp loc fv (Typed.RemoveField (e,l)) |
exp loc fv (Typed.RemoveField (e,l)) |
| 670 |
| RecordLitt r -> |
| RecordLitt r -> |
| 671 |
let fv = ref Fv.empty in |
let fv = ref Fv.empty in |
| 672 |
let r = LabelMap.map |
let r = LabelMap.map |
| 673 |
(fun e -> |
(fun e -> |
| 674 |
let (fv2,e) = expr loc e |
let (fv2,e) = expr glb loc e |
| 675 |
in fv := Fv.cup !fv fv2; e) |
in fv := Fv.cup !fv fv2; e) |
| 676 |
r in |
r in |
| 677 |
exp loc !fv (Typed.RecordLitt r) |
exp loc !fv (Typed.RecordLitt r) |
| 678 |
| String (i,j,s,e) -> |
| String (i,j,s,e) -> |
| 679 |
let (fv,e) = expr loc e in |
let (fv,e) = expr glb loc e in |
| 680 |
exp loc fv (Typed.String (i,j,s,e)) |
exp loc fv (Typed.String (i,j,s,e)) |
| 681 |
| Op (op,le) -> |
| Op (op,le) -> |
| 682 |
let (fvs,ltes) = List.split (List.map (expr loc) le) in |
let (fvs,ltes) = List.split (List.map (expr glb loc) le) in |
| 683 |
let fv = List.fold_left Fv.cup Fv.empty fvs in |
let fv = List.fold_left Fv.cup Fv.empty fvs in |
| 684 |
(try |
(try |
| 685 |
(match (ltes,Typed.find_op op) with |
(match (ltes,Typed.find_op op) with |
| 689 |
with Not_found -> assert false) |
with Not_found -> assert false) |
| 690 |
|
|
| 691 |
| Match (e,b) -> |
| Match (e,b) -> |
| 692 |
let (fv1,e) = expr loc e |
let (fv1,e) = expr glb loc e |
| 693 |
and (fv2,b) = branches b in |
and (fv2,b) = branches glb b in |
| 694 |
exp loc (Fv.cup fv1 fv2) (Typed.Match (e, b)) |
exp loc (Fv.cup fv1 fv2) (Typed.Match (e, b)) |
| 695 |
| Map (e,b) -> |
| Map (e,b) -> |
| 696 |
let (fv1,e) = expr loc e |
let (fv1,e) = expr glb loc e |
| 697 |
and (fv2,b) = branches b in |
and (fv2,b) = branches glb b in |
| 698 |
exp loc (Fv.cup fv1 fv2) (Typed.Map (e, b)) |
exp loc (Fv.cup fv1 fv2) (Typed.Map (e, b)) |
| 699 |
| Transform (e,b) -> |
| Transform (e,b) -> |
| 700 |
let (fv1,e) = expr loc e |
let (fv1,e) = expr glb loc e |
| 701 |
and (fv2,b) = branches b in |
and (fv2,b) = branches glb b in |
| 702 |
exp loc (Fv.cup fv1 fv2) (Typed.Transform (e, b)) |
exp loc (Fv.cup fv1 fv2) (Typed.Transform (e, b)) |
| 703 |
| Xtrans (e,b) -> |
| Xtrans (e,b) -> |
| 704 |
let (fv1,e) = expr loc e |
let (fv1,e) = expr glb loc e |
| 705 |
and (fv2,b) = branches b in |
and (fv2,b) = branches glb b in |
| 706 |
exp loc (Fv.cup fv1 fv2) (Typed.Xtrans (e, b)) |
exp loc (Fv.cup fv1 fv2) (Typed.Xtrans (e, b)) |
| 707 |
| Validate (e,schema,elt) -> |
| Validate (e,schema,elt) -> |
| 708 |
let (fv,e) = expr loc e in |
let (fv,e) = expr glb loc e in |
| 709 |
exp loc fv (Typed.Validate (e, schema, elt)) |
exp loc fv (Typed.Validate (e, schema, elt)) |
| 710 |
| Try (e,b) -> |
| Try (e,b) -> |
| 711 |
let (fv1,e) = expr loc e |
let (fv1,e) = expr glb loc e |
| 712 |
and (fv2,b) = branches b in |
and (fv2,b) = branches glb b in |
| 713 |
exp loc (Fv.cup fv1 fv2) (Typed.Try (e, b)) |
exp loc (Fv.cup fv1 fv2) (Typed.Try (e, b)) |
| 714 |
|
|
| 715 |
|
|
| 716 |
and branches b = |
and branches glb b = |
| 717 |
let fv = ref Fv.empty in |
let fv = ref Fv.empty in |
| 718 |
let accept = ref Types.empty in |
let accept = ref Types.empty in |
| 719 |
let branch (p,e) = |
let branch (p,e) = |
| 720 |
let cur_br = !cur_branch in |
let cur_br = !cur_branch in |
| 721 |
cur_branch := []; |
cur_branch := []; |
| 722 |
let (fv2,e) = expr noloc e in |
let (fv2,e) = expr glb noloc e in |
| 723 |
let br_loc = merge_loc p.loc e.Typed.exp_loc in |
let br_loc = merge_loc p.loc e.Typed.exp_loc in |
| 724 |
let p = pat p in |
let p = pat glb p in |
| 725 |
let fv2 = Fv.diff fv2 (Patterns.fv p) in |
let fv2 = Fv.diff fv2 (Patterns.fv p) in |
| 726 |
fv := Fv.cup !fv fv2; |
fv := Fv.cup !fv fv2; |
| 727 |
accept := Types.cup !accept (Types.descr (Patterns.accept p)); |
accept := Types.cup !accept (Types.descr (Patterns.accept p)); |
| 743 |
} |
} |
| 744 |
) |
) |
| 745 |
|
|
| 746 |
let expr = expr noloc |
let expr glb = expr glb noloc |
| 747 |
|
|
| 748 |
let let_decl p e = |
let let_decl glb p e = |
| 749 |
let (_,e) = expr e in |
let (_,e) = expr glb e in |
| 750 |
{ Typed.let_pat = pat p; |
{ Typed.let_pat = pat glb p; |
| 751 |
Typed.let_body = e; |
Typed.let_body = e; |
| 752 |
Typed.let_compiled = None } |
Typed.let_compiled = None } |
| 753 |
|
|
| 754 |
|
|
| 755 |
|
(* Hide global "typing/parsing" environment *) |
| 756 |
|
|
| 757 |
|
let glb = State.ref "Typer.glb_env" |
| 758 |
|
{ tenv_names = TypeEnv.empty; |
| 759 |
|
tenv_nspref = TypeEnv.add (U.mk "") Atoms.Ns.empty TypeEnv.empty; |
| 760 |
|
tenv_loc = noloc } |
| 761 |
|
|
| 762 |
|
let pat p = pat !glb p |
| 763 |
|
let typ t = typ !glb t |
| 764 |
|
let expr e = expr !glb e |
| 765 |
|
let let_decl p e = let_decl !glb p e |
| 766 |
|
|
| 767 |
|
let register_global_types l = glb := register_global_types !glb l |
| 768 |
|
let dump_global_types ppf = dump_global_types ppf !glb |
| 769 |
|
|
| 770 |
|
let register_ns_prefix p ns = glb := register_ns_prefix !glb p ns |
| 771 |
|
|
| 772 |
(* III. Type-checks *) |
(* III. Type-checks *) |
| 773 |
|
|
| 774 |
type env = Types.descr Env.t |
type env = Types.descr Env.t |
| 1177 |
PRecord (false, LabelMap.from_list_disj [(LabelPool.mk (U.mk name), r)]) |
PRecord (false, LabelMap.from_list_disj [(LabelPool.mk (U.mk name), r)]) |
| 1178 |
|
|
| 1179 |
and cd_type_of_elt_decl (name, typ, _) = |
and cd_type_of_elt_decl (name, typ, _) = |
| 1180 |
let atom_type = PType (Types.atom (Atoms.atom (Atoms.mk (U.mk name)))) in |
let atom_type = PType (Types.atom (Atoms.atom (Atoms.mk Atoms.Ns.empty (U.mk name)))) in |
| 1181 |
let content = match !typ with |
let content = match !typ with |
| 1182 |
| S st -> |
| S st -> |
| 1183 |
PTimes (PType Types.empty_closed_record, cd_type_of_simple_type st) |
PTimes (PType Types.empty_closed_record, cd_type_of_simple_type st) |