Warning: This is a legacy page that is only available for historical reasons. I stopped maintaining this page in spring 2007 when Nicolas Pouillard announced a rewrite of Camlp5 on the OCaml list.
On this page I collected information on Camlp5 that could neither be found in the reference manual nor in the tutorial around 2007. I found out about all that during my work on a quotation system in original syntax.Issue | Original syntax | Revised syntax |
---|---|---|
parenthesis required in record update | { record_expr with field = expr; ... } | { (record_expr) with field = expr; ... } |
fun bindings in record field definitions | { field = fun a -> ... } | { field a = ... } |
no bigarray syntax | a.{1} | Bigarray.Array1.get a 1 |
a.{1,2,3,4} <- b | Bigarray.Genarray.set a [| 1;2;3;4 |] b | |
nested as patterns require parenthesis | function | Some a as opt, b -> ... | function [ ((Some a as opt), b) -> ... |
manifest types | type 'a a = 'a option = None | Some of 'a | type 'a a = 'a option == None | Some of 'a |
top level quantification on type variables | type a = ! 'a . list 'a | |
abstract module type specifications | module type MT | module type MT = 'a |
class declarations | class [ 'a, 'b ] c = ... | class c [ 'a, 'b ] = ... |
class instantiation | [ 'a, 'b ] c | c [ 'a, 'b ] |
class valued function types | typ -> class_type | [ typ ] -> class_type |
semicolon required after every class fields | method virtual m : int | method virtual m : int; |
order of private and virtual | method private virtual m : int | method virtual private m : int; |
method virtual private m : int | ||
object instance variables | val a = ... | value a = ... |
class constraints | constraint t1 = t2 | type t1 = t2 |
SLIST0 and SLIST1 auto-magically provide an $list:...$ anti-quotation. SOPT provides $opt:...$. However, I don't understand (yet) where these anti-quotations come from.
There are also some limitations with SLIST:
You cannot distinguish both rules with an LL(1) grammar, because you might have to parse arbitrarily long to see the difference between field = and expr with.
The Camlp5 solution looks as follows. (The following code is taken from paqo_o.ml. It originates from Daniel de Rauglaudre's pa_o.ml. However, Daniel used the revised syntax.)
(* stream_peek_nth : int -> 'a Stream.t -> 'a option *)
let stream_peek_nth n strm =
try
Some(List.nth (Stream.npeek n strm) (n-1))
with
| Failure "nth" -> None
Now we define an oracle that distinguishes the two grammar rules in question:
(* test_label_eq : unit Grammar.Entry.e *) let test_label_eq = Grammar.Entry.of_parser gram "test_label_eq" (let rec test lev strm = match stream_peek_nth lev strm with | Some (("UIDENT", _) | ("LIDENT", _) | ("", ".")) -> test (lev + 1) strm | Some ("", "=") -> () | _ -> raise Stream.Failure in test 1 )
The Camlp5 grammar is now as follows:
EXTEND expr: [ ... | "simple" LEFTA [ ... | "{"; test_label_eq; lel = lbl_expr_list; "}" -> ... | "{"; e = expr LEVEL "."; "with"; lel = lbl_expr_list; "}" -> ... ...
EXTEND expr: [ ... | "simple" LEFTA [ ... | "("; op = operator_rparen -> ... ...
let operator_rparen = Grammar.Entry.of_parser gram "operator_rparen" (fun strm -> match Stream.npeek 2 strm with | [("", s); ("", ")")] when is_operator s -> begin Stream.junk strm; Stream.junk strm; s end | _ -> raise Stream.Failure)