[wg-camlp4] Matching on concrete syntax (was: Re: Camlp4 uses)
Alain Frisch
alain.frisch at lexifi.com
Wed Apr 3 17:51:35 BST 2013
On 03/29/2013 02:46 PM, Gabriel Scherer wrote:
> Would it be possible to use the extension mechanism itself for
> lightweight quasiquotations?
On 03/29/2013 08:18 PM, Alain Frisch wrote:
> Something similar to
> branches/extension_points/experimental/frisch/print_gen.ml could be
> used to generate automatically an AST lifter. The difficult part is
> to design anti-quotations, though, and since I'm not convinced by
> this approach, I'd rather put energy myself in other projects.
Ok, as usual, I've been sidetracked by your clever idea :-)
I've created a meta quotation expander (or should it be called
"quasiquotation" ?), allowing to write AST builders using concrete
syntax as in:
http://caml.inria.fr/cgi-bin/viewvc.cgi/ocaml/branches/extension_points/experimental/frisch/metaquot_test.ml?revision=HEAD&view=markup
The code for the ppx rewriter supporting this style is:
http://caml.inria.fr/cgi-bin/viewvc.cgi/ocaml/branches/extension_points/experimental/frisch/metaquot.ml?revision=HEAD&view=markup
It relies on a "Parsetree lifter" class (Ast_lifter.lifter). The same
Parsetree lifter can also be used to write a Parsetree printer like the
tool ocamlast I've described previously, but now without relying on the
toplevel printer (which requires runtime access to parsetree.cmi, etc).
The code for such a printer is in:
http://caml.inria.fr/cgi-bin/viewvc.cgi/ocaml/branches/extension_points/experimental/frisch/dumpast.ml?revision=HEAD&view=markup
Ast_lifter.lifter is a partial parametrized class, whose type parameter
describes which output is to be produced (Outcometree.value for the
printer; Parsetree.expression for the meta quotation expander). This
class needs to be extended (through inheritance) in order to provide
"builder functions" for that type, and potentially to override the
default behavior for some type under Parsetree. For instance, the
printer decides to map all locations of Oval_ellipsis. Similarly, the
meta quotation expander detects uses of "anti-quotations" and maps them
to the identity instead of the default lifting behavior.
The code of ast_lifter.ml looks like:
class virtual ['res] lifter =
object (this)
method lift_Parsetree_expression : Parsetree.expression -> 'res=
fun
{ Parsetree.pexp_desc = pexp_desc; Parsetree.pexp_loc = pexp_loc;
Parsetree.pexp_attributes = pexp_attributes }
->
this#record "Parsetree.expression"
[("pexp_desc", (this#lift_Parsetree_expression_desc pexp_desc));
("pexp_loc", (this#lift_Location_t pexp_loc));
("pexp_attributes",
(this#list
(List.map this#lift_Parsetree_attribute pexp_attributes)))]
method lift_Parsetree_expression_desc :
Parsetree.expression_desc -> 'res=
function
| Parsetree.Pexp_ident x0 ->
this#constr "Parsetree.expression_desc"
("Pexp_ident", [this#lift_Asttypes_loc
this#lift_Longident_t x0])
| Parsetree.Pexp_constant x0 ->
this#constr "Parsetree.expression_desc"
("Pexp_constant", [this#lift_Asttypes_constant x0])
.....
which is very tedious to write by hand (and to maintain when the
Parsetree evolves). Of course, this code is not written by hand, it is
generated from the definition of the Parsetree using a small tool:
http://caml.inria.fr/cgi-bin/viewvc.cgi/ocaml/branches/extension_points/experimental/frisch/dumpast.ml?revision=HEAD&view=markup
which is executed once to produce ast_lifter.ml:
./genlifter.exe -I ../../parsing -I ../../stdlib Parsetree.expression >
ast_lifter.ml
All that can be tried by typing "make lifter" in experimental/frisch (on
the extension_points branch, of course, after a successful "make world").
Now, one could go crazy (Camlp4-style) and use the metaquot ppx rewriter
within genlifter.ml itself, and then get for free nasty bootstrapping
problems :-)
Alain
More information about the wg-camlp4
mailing list