@@ -299,7 +299,8 @@ add_axioms_for_format_specifier(
299
299
return {res, std::move (return_code.second )};
300
300
case format_specifiert::STRING:
301
301
{
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);
303
304
return {std::move (string_expr), {}};
304
305
}
305
306
case format_specifiert::HASHCODE:
@@ -355,6 +356,64 @@ add_axioms_for_format_specifier(
355
356
}
356
357
}
357
358
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
+
358
417
// / Parse `s` and add axioms ensuring the output corresponds to the output of
359
418
// / String.format.
360
419
// / \param fresh_symbol: generator of fresh symbols
@@ -396,7 +455,7 @@ std::pair<exprt, string_constraintst> add_axioms_for_format(
396
455
{
397
456
INVARIANT (
398
457
arg_count < args.size (), " number of format must match specifiers" );
399
- arg = to_struct_expr ( args[arg_count++]) ;
458
+ arg = args[arg_count++];
400
459
}
401
460
else
402
461
{
@@ -409,12 +468,23 @@ std::pair<exprt, string_constraintst> add_axioms_for_format(
409
468
arg = to_struct_expr (args[fs.index - 1 ]);
410
469
}
411
470
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);
418
488
merge (constraints, std::move (result.second ));
419
489
intermediary_strings.push_back (result.first );
420
490
}
0 commit comments