Is it possible to write a camlp4 syntax extension that gives you access to the last let binding as a string?

201 views Asked by At

I've got some code like this:

  type boolean = T | F
  type  bexp = Const of boolean 
  |  Var of variable
  |  Bop of bop * bexp * bexp
  |  Not of bexp
  and bop = And | Or | Xor 
  and variable = { name: string; mutable value: boolean }

Later on if I want to create a variable I have to do:

let full         = Var({name ="full"; value  = F});;   

I'd rather not have to repeat the 'full' twice and would like to come up with some introspective way to get the name as a string. I'm thinking camlp4 could work for this, but have no idea where to start.

So ultimately I'd like to be able to do something like:

let full          = Var({name = :letname:; value = F});;

Where :letname: would fill in the current let binding as a string in place of (in this case "full"). (the syntax :letname: is just a suggestion, other ideas for syntax that won't clash with OCaml's syntax?)

A more concise syntax like this would probably be preferable:

var full = F 

Which would then expand to:

let full = Var({name = "full"; value = F});;

Is this possible to do with camlp4 and if so, how would I go about it?

(upon further consideration, the :letname: syntax or something similar would be more general-purpose and useful in more areas)

2

There are 2 answers

0
anon On BEST ANSWER

Try the following. In a separate file, such as test.ml

(* A simple syntax extension for getting the name of an identifier. *) 
open Camlp4 

(* Create an ID for the macro*) 
module Id : Sig.Id = struct 
    let name = "let'"
    let version = "1.0" 
end 

module Make (Syntax : Sig.Camlp4Syntax) = struct 
    open Sig 
    include Syntax 

    (* Extend the syntax with a let' x=e1 in e2 construction*) 
    EXTEND Gram 
    expr: [ 
        [ "let'"; x = patt ; "=" ; e1=expr; "in"; e2=expr -> 
            let name=begin match x with
                | Ast.PaId (_,Ast.IdLid(_,name)) -> name
                | _ -> failwith "Require an identifier in a let' statement."
            end in
            <:expr<
                let $x$ = $e1$ in ($str:name$,$e2$)
            >>
        ] 
    ]; 
    END 
end 

module M = Register.OCamlSyntaxExtension(Id)(Make) 

Next, compile with

 ocamlc -c -I +camlp4 dynlink.cma camlp4lib.cma -pp camlp4of.opt test.ml

On the top level

 ocaml dynlink.cma -I +camlp4 camlp4of.cma

Then

# #load "test03.cmo";;
# let' x=1 in x;;
- : string * int = ("x", 1)

In order to compile with the extension create a different file such as test2.ml

let' x=1 in x

Then, compile with

ocamlc -pp "camlp4of test.cmo" test2.ml
1
ygrek On

Yes, this is possible. Start with reading some camlp4 tutorial to understand how it works and ask more specific questions.