theory_array.cpp

Go to the documentation of this file.
00001 /*****************************************************************************/
00002 /*!
00003  * \file theory_array.cpp
00004  * 
00005  * Author: Clark Barrett
00006  * 
00007  * Created: Thu Feb 27 00:38:55 2003
00008  *
00009  * <hr>
00010  * Copyright (C) 2003 by the Board of Trustees of Leland Stanford
00011  * Junior University and by New York University. 
00012  *
00013  * License to use, copy, modify, sell and/or distribute this software
00014  * and its documentation for any purpose is hereby granted without
00015  * royalty, subject to the terms and conditions defined in the \ref
00016  * LICENSE file provided with this distribution.  In particular:
00017  *
00018  * - The above copyright notice and this permission notice must appear
00019  * in all copies of the software and related documentation.
00020  *
00021  * - THE SOFTWARE IS PROVIDED "AS-IS", WITHOUT ANY WARRANTIES,
00022  * EXPRESSED OR IMPLIED.  USE IT AT YOUR OWN RISK.
00023  * 
00024  * <hr>
00025  * 
00026  */
00027 /*****************************************************************************/
00028 
00029 
00030 #include "theory_array.h"
00031 #include "array_proof_rules.h"
00032 #include "typecheck_exception.h"
00033 #include "parser_exception.h"
00034 #include "smtlib_exception.h"
00035 #include "theory_core.h"
00036 #include "command_line_flags.h"
00037 
00038 
00039 using namespace std;
00040 using namespace CVCL;
00041 
00042 
00043 ///////////////////////////////////////////////////////////////////////////////
00044 // TheoryArray Private Methods                                               //
00045 ///////////////////////////////////////////////////////////////////////////////
00046 
00047 Theorem TheoryArray::renameExpr(const Expr& e) {
00048   Theorem thm = getCommonRules()->varIntroSkolem(e);
00049   DebugAssert(thm.isRewrite() && thm.getRHS().isSkolem(),
00050               "thm = "+thm.toString());
00051   theoryCore()->addToVarDB(thm.getRHS());
00052   return thm;
00053 }
00054 
00055 
00056 ///////////////////////////////////////////////////////////////////////////////
00057 // TheoryArray Public Methods                                                //
00058 ///////////////////////////////////////////////////////////////////////////////
00059 
00060 
00061 TheoryArray::TheoryArray(TheoryCore* core)
00062   : Theory(core, "Arrays"), d_reads(core->getCM()->getCurrentContext()),
00063     d_applicationsInModel(core->getFlags()["applications"].getBool())
00064 {
00065   d_rules = createProofRules();
00066 
00067   // Register new local kinds with ExprManager
00068   getEM()->newKind(ARRAY, "ARRAY", true);
00069   getEM()->newKind(READ, "READ");
00070   getEM()->newKind(WRITE, "WRITE");
00071   getEM()->newKind(ARRAY_LITERAL, "ARRAY_LITERAL");
00072 
00073   vector<int> kinds;
00074   kinds.push_back(ARRAY);
00075   kinds.push_back(READ);
00076   kinds.push_back(WRITE);
00077 
00078   kinds.push_back(ARRAY_LITERAL);
00079 
00080   registerTheory(this, kinds);
00081 }
00082 
00083 
00084 // Destructor: delete the proof rules class if it's present
00085 TheoryArray::~TheoryArray() {
00086   if(d_rules != NULL) delete d_rules;
00087 }
00088 
00089 
00090 Theorem TheoryArray::rewrite(const Expr& e)
00091 
00092 IF_DEBUG(
00093 {
00094   TRACE("rewrite array", "rewrite[Array](", e, ") {");
00095   Theorem res(rewriteDebug(e));
00096   TRACE("rewrite array", "rewrite[Array] => ", res.getExpr(), " }");
00097   return res;
00098 }
00099 
00100 Theorem TheoryArray::rewriteDebug(const Expr& e)
00101 ) // End of IF_DEBUG
00102 
00103 {
00104   Theorem thm;
00105   if (isRead(e)) {
00106     switch(e[0].getKind()) {
00107       case WRITE:
00108         thm = d_rules->rewriteReadWrite(e);
00109         return transitivityRule(thm, simplify(thm.getRHS()));
00110       case ARRAY_LITERAL: {
00111         Theorem res = d_rules->readArrayLiteral(e);
00112         // Simplify recursively
00113         res = transitivityRule(res, simplify(res.getRHS()));
00114         IF_DEBUG(debugger.counter("Read array literals")++);
00115         return res;
00116       }
00117       default: {
00118         const Theorem& rep = e.getRep();
00119         if (rep.isNull()) return reflexivityRule(e);
00120         else return symmetryRule(rep);
00121       }
00122     }
00123   }
00124   else if (!e.isTerm()) {
00125     if (e.isEq() && e[0].isAtomic() && e[1].isAtomic() && isWrite(e[0])) {
00126       Expr left = e[0], right = e[1];
00127       int leftWrites = 1, rightWrites = 0;
00128 
00129       // Count nested writes
00130       Expr e1 = left[0];
00131       while (isWrite(e1)) { leftWrites++; e1 = e1[0]; }
00132 
00133       Expr e2 = right;
00134       while (isWrite(e2)) { rightWrites++; e2 = e2[0]; }
00135 
00136       if (rightWrites == 0) {
00137         if (e1 == e2) {
00138           thm = d_rules->rewriteSameStore(e, leftWrites);
00139           return transitivityRule(thm, simplify(thm.getRHS()));
00140         }
00141         else {
00142           e.setRewriteNormal();
00143           return reflexivityRule(e);
00144         }
00145       }
00146 
00147       if (leftWrites > rightWrites) {
00148         thm = getCommonRules()->rewriteUsingSymmetry(e);
00149         thm = transitivityRule(thm, d_rules->rewriteWriteWrite(thm.getRHS()));
00150       }
00151       else thm = d_rules->rewriteWriteWrite(e);
00152       return transitivityRule(thm, simplify(thm.getRHS()));
00153     }
00154     e.setRewriteNormal();
00155     return reflexivityRule(e);
00156   }
00157   else if (!e.isAtomic()) {
00158     e.setRewriteNormal();
00159     return reflexivityRule(e);
00160   }
00161   else if (isWrite(e)) {
00162     Expr e1 = e[2].getType().isBool() ? e[2].iffExpr(Expr(READ, e[0], e[1])) :
00163                                        e[2].eqExpr(Expr(READ, e[0], e[1]));
00164     thm = simplify(e1);
00165     if (thm.getRHS().isTrue()) {
00166       return d_rules->rewriteRedundantWrite1(
00167                getCommonRules()->iffTrueElim(thm), e);
00168     }
00169     if (isWrite(e[0])) {
00170       if (e[0][1] == e[1]) {
00171         return d_rules->rewriteRedundantWrite2(e);
00172       }
00173       if (e[0][1] > e[1]) {
00174         thm = d_rules->interchangeIndices(e);
00175         return transitivityRule(thm, simplify(thm.getRHS()));
00176       }
00177     }
00178     return reflexivityRule(e);
00179   }
00180   // Do not set the rewriteNormal flag.  If we are called from
00181   // update(), this may be not our own term, and we have no reason to
00182   // claim it to be fully rewritten.
00183   // 
00184   // e.setRewriteNormal();
00185   return reflexivityRule(e);
00186 }
00187 
00188 
00189 void TheoryArray::setup(const Expr& e)
00190 {
00191   if (e.isNot() || e.isEq()) return;
00192   DebugAssert(e.isAtomic(), "e should be atomic");
00193   for (int k = 0; k < e.arity(); ++k) {
00194     e[k].addToNotify(this, e);
00195   }
00196   if (isRead(e)) {
00197     Theorem thm = reflexivityRule(e);
00198     e.setSig(thm);
00199     e.setRep(thm);
00200     // Record the read operator for concrete models
00201     TRACE("model", "TheoryArray: add array read ", e, "");
00202     d_reads.push_back(e);
00203   }
00204   else if (isWrite(e)) {
00205     // there is a hidden dependency of write(a,i,v) on read(a,i)
00206     Expr store = e[0];
00207     while (isWrite(store)) store = store[0];
00208     Expr r = simplifyExpr(Expr(READ, store, e[1]));
00209     theoryCore()->setupTerm(r, this);
00210     DebugAssert(r.isAtomic(), "Should be atomic");
00211     r.addToNotify(this, e);
00212   }
00213 }
00214 
00215 
00216 void TheoryArray::update(const Theorem& e, const Expr& d)
00217 {
00218   int k, ar(d.arity());
00219 
00220   if (isRead(d)) {
00221     const Theorem& dEQdsig = d.getSig();
00222     if (!dEQdsig.isNull()) {
00223       Expr dsig = dEQdsig.getRHS();
00224       Theorem thm = updateHelper(d);
00225       Expr sigNew = thm.getRHS();
00226       if (sigNew == dsig) return;
00227       dsig.setRep(Theorem());
00228       if (isWrite(sigNew[0])) {
00229         thm = transitivityRule(thm, d_rules->rewriteReadWrite(sigNew));
00230         Theorem renameTheorem = renameExpr(d);
00231         enqueueFact(transitivityRule(symmetryRule(renameTheorem), thm));
00232         d.setSig(Theorem());
00233         enqueueFact(renameTheorem);
00234       }
00235       else {
00236         const Theorem& repEQsigNew = sigNew.getRep();
00237         if (!repEQsigNew.isNull()) {
00238           d.setSig(Theorem());
00239           enqueueFact(transitivityRule(repEQsigNew, symmetryRule(thm)));
00240         }
00241         else {
00242           for (k = 0; k < ar; ++k) {
00243             if (sigNew[k] != dsig[k]) {
00244               sigNew[k].addToNotify(this, d);
00245             }
00246           }
00247           d.setSig(thm);
00248           sigNew.setRep(thm);
00249         }
00250       }
00251     }
00252   }
00253   else {
00254     DebugAssert(isWrite(d), "Expected write: d = "+d.toString());
00255     if (find(d).getRHS() == d) {
00256       Theorem thm = updateHelper(d);
00257       Expr sig0, sigNew;
00258       do {
00259         sig0 = thm.getRHS();
00260         thm = transitivityRule(thm, rewrite(sig0));
00261         sigNew = thm.getRHS();
00262       } while (sig0 != sigNew);
00263 
00264       if (d == sigNew) {
00265         // Must have been hidden dependency that changed.  Update notify list.
00266         e.getRHS().addToNotify(this, d);
00267       }
00268       else if (sigNew.isAtomic()) {
00269         enqueueEquality(thm);
00270       }
00271       else {
00272         Theorem renameTheorem = renameExpr(d);
00273         enqueueFact(transitivityRule(symmetryRule(renameTheorem), thm));
00274         enqueueEquality(renameTheorem);
00275       }
00276     }
00277   }
00278 }
00279 
00280 
00281 Theorem TheoryArray::solve(const Theorem& eThm)
00282 {
00283   const Expr& e = eThm.getExpr();
00284   DebugAssert(e.isEq(), "TheoryArray::solve("+e.toString()+")");
00285   if (isWrite(e[0])) {
00286     DebugAssert(!isWrite(e[1]), "Should have been rewritten: e = "
00287                 +e.toString());
00288     return symmetryRule(eThm);
00289   }
00290   return eThm;
00291 }
00292 
00293 
00294 void TheoryArray::checkType(const Expr& e)
00295 {
00296   switch (e.getKind()) {
00297     case ARRAY: {
00298       if (e.arity() != 2) throw Exception
00299           ("ARRAY type should have two arguments");
00300       Type t1(e[0]);
00301       if (t1.isBool()) throw Exception
00302           ("Array index types must be non-Boolean");
00303       if (t1.isFunction()) throw Exception
00304           ("Array index types cannot be functions");
00305       Type t2(e[1]);
00306       if (t2.isBool()) throw Exception
00307           ("Array value types must be non-Boolean");
00308       if (t2.isFunction()) throw Exception
00309           ("Array value types cannot be functions");
00310       break;
00311     }
00312     default:
00313       DebugAssert(false, "Unexpected kind in TheoryArray::checkType"
00314                   +getEM()->getKindName(e.getKind()));
00315   }
00316 
00317 }
00318 
00319 
00320 void TheoryArray::computeType(const Expr& e)
00321 {
00322   switch (e.getKind()) {
00323     case READ: {
00324       DebugAssert(e.arity() == 2,"");
00325       Type arrType = e[0].getType();
00326       Type idxType = getBaseType(e[1]);
00327       if (!isArray(arrType))
00328         throw TypecheckException
00329           ("Expected an ARRAY type in\n\n  "
00330            +e[0].toString()+"\n\nBut received this:\n\n  "
00331            +arrType.toString()+"\n\nIn the expression:\n\n  "
00332            +e.toString());
00333       if(getBaseType(arrType[0]) != idxType) {
00334         throw TypecheckException
00335           ("The type of index expression:\n\n  "
00336            +idxType.toString()
00337            +"\n\nDoes not match the ARRAY index type:\n\n  "
00338            +arrType[0].toString()
00339            +"\n\nIn the expression: "+e.toString());
00340       }
00341       e.setType(arrType[1]);
00342       break;
00343     }
00344     case WRITE: {
00345       DebugAssert(e.arity() == 3,"");
00346       Type arrType = e[0].getType();
00347       Type idxType = getBaseType(e[1]);
00348       Type valType = getBaseType(e[2]);
00349       // FIXME: reimplement this right when subtyping is introduced
00350       bool idxCorrect = getBaseType(arrType[0]) == idxType;
00351       bool valCorrect = getBaseType(arrType[1]) == valType;
00352       if (!isArray(arrType))
00353         throw TypecheckException
00354           ("Expected an ARRAY type in\n\n  "
00355            +e[0].toString()+"\n\nBut received this:\n\n  "
00356            +arrType.toString()+"\n\nIn the expression:\n\n  "
00357            +e.toString());
00358       if(!idxCorrect) {
00359         throw TypecheckException
00360           ("The type of index expression:\n\n  "
00361            +idxType.toString()
00362            +"\n\nDoes not match the ARRAY's type index:\n\n  "
00363            +arrType[0].toString()
00364            +"\n\nIn the expression: "+e.toString());
00365       }
00366       if(!valCorrect) {
00367         throw TypecheckException
00368           ("The type of value expression:\n\n  "
00369            +idxType.toString()
00370            +"\n\nDoes not match the ARRAY's value type:\n\n  "
00371            +arrType[1].toString()
00372            +"\n\nIn the expression: "+e.toString());
00373       }
00374       e.setType(arrType);
00375       break;
00376     }
00377     case ARRAY_LITERAL: {
00378       DebugAssert(e.isClosure(), "TheoryArray::computeType("+e.toString()+")");
00379       DebugAssert(e.getVars().size()==1,
00380                   "TheoryArray::computeType("+e.toString()+")");
00381       Type ind(e.getVars()[0].getType());
00382       e.setType(arrayType(ind, e.getBody().getType()));
00383       break;
00384     }
00385     default:
00386       DebugAssert(false,"Unexpected type");
00387       break;
00388   }
00389 }
00390 
00391 
00392 Type TheoryArray::computeBaseType(const Type& t) {
00393   const Expr& e = t.getExpr();
00394   DebugAssert(e.getKind()==ARRAY && e.arity() == 2,
00395               "TheoryArray::computeBaseType("+t.toString()+")");
00396   vector<Expr> kids;
00397   for(Expr::iterator i=e.begin(), iend=e.end(); i!=iend; ++i) {
00398     kids.push_back(getBaseType(Type(*i)).getExpr());
00399   }
00400   return Type(Expr(e.getOp(), kids));
00401 }
00402 
00403 
00404 void TheoryArray::computeModelTerm(const Expr& e, std::vector<Expr>& v) {
00405   switch(e.getKind()) {
00406   case WRITE:
00407     // a WITH [i] := v -- report a, i and v as the model terms.
00408 //     getModelTerm(e[1], v);
00409 //     getModelTerm(e[2], v);
00410     v.push_back(e[0]);
00411     v.push_back(e[1]);
00412     v.push_back(e[2]);
00413     break;
00414   case READ:
00415     // For a[i], add the index i
00416     // getModelTerm(e[1], v);
00417     v.push_back(e[1]);
00418     // And continue to collect the reads a[i][j] (remember, e is of
00419     // ARRAY type)
00420   default:
00421     // For array terms, find all their reads
00422     if(e.getType().getExpr().getKind() == ARRAY) {
00423       for(CDList<Expr>::const_iterator i=d_reads.begin(), iend=d_reads.end();
00424           i!=iend; ++i) {
00425         DebugAssert(isRead(*i) && (*i).arity()==2, "Bad array read: "
00426                     +(*i).toString());
00427         if((*i)[0] == e) {
00428           // Add both the read operator a[i]
00429           // getModelTerm(*i, v);
00430           v.push_back(*i);
00431       // and the index 'i' to the model terms.  Reason: the index to
00432       // the array should better be a concrete value, and it might not
00433       // necessarily be in the current list of model terms.
00434           // getModelTerm((*i)[1], v);
00435           v.push_back((*i)[1]);
00436         }
00437       }
00438     }
00439     break;
00440   }
00441 }
00442 
00443 
00444 void TheoryArray::computeModel(const Expr& e, std::vector<Expr>& v) {
00445   static unsigned count(0); // For bound vars
00446 
00447   switch(e.getKind()) {
00448   case WRITE: {
00449     // We should already have a value for the original array
00450     Expr res(getModelValue(e[0]).getRHS());
00451     Expr ind(getEM()->newBoundVarExpr("arr_var", int2string(count++)));
00452     Type tp(e.getType());
00453     DebugAssert(isArray(tp) && tp.arity()==2,
00454                 "TheoryArray::computeModel(WRITE)");
00455     ind.setType(tp[0]);
00456     res = rewrite(Expr(READ, res, ind)).getRHS();
00457     Expr indVal(getModelValue(e[1]).getRHS());
00458     Expr updVal(getModelValue(e[2]).getRHS());
00459     res = (ind.eqExpr(indVal)).iteExpr(updVal, res);
00460     res = arrayLiteral(ind, res);
00461     assignValue(e, res);
00462     v.push_back(e);
00463     break;
00464   }
00465 //   case READ: {
00466 //     // Get the assignment for the index
00467 //     Expr idx(getModelValue(e[1]).getRHS());
00468 //     // And the assignment for the 
00469 //     var = read(idxThm.getRHS(), e[0]);
00470 //   }
00471     // And continue to collect the reads a[i][j] (remember, e is of
00472     // ARRAY type)
00473   default: {
00474     // Assign 'e' a value later.
00475     v.push_back(e);
00476     // Map of e[i] to val for concrete values of i and val
00477     ExprHashMap<Expr> reads;
00478     // For array terms, find all their reads
00479     DebugAssert(getBaseType(e).getExpr().getKind() == ARRAY, "");
00480 
00481     for(CDList<Expr>::const_iterator i=d_reads.begin(), iend=d_reads.end();
00482         i!=iend; ++i) {
00483       TRACE("model", "TheoryArray::computeModel: read = ", *i, "");
00484       DebugAssert(isRead(*i) && (*i).arity()==2, "Bad array read: "
00485                   +(*i).toString());
00486       if((*i)[0] == e) {
00487         // Get the value of the index
00488         Theorem asst(getModelValue((*i)[1]));
00489         Expr var;
00490         if(asst.getLHS()!=asst.getRHS()) {
00491           vector<Theorem> thms;
00492           vector<unsigned> changed;
00493           thms.push_back(asst);
00494           changed.push_back(1);
00495           Theorem subst(substitutivityRule(*i, changed, thms));
00496           assignValue(transitivityRule(symmetryRule(subst),
00497                                        getModelValue(*i)));
00498           var = subst.getRHS();
00499         } else
00500           var = *i;
00501         if(d_applicationsInModel) v.push_back(var);
00502         // Record it in the map
00503         Expr val(getModelValue(var).getRHS());
00504         DebugAssert(!val.isNull(), "TheoryArray::computeModel(): Variable "
00505                     +var.toString()+" has a Null value");
00506         reads[var] = val;
00507       }
00508     }
00509     // Create an array literal
00510     if(reads.size()==0) { // Leave the array uninterpreted
00511       assignValue(reflexivityRule(e));
00512     } else {
00513       // Bound var for the index
00514       Expr ind(getEM()->newBoundVarExpr("arr_var", int2string(count++)));
00515       Type tp(e.getType());
00516       DebugAssert(isArray(tp) && tp.arity()==2,
00517                   "TheoryArray::computeModel(WRITE)");
00518       ind.setType(tp[0]);
00519       ExprHashMap<Expr>::iterator i=reads.begin(), iend=reads.end();
00520       DebugAssert(i!=iend,
00521                   "TheoryArray::computeModel(): expected the reads "
00522                   "table be non-empty");
00523       // Use one of the concrete values as a default
00524       Expr res((*i).second);
00525       ++i;
00526       DebugAssert(!res.isNull(), "TheoryArray::computeModel()");
00527       for(; i!=iend; ++i) {
00528         // Optimization: if the current value is the same as that of the
00529         // next application, skip this case; i.e. keep 'res' instead of
00530         // building ite(cond, res, res).
00531         if((*i).second == res) continue;
00532         // ITE condition
00533         Expr cond = ind.eqExpr((*i).first[1]);
00534         res = cond.iteExpr((*i).second, res);
00535       }
00536       // Construct the array literal
00537       res = arrayLiteral(ind, res);
00538       assignValue(e, res);
00539     }
00540     break;
00541   }
00542   }
00543 }
00544 
00545 
00546 Expr TheoryArray::computeTCC(const Expr& e)
00547 {
00548   Expr tcc(Theory::computeTCC(e));
00549   switch (e.getKind()) {
00550     case READ:
00551       DebugAssert(e.arity() == 2,"");
00552       return tcc.andExpr(getTypePred(e[0].getType()[0], e[1]));
00553     case WRITE: {
00554       DebugAssert(e.arity() == 3,"");
00555       Type arrType = e[0].getType();
00556       return rewriteAnd(getTypePred(arrType[0], e[1]).andExpr
00557                         (getTypePred(arrType[1], e[2])).andExpr(tcc)).getRHS();
00558     }
00559     case ARRAY_LITERAL: {
00560       return tcc;
00561     }
00562     default:
00563       DebugAssert(false,"TheoryArray::computeTCC: Unexpected expression: "
00564                   +e.toString());
00565       return tcc;
00566   }
00567 }
00568 
00569 
00570 ///////////////////////////////////////////////////////////////////////////////
00571 // Pretty-printing                                                           //
00572 ///////////////////////////////////////////////////////////////////////////////
00573 
00574 
00575 ExprStream& TheoryArray::print(ExprStream& os, const Expr& e) {
00576   switch(os.lang()) {
00577   case PRESENTATION_LANG:
00578     switch(e.getKind()) {
00579     case READ:
00580       if(e.arity() == 1)
00581         os << "[" << push << e[0] << push << "]";
00582       else
00583         os << e[0] << "[" << push << e[1] << push << "]";
00584       break;
00585     case WRITE:
00586       os << "(" << push << e[0] << space << "WITH [" 
00587          << push << e[1] << "] := " << push << e[2] << push << ")";
00588       break;
00589     case ARRAY:
00590       os << "ARRAY" << space << e[0] << space << "OF" << space << e[1];
00591       break;
00592     case ARRAY_LITERAL:
00593       if(e.isClosure()) {
00594         const vector<Expr>& vars = e.getVars();
00595         const Expr& body = e.getBody();
00596         os << "(" << push << "ARRAY" << space << "(" << push;
00597         bool first(true);
00598         for(size_t i=0; i<vars.size(); ++i) {
00599           if(first) first=false;
00600           else os << push << "," << pop << space;
00601           os << vars[i];
00602           if(vars[i].isVar())
00603             os << ":" << space << pushdag << vars[i].getType() << popdag;
00604         }
00605         os << push << "):" << pop << pop << space << body << push << ")";
00606       } else
00607         e.printAST(os);
00608       break;
00609     default:
00610       // Print the top node in the default LISP format, continue with
00611       // pretty-printing for children.
00612       e.printAST(os);
00613     }
00614     break; // end of case PRESENTATION_LANGUAGE
00615   case SMTLIB_LANG:
00616     d_theoryUsed = true;
00617     switch(e.getKind()) {
00618     case READ:
00619       if(e.arity() == 2)
00620         os << "(" << push << "select" << space << e[0]
00621            << space << e[1] << push << ")";
00622       else
00623         e.printAST(os);
00624       break;
00625     case WRITE:
00626       if(e.arity() == 3)
00627         os << "(" << push << "store" << space << e[0]
00628            << space << e[1] << space << e[2] << push << ")";
00629       else
00630         e.printAST(os);
00631       break;
00632     case ARRAY: // FIXME: change to ARRAY_TYPE
00633       os << "Array";
00634       break;      
00635     default:
00636       throw SmtlibException("TheoryArray::print: default not supported");
00637       // Print the top node in the default LISP format, continue with
00638       // pretty-printing for children.
00639       e.printAST(os);
00640     }
00641     break; // end of case LISP_LANGUAGE
00642   case LISP_LANG:
00643     switch(e.getKind()) {
00644     case READ:
00645       if(e.arity() == 2)
00646         os << "(" << push << "READ" << space << e[0]
00647            << space << e[1] << push << ")";
00648       else
00649         e.printAST(os);
00650       break;
00651     case WRITE:
00652       if(e.arity() == 3)
00653         os << "(" << push << "WRITE" << space << e[0]
00654            << space << e[1] << space << e[2] << push << ")";
00655       else
00656         e.printAST(os);
00657       break;
00658     case ARRAY: // FIXME: change to ARRAY_TYPE
00659       os << "(" << push << "ARRAY" << space << e[0]
00660          << space << e[1] << push << ")";
00661       break;      
00662     default:
00663       // Print the top node in the default LISP format, continue with
00664       // pretty-printing for children.
00665       e.printAST(os);
00666     }
00667     break; // end of case LISP_LANGUAGE
00668   default:
00669     // Print the top node in the default LISP format, continue with
00670     // pretty-printing for children.
00671     e.printAST(os);
00672   }
00673   return os;
00674 }
00675 
00676 //////////////////////////////////////////////////////////////////////////////
00677 //parseExprOp:
00678 //translating special Exprs to regular EXPR??
00679 ///////////////////////////////////////////////////////////////////////////////
00680 Expr
00681 TheoryArray::parseExprOp(const Expr& e) {
00682   TRACE("parser", "TheoryArray::parseExprOp(", e, ")");
00683   // If the expression is not a list, it must have been already
00684   // parsed, so just return it as is.
00685   if(RAW_LIST != e.getKind()) return e;
00686 
00687   DebugAssert(e.arity() > 0,
00688               "TheoryArray::parseExprOp:\n e = "+e.toString());
00689   
00690   const Expr& c1 = e[0][0];
00691   int kind = getEM()->getKind(c1.getString());
00692   switch(kind) {
00693     case READ: 
00694       if(!e.arity() == 3)
00695         throw ParserException("Bad array access expression: "+e.toString());
00696       return Expr(READ, parseExpr(e[1]), parseExpr(e[2]));
00697     case WRITE: 
00698       if(!e.arity() == 4)
00699         throw ParserException("Bad array update expression: "+e.toString());
00700       return Expr(WRITE, parseExpr(e[1]), parseExpr(e[2]), parseExpr(e[3]));
00701     case ARRAY: { 
00702       vector<Expr> k;
00703       Expr::iterator i = e.begin(), iend=e.end();
00704       // Skip first element of the vector of kids in 'e'.
00705       // The first element is the operator.
00706       ++i; 
00707       // Parse the kids of e and push them into the vector 'k'
00708       for(; i!=iend; ++i) 
00709         k.push_back(parseExpr(*i));
00710       return Expr(kind, k, e.getEM());
00711       break;
00712     }
00713     case ARRAY_LITERAL: { // (ARRAY (v tp1) body)
00714       if(!(e.arity() == 3 && e[1].getKind() == RAW_LIST && e[1].arity() == 2))
00715         throw ParserException("Bad ARRAY literal expression: "+e.toString());
00716       const Expr& varPair = e[1];
00717       if(varPair.getKind() != RAW_LIST)
00718         throw ParserException("Bad variable declaration block in ARRAY "
00719                               "literal expression: "+varPair.toString()+
00720                               "\n e = "+e.toString());
00721       if(varPair[0].getKind() != ID)
00722         throw ParserException("Bad variable declaration in ARRAY"
00723                               "literal expression: "+varPair.toString()+
00724                               "\n e = "+e.toString());
00725       Type varTp(parseExpr(varPair[1]));
00726       vector<Expr> var;
00727       var.push_back(addBoundVar(varPair[0][0].getString(), varTp));
00728       Expr body(parseExpr(e[2]));
00729       // Build the resulting Expr as (LAMBDA (vars) body)
00730       return getEM()->newClosureExpr(ARRAY_LITERAL, var, body);
00731       break;
00732     }
00733     default:
00734       DebugAssert(false,
00735                   "TheoryArray::parseExprOp: wrong type: "
00736                   + e.toString());
00737     break;
00738   }
00739   return e;
00740 }
00741 
00742 namespace CVCL {
00743 
00744 Expr arrayLiteral(const Expr& ind, const Expr& body) {
00745   vector<Expr> vars;
00746   vars.push_back(ind);
00747   return body.getEM()->newClosureExpr(ARRAY_LITERAL, vars, body);
00748 }
00749 
00750 } // end of namespace CVCL

Generated on Thu Apr 13 16:57:34 2006 for CVC Lite by  doxygen 1.4.4