@@ -316,8 +316,8 @@ add_axioms_for_format_specifier(
316
316
return {res, std::move (return_code.second )};
317
317
case format_specifiert::STRING:
318
318
{
319
- auto string_expr =
320
- get_string_expr (array_pool, get_arg ( " string_expr " ) );
319
+ const exprt arg_string = get_arg ( " string_expr " );
320
+ const array_string_exprt string_expr = to_array_string_expr (arg_string );
321
321
return {std::move (string_expr), {}};
322
322
}
323
323
case format_specifiert::HASHCODE:
@@ -380,6 +380,69 @@ add_axioms_for_format_specifier(
380
380
}
381
381
}
382
382
383
+ // / Deserialize an argument for format from an \p string
384
+ exprt format_arg_from_string (
385
+ const array_string_exprt &string, const irep_idt &id)
386
+ {
387
+ if (id == " string_expr" )
388
+ return string;
389
+ if (id == ID_int)
390
+ {
391
+ // Assume the string has length 4
392
+ // (int64)string.content[0] << 48 | (int64) string.content[1] << 32 |
393
+ // (int64)string.content[2] << 16 | (int64) string.content[3]
394
+ const signedbv_typet type{64 };
395
+ return bitor_exprt{
396
+ bitor_exprt{
397
+ shl_exprt{
398
+ typecast_exprt (
399
+ index_exprt (
400
+ string.content (), from_integer (0 , string.length ().type ())),
401
+ type),
402
+ 48 },
403
+ shl_exprt{
404
+ typecast_exprt{
405
+ index_exprt{string.content (),
406
+ from_integer (1 , string.length ().type ())},
407
+ type},
408
+ 32 }
409
+ },
410
+ bitor_exprt{
411
+ shl_exprt{
412
+ typecast_exprt (
413
+ index_exprt (
414
+ string.content (), from_integer (1 , string.length ().type ())),
415
+ type),
416
+ 16 },
417
+ typecast_exprt{
418
+ index_exprt{string.content (),
419
+ from_integer (3 , string.length ().type ())},
420
+ type}}
421
+ };
422
+ }
423
+ if (id == ID_char)
424
+ {
425
+ // We assume the string has length exactly 1 and return:
426
+ // (unsigned16)string.content[0]
427
+ const unsignedbv_typet type{16 };
428
+ return typecast_exprt{
429
+ index_exprt (string.content (), from_integer (0 , string.length ().type ())),
430
+ type};
431
+ }
432
+ if (id == ID_boolean)
433
+ {
434
+ // We assume the string already corresponds to the result
435
+ return string;
436
+ }
437
+ if (id == ID_float)
438
+ {
439
+ // Deserialize an int and cast to float
440
+ const exprt as_int = format_arg_from_string (string, ID_int);
441
+ return typecast_exprt{as_int, floatbv_typet{}};
442
+ }
443
+ UNHANDLED_CASE;
444
+ }
445
+
383
446
// / Parse `s` and add axioms ensuring the output corresponds to the output of
384
447
// / String.format.
385
448
// / \param fresh_symbol: generator of fresh symbols
@@ -421,7 +484,7 @@ std::pair<exprt, string_constraintst> add_axioms_for_format(
421
484
{
422
485
INVARIANT (
423
486
arg_count < args.size (), " number of format must match specifiers" );
424
- arg = to_struct_expr ( args[arg_count++]) ;
487
+ arg = args[arg_count++];
425
488
}
426
489
else
427
490
{
@@ -434,12 +497,28 @@ std::pair<exprt, string_constraintst> add_axioms_for_format(
434
497
arg = to_struct_expr (args[fs.index - 1 ]);
435
498
}
436
499
500
+ std::function<exprt (const irep_idt &)> get_arg;
501
+ if (is_refined_string_type (arg.type ()))
502
+ {
503
+ const array_string_exprt string_arg =
504
+ get_string_expr (array_pool, arg);
505
+ get_arg = [string_arg](const irep_idt &id){
506
+ return format_arg_from_string (string_arg, id);
507
+ };
508
+ }
509
+ else
510
+ {
511
+ INVARIANT (
512
+ arg.id () == ID_struct,
513
+ " format argument should be a string or a struct" );
514
+ get_arg = [&](const irep_idt &id){
515
+ return get_component_in_struct (to_struct_expr (arg), id);
516
+ };
517
+ }
437
518
auto result = add_axioms_for_format_specifier (
438
519
fresh_symbol,
439
520
fs,
440
- [&](const irep_idt &id) {
441
- return get_component_in_struct (to_struct_expr (arg), id);
442
- },
521
+ get_arg,
443
522
index_type,
444
523
char_type,
445
524
array_pool,
0 commit comments