expr = MK_EXPR(kind, args);
}
}
- //| /* substring */
- //LPAREN_TOK STRSUB_TOK n1=INTEGER_LITERAL n2=INTEGER_LITERAL RPAREN_TOK
- //{
- //}
| /* A non-built-in function application */
LPAREN_TOK
functionName[name, CHECK_DECLARED]
| STRCON_TOK { $kind = CVC4::kind::STRING_CONCAT; }
| STRLEN_TOK { $kind = CVC4::kind::STRING_LENGTH; }
+ | STRSUB_TOK { $kind = CVC4::kind::STRING_SUBSTR; }
| STRINRE_TOK { $kind = CVC4::kind::STRING_IN_REGEXP; }
| STRTORE_TOK { $kind = CVC4::kind::STRING_TO_REGEXP; }
| RECON_TOK { $kind = CVC4::kind::REGEXP_CONCAT; }
//STRCST_TOK : 'str.cst';
STRCON_TOK : 'str.++';
STRLEN_TOK : 'str.len';
-//STRSUB_TOK : 'str.sub' ;
+STRSUB_TOK : 'str.sub' ;
STRINRE_TOK : 'str.in.re';
STRTORE_TOK : 'str.to.re';
RECON_TOK : 're.++';
operator STRING_LENGTH 1 "string length"
+operator STRING_SUBSTR 3 "string substr"
+
#sort CHAR_TYPE \
# Cardinality::INTEGERS \
# well-founded \
typerule STRING_CONCAT ::CVC4::theory::strings::StringConcatTypeRule
typerule STRING_LENGTH ::CVC4::theory::strings::StringLengthTypeRule
+typerule STRING_SUBSTR ::CVC4::theory::strings::StringSubstrTypeRule
typerule STRING_IN_REGEXP ::CVC4::theory::strings::StringInRegExpTypeRule
bool addedLemma = false;
if( e == EFFORT_FULL && !d_conflict ) {
eq::EqClassesIterator eqcs_i = eq::EqClassesIterator( &d_equalityEngine );
- while( !eqcs_i.isFinished() ){
+ while( !eqcs_i.isFinished() ) {
Node eqc = (*eqcs_i);
//if eqc.getType is string
if (eqc.getType().isString()) {
//get the constant for the equivalence class
//int c_len = ...;
eq::EqClassIterator eqc_i = eq::EqClassIterator( eqc, &d_equalityEngine );
- while( !eqc_i.isFinished() ){
- Node n = (*eqc_i);
-
- //if n is concat, and
- //if n has not instantiatied the concat..length axiom
- //then, add lemma
- if( n.getKind() == kind::STRING_CONCAT || n.getKind() == kind::CONST_STRING ){
- if( d_length_inst.find(n)==d_length_inst.end() ){
- d_length_inst[n] = true;
- Trace("strings-debug") << "get n: " << n << endl;
- Node sk = NodeManager::currentNM()->mkSkolem( "lsym_$$", n.getType(), "created for concat lemma" );
- d_length_intro_vars.push_back( sk );
- Node eq = NodeManager::currentNM()->mkNode( kind::EQUAL, sk, n );
- eq = Rewriter::rewrite(eq);
- Trace("strings-lemma") << "Strings: Add lemma " << eq << std::endl;
- d_out->lemma(eq);
- Node skl = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk );
- Node lsum;
- if( n.getKind() == kind::STRING_CONCAT ){
- //add lemma
- std::vector<Node> node_vec;
- for( unsigned i=0; i<n.getNumChildren(); i++ ) {
- Node lni = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, n[i] );
- node_vec.push_back(lni);
- }
- lsum = NodeManager::currentNM()->mkNode( kind::PLUS, node_vec );
- }else{
- //add lemma
- lsum = NodeManager::currentNM()->mkConst( ::CVC4::Rational( n.getConst<String>().size() ) );
- }
- Node ceq = NodeManager::currentNM()->mkNode( kind::EQUAL, skl, lsum );
- ceq = Rewriter::rewrite(ceq);
- Trace("strings-lemma") << "Strings: Add lemma " << ceq << std::endl;
- d_out->lemma(ceq);
- addedLemma = true;
- }
- }
- ++eqc_i;
- }
+ while( !eqc_i.isFinished() ){
+ Node n = (*eqc_i);
+ //if n is concat, and
+ //if n has not instantiatied the concat..length axiom
+ //then, add lemma
+ if( n.getKind() == kind::STRING_CONCAT || n.getKind() == kind::CONST_STRING ){
+ if( d_length_inst.find(n)==d_length_inst.end() ){
+ d_length_inst[n] = true;
+ Trace("strings-debug") << "get n: " << n << endl;
+ Node sk = NodeManager::currentNM()->mkSkolem( "lsym_$$", n.getType(), "created for concat lemma" );
+ d_length_intro_vars.push_back( sk );
+ Node eq = NodeManager::currentNM()->mkNode( kind::EQUAL, sk, n );
+ eq = Rewriter::rewrite(eq);
+ Trace("strings-lemma") << "Strings: Add term lemma " << eq << std::endl;
+ d_out->lemma(eq);
+ Node skl = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk );
+ Node lsum;
+ if( n.getKind() == kind::STRING_CONCAT ){
+ //add lemma
+ std::vector<Node> node_vec;
+ for( unsigned i=0; i<n.getNumChildren(); i++ ) {
+ Node lni = NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, n[i] );
+ node_vec.push_back(lni);
+ }
+ lsum = NodeManager::currentNM()->mkNode( kind::PLUS, node_vec );
+ }else{
+ //add lemma
+ lsum = NodeManager::currentNM()->mkConst( ::CVC4::Rational( n.getConst<String>().size() ) );
+ }
+ Node ceq = NodeManager::currentNM()->mkNode( kind::EQUAL, skl, lsum );
+ ceq = Rewriter::rewrite(ceq);
+ Trace("strings-lemma") << "Strings: Add length lemma " << ceq << std::endl;
+ d_out->lemma(ceq);
+ addedLemma = true;
+ }
+ }
+ ++eqc_i;
+ }
}
++eqcs_i;
- }
- if( !addedLemma ){
- addedLemma = checkNormalForms();
- Trace("strings-process") << "Done check normal forms, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
- if(!d_conflict && !addedLemma) {
- addedLemma = checkCardinality();
- Trace("strings-process") << "Done check cardinality, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
- if( !d_conflict && !addedLemma ){
- addedLemma = checkInductiveEquations();
- Trace("strings-process") << "Done check inductive equations, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
- }
- }
- }
+ }
+ if( !addedLemma ){
+ addedLemma = checkNormalForms();
+ Trace("strings-process") << "Done check normal forms, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ if(!d_conflict && !addedLemma) {
+ addedLemma = checkCardinality();
+ Trace("strings-process") << "Done check cardinality, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ if( !d_conflict && !addedLemma ){
+ addedLemma = checkInductiveEquations();
+ Trace("strings-process") << "Done check inductive equations, addedLemma = " << addedLemma << ", d_conflict = " << d_conflict << std::endl;
+ }
+ }
+ }
}
Trace("strings-check") << "Theory of strings, done check : " << e << std::endl;
Trace("strings-process") << "Theory of strings, done check : " << e << std::endl;
}
}
-Node StringsPreprocess::simplify( Node t ) {
+
+Node StringsPreprocess::simplify( Node t, std::vector< Node > &new_nodes ) {
std::hash_map<TNode, Node, TNodeHashFunction>::const_iterator i = d_cache.find(t);
if(i != d_cache.end()) {
return (*i).second.isNull() ? t : (*i).second;
if( t.getKind() == kind::STRING_IN_REGEXP ){
// t0 in t1
+ Node t0 = simplify( t[0], new_nodes );
//rewrite it
std::vector< Node > ret;
- simplifyRegExp( t[0], t[1], ret );
+ simplifyRegExp( t0, t[1], ret );
Node n = ret.size() == 1 ? ret[0] : NodeManager::currentNM()->mkNode( kind::AND, ret );
d_cache[t] = (t == n) ? Node::null() : n;
return n;
- }else if( t.getNumChildren()>0 ){
+ }else if( t.getKind() == kind::STRING_SUBSTR ){
+ Node sk1 = NodeManager::currentNM()->mkSkolem( "st1sym_$$", t.getType(), "created for substr" );
+ Node sk2 = NodeManager::currentNM()->mkSkolem( "st2sym_$$", t.getType(), "created for substr" );
+ Node sk3 = NodeManager::currentNM()->mkSkolem( "st3sym_$$", t.getType(), "created for substr" );
+ Node x = simplify( t[0], new_nodes );
+ Node x_eq_123 = NodeManager::currentNM()->mkNode( kind::EQUAL,
+ NodeManager::currentNM()->mkNode( kind::STRING_CONCAT, sk1, sk2, sk3 ), x );
+ new_nodes.push_back( x_eq_123 );
+ Node len_sk1_eq_i = NodeManager::currentNM()->mkNode( kind::EQUAL, t[1],
+ NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk1 ) );
+ new_nodes.push_back( len_sk1_eq_i );
+ Node len_sk2_eq_j = NodeManager::currentNM()->mkNode( kind::EQUAL, t[2],
+ NodeManager::currentNM()->mkNode( kind::STRING_LENGTH, sk2 ) );
+ new_nodes.push_back( len_sk2_eq_j );
+
+ d_cache[t] = sk2;
+ return sk2;
+ } else if( t.getNumChildren()>0 ){
std::vector< Node > cc;
if (t.getMetaKind() == kind::metakind::PARAMETERIZED) {
cc.push_back(t.getOperator());
}
bool changed = false;
for( unsigned i=0; i<t.getNumChildren(); i++ ){
- Node tn = simplify( t[i] );
+ Node tn = simplify( t[i], new_nodes );
cc.push_back( tn );
changed = changed || tn!=t[i];
}
}
void StringsPreprocess::simplify(std::vector< Node > &vec_node) {
+ std::vector< Node > new_nodes;
for( unsigned i=0; i<vec_node.size(); i++ ){
- vec_node[i] = simplify( vec_node[i] );
+ vec_node[i] = simplify( vec_node[i], new_nodes );
}
+ vec_node.insert( vec_node.end(), new_nodes.begin(), new_nodes.end() );
}
}/* CVC4::theory::strings namespace */
std::hash_map<TNode, Node, TNodeHashFunction> d_cache;
private:
void simplifyRegExp( Node s, Node r, std::vector< Node > &ret );
- Node simplify( Node t );
+ Node simplify( Node t, std::vector< Node > &new_nodes );
public:
void simplify(std::vector< Node > &vec_node);
};
retNode = NodeManager::currentNM()->mkNode(kind::PLUS, node_vec);
}
}
- }
+ } else if(node.getKind() == kind::STRING_SUBSTR) {
+ if( node[0].isConst() && node[1].isConst() && node[2].isConst() ) {
+ int i = node[1].getConst<Rational>().getNumerator().toUnsignedInt();
+ int j = node[2].getConst<Rational>().getNumerator().toUnsignedInt();
+ if( node[0].getConst<String>().size() >= (unsigned) (i + j) ) {
+ retNode = NodeManager::currentNM()->mkConst( node[0].getConst<String>().substr(i, j) );
+ } else {
+ // TODO: some issues, must be guarded by users
+ retNode = NodeManager::currentNM()->mkConst( false );
+ }
+ } else {
+ //handled by preprocess
+ }
+ }
Trace("strings-postrewrite") << "Strings::postRewrite returning " << node << std::endl;
return RewriteResponse(REWRITE_DONE, retNode);
}
};
+class StringSubstrTypeRule {
+public:
+ inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
+ throw (TypeCheckingExceptionPrivate, AssertionException) {
+ if( check ){
+ TypeNode t = n[0].getType(check);
+ if (!t.isString()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting string terms in substr");
+ }
+ t = n[1].getType(check);
+ if (!t.isInteger()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting start int terms in substr");
+ }
+ t = n[2].getType(check);
+ if (!t.isInteger()) {
+ throw TypeCheckingExceptionPrivate(n, "expecting length int terms in substr");
+ }
+ }
+ return nodeManager->stringType();
+ }
+};
+
class RegExpConstantTypeRule {
public:
inline static TypeNode computeType(NodeManager* nodeManager, TNode n, bool check)
str004.smt2 \
str005.smt2 \
model001.smt2 \
+ substr001.smt2 \
loop001.smt2 \
loop002.smt2 \
loop003.smt2 \
--- /dev/null
+(set-logic QF_S)\r
+(set-info :status sat)\r
+\r
+(declare-fun x () String)\r
+(declare-fun i1 () Int)\r
+(declare-fun i2 () Int)\r
+(declare-fun i3 () Int)\r
+(declare-fun i4 () Int)\r
+\r
+(assert (= "efg" (str.sub x i1 i2) ) )\r
+(assert (= "bef" (str.sub x i3 i4) ) )\r
+(assert (> (str.len x) 5))\r
+\r
+(check-sat)\r