Version française
Home     About     Download     Resources     Contact us    
Browse thread
small Camlp4 code : get a free name
[ Home ] [ Index: by date | by threads ]
[ Search: ]

[ Message by date: previous | next ] [ Message in thread: previous | next ] [ Thread: previous | next ]
Date: -- (:)
From: blue storm <bluestorm.dylc@g...>
Subject: small Camlp4 code : get a free name
>> I deduce that there is no standard way of introducing
>> `fresh' (w.r.t. the abstract syntax tree) variables
>> within a camlp4 syntax extension? Wouldn't that be nice? =)

>> Has anybody every implemented a solution to that problem?

> That  would be nice, but doing it cleanly would require a large amount of work
> and user visible changes.

I'm not sure it's a "clean" way of doing it, but i think this may works :
you can fold the AST to get every bound variable names, and then look
for conflicts.

I tried to do that. See my camlp4 code at the end of the message.

The folder is very simple : it collects every identifier name, even
not-really-bounded ones (eg. in patterns). I don't think it's a
problem : the important thing is to get no false positive.

Is there a problem with this method ?
Do you have any comment or advice ?

------------------
open Camlp4;

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

  value get_bound_vars =
    let folder = object (self)
      inherit Ast.fold as super;

      value binds = [];
      method binds = binds;

      method ident = fun
        [ <:ident< $lid:id$ >> | <:ident< $uid:id$ >> ->
          {< binds = [id::binds] >}
        | other -> super#ident other ];
    end in
    fun expr -> (folder#expr expr)#binds;

  value get_free_var suffix binds =
    let rec generate var =
      if List.mem var binds
      then generate ("_" ^ var ^ "_")
      else var
    in generate suffix;
end;
------------------


You can test it with this example code (for example) :
------------------
open Camlp4
open PreCast

module FV = Freevars.Make(Syntax)

let _loc = Loc.ghost
let expr = <:expr< match foo with bar -> foo2 | _ -> 1 + 2 >>

let binds = FV.get_bound_vars expr
let fv = FV.get_free_var "foo" binds
(* fv is "_foo_" *)
------------------

Thanks for your comments.