255 lines
7.6 KiB
OCaml
255 lines
7.6 KiB
OCaml
(**************************************************************************)
|
|
(* *)
|
|
(* OCaml *)
|
|
(* *)
|
|
(* Gabriel Scherer, projet Partout, INRIA Paris-Saclay *)
|
|
(* Thomas Refis, Jane Street Europe *)
|
|
(* *)
|
|
(* Copyright 2019 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. *)
|
|
(* *)
|
|
(**************************************************************************)
|
|
|
|
open Asttypes
|
|
open Types
|
|
open Typedtree
|
|
|
|
(* useful pattern auxiliary functions *)
|
|
|
|
let omega = {
|
|
pat_desc = Tpat_any;
|
|
pat_loc = Location.none;
|
|
pat_extra = [];
|
|
pat_type = Ctype.none;
|
|
pat_env = Env.empty;
|
|
pat_attributes = [];
|
|
}
|
|
|
|
let rec omegas i =
|
|
if i <= 0 then [] else omega :: omegas (i-1)
|
|
|
|
let omega_list l = List.map (fun _ -> omega) l
|
|
|
|
module Non_empty_row = struct
|
|
type 'a t = 'a * Typedtree.pattern list
|
|
|
|
let of_initial = function
|
|
| [] -> assert false
|
|
| pat :: patl -> (pat, patl)
|
|
|
|
let map_first f (p, patl) = (f p, patl)
|
|
end
|
|
|
|
(* "views" on patterns are polymorphic variants
|
|
that allow to restrict the set of pattern constructors
|
|
statically allowed at a particular place *)
|
|
|
|
module Simple = struct
|
|
type view = [
|
|
| `Any
|
|
| `Constant of constant
|
|
| `Tuple of pattern list
|
|
| `Construct of
|
|
Longident.t loc * constructor_description * pattern list
|
|
| `Variant of label * pattern option * row_desc ref
|
|
| `Record of
|
|
(Longident.t loc * label_description * pattern) list * closed_flag
|
|
| `Array of pattern list
|
|
| `Lazy of pattern
|
|
]
|
|
|
|
type pattern = view pattern_data
|
|
|
|
let omega = { omega with pat_desc = `Any }
|
|
end
|
|
|
|
module Half_simple = struct
|
|
type view = [
|
|
| Simple.view
|
|
| `Or of pattern * pattern * row_desc option
|
|
]
|
|
|
|
type pattern = view pattern_data
|
|
end
|
|
|
|
module General = struct
|
|
type view = [
|
|
| Half_simple.view
|
|
| `Var of Ident.t * string loc
|
|
| `Alias of pattern * Ident.t * string loc
|
|
]
|
|
type pattern = view pattern_data
|
|
|
|
let view_desc = function
|
|
| Tpat_any ->
|
|
`Any
|
|
| Tpat_var (id, str) ->
|
|
`Var (id, str)
|
|
| Tpat_alias (p, id, str) ->
|
|
`Alias (p, id, str)
|
|
| Tpat_constant cst ->
|
|
`Constant cst
|
|
| Tpat_tuple ps ->
|
|
`Tuple ps
|
|
| Tpat_construct (cstr, cstr_descr, args) ->
|
|
`Construct (cstr, cstr_descr, args)
|
|
| Tpat_variant (cstr, arg, row_desc) ->
|
|
`Variant (cstr, arg, row_desc)
|
|
| Tpat_record (fields, closed) ->
|
|
`Record (fields, closed)
|
|
| Tpat_array ps -> `Array ps
|
|
| Tpat_or (p, q, row_desc) -> `Or (p, q, row_desc)
|
|
| Tpat_lazy p -> `Lazy p
|
|
|
|
let view p : pattern =
|
|
{ p with pat_desc = view_desc p.pat_desc }
|
|
|
|
let erase_desc = function
|
|
| `Any -> Tpat_any
|
|
| `Var (id, str) -> Tpat_var (id, str)
|
|
| `Alias (p, id, str) -> Tpat_alias (p, id, str)
|
|
| `Constant cst -> Tpat_constant cst
|
|
| `Tuple ps -> Tpat_tuple ps
|
|
| `Construct (cstr, cst_descr, args) ->
|
|
Tpat_construct (cstr, cst_descr, args)
|
|
| `Variant (cstr, arg, row_desc) ->
|
|
Tpat_variant (cstr, arg, row_desc)
|
|
| `Record (fields, closed) ->
|
|
Tpat_record (fields, closed)
|
|
| `Array ps -> Tpat_array ps
|
|
| `Or (p, q, row_desc) -> Tpat_or (p, q, row_desc)
|
|
| `Lazy p -> Tpat_lazy p
|
|
|
|
let erase p : Typedtree.pattern =
|
|
{ p with pat_desc = erase_desc p.pat_desc }
|
|
|
|
let rec strip_vars (p : pattern) : Half_simple.pattern =
|
|
match p.pat_desc with
|
|
| `Alias (p, _, _) -> strip_vars (view p)
|
|
| `Var _ -> { p with pat_desc = `Any }
|
|
| #Half_simple.view as view -> { p with pat_desc = view }
|
|
end
|
|
|
|
(* the head constructor of a simple pattern *)
|
|
|
|
module Head : sig
|
|
type desc =
|
|
| Any
|
|
| Construct of constructor_description
|
|
| Constant of constant
|
|
| Tuple of int
|
|
| Record of label_description list
|
|
| Variant of
|
|
{ tag: label; has_arg: bool;
|
|
cstr_row: row_desc ref;
|
|
type_row : unit -> row_desc; }
|
|
| Array of int
|
|
| Lazy
|
|
|
|
type t = desc pattern_data
|
|
|
|
val arity : t -> int
|
|
|
|
(** [deconstruct p] returns the head of [p] and the list of sub patterns. *)
|
|
val deconstruct : Simple.pattern -> t * pattern list
|
|
|
|
(** reconstructs a pattern, putting wildcards as sub-patterns. *)
|
|
val to_omega_pattern : t -> pattern
|
|
|
|
val omega : t
|
|
end = struct
|
|
type desc =
|
|
| Any
|
|
| Construct of constructor_description
|
|
| Constant of constant
|
|
| Tuple of int
|
|
| Record of label_description list
|
|
| Variant of
|
|
{ tag: label; has_arg: bool;
|
|
cstr_row: row_desc ref;
|
|
type_row : unit -> row_desc; }
|
|
(* the row of the type may evolve if [close_variant] is called,
|
|
hence the (unit -> ...) delay *)
|
|
| Array of int
|
|
| Lazy
|
|
|
|
type t = desc pattern_data
|
|
|
|
let deconstruct (q : Simple.pattern) =
|
|
let deconstruct_desc = function
|
|
| `Any -> Any, []
|
|
| `Constant c -> Constant c, []
|
|
| `Tuple args ->
|
|
Tuple (List.length args), args
|
|
| `Construct (_, c, args) ->
|
|
Construct c, args
|
|
| `Variant (tag, arg, cstr_row) ->
|
|
let has_arg, pats =
|
|
match arg with
|
|
| None -> false, []
|
|
| Some a -> true, [a]
|
|
in
|
|
let type_row () =
|
|
match Ctype.expand_head q.pat_env q.pat_type with
|
|
| {desc = Tvariant type_row} -> Btype.row_repr type_row
|
|
| _ -> assert false
|
|
in
|
|
Variant {tag; has_arg; cstr_row; type_row}, pats
|
|
| `Array args ->
|
|
Array (List.length args), args
|
|
| `Record (largs, _) ->
|
|
let lbls = List.map (fun (_,lbl,_) -> lbl) largs in
|
|
let pats = List.map (fun (_,_,pat) -> pat) largs in
|
|
Record lbls, pats
|
|
| `Lazy p ->
|
|
Lazy, [p]
|
|
in
|
|
let desc, pats = deconstruct_desc q.pat_desc in
|
|
{ q with pat_desc = desc }, pats
|
|
|
|
let arity t =
|
|
match t.pat_desc with
|
|
| Any -> 0
|
|
| Constant _ -> 0
|
|
| Construct c -> c.cstr_arity
|
|
| Tuple n | Array n -> n
|
|
| Record l -> List.length l
|
|
| Variant { has_arg; _ } -> if has_arg then 1 else 0
|
|
| Lazy -> 1
|
|
|
|
let to_omega_pattern t =
|
|
let pat_desc =
|
|
let mkloc x = Location.mkloc x t.pat_loc in
|
|
match t.pat_desc with
|
|
| Any -> Tpat_any
|
|
| Lazy -> Tpat_lazy omega
|
|
| Constant c -> Tpat_constant c
|
|
| Tuple n -> Tpat_tuple (omegas n)
|
|
| Array n -> Tpat_array (omegas n)
|
|
| Construct c ->
|
|
let lid_loc = mkloc (Longident.Lident c.cstr_name) in
|
|
Tpat_construct (lid_loc, c, omegas c.cstr_arity)
|
|
| Variant { tag; has_arg; cstr_row } ->
|
|
let arg_opt = if has_arg then Some omega else None in
|
|
Tpat_variant (tag, arg_opt, cstr_row)
|
|
| Record lbls ->
|
|
let lst =
|
|
List.map (fun lbl ->
|
|
let lid_loc = mkloc (Longident.Lident lbl.lbl_name) in
|
|
(lid_loc, lbl, omega)
|
|
) lbls
|
|
in
|
|
Tpat_record (lst, Closed)
|
|
in
|
|
{ t with
|
|
pat_desc;
|
|
pat_extra = [];
|
|
}
|
|
|
|
let omega = { omega with pat_desc = Any }
|
|
end
|