blob: 55e095d7726fed3ee515c543a5ad2bd3c7a71d61 [file] [log] [blame] [edit]
open Ast
open Util
open Source
module IdSet = Set.Make (String)
(* Expressions *)
let (@) = IdSet.union
let (-) = IdSet.diff
let free_opt free_x xo = Option.(value (map free_x xo) ~default:IdSet.empty)
let free_list free_x xs = List.(fold_left IdSet.union IdSet.empty (map free_x xs))
let free_id = IdSet.singleton
let rec free_expr expr =
match expr.it with
| NumE _
| BoolE _
| GetCurStateE
| GetCurContextE _
| ContextKindE _
| YetE _ -> IdSet.empty
| VarE id
| SubE (id, _) -> free_id id
| CvtE (e, _, _)
| UnE (_, e)
| LiftE e
| LenE e
| ChooseE e -> free_expr e
| BinE (_, e1, e2)
| CompE (e1, e2)
| CatE (e1, e2)
| MemE (e1, e2) -> free_expr e1 @ free_expr e2
| CallE (_, al)
| InvCallE (_, _, al) -> free_list free_arg al
| TupE el
| ListE el
| CaseE (_, el) -> free_list free_expr el
| StrE r -> free_list (fun (_, e) -> free_expr !e) r
| AccE (e, p) -> free_expr e @ free_path p
| ExtE (e1, ps, e2, _)
| UpdE (e1, ps, e2) -> free_expr e1 @ free_list free_path ps @ free_expr e2
| OptE e_opt -> free_opt free_expr e_opt
| IterE (e, ie) ->
(* We look for semantic free variables, not the syntactic free variables. *)
(* Therefore, in the expression `x*{x <- xs}`, xs is free, but x is not. *)
let free1 = free_expr e in
let bound, free2 = free_iterexp ie in
(free1 - bound) @ free2
| MatchE (e1, e2) -> free_expr e1 @ free_expr e2
| TopValueE None -> IdSet.empty
| IsDefinedE e
| IsCaseOfE (e, _)
| HasTypeE (e, _)
| IsValidE e
| TopValueE (Some e)
| TopValuesE e -> free_expr e
(* Iters *)
and free_iter = function
| Opt
| List
| List1 -> IdSet.empty
| ListN (e, id_opt) -> free_opt IdSet.singleton id_opt @ free_expr e
(* Paths *)
and free_path path =
match path.it with
| IdxP e -> free_expr e
| SliceP (e1, e2) -> free_expr e1 @ free_expr e2
| DotP _ -> IdSet.empty
(* Args *)
and free_arg arg =
match arg.it with
| ExpA e -> free_expr e
| TypA _
| DefA _ -> IdSet.empty
(* Iter exps *)
and free_xes xes =
let xs, es = List.split xes in
free_list free_id xs, free_list free_expr es
and free_iterexp (iter, xes) =
let bound, free = free_xes xes in
bound, free_iter iter @ free
(* Instructions *)
let rec free_instr instr =
match instr.it with
| IfI (e, il1, il2) -> free_expr e @ free_list free_instr il1 @ free_list free_instr il2
| OtherwiseI il -> free_list free_instr il
| EitherI (il1, il2) -> free_list free_instr il1 @ free_list free_instr il2
| TrapI | FailI | NopI | ReturnI None | ExitI _ | YetI _ -> IdSet.empty
| ThrowI e | PushI e | PopI e | PopAllI e | ReturnI (Some e)
| ExecuteI e | ExecuteSeqI e ->
free_expr e
| LetI (e1, e2) | AppendI (e1, e2) -> free_expr e1 @ free_expr e2
| EnterI (e1, e2, il) -> free_expr e1 @ free_expr e2 @ free_list free_instr il
| AssertI e -> free_expr e
| PerformI (_, al) -> free_list free_arg al
| ReplaceI (e1, p, e2) -> free_expr e1 @ free_path p @ free_expr e2
| ForEachI (xes, il) ->
let free1 = free_list free_instr il in
let bound, free2 = free_xes xes in
(free1 - bound) @ free2
(* Algorithms *)
let free_algo algo =
match algo.it with
| RuleA (_, _, args, instrs)
| FuncA (_, args, instrs) -> free_list free_arg args @ free_list free_instr instrs