Raw File
open EcIdent
open EcSymbols
open EcUtils
open EcMaps

module rec PATH :
sig

  type path = private {
    p_node : path_node;
    p_tag  : int
  }

  and path_node =
    | Psymbol of symbol
    | Pqname  of path * symbol

  val p_equal       : path -> path -> bool
  val p_hash        : path -> int
  val p_compare     : path -> path -> int
  val p_ntr_compare : path -> path -> int

  val mk_path : path_node -> path

  module Mp : Map.S with type key = path
  module Hp : EcMaps.EHashtbl.S with type key = path

  module Sp : sig
    include Set.S with module M = Map.MakeBase(Mp)
    val ntr_elements : t -> elt list
  end

  type mpath = {
    m_top   : mpath_top;
(*    m_targs : TYPES.ty list; *)
    m_args  : mpath list;
    m_tag   : int;
  }

  and mpath_top =
    [ | `Local of ident
      | `Concrete of path * path option ]

  val m_equal       : mpath -> mpath -> bool
  val mt_equal      : mpath_top -> mpath_top -> bool
  val m_hash        : mpath -> int
  val m_compare     : mpath -> mpath -> int
  val m_ntr_compare : mpath -> mpath -> int

  val mpath : mpath_top -> mpath list -> mpath

  module Mm : Map.S with type key = mpath
  module Hm : EcMaps.EHashtbl.S with type key = mpath

  module Sm : sig
    include Set.S with module M = Map.MakeBase(Mm)
    val ntr_elements : t -> elt list
  end

  val m_fv  : int EcIdent.Mid.t -> mpath -> int EcIdent.Mid.t

end
=
struct
  (* ------------------------------------------------------------------------- *)
  (* path                                                                      *)
  type path = {
    p_node : path_node;
    p_tag  : int
  }

  and path_node =
    | Psymbol of symbol
    | Pqname  of path * symbol

  let p_equal   = ((==) : path -> path -> bool)
  let p_hash    = fun p -> p.p_tag
  let p_compare = fun p1 p2 -> p_hash p1 - p_hash p2

  module Hspath = Why3.Hashcons.Make(
    struct
      type t = path

      let equal_node p1 p2 =
        match p1, p2 with
        | Psymbol id1, Psymbol id2 ->
          sym_equal id1 id2
        | Pqname (p1, id1), Pqname(p2, id2) ->
          sym_equal id1 id2 && p_equal p1 p2
        | _ -> false

      let equal p1 p2 = equal_node p1.p_node p2.p_node

      let hash p =
        match p.p_node with
        | Psymbol id    -> Hashtbl.hash id
        | Pqname (p,id) -> Why3.Hashcons.combine p.p_tag (Hashtbl.hash id)

      let tag n p = { p with p_tag = n }
    end)

  let mk_path node =
    Hspath.hashcons { p_node = node; p_tag = -1; }


  (* -------------------------------------------------------------------- *)
  module Path = MakeMSH (
    struct
      type t  = path
      let tag = p_hash
    end)

  let rec p_ntr_compare (p1 : path) (p2 : path) =
    match p1.p_node, p2.p_node with
    | Psymbol _, Pqname  _ -> -1
    | Pqname  _, Psymbol _ -> +1

    | Psymbol x1, Psymbol x2 ->
      String.compare x1 x2

    | Pqname (p1, x1), Pqname (p2, x2) -> begin
        match p_ntr_compare p1 p2 with
        | 0 -> String.compare x1 x2
        | n -> n
      end

  module Mp = Path.M
  module Hp = Path.H

  module Sp = struct
    include Path.S

    let ntr_elements s =
      List.ksort ~key:identity ~cmp:p_ntr_compare (elements s)
  end


  (* ------------------------------------------------------------------------- *)
  (* mpath                                                                     *)

  type mpath = {
      m_top  : mpath_top;
      m_args : mpath list;
      m_tag  : int;
    }

  and mpath_top =
    [ | `Local of ident
      | `Concrete of path * path option ]

  let m_equal   = ((==) : mpath -> mpath -> bool)
  let m_hash    = fun p -> p.m_tag
  let m_compare = fun p1 p2 -> m_hash p1 - m_hash p2

  let rec m_fv fv mp =
    let fv =
      match mp.m_top with
      | `Local id -> EcIdent.fv_add id fv
      | `Concrete _  -> fv in
    List.fold_left m_fv fv mp.m_args


  let mt_equal mt1 mt2 =
    match mt1, mt2 with
    | `Local id1, `Local id2 -> EcIdent.id_equal id1 id2
    | `Concrete(p1, o1), `Concrete(p2, o2) ->
      p_equal p1 p2 && oall2 p_equal o1 o2
    | _, _ -> false

  module Hsmpath = Why3.Hashcons.Make (struct
    type t = mpath

    let equal m1 m2 =
      mt_equal m1.m_top m2.m_top  && List.all2 m_equal m1.m_args m2.m_args

    let hash m =
      let hash =
        match m.m_top with
        | `Local id -> EcIdent.id_hash id
        | `Concrete(p, o) ->
          o |> ofold
                 (fun s h -> Why3.Hashcons.combine h (p_hash s))
                 (p_hash p)
      in
      Why3.Hashcons.combine_list m_hash hash m.m_args

    let tag n p = { p with m_tag = n }
  end)

  let mpath p args =
    Hsmpath.hashcons { m_top = p; m_args = args; m_tag = -1; }

  (* -------------------------------------------------------------------- *)
  module MPath = MakeMSH (struct
    type t  = mpath
    let tag = m_hash
  end)

  let m_top_ntr_compare (mt1 : mpath_top) (mt2 : mpath_top) =
    match mt1, mt2 with
    | `Local    _, `Concrete _ -> -1
    | `Concrete _, `Local    _ -> +1

    | `Local id1, `Local id2 ->
      id_ntr_compare id1 id2

    | `Concrete (p1, op1), `Concrete (p2, op2) -> begin
        match p_ntr_compare p1 p2 with
        | 0 -> ocompare p_ntr_compare op1 op2
        | n -> n
      end

  let rec m_ntr_compare (m1 : mpath) (m2 : mpath) =
    match m_top_ntr_compare m1.m_top m2.m_top with
    | 0 -> List.compare m_ntr_compare m1.m_args m2.m_args
    | n -> n

  module Mm = MPath.M
  module Hm = MPath.H

  module Sm = struct
    include MPath.S
    let ntr_elements s =
      List.ksort ~key:identity ~cmp:m_ntr_compare (elements s)
  end

