CBMC
smt_terms.cpp
Go to the documentation of this file.
1 // Author: Diffblue Ltd.
2 
3 #include "smt_terms.h"
4 
5 #include <util/arith_tools.h>
6 #include <util/mp_arith.h>
7 #include <util/range.h>
8 
9 #include "smt_sorts.h"
10 
11 #include <algorithm>
12 #include <regex>
13 
14 // Define the irep_idts for terms.
15 #define TERM_ID(the_id) \
16  const irep_idt ID_smt_##the_id##_term{"smt_" #the_id "_term"};
17 #include "smt_terms.def"
18 
19 #undef TERM_ID
20 
22  : irept{id, {{ID_type, upcast(std::move(sort))}}, {}}
23 {
24 }
25 
26 bool smt_termt::operator==(const smt_termt &other) const
27 {
28  return irept::operator==(other);
29 }
30 
31 bool smt_termt::operator!=(const smt_termt &other) const
32 {
33  return !(*this == other);
34 }
35 
37 {
38  return downcast(find(ID_type));
39 }
40 
42  : smt_termt{ID_smt_bool_literal_term, smt_bool_sortt{}}
43 {
44  set(ID_value, value);
45 }
46 
48 {
49  return get_bool(ID_value);
50 }
51 
52 static bool is_valid_smt_identifier(irep_idt identifier)
53 {
54  // The below regex matches a complete string which does not contain the `|`
55  // character. So it would match the string `foo bar`, but not `|foo bar|`.
56  static const std::regex valid{"[^\\|]*"};
57  return std::regex_match(id2string(identifier), valid);
58 }
59 
61  irep_idt identifier,
62  smt_sortt sort,
63  std::vector<smt_indext> indices)
64  : smt_termt(ID_smt_identifier_term, std::move(sort))
65 {
66  // The below invariant exists as a sanity check that the string being used for
67  // the identifier is in unescaped form. This is because the escaping and
68  // unescaping are implementation details of the printing to string and
69  // response parsing respectively, not part of the underlying data.
70  INVARIANT(
72  R"(Identifiers may not contain | characters.)");
73  set(ID_identifier, identifier);
74  for(auto &index : indices)
75  {
76  get_sub().push_back(
78  }
79 }
80 
82 {
83  return get(ID_identifier);
84 }
85 
86 std::vector<std::reference_wrapper<const smt_indext>>
88 {
89  return make_range(get_sub()).map([](const irept &index) {
90  return std::cref(
92  });
93 }
94 
96  const mp_integer &value,
98  : smt_termt{ID_smt_bit_vector_constant_term, std::move(sort)}
99 {
100  INVARIANT(
102  "value must fit in number of bits available.");
103  INVARIANT(
104  !value.is_negative(),
105  "Negative numbers are not supported by bit vector constants.");
106  set(ID_value, integer2bvrep(value, get_sort().bit_width()));
107 }
108 
110  const mp_integer &value,
111  std::size_t bit_width)
113 {
114 }
115 
117 {
118  return bvrep2integer(get(ID_value), get_sort().bit_width(), false);
119 }
120 
122 {
123  // The below cast is sound because the constructor only allows bit_vector
124  // sorts to be set.
125  return static_cast<const smt_bit_vector_sortt &>(smt_termt::get_sort());
126 }
127 
129  smt_identifier_termt function_identifier,
130  std::vector<smt_termt> arguments)
131  : smt_termt(ID_smt_function_application_term, function_identifier.get_sort())
132 {
133  set(ID_identifier, std::move(function_identifier));
135  std::make_move_iterator(arguments.begin()),
136  std::make_move_iterator(arguments.end()),
137  std::back_inserter(get_sub()),
138  [](smt_termt &&argument) { return static_cast<irept &&>(argument); });
139 }
140 
141 const smt_identifier_termt &
143 {
144  return static_cast<const smt_identifier_termt &>(find(ID_identifier));
145 }
146 
147 std::vector<std::reference_wrapper<const smt_termt>>
149 {
150  return make_range(get_sub()).map([](const irept &argument) {
151  return std::cref(static_cast<const smt_termt &>(argument));
152  });
153 }
154 
156  std::vector<smt_identifier_termt> bound_variables,
157  smt_termt predicate)
158  : smt_termt{ID_smt_forall_term, smt_bool_sortt{}}
159 {
160  INVARIANT(
161  !bound_variables.empty(),
162  "A forall term should bind at least one variable.");
164  std::make_move_iterator(bound_variables.begin()),
165  std::make_move_iterator(bound_variables.end()),
166  std::back_inserter(get_sub()),
167  [](smt_identifier_termt &&bound_variable) {
168  return irept{std::move(bound_variable)};
169  });
170  INVARIANT(
172  "Predicate of forall quantifier is expected to have bool sort.");
173  set(ID_body, std::move(predicate));
174 }
175 
177 {
178  return static_cast<const smt_termt &>(find(ID_body));
179 }
180 
181 std::vector<std::reference_wrapper<const smt_identifier_termt>>
183 {
184  return make_range(get_sub()).map([](const irept &variable) {
185  return std::cref(static_cast<const smt_identifier_termt &>(variable));
186  });
187 }
188 
190  std::vector<smt_identifier_termt> bound_variables,
191  smt_termt predicate)
192  : smt_termt{ID_smt_exists_term, smt_bool_sortt{}}
193 {
194  INVARIANT(
195  !bound_variables.empty(),
196  "A exists term should bind at least one variable.");
198  std::make_move_iterator(bound_variables.begin()),
199  std::make_move_iterator(bound_variables.end()),
200  std::back_inserter(get_sub()),
201  [](smt_identifier_termt &&bound_variable) {
202  return irept{std::move(bound_variable)};
203  });
204  INVARIANT(
206  "Predicate of exists quantifier is expected to have bool sort.");
207  set(ID_body, std::move(predicate));
208 }
209 
211 {
212  return static_cast<const smt_termt &>(find(ID_body));
213 }
214 
215 std::vector<std::reference_wrapper<const smt_identifier_termt>>
217 {
218  return make_range(get_sub()).map([](const irept &variable) {
219  return std::cref(static_cast<const smt_identifier_termt &>(variable));
220  });
221 }
222 
223 template <typename visitort>
224 void accept(const smt_termt &term, const irep_idt &id, visitort &&visitor)
225 {
226 #define TERM_ID(the_id) \
227  if(id == ID_smt_##the_id##_term) \
228  return visitor.visit(static_cast<const smt_##the_id##_termt &>(term));
229 // The include below is marked as nolint because including the same file
230 // multiple times is required as part of the x macro pattern.
231 #include "smt_terms.def" // NOLINT(build/include)
232 #undef TERM_ID
233  UNREACHABLE;
234 }
235 
237 {
238  ::accept(*this, id(), visitor);
239 }
240 
242 {
243  ::accept(*this, id(), std::move(visitor));
244 }
static abstract_object_pointert transform(const exprt &expr, const std::vector< abstract_object_pointert > &operands, const abstract_environmentt &environment, const namespacet &ns)
mp_integer bvrep2integer(const irep_idt &src, std::size_t width, bool is_signed)
convert a bit-vector representation (possibly signed) to integer
irep_idt integer2bvrep(const mp_integer &src, std::size_t width)
convert an integer to bit-vector representation with given width This uses two's complement for negat...
mp_integer power(const mp_integer &base, const mp_integer &exponent)
A multi-precision implementation of the power operator.
dstringt has one field, an unsigned integer no which is an index into a static table of strings.
Definition: dstring.h:38
There are a large number of kinds of tree structured or tree-like data in CPROVER.
Definition: irep.h:364
bool get_bool(const irep_idt &name) const
Definition: irep.cpp:57
bool operator==(const irept &other) const
Definition: irep.cpp:133
subt & get_sub()
Definition: irep.h:448
const irept & find(const irep_idt &name) const
Definition: irep.cpp:93
const irep_idt & get(const irep_idt &name) const
Definition: irep.cpp:44
void set(const irep_idt &name, const irep_idt &value)
Definition: irep.h:412
const smt_bit_vector_sortt & get_sort() const
Definition: smt_terms.cpp:121
smt_bit_vector_constant_termt(const mp_integer &value, smt_bit_vector_sortt)
Definition: smt_terms.cpp:95
mp_integer value() const
Definition: smt_terms.cpp:116
std::size_t bit_width() const
Definition: smt_sorts.cpp:62
smt_bool_literal_termt(bool value)
Definition: smt_terms.cpp:41
bool value() const
Definition: smt_terms.cpp:47
const smt_termt & predicate() const
Definition: smt_terms.cpp:210
std::vector< std::reference_wrapper< const smt_identifier_termt > > bound_variables() const
Definition: smt_terms.cpp:216
smt_exists_termt(std::vector< smt_identifier_termt > bound_variables, smt_termt predicate)
Definition: smt_terms.cpp:189
smt_forall_termt(std::vector< smt_identifier_termt > bound_variables, smt_termt predicate)
Definition: smt_terms.cpp:155
const smt_termt & predicate() const
Definition: smt_terms.cpp:176
std::vector< std::reference_wrapper< const smt_identifier_termt > > bound_variables() const
Definition: smt_terms.cpp:182
const smt_identifier_termt & function_identifier() const
Definition: smt_terms.cpp:142
smt_function_application_termt(smt_identifier_termt function_identifier, std::vector< smt_termt > arguments)
Unchecked construction of function application terms.
Definition: smt_terms.cpp:128
std::vector< std::reference_wrapper< const smt_termt > > arguments() const
Definition: smt_terms.cpp:148
Stores identifiers in unescaped and unquoted form.
Definition: smt_terms.h:93
irep_idt identifier() const
Definition: smt_terms.cpp:81
smt_identifier_termt(irep_idt identifier, smt_sortt sort, std::vector< smt_indext > indices={})
Constructs an identifier term with the given identifier and sort.
Definition: smt_terms.cpp:60
std::vector< std::reference_wrapper< const smt_indext > > indices() const
Definition: smt_terms.cpp:87
Class for adding the ability to up and down cast smt_indext to and from irept.
Definition: smt_index.h:37
static irept upcast(smt_sortt sort)
Definition: smt_sorts.h:66
static const smt_sortt & downcast(const irept &)
Definition: smt_sorts.h:72
const sub_classt * cast() const &
const smt_sortt & get_sort() const
Definition: smt_terms.cpp:36
bool operator==(const smt_termt &) const
Definition: smt_terms.cpp:26
void accept(smt_term_const_downcast_visitort &) const
Definition: smt_terms.cpp:236
smt_termt()=delete
bool operator!=(const smt_termt &) const
Definition: smt_terms.cpp:31
const std::string & id2string(const irep_idt &d)
Definition: irep.h:44
Ranges: pair of begin and end iterators, which can be initialized from containers,...
ranget< iteratort > make_range(iteratort begin, iteratort end)
Definition: range.h:522
Data structure for smt sorts.
void accept(const smt_termt &term, const irep_idt &id, visitort &&visitor)
Definition: smt_terms.cpp:224
static bool is_valid_smt_identifier(irep_idt identifier)
Definition: smt_terms.cpp:52
BigInt mp_integer
Definition: smt_terms.h:17
#define UNREACHABLE
This should be used to mark dead code.
Definition: invariant.h:525