return returnRewrite(node, res, "ctn-rpl-non-ctn");
}
}
+
+ // (str.contains x (str.++ w (str.replace x y x) z)) --->
+ // (and (= w "") (= x (str.replace x y x)) (= z ""))
+ if (node[0] == n[0] && node[0] == n[2])
+ {
+ Node ret;
+ if (nc2.size() > 1)
+ {
+ Node emp = nm->mkConst(CVC4::String(""));
+ NodeBuilder<> nb(kind::AND);
+ for (const Node& n2 : nc2)
+ {
+ if (n2 == n)
+ {
+ nb << nm->mkNode(kind::EQUAL, node[0], node[1]);
+ }
+ else
+ {
+ nb << nm->mkNode(kind::EQUAL, emp, n2);
+ }
+ }
+ ret = nb.constructNode();
+ }
+ else
+ {
+ ret = nm->mkNode(kind::EQUAL, node[0], node[1]);
+ }
+ return returnRewrite(node, ret, "ctn-repl-self");
+ }
}
}
}
}
+ if (node[0].getKind() == kind::STRING_SUBSTR)
+ {
+ // (str.contains (str.substr x n (str.len y)) y) --->
+ // (= (str.substr x n (str.len y)) y)
+ //
+ // TODO: generalize with over-/underapproximation to:
+ //
+ // (str.contains x y) ---> (= x y) if (<= (str.len x) (str.len y))
+ if (node[0][2] == nm->mkNode(kind::STRING_LENGTH, node[1]))
+ {
+ Node ret = nm->mkNode(kind::EQUAL, node[0], node[1]);
+ return returnRewrite(node, ret, "ctn-substr");
+ }
+ }
+
+ if (node[1].getKind() == kind::STRING_STRREPL)
+ {
+ // (str.contains x (str.replace y x y)) --->
+ // (str.contains x y)
+ if (node[0] == node[1][1] && node[1][0] == node[1][2])
+ {
+ Node ret = nm->mkNode(kind::STRING_STRCTN, node[0], node[1][0]);
+ return returnRewrite(node, ret, "ctn-repl");
+ }
+
+ // (str.contains x (str.replace "" x y)) --->
+ // (= "" (str.replace "" x y))
+ Node emp = nm->mkConst(CVC4::String(""));
+ if (node[0] == node[1][1] && node[1][0] == emp)
+ {
+ Node ret = nm->mkNode(kind::EQUAL, emp, node[1]);
+ return returnRewrite(node, ret, "ctn-repl-empty");
+ }
+ }
+
Trace("strings-rewrite-nf") << "No rewrites for : " << node << std::endl;
return node;
}
void testRewriteContains()
{
+ TypeNode intType = d_nm->integerType();
TypeNode strType = d_nm->stringType();
Node empty = d_nm->mkConst(::CVC4::String(""));
Node x = d_nm->mkVar("x", strType);
Node y = d_nm->mkVar("y", strType);
Node z = d_nm->mkVar("z", strType);
+ Node n = d_nm->mkVar("n", intType);
Node one = d_nm->mkConst(Rational(2));
Node three = d_nm->mkConst(Rational(3));
Node four = d_nm->mkConst(Rational(4));
d_nm->mkNode(kind::EQUAL, z, empty));
Node res_yx_cnts_xy = Rewriter::rewrite(yx_cnts_xy);
TS_ASSERT_EQUALS(res_yx_cnts_xzy, res_yx_cnts_xy);
+
+ // Same normal form for:
+ //
+ // (str.contains (str.substr x n (str.len y)) y)
+ //
+ // (= (str.substr x n (str.len y)) y)
+ Node ctn_substr = d_nm->mkNode(
+ kind::STRING_STRCTN,
+ d_nm->mkNode(
+ kind::STRING_SUBSTR, x, n, d_nm->mkNode(kind::STRING_LENGTH, y)),
+ y);
+ Node substr_eq = d_nm->mkNode(
+ kind::EQUAL,
+ d_nm->mkNode(
+ kind::STRING_SUBSTR, x, n, d_nm->mkNode(kind::STRING_LENGTH, y)),
+ y);
+ Node res_ctn_substr = Rewriter::rewrite(ctn_substr);
+ Node res_substr_eq = Rewriter::rewrite(substr_eq);
+ TS_ASSERT_EQUALS(res_ctn_substr, res_substr_eq);
+
+ // Same normal form for:
+ //
+ // (str.contains x (str.replace y x y))
+ //
+ // (str.contains x y)
+ Node ctn_repl_y_x_y = d_nm->mkNode(
+ kind::STRING_STRCTN, x, d_nm->mkNode(kind::STRING_STRREPL, y, x, y));
+ Node ctn_x_y = d_nm->mkNode(kind::STRING_STRCTN, x, y);
+ Node res_ctn_repl_y_x_y = Rewriter::rewrite(ctn_repl_y_x_y);
+ Node res_ctn_x_y = Rewriter::rewrite(ctn_x_y);
+ TS_ASSERT_EQUALS(res_ctn_repl_y_x_y, res_ctn_x_y);
+
+ // Same normal form for:
+ //
+ // (str.contains x (str.replace x y x))
+ //
+ // (= x (str.replace x y x))
+ Node ctn_repl_self = d_nm->mkNode(
+ kind::STRING_STRCTN, x, d_nm->mkNode(kind::STRING_STRREPL, x, y, x));
+ Node eq_repl = d_nm->mkNode(
+ kind::EQUAL, x, d_nm->mkNode(kind::STRING_STRREPL, x, y, x));
+ Node res_ctn_repl_self = Rewriter::rewrite(ctn_repl_self);
+ Node res_eq_repl = Rewriter::rewrite(eq_repl);
+ TS_ASSERT_EQUALS(res_ctn_repl_self, res_eq_repl);
+
+ // (str.contains x (str.++ "A" (str.replace x y x))) ---> false
+ Node ctn_repl_self_f =
+ d_nm->mkNode(kind::STRING_STRCTN,
+ x,
+ d_nm->mkNode(kind::STRING_CONCAT,
+ a,
+ d_nm->mkNode(kind::STRING_STRREPL, x, y, x)));
+ Node res_ctn_repl_self_f = Rewriter::rewrite(ctn_repl_self_f);
+ TS_ASSERT_EQUALS(res_ctn_repl_self_f, f);
+
+ // Same normal form for:
+ //
+ // (str.contains x (str.replace "" x y))
+ //
+ // (= "" (str.replace "" x y))
+ Node ctn_repl_empty =
+ d_nm->mkNode(kind::STRING_STRCTN,
+ x,
+ d_nm->mkNode(kind::STRING_STRREPL, empty, x, y));
+ Node eq_repl_empty = d_nm->mkNode(
+ kind::EQUAL, empty, d_nm->mkNode(kind::STRING_STRREPL, empty, x, y));
+ Node res_ctn_repl_empty = Rewriter::rewrite(ctn_repl_empty);
+ Node res_eq_repl_empty = Rewriter::rewrite(eq_repl_empty);
+ TS_ASSERT_EQUALS(res_ctn_repl_empty, res_eq_repl_empty);
}
};