@@ -11,6 +11,8 @@ Author: Daniel Kroening, kroening@kroening.com
1111#include " namespace.h"
1212#include " range.h"
1313
14+ #include < map>
15+
1416bool constant_exprt::value_is_zero_string () const
1517{
1618 const std::string val=id2string (get_value ());
@@ -134,3 +136,136 @@ void let_exprt::validate(const exprt &expr, const validation_modet vm)
134136 " let bindings must be type consistent" );
135137 }
136138}
139+
140+ static optionalt<exprt> substitute_symbols_rec (
141+ const std::map<irep_idt, exprt> &substitutions,
142+ exprt src)
143+ {
144+ if (src.id () == ID_symbol)
145+ {
146+ auto s_it = substitutions.find (to_symbol_expr (src).get_identifier ());
147+ if (s_it == substitutions.end ())
148+ return {};
149+ else
150+ return s_it->second ;
151+ }
152+ else if (
153+ src.id () == ID_forall || src.id () == ID_exists || src.id () == ID_lambda)
154+ {
155+ const auto &binding_expr = to_binding_expr (src);
156+
157+ // bindings may be nested,
158+ // which may hide some of our substitutions
159+ auto new_substitutions = substitutions;
160+ for (const auto &variable : binding_expr.variables ())
161+ new_substitutions.erase (variable.get_identifier ());
162+
163+ auto op_result =
164+ substitute_symbols_rec (new_substitutions, binding_expr.where ());
165+ if (op_result.has_value ())
166+ return binding_exprt (
167+ src.id (),
168+ binding_expr.variables (),
169+ op_result.value (),
170+ binding_expr.type ());
171+ else
172+ return {};
173+ }
174+ else if (src.id () == ID_let)
175+ {
176+ auto new_let_expr = to_let_expr (src); // copy
177+ const auto &binding_expr = to_let_expr (src).binding ();
178+
179+ // bindings may be nested,
180+ // which may hide some of our substitutions
181+ auto new_substitutions = substitutions;
182+ for (const auto &variable : binding_expr.variables ())
183+ new_substitutions.erase (variable.get_identifier ());
184+
185+ bool op_changed = false ;
186+
187+ for (auto &op : new_let_expr.values ())
188+ {
189+ auto op_result = substitute_symbols_rec (new_substitutions, op);
190+
191+ if (op_result.has_value ())
192+ {
193+ op = op_result.value ();
194+ op_changed = true ;
195+ }
196+ }
197+
198+ auto op_result =
199+ substitute_symbols_rec (new_substitutions, binding_expr.where ());
200+ if (op_result.has_value ())
201+ {
202+ new_let_expr.where () = op_result.value ();
203+ op_changed = true ;
204+ }
205+
206+ if (op_changed)
207+ return std::move (new_let_expr);
208+ else
209+ return {};
210+ }
211+
212+ if (!src.has_operands ())
213+ return {};
214+
215+ bool op_changed = false ;
216+
217+ for (auto &op : src.operands ())
218+ {
219+ auto op_result = substitute_symbols_rec (substitutions, op);
220+
221+ if (op_result.has_value ())
222+ {
223+ op = op_result.value ();
224+ op_changed = true ;
225+ }
226+ }
227+
228+ if (op_changed)
229+ return src;
230+ else
231+ return {};
232+ }
233+
234+ exprt binding_exprt::instantiate (const operandst &values) const
235+ {
236+ // number of values must match the number of bound variables
237+ auto &variables = this ->variables ();
238+ PRECONDITION (variables.size () == values.size ());
239+
240+ std::map<symbol_exprt, exprt> value_map;
241+
242+ for (std::size_t i = 0 ; i < variables.size (); i++)
243+ {
244+ // types must match
245+ PRECONDITION (variables[i].type () == values[i].type ());
246+ value_map[variables[i]] = values[i];
247+ }
248+
249+ // build a substitution map
250+ std::map<irep_idt, exprt> substitutions;
251+
252+ for (std::size_t i = 0 ; i < variables.size (); i++)
253+ substitutions[variables[i].get_identifier ()] = values[i];
254+
255+ // now recurse downwards and substitute in 'where'
256+ auto substitute_result = substitute_symbols_rec (substitutions, where ());
257+
258+ if (substitute_result.has_value ())
259+ return substitute_result.value ();
260+ else
261+ return where (); // trivial case, variables not used
262+ }
263+
264+ exprt binding_exprt::instantiate (const variablest &new_variables) const
265+ {
266+ std::vector<exprt> values;
267+ values.reserve (new_variables.size ());
268+ for (const auto &new_variable : new_variables)
269+ values.push_back (new_variable);
270+ return instantiate (values);
271+ }
0 commit comments