Skip to content

Commit a0f50df

Browse files
Make add_axioms_for_format accept string arguments
Add the possibility to pass argument to the builtin format functtion as strings instead structs with fields.
1 parent d54c0b5 commit a0f50df

File tree

1 file changed

+78
-8
lines changed

1 file changed

+78
-8
lines changed

src/solvers/strings/string_constraint_generator_format.cpp

Lines changed: 78 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -299,7 +299,8 @@ add_axioms_for_format_specifier(
299299
return {res, std::move(return_code.second)};
300300
case format_specifiert::STRING:
301301
{
302-
auto string_expr = get_string_expr(array_pool, get_arg("string_expr"));
302+
const exprt arg_string = get_arg("string_expr");
303+
const array_string_exprt string_expr = to_array_string_expr(arg_string);
303304
return {std::move(string_expr), {}};
304305
}
305306
case format_specifiert::HASHCODE:
@@ -355,6 +356,64 @@ add_axioms_for_format_specifier(
355356
}
356357
}
357358

359+
/// Deserialize an argument for format from \p string.
360+
/// \p id should be one of: string_expr, int, char, boolean, float.
361+
/// The primitive values are expected to all be encoded using 4 characters.
362+
exprt format_arg_from_string(const array_string_exprt &string,
363+
const irep_idt &id) {
364+
if(id == "string_expr")
365+
return string;
366+
if(id == ID_int) {
367+
// Assume the string has length 4
368+
// (int64)string.content[0] << 48 | (int64) string.content[1] << 32 |
369+
// (int64)string.content[2] << 16 | (int64) string.content[3]
370+
const signedbv_typet type{64};
371+
return bitor_exprt{
372+
bitor_exprt{
373+
shl_exprt{typecast_exprt{
374+
index_exprt{string.content(),
375+
from_integer(0, string.length().type())},
376+
type},
377+
48},
378+
shl_exprt{typecast_exprt{
379+
index_exprt{string.content(),
380+
from_integer(1, string.length().type())},
381+
type},
382+
32}},
383+
bitor_exprt{
384+
shl_exprt{typecast_exprt{
385+
index_exprt{string.content(),
386+
from_integer(2, string.length().type())},
387+
type},
388+
16},
389+
typecast_exprt{index_exprt{string.content(),
390+
from_integer(3, string.length().type())},
391+
type}}};
392+
}
393+
if(id == ID_char) {
394+
// We assume the string has length exactly 4 and ignore the first 3
395+
// (unsigned16)string.content[3]
396+
const unsignedbv_typet type{16};
397+
return typecast_exprt{
398+
index_exprt{string.content(), from_integer(3, string.length().type())},
399+
type};
400+
}
401+
if(id == ID_boolean) {
402+
// We assume the string has length exactly 4 and ignore the first 3
403+
// (bool)string.content[3]
404+
const c_bool_typet type{8};
405+
return typecast_exprt{
406+
index_exprt{string.content(), from_integer(3, string.length().type())},
407+
type};
408+
}
409+
if(id == ID_float) {
410+
// Deserialize an int and cast to float
411+
const exprt as_int = format_arg_from_string(string, ID_int);
412+
return typecast_exprt{as_int, floatbv_typet{}};
413+
}
414+
UNHANDLED_CASE;
415+
}
416+
358417
/// Parse `s` and add axioms ensuring the output corresponds to the output of
359418
/// String.format.
360419
/// \param fresh_symbol: generator of fresh symbols
@@ -396,7 +455,7 @@ std::pair<exprt, string_constraintst> add_axioms_for_format(
396455
{
397456
INVARIANT(
398457
arg_count < args.size(), "number of format must match specifiers");
399-
arg = to_struct_expr(args[arg_count++]);
458+
arg = args[arg_count++];
400459
}
401460
else
402461
{
@@ -409,12 +468,23 @@ std::pair<exprt, string_constraintst> add_axioms_for_format(
409468
arg = to_struct_expr(args[fs.index - 1]);
410469
}
411470

412-
auto result = add_axioms_for_format_specifier(
413-
fresh_symbol, fs,
414-
[&](const irep_idt &id) {
415-
return get_component_in_struct(to_struct_expr(arg), id);
416-
},
417-
index_type, char_type, array_pool, message, ns);
471+
std::function<exprt(const irep_idt &)> get_arg;
472+
if (is_refined_string_type(arg.type())) {
473+
const array_string_exprt string_arg =
474+
get_string_expr(array_pool, arg);
475+
get_arg = [string_arg](const irep_idt &id) {
476+
return format_arg_from_string(string_arg, id);
477+
};
478+
} else {
479+
INVARIANT(arg.id() == ID_struct,
480+
"format argument should be a string or a struct");
481+
get_arg = [&](const irep_idt &id) {
482+
return get_component_in_struct(to_struct_expr(arg), id);
483+
};
484+
}
485+
auto result = add_axioms_for_format_specifier(fresh_symbol, fs, get_arg,
486+
index_type, char_type,
487+
array_pool, message, ns);
418488
merge(constraints, std::move(result.second));
419489
intermediary_strings.push_back(result.first);
420490
}

0 commit comments

Comments
 (0)