You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 

67 lines
1.7 KiB

open Lang
let fail s = Complice.Utils.failwith (Format.sprintf "scope analysis: %s" s)
module Scope () = struct
let mk_fresh =
let seen = Hashtbl.create 512 in
fun x ->
match Hashtbl.find_opt seen x with
| None ->
Hashtbl.add seen x 0 ; x
| Some n ->
Hashtbl.replace seen x (n + 1) ;
Format.sprintf "_%s%d" x n
module Env = Map.Make (String)
let old_names = Hashtbl.create 512
let unused = Hashtbl.create 512
let add key value scope =
Hashtbl.add old_names value key ;
Hashtbl.add unused value () ;
Env.add key value scope
let const scope = function
| Literal b ->
Literal b
| Var id -> (
try
let new_name = Env.find id scope in
Hashtbl.remove unused new_name ;
Var new_name
with Not_found -> fail (Format.sprintf "unbound variable %s" id) )
let rec expr scope = function
| Const c ->
Const (const scope c)
| Bind (p, e, e') ->
let fresh_p = mk_fresh p in
let fresh_e = expr scope e in
let fresh_e' = expr (add p fresh_p scope) e' in
Bind (fresh_p, fresh_e, fresh_e')
| Abstract (p, e) ->
let fresh_p = mk_fresh p in
let fresh_e = expr (add p fresh_p scope) e in
Abstract (fresh_p, fresh_e)
| Apply (e, e') ->
Apply (expr scope e, expr scope e')
let check_unused () =
Hashtbl.iter
(fun k _ ->
fail (Format.sprintf "unused variable %s" (Hashtbl.find old_names k)))
unused
let file f =
let res = expr Env.empty f in
check_unused () ; res
end
let file f =
let module M = Scope () in
let renamed = M.file f in
let old_names = M.old_names in
(renamed, old_names)