3
0
Fork 0
mirror of https://github.com/Z3Prover/z3 synced 2025-04-22 16:45:31 +00:00
This commit is contained in:
Christoph M. Wintersteiger 2015-12-07 13:14:00 +00:00
commit cfc25b5094
18 changed files with 1505 additions and 219 deletions

View file

@ -0,0 +1,7 @@
prefix=@PREFIX@
assemblies_dir=${prefix}/lib/mono/@GAC_PKG_NAME@
Name: @GAC_PKG_NAME@
Description: .NET bindings for The Microsoft Z3 SMT solver
Version: @VERSION@
Libs: -r:${assemblies_dir}/Microsoft.Z3.dll

Binary file not shown.

View file

@ -8189,7 +8189,7 @@ def is_fprm_value(a):
class FPNumRef(FPRef):
def isNaN(self):
return self.decl().kind() == Z3_OP_FPA_NAN
def isInf(self):
return self.decl().kind() == Z3_OP_FPA_PLUS_INF or self.decl().kind() == Z3_OP_FPA_MINUS_INF
@ -8201,7 +8201,7 @@ class FPNumRef(FPRef):
return (self.num_args() == 0 and (k == Z3_OP_FPA_MINUS_INF or k == Z3_OP_FPA_MINUS_ZERO)) or (self.sign() == True)
"""
The sign of the numeral
The sign of the numeral.
>>> x = FPNumRef(+1.0, FPSort(8, 24))
>>> x.sign()
@ -8215,30 +8215,32 @@ class FPNumRef(FPRef):
if Z3_fpa_get_numeral_sign(self.ctx.ref(), self.as_ast(), byref(l)) == False:
raise Z3Exception("error retrieving the sign of a numeral.")
return l.value != 0
"""
The significand of the numeral
The significand of the numeral.
>>> x = FPNumRef(2.5, FPSort(8, 24))
>>> x.significand()
1.25
"""
def significand(self):
return Z3_fpa_get_numeral_significand_string(self.ctx.ref(), self.as_ast())
"""
The exponent of the numeral
The exponent of the numeral.
>>> x = FPNumRef(2.5, FPSort(8, 24))
>>>
>>> x.exponent()
1
"""
def exponent(self):
return Z3_fpa_get_numeral_exponent_string(self.ctx.ref(), self.as_ast())
"""
The exponent of the numeral as a long
The exponent of the numeral as a long.
>>> x = FPNumRef(2.5, FPSort(8, 24))
>>> x.exponent_as_long()
1
"""
def exponent_as_long(self):
@ -8246,11 +8248,12 @@ class FPNumRef(FPRef):
if not Z3_fpa_get_numeral_exponent_int64(self.ctx.ref(), self.as_ast(), ptr):
raise Z3Exception("error retrieving the exponent of a numeral.")
return ptr[0]
"""
The string representation of the numeral
The string representation of the numeral.
>>> x = FPNumRef(20, FPSort(8, 24))
>>> x.as_string()
1.25*(2**4)
"""
def as_string(self):
@ -8378,7 +8381,7 @@ def FPVal(sig, exp=None, fps=None, ctx=None):
val = val + 'p'
val = val + _to_int_str(exp)
return FPNumRef(Z3_mk_numeral(ctx.ref(), val, fps.ast), ctx)
def FP(name, fpsort, ctx=None):
"""Return a floating-point constant named `name`.
`fpsort` is the floating-point sort.
@ -8640,47 +8643,47 @@ def fpIsNaN(a):
return FPRef(Z3_mk_fpa_is_nan(a.ctx_ref(), a.as_ast()), a.ctx)
def fpIsInfinite(a):
"""Create a Z3 floating-point isNaN expression.
"""Create a Z3 floating-point isInfinite expression.
"""
if __debug__:
_z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions")
return FPRef(Z3_mk_fpa_is_infinite(a.ctx_ref(), a.as_ast()), a.ctx)
def fpIsZero(a):
"""Create a Z3 floating-point isNaN expression.
"""Create a Z3 floating-point isZero expression.
"""
if __debug__:
_z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions")
return FPRef(Z3_mk_fpa_is_zero(a.ctx_ref(), a.as_ast()), a.ctx)
def fpIsNormal(a):
"""Create a Z3 floating-point isNaN expression.
"""Create a Z3 floating-point isNormal expression.
"""
if __debug__:
_z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions")
return FPRef(Z3_mk_fpa_is_normal(a.ctx_ref(), a.as_ast()), a.ctx)
def fpIsSubnormal(a):
"""Create a Z3 floating-point isNaN expression.
"""Create a Z3 floating-point isSubnormal expression.
"""
if __debug__:
_z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions")
return FPRef(Z3_mk_fpa_is_subnormal(a.ctx_ref(), a.as_ast()), a.ctx)
def fpIsNegative(a):
"""Create a Z3 floating-point isNaN expression.
"""Create a Z3 floating-point isNegative expression.
"""
if __debug__:
_z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions")
return FPRef(Z3_mk_fpa_is_negative(a.ctx_ref(), a.as_ast()), a.ctx)
def fpIsPositive(a):
"""Create a Z3 floating-point isNaN expression.
"""Create a Z3 floating-point isPositive expression.
"""
if __debug__:
_z3_assert(is_fp(a), "Argument must be Z3 floating-point expressions")
return FPRef(Z3_mk_fpa_is_positive(a.ctx_ref(), a.as_ast()), a.ctx)
def _check_fp_args(a, b):
if __debug__:
_z3_assert(is_fp(a) or is_fp(b), "At least one of the arguments must be a Z3 floating-point expression")

View file

@ -2013,6 +2013,7 @@ public:
app * mk_distinct_expanded(unsigned num_args, expr * const * args);
app * mk_true() { return m_true; }
app * mk_false() { return m_false; }
app * mk_bool_val(bool b) { return b?m_true:m_false; }
app * mk_interp(expr * arg) { return mk_app(m_basic_family_id, OP_INTERP, arg); }

View file

