/*****************************************************************************/ /*! * \file vcl.cpp * * Author: Clark Barrett * * Created: Tue Dec 31 18:27:11 2002 * *
* License to use, copy, modify, sell and/or distribute this software * and its documentation for any purpose is hereby granted without * royalty, subject to the terms and conditions defined in the \ref * LICENSE file provided with this distribution. * *
* */ /*****************************************************************************/ #include #include "os.h" #include "vcl.h" #include "parser.h" #include "vc_cmd.h" #include "search_simple.h" #include "search_fast.h" #include "search_sat.h" #include "theory_core.h" #include "theory_uf.h" #include "theory_arith_old.h" #include "theory_arith_new.h" #include "theory_bitvector.h" #include "theory_array.h" #include "theory_quant.h" #include "theory_records.h" #include "theory_simulate.h" #include "theory_datatype.h" #include "theory_datatype_lazy.h" #include "translator.h" #include "typecheck_exception.h" #include "eval_exception.h" #include "expr_transform.h" #include "theorem_manager.h" namespace CVC3{ VCL* myvcl; } using namespace std; using namespace CVC3; /////////////////////////////////////////////////////////////////////////////// // Static ValidityChecker methods /////////////////////////////////////////////////////////////////////////////// ValidityChecker* ValidityChecker::create(const CLFlags& flags) { return new VCL(flags); } CLFlags ValidityChecker::createFlags() { CLFlags flags; // We expect the user to type cvc3 -h to get help, which will set // the "help" flag to false; that's why it's initially true. // Overall system control flags flags.addFlag("timeout", CLFlag(0, "Kill cvc3 process after given number of seconds (0==no limit)")); flags.addFlag("resource", CLFlag(0, "Set finite resource limit (0==no limit)")); flags.addFlag("mm", CLFlag("chunks", "Memory manager (chunks, malloc)")); // Information printing flags flags.addFlag("help",CLFlag(true, "print usage information and exit")); flags.addFlag("version",CLFlag(true, "print version information and exit")); flags.addFlag("interactive", CLFlag(false, "Interactive mode")); flags.addFlag("stats", CLFlag(false, "Print run-time statistics")); flags.addFlag("seed", CLFlag(1, "Set the seed for random sequence")); flags.addFlag("printResults", CLFlag(true, "Print results of interactive commands.")); flags.addFlag("dump-log", CLFlag("", "Dump API call log in CVC3 input " "format to given file " "(off when file name is \"\")")); //Translation related flags flags.addFlag("expResult", CLFlag("", "For smtlib translation. Give the expected result")); flags.addFlag("category", CLFlag("unknown", "For smtlib translation. Give the category")); flags.addFlag("translate", CLFlag(false, "Produce a complete translation from " "the input language to output language. ")); flags.addFlag("real2int", CLFlag(false, "When translating, convert reals to integers.")); flags.addFlag("convertArith", CLFlag(false, "When translating, try to rewrite arith terms into smt-lib subset")); flags.addFlag("convert2diff", CLFlag("", "When translating, try to force into difference logic. Legal values are int and real.")); flags.addFlag("iteLiftArith", CLFlag(false, "For translation. If true, ite's are lifted out of arith exprs.")); flags.addFlag("convertArray", CLFlag(false, "For translation. If true, arrays are converted to uninterpreted functions if possible.")); flags.addFlag("combineAssump", CLFlag(false, "For translation. If true, assumptions are combined into the query.")); // Parser related flags flags.addFlag("old-func-syntax",CLFlag(false, "Enable parsing of old-style function syntax")); // Pretty-printing related flags flags.addFlag("dagify-exprs", CLFlag(true, "Print expressions with sharing as DAGs")); flags.addFlag("lang", CLFlag("presentation", "Input language " "(presentation, smtlib, internal)")); flags.addFlag("output-lang", CLFlag("", "Output language " "(presentation, smtlib, simplify, internal, lisp)")); flags.addFlag("indent", CLFlag(false, "Print expressions with indentation")); flags.addFlag("width", CLFlag(80, "Suggested line width for printing")); flags.addFlag("print-depth", CLFlag(-1, "Max. depth to print expressions ")); flags.addFlag("print-assump", CLFlag(false, "Print assumptions in Theorems ")); // Search Engine (SAT) related flags flags.addFlag("sat",CLFlag("minisat", "choose a SAT solver to use " "(fast, simple, sat, minisat)")); flags.addFlag("de",CLFlag("dfs", "choose a decision engine to use " "(dfs, sat)")); // Proofs and Assumptions flags.addFlag("proofs", CLFlag(false, "Produce proofs")); flags.addFlag("check-proofs", CLFlag(IF_DEBUG(true ||) false, "Check proofs on-the-fly")); flags.addFlag("minimizeClauses", CLFlag(false, "Use brute-force minimization of clauses")); // Core framework switches flags.addFlag("tcc", CLFlag(false, "Check TCCs for each ASSERT and QUERY")); flags.addFlag("cnf", CLFlag(true, "Convert top-level Boolean formulas to CNF")); flags.addFlag("ignore-cnf-vars", CLFlag(false, "Do not split on aux. CNF vars (with +cnf)")); flags.addFlag("orig-formula", CLFlag(false, "Preserve the original formula with +cnf (for splitter heuristics)")); flags.addFlag("iflift", CLFlag(false, "Translate if-then-else terms to CNF (with +cnf)")); flags.addFlag("circuit", CLFlag(false, "With +cnf, use circuit propagation")); flags.addFlag("un-ite-ify", CLFlag(false, "Unconvert ITE expressions")); flags.addFlag("ite-cond-simp", CLFlag(false, "Replace ITE condition by TRUE/FALSE in subexprs")); flags.addFlag("pp-pushneg", CLFlag(false, "Push negation in preprocessor")); flags.addFlag("pushneg", CLFlag(true, "Push negation while simplifying")); flags.addFlag("simp-and", CLFlag(false, "Rewrite x&y to x&y[x/true]")); flags.addFlag("simp-or", CLFlag(false, "Rewrite x|y to x|y[x/false]")); // Concrete model generation (counterexamples) flags flags.addFlag("applications", CLFlag(true, "Add relevant function applications and array accesses to the concrete countermodel")); // Debugging flags (only for the debug build) // #ifdef DEBUG vector > sv; flags.addFlag("trace", CLFlag(sv, "Tracing. Multiple flags add up.")); flags.addFlag("dump-trace", CLFlag("", "Dump debugging trace to " "given file (off when file name is \"\")")); // #endif // DP-specific flags // Arithmetic flags.addFlag("arith-new",CLFlag(false, "Use new arithmetic dp")); flags.addFlag("var-order", CLFlag(false, "Use simple variable order in arith")); flags.addFlag("ineq-delay", CLFlag(10, "Accumulate this many inequalities " "before processing")); // Arrays flags.addFlag("liftReadIte", CLFlag(true, "Lift read of ite")); // Quantifiers flags.addFlag("max-quant-inst", CLFlag(200, "The maximum number of" " naive instantiations")); flags.addFlag("quant-new", CLFlag(true, "Use new quantifier instantiation algorithm")); flags.addFlag("quant-lazy", CLFlag(false, "Instantiate lazily")); flags.addFlag("quant-sem-match", CLFlag(false, "Attempt to match semantically when instantiating")); flags.addFlag("quant-const-match", CLFlag(true, "When matching semantically, only match with constants")); flags.addFlag("quant-match-old", CLFlag(false, "Use the old match algorithm")); flags.addFlag("quant-inst-part", CLFlag(false, "Use partial instantiation")); flags.addFlag("quant-inst-mult", CLFlag(true, "Use multi-triggers in instantiation")); flags.addFlag("quant-trig-new", CLFlag(true, "Use new trig algorithms")); flags.addFlag("quant-max-inst", CLFlag(600, "The maximum number of instantiations")); flags.addFlag("quant-inst-end", CLFlag(true, "Use end heuristic")); flags.addFlag("quant-inst-lcache", CLFlag(true, "Cache instantiations")); flags.addFlag("quant-inst-gcache", CLFlag(false, "Cache instantiations")); flags.addFlag("quant-inst-true", CLFlag(true, "Ignore true instantiations")); flags.addFlag("quant-pullvar", CLFlag(false, "Pull out vars")); flags.addFlag("quant-trig-loop", CLFlag(0, "Trigger loop prevention method, 0, 1, 2")); flags.addFlag("quant-score", CLFlag(true, "Use instantiation level")); flags.addFlag("quant-polarity", CLFlag(true, "Use polarity ")); flags.addFlag("quant-equ", CLFlag(true, "Use equality matching")); flags.addFlag("quant-max-score", CLFlag(0, "Maximum initial dynamic score")); flags.addFlag("quant-inst-all", CLFlag(false, "try all possible instantiation eagerly")); flags.addFlag("quant-trans3", CLFlag(true, "Use trans heuristic")); flags.addFlag("quant-trans2", CLFlag(true, "Use trans2 heuristic")); flags.addFlag("quant-naive-num", CLFlag(100, "Maximum number to call niave instantiation")); //Bitvectors flags.addFlag("bv32-flag", CLFlag(false, "assume that all bitvectors are 32bits with no overflow")); flags.addFlag("bv-rewrite", CLFlag(true, "Rewrite bitvector expressions")); flags.addFlag("bv-concatnormal-rewrite", CLFlag(true, "Concat Normal Form rewrites")); flags.addFlag("bv-plusnormal-rewrite", CLFlag(true, "Bvplus Normal Form rewrites")); flags.addFlag("bv-rw-bitblast", CLFlag(false, "Rewrite while bit-blasting")); flags.addFlag("bv-cnf-bitblast", CLFlag(true,"Bitblast equalities in CNFconverter with +cnf")); flags.addFlag("bv-lhs-minus-rhs", CLFlag(false,"Do lhs-rhs=0 if both lhs/rhs are BVPLUS")); flags.addFlag("bv-pushnegation", CLFlag(true,"pushnegation to the leaves")); // Uninterpreted Functions flags.addFlag("trans-closure", CLFlag(false,"enables transitive closure of binary relations")); // Datatypes flags.addFlag("dt-smartsplits", CLFlag(true, "enables smart splitting in datatype theory")); flags.addFlag("dt-lazy", CLFlag(false, "lazy splitting on datatypes")); return flags; } ValidityChecker* ValidityChecker::create() { return new VCL(createFlags()); } /////////////////////////////////////////////////////////////////////////////// // VCL private methods /////////////////////////////////////////////////////////////////////////////// Theorem3 VCL::deriveClosure(const Theorem3& thm) { vector assump; set assumpSet; // Compute the vector of assumptions for thm, and iteratively move // the assumptions to the RHS until done. Each closure step may // introduce new assumptions from the proofs of TCCs, so those need // to be dealt with in the same way, until no assumptions remain. Theorem3 res = thm; vector tccs; while(true) { { const Assumptions& a(res.getAssumptionsRef()); if (a.empty()) break; assump.clear(); assumpSet.clear(); Assumptions::iterator i=a.begin(), iend=a.end(); if(i!=iend) i->clearAllFlags(); // Collect the assumptions of 'res' *without* TCCs for(; i!=iend; ++i) getAssumptionsRec(*i, assumpSet, false); // Build the vectors of assumptions and TCCs if(getFlags()["tcc"].getBool()) { tccs.clear(); for(set::iterator i=assumpSet.begin(), iend=assumpSet.end(); i!=iend; ++i) { assump.push_back(i->thm().getExpr()); tccs.push_back(i->tcc()); } } } // Derive the closure res = d_se->getCommonRules()->implIntro3(res, assump, tccs); } return res; } //! Recursive assumption graph traversal to find user assumptions /*! * If an assumption has a TCC, traverse the proof of TCC and add its * assumptions to the set recursively. */ void VCL::getAssumptionsRec(const Theorem& thm, set& assumptions, bool addTCCs) { if(thm.isNull() || thm.isRefl() || thm.isFlagged()) return; thm.setFlag(); if(thm.isAssump()) { if(d_userAssertions->count(thm.getExpr())>0) { const UserAssertion& a = (*d_userAssertions)[thm.getExpr()]; assumptions.insert(a); if(addTCCs) { DebugAssert(!a.tcc().isNull(), "getAssumptionsRec(a=" +a.thm().toString()+", thm = "+thm.toString()+")"); getAssumptionsRec(a.tcc(), assumptions, true); } } else { // it's a splitter UserAssertion a(thm, Theorem(), d_nextIdx++); assumptions.insert(a); } } else { const Assumptions& a(thm.getAssumptionsRef()); for(Assumptions::iterator i=a.begin(), iend=a.end(); i!=iend; ++i) getAssumptionsRec(*i, assumptions, addTCCs); } } void VCL::getAssumptions(const Assumptions& a, vector& assumptions) { set assumpSet; if(a.empty()) return; Assumptions::iterator i=a.begin(), iend=a.end(); if(i!=iend) i->clearAllFlags(); for(; i!=iend; ++i) getAssumptionsRec(*i, assumpSet, getFlags()["tcc"].getBool()); // Order assumptions by their creation time for(set::iterator i=assumpSet.begin(), iend=assumpSet.end(); i!=iend; ++i) assumptions.push_back(i->thm().getExpr()); } IF_DEBUG( void VCL::dumpTrace(int scope) { vector fields; fields.push_back(strPair("scope", int2string(scope))); debugger.dumpTrace("scope", fields); } ) /////////////////////////////////////////////////////////////////////////////// // Public VCL methods /////////////////////////////////////////////////////////////////////////////// VCL::VCL(const CLFlags& flags) : d_flags(new CLFlags(flags)), d_nextIdx(0) { // Set the dependent flags so that they are consistent if ((*d_flags)["translate"].getBool()) d_flags->setFlag("printResults", false); IF_DEBUG( // Initialize the global debugger CVC3::debugger.init(&((*d_flags)["trace"].getStrVec()), &((*d_flags)["dump-trace"].getString())) ); d_cm = new ContextManager(); // Initialize the database of user assertions. It has to be // initialized after d_cm. d_userAssertions = new(true) CDMap(getCurrentContext()); d_em = new ExprManager(d_cm, *d_flags); d_tm = new TheoremManager(d_cm, d_em, *d_flags); d_em->setTM(d_tm); d_translator = new Translator(d_em, (*d_flags)["translate"].getBool(), (*d_flags)["real2int"].getBool(), (*d_flags)["convertArith"].getBool(), (*d_flags)["convert2diff"].getString(), (*d_flags)["iteLiftArith"].getBool(), (*d_flags)["expResult"].getString(), (*d_flags)["category"].getString(), (*d_flags)["convertArray"].getBool(), (*d_flags)["combineAssump"].getBool()); d_dump = d_translator->start((*d_flags)["dump-log"].getString()); d_theoryCore = new TheoryCore(d_cm, d_em, d_tm, d_translator, *d_flags, d_statistics); d_theories.push_back(d_theoryCore); // Fast rewriting of literals is done by setting their find to true or false. falseExpr().setFind(d_theoryCore->reflexivityRule(falseExpr())); trueExpr().setFind(d_theoryCore->reflexivityRule(trueExpr())); d_theories.push_back(d_theoryUF = new TheoryUF(d_theoryCore)); if ((*d_flags)["arith-new"].getBool()) { d_theories.push_back(d_theoryArith = new TheoryArithNew(d_theoryCore)); } else { d_theories.push_back(d_theoryArith = new TheoryArithOld(d_theoryCore)); } d_theories.push_back(d_theoryArray = new TheoryArray(d_theoryCore)); d_theories.push_back(d_theoryRecords = new TheoryRecords(d_theoryCore)); d_theories.push_back(d_theorySimulate = new TheorySimulate(d_theoryCore)); d_theories.push_back(d_theoryBitvector = new TheoryBitvector(d_theoryCore)); if ((*d_flags)["dt-lazy"].getBool()) { d_theories.push_back(d_theoryDatatype = new TheoryDatatypeLazy(d_theoryCore)); } else { d_theories.push_back(d_theoryDatatype = new TheoryDatatype(d_theoryCore)); } d_theories.push_back(d_theoryQuant = new TheoryQuant(d_theoryCore)); d_translator->setTheoryCore(d_theoryCore); d_translator->setTheoryUF(d_theoryUF); d_translator->setTheoryArith(d_theoryArith); d_translator->setTheoryArray(d_theoryArray); d_translator->setTheoryQuant(d_theoryQuant); d_translator->setTheoryRecords(d_theoryRecords); d_translator->setTheorySimulate(d_theorySimulate); d_translator->setTheoryBitvector(d_theoryBitvector); d_translator->setTheoryDatatype(d_theoryDatatype); // Must be created after TheoryCore, since it needs it. // When we have more than one search engine, select one to create // based on flags const string& satEngine = (*d_flags)["sat"].getString(); if (satEngine == "simple") d_se = new SearchSimple(d_theoryCore); else if (satEngine == "fast") d_se = new SearchEngineFast(d_theoryCore); else if (satEngine == "sat" || satEngine == "minisat") d_se = new SearchSat(d_theoryCore, satEngine); else throw CLException("Unrecognized SAT solver name: " +(*d_flags)["sat"].getString()); // Initial scope level should be 1 d_cm->push(); d_stackLevel = new(true) CDO(d_cm->getCurrentContext(), 0); d_theoryCore->setResourceLimit((unsigned)((*d_flags)["resource"].getInt())); myvcl = this; } VCL::~VCL() { popto(0); d_cm->popto(0); delete d_stackLevel; free(d_stackLevel); d_translator->finish(); delete d_translator; TRACE_MSG("delete", "Deleting SearchEngine {"); delete d_se; TRACE_MSG("delete", "Finished deleting SearchEngine }"); // This map contains expressions and theorems; delete it before // d_em, d_tm, and d_cm. TRACE_MSG("delete", "Deleting d_userAssertions {"); delete d_userAssertions; free(d_userAssertions); TRACE_MSG("delete", "Finished deleting d_userAssertions }"); // and set these to null so their destructors don't blow up d_lastQuery = Theorem3(); d_lastQueryTCC = Theorem(); d_lastClosure = Theorem3(); // Delete ExprManager BEFORE TheoremManager, since Exprs use Theorems TRACE_MSG("delete", "Clearing d_em {"); d_em->clear(); d_tm->clear(); TRACE_MSG("delete", "Finished clearing d_em }"); TRACE_MSG("delete", "Deleting d_cm {"); delete d_cm; TRACE_MSG("delete", "Finished deleting d_cm }"); for(size_t i=0; igetName()); TRACE("delete", "Deleting Theory[", name, "] {"); delete d_theories[i]; TRACE("delete", "Finished deleting Theory[", name, "] }"); } // TheoremManager does not call ~Theorem() destructors, and only // releases memory. At worst, we'll lose some Assumptions. TRACE_MSG("delete", "Deleting d_tm {"); delete d_tm; TRACE_MSG("delete", "Finished deleting d_tm }"); TRACE_MSG("delete", "Deleting d_em {"); delete d_em; TRACE_MSG("delete", "Finished deleting d_em }"); TRACE_MSG("delete", "Deleting d_flags [end of ~VCL()]"); delete d_flags; // No more TRACE-ing after this point (it needs d_flags) } void VCL::reprocessFlags() { if (d_se->getName() != (*d_flags)["sat"].getString()) { delete d_se; const string& satEngine = (*d_flags)["sat"].getString(); if (satEngine == "simple") d_se = new SearchSimple(d_theoryCore); else if (satEngine == "fast") d_se = new SearchEngineFast(d_theoryCore); else if (satEngine == "sat" || satEngine == "minisat") d_se = new SearchSat(d_theoryCore, satEngine); else throw CLException("Unrecognized SAT solver name: " +(*d_flags)["sat"].getString()); } if (d_theoryArith->getName() == "ArithmeticOld" && (*d_flags)["arith-new"].getBool()) { delete d_theoryArith; d_theoryArith = new TheoryArithNew(d_theoryCore); d_theories[2] = d_theoryArith; d_translator->setTheoryArith(d_theoryArith); } else if (d_theoryArith->getName() == "ArithmeticNew" && !(*d_flags)["arith-new"].getBool()) { delete d_theoryArith; d_theoryArith = new TheoryArithOld(d_theoryCore); d_theories[2] = d_theoryArith; d_translator->setTheoryArith(d_theoryArith); } //TODO: handle more flags } TheoryCore* VCL::core(){ return d_theoryCore; } Type VCL::boolType(){ return d_theoryCore->boolType(); } Type VCL::realType() { return d_theoryArith->realType(); } Type VCL::intType() { return d_theoryArith->intType(); } Type VCL::subrangeType(const Expr& l, const Expr& r) { return d_theoryArith->subrangeType(l, r); } Type VCL::subtypeType(const Expr& pred, const Expr& witness) { return d_theoryCore->newSubtypeExpr(pred, witness); } Type VCL::tupleType(const Type& type0, const Type& type1) { vector types; types.push_back(type0); types.push_back(type1); return d_theoryRecords->tupleType(types); } Type VCL::tupleType(const Type& type0, const Type& type1, const Type& type2) { vector types; types.push_back(type0); types.push_back(type1); types.push_back(type2); return d_theoryRecords->tupleType(types); } Type VCL::tupleType(const vector& types) { return d_theoryRecords->tupleType(types); } Type VCL::recordType(const string& field, const Type& type) { vector fields; vector kids; fields.push_back(field); kids.push_back(type); return Type(d_theoryRecords->recordType(fields, kids)); } Type VCL::recordType(const string& field0, const Type& type0, const string& field1, const Type& type1) { vector fields; vector kids; fields.push_back(field0); fields.push_back(field1); kids.push_back(type0); kids.push_back(type1); sort2(fields, kids); return Type(d_theoryRecords->recordType(fields, kids)); } Type VCL::recordType(const string& field0, const Type& type0, const string& field1, const Type& type1, const string& field2, const Type& type2) { vector fields; vector kids; fields.push_back(field0); fields.push_back(field1); fields.push_back(field2); kids.push_back(type0); kids.push_back(type1); kids.push_back(type2); sort2(fields, kids); return Type(d_theoryRecords->recordType(fields, kids)); } Type VCL::recordType(const vector& fields, const vector& types) { DebugAssert(fields.size() == types.size(), "VCL::recordType: number of fields is different \n" "from the number of types"); // Create copies of the vectors to sort them vector fs(fields); vector ts(types); sort2(fs, ts); return Type(d_theoryRecords->recordType(fs, ts)); } Type VCL::dataType(const string& name, const string& constructor, const vector& selectors, const vector& types) { vector constructors; constructors.push_back(constructor); vector > selectorsVec; selectorsVec.push_back(selectors); vector > typesVec; typesVec.push_back(types); return dataType(name, constructors, selectorsVec, typesVec); } Type VCL::dataType(const string& name, const vector& constructors, const vector >& selectors, const vector >& types) { return d_theoryDatatype->dataType(name, constructors, selectors, types); } void VCL::dataType(const vector& names, const vector >& constructors, const vector > >& selectors, const vector > >& types, vector& returnTypes) { d_theoryDatatype->dataType(names, constructors, selectors, types, returnTypes); } Type VCL::arrayType(const Type& typeIndex, const Type& typeData) { return ::arrayType(typeIndex, typeData); } Type VCL::bitvecType(int n) { return d_theoryBitvector->newBitvectorType(n); } Type VCL::funType(const Type& typeDom, const Type& typeRan) { return typeDom.funType(typeRan); } Type VCL::funType(const vector& typeDom, const Type& typeRan) { DebugAssert(typeDom.size() >= 1, "VCL::funType: missing domain types"); return Type::funType(typeDom, typeRan); } Type VCL::createType(const string& typeName) { if(d_dump) { d_translator->dump(Expr(TYPE, listExpr(idExpr(typeName)))); } return d_theoryCore->newTypeExpr(typeName); } Type VCL::createType(const string& typeName, const Type& def) { if (d_dump) { d_translator->dump(Expr(TYPE, idExpr(typeName), def.getExpr()), true); } return d_theoryCore->newTypeExpr(typeName, def); } Type VCL::lookupType(const string& typeName) { // TODO: check if it already exists return d_theoryCore->newTypeExpr(typeName); } Expr VCL::varExpr(const string& name, const Type& type) { // Check if the ofstream is open (as opposed to the command line flag) if(d_dump) { d_translator->dump(Expr(CONST, idExpr(name), type.getExpr())); } return d_theoryCore->newVar(name, type); } Expr VCL::varExpr(const string& name, const Type& type, const Expr& def) { // Check if the ofstream is open (as opposed to the command line flag) if(d_dump) { d_translator->dump(Expr(CONST, idExpr(name), type.getExpr(), def), true); } // Prove the TCCs of the definition if(getFlags()["tcc"].getBool()) { Type tpDef(def.getType()), tpVar(type); // Make sure that def is in the subtype of tpVar; that is, prove // FORALL (x: tpDef): x = def => typePred(tpVar)(x) if(tpDef != tpVar) { // Typecheck the base types if(getBaseType(tpDef) != getBaseType(type)) { throw TypecheckException("Type mismatch in constant definition:\n" "Constant "+name+ " is declared with type:\n " +type.toString() +"\nBut the type of definition is\n " +tpDef.toString()); } TRACE("tccs", "CONST def: "+name+" : "+tpVar.toString() +" := : ", tpDef, ";"); vector boundVars; boundVars.push_back(boundVarExpr(name, "tcc", tpDef)); Expr body(boundVars[0].eqExpr(def).impExpr(getTypePred(tpVar, boundVars[0]))); Expr quant(forallExpr(boundVars, body)); try { checkTCC(quant); } catch(TypecheckException&) { throw TypecheckException ("Type mismatch in constant definition:\n" "Constant "+name+ " is declared with type:\n " +type.toString() +"\nBut the type of definition is\n " +def.getType().toString() +"\n\n which is not a subtype of the constant"); } } } return d_theoryCore->newVar(name, type, def); } Expr VCL::boundVarExpr(const string& name, const string& uid, const Type& type) { return d_em->newBoundVarExpr(name, uid, type); } Expr VCL::lookupVar(const string& name, Type* type) { return d_theoryCore->lookupVar(name, type); } Type VCL::getType(const Expr& e) { return e.getType(); } Type VCL::getBaseType(const Expr& e) { return d_theoryCore->getBaseType(e); } Type VCL::getBaseType(const Type& t) { return d_theoryCore->getBaseType(t); } Expr VCL::getTypePred(const Type&t, const Expr& e) { return d_theoryCore->getTypePred(t, e); } Expr VCL::stringExpr(const string& str) { return getEM()->newStringExpr(str); } Expr VCL::idExpr(const string& name) { return Expr(ID, stringExpr(name)); } Expr VCL::listExpr(const vector& kids) { return Expr(RAW_LIST, kids, getEM()); } Expr VCL::listExpr(const Expr& e1) { return Expr(RAW_LIST, e1); } Expr VCL::listExpr(const Expr& e1, const Expr& e2) { return Expr(RAW_LIST, e1, e2); } Expr VCL::listExpr(const Expr& e1, const Expr& e2, const Expr& e3) { return Expr(RAW_LIST, e1, e2, e3); } Expr VCL::listExpr(const string& op, const vector& kids) { vector newKids; newKids.push_back(idExpr(op)); newKids.insert(newKids.end(), kids.begin(), kids.end()); return listExpr(newKids); } Expr VCL::listExpr(const string& op, const Expr& e1) { return Expr(RAW_LIST, idExpr(op), e1); } Expr VCL::listExpr(const string& op, const Expr& e1, const Expr& e2) { return Expr(RAW_LIST, idExpr(op), e1, e2); } Expr VCL::listExpr(const string& op, const Expr& e1, const Expr& e2, const Expr& e3) { vector kids; kids.push_back(idExpr(op)); kids.push_back(e1); kids.push_back(e2); kids.push_back(e3); return listExpr(kids); } void VCL::printExpr(const Expr& e) { printExpr(e, cout); } void VCL::printExpr(const Expr& e, ostream& os) { os << e << endl; } Expr VCL::parseExpr(const Expr& e) { return d_theoryCore->parseExprTop(e); } Type VCL::parseType(const Expr& e) { return Type(d_theoryCore->parseExpr(e)); } Expr VCL::importExpr(const Expr& e) { return d_em->rebuild(e); } Type VCL::importType(const Type& t) { return Type(d_em->rebuild(t.getExpr())); } Expr VCL::trueExpr() { return d_em->trueExpr(); } Expr VCL::falseExpr() { return d_em->falseExpr(); } Expr VCL::notExpr(const Expr& child) { return !child; } Expr VCL::andExpr(const Expr& left, const Expr& right) { return left && right; } Expr VCL::andExpr(const vector& children) { if (children.size() == 0) throw Exception("andExpr requires at least one child"); return Expr(AND, children); } Expr VCL::orExpr(const Expr& left, const Expr& right) { return left || right; } Expr VCL::orExpr(const vector& children) { if (children.size() == 0) throw Exception("orExpr requires at least one child"); return Expr(OR, children); } Expr VCL::impliesExpr(const Expr& hyp, const Expr& conc) { return hyp.impExpr(conc); } Expr VCL::iffExpr(const Expr& left, const Expr& right) { return left.iffExpr(right); } Expr VCL::eqExpr(const Expr& child0, const Expr& child1) { return child0.eqExpr(child1); } Expr VCL::iteExpr(const Expr& ifpart, const Expr& thenpart, const Expr& elsepart) { return ifpart.iteExpr(thenpart, elsepart); } Op VCL::createOp(const string& name, const Type& type) { if (!type.isFunction()) throw Exception("createOp: expected function type"); if(d_dump) { d_translator->dump(Expr(CONST, idExpr(name), type.getExpr())); } return d_theoryCore->newFunction(name, type, getFlags()["trans-closure"].getBool()); } Op VCL::createOp(const string& name, const Type& type, const Expr& def) { if (!type.isFunction()) throw TypecheckException ("Type error in createOp:\n" "Constant "+name+ " is declared with type:\n " +type.toString() +"\n which is not a function type"); if (getBaseType(type) != getBaseType(def.getType())) throw TypecheckException ("Type mismatch in createOp:\n" "Function "+name+ " is declared with type:\n " +type.toString() +"\nBut the type of definition is\n " +def.getType().toString() +"\n\n which does not match"); if(d_dump) { d_translator->dump(Expr(CONST, idExpr(name), type.getExpr(), def), true); } // Prove the TCCs of the definition if(getFlags()["tcc"].getBool()) { Type tpDef(def.getType()); // Make sure that def is within the subtype; that is, prove // FORALL (xs: argType): typePred_{return_type}(def(xs)) if(tpDef != type) { vector boundVars; for (int i = 0; i < type.arity()-1; ++i) { boundVars.push_back(d_em->newBoundVarExpr(type[i])); } Expr app = Expr(def.mkOp(), boundVars); Expr body(getTypePred(type[type.arity()-1], app)); Expr quant(forallExpr(boundVars, body)); Expr tcc = quant.andExpr(d_theoryCore->getTCC(quant)); // Query the subtyping formula bool typesMatch = true; try { checkTCC(tcc); } catch (TypecheckException&) { typesMatch = false; } if(!typesMatch) { throw TypecheckException ("Type mismatch in createOp:\n" "Function "+name+ " is declared with type:\n " +type.toString() +"\nBut the definition is\n " +def.toString() +"\n\nwhose type could not be proved to be a subtype"); } } } return d_theoryCore->newFunction(name, type, def); } Expr VCL::funExpr(const Op& op, const Expr& child) { return Expr(op, child); } Expr VCL::funExpr(const Op& op, const Expr& left, const Expr& right) { return Expr(op, left, right); } Expr VCL::funExpr(const Op& op, const Expr& child0, const Expr& child1, const Expr& child2) { return Expr(op, child0, child1, child2); } Expr VCL::funExpr(const Op& op, const vector& children) { return Expr(op, children); } Expr VCL::ratExpr(int n, int d) { DebugAssert(d != 0,"denominator cannot be 0"); return d_em->newRatExpr(Rational(n,d)); } Expr VCL::ratExpr(const string& n, const string& d, int base) { return d_em->newRatExpr(Rational(n.c_str(), d.c_str(), base)); } Expr VCL::ratExpr(const string& n, int base) { string::size_type pos = n.rfind("."); if (pos == string::npos) { return d_em->newRatExpr(Rational(n.c_str(), base)); } string afterdec = n.substr(pos+1); string beforedec = n.substr(0, pos); if (afterdec.size() == 0 || beforedec.size() == 0) { throw Exception("Cannot convert string to rational: "+n); } pos = beforedec.rfind("."); if (pos != string::npos) { throw Exception("Cannot convert string to rational: "+n); } Rational r = Rational(beforedec.c_str(), base); Rational fracPart = Rational(afterdec.c_str(), base); r = r + (fracPart / pow(afterdec.size(), base)); return d_em->newRatExpr(r); } Expr VCL::uminusExpr(const Expr& child) { return -child; } Expr VCL::plusExpr(const Expr& left, const Expr& right) { return left + right; } Expr VCL::minusExpr(const Expr& left, const Expr& right) { return left - right; } Expr VCL::multExpr(const Expr& left, const Expr& right) { return left * right; } Expr VCL::powExpr(const Expr& x, const Expr& n) { return ::powExpr(n, x); } Expr VCL::divideExpr(const Expr& num, const Expr& denom) { return ::divideExpr(num,denom); } Expr VCL::ltExpr(const Expr& left, const Expr& right) { return ::ltExpr(left, right); } Expr VCL::leExpr(const Expr& left, const Expr& right) { return ::leExpr(left, right); } Expr VCL::gtExpr(const Expr& left, const Expr& right) { return ::gtExpr(left, right); } Expr VCL::geExpr(const Expr& left, const Expr& right) { return ::geExpr(left, right); } Expr VCL::recordExpr(const string& field, const Expr& expr) { vector fields; vector kids; kids.push_back(expr); fields.push_back(field); return d_theoryRecords->recordExpr(fields, kids); } Expr VCL::recordExpr(const string& field0, const Expr& expr0, const string& field1, const Expr& expr1) { vector fields; vector kids; fields.push_back(field0); fields.push_back(field1); kids.push_back(expr0); kids.push_back(expr1); sort2(fields, kids); return d_theoryRecords->recordExpr(fields, kids); } Expr VCL::recordExpr(const string& field0, const Expr& expr0, const string& field1, const Expr& expr1, const string& field2, const Expr& expr2) { vector fields; vector kids; fields.push_back(field0); fields.push_back(field1); fields.push_back(field2); kids.push_back(expr0); kids.push_back(expr1); kids.push_back(expr2); sort2(fields, kids); return d_theoryRecords->recordExpr(fields, kids); } Expr VCL::recordExpr(const vector& fields, const vector& exprs) { DebugAssert(fields.size() > 0, "VCL::recordExpr()"); DebugAssert(fields.size() == exprs.size(),"VCL::recordExpr()"); // Create copies of the vectors to sort them vector fs(fields); vector es(exprs); sort2(fs, es); return d_theoryRecords->recordExpr(fs, es); } Expr VCL::recSelectExpr(const Expr& record, const string& field) { return d_theoryRecords->recordSelect(record, field); } Expr VCL::recUpdateExpr(const Expr& record, const string& field, const Expr& newValue) { return d_theoryRecords->recordUpdate(record, field, newValue); } Expr VCL::readExpr(const Expr& array, const Expr& index) { return Expr(READ, array, index); } Expr VCL::writeExpr(const Expr& array, const Expr& index, const Expr& newValue) { return Expr(WRITE, array, index, newValue); } Expr VCL::newBVConstExpr(const std::string& s, int base) { return d_theoryBitvector->newBVConstExpr(s, base); } Expr VCL::newBVConstExpr(const std::vector& bits) { return d_theoryBitvector->newBVConstExpr(bits); } Expr VCL::newBVConstExpr(const Rational& r, int len) { return d_theoryBitvector->newBVConstExpr(r, len); } Expr VCL::newConcatExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newConcatExpr(t1, t2); } Expr VCL::newConcatExpr(const std::vector& kids) { return d_theoryBitvector->newConcatExpr(kids); } Expr VCL::newBVExtractExpr(const Expr& e, int hi, int low) { return d_theoryBitvector->newBVExtractExpr(e, hi, low); } Expr VCL::newBVNegExpr(const Expr& t1) { return d_theoryBitvector->newBVNegExpr(t1); } Expr VCL::newBVAndExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVAndExpr(t1, t2); } Expr VCL::newBVAndExpr(const std::vector& kids) { return d_theoryBitvector->newBVAndExpr(kids); } Expr VCL::newBVOrExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVOrExpr(t1, t2); } Expr VCL::newBVOrExpr(const std::vector& kids) { return d_theoryBitvector->newBVOrExpr(kids); } Expr VCL::newBVXorExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVXorExpr(t1, t2); } Expr VCL::newBVXorExpr(const std::vector& kids) { return d_theoryBitvector->newBVXorExpr(kids); } Expr VCL::newBVXnorExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVXnorExpr(t1, t2); } Expr VCL::newBVXnorExpr(const std::vector& kids) { return d_theoryBitvector->newBVXnorExpr(kids); } Expr VCL::newBVNandExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVNandExpr(t1, t2); } Expr VCL::newBVNorExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVNorExpr(t1, t2); } Expr VCL::newBVLTExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVLTExpr(t1, t2); } Expr VCL::newBVLEExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVLEExpr(t1, t2); } Expr VCL::newBVSLTExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVSLTExpr(t1, t2); } Expr VCL::newBVSLEExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVSLEExpr(t1, t2); } Expr VCL::newSXExpr(const Expr& t1, int len) { return d_theoryBitvector->newSXExpr(t1, len); } Expr VCL::newBVUminusExpr(const Expr& t1) { return d_theoryBitvector->newBVUminusExpr(t1); } Expr VCL::newBVSubExpr(const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVSubExpr(t1, t2); } Expr VCL::newBVPlusExpr(int numbits, const std::vector& k) { return d_theoryBitvector->newBVPlusExpr(numbits, k); } Expr VCL::newBVMultExpr(int numbits, const Expr& t1, const Expr& t2) { return d_theoryBitvector->newBVMultExpr(numbits, t1, t2); } Expr VCL::newFixedLeftShiftExpr(const Expr& t1, int r) { return d_theoryBitvector->newFixedLeftShiftExpr(t1, r); } Expr VCL::newFixedConstWidthLeftShiftExpr(const Expr& t1, int r) { return d_theoryBitvector->newFixedConstWidthLeftShiftExpr(t1, r); } Expr VCL::newFixedRightShiftExpr(const Expr& t1, int r) { return d_theoryBitvector->newFixedRightShiftExpr(t1, r); } Expr VCL::tupleExpr(const vector& exprs) { DebugAssert(exprs.size() > 0, "VCL::tupleExpr()"); return d_theoryRecords->tupleExpr(exprs); } Expr VCL::tupleSelectExpr(const Expr& tuple, int index) { return d_theoryRecords->tupleSelect(tuple, index); } Expr VCL::tupleUpdateExpr(const Expr& tuple, int index, const Expr& newValue) { return d_theoryRecords->tupleUpdate(tuple, index, newValue); } Expr VCL::datatypeConsExpr(const string& constructor, const vector& args) { return d_theoryDatatype->datatypeConsExpr(constructor, args); } Expr VCL::datatypeSelExpr(const string& selector, const Expr& arg) { return d_theoryDatatype->datatypeSelExpr(selector, arg); } Expr VCL::datatypeTestExpr(const string& constructor, const Expr& arg) { return d_theoryDatatype->datatypeTestExpr(constructor, arg); } Expr VCL::forallExpr(const vector& vars, const Expr& body) { DebugAssert(vars.size() > 0, "VCL::andExpr()"); return d_em->newClosureExpr(FORALL, vars, body); } Expr VCL::existsExpr(const vector& vars, const Expr& body) { return d_em->newClosureExpr(EXISTS, vars, body); } Op VCL::lambdaExpr(const vector& vars, const Expr& body) { return d_em->newClosureExpr(LAMBDA, vars, body).mkOp(); } Expr VCL::simulateExpr(const Expr& f, const Expr& s0, const vector& inputs, const Expr& n) { vector kids; kids.push_back(f); kids.push_back(s0); kids.insert(kids.end(), inputs.begin(), inputs.end()); kids.push_back(n); return Expr(SIMULATE, kids); } void VCL::setResourceLimit(unsigned limit) { d_theoryCore->setResourceLimit(limit); } Theorem VCL::checkTCC(const Expr& tcc) { Theorem tccThm; d_se->push(); QueryResult res = d_se->checkValid(tcc, tccThm); switch (res) { case VALID: d_lastQueryTCC = tccThm; d_se->pop(); break; case INVALID: throw TypecheckException("Failed TCC:\n\n " +tcc.toString() +"\n\nWhich simplified to:\n\n " +simplify(tcc).toString() +"\n\nAnd the last formula is not valid " "in the current context."); case ABORT: throw TypecheckException("Budget exceeded:\n\n " "Unable to verify TCC:\n\n " +tcc.toString() +"\n\nWhich simplified to:\n\n " +simplify(tcc).toString()); case UNKNOWN: throw TypecheckException("Result unknown:\n\n " "Unable to verify TCC:\n\n " +tcc.toString() +"\n\nWhich simplified to:\n\n " +simplify(tcc).toString() +"\n\nAnd the last formula is unknown " "in the current context."); default: FatalAssert(false, "Unexpected case"); } return tccThm; } void VCL::assertFormula(const Expr& e) { // Typecheck the user input if(!e.getType().isBool()) { throw TypecheckException("Non-BOOLEAN formula in ASSERT:\n " +Expr(ASSERT, e).toString() +"\nDerived type of the formula:\n " +e.getType().toString()); } // Check if the ofstream is open (as opposed to the command line flag) if(d_dump) { if (d_translator->dumpAssertion(e)) return; } TRACE("assetFormula", "VCL::assertFormula(", e, ") {"); // See if e was already asserted before if(d_userAssertions->count(e) > 0) { TRACE_MSG("assertFormula", "VCL::assertFormula[repeated assertion] => }"); return; } // Check the validity of the TCC Theorem tccThm; if(getFlags()["tcc"].getBool()) { Expr tcc(d_theoryCore->getTCC(e)); tccThm = checkTCC(tcc); } Theorem thm = d_se->newUserAssumption(e); (*d_userAssertions)[e] = UserAssertion(thm, tccThm, d_nextIdx++); TRACE_MSG("assertFormula", "VCL::assertFormula => }"); } void VCL::registerAtom(const Expr& e) { //TODO: add to interactive interface d_se->registerAtom(e); } Expr VCL::getImpliedLiteral() { //TODO: add to interactive interface Theorem thm = d_se->getImpliedLiteral(); if (thm.isNull()) return Expr(); return thm.getExpr(); } Expr VCL::simplify(const Expr& e) { //TODO: add to interactive interface return simplifyThm(e).getRHS(); } Theorem VCL::simplifyThm(const Expr& e) { e.getType(); Theorem res = d_theoryCore->getExprTrans()->preprocess(e); Theorem simpThm = d_theoryCore->simplify(res.getRHS()); res = d_theoryCore->transitivityRule(res, simpThm); return res; } QueryResult VCL::query(const Expr& e) { TRACE("query", "VCL::query(", e,") {"); // Typecheck the user input if(!e.getType().isBool()) { throw TypecheckException("Non-BOOLEAN formula in QUERY:\n " +Expr(QUERY, e).toString() +"\nDerived type of the formula:\n " +e.getType().toString()); } if(d_dump) { if (d_translator->dumpQuery(e)) return UNKNOWN; } // Check the validity of the TCC Theorem tccThm = d_se->getCommonRules()->trueTheorem(); if(getFlags()["tcc"].getBool()) { Expr tcc(d_theoryCore->getTCC(e)); // FIXME: we have to guarantee that the TCC of 'tcc' is always valid tccThm = checkTCC(tcc); } Theorem res; QueryResult qres = d_se->checkValid(e, res); switch (qres) { case VALID: d_lastQuery = d_se->getCommonRules()->queryTCC(res, tccThm); break; default: d_lastQueryTCC = Theorem(); d_lastQuery = Theorem3(); d_lastClosure = Theorem3(); } TRACE("query", "VCL::query => ", qres == VALID ? "VALID" : qres == INVALID ? "INVALID" : qres == ABORT ? "ABORT" : "UNKNOWN", " }"); if (d_dump) d_translator->dumpQueryResult(qres); return qres; } QueryResult VCL::checkUnsat(const Expr& e) { return query(e.negate()); } QueryResult VCL::checkContinue() { if(d_dump) { d_translator->dump(d_em->newLeafExpr(CONTINUE), true); } vector assertions; d_se->getCounterExample(assertions); Theorem thm; if (assertions.size() == 0) { return d_se->restart(falseExpr(), thm); } Expr eAnd = assertions.size() == 1 ? assertions[0] : andExpr(assertions); return d_se->restart(!eAnd, thm); } QueryResult VCL::restart(const Expr& e) { if (d_dump) { d_translator->dump(Expr(RESTART, e), true); } Theorem thm; return d_se->restart(e, thm); } void VCL::returnFromCheck() { //TODO: add to interactive interface d_se->returnFromCheck(); } void VCL::getUserAssumptions(vector& assumptions) { // TODO: add to interactive interface d_se->getUserAssumptions(assumptions); } void VCL::getInternalAssumptions(vector& assumptions) { // TODO: add to interactive interface d_se->getInternalAssumptions(assumptions); } void VCL::getAssumptions(vector& assumptions) { if(d_dump) { d_translator->dump(d_em->newLeafExpr(ASSUMPTIONS), true); } d_se->getAssumptions(assumptions); } void VCL::getAssumptionsUsed(vector& assumptions) { if(d_dump) { d_translator->dump(d_em->newLeafExpr(DUMP_ASSUMPTIONS), true); } Theorem thm = d_se->lastThm(); if (thm.isNull()) return; thm.getLeafAssumptions(assumptions); } void VCL::getCounterExample(vector& assertions, bool inOrder) { if(d_dump) { d_translator->dump(d_em->newLeafExpr(COUNTEREXAMPLE), true); } if (!(*d_flags)["translate"].getBool()) d_se->getCounterExample(assertions, inOrder); } void VCL::getConcreteModel(ExprMap & m) { if(d_dump) { d_translator->dump(d_em->newLeafExpr(COUNTERMODEL), true); } if (!(*d_flags)["translate"].getBool()) d_se->getConcreteModel(m); } bool VCL::inconsistent(vector& assumptions) { // TODO: add to interactive interface if (d_theoryCore->inconsistent()) { // TODO: do we need local getAssumptions? getAssumptions(d_theoryCore->inconsistentThm().getAssumptionsRef(), assumptions); return true; } return false; } bool VCL::incomplete() { // TODO: add to interactive interface // Return true only after a failed query return (d_lastQuery.isNull() && d_theoryCore->incomplete()); } bool VCL::incomplete(vector& reasons) { // TODO: add to interactive interface // Return true only after a failed query return (d_lastQuery.isNull() && d_theoryCore->incomplete(reasons)); } Proof VCL::getProof() { if(d_dump) { d_translator->dump(d_em->newLeafExpr(DUMP_PROOF), true); } if(d_lastQuery.isNull()) throw EvalException ("Method getProof() (or command DUMP_PROOF)\n" " must be called only after a Valid QUERY"); return d_se->getProof(); } Expr VCL::getTCC(){ static Expr null; if(d_dump) { d_translator->dump(d_em->newLeafExpr(DUMP_TCC), true); } if(d_lastQueryTCC.isNull()) return null; else return d_lastQueryTCC.getExpr(); } void VCL::getAssumptionsTCC(vector& assumptions) { if(d_dump) { d_translator->dump(d_em->newLeafExpr(DUMP_TCC_ASSUMPTIONS), true); } if(d_lastQuery.isNull()) throw EvalException ("Method getAssumptionsTCC() (or command DUMP_TCC_ASSUMPTIONS)\n" " must be called only after a Valid QUERY"); getAssumptions(d_lastQueryTCC.getAssumptionsRef(), assumptions); } Proof VCL::getProofTCC() { static Proof null; if(d_dump) { d_translator->dump(d_em->newLeafExpr(DUMP_TCC_PROOF), true); } if(d_lastQueryTCC.isNull()) return null; else return d_lastQueryTCC.getProof(); } Expr VCL::getClosure() { static Expr null; if(d_dump) { d_translator->dump(d_em->newLeafExpr(DUMP_CLOSURE), true); } if(d_lastClosure.isNull() && !d_lastQuery.isNull()) { // Construct the proof of closure and cache it in d_lastClosure d_lastClosure = deriveClosure(d_lastQuery); } if(d_lastClosure.isNull()) return null; else return d_lastClosure.getExpr(); } Proof VCL::getProofClosure() { static Proof null; if(d_dump) { d_translator->dump(d_em->newLeafExpr(DUMP_CLOSURE_PROOF), true); } if(d_lastClosure.isNull() && !d_lastQuery.isNull()) { // Construct the proof of closure and cache it in d_lastClosure d_lastClosure = deriveClosure(d_lastQuery); } if(d_lastClosure.isNull()) return null; else return d_lastClosure.getProof(); } int VCL::stackLevel() { return d_stackLevel->get(); } void VCL::push() { if(d_dump) { d_translator->dump(d_em->newLeafExpr(PUSH), true); } d_se->push(); d_stackLevel->set(stackLevel()+1); } void VCL::pop() { if(d_dump) { d_translator->dump(d_em->newLeafExpr(POP), true); } if (stackLevel() == 0) { throw EvalException ("POP called with no previous call to PUSH"); } int level = stackLevel(); while (level == stackLevel()) d_se->pop(); } void VCL::popto(int toLevel) { // Check if the ofstream is open (as opposed to the command line flag) if(d_dump) { d_translator->dump(Expr(POPTO, ratExpr(toLevel, 1)), true); } if (toLevel < 0) toLevel = 0; while (stackLevel() > toLevel) { d_se->pop(); } } int VCL::scopeLevel() { return d_cm->scopeLevel(); } void VCL::pushScope() { throw EvalException ("Scope-level push/pop is no longer supported"); d_cm->push(); if(d_dump) { d_translator->dump(d_em->newLeafExpr(PUSH_SCOPE), true); } IF_DEBUG(if((*d_flags)["dump-trace"].getString() != "") dumpTrace(scopeLevel())); } void VCL::popScope() { throw EvalException ("Scope-level push/pop is no longer supported"); if(d_dump) { d_translator->dump(d_em->newLeafExpr(POP_SCOPE), true); } if (scopeLevel() == 1) { cout << "Cannot POP from scope level 1" << endl; } else d_cm->pop(); IF_DEBUG(if((*d_flags)["dump-trace"].getString() != "") dumpTrace(scopeLevel())); } void VCL::poptoScope(int toLevel) { throw EvalException ("Scope-level push/pop is no longer supported"); if(d_dump) { d_translator->dump(Expr(POPTO_SCOPE, ratExpr(toLevel, 1)), true); } if (toLevel < 1) { d_cm->popto(0); d_cm->push(); } else d_cm->popto(toLevel); IF_DEBUG(if((*d_flags)["dump-trace"].getString() != "") dumpTrace(scopeLevel())); } Context* VCL::getCurrentContext() { return d_cm->getCurrentContext(); } void VCL::loadFile(const string& fileName, InputLanguage lang, bool interactive) { // TODO: move these? Parser parser(this, lang, interactive, fileName); VCCmd cmd(this, &parser); cmd.processCommands(); } void VCL::loadFile(istream& is, InputLanguage lang, bool interactive) { // TODO: move these? Parser parser(this, lang, is, interactive); VCCmd cmd(this, &parser); cmd.processCommands(); } unsigned long VCL::printMemory() { cout << "VCL: " << sizeof(VCL) + d_theories.size() * sizeof(Theory*) << endl; cout << "Context: " << d_cm->getMemory() << endl; return 0; // d_em->printMemory(); // d_tm->printMemory(); // d_translator->printMemory(); // d_se->printMemory(); // d_theoryCore->printMemory(); }