mirror of
https://github.com/Z3Prover/z3
synced 2025-04-23 09:05:31 +00:00
implementing last-index-of #2089
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
62ec02e50f
commit
3c8fd83c97
10 changed files with 174 additions and 31 deletions
|
@ -391,44 +391,57 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
|
|||
|
||||
case OP_SEQ_UNIT:
|
||||
SASSERT(num_args == 1);
|
||||
return mk_seq_unit(args[0], result);
|
||||
st = mk_seq_unit(args[0], result);
|
||||
break;
|
||||
case OP_SEQ_EMPTY:
|
||||
return BR_FAILED;
|
||||
case OP_RE_PLUS:
|
||||
SASSERT(num_args == 1);
|
||||
return mk_re_plus(args[0], result);
|
||||
st = mk_re_plus(args[0], result);
|
||||
break;
|
||||
case OP_RE_STAR:
|
||||
SASSERT(num_args == 1);
|
||||
st = mk_re_star(args[0], result);
|
||||
break;
|
||||
case OP_RE_OPTION:
|
||||
SASSERT(num_args == 1);
|
||||
return mk_re_opt(args[0], result);
|
||||
st = mk_re_opt(args[0], result);
|
||||
break;
|
||||
case OP_RE_CONCAT:
|
||||
if (num_args == 1) {
|
||||
result = args[0];
|
||||
return BR_DONE;
|
||||
st = BR_DONE;
|
||||
}
|
||||
else {
|
||||
SASSERT(num_args == 2);
|
||||
st = mk_re_concat(args[0], args[1], result);
|
||||
}
|
||||
SASSERT(num_args == 2);
|
||||
st = mk_re_concat(args[0], args[1], result);
|
||||
break;
|
||||
case OP_RE_UNION:
|
||||
if (num_args == 1) {
|
||||
result = args[0]; return BR_DONE;
|
||||
result = args[0];
|
||||
st = BR_DONE;
|
||||
}
|
||||
SASSERT(num_args == 2);
|
||||
return mk_re_union(args[0], args[1], result);
|
||||
else {
|
||||
SASSERT(num_args == 2);
|
||||
st = mk_re_union(args[0], args[1], result);
|
||||
}
|
||||
break;
|
||||
case OP_RE_RANGE:
|
||||
SASSERT(num_args == 2);
|
||||
return mk_re_range(args[0], args[1], result);
|
||||
st = mk_re_range(args[0], args[1], result);
|
||||
break;
|
||||
case OP_RE_INTERSECT:
|
||||
SASSERT(num_args == 2);
|
||||
return mk_re_inter(args[0], args[1], result);
|
||||
st = mk_re_inter(args[0], args[1], result);
|
||||
break;
|
||||
case OP_RE_COMPLEMENT:
|
||||
SASSERT(num_args == 1);
|
||||
return mk_re_complement(args[0], result);
|
||||
st = mk_re_complement(args[0], result);
|
||||
break;
|
||||
case OP_RE_LOOP:
|
||||
return mk_re_loop(num_args, args, result);
|
||||
st = mk_re_loop(num_args, args, result);
|
||||
break;
|
||||
case OP_RE_EMPTY_SET:
|
||||
return BR_FAILED;
|
||||
case OP_RE_FULL_SEQ_SET:
|
||||
|
@ -442,23 +455,29 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
|
|||
case OP_SEQ_CONCAT:
|
||||
if (num_args == 1) {
|
||||
result = args[0];
|
||||
return BR_DONE;
|
||||
st = BR_DONE;
|
||||
}
|
||||
SASSERT(num_args == 2);
|
||||
return mk_seq_concat(args[0], args[1], result);
|
||||
else {
|
||||
SASSERT(num_args == 2);
|
||||
st = mk_seq_concat(args[0], args[1], result);
|
||||
}
|
||||
break;
|
||||
case OP_SEQ_LENGTH:
|
||||
SASSERT(num_args == 1);
|
||||
return mk_seq_length(args[0], result);
|
||||
st = mk_seq_length(args[0], result);
|
||||
break;
|
||||
case OP_SEQ_EXTRACT:
|
||||
SASSERT(num_args == 3);
|
||||
st = mk_seq_extract(args[0], args[1], args[2], result);
|
||||
break;
|
||||
case OP_SEQ_CONTAINS:
|
||||
SASSERT(num_args == 2);
|
||||
return mk_seq_contains(args[0], args[1], result);
|
||||
st = mk_seq_contains(args[0], args[1], result);
|
||||
break;
|
||||
case OP_SEQ_AT:
|
||||
SASSERT(num_args == 2);
|
||||
return mk_seq_at(args[0], args[1], result);
|
||||
st = mk_seq_at(args[0], args[1], result);
|
||||
break;
|
||||
#if 0
|
||||
case OP_SEQ_NTH:
|
||||
SASSERT(num_args == 2);
|
||||
|
@ -466,35 +485,49 @@ br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * con
|
|||
#endif
|
||||
case OP_SEQ_PREFIX:
|
||||
SASSERT(num_args == 2);
|
||||
return mk_seq_prefix(args[0], args[1], result);
|
||||
st = mk_seq_prefix(args[0], args[1], result);
|
||||
break;
|
||||
case OP_SEQ_SUFFIX:
|
||||
SASSERT(num_args == 2);
|
||||
return mk_seq_suffix(args[0], args[1], result);
|
||||
st = mk_seq_suffix(args[0], args[1], result);
|
||||
break;
|
||||
case OP_SEQ_INDEX:
|
||||
if (num_args == 2) {
|
||||
expr_ref arg3(m_autil.mk_int(0), m());
|
||||
result = m_util.str.mk_index(args[0], args[1], arg3);
|
||||
return BR_REWRITE1;
|
||||
st = BR_REWRITE1;
|
||||
}
|
||||
SASSERT(num_args == 3);
|
||||
return mk_seq_index(args[0], args[1], args[2], result);
|
||||
else {
|
||||
SASSERT(num_args == 3);
|
||||
st = mk_seq_index(args[0], args[1], args[2], result);
|
||||
}
|
||||
break;
|
||||
case OP_SEQ_LAST_INDEX:
|
||||
SASSERT(num_args == 2);
|
||||
st = mk_seq_last_index(args[0], args[1], result);
|
||||
break;
|
||||
case OP_SEQ_REPLACE:
|
||||
SASSERT(num_args == 3);
|
||||
return mk_seq_replace(args[0], args[1], args[2], result);
|
||||
st = mk_seq_replace(args[0], args[1], args[2], result);
|
||||
break;
|
||||
case OP_SEQ_TO_RE:
|
||||
SASSERT(num_args == 1);
|
||||
return mk_str_to_regexp(args[0], result);
|
||||
st = mk_str_to_regexp(args[0], result);
|
||||
break;
|
||||
case OP_SEQ_IN_RE:
|
||||
SASSERT(num_args == 2);
|
||||
return mk_str_in_regexp(args[0], args[1], result);
|
||||
st = mk_str_in_regexp(args[0], args[1], result);
|
||||
break;
|
||||
case OP_STRING_CONST:
|
||||
return BR_FAILED;
|
||||
case OP_STRING_ITOS:
|
||||
SASSERT(num_args == 1);
|
||||
return mk_str_itos(args[0], result);
|
||||
st = mk_str_itos(args[0], result);
|
||||
break;
|
||||
case OP_STRING_STOI:
|
||||
SASSERT(num_args == 1);
|
||||
return mk_str_stoi(args[0], result);
|
||||
st = mk_str_stoi(args[0], result);
|
||||
break;
|
||||
case _OP_STRING_CONCAT:
|
||||
case _OP_STRING_PREFIX:
|
||||
case _OP_STRING_SUFFIX:
|
||||
|
@ -908,6 +941,18 @@ br_status seq_rewriter::mk_seq_nth(expr* a, expr* b, expr_ref& result) {
|
|||
return BR_FAILED;
|
||||
}
|
||||
|
||||
br_status seq_rewriter::mk_seq_last_index(expr* a, expr* b, expr_ref& result) {
|
||||
zstring s1, s2;
|
||||
bool isc1 = m_util.str.is_string(a, s1);
|
||||
bool isc2 = m_util.str.is_string(b, s2);
|
||||
if (isc1 && isc2) {
|
||||
int idx = s1.last_indexof(s2);
|
||||
result = m_autil.mk_numeral(rational(idx), true);
|
||||
return BR_DONE;
|
||||
}
|
||||
return BR_FAILED;
|
||||
}
|
||||
|
||||
br_status seq_rewriter::mk_seq_index(expr* a, expr* b, expr* c, expr_ref& result) {
|
||||
zstring s1, s2;
|
||||
rational r;
|
||||
|
|
|
@ -116,6 +116,7 @@ class seq_rewriter {
|
|||
br_status mk_seq_at(expr* a, expr* b, expr_ref& result);
|
||||
br_status mk_seq_nth(expr* a, expr* b, expr_ref& result);
|
||||
br_status mk_seq_index(expr* a, expr* b, expr* c, expr_ref& result);
|
||||
br_status mk_seq_last_index(expr* a, expr* b, expr_ref& result);
|
||||
br_status mk_seq_replace(expr* a, expr* b, expr* c, expr_ref& result);
|
||||
br_status mk_seq_prefix(expr* a, expr* b, expr_ref& result);
|
||||
br_status mk_seq_suffix(expr* a, expr* b, expr_ref& result);
|
||||
|
|
|
@ -273,6 +273,21 @@ int zstring::indexof(zstring const& other, int offset) const {
|
|||
return -1;
|
||||
}
|
||||
|
||||
int zstring::last_indexof(zstring const& other) const {
|
||||
if (other.length() == 0) return length();
|
||||
if (other.length() > length()) return -1;
|
||||
for (unsigned last = length() - other.length(); last-- > 0; ) {
|
||||
bool suffix = true;
|
||||
for (unsigned j = 0; suffix && j < other.length(); ++j) {
|
||||
suffix = m_buffer[last + j] == other[j];
|
||||
}
|
||||
if (suffix) {
|
||||
return static_cast<int>(last);
|
||||
}
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
zstring zstring::extract(int offset, int len) const {
|
||||
zstring result(m_encoding);
|
||||
SASSERT(0 <= offset && 0 <= len);
|
||||
|
@ -530,6 +545,7 @@ void seq_decl_plugin::init() {
|
|||
m_sigs[OP_SEQ_EXTRACT] = alloc(psig, m, "seq.extract", 1, 3, seqAint2T, seqA);
|
||||
m_sigs[OP_SEQ_REPLACE] = alloc(psig, m, "seq.replace", 1, 3, seq3A, seqA);
|
||||
m_sigs[OP_SEQ_INDEX] = alloc(psig, m, "seq.indexof", 1, 3, seq2AintT, intT);
|
||||
m_sigs[OP_SEQ_LAST_INDEX] = alloc(psig, m, "seq.last_indexof", 1, 2, seqAseqA, intT);
|
||||
m_sigs[OP_SEQ_AT] = alloc(psig, m, "seq.at", 1, 2, seqAintT, seqA);
|
||||
m_sigs[OP_SEQ_NTH] = alloc(psig, m, "seq.nth", 1, 2, seqAintT, A);
|
||||
m_sigs[OP_SEQ_LENGTH] = alloc(psig, m, "seq.len", 1, 1, &seqA, intT);
|
||||
|
@ -774,7 +790,13 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
|
|||
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, OP_SEQ_INDEX));
|
||||
}
|
||||
return mk_str_fun(k, arity, domain, range, OP_SEQ_INDEX);
|
||||
|
||||
case OP_SEQ_LAST_INDEX:
|
||||
if (arity != 2) {
|
||||
m.raise_exception("two arguments expected tin last_indexof");
|
||||
}
|
||||
else {
|
||||
return mk_seq_fun(k, arity, domain, range, OP_SEQ_LAST_INDEX);
|
||||
}
|
||||
case OP_SEQ_PREFIX:
|
||||
return mk_seq_fun(k, arity, domain, range, _OP_STRING_PREFIX);
|
||||
case _OP_STRING_PREFIX:
|
||||
|
|
|
@ -43,6 +43,7 @@ enum seq_op_kind {
|
|||
OP_SEQ_NTH,
|
||||
OP_SEQ_LENGTH,
|
||||
OP_SEQ_INDEX,
|
||||
OP_SEQ_LAST_INDEX,
|
||||
OP_SEQ_TO_RE,
|
||||
OP_SEQ_IN_RE,
|
||||
|
||||
|
@ -113,6 +114,7 @@ public:
|
|||
bool prefixof(zstring const& other) const;
|
||||
bool contains(zstring const& other) const;
|
||||
int indexof(zstring const& other, int offset) const;
|
||||
int last_indexof(zstring const& other) const;
|
||||
zstring extract(int lo, int hi) const;
|
||||
zstring operator+(zstring const& other) const;
|
||||
bool operator==(const zstring& other) const;
|
||||
|
@ -260,6 +262,7 @@ public:
|
|||
app* mk_prefix(expr* a, expr* b) const { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_PREFIX, 2, es); }
|
||||
app* mk_suffix(expr* a, expr* b) const { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_SUFFIX, 2, es); }
|
||||
app* mk_index(expr* a, expr* b, expr* i) const { expr* es[3] = { a, b, i}; return m.mk_app(m_fid, OP_SEQ_INDEX, 3, es); }
|
||||
app* mk_last_index(expr* a, expr* b) const { expr* es[2] = { a, b}; return m.mk_app(m_fid, OP_SEQ_LAST_INDEX, 2, es); }
|
||||
app* mk_unit(expr* u) const { return m.mk_app(m_fid, OP_SEQ_UNIT, 1, &u); }
|
||||
app* mk_char(zstring const& s, unsigned idx) const;
|
||||
app* mk_itos(expr* i) const { return m.mk_app(m_fid, OP_STRING_ITOS, 1, &i); }
|
||||
|
@ -285,6 +288,7 @@ public:
|
|||
bool is_nth(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_NTH); }
|
||||
bool is_nth(expr const* n, expr*& s, unsigned& idx) const;
|
||||
bool is_index(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_INDEX); }
|
||||
bool is_last_index(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_LAST_INDEX); }
|
||||
bool is_replace(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_REPLACE); }
|
||||
bool is_prefix(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_PREFIX); }
|
||||
bool is_suffix(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_SUFFIX); }
|
||||
|
@ -311,6 +315,7 @@ public:
|
|||
MATCH_BINARY(is_nth);
|
||||
MATCH_BINARY(is_index);
|
||||
MATCH_TERNARY(is_index);
|
||||
MATCH_BINARY(is_last_index);
|
||||
MATCH_TERNARY(is_replace);
|
||||
MATCH_BINARY(is_prefix);
|
||||
MATCH_BINARY(is_suffix);
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue