|
9 | 9 | #include "boolbv.h"
|
10 | 10 |
|
11 | 11 | #include <util/range.h>
|
| 12 | +#include <util/replace_symbol.h> |
12 | 13 | #include <util/std_expr.h>
|
13 | 14 |
|
14 | 15 | bvt boolbvt::convert_let(const let_exprt &expr)
|
15 | 16 | {
|
16 | 17 | const auto &variables = expr.variables();
|
17 | 18 | const auto &values = expr.values();
|
18 | 19 |
|
| 20 | + DATA_INVARIANT( |
| 21 | + expr.type() == expr.where().type(), |
| 22 | + "let must have the type of the 'where' operand"); |
| 23 | + |
| 24 | + // Check the types. |
19 | 25 | for(auto &binding : make_range(variables).zip(values))
|
20 | 26 | {
|
21 |
| - const bvt value_bv = convert_bv(binding.second); |
| 27 | + DATA_INVARIANT( |
| 28 | + binding.first.type() == binding.second.type(), |
| 29 | + "let value must have the type of the let symbol"); |
| 30 | + } |
| 31 | + |
| 32 | + // A let expression can bind multiple symbols simultaneously. |
| 33 | + // This is a 'concurrent' binding, i.e., the symbols are not yet |
| 34 | + // visible when evaluating the values. SMT-LIB also has this |
| 35 | + // semantics. We therefore first convert all values, |
| 36 | + // and only then assign them. |
| 37 | + std::vector<bvt> converted_values; |
| 38 | + converted_values.reserve(variables.size()); |
| 39 | + |
| 40 | + for(auto &value : values) |
| 41 | + converted_values.push_back(convert_bv(value)); |
| 42 | + |
| 43 | + scope_counter++; |
| 44 | + |
| 45 | + // for renaming the bound symbols |
| 46 | + replace_symbolt replace_symbol; |
| 47 | + |
| 48 | + // Now assign |
| 49 | + for(const auto &binding : make_range(variables).zip(converted_values)) |
| 50 | + { |
| 51 | + bool is_boolean = binding.first.type().id() == ID_bool; |
| 52 | + const auto &old_identifier = binding.first.get_identifier(); |
| 53 | + |
| 54 | + // produce a new identifier |
| 55 | + const irep_idt new_identifier = |
| 56 | + "boolbvt::scope::" + std::to_string(scope_counter) + |
| 57 | + "::" + id2string(old_identifier); |
22 | 58 |
|
23 |
| - // We expect the identifiers of the bound symbols to be unique, |
24 |
| - // and thus, these can go straight into the symbol to literal map. |
25 |
| - // This property also allows us to cache any subexpressions. |
26 |
| - const irep_idt &id = binding.first.get_identifier(); |
| 59 | + // make the symbol visible |
| 60 | + if(is_boolean) |
| 61 | + { |
| 62 | + DATA_INVARIANT(binding.second.size() == 1, "boolean values have one bit"); |
| 63 | + symbols[new_identifier] = binding.second[0]; |
| 64 | + } |
| 65 | + else |
| 66 | + map.set_literals(new_identifier, binding.first.type(), binding.second); |
27 | 67 |
|
28 |
| - // the symbol shall be visible during the recursive call |
29 |
| - // to convert_bv |
30 |
| - map.set_literals(id, binding.first.type(), value_bv); |
| 68 | + // remember the renaming |
| 69 | + replace_symbol.insert( |
| 70 | + binding.first, symbol_exprt(new_identifier, binding.first.type())); |
31 | 71 | }
|
32 | 72 |
|
33 |
| - bvt result_bv=convert_bv(expr.where()); |
| 73 | + // rename the bound symbols in 'where' |
| 74 | + exprt where_renamed = expr.where(); |
| 75 | + replace_symbol(where_renamed); |
34 | 76 |
|
35 |
| - // now remove, no longer needed |
36 |
| - for(auto &variable : variables) |
37 |
| - map.erase_literals(variable.get_identifier(), variable.type()); |
| 77 | + // recursive call |
| 78 | + bvt result_bv = convert_bv(where_renamed); |
| 79 | + |
| 80 | + // the mapping can now be deleted |
| 81 | + for(const auto &entry : replace_symbol.get_expr_map()) |
| 82 | + { |
| 83 | + const auto &new_symbol = to_symbol_expr(entry.second); |
| 84 | + const auto &type = new_symbol.type(); |
| 85 | + if(type.id() == ID_bool) |
| 86 | + symbols.erase(new_symbol.get_identifier()); |
| 87 | + else |
| 88 | + map.erase_literals(new_symbol.get_identifier(), type); |
| 89 | + } |
38 | 90 |
|
39 | 91 | return result_bv;
|
40 | 92 | }
|
0 commit comments