@ -363,6 +363,23 @@ format * smt2_pp_environment::pp_arith_literal(app * t, bool decimal, unsigned d
}
}
format * smt2_pp_environment::pp_string_literal(app * t) {
std::string s;
VERIFY (get_sutil().str.is_string(t, s));
std::ostringstream buffer;
buffer << "\"";
for (unsigned i = 0; i < s.length(); ++i) {
if (s[i] == '\"') {
buffer << "\"\"";
}
else {
buffer << s[i];
}
}
buffer << "\"";
return mk_string(get_manager(), buffer.str().c_str());
}
format * smt2_pp_environment::pp_datalog_literal(app * t) {
uint64 v;
VERIFY (get_dlutil().is_numeral(t, v));
@ -407,6 +424,11 @@ format_ns::format * smt2_pp_environment::pp_sort(sort * s) {
fs.push_back(mk_unsigned(m, sbits));
return mk_seq1(m, fs.begin(), fs.end(), f2f(), "_");
}
if ((get_sutil().is_seq(s) || get_sutil().is_re(s)) && !get_sutil().is_string(s)) {
ptr_buffer<format> fs;
fs.push_back(pp_sort(to_sort(s->get_parameter(0).get_ast())));
return mk_seq1(m, fs.begin(), fs.end(), f2f(), get_sutil().is_seq(s)?"Seq":"Re");
}
return format_ns::mk_string(get_manager(), s->get_name().str().c_str());
}
@ -578,6 +600,9 @@ class smt2_printer {
if (m_env.get_autil().is_numeral(c) || m_env.get_autil().is_irrational_algebraic_numeral(c)) {
f = m_env.pp_arith_literal(c, m_pp_decimal, m_pp_decimal_precision);
}
else if (m_env.get_sutil().str.is_string(c)) {
f = m_env.pp_string_literal(c);
}
else if (m_env.get_bvutil().is_numeral(c)) {
f = m_env.pp_bv_literal(c, m_pp_bv_lits, m_pp_bv_neg);
}

View file

@ -29,6 +29,7 @@ Revision History:
#include"array_decl_plugin.h"
#include"fpa_decl_plugin.h"
#include"dl_decl_plugin.h"
#include"seq_decl_plugin.h"
#include"smt2_util.h"
class smt2_pp_environment {
@ -47,6 +48,7 @@ public:
virtual bv_util & get_bvutil() = 0;
virtual array_util & get_arutil() = 0;
virtual fpa_util & get_futil() = 0;
virtual seq_util & get_sutil() = 0;
virtual datalog::dl_decl_util& get_dlutil() = 0;
virtual bool uses(symbol const & s) const = 0;
virtual format_ns::format * pp_fdecl(func_decl * f, unsigned & len);
@ -54,6 +56,7 @@ public:
virtual format_ns::format * pp_arith_literal(app * t, bool decimal, unsigned prec);
virtual format_ns::format * pp_float_literal(app * t, bool use_bv_lits, bool use_float_real_lits);
virtual format_ns::format * pp_datalog_literal(app * t);
virtual format_ns::format * pp_string_literal(app * t);
virtual format_ns::format * pp_sort(sort * s);
virtual format_ns::format * pp_fdecl_ref(func_decl * f);
format_ns::format * pp_fdecl_name(symbol const & fname, unsigned & len) const;
@ -70,12 +73,14 @@ class smt2_pp_environment_dbg : public smt2_pp_environment {
bv_util m_bvutil;
array_util m_arutil;
fpa_util m_futil;
seq_util m_sutil;
datalog::dl_decl_util m_dlutil;
public:
smt2_pp_environment_dbg(ast_manager & m):m_manager(m), m_autil(m), m_bvutil(m), m_arutil(m), m_futil(m), m_dlutil(m) {}
smt2_pp_environment_dbg(ast_manager & m):m_manager(m), m_autil(m), m_bvutil(m), m_arutil(m), m_futil(m), m_sutil(m), m_dlutil(m) {}
virtual ast_manager & get_manager() const { return m_manager; }
virtual arith_util & get_autil() { return m_autil; }
virtual bv_util & get_bvutil() { return m_bvutil; }
virtual seq_util & get_sutil() { return m_sutil; }
virtual array_util & get_arutil() { return m_arutil; }
virtual fpa_util & get_futil() { return m_futil; }
virtual datalog::dl_decl_util& get_dlutil() { return m_dlutil; }

View file

@ -0,0 +1,341 @@
/*++
Copyright (c) 2015 Microsoft Corporation
Module Name:
seq_rewriter.cpp
Abstract:
Basic rewriting rules for sequences constraints.
Author:
Nikolaj Bjorner (nbjorner) 2015-12-5
Notes:
--*/
#include"seq_rewriter.h"
#include"arith_decl_plugin.h"
#include"ast_pp.h"
br_status seq_rewriter::mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result) {
SASSERT(f->get_family_id() == get_fid());
switch(f->get_decl_kind()) {
case OP_SEQ_UNIT:
case OP_SEQ_EMPTY:
case OP_RE_PLUS:
case OP_RE_STAR:
case OP_RE_OPTION:
case OP_RE_RANGE:
case OP_RE_CONCAT:
case OP_RE_UNION:
case OP_RE_INTERSECT:
case OP_RE_LOOP:
case OP_RE_EMPTY_SET:
case OP_RE_FULL_SET:
case OP_RE_EMPTY_SEQ:
case OP_RE_OF_PRED:
return BR_FAILED;
// string specific operators.
case OP_STRING_CONST:
return BR_FAILED;
case OP_SEQ_CONCAT:
SASSERT(num_args == 2);
return mk_seq_concat(args[0], args[1], result);
case OP_SEQ_LENGTH:
SASSERT(num_args == 1);
return mk_str_length(args[0], result);
case OP_SEQ_EXTRACT:
SASSERT(num_args == 3);
return mk_str_substr(args[0], args[1], args[2], result);
case OP_SEQ_CONTAINS:
SASSERT(num_args == 2);
return mk_str_strctn(args[0], args[1], result);
case OP_SEQ_AT:
SASSERT(num_args == 2);
return mk_str_at(args[0], args[1], result);
case OP_STRING_STRIDOF:
SASSERT(num_args == 3);
return mk_str_stridof(args[0], args[1], args[2], result);
case OP_STRING_STRREPL:
SASSERT(num_args == 3);
return mk_str_strrepl(args[0], args[1], args[2], result);
case OP_SEQ_PREFIX:
SASSERT(num_args == 2);
return mk_seq_prefix(args[0], args[1], result);
case OP_SEQ_SUFFIX:
SASSERT(num_args == 2);
return mk_seq_suffix(args[0], args[1], result);
case OP_STRING_ITOS:
SASSERT(num_args == 1);
return mk_str_itos(args[0], result);
case OP_STRING_STOI:
SASSERT(num_args == 1);
return mk_str_stoi(args[0], result);
case OP_SEQ_TO_RE:
case OP_SEQ_IN_RE:
case OP_REGEXP_LOOP:
return BR_FAILED;
case _OP_STRING_CONCAT:
case _OP_STRING_PREFIX:
case _OP_STRING_SUFFIX:
case _OP_STRING_STRCTN:
case _OP_STRING_LENGTH:
case _OP_STRING_CHARAT:
case _OP_STRING_IN_REGEXP:
case _OP_STRING_TO_REGEXP:
case _OP_STRING_SUBSTR:
UNREACHABLE();
}
return BR_FAILED;
}
/*
string + string = string
a + (b + c) = (a + b) + c
a + "" = a
"" + a = a
(a + string) + string = a + string
*/
br_status seq_rewriter::mk_seq_concat(expr* a, expr* b, expr_ref& result) {
std::string s1, s2;
expr* c, *d;
bool isc1 = m_util.str.is_string(a, s1);
bool isc2 = m_util.str.is_string(b, s2);
if (isc1 && isc2) {
result = m_util.str.mk_string(s1 + s2);
return BR_DONE;
}
if (m_util.str.is_concat(b, c, d)) {
result = m_util.str.mk_concat(m_util.str.mk_concat(a, c), d);
return BR_REWRITE2;
}
if (m_util.str.is_empty(a)) {
result = b;
return BR_DONE;
}
if (m_util.str.is_empty(b)) {
result = a;
return BR_DONE;
}
if (m_util.str.is_concat(a, c, d) &&
m_util.str.is_string(d, s1) && isc2) {
result = m_util.str.mk_concat(c, m_util.str.mk_string(s1 + s2));
return BR_DONE;
}
return BR_FAILED;
}
br_status seq_rewriter::mk_str_length(expr* a, expr_ref& result) {
std::string b;
m_es.reset();
m_util.str.get_concat(a, m_es);
size_t len = 0;
size_t j = 0;
for (unsigned i = 0; i < m_es.size(); ++i) {
if (m_util.str.is_string(m_es[i], b)) {
len += b.length();
}
else {
m_es[j] = m_es[i];
++j;
}
}
if (j == 0) {
result = m_autil.mk_numeral(rational(len, rational::ui64()), true);
return BR_DONE;
}
if (j != m_es.size()) {
expr_ref_vector es(m());
for (unsigned i = 0; i < j; ++i) {
es.push_back(m_util.str.mk_length(m_es[i]));
}
if (len != 0) {
es.push_back(m_autil.mk_numeral(rational(len, rational::ui64()), true));
}
result = m_autil.mk_add(es.size(), es.c_ptr());
return BR_DONE;
}
return BR_FAILED;
}
br_status seq_rewriter::mk_str_substr(expr* a, expr* b, expr* c, expr_ref& result) {
std::string s;
rational pos, len;
if (m_util.str.is_string(a, s) && m_autil.is_numeral(b, pos) && m_autil.is_numeral(c, len) &&
pos.is_unsigned() && len.is_unsigned() && pos.get_unsigned() <= s.length()) {
unsigned _pos = pos.get_unsigned();
unsigned _len = len.get_unsigned();
result = m_util.str.mk_string(s.substr(_pos, _len));
return BR_DONE;
}
return BR_FAILED;
}
br_status seq_rewriter::mk_str_strctn(expr* a, expr* b, expr_ref& result) {
std::string c, d;
if (m_util.str.is_string(a, c) && m_util.str.is_string(b, d)) {
result = m().mk_bool_val(0 != strstr(d.c_str(), c.c_str()));
return BR_DONE;
}
return BR_FAILED;
}
br_status seq_rewriter::mk_str_at(expr* a, expr* b, expr_ref& result) {
std::string c;
rational r;
if (m_util.str.is_string(a, c) && m_autil.is_numeral(b, r) && r.is_unsigned()) {
unsigned j = r.get_unsigned();
if (j < c.length()) {
char ch = c[j];
c[0] = ch;
c[1] = 0;
result = m_util.str.mk_string(c);
return BR_DONE;
}
}
return BR_FAILED;
}
br_status seq_rewriter::mk_str_stridof(expr* a, expr* b, expr* c, expr_ref& result) {
std::string s1, s2;
rational r;
bool isc1 = m_util.str.is_string(a, s1);
bool isc2 = m_util.str.is_string(b, s2);
if (isc1 && isc2 && m_autil.is_numeral(c, r) && r.is_unsigned()) {
for (unsigned i = r.get_unsigned(); i < s1.length(); ++i) {
if (strncmp(s1.c_str() + i, s2.c_str(), s2.length()) == 0) {
result = m_autil.mk_numeral(rational(i) - r, true);
return BR_DONE;
}
}
result = m_autil.mk_numeral(rational(-1), true);
return BR_DONE;
}
if (m_autil.is_numeral(c, r) && r.is_neg()) {
result = m_autil.mk_numeral(rational(-1), true);
return BR_DONE;
}
if (m_util.str.is_empty(b)) {
result = c;
return BR_DONE;
}
// Enhancement: walk segments of a, determine which segments must overlap, must not overlap, may overlap.
return BR_FAILED;
}
br_status seq_rewriter::mk_str_strrepl(expr* a, expr* b, expr* c, expr_ref& result) {
std::string s1, s2, s3;
if (m_util.str.is_string(a, s1) && m_util.str.is_string(b, s2) &&
m_util.str.is_string(c, s3)) {
std::ostringstream buffer;
for (size_t i = 0; i < s1.length(); ) {
if (strncmp(s1.c_str() + i, s2.c_str(), s2.length()) == 0) {
buffer << s3;
i += s2.length();
}
else {
buffer << s1[i];
++i;
}
}
result = m_util.str.mk_string(buffer.str());
return BR_DONE;
}
if (b == c) {
result = a;
return BR_DONE;
}
return BR_FAILED;
}
br_status seq_rewriter::mk_seq_prefix(expr* a, expr* b, expr_ref& result) {
std::string s1, s2;
bool isc1 = m_util.str.is_string(a, s1);
bool isc2 = m_util.str.is_string(b, s2);
if (isc1 && isc2) {
bool prefix = s1.length() <= s2.length();
for (unsigned i = 0; i < s1.length() && prefix; ++i) {
prefix = s1[i] == s2[i];
}
result = m().mk_bool_val(prefix);
return BR_DONE;
}
if (m_util.str.is_empty(a)) {
result = m().mk_true();
return BR_DONE;
}
return BR_FAILED;
}
br_status seq_rewriter::mk_seq_suffix(expr* a, expr* b, expr_ref& result) {
std::string s1, s2;
bool isc1 = m_util.str.is_string(a, s1);
if (isc1 && m_util.str.is_string(b, s2)) {
bool suffix = s1.length() <= s2.length();
for (unsigned i = 0; i < s1.length() && suffix; ++i) {
suffix = s1[s1.length() - i - 1] == s2[s2.length() - i - 1];
}
result = m().mk_bool_val(suffix);
return BR_DONE;
}
if (m_util.str.is_empty(a)) {
result = m().mk_true();
return BR_DONE;
}
return BR_FAILED;
}
br_status seq_rewriter::mk_str_itos(expr* a, expr_ref& result) {
rational r;
if (m_autil.is_numeral(a, r)) {
result = m_util.str.mk_string(r.to_string());
return BR_DONE;
}
return BR_FAILED;
}
br_status seq_rewriter::mk_str_stoi(expr* a, expr_ref& result) {
std::string s;
if (m_util.str.is_string(a, s)) {
for (unsigned i = 0; i < s.length(); ++i) {
if (s[i] == '-') { if (i != 0) return BR_FAILED; }
else if ('0' <= s[i] && s[i] <= '9') continue;
return BR_FAILED;
}
rational r(s.c_str());
result = m_autil.mk_numeral(r, true);
return BR_DONE;
}
return BR_FAILED;
}
br_status seq_rewriter::mk_str_in_regexp(expr* a, expr* b, expr_ref& result) {
return BR_FAILED;
}
br_status seq_rewriter::mk_str_to_regexp(expr* a, expr_ref& result) {
return BR_FAILED;
}
br_status seq_rewriter::mk_re_concat(expr* a, expr* b, expr_ref& result) {
return BR_FAILED;
}
br_status seq_rewriter::mk_re_union(expr* a, expr* b, expr_ref& result) {
return BR_FAILED;
}
br_status seq_rewriter::mk_re_star(expr* a, expr_ref& result) {
return BR_FAILED;
}
br_status seq_rewriter::mk_re_plus(expr* a, expr_ref& result) {
return BR_FAILED;
}
br_status seq_rewriter::mk_re_opt(expr* a, expr_ref& result) {
return BR_FAILED;
}

View file

@ -0,0 +1,70 @@
/*++
Copyright (c) 2015 Microsoft Corporation
Module Name:
seq_rewriter.h
Abstract:
Basic rewriting rules for sequences constraints.
Author:
Nikolaj Bjorner (nbjorner) 2015-12-5
Notes:
--*/
#ifndef SEQ_REWRITER_H_
#define SEQ_REWRITER_H_
#include"seq_decl_plugin.h"
#include"arith_decl_plugin.h"
#include"rewriter_types.h"
#include"params.h"
#include"lbool.h"
/**
\brief Cheap rewrite rules for seq constraints
*/
class seq_rewriter {
seq_util m_util;
arith_util m_autil;
ptr_vector<expr> m_es;
br_status mk_seq_concat(expr* a, expr* b, expr_ref& result);
br_status mk_str_length(expr* a, expr_ref& result);
br_status mk_str_substr(expr* a, expr* b, expr* c, expr_ref& result);
br_status mk_str_strctn(expr* a, expr* b, expr_ref& result);
br_status mk_str_at(expr* a, expr* b, expr_ref& result);
br_status mk_str_stridof(expr* a, expr* b, expr* c, expr_ref& result);
br_status mk_str_strrepl(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);
br_status mk_str_itos(expr* a, expr_ref& result);
br_status mk_str_stoi(expr* a, expr_ref& result);
br_status mk_str_in_regexp(expr* a, expr* b, expr_ref& result);
br_status mk_str_to_regexp(expr* a, expr_ref& result);
br_status mk_re_concat(expr* a, expr* b, expr_ref& result);
br_status mk_re_union(expr* a, expr* b, expr_ref& result);
br_status mk_re_star(expr* a, expr_ref& result);
br_status mk_re_plus(expr* a, expr_ref& result);
br_status mk_re_opt(expr* a, expr_ref& result);
public:
seq_rewriter(ast_manager & m, params_ref const & p = params_ref()):
m_util(m), m_autil(m) {
}
ast_manager & m() const { return m_util.get_manager(); }
family_id get_fid() const { return m_util.get_family_id(); }
void updt_params(params_ref const & p) {}
static void get_param_descrs(param_descrs & r) {}
br_status mk_app_core(func_decl * f, unsigned num_args, expr * const * args, expr_ref & result);
};
#endif

View file

@ -26,6 +26,7 @@ Notes:
#include"fpa_rewriter.h"
#include"dl_rewriter.h"
#include"pb_rewriter.h"
#include"seq_rewriter.h"
#include"rewriter_def.h"
#include"expr_substitution.h"
#include"ast_smt2_pp.h"
@ -43,6 +44,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
fpa_rewriter m_f_rw;
dl_rewriter m_dl_rw;
pb_rewriter m_pb_rw;
seq_rewriter m_seq_rw;
arith_util m_a_util;
bv_util m_bv_util;
unsigned long long m_max_memory; // in bytes
@ -76,6 +78,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
m_bv_rw.updt_params(p);
m_ar_rw.updt_params(p);
m_f_rw.updt_params(p);
m_seq_rw.updt_params(p);
updt_local_params(p);
}
@ -200,6 +203,8 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
return m_dl_rw.mk_app_core(f, num, args, result);
if (fid == m_pb_rw.get_fid())
return m_pb_rw.mk_app_core(f, num, args, result);
if (fid == m_seq_rw.get_fid())
return m_seq_rw.mk_app_core(f, num, args, result);
return BR_FAILED;
}
@ -650,6 +655,7 @@ struct th_rewriter_cfg : public default_rewriter_cfg {
m_f_rw(m, p),
m_dl_rw(m),
m_pb_rw(m),
m_seq_rw(m),
m_a_util(m),
m_bv_util(m),
m_used_dependencies(m),

View file

@ -19,13 +19,19 @@ Revision History:
#include "seq_decl_plugin.h"
#include "arith_decl_plugin.h"
#include "array_decl_plugin.h"
#include "ast_pp.h"
#include <sstream>
seq_decl_plugin::seq_decl_plugin(): m_init(false) {}
seq_decl_plugin::seq_decl_plugin(): m_init(false),
m_stringc_sym("String"),
m_string(0),
m_char(0) {}
void seq_decl_plugin::finalize() {
for (unsigned i = 0; i < m_sigs.size(); ++i)
dealloc(m_sigs[i]);
m_manager->dec_ref(m_string);
m_manager->dec_ref(m_char);
}
bool seq_decl_plugin::is_sort_param(sort* s, unsigned& idx) {
@ -35,33 +41,70 @@ bool seq_decl_plugin::is_sort_param(sort* s, unsigned& idx) {
}
bool seq_decl_plugin::match(ptr_vector<sort>& binding, sort* s, sort* sP) {
ast_manager& m = *m_manager;
if (s == sP) return true;
unsigned i;
if (is_sort_param(sP, i)) {
if (binding.size() <= i) binding.resize(i+1);
if (binding[i] && (binding[i] != s)) return false;
TRACE("seq", tout << "setting binding @ " << i << " to " << mk_pp(s, m) << "\n";);
binding[i] = s;
return true;
}
if (s->get_family_id() == sP->get_family_id() &&
s->get_decl_kind() == sP->get_decl_kind() &&
s->get_name() == sP->get_name()) {
SASSERT(s->get_num_parameters() == sP->get_num_parameters());
for (unsigned i = 0; i < s->get_num_parameters(); ++i) {
parameter const& p = s->get_parameter(i);
if (p.is_ast() && is_sort(p.get_ast())) {
parameter const& p2 = sP->get_parameter(i);
if (!match(binding, to_sort(p.get_ast()), to_sort(p2.get_ast()))) return false;
}
s->get_num_parameters() == sP->get_num_parameters()) {
for (unsigned i = 0; i < s->get_num_parameters(); ++i) {
parameter const& p = s->get_parameter(i);
if (p.is_ast() && is_sort(p.get_ast())) {
parameter const& p2 = sP->get_parameter(i);
if (!match(binding, to_sort(p.get_ast()), to_sort(p2.get_ast()))) return false;
}
}
return true;
}
else {
TRACE("seq", tout << "Could not match " << mk_pp(s, m) << " and " << mk_pp(sP, m) << "\n";);
return false;
}
}
/*
\brief match left associative operator.
*/
void seq_decl_plugin::match_left_assoc(psig& sig, unsigned dsz, sort *const* dom, sort* range, sort_ref& range_out) {
ptr_vector<sort> binding;
ast_manager& m = *m_manager;
TRACE("seq",
tout << sig.m_name << ": ";
for (unsigned i = 0; i < dsz; ++i) tout << mk_pp(dom[i], m) << " ";
if (range) tout << " range: " << mk_pp(range, m);
tout << "\n";);
if (dsz == 0) {
std::ostringstream strm;
strm << "Unexpected number of arguments to '" << sig.m_name << "' ";
strm << "at least one argument expected " << dsz << " given";
m.raise_exception(strm.str().c_str());
}
bool is_match = true;
for (unsigned i = 0; is_match && i < dsz; ++i) {
is_match = match(binding, dom[i], sig.m_dom[0].get());
}
if (range && is_match) {
is_match = match(binding, range, sig.m_range);
}
if (!is_match) {
std::ostringstream strm;
strm << "Sort of function '" << sig.m_name << "' ";
strm << "does not match the declared type";
m.raise_exception(strm.str().c_str());
}
range_out = apply_binding(binding, sig.m_range);
TRACE("seq", tout << mk_pp(range_out, m) << "\n";);
}
void seq_decl_plugin::match(psig& sig, unsigned dsz, sort *const* dom, sort* range, sort_ref& range_out) {
ptr_vector<sort> binding;
ast_manager& m = *m_manager;
@ -118,54 +161,78 @@ void seq_decl_plugin::init() {
ast_manager& m = *m_manager;
m_init = true;
sort* A = m.mk_uninterpreted_sort(symbol((unsigned)0));
sort* B = m.mk_uninterpreted_sort(symbol((unsigned)1));
sort* strT = m_string;
parameter paramA(A);
parameter paramS(strT);
sort* seqA = m.mk_sort(m_family_id, SEQ_SORT, 1, &paramA);
sort* reA = m.mk_sort(m_family_id, RE_SORT, 1, &paramA);
sort* seqAseqA[2] = { seqA, seqA };
sort* seqAA[2] = { seqA, A };
sort* seqAB[2] = { seqA, B };
sort* seqAreA[2] = { seqA, reA };
sort* AseqA[2] = { A, seqA };
sort* reAreA[2] = { reA, reA };
sort* AA[2] = { A, A };
sort* seqABB[3] = { seqA, B, B };
sort* reT = m.mk_sort(m_family_id, RE_SORT, 1, &paramS);
sort* boolT = m.mk_bool_sort();
sort* intT = arith_util(m).mk_int();
sort* predA = array_util(m).mk_array_sort(A, boolT);
sort* u16T = 0;
sort* u32T = 0;
sort* seqAseqA[2] = { seqA, seqA };
sort* seqAreA[2] = { seqA, reA };
sort* reAreA[2] = { reA, reA };
sort* AA[2] = { A, A };
sort* seqAint2T[3] = { seqA, intT, intT };
sort* str2T[2] = { strT, strT };
sort* str3T[3] = { strT, strT, strT };
sort* strTint2T[3] = { strT, intT, intT };
sort* re2T[2] = { reT, reT };
sort* strTreT[2] = { strT, reT };
sort* str2TintT[3] = { strT, strT, intT };
sort* seqAintT[2] = { seqA, intT };
m_sigs.resize(LAST_SEQ_OP);
// TBD: have (par ..) construct and load parameterized signature from premable.
m_sigs[OP_SEQ_UNIT] = alloc(psig, m, "seq-unit", 1, 1, &A, seqA);
m_sigs[OP_SEQ_EMPTY] = alloc(psig, m, "seq-empty", 1, 0, 0, seqA);
m_sigs[OP_SEQ_CONCAT] = alloc(psig, m, "seq-concat", 1, 2, seqAseqA, seqA);
m_sigs[OP_SEQ_CONS] = alloc(psig, m, "seq-cons", 1, 2, AseqA, seqA);
m_sigs[OP_SEQ_REV_CONS] = alloc(psig, m, "seq-rev-cons", 1, 2, seqAA, seqA);
m_sigs[OP_SEQ_HEAD] = alloc(psig, m, "seq-head", 1, 1, &seqA, A);
m_sigs[OP_SEQ_TAIL] = alloc(psig, m, "seq-tail", 1, 1, &seqA, seqA);
m_sigs[OP_SEQ_LAST] = alloc(psig, m, "seq-last", 1, 1, &seqA, A);
m_sigs[OP_SEQ_FIRST] = alloc(psig, m, "seq-first", 1, 1, &seqA, seqA);
m_sigs[OP_SEQ_PREFIX_OF] = alloc(psig, m, "seq-prefix-of", 1, 2, seqAseqA, boolT);
m_sigs[OP_SEQ_SUFFIX_OF] = alloc(psig, m, "seq-suffix-of", 1, 2, seqAseqA, boolT);
m_sigs[OP_SEQ_SUBSEQ_OF] = alloc(psig, m, "seq-subseq-of", 1, 2, seqAseqA, boolT);
m_sigs[OP_SEQ_EXTRACT] = alloc(psig, m, "seq-extract", 2, 3, seqABB, seqA);
m_sigs[OP_SEQ_NTH] = alloc(psig, m, "seq-nth", 2, 2, seqAB, A);
m_sigs[OP_SEQ_UNIT] = alloc(psig, m, "seq.unit", 1, 1, &A, seqA);
m_sigs[OP_SEQ_EMPTY] = alloc(psig, m, "seq.empty", 1, 0, 0, seqA);
m_sigs[OP_SEQ_CONCAT] = alloc(psig, m, "seq.++", 1, 2, seqAseqA, seqA);
m_sigs[OP_SEQ_PREFIX] = alloc(psig, m, "seq.prefixof", 1, 2, seqAseqA, boolT);
m_sigs[OP_SEQ_SUFFIX] = alloc(psig, m, "seq.suffixof", 1, 2, seqAseqA, boolT);
m_sigs[OP_SEQ_CONTAINS] = alloc(psig, m, "seq.contains", 1, 2, seqAseqA, boolT);
m_sigs[OP_SEQ_EXTRACT] = alloc(psig, m, "seq.extract", 1, 3, seqAint2T, seqA);
m_sigs[OP_SEQ_AT] = alloc(psig, m, "seq.at", 1, 2, seqAintT, seqA);
m_sigs[OP_SEQ_LENGTH] = alloc(psig, m, "seq-length", 1, 1, &seqA, intT);
m_sigs[OP_RE_PLUS] = alloc(psig, m, "re-plus", 1, 1, &reA, reA);
m_sigs[OP_RE_STAR] = alloc(psig, m, "re-star", 1, 1, &reA, reA);
m_sigs[OP_RE_OPTION] = alloc(psig, m, "re-option", 1, 1, &reA, reA);
m_sigs[OP_RE_RANGE] = alloc(psig, m, "re-range", 1, 2, AA, reA);
m_sigs[OP_RE_CONCAT] = alloc(psig, m, "re-concat", 1, 2, reAreA, reA);
m_sigs[OP_RE_UNION] = alloc(psig, m, "re-union", 1, 2, reAreA, reA);
m_sigs[OP_RE_INTERSECT] = alloc(psig, m, "re-intersect", 1, 2, reAreA, reA);
m_sigs[OP_RE_DIFFERENCE] = alloc(psig, m, "re-difference", 1, 2, reAreA, reA);
m_sigs[OP_RE_COMPLEMENT] = alloc(psig, m, "re-complement", 1, 1, &reA, reA);
m_sigs[OP_RE_LOOP] = alloc(psig, m, "re-loop", 1, 1, &reA, reA);
m_sigs[OP_RE_PLUS] = alloc(psig, m, "re.+", 1, 1, &reA, reA);
m_sigs[OP_RE_STAR] = alloc(psig, m, "re.*", 1, 1, &reA, reA);
m_sigs[OP_RE_OPTION] = alloc(psig, m, "re.opt", 1, 1, &reA, reA);
m_sigs[OP_RE_RANGE] = alloc(psig, m, "re.range", 1, 2, seqAseqA, reA);
m_sigs[OP_RE_CONCAT] = alloc(psig, m, "re.++", 1, 2, reAreA, reA);
m_sigs[OP_RE_UNION] = alloc(psig, m, "re.union", 1, 2, reAreA, reA);
m_sigs[OP_RE_INTERSECT] = alloc(psig, m, "re.inter", 1, 2, reAreA, reA);
m_sigs[OP_RE_LOOP] = alloc(psig, m, "re-loop", 1, 1, &reA, reA);
m_sigs[OP_RE_EMPTY_SEQ] = alloc(psig, m, "re-empty-seq", 1, 0, 0, reA);
m_sigs[OP_RE_EMPTY_SET] = alloc(psig, m, "re-empty-set", 1, 0, 0, reA);
m_sigs[OP_RE_FULL_SET] = alloc(psig, m, "re-full-set", 1, 0, 0, reA);
m_sigs[OP_RE_OF_SEQ] = alloc(psig, m, "re-of-seq", 1, 1, &seqA, reA);
m_sigs[OP_RE_OF_PRED] = alloc(psig, m, "re-of-pred", 1, 1, &predA, reA);
m_sigs[OP_RE_MEMBER] = alloc(psig, m, "re-member", 1, 2, seqAreA, boolT);
m_sigs[OP_RE_EMPTY_SET] = alloc(psig, m, "re-empty-set", 1, 0, 0, reA);
m_sigs[OP_RE_FULL_SET] = alloc(psig, m, "re-full-set", 1, 0, 0, reA);
m_sigs[OP_SEQ_TO_RE] = alloc(psig, m, "seq.to.re", 1, 1, &seqA, reA);
m_sigs[OP_RE_OF_PRED] = alloc(psig, m, "re-of-pred", 1, 1, &predA, reA);
m_sigs[OP_SEQ_IN_RE] = alloc(psig, m, "seq.in.re", 1, 2, seqAreA, boolT);
m_sigs[OP_STRING_CONST] = 0;
m_sigs[OP_STRING_STRIDOF] = alloc(psig, m, "str.indexof", 0, 3, str2TintT, intT);
m_sigs[OP_STRING_STRREPL] = alloc(psig, m, "str.replace", 0, 3, str3T, strT);
m_sigs[OP_STRING_ITOS] = alloc(psig, m, "int.to.str", 0, 1, &intT, strT);
m_sigs[OP_STRING_STOI] = alloc(psig, m, "str.to.int", 0, 1, &strT, intT);
m_sigs[OP_REGEXP_LOOP] = alloc(psig, m, "re.loop", 0, 2, strTint2T, reT); // maybe 3 arguments.
m_sigs[_OP_STRING_CONCAT] = alloc(psig, m, "str.++", 1, 2, str2T, strT);
m_sigs[_OP_STRING_LENGTH] = alloc(psig, m, "str.len", 0, 1, &strT, intT);
m_sigs[_OP_STRING_STRCTN] = alloc(psig, m, "str.contains", 0, 2, str2T, boolT);
m_sigs[_OP_STRING_CHARAT] = alloc(psig, m, "str.at", 0, 2, strTint2T, strT);
m_sigs[_OP_STRING_PREFIX] = alloc(psig, m, "str.prefixof", 0, 2, str2T, boolT);
m_sigs[_OP_STRING_SUFFIX] = alloc(psig, m, "str.suffixof", 0, 2, str2T, boolT);
m_sigs[_OP_STRING_IN_REGEXP] = alloc(psig, m, "str.in.re", 0, 2, strTreT, boolT);
m_sigs[_OP_STRING_TO_REGEXP] = alloc(psig, m, "str.to.re", 0, 1, &strT, reT);
m_sigs[_OP_STRING_SUBSTR] = alloc(psig, m, "str.substr", 0, 3, strTint2T, boolT);
}
void seq_decl_plugin::set_manager(ast_manager* m, family_id id) {
decl_plugin::set_manager(m, id);
m_char = m->mk_sort(symbol("Char"), sort_info(m_family_id, _CHAR_SORT, 0, (parameter const*)0));
m->inc_ref(m_char);
parameter param(m_char);
m_string = m->mk_sort(symbol("String"), sort_info(m_family_id, SEQ_SORT, 1, &param));
m->inc_ref(m_string);
}
sort * seq_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) {
@ -179,6 +246,9 @@ sort * seq_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter
if (!parameters[0].is_ast() || !is_sort(parameters[0].get_ast())) {
m.raise_exception("invalid sequence sort, parameter is not a sort");
}
if (parameters[0].get_ast() == m_char) {
return m_string;
}
return m.mk_sort(symbol("Seq"), sort_info(m_family_id, SEQ_SORT, num_parameters, parameters));
case RE_SORT:
if (num_parameters != 1) {
@ -188,12 +258,31 @@ sort * seq_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter
m.raise_exception("invalid regex sort, parameter is not a sort");
}
return m.mk_sort(symbol("RegEx"), sort_info(m_family_id, RE_SORT, num_parameters, parameters));
case _STRING_SORT:
return m_string;
case _CHAR_SORT:
return m_char;
default:
UNREACHABLE();
return 0;
}
}
func_decl* seq_decl_plugin::mk_seq_fun(decl_kind k, unsigned arity, sort* const* domain, sort* range, decl_kind k_string) {
ast_manager& m = *m_manager;
sort_ref rng(m);
match(*m_sigs[k], arity, domain, range, rng);
return m.mk_func_decl(m_sigs[(domain[0] == m_string)?k_string:k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k));
}
func_decl* seq_decl_plugin::mk_str_fun(decl_kind k, unsigned arity, sort* const* domain, sort* range, decl_kind k_seq) {
ast_manager& m = *m_manager;
sort_ref rng(m);
match(*m_sigs[k], arity, domain, range, rng);
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k_seq));
}
func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters, parameter const * parameters,
unsigned arity, sort * const * domain, sort * range) {
init();
@ -202,36 +291,16 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
switch(k) {
case OP_SEQ_UNIT:
case OP_SEQ_EMPTY:
case OP_SEQ_CONCAT:
case OP_SEQ_CONS:
case OP_SEQ_REV_CONS:
case OP_SEQ_HEAD:
case OP_SEQ_TAIL:
case OP_SEQ_LAST:
case OP_SEQ_FIRST:
case OP_SEQ_PREFIX_OF:
case OP_SEQ_SUFFIX_OF:
case OP_SEQ_SUBSEQ_OF:
case OP_SEQ_LENGTH:
case OP_RE_PLUS:
case OP_RE_STAR:
case OP_RE_OPTION:
case OP_RE_RANGE:
case OP_RE_CONCAT:
case OP_RE_UNION:
case OP_RE_INTERSECT:
case OP_RE_DIFFERENCE:
case OP_RE_COMPLEMENT:
case OP_RE_EMPTY_SEQ:
case OP_RE_EMPTY_SET:
case OP_RE_OF_SEQ:
case OP_RE_OF_PRED:
case OP_RE_MEMBER:
match(*m_sigs[k], arity, domain, range, rng);
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k));
case OP_SEQ_EXTRACT:
case OP_SEQ_NTH:
// TBD check numeric arguments for being BVs or integers.
match(*m_sigs[k], arity, domain, range, rng);
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k));
case OP_RE_LOOP:
@ -239,7 +308,80 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
if (num_parameters != 2 || !parameters[0].is_int() || !parameters[1].is_int()) {
m.raise_exception("Expecting two numeral parameters to function re-loop");
}
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k, num_parameters, parameters));
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k, num_parameters, parameters));
case OP_STRING_CONST:
if (!(num_parameters == 1 && arity == 0 && parameters[0].is_symbol())) {
m.raise_exception("invalid string declaration");
}
return m.mk_const_decl(m_stringc_sym, m_string,
func_decl_info(m_family_id, OP_STRING_CONST, num_parameters, parameters));
case OP_SEQ_CONCAT: {
match_left_assoc(*m_sigs[k], arity, domain, range, rng);
func_decl_info info(m_family_id, k);
info.set_left_associative();
return m.mk_func_decl(m_sigs[(rng == m_string)?_OP_STRING_CONCAT:k]->m_name, rng, rng, rng, info);
}
case OP_RE_CONCAT: {
match_left_assoc(*m_sigs[k], arity, domain, range, rng);
func_decl_info info(m_family_id, k);
info.set_left_associative();
return m.mk_func_decl(m_sigs[k]->m_name, rng, rng, rng, info);
}
case _OP_STRING_CONCAT: {
match_left_assoc(*m_sigs[k], arity, domain, range, rng);
func_decl_info info(m_family_id, OP_SEQ_CONCAT);
info.set_left_associative();
return m.mk_func_decl(m_sigs[k]->m_name, rng, rng, rng, info);
}
case OP_SEQ_PREFIX:
return mk_seq_fun(k, arity, domain, range, _OP_STRING_PREFIX);
case _OP_STRING_PREFIX:
return mk_str_fun(k, arity, domain, range, OP_SEQ_PREFIX);
case OP_SEQ_SUFFIX:
return mk_seq_fun(k, arity, domain, range, _OP_STRING_SUFFIX);
case _OP_STRING_SUFFIX:
return mk_str_fun(k, arity, domain, range, OP_SEQ_SUFFIX);
case OP_SEQ_LENGTH:
return mk_seq_fun(k, arity, domain, range, _OP_STRING_LENGTH);
case _OP_STRING_LENGTH:
return mk_str_fun(k, arity, domain, range, OP_SEQ_LENGTH);
case OP_SEQ_CONTAINS:
return mk_seq_fun(k, arity, domain, range, _OP_STRING_STRCTN);
case _OP_STRING_STRCTN:
return mk_str_fun(k, arity, domain, range, OP_SEQ_CONTAINS);
case OP_SEQ_TO_RE:
return mk_seq_fun(k, arity, domain, range, _OP_STRING_TO_REGEXP);
case _OP_STRING_TO_REGEXP:
return mk_str_fun(k, arity, domain, range, OP_SEQ_TO_RE);
case OP_SEQ_IN_RE:
return mk_seq_fun(k, arity, domain, range, _OP_STRING_IN_REGEXP);
case _OP_STRING_IN_REGEXP:
return mk_str_fun(k, arity, domain, range, OP_SEQ_IN_RE);
case OP_SEQ_AT:
return mk_seq_fun(k, arity, domain, range, _OP_STRING_CHARAT);
case _OP_STRING_CHARAT:
return mk_str_fun(k, arity, domain, range, OP_SEQ_AT);
case OP_SEQ_EXTRACT:
return mk_seq_fun(k, arity, domain, range, _OP_STRING_SUBSTR);
case _OP_STRING_SUBSTR:
return mk_str_fun(k, arity, domain, range, OP_SEQ_EXTRACT);
case OP_STRING_STRIDOF:
case OP_STRING_STRREPL:
case OP_STRING_ITOS:
case OP_STRING_STOI:
case OP_REGEXP_LOOP:
match(*m_sigs[k], arity, domain, range, rng);
return m.mk_func_decl(m_sigs[k]->m_name, arity, domain, rng, func_decl_info(m_family_id, k));
default:
UNREACHABLE();
return 0;
@ -249,7 +391,9 @@ func_decl * seq_decl_plugin::mk_func_decl(decl_kind k, unsigned num_parameters,
void seq_decl_plugin::get_op_names(svector<builtin_name> & op_names, symbol const & logic) {
init();
for (unsigned i = 0; i < m_sigs.size(); ++i) {
op_names.push_back(builtin_name(m_sigs[i]->m_name.str().c_str(), i));
if (m_sigs[i]) {
op_names.push_back(builtin_name(m_sigs[i]->m_name.str().c_str(), i));
}
}
}
@ -257,9 +401,29 @@ void seq_decl_plugin::get_sort_names(svector<builtin_name> & sort_names, symbol
init();
sort_names.push_back(builtin_name("Seq", SEQ_SORT));
sort_names.push_back(builtin_name("RegEx", RE_SORT));
sort_names.push_back(builtin_name("String", _STRING_SORT));
}
app* seq_decl_plugin::mk_string(symbol const& s) {
parameter param(s);
func_decl* f = m_manager->mk_const_decl(m_stringc_sym, m_string,
func_decl_info(m_family_id, OP_STRING_CONST, 1, &param));
return m_manager->mk_const(f);
}
bool seq_decl_plugin::is_value(app* e) const {
// TBD: empty sequence is a value.
return false;
return is_app_of(e, m_family_id, OP_STRING_CONST);
}
app* seq_util::str::mk_string(symbol const& s) {
return u.seq.mk_string(s);
}
void seq_util::str::get_concat(expr* e, ptr_vector<expr>& es) const {
expr* e1, *e2;
while (is_concat(e, e1, e2)) {
get_concat(e1, es);
e = e2;
}
es.push_back(e);
}

View file

@ -11,10 +11,12 @@ Abstract:
Author:
Nikolaj Bjorner (nbjorner) 2011-14-11
Nikolaj Bjorner (nbjorner) 2011-11-14
Revision History:
Updated to string sequences 2015-12-5
--*/
#ifndef SEQ_DECL_PLUGIN_H_
#define SEQ_DECL_PLUGIN_H_
@ -24,25 +26,23 @@ Revision History:
enum seq_sort_kind {
SEQ_SORT,
RE_SORT
RE_SORT,
_STRING_SORT, // internal only
_CHAR_SORT // internal only
};
enum seq_op_kind {
OP_SEQ_UNIT,
OP_SEQ_EMPTY,
OP_SEQ_CONCAT,
OP_SEQ_CONS,
OP_SEQ_REV_CONS,
OP_SEQ_HEAD,
OP_SEQ_TAIL,
OP_SEQ_LAST,
OP_SEQ_FIRST,
OP_SEQ_PREFIX_OF,
OP_SEQ_SUFFIX_OF,
OP_SEQ_SUBSEQ_OF,
OP_SEQ_PREFIX,
OP_SEQ_SUFFIX,
OP_SEQ_CONTAINS,
OP_SEQ_EXTRACT,
OP_SEQ_NTH,
OP_SEQ_AT,
OP_SEQ_LENGTH,
OP_SEQ_TO_RE,
OP_SEQ_IN_RE,
OP_RE_PLUS,
OP_RE_STAR,
@ -51,16 +51,30 @@ enum seq_op_kind {
OP_RE_CONCAT,
OP_RE_UNION,
OP_RE_INTERSECT,
OP_RE_COMPLEMENT,
OP_RE_DIFFERENCE,
OP_RE_LOOP,
OP_RE_EMPTY_SET,
OP_RE_FULL_SET,
OP_RE_EMPTY_SEQ,
OP_RE_OF_SEQ,
OP_RE_OF_PRED,
OP_RE_MEMBER,
// string specific operators.
OP_STRING_CONST,
OP_STRING_STRIDOF, // TBD generalize
OP_STRING_STRREPL, // TBD generalize
OP_STRING_ITOS,
OP_STRING_STOI,
OP_REGEXP_LOOP, // TBD re-loop: integers as parameters or arguments?
// internal only operators. Converted to SEQ variants.
_OP_STRING_CONCAT,
_OP_STRING_LENGTH,
_OP_STRING_STRCTN,
_OP_STRING_PREFIX,
_OP_STRING_SUFFIX,
_OP_STRING_IN_REGEXP,
_OP_STRING_TO_REGEXP,
_OP_STRING_CHARAT,
_OP_STRING_SUBSTR,
LAST_SEQ_OP
};
@ -83,24 +97,34 @@ class seq_decl_plugin : public decl_plugin {
};
ptr_vector<psig> m_sigs;
bool m_init;
bool m_init;
symbol m_stringc_sym;
sort* m_string;
sort* m_char;
void match(psig& sig, unsigned dsz, sort* const* dom, sort* range, sort_ref& rng);
void match_left_assoc(psig& sig, unsigned dsz, sort* const* dom, sort* range, sort_ref& rng);
bool match(ptr_vector<sort>& binding, sort* s, sort* sP);
sort* apply_binding(ptr_vector<sort> const& binding, sort* s);
bool is_sort_param(sort* s, unsigned& idx);
func_decl* mk_seq_fun(decl_kind k, unsigned arity, sort* const* domain, sort* range, decl_kind k_string);
func_decl* mk_str_fun(decl_kind k, unsigned arity, sort* const* domain, sort* range, decl_kind k_seq);
void init();
virtual void set_manager(ast_manager * m, family_id id);
public:
seq_decl_plugin();
virtual ~seq_decl_plugin() {}
virtual void finalize();
virtual decl_plugin * mk_fresh() { return alloc(seq_decl_plugin); }
virtual sort * mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters);
@ -116,6 +140,118 @@ public:
virtual bool is_unique_value(app * e) const { return is_value(e); }
bool is_char(ast* a) const { return a == m_char; }
app* mk_string(symbol const& s);
};
class seq_util {
ast_manager& m;
seq_decl_plugin& seq;
family_id m_fid;
public:
ast_manager& get_manager() const { return m; }
bool is_string(sort* s) const { return is_seq(s) && seq.is_char(s->get_parameter(0).get_ast()); }
bool is_seq(sort* s) const { return is_sort_of(s, m_fid, SEQ_SORT); }
bool is_re(sort* s) const { return is_sort_of(s, m_fid, RE_SORT); }
class str {
seq_util& u;
ast_manager& m;
family_id m_fid;
public:
str(seq_util& u):u(u), m(u.m), m_fid(u.m_fid) {}
app* mk_string(symbol const& s);
app* mk_string(char const* s) { return mk_string(symbol(s)); }
app* mk_string(std::string const& s) { return mk_string(symbol(s.c_str())); }
app* mk_concat(expr* a, expr* b) { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_CONCAT, 2, es); }
app* mk_length(expr* a) { return m.mk_app(m_fid, OP_SEQ_LENGTH, 1, &a); }
app* mk_substr(expr* a, expr* b, expr* c) { expr* es[3] = { a, b, c }; return m.mk_app(m_fid, OP_SEQ_EXTRACT, 3, es); }
app* mk_strctn(expr* a, expr* b) { expr* es[2] = { a, b }; return m.mk_app(m_fid, OP_SEQ_CONTAINS, 2, es); }
bool is_string(expr const * n) const { return is_app_of(n, m_fid, OP_STRING_CONST); }
bool is_string(expr const* n, std::string& s) const {
return is_string(n) && (s = to_app(n)->get_decl()->get_parameter(0).get_symbol().str(), true);
}
bool is_string(expr const* n, symbol& s) const {
return is_string(n) && (s = to_app(n)->get_decl()->get_parameter(0).get_symbol(), true);
}
bool is_empty(expr const* n) const { symbol s; return is_app_of(n, m_fid, OP_SEQ_EMPTY) || (is_string(n, s) && !s.is_numerical() && strcmp(s.bare_str(),"") == 0); }
bool is_concat(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_CONCAT); }
bool is_length(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_LENGTH); }
bool is_extract(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_EXTRACT); }
bool is_contains(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_CONTAINS); }
bool is_at(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_AT); }
bool is_stridof(expr const* n) const { return is_app_of(n, m_fid, OP_STRING_STRIDOF); }
bool is_repl(expr const* n) const { return is_app_of(n, m_fid, OP_STRING_STRREPL); }
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); }
bool is_itos(expr const* n) const { return is_app_of(n, m_fid, OP_STRING_ITOS); }
bool is_stoi(expr const* n) const { return is_app_of(n, m_fid, OP_STRING_STOI); }
bool is_in_re(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_IN_RE); }
MATCH_BINARY(is_concat);
MATCH_UNARY(is_length);
MATCH_TERNARY(is_extract);
MATCH_BINARY(is_contains);
MATCH_BINARY(is_at);
MATCH_BINARY(is_stridof);
MATCH_BINARY(is_repl);
MATCH_BINARY(is_prefix);
MATCH_BINARY(is_suffix);
MATCH_UNARY(is_itos);
MATCH_UNARY(is_stoi);
MATCH_BINARY(is_in_re);
void get_concat(expr* e, ptr_vector<expr>& es) const;
};
class re {
seq_util& u;
ast_manager& m;
family_id m_fid;
public:
re(seq_util& u):u(u), m(u.m), m_fid(u.m_fid) {}
bool is_to_re(expr const* n) const { return is_app_of(n, m_fid, OP_SEQ_TO_RE); }
bool is_concat(expr const* n) const { return is_app_of(n, m_fid, OP_RE_CONCAT); }
bool is_union(expr const* n) const { return is_app_of(n, m_fid, OP_RE_UNION); }
bool is_inter(expr const* n) const { return is_app_of(n, m_fid, OP_RE_INTERSECT); }
bool is_star(expr const* n) const { return is_app_of(n, m_fid, OP_RE_STAR); }
bool is_plus(expr const* n) const { return is_app_of(n, m_fid, OP_RE_PLUS); }
bool is_opt(expr const* n) const { return is_app_of(n, m_fid, OP_RE_OPTION); }
bool is_range(expr const* n) const { return is_app_of(n, m_fid, OP_RE_RANGE); }
bool is_loop(expr const* n) const { return is_app_of(n, m_fid, OP_REGEXP_LOOP); }
MATCH_UNARY(is_to_re);
MATCH_BINARY(is_concat);
MATCH_BINARY(is_union);
MATCH_BINARY(is_inter);
MATCH_UNARY(is_star);
MATCH_UNARY(is_plus);
MATCH_UNARY(is_opt);
};
str str;
re re;
seq_util(ast_manager& m):
m(m),
seq(*static_cast<seq_decl_plugin*>(m.get_plugin(m.mk_family_id("seq")))),
m_fid(seq.get_family_id()),
str(*this),
re(*this) {
}
~seq_util() {}
family_id get_family_id() const { return m_fid; }
};

