🔗 Docs
This section has code examples to help you understand it better.
To run the examples:
make demo-building_ast
- Description
- Building ASTs with Pure OCaml
- Building ASTs with
AST_builder
- Using Metaquot for AST Construction
- Building Complex Expressions
- Conclusion
Building an AST (Abstract Syntax Tree) is a fundamental part of creating a PPX in OCaml. You'll need to construct an AST to represent the code you want to generate or transform.
For example, if you want to generate the following code:
let zero = [%int 0]
and replace the extension point [%int 0]
with 0
to produce let zero = 0
, you’ll need to build an AST that represents this transformation.
There are several methods to build an AST. We’ll discuss three approaches:
- Building ASTs with Pure OCaml
- Building ASTs with
AST_builder
- Using Metaquot for AST Construction
The most fundamental way to build an AST is to manually construct it using Low-Level Builders data structures.
To construct an AST for a simple integer value 0
:
let zero ~loc : Ppxlib_ast.Ast.expression =
{
pexp_desc = Pexp_constant (Pconst_integer ("0", None));
pexp_loc = loc;
pexp_loc_stack = [];
pexp_attributes = [];
}
While this method provides full control over the AST, it is verbose and less maintainable.
PPXLib provides the AST_builder
module, which simplifies the process of building ASTs by providing helper functions.
Using pexp_constant
, you can construct an integer AST like this:
let one ~loc =
Ast_builder.Default.pexp_constant ~loc (Parsetree.Pconst_integer ("1", None))
This method is more readable and concise compared to the pure OCaml approach.
For even more simplicity, use eint
:
let two ~loc = Ast_builder.Default.eint ~loc 2
💡 Tip
eint
is an abbreviation for expression (e
) integer (int
).
Metaquot is a syntax extension that allows you to write ASTs in a more natural and readable way.
With Metaquot, you can construct an integer AST like this:
let three ~loc = [%expr 3]
💡 Tip
Metaquot is highly readable and intuitive but is static. For dynamic values, use Anti-Quotations.
Anti-Quotations allow you to insert dynamic expressions into your Metaquot ASTs.
To insert a dynamic expression into a Metaquot AST:
let anti_quotation_expr expr = [%expr 1 + [%e expr]]
For example, to insert the AST for 1
:
let _ =
print_endline
("\nLet expression with metaquot and anti-quotation: "
^ Astlib.Pprintast.string_of_expression (anti_quotation_expr (one ~loc)))
Beyond simple expressions, you may need to build more complex ASTs, such as let
expressions.
To build a let
expression that binds the value 3
to the variable foo
:
let let_expression =
let expression =
Ast_builder.Default.pexp_constant ~loc:Location.none
(Pconst_integer ("3", None))
in
let pattern =
Ast_builder.Default.ppat_var ~loc:Location.none
(Ast_builder.Default.Located.mk ~loc:Location.none "foo")
in
let let_binding =
Ast_builder.Default.value_binding ~loc:Location.none ~pat:pattern
~expr:expression
in
Ast_builder.Default.pexp_let ~loc:Location.none Nonrecursive [ let_binding ]
(Ast_builder.Default.eunit ~loc:Location.none)
Alternatively, with Metaquot:
let let_expression =
[%expr
let foo = 3 in
()]
This approach is shorter and easier to understand.
In this section, we explored three methods for building ASTs:
- Pure OCaml: The most basic but verbose approach.
- Using
AST_builder
: A more readable and maintainable option. - Using Metaquot: The most intuitive method, especially when combined with Anti-Quotations for dynamic values.
Each method has its strengths, so choose the one that best fits your needs. Understanding all three will give you greater flexibility in creating effective and maintainable PPXs.