Skip to content
This repository has been archived by the owner on Sep 26, 2019. It is now read-only.
/ ppx_view Public archive

A ppx rewriter that provides pattern matching on abstract types by transforming patterns into views/expressions.

License

Notifications You must be signed in to change notification settings

ocaml-ppx/ppx_view

Repository files navigation

A ppx rewriter that provides pattern matching on abstract types by transforming patterns into views/expressions.

Syntax

ppx_view transforms the patterns of match/function constructs wrapped inside [%view] extensions by replacing matches against constructors with function calls.

For instance, in the following code:

match%view expr with
| Constr var -> var

the constructor Constr is turned into a call to the function constr, which is expected to be a view pattern:

val constr : (string, 'a, 'b) View.t -> (expression, 'a, 'b) View.t

Technically, the above expression is rewritten into:

Viewlib.View.match_ __POS__
    [Viewlib.View.case (constr Viewlib.View.__)
       (fun (Viewlib.View.Var_snoc (Viewlib.View.Var_nil, var)) -> var)]
    expr

where __ is used to capture the variable.

Mapping

ppx_view applies the following mapping:

  • a literal constant c of type typ is mapped to View.typ c;

  • an interval pattern c1..c2 is mapped to View.interval e1 e2 where ci is mapped to ei;

  • a variable pattern is mapped to View.__;

  • a catch-all pattern is mapped to View.drop;

  • a record pattern { lbl1 = p1; lbl2 = p2; ... } is mapped to lbl1'match e1 (lbl2'match e2 ...) where pi is mapped to ei;

  • a constructor pattern C (p1, ..., pn) is mapped to c e1 ... en where pi is mapped to ei, except for constructors from the core library:

    • Some is mapped to View.some;
    • None is mapped to View.none;
    • :: is mapped to View.cons;
    • [] is mapped to View.nil;
    • () is mapped to View.unit;
    • true is mapped to View.true_;
    • false is mapped to View.false_.

Note: the following patterns are currently not supported:

  • polymorphic variants;
  • lazy;
  • module unpacking;
  • exceptions.

Library

The Parseview module of the library contains the functions corresponding to the constructors and records from the Parsetree module. Such functions use "shortcuts" to xyz_desc fields, allowing to directly match constructors:

open Viewast

let is_zero : Parsetree.expression -> true = function%view
  | Pexp_constant (Pconst_integer ("0", _)) -> true
  | Pexp_ident { txt = Lident "zero"; _ } -> true
  | _ -> false

The access to other fields is done through a [@view ...] annotation:

open Viewast

let is_zero : Parsetree.expression -> true = function%view
  | (Pexp_constant (Pconst_integer ("0", _)))[@view { pexp_loc; }] -> true, pexp_loc
  | Pexp_ident { txt = Lident "zero"; loc; } -> true, loc
  | _ -> false, Location.none

The library also provides an Ast_viewer module that acts as the counterpart of the Ast_helper module. It allows to write patterns very similar to the corresponding expressions:

open Viewast

let twice_mapper =
  let module H = Ast_helper in
  let module M = Ast_mapper in
  let module V = Ast_viewer in
  let super = M.default_mapper in
  let expr self e =
    match%view super.expr self e with
    | V.Exp.Constant (V.Const.String (str, _)) ->
      H.Exp.constant (H.Const.string (str ^ str))
    | other ->
      other
  and pat self p =
    match%view super.pat self p with
    | V.Pat.Constant (V.Const.String (str, _)) ->
      H.Pat.constant (H.Const.string (str ^ str))
    | other ->
      other
  in
  { super with expr; pat; }

Not patterns

Following the proposal in MPR#7628, not pattern are implemented through the Not constructor, that is rewritten to View.not. Not patterns allow to write patterns that are matched if a subpattern is not matched as in:

match%view expr with
| Pexp_constant (Not (Pconst_integer _ | Pconst_float _)) ->
  (* expr is not a number *)
| Pexp_constant (Pconst_integer _) ->
  (* expr is an integer *)
| Pexp_constant (Pconst_float _) ->
  (* expr is a float *)

Not patterns cannot contain variables.

Limitations

The major limitations of view patterns are the lack of checks for non-redundancy and exhaustivity.

About

A ppx rewriter that provides pattern matching on abstract types by transforming patterns into views/expressions.

Resources

License

Stars

Watchers

Forks

Packages

No packages published