[wg-camlp4] Matching on concrete syntax (was: Re: Camlp4 uses)

Gabriel Scherer gabriel.scherer at gmail.com
Fri Mar 29 13:46:47 GMT 2013


Would it be possible to use the extension mechanism itself for lightweight
quasiquotations?

I did a small experiment with -ppx recently (
http://gallium.inria.fr/blog/a-library-to-record-ocaml-backtraces/smartcatch_ppx.ml,
as a contribution to Jacques-Henri Jourdan's work on
http://gallium.inria.fr/blog/a-library-to-record-ocaml-backtraces/ ), and
frankly the absence of quasiquotations felt like a pain in the ass. Compare
the camlp4 part of the relevant code:

  let add_debug_expr _loc patvar e =
    <:expr<
        let _ = ExceptionHandling.register $lid:patvar$ in
        $e$
    >>

with the Ast_rewriter equivalent (the recommended solution alongside -ppx
right now):

let add_register patvar body =
  let open Ast_mapper in
  let register_fun = Location.mknoloc (Longident.parse
"ExceptionHandling.register") in
  (* let _ = <register_fun> <patvar> in <body> *)
  E.(let_ Nonrecursive
       [P.any (), apply (ident register_fun)  ["", ident patvar]]
       body)

There is a gap of readability, maintainability but also writability between
the two approaches. I suspect that the Ast_mapper.E domain-specific
language could be improved to reduce it, but I'm not sure quasiquotations
are not the best long-term solution. But maybe we can have quasiquotations
with the current extension mechanism?

let add_register patvar body =
  [%quote
    let _ = ExceptionHandling.register [%anti patvar] in [%anti body]
  ]


I'm rather interested in getting ideas of how this actually would work and
fleshing it out.

(Note that the problem here is to have a convenient way to write little
pieces of OCaml AST when you program AST-to-AST filters of any kind. This
is a restricted use case as compared to Camlp4 quasiquotations conventions,
that offer facilities for antiquotations inside foreign quotations
implementing a completely different syntax. I used the latter in Macaque,
and they are exposed to end-users, so user-friendliness of the
antiquotation syntax was important. Here it's only for extension *writers*,
so it's ok if it's *a bit* heavy.)

On Fri, Mar 29, 2013 at 2:04 PM, Alain Frisch <alain.frisch at lexifi.com>wrote:

> On 01/29/2013 05:22 PM, Alain Frisch wrote:
>
>> On 01/29/2013 04:37 PM, Xavier Clerc wrote:
>>
>>> However, during development,
>>> it was a time-saver to be able to easily express and experiment new
>>> ideas by manipulating "bits of the actual language". Camlp4 was kind
>>> enough to translate them for me into AST code which I had to check.
>>>
>>
>> What about having a tool (either stand-alone or part of the compilers)
>> which dumps the Parsetree representation of some code fragment in as
>> textual OCaml values (probably without locations)?
>>
>> So you can type your "model" as source code and obtain quickly the
>> Parsetree representation, copy/paste it into a nice pattern and replace
>> some parts with variables.
>>
>
> I've hacked a quick implementation of such a tool, reusing the generic
> value printer from the toplevel:
>
> http://caml.inria.fr/cgi-bin/**viewvc.cgi/ocaml/branches/**
> extension_points/tools/dump_**ast.ml?revision=HEAD&view=**markup<http://caml.inria.fr/cgi-bin/viewvc.cgi/ocaml/branches/extension_points/tools/dump_ast.ml?revision=HEAD&view=markup>
>
> It parses either command-line arguments (currently, as types, expressions
> or patterns) or external .ml/.mli files, and shows the internal Parsetree
> representation.  By default, location and empty attribute fields are
> removed (they can be restored with command-line flags: -locs and
> -emptyattrs).
>
> Examples:
>
> $ ./ocamlast -w 50 -e "1 + x [@attr] * 2"
> {pexp_desc =
>   Pexp_apply
>    ({pexp_desc = Pexp_ident {txt = Lident "*"}},
>    [("",
>      {pexp_desc =
>        Pexp_apply
>         ({pexp_desc =
>            Pexp_ident {txt = Lident "+"}},
>         [("",
>           {pexp_desc =
>             Pexp_constant (Const_int 1)});
>          ("",
>           {pexp_desc =
>             Pexp_ident {txt = Lident "x"}})]);
>       pexp_attributes =
>        [("attr",
>          {pexp_desc =
>            Pexp_construct ({txt = Lident "()"},
>             None, false)})]});
>     ("",
>      {pexp_desc = Pexp_constant (Const_int 2)})])}
>
>
> $ ./ocamlast -w 50 -emptyattrs -t "int list * string"
> {ptyp_desc =
>   Ptyp_tuple
>    [{ptyp_desc =
>       Ptyp_constr ({txt = Lident "list"},
>        [{ptyp_desc =
>           Ptyp_constr ({txt = Lident "int"}, []);
>          ptyp_attributes = []}]);
>      ptyp_attributes = []};
>     {ptyp_desc =
>       Ptyp_constr ({txt = Lident "string"}, []);
>      ptyp_attributes = []}];
>  ptyp_attributes = []}
>
>
> This should should simplify the learning curve of the Parsetree, and even
> allow quick copy/paste to write patterns/expressions on Parsetree.  That
> said, creating Parsetree fragments manually is quite tedious, and I've
> created a module to make this easier:
>
> http://caml.inria.fr/cgi-bin/**viewvc.cgi/ocaml/branches/**
> extension_points/parsing/ast_**helper.mli?revision=HEAD&view=**markup<http://caml.inria.fr/cgi-bin/viewvc.cgi/ocaml/branches/extension_points/parsing/ast_helper.mli?revision=HEAD&view=markup>
>
> Currently, this module exposes "builder functions" which are very close to
> Parsetree constructors/records (making locations and attributes optional),
> but one can easily improve its interface (either by changing the existing
> functions, e.g. to use optional and labelled arguments, or by exposing
> other function to cover common cases).
>
>
>
> Alain
> ______________________________**_________________
> wg-camlp4 mailing list
> wg-camlp4 at lists.ocaml.org
> http://lists.ocaml.org/**listinfo/wg-camlp4<http://lists.ocaml.org/listinfo/wg-camlp4>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.ocaml.org/pipermail/wg-camlp4/attachments/20130329/467e1def/attachment.html>


More information about the wg-camlp4 mailing list