@@ -303,7 +303,8 @@ add_axioms_for_format_specifier(
303
303
return {res, std::move (return_code.second )};
304
304
case format_specifiert::STRING:
305
305
{
306
- auto string_expr = get_string_expr (array_pool, get_arg (" string_expr" ));
306
+ const exprt arg_string = get_arg (" string_expr" );
307
+ const array_string_exprt string_expr = to_array_string_expr (arg_string);
307
308
return {std::move (string_expr), {}};
308
309
}
309
310
case format_specifiert::HASHCODE:
@@ -365,6 +366,55 @@ add_axioms_for_format_specifier(
365
366
}
366
367
}
367
368
369
+ // / Deserialize an argument for format from \p string.
370
+ // / \p id should be one of: string_expr, int, char, boolean, float.
371
+ // / The primitive values are expected to all be encoded using 4 characters.
372
+ static exprt format_arg_from_string (
373
+ const array_string_exprt &string, const irep_idt &id)
374
+ {
375
+ if (id == " string_expr" )
376
+ return string;
377
+ if (id == ID_int)
378
+ {
379
+ // Assume the string has length 4
380
+ // (int64)string.content[0] << 48 | (int64) string.content[1] << 32 |
381
+ // (int64)string.content[2] << 16 | (int64) string.content[3]
382
+ const signedbv_typet type{64 };
383
+ return bitor_exprt{
384
+ bitor_exprt{
385
+ shl_exprt{typecast_exprt{string[0 ], type}, 48 },
386
+ shl_exprt{typecast_exprt{string[1 ], type}, 32 }},
387
+ bitor_exprt{
388
+ shl_exprt{typecast_exprt{string[2 ], type}, 16 },
389
+ typecast_exprt{string[3 ], type}}};
390
+ }
391
+ if (id == ID_char)
392
+ {
393
+ // We assume the string has length exactly 4 and ignore the first 3
394
+ // (unsigned16)string.content[3]
395
+ const unsignedbv_typet type{16 };
396
+ return typecast_exprt{
397
+ index_exprt{string.content (), from_integer (3 , string.length ().type ())},
398
+ type};
399
+ }
400
+ if (id == ID_boolean)
401
+ {
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
+ {
411
+ // Deserialize an int and cast to float
412
+ const exprt as_int = format_arg_from_string (string, ID_int);
413
+ return typecast_exprt{as_int, floatbv_typet{}};
414
+ }
415
+ UNHANDLED_CASE;
416
+ }
417
+
368
418
// / Parse `s` and add axioms ensuring the output corresponds to the output of
369
419
// / String.format.
370
420
// / \param fresh_symbol: generator of fresh symbols
@@ -406,7 +456,7 @@ std::pair<exprt, string_constraintst> add_axioms_for_format(
406
456
{
407
457
INVARIANT (
408
458
arg_count < args.size (), " number of format must match specifiers" );
409
- arg = to_struct_expr ( args[arg_count++]) ;
459
+ arg = args[arg_count++];
410
460
}
411
461
else
412
462
{
@@ -419,12 +469,27 @@ std::pair<exprt, string_constraintst> add_axioms_for_format(
419
469
arg = to_struct_expr (args[fs.index - 1 ]);
420
470
}
421
471
472
+ std::function<exprt (const irep_idt &)> get_arg;
473
+ if (is_refined_string_type (arg.type ())) {
474
+ const array_string_exprt string_arg =
475
+ get_string_expr (array_pool, arg);
476
+ get_arg = [string_arg](const irep_idt &id) {
477
+ return format_arg_from_string (string_arg, id);
478
+ };
479
+ }
480
+ else
481
+ {
482
+ INVARIANT (
483
+ arg.id () == ID_struct,
484
+ " format argument should be a string or a struct" );
485
+ get_arg = [&](const irep_idt &id) {
486
+ return get_component_in_struct (to_struct_expr (arg), id);
487
+ };
488
+ }
422
489
auto result = add_axioms_for_format_specifier (
423
490
fresh_symbol,
424
491
fs,
425
- [&](const irep_idt &id) {
426
- return get_component_in_struct (to_struct_expr (arg), id);
427
- },
492
+ get_arg,
428
493
index_type,
429
494
char_type,
430
495
array_pool,
0 commit comments