The future of ppx https://discuss.ocaml.org/t/the-future-of-ppx/
OCaml
55
374 commits
updated May 20, 2020
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 -> 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.
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:
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; }
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.
OCaml
99.8%
The future of ppx https://discuss.ocaml.org/t/the-future-of-ppx/
OCaml
55
374 commits
updated May 20, 2020
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 -> 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.
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:
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; }
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.
OCaml
99.8%