123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118(**************************************************************************)(* This file is part of the Codex semantics library. *)(* *)(* Copyright (C) 2013-2025 *)(* CEA (Commissariat à l'énergie atomique et aux énergies *)(* alternatives) *)(* *)(* you can redistribute it and/or modify it under the terms of the GNU *)(* Lesser General Public License as published by the Free Software *)(* Foundation, version 2.1. *)(* *)(* It is distributed in the hope that it will be useful, *)(* but WITHOUT ANY WARRANTY; without even the implied warranty of *)(* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *)(* GNU Lesser General Public License for more details. *)(* *)(* See the GNU Lesser General Public License version 2.1 *)(* for more details (enclosed in the file LICENSE). *)(* *)(**************************************************************************)(* Compute, for each variable, the set of variables on which it
depends.
When considering the graph of terms, this corresponds to computing
the set of nodes that are reachable from the initial term. Most of
this is easy to compute on the fly. But to compte the set of
indices needed in the tuples, we need to perform an initial
pass, which is what this module implements. *)moduleMake(T:Sig.TERMS)=structmoduleCapturedSet=Set.Make(T.Any)moduleCHash=Hashtbl.Make(T.Any)moduleCFG_Node_Hash=Hashtbl.Make(T.CFG_Node)moduleIntSet=Set.Make(Int)letdepsc=(* The algorithm is a basic depth-first search, using the
following hashes to mark the visited terms. *)(* If in the hash, the constraint is required. *)lethash=CHash.create117in(* If in the hash, which indices are required for this constraint. *)letcfg_node_hash=CFG_Node_Hash.create117in(* Link from a variable to its closed term. Note that this cannot
be done when we create the variable (since the closed term does
not yet bound_typ). *)letvar_to_mu_i=CHash.create117inletrecconstr:'a.'aT.t->unit=func->letany=T.AnycinifCHash.memhashanythen()elsebeginCHash.replacehashany();letopenTinmatchUtils.get_termcwith|T0_|Empty|Unknown_->()|Mu_formal_->(* A formal depends on its position in the body. *)let(mu,i)=CHash.findvar_to_mu_ianyintuplemui|T1{a}->constra|T2{a;b}->constra;constrb|Tuple_get(i,tup)->tupletupi|Inductive_var{definition}->constrdefinitionendandtupletupi=matchCFG_Node_Hash.findcfg_node_hashtupwith|exceptionNot_found->beginCFG_Node_Hash.replacecfg_node_hashtupIntSet.empty;(* Do things that are done only once per tuple. *)(matchtupwith|Inductive_vars_->assertfalse|Nondet{conda_bool;condb_bool}->constrconda_bool;constrcondb_bool;|Mu{var;body_cond}->beginvar|>Immutable_array.iteri(funivar->CHash.replacevar_to_mu_ivar(tup,i));constrbody_cond;end);tupletupiend|indices->ifIntSet.memiindicesthen()elsebeginCFG_Node_Hash.replacecfg_node_hashtup(IntSet.addiindices);matchtupwith|Inductive_vars_->assertfalse|Nondet{a;b}->letT.Anya=Immutable_array.getaiinconstra;letT.Anyb=Immutable_array.getbiinconstrb|Mu{var;init;body}->letT.Anyinit=Immutable_array.getinitiinconstrinit;letT.Anybody=Immutable_array.getbodyiinconstrbody;letvar=Immutable_array.getvariin(* constr var; *)(* No need to fully call constr here. *)CHash.replacehashvar();endinconstrc;((* (fun x -> CHash.mem hash x), *)(funtup->tryletres=CFG_Node_Hash.findcfg_node_hashtupinIntSet.elementsreswithNot_found->[]))end