ocaml/typing/patterns.ml

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