TypeNode NodeManager::getDatatypeForTupleRecord(TypeNode t) { Assert(t.isTuple() || t.isRecord()); // if the type doesn't have an associated datatype, then make one for it TypeNode& dtt = d_tupleAndRecordTypes[t]; if(dtt.isNull()) { if(t.isTuple()) { Datatype dt("__cvc4_tuple"); DatatypeConstructor c("__cvc4_tuple_ctor"); for(TypeNode::const_iterator i = t.begin(); i != t.end(); ++i) { c.addArg("__cvc4_tuple_stor", (*i).toType()); } dt.addConstructor(c); dtt = TypeNode::fromType(toExprManager()->mkDatatypeType(dt)); Debug("tuprec") << "REWROTE " << t << " to " << dtt << std::endl; dtt.setAttribute(DatatypeTupleAttr(), t); } else { const Record& rec = t.getRecord(); Datatype dt("__cvc4_record"); DatatypeConstructor c("__cvc4_record_ctor"); for(Record::const_iterator i = rec.begin(); i != rec.end(); ++i) { c.addArg((*i).first, (*i).second); } dt.addConstructor(c); dtt = TypeNode::fromType(toExprManager()->mkDatatypeType(dt)); Debug("tuprec") << "REWROTE " << t << " to " << dtt << std::endl; dtt.setAttribute(DatatypeRecordAttr(), t); } } else { Debug("tuprec") << "REUSING cached " << t << ": " << dtt << std::endl; } Assert(!dtt.isNull()); return dtt; }
Node ModelPostprocessor::rewriteAs(TNode n, TypeNode asType) { if(n.getType().isSubtypeOf(asType)) { // good to go, we have the right type return n; } if(!n.isConst()) { // we don't handle non-const right now return n; } if(asType.isBoolean()) { if(n.getType().isBitVector(1u)) { // type mismatch: should only happen for Boolean-term conversion under // datatype constructor applications; rewrite from BV(1) back to Boolean bool tf = (n.getConst<BitVector>().getValue() == 1); return NodeManager::currentNM()->mkConst(tf); } if(n.getType().isDatatype() && n.getType().hasAttribute(BooleanTermAttr())) { // type mismatch: should only happen for Boolean-term conversion under // datatype constructor applications; rewrite from datatype back to Boolean Assert(n.getKind() == kind::APPLY_CONSTRUCTOR); Assert(n.getNumChildren() == 0); // we assume (by construction) false is first; see boolean_terms.cpp bool tf = (Datatype::indexOf(n.getOperator().toExpr()) == 1); Debug("boolean-terms") << "+++ rewriteAs " << n << " : " << asType << " ==> " << tf << endl; return NodeManager::currentNM()->mkConst(tf); } } if(n.getType().isBoolean()) { bool tf = n.getConst<bool>(); if(asType.isBitVector(1u)) { return NodeManager::currentNM()->mkConst(BitVector(1u, tf ? 1u : 0u)); } if(asType.isDatatype() && asType.hasAttribute(BooleanTermAttr())) { const Datatype& asDatatype = asType.getConst<Datatype>(); return NodeManager::currentNM()->mkNode(kind::APPLY_CONSTRUCTOR, (tf ? asDatatype[0] : asDatatype[1]).getConstructor()); } } if(n.getType().isRecord() && asType.isRecord()) { Debug("boolean-terms") << "+++ got a record - rewriteAs " << n << " : " << asType << endl; const Record& rec CVC4_UNUSED = n.getType().getConst<Record>(); const Record& asRec = asType.getConst<Record>(); Assert(rec.getNumFields() == asRec.getNumFields()); Assert(n.getNumChildren() == asRec.getNumFields()); NodeBuilder<> b(n.getKind()); b << asType; for(size_t i = 0; i < n.getNumChildren(); ++i) { b << rewriteAs(n[i], TypeNode::fromType(asRec[i].second)); } Node out = b; Debug("boolean-terms") << "+++ returning record " << out << endl; return out; }
TypeNode NodeManager::getDatatypeForTupleRecord(TypeNode t) { Assert(t.isTuple() || t.isRecord()); //AJR: not sure why .getBaseType() was used in two cases below, // disabling this, which is necessary to fix bug 605/667, // which involves records of INT which were mapped to records of REAL below. TypeNode tOrig = t; if(t.isTuple()) { vector<TypeNode> v; bool changed = false; for(size_t i = 0; i < t.getNumChildren(); ++i) { TypeNode tn = t[i]; TypeNode base; if(tn.isTuple() || tn.isRecord()) { base = getDatatypeForTupleRecord(tn); } else { base = tn;//.getBaseType(); } changed = changed || (tn != base); v.push_back(base); } if(changed) { t = mkTupleType(v); } } else { const Record& r = t.getRecord(); std::vector< std::pair<std::string, Type> > v; bool changed = false; const Record::FieldVector& fields = r.getFields(); for(Record::FieldVector::const_iterator i = fields.begin(); i != fields.end(); ++i) { Type tn = (*i).second; Type base; if(tn.isTuple() || tn.isRecord()) { base = getDatatypeForTupleRecord(TypeNode::fromType(tn)).toType(); } else { base = tn;//.getBaseType(); } changed = changed || (tn != base); v.push_back(std::make_pair((*i).first, base)); } if(changed) { t = mkRecordType(Record(v)); } } // if the type doesn't have an associated datatype, then make one for it TypeNode& dtt = d_tupleAndRecordTypes[t]; if(dtt.isNull()) { if(t.isTuple()) { Datatype dt("__cvc4_tuple"); DatatypeConstructor c("__cvc4_tuple_ctor"); for(TypeNode::const_iterator i = t.begin(); i != t.end(); ++i) { c.addArg("__cvc4_tuple_stor", (*i).toType()); } dt.addConstructor(c); dtt = TypeNode::fromType(toExprManager()->mkDatatypeType(dt)); Debug("tuprec") << "REWROTE " << t << " to " << dtt << std::endl; dtt.setAttribute(DatatypeTupleAttr(), tOrig); } else { const Record& rec = t.getRecord(); const Record::FieldVector& fields = rec.getFields(); Datatype dt("__cvc4_record"); DatatypeConstructor c("__cvc4_record_ctor"); for(Record::FieldVector::const_iterator i = fields.begin(); i != fields.end(); ++i) { c.addArg((*i).first, (*i).second); } dt.addConstructor(c); dtt = TypeNode::fromType(toExprManager()->mkDatatypeType(dt)); Debug("tuprec") << "REWROTE " << t << " to " << dtt << std::endl; dtt.setAttribute(DatatypeRecordAttr(), tOrig); } } else { Debug("tuprec") << "REUSING cached " << t << ": " << dtt << std::endl; } Assert(!dtt.isNull()); return dtt; }