Skip to content
Snippets Groups Projects
freshName.ml 5.33 KiB
(* Time-stamp: <modified the 29/08/2019 (at 15:05) by Erwan Jahier> *)


(* maps node_key to a string that won't clash *)
let node_key_tbl = Hashtbl.create 0

(* maps node name (string) to a counter *)
let node_name_tbl = Hashtbl.create 0

(* exported *)
let (node_key: Lic.node_key -> string -> string) =
  fun nk name -> 
    let (long, _sargs) = nk in
    try Hashtbl.find node_key_tbl nk
    (* Note that we ignore the "name" in argument in this case *)
    with Not_found -> 
      (* let's build an ident that won't clash *)
      (* all new name should not begins with a "_" ; hence we prefix by "n_" *)
      let name = if name = "" then "n_" ^ (Lv6Id.no_pack_string_of_long long) else name in
      if not (Hashtbl.mem node_name_tbl name) then
        (
          (* that name won't clash, but let's tabulate it *)
          Hashtbl.add node_name_tbl name 2;
          Hashtbl.add node_key_tbl nk name;
          name
        )
      else
        (* That name have already been given, there is a possible clash! *)
        let cpt = Hashtbl.find node_name_tbl name in
        let fresh_name = 
          Hashtbl.replace node_name_tbl name (cpt+1);
          name ^ "_" ^ (string_of_int cpt)
        in
        Hashtbl.add node_key_tbl nk fresh_name;
        fresh_name


(********************************************************************************)
(* Dealing with fresh local (to the node) variable idents *)
let local_var_tbl = Hashtbl.create 0

(********************************************************************************)
(* The idea is to prefix fresh var name by "_", except if at least
   one user ident begins by "_". In that case, we try to prefix them
   by "_0", and then "_1", and so on so forth. We take the first
   possible one.

   nb : this won't work if the user have defined all idents from "_1" to
   "_1073741823" (on 32-bits machine), but I bet that this compiler
   would die before anyway...

   nb : We stored in Lv6parserUtils.name_table the set of idents that begins by "_".
*)
let fresh_var_prefix = ref "_"

let char_is_int = function
  |'0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9' -> true
  | _  -> false

(* Returns None if str.[1] is not an int, and Some i otherwhise,
   where i is the biggest possible int in str after the "_" (e.g.,
   "_23toto" returns "Some 23" *)
let (get_int : string -> int option) =
  fun str -> 
    let _ = assert (str<>"" && str.[0]='_') in
    let s = String.length str in
      if s>1 && char_is_int str.[1] then
        let j = ref 2 in
          while  !j<s && char_is_int str.[!j]  do incr j done;
          Some (int_of_string (String.sub str 1 (!j-1)))
      else
        None

let _ = (* A few unit tests *)
  assert (get_int "_" = None);
  assert (get_int "_toto" = None);
  assert (get_int "_1" = Some 1);
  assert (get_int "_1234" = Some 1234);
  assert (get_int "_1234toto" = Some 1234)
  
module IntSet = 
  Set.Make(struct
             type t = int
             let compare = compare
           end)

(* Make sure that update_fresh_var_prefix has been called *)
let fresh_var_prefix_updated = ref false

(* exported *)
let (update_fresh_var_prefix : unit -> unit) =
  fun _ ->
    let used_ints = (* the set of ints apprearing after a "_" in program idents *)
      Hashtbl.fold 
        (fun name _ acc -> 
           match get_int name with
               None -> IntSet.add (-1) acc
             | Some i -> IntSet.add i acc
        )
        Lv6parserUtils.name_table
        IntSet.empty
    in
    let used_ints = IntSet.elements used_ints in
    let rec find_int l =
      match l with 
        | [] -> -1
        | [i] -> if i > 0 then 0 else i+1
        | i::j::tail -> if j=i+1 then find_int (j::tail) else i+1
    in 
    let index = find_int used_ints in
      if index = (-1) then 
        ()
          (* no var begins by "_", so "_" is a good prefix.*)
      else (
        let new_prefix =  ("_" ^ (string_of_int index)) in
          fresh_var_prefix := new_prefix ; 
          Lv6Verbose.exe ~level:1 (
            fun () ->
            prerr_string ("I use " ^ new_prefix ^ " as prefix for fresh var names.\n");
            flush stderr
          )
      );
    fresh_var_prefix_updated := true


(********************************************************************************)
(* exported *)

let (local_var : string -> string) =
  fun prefix ->
    try 
      let cpt = Hashtbl.find local_var_tbl prefix in
      assert (!fresh_var_prefix_updated);
      Hashtbl.replace local_var_tbl prefix (cpt+1);
      !fresh_var_prefix ^ prefix ^"_"^ (string_of_int cpt)
    with
        Not_found -> 
          Hashtbl.add local_var_tbl prefix 2;
          !fresh_var_prefix ^ prefix ^ "_1"

(********************************************************************************)
(* exported *)
open Lic
let (var_info : string -> Lic.type_ -> Lic.id_clock -> Lic.var_info) =
  fun str type_eff clock_eff ->
    let id = Lv6Id.of_string (local_var str) in
    let var =
      { 
        var_name_eff   = id;
        var_nature_eff = AstCore.VarLocal;
        var_number_eff = -1; (* this field is used only for i/o. 
                                Should i rather put something sensible there ? *)
        var_type_eff   = type_eff;
        var_clock_eff  = clock_eff;
      }
    in
    var


(********************************************************************************)

let (array_type : Lic.type_ -> string -> string) =
  fun _t name -> 
    "A_" ^ name