130 lines
4.0 KiB
OCaml
130 lines
4.0 KiB
OCaml
(**************************************************************************)
|
|
(* *)
|
|
(* OCaml *)
|
|
(* *)
|
|
(* Xavier Leroy, projet Cristal, INRIA Rocquencourt *)
|
|
(* *)
|
|
(* Copyright 1996 Institut National de Recherche en Informatique et *)
|
|
(* en Automatique. *)
|
|
(* *)
|
|
(* All rights reserved. This file is distributed under the terms of *)
|
|
(* the GNU Lesser General Public License version 2.1, with the *)
|
|
(* special exception on linking described in the file LICENSE. *)
|
|
(* *)
|
|
(**************************************************************************)
|
|
|
|
type t =
|
|
Pident of Ident.t
|
|
| Pdot of t * string
|
|
| Papply of t * t
|
|
|
|
let rec same p1 p2 =
|
|
p1 == p2
|
|
|| match (p1, p2) with
|
|
(Pident id1, Pident id2) -> Ident.same id1 id2
|
|
| (Pdot(p1, s1), Pdot(p2, s2)) -> s1 = s2 && same p1 p2
|
|
| (Papply(fun1, arg1), Papply(fun2, arg2)) ->
|
|
same fun1 fun2 && same arg1 arg2
|
|
| (_, _) -> false
|
|
|
|
let rec compare p1 p2 =
|
|
if p1 == p2 then 0
|
|
else match (p1, p2) with
|
|
(Pident id1, Pident id2) -> Ident.compare id1 id2
|
|
| (Pdot(p1, s1), Pdot(p2, s2)) ->
|
|
let h = compare p1 p2 in
|
|
if h <> 0 then h else String.compare s1 s2
|
|
| (Papply(fun1, arg1), Papply(fun2, arg2)) ->
|
|
let h = compare fun1 fun2 in
|
|
if h <> 0 then h else compare arg1 arg2
|
|
| ((Pident _ | Pdot _), (Pdot _ | Papply _)) -> -1
|
|
| ((Pdot _ | Papply _), (Pident _ | Pdot _)) -> 1
|
|
|
|
let rec find_free_opt ids = function
|
|
Pident id -> List.find_opt (Ident.same id) ids
|
|
| Pdot(p, _s) -> find_free_opt ids p
|
|
| Papply(p1, p2) ->
|
|
match find_free_opt ids p1 with
|
|
| None -> find_free_opt ids p2
|
|
| Some _ as res -> res
|
|
|
|
let exists_free ids p =
|
|
match find_free_opt ids p with
|
|
| None -> false
|
|
| _ -> true
|
|
|
|
let rec scope = function
|
|
Pident id -> Ident.scope id
|
|
| Pdot(p, _s) -> scope p
|
|
| Papply(p1, p2) -> max (scope p1) (scope p2)
|
|
|
|
let kfalse _ = false
|
|
|
|
let rec name ?(paren=kfalse) = function
|
|
Pident id -> Ident.name id
|
|
| Pdot(p, s) ->
|
|
name ~paren p ^ if paren s then ".( " ^ s ^ " )" else "." ^ s
|
|
| Papply(p1, p2) -> name ~paren p1 ^ "(" ^ name ~paren p2 ^ ")"
|
|
|
|
let rec print ppf = function
|
|
| Pident id -> Ident.print_with_scope ppf id
|
|
| Pdot(p, s) -> Format.fprintf ppf "%a.%s" print p s
|
|
| Papply(p1, p2) -> Format.fprintf ppf "%a(%a)" print p1 print p2
|
|
|
|
let rec head = function
|
|
Pident id -> id
|
|
| Pdot(p, _s) -> head p
|
|
| Papply _ -> assert false
|
|
|
|
let flatten =
|
|
let rec flatten acc = function
|
|
| Pident id -> `Ok (id, acc)
|
|
| Pdot (p, s) -> flatten (s :: acc) p
|
|
| Papply _ -> `Contains_apply
|
|
in
|
|
fun t -> flatten [] t
|
|
|
|
let heads p =
|
|
let rec heads p acc = match p with
|
|
| Pident id -> id :: acc
|
|
| Pdot (p, _s) -> heads p acc
|
|
| Papply(p1, p2) ->
|
|
heads p1 (heads p2 acc)
|
|
in heads p []
|
|
|
|
let rec last = function
|
|
| Pident id -> Ident.name id
|
|
| Pdot(_, s) -> s
|
|
| Papply(_, p) -> last p
|
|
|
|
let is_uident s =
|
|
assert (s <> "");
|
|
match s.[0] with
|
|
| 'A'..'Z' -> true
|
|
| _ -> false
|
|
|
|
type typath =
|
|
| Regular of t
|
|
| Ext of t * string
|
|
| LocalExt of Ident.t
|
|
| Cstr of t * string
|
|
|
|
let constructor_typath = function
|
|
| Pident id when is_uident (Ident.name id) -> LocalExt id
|
|
| Pdot(ty_path, s) when is_uident s ->
|
|
if is_uident (last ty_path) then Ext (ty_path, s)
|
|
else Cstr (ty_path, s)
|
|
| p -> Regular p
|
|
|
|
let is_constructor_typath p =
|
|
match constructor_typath p with
|
|
| Regular _ -> false
|
|
| _ -> true
|
|
|
|
module T = struct
|
|
type nonrec t = t
|
|
let compare = compare
|
|
end
|
|
module Set = Set.Make(T)
|
|
module Map = Map.Make(T)
|