z3-z3-4.13.0.src.ast.ast_translation.cpp Maven / Gradle / Ivy
The newest version!
/*++
Copyright (c) 2008 Microsoft Corporation
Module Name:
ast_translation.cpp
Abstract:
AST translation functions
Author:
Christoph Wintersteiger (t-cwinte) 2008-11-20
Revision History:
--*/
#include "ast/arith_decl_plugin.h"
#include "ast/bv_decl_plugin.h"
#include "ast/datatype_decl_plugin.h"
#include "ast/array_decl_plugin.h"
#include "ast/format.h"
#include "ast/ast_translation.h"
#include "ast/ast_ll_pp.h"
#include "ast/ast_pp.h"
ast_translation::~ast_translation() {
reset_cache();
}
void ast_translation::cleanup() {
reset_cache();
m_cache.finalize();
m_result_stack.finalize();
m_frame_stack.finalize();
m_extra_children_stack.finalize();
}
void ast_translation::reset_cache() {
for (auto & kv : m_cache) {
m_from_manager.dec_ref(kv.m_key);
m_to_manager.dec_ref(kv.m_value);
}
m_cache.reset();
}
void ast_translation::cache(ast * s, ast * t) {
SASSERT(!m_cache.contains(s));
if (s->get_ref_count() > 1) {
m_from_manager.inc_ref(s);
m_to_manager.inc_ref(t);
m_cache.insert(s, t);
++m_insert_count;
}
}
void ast_translation::collect_decl_extra_children(decl * d) {
unsigned num_params = d->get_num_parameters();
for (unsigned i = 0; i < num_params; i++) {
parameter const & p = d->get_parameter(i);
if (p.is_ast())
m_extra_children_stack.push_back(p.get_ast());
}
}
void ast_translation::push_frame(ast * n) {
// ensure poly roots are pushed first.
if (m_from_manager.has_type_vars() && n->get_kind() == AST_FUNC_DECL && to_func_decl(n)->is_polymorphic()) {
func_decl* g = m_from_manager.poly_root(to_func_decl(n));
if (n != g && m_cache.contains(g)) {
m_frame_stack.push_back(frame(n, 0, m_extra_children_stack.size(), m_result_stack.size()));
}
}
m_frame_stack.push_back(frame(n, 0, m_extra_children_stack.size(), m_result_stack.size()));
switch (n->get_kind()) {
case AST_SORT:
case AST_FUNC_DECL:
collect_decl_extra_children(to_decl(n));
break;
default:
break;
}
}
bool ast_translation::visit(ast * n) {
if (n->get_ref_count() > 1) {
ast * r;
if (m_cache.find(n, r)) {
m_result_stack.push_back(r);
++m_hit_count;
return true;
}
else {
++m_miss_count;
}
}
push_frame(n);
return false;
}
void ast_translation::copy_params(decl * d, unsigned rpos, buffer & ps) {
unsigned num = d->get_num_parameters();
unsigned j = rpos;
for (unsigned i = 0; i < num; i++) {
parameter const & p = d->get_parameter(i);
if (p.is_ast()) {
ps.push_back(parameter(m_result_stack[j]));
j++;
}
else if (p.is_external()) {
SASSERT(d->get_family_id() != null_family_id);
decl_plugin & from_plugin = *(m_from_manager.get_plugin(d->get_family_id()));
decl_plugin & to_plugin = *(m_to_manager.get_plugin(d->get_family_id()));
ps.push_back(from_plugin.translate(p, to_plugin));
}
else {
ps.push_back(p);
}
}
}
void ast_translation::mk_sort(sort * s, frame & fr) {
sort_info * si = s->get_info();
sort * new_s;
if (si == nullptr) {
// TODO: investigate: this branch is probably unreachable.
// It became unreachable after we started using mk_uninterpreted_sort for creating uninterpreted sorts,
// and mk_uninterpreted_sort actually creates a user_sort.
new_s = m_to_manager.mk_uninterpreted_sort(s->get_name());
SASSERT(m_result_stack.size() == fr.m_rpos);
}
else {
buffer ps;
copy_params(s, fr.m_rpos, ps);
new_s = m_to_manager.mk_sort(s->get_name(), sort_info(si->get_family_id(),
si->get_decl_kind(),
si->get_num_elements(),
si->get_num_parameters(),
ps.data(),
s->private_parameters()));
}
m_result_stack.shrink(fr.m_rpos);
m_result_stack.push_back(new_s);
m_extra_children_stack.shrink(fr.m_cpos);
cache(s, new_s);
m_frame_stack.pop_back();
}
void ast_translation::mk_func_decl(func_decl * f, frame & fr) {
func_decl_info * fi = f->get_info();
SASSERT(fr.m_cpos <= m_extra_children_stack.size());
unsigned num_extra = m_extra_children_stack.size() - fr.m_cpos;
sort ** new_domain = reinterpret_cast(m_result_stack.data() + fr.m_rpos + num_extra);
sort * new_range = static_cast(m_result_stack.back());
func_decl * new_f;
if (fi == nullptr) {
new_f = m_to_manager.mk_func_decl(f->get_name(),
f->get_arity(),
new_domain,
new_range);
}
else if (f->is_polymorphic() && m_from_manager.poly_root(f) != f) {
func_decl* fr = to_func_decl(m_cache[m_from_manager.poly_root(f)]);
new_f = m_to_manager.instantiate_polymorphic(fr, f->get_arity(), new_domain, new_range);
}
else {
buffer ps;
copy_params(f, fr.m_rpos, ps);
func_decl_info new_fi(fi->get_family_id(),
fi->get_decl_kind(),
fi->get_num_parameters(),
ps.data());
new_fi.set_left_associative(fi->is_left_associative());
new_fi.set_right_associative(fi->is_right_associative());
new_fi.set_flat_associative(fi->is_flat_associative());
new_fi.set_commutative(fi->is_commutative());
new_fi.set_chainable(fi->is_chainable());
new_fi.set_pairwise(fi->is_pairwise());
new_fi.set_injective(fi->is_injective());
new_fi.set_skolem(fi->is_skolem());
new_fi.set_idempotent(fi->is_idempotent());
new_fi.set_lambda(fi->is_lambda());
new_f = m_to_manager.mk_func_decl(f->get_name(),
f->get_arity(),
new_domain,
new_range,
new_fi);
if (new_fi.is_lambda()) {
quantifier* q = from().is_lambda_def(f);
ast_translation tr(from(), to());
quantifier* new_q = tr(q);
to().add_lambda_def(new_f, new_q);
}
}
TRACE("ast_translation",
tout << f->get_name() << " "; if (fi) tout << *fi; tout << "\n";
tout << "---->\n";
tout << new_f->get_name() << " "; if (new_f->get_info()) tout << *(new_f->get_info()); tout << "\n";);
m_result_stack.shrink(fr.m_rpos);
m_result_stack.push_back(new_f);
m_extra_children_stack.shrink(fr.m_cpos);
cache(f, new_f);
m_frame_stack.pop_back();
}
ast * ast_translation::process(ast const * _n) {
if (!_n) return nullptr;
SASSERT(m_result_stack.empty());
SASSERT(m_frame_stack.empty());
SASSERT(m_extra_children_stack.empty());
++m_num_process;
if (m_num_process > (1 << 14)) {
reset_cache();
m_num_process = 0;
}
if (!visit(const_cast(_n))) {
while (!m_frame_stack.empty()) {
loop:
++m_loop_count;
frame & fr = m_frame_stack.back();
ast * n = fr.m_n;
ast * r;
TRACE("ast_translation", tout << mk_ll_pp(n, m_from_manager, false) << "\n";);
if (fr.m_idx == 0 && n->get_ref_count() > 1) {
if (m_cache.find(n, r)) {
SASSERT(m_result_stack.size() == fr.m_rpos);
m_result_stack.push_back(r);
m_extra_children_stack.shrink(fr.m_cpos);
m_frame_stack.pop_back();
TRACE("ast_translation", tout << "hit\n";);
m_hit_count++;
continue;
}
else {
m_miss_count++;
}
}
switch (n->get_kind()) {
case AST_VAR: {
if (fr.m_idx == 0) {
fr.m_idx = 1;
if (!visit(to_var(n)->get_sort()))
goto loop;
}
sort * new_s = to_sort(m_result_stack.back());
var * new_var = m_to_manager.mk_var(to_var(n)->get_idx(), new_s);
m_result_stack.pop_back();
m_result_stack.push_back(new_var);
cache(n, new_var);
m_frame_stack.pop_back();
break;
}
case AST_APP: {
if (fr.m_idx == 0) {
fr.m_idx = 1;
if (!visit(to_app(n)->get_decl()))
goto loop;
}
unsigned num = to_app(n)->get_num_args();
while (fr.m_idx <= num) {
expr * arg = to_app(n)->get_arg(fr.m_idx - 1);
fr.m_idx++;
if (!visit(arg))
goto loop;
}
func_decl * new_f = to_func_decl(m_result_stack[fr.m_rpos]);
expr ** new_args = reinterpret_cast(m_result_stack.data() + fr.m_rpos + 1);
expr * new_app = m_to_manager.mk_app(new_f, num, new_args);
m_result_stack.shrink(fr.m_rpos);
m_result_stack.push_back(new_app);
cache(n, new_app);
m_frame_stack.pop_back();
break;
}
case AST_QUANTIFIER: {
unsigned num_decls = to_quantifier(n)->get_num_decls();
unsigned num = num_decls + to_quantifier(n)->get_num_children();
while (fr.m_idx < num) {
ast * child;
if (fr.m_idx < num_decls)
child = to_quantifier(n)->get_decl_sort(fr.m_idx);
else
child = to_quantifier(n)->get_child(fr.m_idx - num_decls);
fr.m_idx++;
if (!visit(child))
goto loop;
}
symbol const * dnames = to_quantifier(n)->get_decl_names();
sort ** dsorts = reinterpret_cast(m_result_stack.data() + fr.m_rpos);
expr * body = static_cast(m_result_stack[fr.m_rpos + num_decls]);
unsigned num_pats = to_quantifier(n)->get_num_patterns();
expr ** pats = reinterpret_cast(m_result_stack.data() + fr.m_rpos + num_decls + 1);
unsigned num_no_pats = to_quantifier(n)->get_num_no_patterns();
expr ** no_pats = pats + num_pats;
quantifier * new_q = m_to_manager.mk_quantifier(to_quantifier(n)->get_kind(),
num_decls,
dsorts,
dnames,
body,
to_quantifier(n)->get_weight(),
to_quantifier(n)->get_qid(),
to_quantifier(n)->get_skid(),
num_pats, pats,
num_no_pats, no_pats);
m_result_stack.shrink(fr.m_rpos);
m_result_stack.push_back(new_q);
cache(n, new_q);
m_frame_stack.pop_back();
break;
}
case AST_SORT: {
SASSERT(fr.m_cpos <= m_extra_children_stack.size());
unsigned num = m_extra_children_stack.size() - fr.m_cpos;
while (fr.m_idx < num) {
ast * c = m_extra_children_stack[fr.m_cpos + fr.m_idx];
fr.m_idx++;
if (!visit(c))
goto loop;
}
mk_sort(to_sort(n), fr);
break;
}
case AST_FUNC_DECL: {
SASSERT(fr.m_cpos <= m_extra_children_stack.size());
unsigned num_extra = m_extra_children_stack.size() - fr.m_cpos;
unsigned arity = to_func_decl(n)->get_arity();
unsigned num = num_extra + arity + 1;
while (fr.m_idx < num) {
ast * c;
if (fr.m_idx < num_extra)
c = m_extra_children_stack[fr.m_cpos + fr.m_idx];
else if (fr.m_idx < num_extra + arity)
c = to_func_decl(n)->get_domain(fr.m_idx - num_extra);
else
c = to_func_decl(n)->get_range();
fr.m_idx++;
if (!visit(c))
goto loop;
}
mk_func_decl(to_func_decl(n), fr);
break;
}
default:
UNREACHABLE();
break;
}
}
}
SASSERT(m_result_stack.size() == 1);
ast * r = m_result_stack.back();
m_result_stack.reset();
return r;
}
expr_dependency * expr_dependency_translation::operator()(expr_dependency * d) {
if (d == nullptr)
return d;
m_buffer.reset();
m_translation.from().linearize(d, m_buffer);
unsigned sz = m_buffer.size();
SASSERT(sz >= 1);
for (unsigned i = 0; i < sz; i++) {
m_buffer[i] = m_translation(m_buffer[i]);
}
return m_translation.to().mk_join(sz, m_buffer.data());
}