16
16
#include < util/expr_iterator.h>
17
17
#include < util/graph.h>
18
18
#include < util/magic.h>
19
+ #include < util/make_unique.h>
19
20
#include " string_refinement_util.h"
20
21
22
+ // / Get the valuation of the string, given a valuation
23
+ static optionalt<std::vector<mp_integer>> eval_string (
24
+ const array_string_exprt &a,
25
+ const std::function<exprt(const exprt &)> &get_value);
26
+
27
+ // / Make a string from a constant array
28
+ static array_string_exprt make_string (
29
+ const std::vector<mp_integer> &array,
30
+ const array_typet &array_type);
31
+
21
32
bool is_char_type (const typet &type)
22
33
{
23
34
return type.id () == ID_unsignedbv &&
@@ -175,6 +186,119 @@ string_insertion_builtin_functiont::string_insertion_builtin_functiont(
175
186
args.insert (args.end (), fun_args.begin () + 4 , fun_args.end ());
176
187
}
177
188
189
+ optionalt<std::vector<mp_integer>> eval_string (
190
+ const array_string_exprt &a,
191
+ const std::function<exprt(const exprt &)> &get_value)
192
+ {
193
+ if (a.id () == ID_if)
194
+ {
195
+ const if_exprt &ite = to_if_expr (a);
196
+ const exprt cond = get_value (ite.cond ());
197
+ if (!cond.is_constant ())
198
+ return {};
199
+ return cond.is_true ()
200
+ ? eval_string (to_array_string_expr (ite.true_case ()), get_value)
201
+ : eval_string (to_array_string_expr (ite.false_case ()), get_value);
202
+ }
203
+
204
+ const auto size = numeric_cast<std::size_t >(get_value (a.length ()));
205
+ const exprt content = get_value (a.content ());
206
+ const auto &array = expr_try_dynamic_cast<array_exprt>(content);
207
+ if (!size || !array)
208
+ return {};
209
+
210
+ const auto &ops = array->operands ();
211
+ INVARIANT (*size == ops.size (), " operands size should match string size" );
212
+
213
+ std::vector<mp_integer> result;
214
+ const mp_integer unknown (' ?' );
215
+ const auto &insert = std::back_inserter (result);
216
+ std::transform (
217
+ ops.begin (), ops.end (), insert, [unknown](const exprt &e) { // NOLINT
218
+ if (const auto i = numeric_cast<mp_integer>(e))
219
+ return *i;
220
+ return unknown;
221
+ });
222
+ return result;
223
+ }
224
+
225
+ array_string_exprt
226
+ make_string (const std::vector<mp_integer> &array, const array_typet &array_type)
227
+ {
228
+ const typet &char_type = array_type.subtype ();
229
+ array_exprt array_expr (array_type);
230
+ const auto &insert = std::back_inserter (array_expr.operands ());
231
+ std::transform (
232
+ array.begin (), array.end (), insert, [&](const mp_integer &i) { // NOLINT
233
+ return from_integer (i, char_type);
234
+ });
235
+ return to_array_string_expr (array_expr);
236
+ }
237
+
238
+ std::vector<mp_integer> string_concatenation_builtin_functiont::eval (
239
+ const std::vector<mp_integer> &input1_value,
240
+ const std::vector<mp_integer> &input2_value,
241
+ const std::vector<mp_integer> &args_value) const
242
+ {
243
+ const std::size_t start_index =
244
+ args_value.size () > 0 && args_value[0 ] > 0 ? args_value[0 ].to_ulong () : 0 ;
245
+ const std::size_t end_index = args_value.size () > 1 && args_value[1 ] > 0
246
+ ? args_value[1 ].to_ulong ()
247
+ : input2_value.size ();
248
+
249
+ std::vector<mp_integer> result (input1_value);
250
+ result.insert (
251
+ result.end (),
252
+ input2_value.begin () + start_index,
253
+ input2_value.begin () + end_index);
254
+ return result;
255
+ }
256
+
257
+ std::vector<mp_integer> string_insertion_builtin_functiont::eval (
258
+ const std::vector<mp_integer> &input1_value,
259
+ const std::vector<mp_integer> &input2_value,
260
+ const std::vector<mp_integer> &args_value) const
261
+ {
262
+ PRECONDITION (args_value.size () >= 1 || args_value.size () <= 3 );
263
+ const std::size_t &offset = numeric_cast_v<std::size_t >(args_value[0 ]);
264
+ const std::size_t &start =
265
+ args_value.size () > 1 ? numeric_cast_v<std::size_t >(args_value[1 ]) : 0 ;
266
+ const std::size_t &end = args_value.size () > 2
267
+ ? numeric_cast_v<std::size_t >(args_value[2 ])
268
+ : input2_value.size ();
269
+
270
+ std::vector<mp_integer> result (input1_value);
271
+ result.insert (
272
+ result.begin () + offset,
273
+ input2_value.begin () + start,
274
+ input2_value.end () + end);
275
+ return result;
276
+ }
277
+
278
+ optionalt<exprt> string_insertion_builtin_functiont::eval (
279
+ const std::function<exprt(const exprt &)> &get_value) const
280
+ {
281
+ const auto &input1_value = eval_string (input1, get_value);
282
+ const auto &input2_value = eval_string (input2, get_value);
283
+ if (!input2_value.has_value () || !input1_value.has_value ())
284
+ return {};
285
+
286
+ std::vector<mp_integer> arg_values;
287
+ const auto &insert = std::back_inserter (arg_values);
288
+ const mp_integer unknown (' ?' );
289
+ std::transform (
290
+ args.begin (), args.end (), insert, [&](const exprt &e) { // NOLINT
291
+ if (const auto val = numeric_cast<mp_integer>(get_value (e)))
292
+ return *val;
293
+ return unknown;
294
+ });
295
+
296
+ const auto result_value = eval (*input1_value, *input2_value, arg_values);
297
+ const auto length = from_integer (result_value.size (), result.length ().type ());
298
+ const array_typet type (result.type ().subtype (), length);
299
+ return make_string (result_value, type);
300
+ }
301
+
178
302
// / Construct a string_builtin_functiont object from a function application
179
303
// / \return a unique pointer to the created object, this unique pointer is empty
180
304
// / if the function does not correspond to one of the supported
@@ -192,8 +316,8 @@ static std::unique_ptr<string_builtin_functiont> to_string_builtin_function(
192
316
new string_insertion_builtin_functiont (fun_app.arguments (), array_pool));
193
317
194
318
if (id == ID_cprover_string_concat_func)
195
- return std::unique_ptr<string_builtin_functiont >(
196
- new string_insertion_builtin_functiont ( fun_app.arguments (), array_pool) );
319
+ return util_make_unique<string_concatenation_builtin_functiont >(
320
+ fun_app.arguments (), array_pool);
197
321
198
322
return {};
199
323
}
0 commit comments