|
13 | 13 |
|
14 | 14 | #include <solvers/refinement/string_refinement_invariant.h>
|
15 | 15 | #include <solvers/refinement/string_constraint_generator.h>
|
| 16 | +#include "expr_cast.h" |
16 | 17 |
|
17 | 18 | /// add axioms to say that the returned string expression `res` has length `k`
|
18 | 19 | /// and characters at position `i` in `res` are equal to the character at
|
@@ -359,38 +360,66 @@ string_exprt string_constraint_generatort::add_axioms_for_char_set(
|
359 | 360 | return res;
|
360 | 361 | }
|
361 | 362 |
|
| 363 | +/// Convert two expressions to pair of chars |
| 364 | +/// If both expressions are characters, return pair of them |
| 365 | +/// If both expressions are 1-length strings, return first character of each |
| 366 | +/// Otherwise return empty optional |
| 367 | +/// \param expr1 First expression |
| 368 | +/// \param expr2 Second expression |
| 369 | +/// \return Optional pair of two expressions |
| 370 | +static optionalt<std::pair<exprt, exprt>> to_char_pair( |
| 371 | + exprt expr1, exprt expr2) |
| 372 | +{ |
| 373 | + if((expr1.type().id()==ID_unsignedbv |
| 374 | + || expr1.type().id()==ID_char) |
| 375 | + && (expr2.type().id()==ID_char |
| 376 | + || expr2.type().id()==ID_unsignedbv)) |
| 377 | + return std::make_pair(expr1, expr2); |
| 378 | + const auto expr1_str=to_string_expr(expr1); |
| 379 | + const auto expr2_str=to_string_expr(expr2); |
| 380 | + const auto expr1_length=expr_cast<size_t>(expr1_str.length()); |
| 381 | + const auto expr2_length=expr_cast<size_t>(expr2_str.length()); |
| 382 | + if(expr1_length && expr2_length && *expr1_length==1 && *expr2_length==1) |
| 383 | + return std::make_pair(exprt(expr1_str[0]), exprt(expr2_str[0])); |
| 384 | + return { }; |
| 385 | +} |
| 386 | + |
362 | 387 | /// add axioms corresponding to the String.replace java function
|
363 | 388 | /// \par parameters: function application with three arguments, the first is a
|
364 | 389 | /// string,
|
365 |
| -/// the second and the third are characters |
| 390 | +/// the second and the third are either pair of characters or a pair of strings |
366 | 391 | /// \return a new string expression
|
367 | 392 | string_exprt string_constraint_generatort::add_axioms_for_replace(
|
368 | 393 | const function_application_exprt &f)
|
369 | 394 | {
|
370 | 395 | string_exprt str=get_string_expr(args(f, 3)[0]);
|
371 | 396 | const refined_string_typet &ref_type=to_refined_string_type(str.type());
|
372 |
| - const exprt &old_char=args(f, 3)[1]; |
373 |
| - const exprt &new_char=args(f, 3)[2]; |
374 |
| - string_exprt res=fresh_string(ref_type); |
375 |
| - |
376 |
| - // We add axioms: |
377 |
| - // a1 : |res| = |str| |
378 |
| - // a2 : forall qvar, 0<=qvar<|res|, |
379 |
| - // str[qvar]=oldChar => res[qvar]=newChar |
380 |
| - // !str[qvar]=oldChar => res[qvar]=str[qvar] |
381 |
| - |
382 |
| - m_axioms.push_back(res.axiom_for_has_same_length_as(str)); |
383 |
| - |
384 |
| - symbol_exprt qvar=fresh_univ_index("QA_replace", ref_type.get_index_type()); |
385 |
| - implies_exprt case1( |
386 |
| - equal_exprt(str[qvar], old_char), |
387 |
| - equal_exprt(res[qvar], new_char)); |
388 |
| - implies_exprt case2( |
389 |
| - not_exprt(equal_exprt(str[qvar], old_char)), |
390 |
| - equal_exprt(res[qvar], str[qvar])); |
391 |
| - string_constraintt a2(qvar, res.length(), and_exprt(case1, case2)); |
392 |
| - m_axioms.push_back(a2); |
393 |
| - return res; |
| 397 | + if(const auto maybe_chars=to_char_pair(args(f, 3)[1], args(f, 3)[2])) |
| 398 | + { |
| 399 | + const auto old_char=maybe_chars->first; |
| 400 | + const auto new_char=maybe_chars->second; |
| 401 | + string_exprt res=fresh_string(ref_type); |
| 402 | + |
| 403 | + // We add axioms: |
| 404 | + // a1 : |res| = |str| |
| 405 | + // a2 : forall qvar, 0<=qvar<|res|, |
| 406 | + // str[qvar]=oldChar => res[qvar]=newChar |
| 407 | + // !str[qvar]=oldChar => res[qvar]=str[qvar] |
| 408 | + |
| 409 | + m_axioms.push_back(res.axiom_for_has_same_length_as(str)); |
| 410 | + |
| 411 | + symbol_exprt qvar=fresh_univ_index("QA_replace", ref_type.get_index_type()); |
| 412 | + implies_exprt case1( |
| 413 | + equal_exprt(str[qvar], old_char), |
| 414 | + equal_exprt(res[qvar], new_char)); |
| 415 | + implies_exprt case2( |
| 416 | + not_exprt(equal_exprt(str[qvar], old_char)), |
| 417 | + equal_exprt(res[qvar], str[qvar])); |
| 418 | + string_constraintt a2(qvar, res.length(), and_exprt(case1, case2)); |
| 419 | + m_axioms.push_back(a2); |
| 420 | + return res; |
| 421 | + } |
| 422 | + return str; |
394 | 423 | }
|
395 | 424 |
|
396 | 425 | /// add axioms corresponding to the StringBuilder.deleteCharAt java function
|
|
0 commit comments