This project is under construction
For more info, see this blog post.
The ppxlib project provides the basis for the ppx system, which is currently the officially supported method for meta-programming in OCaml. It offers a principled way to generate code at compile time in OCaml projects.
Ppxlib comes with a user manual aimed at both users and authors of ppx rewriters.
This repository was created by merging several older projects. See the history for more details.
A ppx rewriter that provides pattern matching on abstract types by transforming patterns into views/expressions.
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 -> varthe 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.tTechnically, 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)]
exprwhere __ is used to capture the variable.
ppx_view applies the following mapping:
-
a literal constant
cof typetypis mapped toView.typ c; -
an interval pattern
c1..c2is mapped toView.interval e1 e2whereciis mapped toei; -
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 tolbl1'match e1 (lbl2'match e2 ...)wherepiis mapped toei; -
a constructor pattern
C (p1, ..., pn)is mapped toc e1 ... enwherepiis mapped toei, except for constructors from the core library:Someis mapped toView.some;Noneis mapped toView.none;::is mapped toView.cons;[]is mapped toView.nil;()is mapped toView.unit;trueis mapped toView.true_;falseis mapped toView.false_.
Note: the following patterns are currently not supported:
- polymorphic variants;
- lazy;
- module unpacking;
- exceptions.
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
| _ -> falseThe 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.noneThe 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; }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.
The major limitations of view patterns are the lack of checks for non-redundancy and exhaustivity.