CVC3

theory_records.cpp

Go to the documentation of this file.
00001 /*****************************************************************************/
00002 /*!
00003  * \file theory_records.cpp
00004  * 
00005  * Author: Daniel Wichs
00006  * 
00007  * Created: 7/21/03
00008  *
00009  * <hr>
00010  *
00011  * License to use, copy, modify, sell and/or distribute this software
00012  * and its documentation for any purpose is hereby granted without
00013  * royalty, subject to the terms and conditions defined in the \ref
00014  * LICENSE file provided with this distribution.
00015  * 
00016  * <hr>
00017  * 
00018  */
00019 /*****************************************************************************/
00020 #include "theory_records.h"
00021 #include "typecheck_exception.h"
00022 #include "parser_exception.h"
00023 #include "smtlib_exception.h"
00024 #include "records_proof_rules.h"
00025 #include "theory_core.h"
00026 
00027 
00028 using namespace std;
00029 using namespace CVC3;
00030 
00031 /*!
00032  * When a record/tuple (dis)equality is expanded into the
00033  * (dis)equalities of fields, we have to perform rewrites on the
00034  * resulting record terms before the simplifier kicks in.  
00035  *
00036  * Otherwise, if we have r1.f = r2.f, but r1=r2 was asserted before,
00037  * for some complex record expressions r1 and r2, then the simplifier
00038  * will substitute r2 for r1, and we get r2.f=r2.f at the end, which
00039  * is not a useful fact to have.
00040  *
00041  * However, r1.f and/or r2.f may rewrite to something interesting, and
00042  * the equality may yield new important facts.
00043  */
00044 Theorem 
00045 TheoryRecords::rewriteAux(const Expr& e) {
00046   Theorem res;
00047   switch(e.getKind()) {
00048   case EQ:
00049   case IFF:
00050   case AND:
00051   case OR: {
00052     vector<unsigned> changed;
00053     vector<Theorem> thms;
00054     for(int i=0, iend=e.arity(); i<iend; ++i) {
00055       Theorem t(rewriteAux(e[i]));
00056       if(t.getLHS() != t.getRHS()) {
00057   changed.push_back(i);
00058   thms.push_back(t);
00059       }
00060     }
00061     if(thms.size() > 0) {
00062       res = substitutivityRule(e, changed, thms);
00063       // Need to guarantee that new expressions are fully simplified
00064       if(res.getRHS().hasFind())
00065   res = transitivityRule(res, res.getRHS().getFind());
00066     } else
00067       res = reflexivityRule(e);
00068     break;
00069   }
00070   case NOT: {
00071     vector<Theorem> thms;
00072     thms.push_back(rewriteAux(e[0]));
00073     if(thms[0].getLHS() != thms[0].getRHS()) {
00074       res = substitutivityRule(NOT, thms);
00075       // Need to guarantee that new expressions are fully simplified
00076       if(res.getRHS().hasFind())
00077   res = transitivityRule(res, res.getRHS().getFind());
00078     } else
00079       res = reflexivityRule(e);
00080     break;
00081   }
00082   default:
00083     res = rewrite(e);
00084     break;
00085   }
00086   return res;
00087 }
00088 
00089 
00090 Theorem 
00091 TheoryRecords::rewriteAux(const Theorem& thm) {
00092   return iffMP(thm, rewriteAux(thm.getExpr()));
00093 }
00094 
00095 
00096 TheoryRecords::TheoryRecords(TheoryCore* core)
00097   : Theory(core, "Records")
00098 {
00099 
00100   getEM()->newKind(RECORD_TYPE, "_RECORD_TYPE", true);
00101   getEM()->newKind(TUPLE_TYPE, "_TUPLE_TYPE", true);
00102 
00103   getEM()->newKind(RECORD, "_RECORD");
00104   getEM()->newKind(RECORD_SELECT, "_RECORD_SELECT");
00105   getEM()->newKind(RECORD_UPDATE, "_RECORD_UPDATE");
00106   getEM()->newKind(TUPLE, "_TUPLE");
00107   getEM()->newKind(TUPLE_SELECT, "_TUPLE_SELECT");
00108   getEM()->newKind(TUPLE_UPDATE, "_TUPLE_UPDATE");
00109 
00110   d_rules = createProofRules();
00111   vector<int> kinds;
00112 
00113   kinds.push_back(RECORD);
00114   kinds.push_back(RECORD_SELECT);
00115   kinds.push_back(RECORD_UPDATE);
00116   kinds.push_back(RECORD_TYPE);
00117   kinds.push_back(TUPLE_TYPE);
00118   kinds.push_back(TUPLE);
00119   kinds.push_back(TUPLE_SELECT);
00120   kinds.push_back(TUPLE_UPDATE);
00121 
00122   registerTheory(this, kinds);
00123 }
00124 
00125 TheoryRecords::~TheoryRecords() {
00126   delete d_rules;
00127 }
00128 
00129 void TheoryRecords::assertFact(const Theorem& e)
00130 {
00131   //  TRACE("records", "assertFact => ", e.toString(), "");
00132   const Expr& expr = e.getExpr();
00133   Theorem expanded;
00134   switch(expr.getKind()) {
00135   case IFF:
00136   case EQ: {
00137     int lhsKind = getBaseType(expr[0]).getExpr().getOpKind();
00138     if(lhsKind == RECORD_TYPE || lhsKind== TUPLE_TYPE)
00139       {
00140   expanded = rewriteAux(d_rules->expandEq(e));
00141   TRACE("records", "assertFact: enqueuing: ", expanded.toString(), "");
00142   enqueueFact(expanded);
00143       }
00144     return;
00145   }
00146   case NOT:
00147     DebugAssert(expr[0].getKind() == EQ || expr[0].getKind() == IFF,
00148                 "expecting a disequality or boolean field extraction: "
00149                 +expr.toString());
00150     break;
00151   default:
00152     DebugAssert(false, "TheoryRecords::assertFact expected an equation"
00153     " or negation of equation expression. Instead it got"
00154     + e.toString());
00155     
00156   }
00157       
00158 }
00159 
00160 
00161 Theorem TheoryRecords::rewrite(const Expr& e) {
00162   Theorem rw;
00163   TRACE("records", "rewrite(", e, ") {");
00164   bool needRecursion=false;
00165   switch(e.getOpKind()) {
00166   case TUPLE_SELECT:
00167   case RECORD_SELECT: {
00168     switch(e[0].getOpKind()){
00169     case RECORD:{
00170       rw = d_rules->rewriteLitSelect(e);
00171       break;
00172     }
00173     case TUPLE: {
00174       rw =   d_rules->rewriteLitSelect(e);
00175       break;
00176     }
00177     case RECORD_UPDATE: {
00178       rw = d_rules->rewriteUpdateSelect(e);
00179       needRecursion=true;
00180       break;
00181     }
00182     case TUPLE_UPDATE: {
00183       rw = d_rules->rewriteUpdateSelect(e);
00184       needRecursion=true;
00185       break;
00186     }
00187     default:{
00188       rw =  reflexivityRule(e);
00189       break;
00190     }
00191     }
00192     break;
00193   } 
00194   case RECORD_UPDATE: {
00195     DebugAssert(e.arity() == 2, 
00196     "TheoryRecords::rewrite(RECORD_UPDATE): e="+e.toString());
00197     if(e[0].getOpKind() == RECORD)
00198       rw= d_rules->rewriteLitUpdate(e);
00199     else
00200       rw =  reflexivityRule(e);
00201     break;
00202   }
00203   case TUPLE_UPDATE: {
00204     if(e[0].getOpKind() == TUPLE)
00205       rw = d_rules->rewriteLitUpdate(e);
00206     else
00207       rw =  reflexivityRule(e);
00208     break;
00209   }
00210   case RECORD:
00211   case TUPLE:
00212     rw = rewriteCC(e); // Congruence closure rewrites
00213     break;
00214   default: {
00215     rw = reflexivityRule(e);
00216     break;
00217   }   
00218   }
00219   Theorem res;
00220   if(needRecursion==true) res = transitivityRule(rw, rewrite(rw.getRHS()));
00221   else
00222     res = rw;
00223   TRACE("records", "rewrite => ", res.getRHS(), " }");
00224   return res;
00225 }
00226 
00227 
00228 Expr TheoryRecords::computeTCC(const Expr& e)
00229 {
00230   TRACE("records", "computeTCC( ", e, ")   {");
00231   Expr tcc(Theory::computeTCC(e));
00232   switch (e.getOpKind()) {
00233   case RECORD:
00234   case RECORD_SELECT:
00235   case TUPLE:
00236   case TUPLE_SELECT:
00237     break;
00238   case RECORD_UPDATE: {
00239     Expr tExpr = e.getType().getExpr();
00240     const std::string field(getField(e));
00241     int index = getFieldIndex(tExpr, field);
00242     Expr pred = getTypePred(e.getType()[index], e[1]);
00243     tcc = rewriteAnd(tcc.andExpr(pred)).getRHS();
00244     break;
00245   }
00246   case TUPLE_UPDATE: {
00247     Expr tExpr = e.getType().getExpr();
00248     int index = getIndex(e);
00249     Expr pred = getTypePred(e.getType()[index], e[1]);
00250     tcc = rewriteAnd(tcc.andExpr(pred)).getRHS();
00251     break;
00252   }
00253   default: {
00254     DebugAssert (false, "Theory records cannot calculate this tcc");
00255   }
00256   }
00257   TRACE("records", "computeTCC => ", tcc, "}");
00258   return tcc;
00259 }
00260 
00261 void TheoryRecords::computeModelTerm(const Expr& e, std::vector<Expr>& v) {
00262   Type t = e.getType();
00263   Expr tExpr  = t.getExpr();
00264   if(tExpr.getOpKind() == RECORD_TYPE) {
00265     const vector<Expr>& fields = getFields(tExpr);
00266     for(unsigned int i = 0; i < fields.size() ; i++) {
00267       Expr term(recordSelect(e, fields[i].getString()));
00268       term = rewrite(term).getRHS();
00269       v.push_back(term);
00270     }
00271   }
00272   else if(tExpr.getOpKind() == TUPLE_TYPE) {
00273     for(int i=0; i<tExpr.arity(); i++) {
00274       Expr term(tupleSelect(e, i));
00275       term = rewrite(term).getRHS();
00276       v.push_back(term);
00277     }
00278   }
00279 }
00280 
00281 void TheoryRecords::computeModel(const Expr& e, std::vector<Expr>& v) {
00282   Type t = getBaseType(e);
00283   Expr tExpr  = t.getExpr();
00284   vector<Theorem> thms;
00285   vector<unsigned> changed;
00286   Theorem asst;
00287   if(tExpr.getOpKind() == RECORD_TYPE)
00288     asst = d_rules->expandRecord(e);
00289   else if(tExpr.getOpKind() == TUPLE_TYPE)
00290     asst = d_rules->expandTuple(e);
00291   else {
00292     DebugAssert(false, "TheoryRecords::computeModel("+e.toString()+")");
00293     return;
00294   }
00295 
00296   const Expr& lit = asst.getRHS();
00297   int size(lit.arity());
00298   for(int i = 0; i < size ; i++) {
00299     Theorem thm(getModelValue(lit[i]));
00300     if(thm.getLHS() != thm.getRHS()) {
00301       thms.push_back(thm);
00302       changed.push_back(i);
00303     }
00304   }
00305   if(changed.size()>0)
00306     asst = transitivityRule(asst, substitutivityRule(lit, changed, thms));
00307   assignValue(asst);
00308   v.push_back(e);
00309 }
00310 
00311 
00312 Expr TheoryRecords::computeTypePred(const Type& t, const Expr& e)
00313 {
00314   TRACE("typePred", "ComputeTypePred[Records]", e, "");
00315   Expr tExpr = t.getExpr();
00316   switch(tExpr.getOpKind()) {
00317   case RECORD_TYPE: {
00318     const vector<Expr>& fields = getFields(tExpr);
00319     vector<Expr> fieldPreds;
00320     for(unsigned int i = 0; i<fields.size(); i++) {
00321       Expr sel(recordSelect(e, fields[i].getString()));
00322       fieldPreds.push_back(getTypePred(tExpr[i], sel));
00323     }
00324       Expr pred = andExpr(fieldPreds);
00325       TRACE("typePred", "Computed predicate ", pred, "");
00326       return pred;
00327   }
00328   case TUPLE_TYPE: {
00329     std::vector<Expr> fieldPreds;
00330     for(int i = 0; i<tExpr.arity(); i++) {
00331       fieldPreds.push_back(getTypePred(tExpr[i], tupleSelect(e, i)));
00332     }
00333     Expr pred = andExpr(fieldPreds);
00334     TRACE("typePred", "Computed predicate ", pred, "");
00335     return pred;    
00336   }
00337   default:
00338    DebugAssert(false, "computeTypePred[TheoryRecords] called with wrong type");
00339    return Expr();
00340   }
00341 }
00342 
00343 
00344 void TheoryRecords::checkType(const Expr& e)
00345 {
00346   switch (e.getOpKind()) {
00347     case RECORD_TYPE: {
00348       Expr::iterator i = e.begin(), iend = e.end();
00349       for (; i != iend; ) {
00350         Type t(*i);
00351         ++i;
00352         if (t.isBool()) throw Exception
00353             ("Records cannot contain BOOLEANs: "
00354              +e.toString());
00355         if (t.isFunction()) throw Exception
00356             ("Records cannot contain functions");
00357       }
00358       break;
00359     }
00360     case TUPLE_TYPE: {
00361       Expr::iterator i = e.begin(), iend = e.end();
00362       for (; i != iend; ) {
00363         Type t(*i);
00364         ++i;
00365         if (t.isBool()) throw Exception
00366             ("Tuples cannot contain BOOLEANs: "
00367              +e.toString());
00368         if (t.isFunction()) throw Exception
00369             ("Tuples cannot contain functions");
00370       }
00371       break;
00372     }
00373     default:
00374       DebugAssert(false, "Unexpected kind in TheoryRecords::checkType"
00375                   +getEM()->getKindName(e.getOpKind()));
00376   }
00377 }
00378 
00379 
00380 //TODO: implement finiteTypeInfo
00381 Cardinality TheoryRecords::finiteTypeInfo(Expr& e, Unsigned& n,
00382                                           bool enumerate, bool computeSize)
00383 {
00384   return CARD_UNKNOWN;
00385 }
00386 
00387 
00388 void TheoryRecords::computeType(const Expr& e)
00389 {
00390   switch (e.getOpKind()) {
00391   case RECORD:{
00392     DebugAssert(e.arity() > 0, "wrong arity of RECORD" + e.toString());
00393     vector<Expr> fieldTypes;
00394     const vector<Expr>& fields = getFields(e);
00395     string previous;
00396     DebugAssert((unsigned int)e.arity() == fields.size(),
00397     "size of fields does not match size of values");
00398     for(int i = 0; i<e.arity(); ++i) {
00399       DebugAssert(fields[i].getString() != previous, 
00400       "a record cannot not contain repeated fields"
00401       + e.toString());
00402       fieldTypes.push_back(e[i].getType().getExpr());
00403       previous=fields[i].getString();
00404     }
00405     e.setType(Type(recordType(fields, fieldTypes)));
00406     return;
00407   }
00408   case RECORD_SELECT: {
00409     DebugAssert(e.arity() == 1, "wrong arity of RECORD_SELECT" + e.toString());
00410     Expr t = e[0].getType().getExpr();
00411     const string& field = getField(e);
00412     DebugAssert(t.getOpKind() == RECORD_TYPE, "incorrect RECORD_SELECT expression"
00413     "first child not a RECORD_TYPE" + e.toString());
00414     int index = getFieldIndex(t, field);
00415     if(index==-1)
00416       throw TypecheckException("record selection does not match any field "
00417              "in record" + e.toString());
00418     e.setType(Type(t[index]));
00419     return;
00420   }
00421   case RECORD_UPDATE: {
00422     DebugAssert(e.arity() == 2, "wrong arity of RECORD_UPDATE" + e.toString());
00423     Expr t = e[0].getType().getExpr();
00424     const string& field = getField(e);
00425     DebugAssert(t.getOpKind() == RECORD_TYPE, "incorrect RECORD_SELECT expression"
00426     "first child not a RECORD_TYPE" + e.toString());
00427     int index = getFieldIndex(t, field);
00428     if(index==-1)
00429       throw TypecheckException
00430   ("record update field \""+field
00431    +"\" does not match any in record type:\n"
00432    +t.toString()+"\n\nThe complete expression is:\n\n"
00433    + e.toString());
00434     if(getBaseType(Type(t[index])) != getBaseType(e[1]))
00435       throw TypecheckException("Type checking error: \n"+ e.toString());
00436     e.setType(e[0].getType());
00437     return;
00438   }
00439   case TUPLE: {
00440     DebugAssert(e.arity() > 0, "wrong arity of TUPLE"+ e.toString());
00441     std::vector<Expr> types;
00442     for(Expr::iterator it = e.begin(), end=e.end(); it!=end; ++it)
00443       {
00444   types.push_back((*it).getType().getExpr());
00445       }
00446     e.setType(Type(Expr(TUPLE_TYPE, types, getEM())));
00447     return;
00448   }
00449   case TUPLE_SELECT: {
00450     DebugAssert(e.arity() == 1, "wrong arity of TUPLE_SELECT" + e.toString());
00451     Expr t = e[0].getType().getExpr();
00452     int index = getIndex(e);
00453     DebugAssert(t.getOpKind() == TUPLE_TYPE,
00454     "incorrect TUPLE_SELECT expression: "
00455     "first child is not a TUPLE_TYPE:\n\n" + e.toString());
00456     if(index >= t.arity())
00457       throw TypecheckException("tuple index exceeds number of fields: \n"
00458              + e.toString());
00459     e.setType(Type(t[index]));
00460     return;
00461   }
00462   case TUPLE_UPDATE: {
00463     DebugAssert(e.arity() == 2, "wrong arity of TUPLE_UPDATE" + e.toString());
00464     Expr t = e[0].getType().getExpr();
00465     int index = getIndex(e);
00466     DebugAssert(t.getOpKind() == TUPLE_TYPE, "incorrect TUPLE_SELECT expression: "
00467     "first child not a TUPLE_TYPE:\n\n" + e.toString());
00468     if(index >= t.arity())
00469       throw TypecheckException("tuple index exceeds number of fields: \n"
00470              + e.toString());
00471     if(getBaseType(Type(t[index])) != getBaseType(e[1]))
00472       throw TypecheckException("tuple update type mismatch: \n"+ e.toString());
00473     e.setType(e[0].getType());
00474     return;
00475   }
00476   default:
00477     DebugAssert(false,"Unexpected type: "+e.toString());
00478     break;
00479   }
00480 }
00481 
00482 
00483 Type
00484 TheoryRecords::computeBaseType(const Type& t) {
00485   const Expr& e = t.getExpr();
00486   Type res;
00487   switch(e.getOpKind()) {
00488   case TUPLE_TYPE:
00489   case RECORD_TYPE: {
00490     DebugAssert(e.arity() > 0, "Expected non-empty type");
00491     vector<Expr> kids;
00492     for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) {
00493       kids.push_back(getBaseType(Type(*i)).getExpr());
00494     }
00495     res = Type(Expr(e.getOp(), kids));
00496     break;
00497   }
00498   default:
00499     DebugAssert(false,
00500     "TheoryRecords::computeBaseType("+t.toString()+")");
00501     res = t;
00502   }
00503   return res;
00504 }
00505 
00506 
00507 void
00508 TheoryRecords::setup(const Expr& e) {
00509   // Only set up terms
00510   if (e.isTerm()) {
00511     switch(e.getOpKind()) {
00512     case RECORD:
00513     case TUPLE: // Setup for congruence closure
00514       setupCC(e);
00515       break;
00516     default: { // Everything else
00517       for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i)
00518   i->addToNotify(this, e);
00519       // Check if we have a tuple of record type, and set up those for CC
00520       Type tp(getBaseType(e));
00521       Theorem thm;
00522       if(isRecordType(tp)) // Expand e into its literal, and it setup for CC
00523   thm = d_rules->expandRecord(e);
00524       else if(isTupleType(tp))
00525   thm = d_rules->expandTuple(e);
00526       if(!thm.isNull()) {
00527   Expr lit(thm.getRHS());
00528   TRACE("records", "setup: lit = ", lit, "");
00529   // Simplify the kids
00530   vector<Theorem> thms;
00531   vector<unsigned> changed;
00532   for(int i=0,iend=lit.arity(); i<iend; ++i) {
00533     TRACE("records", "setup: rewriting lit["+int2string(i)+"] = ",
00534     lit[i], "");
00535     Theorem t = rewrite(lit[i]);
00536     t = transitivityRule(t, find(t.getRHS()));
00537     if(lit[i] != t.getRHS()) {
00538       thms.push_back(t);
00539       changed.push_back(i);
00540     }
00541   }
00542   if(changed.size()>0) {
00543     thm = transitivityRule(thm, substitutivityRule(lit, changed, thms));
00544     lit = thm.getRHS();
00545   }
00546   // Check if lit has already been setup
00547   if(lit.hasFind()) {
00548     enqueueFact(transitivityRule(thm, find(lit)));
00549   } else {
00550     theoryCore()->setupTerm(lit, this, thm);
00551     assertEqualities(symmetryRule(thm));
00552   }
00553       }
00554     }
00555     }
00556   }
00557 }
00558  
00559 
00560 void
00561 TheoryRecords::update(const Theorem& e, const Expr& d) {
00562   if (inconsistent()) return;
00563   DebugAssert(d.hasFind(), "Expected d to have find");
00564 
00565   switch(d.getOpKind()) {
00566   case RECORD:
00567   case TUPLE:
00568     // Record and tuple literals are handled by congruence closure updates
00569     updateCC(e, d);
00570     break;
00571   default: // Everything else
00572     // If d is not its own representative, don't do anything; the
00573     // representative will be sent to us eventually.
00574     if (find(d).getRHS() == d) {
00575       // Substitute e[1] for e[0] in d and assert the result equal to d
00576       Theorem thm = updateHelper(d);
00577       thm = transitivityRule(thm, rewrite(thm.getRHS()));
00578       assertEqualities(transitivityRule(thm, find(thm.getRHS())));
00579     }
00580   }
00581 }
00582 
00583 
00584 ExprStream& TheoryRecords::print(ExprStream& os, const Expr& e)
00585 {
00586    switch(os.lang()) {
00587    case PRESENTATION_LANG: {
00588      switch(e.getOpKind()){
00589      case TUPLE:{
00590        int i=0, iend=e.arity();
00591        os << "(" << push;
00592        if(i!=iend) os << e[i];
00593        ++i;
00594        for(; i!=iend; ++i) os << push << "," << pop << space << e[i];
00595        os << push << ")";
00596        break;
00597      }
00598      case TUPLE_TYPE: {
00599        int i=0, iend=e.arity();
00600        os << "[" << push;
00601        if(i!=iend) os << e[i];
00602        ++i;
00603        for(; i!=iend; ++i) os << push << "," << pop << space << e[i];
00604        os << push << "]";
00605        break;
00606      }
00607      case RECORD: {
00608        size_t i=0, iend=e.arity();
00609        if(!isRecord(e)) {
00610    e.printAST(os);
00611    break;
00612        }
00613        const vector<Expr>& fields = getFields(e);
00614        if(iend != fields.size()) {
00615    e.printAST(os); 
00616    break;
00617        }
00618        os << "(# " << push;
00619        if(i!=iend) {
00620    os <<  fields[i].getString() << space 
00621       << ":="<< space << push << e[i] << pop;
00622    ++i;
00623        }
00624        for(; i!=iend; ++i)
00625    os << push << "," << pop << space <<  fields[i].getString()
00626       << space 
00627       << ":="<< space << push << e[i] << pop;
00628        os << push << space << "#)";
00629        break;
00630      }
00631      case RECORD_TYPE: {
00632        size_t i=0, iend=e.arity();
00633        if(!isRecordType(e)) {
00634    e.printAST(os);
00635    break;
00636        }
00637        const vector<Expr>& fields = getFields(e);
00638        if(iend != fields.size()) {
00639    e.printAST(os); 
00640    break;
00641        }
00642        os << "[# " << push;
00643        if(i!=iend) {
00644    os <<  fields[i].getString() << ":"<< space << push << e[i] << pop;
00645    ++i;
00646        }
00647        for(; i!=iend; ++i)
00648    os << push << "," << pop << space <<  fields[i].getString()
00649       << ":"<< space << push << e[i] << pop;
00650        os << push << space << "#]";
00651        break;
00652      }
00653      case RECORD_SELECT:
00654        if(isRecordAccess(e) && e.arity() == 1)
00655    os << "(" << push <<  e[0] << push << ")" << "." << push 
00656       << getField(e);
00657        else
00658    e.printAST(os);
00659        break;
00660      case TUPLE_SELECT:
00661        if(isTupleAccess(e) && e.arity() == 1)
00662    os << "(" << push << e[0]  << push << ")" <<   "." << push 
00663       << getIndex(e);
00664        else
00665    e.printAST(os);
00666        break;
00667      case RECORD_UPDATE:
00668        if(isRecordAccess(e) && e.arity() == 2)
00669    os << "(" << push <<  e[0] << space << "WITH ."
00670       << push << getField(e)
00671       << space << ":=" << space << push << e[1] << push << ")";
00672        else
00673    e.printAST(os);
00674        break;
00675      case TUPLE_UPDATE:
00676        if(isTupleAccess(e) && e.arity() == 2)
00677    os << "(" << push <<  e[0] << space << "WITH ."
00678       << push << getIndex(e) 
00679       << space << ":=" << space << push << e[1] << push << ")";
00680        else
00681    e.printAST(os);
00682        break;
00683      default:
00684        e.printAST(os);
00685        break;
00686      }
00687      break;
00688    }
00689    case SMTLIB_LANG:
00690    case SMTLIB_V2_LANG: {
00691      d_theoryUsed = true;
00692      throw SmtlibException("TheoryRecords::print: SMTLIB not supported");
00693      switch(e.getOpKind()){
00694      case TUPLE:{
00695        int i=0, iend=e.arity();
00696        os << "(" << push << "TUPLE";
00697        for(; i<iend; ++i) os << space << e[i];
00698        os << push << ")";
00699        break;
00700      }
00701      case TUPLE_TYPE: { // FIXME: change to TUPLE_TYPE
00702        int i=0, iend=e.arity();
00703        os << "(" << push << "TUPLE_TYPE";
00704        for(; i!=iend; ++i) os << space << e[i];
00705        os << push << ")";
00706        break;
00707      }
00708      case RECORD: {
00709        size_t i=0, iend=e.arity();
00710        if(!isRecord(e)) {
00711    e.printAST(os);
00712    break;
00713        }
00714        const vector<Expr>& fields = getFields(e);
00715        if(iend != fields.size()) {
00716    e.printAST(os); 
00717    break;
00718        }
00719        os << "(" << push << "RECORD";
00720        for(; i!=iend; ++i)
00721    os <<  space << "(" << push << fields[i].getString() << space 
00722       << e[i] << push << ")" << pop << pop;
00723        os << push << ")";
00724        break;
00725      }
00726      case RECORD_TYPE: {
00727        size_t i=0, iend=e.arity();
00728        if(!isRecord(e)) {
00729    e.printAST(os);
00730    break;
00731        }
00732        const vector<Expr>& fields = getFields(e);
00733        if(iend != fields.size()) {
00734    e.printAST(os); 
00735    break;
00736        }
00737        os << "(" << push << "RECORD_TYPE";
00738        for(; i!=iend; ++i)
00739    os << space << "(" << push <<  fields[i].getString()
00740       << space << e[i] << push << ")" << pop << pop;
00741        os << push << space << ")";
00742        break;
00743      }
00744      case RECORD_SELECT:
00745        if(isRecordAccess(e))
00746    os << "(" << push << "RECORD_SELECT" << space 
00747       << e[0] << space << getField(e) << push << ")";
00748        else
00749    e.printAST(os);
00750        break;
00751      case TUPLE_SELECT:
00752        if(isTupleAccess(e))
00753    os << "(" << push << "TUPLE_SELECT" << space
00754       << e[0] << space << getIndex(e) << push << ")";
00755        else
00756    e.printAST(os);
00757        break;
00758      case RECORD_UPDATE:
00759        if(isRecordAccess(e) && e.arity() == 2)
00760    os << "(" << push << "RECORD_UPDATE" << space
00761       << e[0] << space << getField(e) 
00762       << space << e[1] << push << ")";
00763        else
00764    e.printAST(os);
00765        break;
00766      case TUPLE_UPDATE:
00767        if(isTupleAccess(e))
00768    os << "(" << push << "TUPLE_UPDATE" << space << e[0]
00769       << space << getIndex(e) 
00770       << space << e[1] << push << ")";
00771        else
00772    e.printAST(os);
00773        break;
00774      default:
00775        e.printAST(os);
00776        break;
00777      }
00778      break;
00779    }
00780    case LISP_LANG: {
00781      switch(e.getOpKind()){
00782      case TUPLE:{
00783        int i=0, iend=e.arity();
00784        os << "(" << push << "TUPLE";
00785        for(; i<iend; ++i) os << space << e[i];
00786        os << push << ")";
00787        break;
00788      }
00789      case TUPLE_TYPE: { // FIXME: change to TUPLE_TYPE
00790        int i=0, iend=e.arity();
00791        os << "(" << push << "TUPLE_TYPE";
00792        for(; i!=iend; ++i) os << space << e[i];
00793        os << push << ")";
00794        break;
00795      }
00796      case RECORD: {
00797        size_t i=0, iend=e.arity();
00798        if(!isRecord(e)) {
00799    e.printAST(os);
00800    break;
00801        }
00802        const vector<Expr>& fields = getFields(e);
00803        if(iend != fields.size()) {
00804    e.printAST(os); 
00805    break;
00806        }
00807        os << "(" << push << "RECORD";
00808        for(; i!=iend; ++i)
00809    os <<  space << "(" << push << fields[i].getString() << space 
00810       << e[i] << push << ")" << pop << pop;
00811        os << push << ")";
00812        break;
00813      }
00814      case RECORD_TYPE: {
00815        size_t i=0, iend=e.arity();
00816        if(!isRecord(e)) {
00817    e.printAST(os);
00818    break;
00819        }
00820        const vector<Expr>& fields = getFields(e);
00821        if(iend != fields.size()) {
00822    e.printAST(os); 
00823    break;
00824        }
00825        os << "(" << push << "RECORD_TYPE";
00826        for(; i!=iend; ++i)
00827    os << space << "(" << push <<  fields[i].getString()
00828       << space << e[i] << push << ")" << pop << pop;
00829        os << push << space << ")";
00830        break;
00831      }
00832      case RECORD_SELECT:
00833        if(isRecordAccess(e))
00834    os << "(" << push << "RECORD_SELECT" << space 
00835       << e[0] << space << getField(e) << push << ")";
00836        else
00837    e.printAST(os);
00838        break;
00839      case TUPLE_SELECT:
00840        if(isTupleAccess(e))
00841    os << "(" << push << "TUPLE_SELECT" << space
00842       << e[0] << space << getIndex(e) << push << ")";
00843        else
00844    e.printAST(os);
00845        break;
00846      case RECORD_UPDATE:
00847        if(isRecordAccess(e) && e.arity() == 2)
00848    os << "(" << push << "RECORD_UPDATE" << space
00849       << e[0] << space << getField(e)
00850       << space << e[1] << push << ")";
00851        else
00852    e.printAST(os);
00853        break;
00854      case TUPLE_UPDATE:
00855        if(isTupleAccess(e))
00856    os << "(" << push << "TUPLE_UPDATE" << space << e[0]
00857       << space << getIndex(e)
00858       << space << e[1] << push << ")";
00859        else
00860    e.printAST(os);
00861        break;
00862      default:
00863        e.printAST(os);
00864        break;
00865      }
00866      break;
00867    }
00868    default:
00869      e.printAST(os);
00870      break;
00871    }
00872    return os;
00873 }
00874 
00875 ///////////////////////////////////////////////////////////////////////////////
00876 //parseExprOp:
00877 //translating special Exprs to regular EXPR??
00878 ///////////////////////////////////////////////////////////////////////////////
00879 Expr
00880 TheoryRecords::parseExprOp(const Expr& e) {
00881   TRACE("parser", "TheoryRecords::parseExprOp(", e, ")");
00882   // If the expression is not a list, it must have been already
00883   // parsed, so just return it as is.
00884   if(RAW_LIST != e.getKind()) return e;
00885 
00886   DebugAssert(e.arity() > 0,
00887         "TheoryRecords::parseExprOp:\n e = "+e.toString());
00888   
00889   const Expr& c1 = e[0][0];
00890   const string& kindStr = c1.getString();
00891   int kind = e.getEM()->getKind(kindStr);
00892   switch(kind) {
00893   case RECORD_TYPE: // (RECORD_TYPE (f1 e1) (f2 e2) ...)
00894   case RECORD: {    // (RECORD      (f1 e1) (f2 e2) ...)
00895     if(e.arity() < 2)
00896       throw ParserException("Empty "+kindStr+": "+e.toString());
00897     vector<Expr> fields;
00898     vector<Expr> kids; 
00899     Expr::iterator i = e.begin(), iend=e.end();
00900     ++i;
00901     for(; i!=iend; ++i) {
00902       if(i->arity() != 2 || (*i)[0].getKind() != ID)
00903   throw ParserException("Bad field declaration in "+kindStr+": "
00904             +i->toString()+"\n in "+e.toString());
00905       fields.push_back((*i)[0][0]);
00906       kids.push_back(parseExpr((*i)[1]));
00907     }
00908     return (kind==RECORD)? recordExpr(fields, kids)
00909       : recordType(fields, kids).getExpr();
00910   }
00911   case RECORD_SELECT: { // (RECORD_SELECT e field)
00912     if(e.arity() != 3 || e[2].getKind() != ID)
00913       throw ParserException("Field must be an ID in RECORD_SELECT: "
00914           +e.toString());
00915     return recordSelect(parseExpr(e[1]), e[2][0].getString());
00916   }
00917   case RECORD_UPDATE: { // (RECORD_UPDATE e1 field e2)
00918     if(e.arity() != 4 || e[2].getKind() != ID)
00919       throw ParserException("Field must be an ID in RECORD_UPDATE: "
00920           +e.toString());
00921     return recordUpdate(parseExpr(e[1]), e[2][0].getString(), parseExpr(e[3]));
00922   }
00923   case TUPLE_SELECT:  { // (TUPLE_SELECT e index)
00924     if(e.arity() != 3 || !e[2].isRational() || !e[2].getRational().isInteger())
00925       throw ParserException("Index must be an integer in TUPLE_SELECT: "
00926           +e.toString());
00927     return tupleSelect(parseExpr(e[1]), e[2].getRational().getInt());
00928   }
00929   case TUPLE_UPDATE:  { // (TUPLE_UPDATE e1 index e2)
00930     if(e.arity() != 4 || !e[2].isRational() || !e[2].getRational().isInteger())
00931       throw ParserException("Index must be an integer in TUPLE_UPDATE: "
00932           +e.toString());
00933     return tupleUpdate(parseExpr(e[1]), e[2].getRational().getInt(),
00934            parseExpr(e[3]));
00935   }
00936   case TUPLE_TYPE:
00937   case TUPLE: {
00938     if(e.arity() < 2)
00939       throw ParserException("Empty "+kindStr+": "+e.toString());
00940     vector<Expr> k;
00941     Expr::iterator i = e.begin(), iend=e.end();
00942     // Skip first element of the vector of kids in 'e'.
00943     // The first element is the operator.
00944     ++i; 
00945     // Parse the kids of e and push them into the vector 'k'
00946     for(; i!=iend; ++i) 
00947       k.push_back(parseExpr(*i));
00948     return (kind==TUPLE)? tupleExpr(k) : tupleType(k).getExpr();
00949   }
00950   default:
00951     DebugAssert(false,
00952     "TheoryRecords::parseExprOp: invalid command or expression: " + e.toString());
00953     break;
00954   }
00955   return e;
00956 }
00957 
00958 
00959 //! Create a record literal
00960 Expr
00961 TheoryRecords::recordExpr(const std::vector<std::string>& fields,
00962         const std::vector<Expr>& kids) {
00963   vector<Expr> fieldExprs;
00964   vector<string>::const_iterator i = fields.begin(), iend = fields.end();
00965   for (; i != iend; ++i) fieldExprs.push_back(getEM()->newStringExpr(*i));
00966   return recordExpr(fieldExprs, kids);
00967 }
00968 
00969 Expr
00970 TheoryRecords::recordExpr(const std::vector<Expr>& fields,
00971         const std::vector<Expr>& kids) {
00972   return Expr(Expr(RECORD, fields).mkOp(), kids);
00973 }
00974 
00975 //! Create a record type
00976 Type
00977 TheoryRecords::recordType(const std::vector<std::string>& fields,
00978         const std::vector<Type>& types) {
00979   vector<Expr> kids;
00980   for(vector<Type>::const_iterator i=types.begin(), iend=types.end();
00981       i!=iend; ++i)
00982     kids.push_back(i->getExpr());
00983   return recordType(fields, kids);
00984 }
00985 
00986 //! Create a record type
00987 Type
00988 TheoryRecords::recordType(const std::vector<std::string>& fields,
00989         const std::vector<Expr>& types) {
00990   vector<Expr> fieldExprs;
00991   vector<string>::const_iterator i = fields.begin(), iend = fields.end();
00992   for (; i != iend; ++i) fieldExprs.push_back(getEM()->newStringExpr(*i));
00993   return recordType(fieldExprs, types);
00994 }
00995 
00996 Type
00997 TheoryRecords::recordType(const std::vector<Expr>& fields,
00998         const std::vector<Expr>& types) {
00999   return Type(Expr(Expr(RECORD_TYPE, fields).mkOp(), types));
01000 }
01001 
01002 //! Create a record field selector expression
01003 Expr
01004 TheoryRecords::recordSelect(const Expr& r, const std::string& field) {
01005   return Expr(getEM()->newSymbolExpr(field, RECORD_SELECT).mkOp(), r);
01006 }
01007 
01008 //! Create a record field update expression
01009 Expr
01010 TheoryRecords::recordUpdate(const Expr& r, const std::string& field,
01011           const Expr& val) {
01012   return Expr(getEM()->newSymbolExpr(field, RECORD_UPDATE).mkOp(), r, val);
01013 }
01014 
01015 //! Get the list of fields from a record literal
01016 const vector<Expr>&
01017 TheoryRecords::getFields(const Expr& r) {
01018   DebugAssert(r.isApply() &&
01019               (r.getOpKind() == RECORD || r.getOpKind() == RECORD_TYPE),
01020         "TheoryRecords::getFields: Not a record literal: "
01021         +r.toString(AST_LANG));
01022   return r.getOpExpr().getKids();
01023 }
01024 
01025 // Get the i-th field name from the record literal
01026 const string&
01027 TheoryRecords::getField(const Expr& r, int i) {
01028   DebugAssert(r.isApply() && 
01029               (r.getOpKind() == RECORD || r.getOpKind() == RECORD_TYPE),
01030         "TheoryRecords::getField: Not a record literal: "
01031         +r.toString());
01032   return r.getOpExpr()[i].getString();
01033 }
01034 
01035 // Get field index from the record literal
01036 int
01037 TheoryRecords::getFieldIndex(const Expr& e, const string& field) {
01038   const vector<Expr>& fields = getFields(e);
01039   for(size_t i=0, iend=fields.size(); i<iend; ++i) {
01040     if(fields[i].getString() == field) return i;
01041   }
01042   DebugAssert(false, "TheoryRecords::getFieldIndex(e="+e.toString()
01043         +", field="+field+"): field is not found");
01044   return -1;
01045 }
01046 
01047 //! Get the field name from the record select and update expressions
01048 const std::string&
01049 TheoryRecords::getField(const Expr& r) {
01050   DebugAssert(r.isApply() && (r.getOpKind() == RECORD_SELECT ||
01051                               r.getOpKind() == RECORD_UPDATE),
01052         "TheoryRecords::getField: Not a record literal: ");
01053   return r.getOpExpr().getName();
01054 }
01055 
01056 //! Create a tuple literal
01057 Expr
01058 TheoryRecords::tupleExpr(const std::vector<Expr>& kids) {
01059   return Expr(TUPLE, kids, getEM());
01060 }
01061 
01062 //! Create a tuple type
01063 Type
01064 TheoryRecords::tupleType(const std::vector<Type>& types) {
01065   vector<Expr> kids;
01066   for(vector<Type>::const_iterator i=types.begin(), iend=types.end();
01067       i!=iend; ++i)
01068     kids.push_back(i->getExpr());
01069   return Type(Expr(TUPLE_TYPE, kids, getEM()));
01070 }
01071 
01072 //! Create a tuple type
01073 Type
01074 TheoryRecords::tupleType(const std::vector<Expr>& types) {
01075   return Expr(TUPLE_TYPE, types, getEM());
01076 }
01077 
01078 //! Create a tuple index selector expression
01079 Expr
01080 TheoryRecords::tupleSelect(const Expr& tup, int i) {
01081   return Expr(Expr(TUPLE_SELECT, getEM()->newRatExpr(i)).mkOp(), tup);
01082 }
01083 
01084 //! Create a tuple index update expression
01085 Expr
01086 TheoryRecords::tupleUpdate(const Expr& tup, int i, const Expr& val) {
01087   return Expr(Expr(TUPLE_UPDATE, getEM()->newRatExpr(i)).mkOp(), tup, val);
01088 }
01089 
01090 //! Get the index from the tuple select and update expressions
01091 int
01092 TheoryRecords::getIndex(const Expr& r) {
01093   DebugAssert(r.isApply() && (r.getOpKind() == TUPLE_SELECT ||
01094                               r.getOpKind() == TUPLE_UPDATE),
01095         "TheoryRecords::getField: Not a record literal: ");
01096   return r.getOpExpr()[0].getRational().getInt();
01097 }