@@ -239,6 +239,18 @@ static std::vector<format_elementt> parse_format_string(std::string s)
239
239
return al;
240
240
}
241
241
242
+ // / Expression which is true when the string is equal to the literal "null"
243
+ static exprt is_null (const array_string_exprt &string)
244
+ {
245
+ return and_exprt{
246
+ equal_exprt{string.length (), from_integer (4 , string.length ().type ())},
247
+ and_exprt{
248
+ equal_exprt{string[0 ], from_integer (' n' , string[0 ].type ())},
249
+ equal_exprt{string[1 ], from_integer (' u' , string[0 ].type ())},
250
+ equal_exprt{string[2 ], from_integer (' l' , string[0 ].type ())},
251
+ equal_exprt{string[3 ], from_integer (' l' , string[0 ].type ())}}};
252
+ }
253
+
242
254
// / Parse `s` and add axioms ensuring the output corresponds to the output of
243
255
// / String.format. Assumes the argument is a string representing one of:
244
256
// / string expr, int, float, char, boolean, hashcode, date_time.
@@ -286,8 +298,30 @@ add_axioms_for_format_specifier(
286
298
fresh_symbol, res, get_arg (ID_float), array_pool, ns);
287
299
return {res, std::move (return_code.second )};
288
300
case format_specifiert::CHARACTER:
289
- return_code = add_axioms_from_char (res, get_arg (ID_char));
290
- return {res, std::move (return_code.second )};
301
+ {
302
+ exprt arg_string = get_arg (ID_char);
303
+ array_string_exprt &string_expr = to_array_string_expr (arg_string);
304
+ // In the case the arg is null, the result will be equal to "null" and
305
+ // and otherwise we just take the 4th character of the string.
306
+ const exprt is_null_literal = is_null (string_expr);
307
+ constraints.existential .push_back (equal_exprt{
308
+ res.length (),
309
+ if_exprt{
310
+ is_null_literal,
311
+ from_integer (4 , index_type),
312
+ from_integer (1 , index_type)}});
313
+ constraints.existential .push_back (implies_exprt{
314
+ is_null_literal,
315
+ and_exprt{
316
+ equal_exprt{res[0 ], from_integer (' n' , char_type)},
317
+ equal_exprt{res[1 ], from_integer (' u' , char_type)},
318
+ equal_exprt{res[2 ], from_integer (' l' , char_type)},
319
+ equal_exprt{res[3 ], from_integer (' l' , char_type)}}});
320
+ constraints.existential .push_back (implies_exprt{
321
+ not_exprt{is_null_literal},
322
+ equal_exprt{res[0 ], typecast_exprt{string_expr[3 ], char_type}}});
323
+ return {res, constraints};
324
+ }
291
325
case format_specifiert::BOOLEAN:
292
326
return_code = add_axioms_from_bool (res, get_arg (ID_boolean));
293
327
return {res, std::move (return_code.second )};
@@ -378,23 +412,18 @@ static exprt format_arg_from_string(
378
412
shl_exprt{typecast_exprt{string[2 ], type}, 16 },
379
413
typecast_exprt{string[3 ], type}}};
380
414
}
415
+
381
416
if (id == ID_char)
382
417
{
383
- // We assume the string has length exactly 4 and ignore the first 3
384
- // (unsigned16)string.content[3]
385
- const unsignedbv_typet type{16 };
386
- return typecast_exprt{
387
- index_exprt{string.content (), from_integer (3 , string.length ().type ())},
388
- type};
418
+ // Leave the string unchanged as the "null" string is used to represent null
419
+ return string;
389
420
}
390
421
if (id == ID_boolean)
391
422
{
392
- // We assume the string has length exactly 4 and ignore the first 3
393
- // (bool)string.content[3]
394
- const c_bool_typet type{8 };
395
- return typecast_exprt{
396
- index_exprt{string.content (), from_integer (3 , string.length ().type ())},
397
- type};
423
+ // We assume the string has length exactly 4, if it is "null" return false
424
+ // and otherwise ignore the first 3 and return (bool)string.content[3]
425
+ return if_exprt{
426
+ is_null (string), false_exprt{}, typecast_exprt{string[3 ], bool_typet ()}};
398
427
}
399
428
if (id == ID_float)
400
429
{
0 commit comments