mirror of
https://github.com/Z3Prover/z3
synced 2026-05-31 14:17:47 +00:00
updated tests
Signed-off-by: Nikolaj Bjorner <nbjorner@microsoft.com>
This commit is contained in:
parent
34cb0a17fc
commit
b0a4a15c98
3 changed files with 106 additions and 86 deletions
|
|
@ -20,15 +20,15 @@
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <windows.h>
|
|
||||||
#include <crtdbg.h>
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
static jmp_buf jmp_env;
|
static jmp_buf jmp_env;
|
||||||
static volatile int in_test = 0;
|
static volatile int in_test = 0;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#include <crtdbg.h>
|
||||||
|
|
||||||
void abort_handler(int sig) {
|
void abort_handler(int sig) {
|
||||||
(void)sig;
|
(void)sig;
|
||||||
if (in_test) {
|
if (in_test) {
|
||||||
|
|
@ -50,13 +50,6 @@ void suppress_dialogs() {
|
||||||
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
|
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
|
||||||
signal(SIGABRT, abort_handler);
|
signal(SIGABRT, abort_handler);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
void suppress_dialogs() {}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int tests_run = 0;
|
|
||||||
static int tests_passed = 0;
|
|
||||||
static int tests_crashed = 0;
|
|
||||||
|
|
||||||
#define RUN_TEST(name) do { \
|
#define RUN_TEST(name) do { \
|
||||||
fprintf(stderr, "[TEST] Running %s\n", #name); \
|
fprintf(stderr, "[TEST] Running %s\n", #name); \
|
||||||
|
|
@ -79,6 +72,40 @@ static int tests_crashed = 0;
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
void abort_handler(int sig) {
|
||||||
|
(void)sig;
|
||||||
|
if (in_test) {
|
||||||
|
in_test = 0;
|
||||||
|
signal(SIGABRT, abort_handler);
|
||||||
|
longjmp(jmp_env, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void suppress_dialogs() { signal(SIGABRT, abort_handler); }
|
||||||
|
|
||||||
|
#define RUN_TEST(name) do { \
|
||||||
|
fprintf(stderr, "[TEST] Running %s\n", #name); \
|
||||||
|
tests_run++; \
|
||||||
|
in_test = 1; \
|
||||||
|
if (setjmp(jmp_env) == 0) { \
|
||||||
|
name(); \
|
||||||
|
in_test = 0; \
|
||||||
|
tests_passed++; \
|
||||||
|
fprintf(stderr, "[TEST] PASS %s\n", #name); \
|
||||||
|
} else { \
|
||||||
|
tests_crashed++; \
|
||||||
|
fprintf(stderr, "[TEST] ABORT %s (caught SIGABRT)\n", #name); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int tests_run = 0;
|
||||||
|
static int tests_passed = 0;
|
||||||
|
static int tests_crashed = 0;
|
||||||
|
|
||||||
/* ===== Helpers ===== */
|
/* ===== Helpers ===== */
|
||||||
static Z3_sort mk_string_sort(Z3_context ctx) { return Z3_mk_string_sort(ctx); }
|
static Z3_sort mk_string_sort(Z3_context ctx) { return Z3_mk_string_sort(ctx); }
|
||||||
static Z3_ast mk_str(Z3_context ctx, const char* s) { return Z3_mk_string(ctx, s); }
|
static Z3_ast mk_str(Z3_context ctx, const char* s) { return Z3_mk_string(ctx, s); }
|
||||||
|
|
|
||||||
|
|
@ -4,15 +4,15 @@
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
|
||||||
#include <setjmp.h>
|
#include <setjmp.h>
|
||||||
|
|
||||||
#ifdef _WIN32
|
|
||||||
#include <windows.h>
|
|
||||||
#include <crtdbg.h>
|
|
||||||
#include <signal.h>
|
#include <signal.h>
|
||||||
|
|
||||||
static jmp_buf jmp_env;
|
static jmp_buf jmp_env;
|
||||||
static volatile int in_test = 0;
|
static volatile int in_test = 0;
|
||||||
|
|
||||||
|
#ifdef _WIN32
|
||||||
|
#include <windows.h>
|
||||||
|
#include <crtdbg.h>
|
||||||
|
|
||||||
void abort_handler(int sig) {
|
void abort_handler(int sig) {
|
||||||
(void)sig;
|
(void)sig;
|
||||||
if (in_test) {
|
if (in_test) {
|
||||||
|
|
@ -34,12 +34,6 @@ void suppress_dialogs() {
|
||||||
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
|
_set_abort_behavior(0, _WRITE_ABORT_MSG | _CALL_REPORTFAULT);
|
||||||
signal(SIGABRT, abort_handler);
|
signal(SIGABRT, abort_handler);
|
||||||
}
|
}
|
||||||
#else
|
|
||||||
void suppress_dialogs() {}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
static int tests_run = 0;
|
|
||||||
static int tests_passed = 0;
|
|
||||||
|
|
||||||
#define RUN_TEST(name) do { \
|
#define RUN_TEST(name) do { \
|
||||||
fprintf(stderr, "[TEST] Running %s\n", #name); \
|
fprintf(stderr, "[TEST] Running %s\n", #name); \
|
||||||
|
|
@ -60,6 +54,38 @@ static int tests_passed = 0;
|
||||||
} \
|
} \
|
||||||
} while(0)
|
} while(0)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
void abort_handler(int sig) {
|
||||||
|
(void)sig;
|
||||||
|
if (in_test) {
|
||||||
|
in_test = 0;
|
||||||
|
signal(SIGABRT, abort_handler);
|
||||||
|
longjmp(jmp_env, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void suppress_dialogs() { signal(SIGABRT, abort_handler); }
|
||||||
|
|
||||||
|
#define RUN_TEST(name) do { \
|
||||||
|
fprintf(stderr, "[TEST] Running %s\n", #name); \
|
||||||
|
tests_run++; \
|
||||||
|
in_test = 1; \
|
||||||
|
if (setjmp(jmp_env) == 0) { \
|
||||||
|
name(); \
|
||||||
|
in_test = 0; \
|
||||||
|
tests_passed++; \
|
||||||
|
fprintf(stderr, "[TEST] PASS %s\n", #name); \
|
||||||
|
} else { \
|
||||||
|
fprintf(stderr, "[TEST] ABORT %s (caught SIGABRT)\n", #name); \
|
||||||
|
} \
|
||||||
|
} while(0)
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static int tests_run = 0;
|
||||||
|
static int tests_passed = 0;
|
||||||
|
|
||||||
/* Helper to create string sort, variables, constants */
|
/* Helper to create string sort, variables, constants */
|
||||||
Z3_sort mk_string_sort(Z3_context ctx) { return Z3_mk_string_sort(ctx); }
|
Z3_sort mk_string_sort(Z3_context ctx) { return Z3_mk_string_sort(ctx); }
|
||||||
Z3_ast mk_string_var(Z3_context ctx, const char* name) {
|
Z3_ast mk_string_var(Z3_context ctx, const char* name) {
|
||||||
|
|
|
||||||
|
|
@ -1125,80 +1125,41 @@ namespace seq {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// consume symbolic characters (s_unit tokens) via uniform derivative
|
// consume symbolic characters via uniform derivatives
|
||||||
// check. When all minterms of the regex produce the same Brzozowski
|
|
||||||
// derivative, the derivative is independent of the character value
|
|
||||||
// and we can deterministically consume the token. Forward direction
|
|
||||||
// only (matches ZIPT history tracking convention).
|
|
||||||
//
|
|
||||||
// Extended: when uniform derivative fails but the token has a char_range
|
|
||||||
// constraint (from apply_regex_var_split), check if the char_range is a
|
|
||||||
// subset of a single minterm's character class. If so, the derivative
|
|
||||||
// is deterministic for that token.
|
|
||||||
// Mirrors ZIPT StrMem.SimplifyCharRegex lines 96-117.
|
|
||||||
for (str_mem& mem : m_str_mem) {
|
for (str_mem& mem : m_str_mem) {
|
||||||
SASSERT(mem.m_str && mem.m_regex);
|
SASSERT(mem.m_str && mem.m_regex);
|
||||||
if (mem.is_primitive())
|
if (mem.is_primitive())
|
||||||
continue;
|
continue;
|
||||||
while (mem.m_str && !mem.m_str->is_empty()) {
|
while (mem.m_str && !mem.m_str->is_empty()) {
|
||||||
euf::snode* tok = mem.m_str->first();
|
|
||||||
if (!tok || !tok->is_unit())
|
// TODO: generalize this to work for reverse derivative as well.
|
||||||
|
euf::snode *tok = mem.m_str->first();
|
||||||
|
if (!tok || !tok->is_char_or_unit())
|
||||||
break;
|
break;
|
||||||
|
|
||||||
//
|
seq_rewriter rw(m);
|
||||||
// TODO -rewrite to use symbolic derivative and add back resulting derived regex.
|
expr_ref d(rw.mk_derivative(mem.m_regex->get_expr()), m);
|
||||||
//
|
|
||||||
|
|
||||||
// compute minterms and check for uniform derivative
|
// Extract the inner char expression from seq.unit(?inner)
|
||||||
euf::snode_vector minterms;
|
expr *unit_expr = tok->arg(0)->get_expr(), *inner_char;
|
||||||
sg.compute_minterms(mem.m_regex, minterms);
|
|
||||||
VERIFY(!minterms.empty());
|
// substitute the inner char for the derivative variable in d
|
||||||
// try char_range subset approach.
|
var_subst vs(m);
|
||||||
// If the symbolic char has a char_range constraint and that
|
d = vs(d, inner_char);
|
||||||
// range is a subset of exactly one minterm's character class,
|
|
||||||
// we can deterministically take that minterm's derivative.
|
th_rewriter thrw(m);
|
||||||
SASSERT(m_graph.m_parikh);
|
thrw(d);
|
||||||
auto full = char_set::full(zstring::max_char());
|
|
||||||
char_set* cs;
|
auto next = sg.mk(d);
|
||||||
dep_tracker dep;
|
if (next->is_fail()) {
|
||||||
if (m_char_ranges.contains(tok->id())) {
|
m_is_general_conflict = true;
|
||||||
auto& ranges = m_char_ranges[tok->id()];
|
set_conflict(backtrack_reason::regex, mem.m_dep);
|
||||||
cs = &ranges.first;
|
return simplify_result::conflict;
|
||||||
dep = ranges.second;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
cs = &full;
|
|
||||||
dep = graph().dep_mgr().mk_empty();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!cs->is_empty()) {
|
mem.m_str = sg.drop_left(mem.m_str, 1);
|
||||||
euf::snode* matching_deriv = nullptr;
|
mem.m_regex = next;
|
||||||
bool found = false;
|
mem.m_history = sg.mk_concat(mem.m_history, tok);
|
||||||
for (euf::snode* mt : minterms) {
|
|
||||||
SASSERT(mt && mt->get_expr());
|
|
||||||
SASSERT(!mt->is_fail());
|
|
||||||
char_set mt_cs = m_graph.m_seq_regex->minterm_to_char_set(mt->get_expr());
|
|
||||||
if (cs->is_subset(mt_cs)) {
|
|
||||||
euf::snode* deriv = sg.brzozowski_deriv(mem.m_regex, mt);
|
|
||||||
if (!deriv) { found = false; break; }
|
|
||||||
if (deriv->is_fail()) {
|
|
||||||
m_is_general_conflict = true;
|
|
||||||
set_conflict(backtrack_reason::regex, graph().dep_mgr().mk_join(mem.m_dep, dep));
|
|
||||||
return simplify_result::conflict;
|
|
||||||
}
|
|
||||||
matching_deriv = deriv;
|
|
||||||
found = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (found && matching_deriv) {
|
|
||||||
mem.m_str = sg.drop_left(mem.m_str, 1);
|
|
||||||
mem.m_regex = matching_deriv;
|
|
||||||
mem.m_history = sg.mk_concat(mem.m_history, tok);
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -3146,6 +3107,7 @@ namespace seq {
|
||||||
SASSERT(mem.m_str && mem.m_regex);
|
SASSERT(mem.m_str && mem.m_regex);
|
||||||
if (mem.is_primitive())
|
if (mem.is_primitive())
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
euf::snode *first = mem.m_str->first();
|
euf::snode *first = mem.m_str->first();
|
||||||
if (!first || !first->is_char_or_unit())
|
if (!first || !first->is_char_or_unit())
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -3272,6 +3234,11 @@ namespace seq {
|
||||||
created = true;
|
created = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// TODO: replace this with a version that just uses symbolic derivatives
|
||||||
|
// and not min-terms.
|
||||||
|
// It solves x -> unit(nth(x, 0)) ++ x
|
||||||
|
// Then the split_regex_unit can solve process the node further.
|
||||||
|
|
||||||
// Branch 2+: for each minterm m_i, x → ?c · x
|
// Branch 2+: for each minterm m_i, x → ?c · x
|
||||||
// where ?c is a symbolic char constrained by the minterm
|
// where ?c is a symbolic char constrained by the minterm
|
||||||
for (euf::snode* mt : minterms) {
|
for (euf::snode* mt : minterms) {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue