8.14 Extension nodes
(Introduced in OCaml 4.02,infix notations for constructs other than expressions added in 4.03,infix notation (e1 ;%ext e2) added in 4.04.)
Extension nodes are generic placeholders in the syntax tree. They arerejected by the type-checker and are intended to be “expanded” by externaltools such as -ppx rewriters.
Extension nodes share the same notion of identifier and payload asattributes 8.13.
The first form of extension node is used for “algebraic” categories:
|
A second form of extension node can be used in structures andsignatures, both in the module and object languages:
|
An infix form is available for extension nodes whenthe payload is of the same kind(expression with expression, pattern with pattern …).
Examples:
- let%foo x = 2 in x + 1 === [%foo let x = 2 in x + 1]
- begin%foo ... end === [%foo begin ... end]
- x ;%foo 2 === [%foo x; 2]
- module%foo M = .. === [%%foo module M = ... ]
- val%foo x : t === [%%foo: val x : t]
When this form is used together with the infix syntax for attributes,the attributes are considered to apply to the payload:
- fun%foo[@bar] x -> x + 1 === [%foo (fun x -> x + 1)[@bar ] ];
Quoted strings {|…|} are particularly interesting for payloadsthat embed foreign syntax fragments. Those fragments can be interpretedby a preprocessor and turned into OCaml code without requiring escapingquotes. For instance, you can use [%sql {|…|}] torepresent arbitrary SQL statements – assuming you have a ppx-rewriterthat recognizes the %sql extension.
Note that the word-delimited form, for example {sql|…|sql}, shouldnot be used for signaling that an extension is in use.Indeed, the user cannot see from the code whether this string literal hasdifferent semantics than they expect. Moreover, giving semantics to aspecific delimiter limits the freedom to change the delimiter to avoidescaping issues.
8.14.1 Built-in extension nodes
(Introduced in OCaml 4.03)
Some extension nodes are understood by the compiler itself:
- “ocaml.extension_constructor” or “extension_constructor”take as payload a constructor from an extensible variant type(see 8.15) and return its extensionconstructor slot.
type t = .. type t += X of int | Y of string let x = [%extension_constructor X] let y = [%extension_constructor Y]
x <> y;; - : bool = true