This chapter explains how to create OCaml
syntax trees using
quotations.
The OCaml
syntax tree is defined in the module
MLast
(file ``mLast.mli''): it is of course always possible to create
your syntax tree nodes by combining values of these types. But, for
that, you need a precise documentation of all the constructors, how
they have to be used, and which syntactic construct they correspond
to.
Chapter 4 explained us that quotations are helpful to
represent abstract values with concrete syntax. This is very adapted
for abstract syntax trees, since they have corresponding concrete
syntaxes. In this case, you have nothing to learn: if you know the
concrete syntax, you know the abstract syntax. Actually, you need to
know the revised syntax (chapter 5) because it is the
syntax used in these quotations.
The provided quotation extension is the file q_MLast.cmo
. Once
this file loaded, you can write any complicated piece of program in
concrete syntax, e.g.:
<:expr< match f $x$ with [ $uid:p$ -> $x$ | C z -> 7 ] >>
This example corresponds exactly to this code (written in normal syntax):
MLast.ExMat
(loc, MLast.ExApp (loc, MLast.ExLid (loc, "f"), x),
[MLast.PaUid (loc, p), None, x;
MLast.PaApp
(loc, MLast.PaUid (loc, "C"), MLast.PaLid (loc, "z")), None,
MLast.ExInt (loc, "7")]);;
These two forms are absolutely equivalent, but the first one is much
simpler and more readable. Notice the expressions between dollar signs
$
: they are antiquotations (see chapter
4). We are going to see how to use them.
For the moment, here is the list of the quotations defined in the file
q_MLast.cmo
:
expr
to create expression nodes
patt
to create pattern nodes
ctyp
to create type nodes
sig_item
to create signature item nodes
str_item
to create structure item nodes
module_type
to create module type nodes
module_expr
to create module expression nodes
Each of these quotations use the revised syntax (chapter
5). You have to know that their expression form
(i.e. not pattern) all contain the variable named "loc"
.
It allows you to specify a source location to the syntax tree.
There must then exist a variable "loc"
visible in the
environment where the quotation is used.
Notice that in the Camlp4
grammar system (chapter
3), the variable "loc"
in defined in all semantic
actions of the rules: Camlp4 grammar system and Camlp4 quotations of
abstract syntax trees are made to work together.
The antiquotations allow to insert abstract syntax trees inside other
abstract syntax trees. They are enclosed by dollar signs
$
. Between these dollars, you can put any expression or pattern
in the enclosing syntax.
For example, if you have a variable "x"
of type
MLast.expr
, you may want to create ``the tree node
corresponding to the call of some function "f"
with this
expression. This can be written:
<:expr< f $x$ >>
Note that if the quotation is is position of pattern, the content of
the quotation must be a pattern: here are legal pieces of program (in
normal syntax):
function <:expr< f $x$ >> -> x;;
function <:expr< f $_$ >> -> 1;;
6.2 |
Antiquotations labels |
|
Some of these antiquotations may be used with a label (an identifier
ending with a colon character ":"
in the beginning of the
antiquotation). It is for the case when the concrete syntax is not
enough to know what we are talking about.
For example, if x
is a variable of type string, we need ways
to create 1/ the tree node corresponding to the variable whose name is
the value of x
2/ the tree node corresponding to the string
whose content is the value of x
3/ the tree node
corresponding to the constructor whose name is the value of
x
.
Labels allow to do that: in the first case, it must be "lid"
(for ``l(owercase) id(entifier)''), in the second case, "str"
(for ``str(ing)''), in the third case, "uid"
(for ``u(ppercase)
id(entifier)''), i.e. respectively:
<:expr< f $lid:x$ >>
<:expr< f $str:x$ >>
<:expr< f $uid:x$ >>
Therefore:
let x = "foo" in <:expr< f $lid:x$ >> is equivalent to: <:expr< f foo >>
let x = "foo" in <:expr< f $str:x$ >> " <:expr< f "foo" >>
let x = "Foo" in <:expr< f $uid:x$ >> " <:expr< f Foo >>
Important remark: the antiquotations of type string (str) and
character (chr) must contain an ``escaped'' string: some characters
like backslashes, quotes, doubles quotes must be prefixed by a
backslash. To be sure, use the OCaml library functions
"String.Escaped"
and "Char.Escaped"
.
A label often encountered is "list"
: it is when the syntactic
construct may expect a list at this place. Here are examples with
two antiquotations, one being labelled, the other not:
<:expr< [| $list:x$ |] >>
<:expr< [| $x$ |] >>
-
In the first case,
x
must be a value of type
MLast.expr
list, and the quotation represents an array whose
elements are in x
.
- In the second case,
x
if of type MLast.expr
, and the
quotation represents an array of just one element.
Notice that the antiquotations must respect the enclosing syntax
rules: if x
and y
are of type MLast.expr
and
z
of type MLast.expr
list, the code:
<:expr< [| $list: x::y::z $ |] >>
is correct in normal syntax, but if you use the revised syntax, you must
write it:
<:expr< [| $list: [x; y :: z] $ |] >>
Well, we could describe all nodes one by one, but they are actually
already described in the reference manual. Refer to it.