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
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)
|
|
|