/*++ Copyright (c) 2011 Microsoft Corporation Module Name: dl_decl_plugin.h Abstract: Author: Nikolaj Bjorner (nbjorner) 2011-14-11 Revision History: --*/ #include "seq_decl_plugin.h" #include "arith_decl_plugin.h" #include "array_decl_plugin.h" #include seq_decl_plugin::seq_decl_plugin(): m_init(false) {} void seq_decl_plugin::finalize() { for (unsigned i = 0; i < m_sigs.size(); ++i) dealloc(m_sigs[i]); } bool seq_decl_plugin::is_sort_param(sort* s, unsigned& idx) { return s->get_name().is_numerical() && (idx = s->get_name().get_num(), true); } bool seq_decl_plugin::match(ptr_vector& binding, sort* s, sort* sP) { 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; 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; } } return true; } else { return false; } } void seq_decl_plugin::match(psig& sig, unsigned dsz, sort *const* dom, sort* range, sort_ref& range_out) { ptr_vector binding; ast_manager& m = *m_manager; if (sig.m_dom.size() != dsz) { std::ostringstream strm; strm << "Unexpected number of arguments to '" << sig.m_name << "' "; strm << sig.m_dom.size() << " arguments 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[i].get()); } if (range && is_match) { is_match = match(binding, range, sig.m_range); } if (!is_match) { std::ostringstream strm; strm << "Sort of polymorphic function '" << sig.m_name << "' "; strm << "does not match the declared type"; m.raise_exception(strm.str().c_str()); } if (!range && dsz == 0) { std::ostringstream strm; strm << "Sort of polymorphic function '" << sig.m_name << "' "; strm << "is ambiguous. Function takes no arguments and sort of range has not been constrained"; m.raise_exception(strm.str().c_str()); } range_out = apply_binding(binding, sig.m_range); } sort* seq_decl_plugin::apply_binding(ptr_vector const& binding, sort* s) { unsigned i; if (is_sort_param(s, i)) { if (binding.size() <= i || !binding[i]) { m_manager->raise_exception("Expecting type parameter to be bound"); } return binding[i]; } if (is_sort_of(s, m_family_id, SEQ_SORT) || is_sort_of(s, m_family_id, RE_SORT)) { SASSERT(s->get_num_parameters() == 1); SASSERT(s->get_parameter(0).is_ast()); SASSERT(is_sort(s->get_parameter(0).get_ast())); sort* p = apply_binding(binding, to_sort(s->get_parameter(0).get_ast())); parameter param(p); return mk_sort(s->get_decl_kind(), 1, ¶m); } return s; } void seq_decl_plugin::init() { if(m_init) return; ast_manager& m = *m_manager; m_init = true; sort* A = m.mk_sort(symbol((unsigned)0)); sort* B = m.mk_sort(symbol((unsigned)1)); parameter paramA(A); sort* seqA = m.mk_sort(m_family_id, SEQ_SORT, 1, ¶mA); sort* reA = m.mk_sort(m_family_id, RE_SORT, 1, ¶mA); 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* boolT = m.mk_bool_sort(); sort* intT = arith_util(m).mk_int(); sort* predA = array_util(m).mk_array_sort(A, boolT); 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_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_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); } sort * seq_decl_plugin::mk_sort(decl_kind k, unsigned num_parameters, parameter const * parameters) { init(); ast_manager& m = *m_manager; switch (k) { case SEQ_SORT: if (num_parameters != 1) { m.raise_exception("Invalid sequence sort, expecting one parameter"); } if (!parameters[0].is_ast() || !is_sort(parameters[0].get_ast())) { m.raise_exception("invalid sequence sort, parameter is not a sort"); } return m.mk_sort(symbol("Seq"), sort_info(m_family_id, SEQ_SORT, num_parameters, parameters)); case RE_SORT: if (num_parameters != 1) { m.raise_exception("Invalid regex sort, expecting one parameter"); } if (!parameters[0].is_ast() || !is_sort(parameters[0].get_ast())) { 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)); default: UNREACHABLE(); return 0; } } 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(); ast_manager& m = *m_manager; sort_ref rng(m); 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: match(*m_sigs[k], arity, domain, range, rng); 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)); default: UNREACHABLE(); return 0; } } void seq_decl_plugin::get_op_names(svector & 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)); } } void seq_decl_plugin::get_sort_names(svector & sort_names, symbol const & logic) { init(); sort_names.push_back(builtin_name("Seq", SEQ_SORT)); sort_names.push_back(builtin_name("RegEx", RE_SORT)); } bool seq_decl_plugin::is_value(app* e) const { // TBD: empty sequence is a value. return false; }