View file

@ -245,6 +245,7 @@ protected:
bv_util m_bvutil;
array_util m_arutil;
fpa_util m_futil;
seq_util m_sutil;
datalog::dl_decl_util m_dlutil;
format_ns::format * pp_fdecl_name(symbol const & s, func_decls const & fs, func_decl * f, unsigned & len) {
@ -265,13 +266,14 @@ protected:
}
public:
pp_env(cmd_context & o):m_owner(o), m_autil(o.m()), m_bvutil(o.m()), m_arutil(o.m()), m_futil(o.m()), m_dlutil(o.m()) {}
pp_env(cmd_context & o):m_owner(o), m_autil(o.m()), m_bvutil(o.m()), m_arutil(o.m()), m_futil(o.m()), m_sutil(o.m()), m_dlutil(o.m()) {}
virtual ~pp_env() {}
virtual ast_manager & get_manager() const { return m_owner.m(); }
virtual arith_util & get_autil() { return m_autil; }
virtual bv_util & get_bvutil() { return m_bvutil; }
virtual array_util & get_arutil() { return m_arutil; }
virtual fpa_util & get_futil() { return m_futil; }
virtual seq_util & get_sutil() { return m_sutil; }
virtual datalog::dl_decl_util& get_dlutil() { return m_dlutil; }
virtual bool uses(symbol const & s) const {
return

View file

@ -22,6 +22,7 @@ Revision History:
#include"datatype_decl_plugin.h"
#include"bv_decl_plugin.h"
#include"arith_decl_plugin.h"
#include"seq_decl_plugin.h"
#include"ast_pp.h"
#include"well_sorted.h"
#include"pattern_validation.h"
@ -65,6 +66,7 @@ namespace smt2 {
scoped_ptr<bv_util> m_bv_util;
scoped_ptr<arith_util> m_arith_util;
scoped_ptr<seq_util> m_seq_util;
scoped_ptr<pattern_validator> m_pattern_validator;
scoped_ptr<var_shifter> m_var_shifter;
@ -270,6 +272,12 @@ namespace smt2 {
return *(m_arith_util.get());
}
seq_util & sutil() {
if (m_seq_util.get() == 0)
m_seq_util = alloc(seq_util, m());
return *(m_seq_util.get());
}
bv_util & butil() {
if (m_bv_util.get() == 0)
m_bv_util = alloc(bv_util, m());
@ -1059,6 +1067,13 @@ namespace smt2 {
next();
}
void parse_string_const() {
SASSERT(curr() == scanner::STRING_TOKEN);
expr_stack().push_back(sutil().str.mk_string(m_scanner.get_string()));
TRACE("smt2parser", tout << "new string: " << mk_pp(expr_stack().back(), m()) << "\n";);
next();
}
void push_pattern_frame() {
// TODO: It seems the only reliable way to parse patterns is:
// Parse as an S-Expr, then try to convert it to an useful pattern.
@ -1723,6 +1738,9 @@ namespace smt2 {
break;
case scanner::KEYWORD_TOKEN:
throw parser_exception("invalid expression, unexpected keyword");
case scanner::STRING_TOKEN:
parse_string_const();
break;
default:
throw parser_exception("invalid expression, unexpected input");
}
@ -2609,6 +2627,7 @@ namespace smt2 {
m_bv_util = 0;
m_arith_util = 0;
m_seq_util = 0;
m_pattern_validator = 0;
m_var_shifter = 0;
}

View file

@ -171,10 +171,7 @@ namespace smt2 {
throw scanner_exception("unexpected end of string", m_line, m_spos);
if (c == '\"') {
next();
if (curr() == '\"') {
m_string.push_back(c);
}
else {
if (curr() != '\"') {
m_string.push_back(0);
return STRING_TOKEN;
}

View file

@ -20,8 +20,64 @@ Revision History:
#define THEORY_SEQ_EMPTY_H_
#include "smt_theory.h"
#include "seq_decl_plugin.h"
namespace smt {
class seq_factory : public value_factory {
typedef hashtable<symbol, symbol_hash_proc, symbol_eq_proc> symbol_set;
proto_model& m_model;
seq_util u;
symbol_set m_strings;
unsigned m_next;
public:
seq_factory(ast_manager & m, family_id fid, proto_model & md):
value_factory(m, fid),
m_model(md),
u(m),
m_next(0)
{
m_strings.insert(symbol(""));
m_strings.insert(symbol("a"));
m_strings.insert(symbol("b"));
}
virtual expr* get_some_value(sort* s) {
if (u.is_string(s))
return u.str.mk_string(symbol(""));
NOT_IMPLEMENTED_YET();
return 0;
}
virtual bool get_some_values(sort* s, expr_ref& v1, expr_ref& v2) {
if (u.is_string(s)) {
v1 = u.str.mk_string("a");
v2 = u.str.mk_string("b");
return true;
}
NOT_IMPLEMENTED_YET();
return false;
}
virtual expr* get_fresh_value(sort* s) {
if (u.is_string(s)) {
while (true) {
std::ostringstream strm;
strm << "S" << m_next++;
symbol sym(strm.str().c_str());
if (m_strings.contains(sym)) continue;
m_strings.insert(sym);
return u.str.mk_string(sym);
}
}
NOT_IMPLEMENTED_YET();
return 0;
}
virtual void register_value(expr* n) {
symbol sym;
if (u.str.is_string(n, sym)) {
m_strings.insert(sym);
}
}
};
class theory_seq_empty : public theory {
bool m_used;
virtual final_check_status final_check_eh() { return m_used?FC_GIVEUP:FC_DONE; }
@ -33,6 +89,10 @@ namespace smt {
virtual char const * get_name() const { return "seq-empty"; }
public:
theory_seq_empty(ast_manager& m):theory(m.mk_family_id("seq")), m_used(false) {}
virtual void init_model(model_generator & mg) {
mg.register_factory(alloc(seq_factory, get_manager(), get_family_id(), mg.get_model()));
}
};
};