1616#include < util/expr_iterator.h>
1717#include < util/graph.h>
1818#include < util/magic.h>
19+ #include < util/make_unique.h>
1920#include " string_refinement_util.h"
2021
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+
2132bool is_char_type (const typet &type)
2233{
2334 return type.id () == ID_unsignedbv &&
@@ -175,6 +186,119 @@ string_insertion_builtin_functiont::string_insertion_builtin_functiont(
175186 args.insert (args.end (), fun_args.begin () + 4 , fun_args.end ());
176187}
177188
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+
178302// / Construct a string_builtin_functiont object from a function application
179303// / \return a unique pointer to the created object, this unique pointer is empty
180304// / 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(
192316 new string_insertion_builtin_functiont (fun_app.arguments (), array_pool));
193317
194318 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);
197321
198322 return {};
199323}
0 commit comments