end

and TYPES : sig

  type ty = {
    ty_node : ty_node;
    ty_fv   : int Mid.t;
    ty_tag  : int;
  }

  and ty_node =
    | Tglob   of PATH.mpath (* The tuple of global variable of the module *)
    | Tunivar of EcUid.uid
    | Tvar    of EcIdent.t
    | Ttuple  of ty list
    | Tconstr of PATH.path * ty list
    | Tfun    of ty * ty

  val ty_equal : ty -> ty -> bool
  val ty_hash  : ty -> int

  val mk_ty : ty_node -> ty

  module Mty : Map.S with type key = ty
  module Sty : Set.S with module M = Map.MakeBase(Mty)
  module Hty : EcMaps.EHashtbl.S with type key = ty

end
=
struct

  type ty = {
    ty_node : ty_node;
    ty_fv   : int Mid.t;
    ty_tag  : int;
  }

  and ty_node =
    | Tglob   of PATH.mpath (* The tuple of global variable of the module *)
    | Tunivar of EcUid.uid
    | Tvar    of EcIdent.t
    | Ttuple  of ty list
    | Tconstr of PATH.path * ty list
    | Tfun    of ty * ty

  let ty_equal : ty -> ty -> bool = (==)
  let ty_hash ty = ty.ty_tag

  module Hsty = Why3.Hashcons.Make (struct
    type t = ty

    let equal ty1 ty2 =
      match ty1.ty_node, ty2.ty_node with
      | Tglob m1, Tglob m2 ->
        PATH.m_equal m1 m2

      | Tunivar u1, Tunivar u2 ->
        EcUid.uid_equal u1 u2

      | Tvar v1, Tvar v2 ->
        id_equal v1 v2

      | Ttuple lt1, Ttuple lt2 ->
        List.all2 ty_equal lt1 lt2

      | Tconstr (p1, lt1), Tconstr (p2, lt2) ->
        PATH.p_equal p1 p2 && List.all2 ty_equal lt1 lt2

      | Tfun (d1, c1), Tfun (d2, c2)->
        ty_equal d1 d2 && ty_equal c1 c2

      | _, _ -> false

    let hash ty =
      match ty.ty_node with
      | Tglob m          -> PATH.m_hash m
      | Tunivar u        -> u
      | Tvar    id       -> EcIdent.tag id
      | Ttuple  tl       -> Why3.Hashcons.combine_list ty_hash 0 tl
      | Tconstr (p, tl)  -> Why3.Hashcons.combine_list ty_hash p.p_tag tl
      | Tfun    (t1, t2) -> Why3.Hashcons.combine (ty_hash t1) (ty_hash t2)

    let fv ty =
      let union ex =
        List.fold_left (fun s a -> fv_union s (ex a)) Mid.empty in

      match ty with
      | Tglob m          -> PATH.m_fv Mid.empty m
      | Tunivar _        -> Mid.empty
      | Tvar    _        -> Mid.empty
      | Ttuple  tys      -> union (fun a -> a.ty_fv) tys
      | Tconstr (_, tys) -> union (fun a -> a.ty_fv) tys
      | Tfun    (t1, t2) -> union (fun a -> a.ty_fv) [t1; t2]

    let tag n ty = { ty with ty_tag = n; ty_fv = fv ty.ty_node; }
  end)

  let mk_ty node =
    Hsty.hashcons { ty_node = node; ty_tag = -1; ty_fv = Mid.empty }

  module MSHty = EcMaps.MakeMSH(struct
    type t = ty
    let tag t = t.ty_tag
  end)

  module Mty = MSHty.M
  module Sty = MSHty.S
  module Hty = MSHty.H

end
back to top