/********************* */ /*! \file datatype.cpp ** \verbatim ** Top contributors (to current version): ** Andrew Reynolds, Morgan Deters, Tim King ** This file is part of the CVC4 project. ** Copyright (c) 2009-2019 by the authors listed in the file AUTHORS ** in the top-level source directory) and their institutional affiliations. ** All rights reserved. See the file COPYING in the top-level source ** directory for licensing information.\endverbatim ** ** \brief A class representing a Datatype definition ** ** A class representing a Datatype definition for the theory of ** inductive datatypes. **/ #include "expr/datatype.h" #include #include #include "base/check.h" #include "expr/attribute.h" #include "expr/dtype.h" #include "expr/expr_manager.h" #include "expr/expr_manager_scope.h" #include "expr/node.h" #include "expr/node_algorithm.h" #include "expr/node_manager.h" #include "expr/type.h" #include "expr/type_matcher.h" #include "options/datatypes_options.h" #include "options/set_language.h" #include "theory/type_enumerator.h" using namespace std; namespace CVC4 { Datatype::~Datatype() { ExprManagerScope ems(*d_em); d_internal.reset(); d_constructors.clear(); } Datatype::Datatype(ExprManager* em, std::string name, bool isCo) : d_em(em), d_internal(nullptr), d_record(NULL), d_isRecord(false), d_constructors() { ExprManagerScope ems(*d_em); d_internal = std::make_shared(name, isCo); } Datatype::Datatype(ExprManager* em, std::string name, const std::vector& params, bool isCo) : d_em(em), d_internal(nullptr), d_record(NULL), d_isRecord(false), d_constructors() { ExprManagerScope ems(*d_em); std::vector paramsn; for (const Type& t : params) { paramsn.push_back(TypeNode::fromType(t)); } d_internal = std::make_shared(name, paramsn, isCo); } const Datatype& Datatype::datatypeOf(Expr item) { ExprManagerScope ems(item); TypeNode t = Node::fromExpr(item).getType(); switch(t.getKind()) { case kind::CONSTRUCTOR_TYPE: return DatatypeType(t[t.getNumChildren() - 1].toType()).getDatatype(); case kind::SELECTOR_TYPE: case kind::TESTER_TYPE: return DatatypeType(t[0].toType()).getDatatype(); default: Unhandled() << "arg must be a datatype constructor, selector, or tester"; } } size_t Datatype::indexOf(Expr item) { ExprManagerScope ems(item); PrettyCheckArgument(item.getType().isConstructor() || item.getType().isTester() || item.getType().isSelector(), item, "arg must be a datatype constructor, selector, or tester"); return indexOfInternal(item); } size_t Datatype::indexOfInternal(Expr item) { TNode n = Node::fromExpr(item); if( item.getKind()==kind::APPLY_TYPE_ASCRIPTION ){ return indexOf( item[0] ); }else{ Assert(n.hasAttribute(DTypeIndexAttr())); return n.getAttribute(DTypeIndexAttr()); } } size_t Datatype::cindexOf(Expr item) { ExprManagerScope ems(item); PrettyCheckArgument(item.getType().isSelector(), item, "arg must be a datatype selector"); return cindexOfInternal(item); } size_t Datatype::cindexOfInternal(Expr item) { TNode n = Node::fromExpr(item); if( item.getKind()==kind::APPLY_TYPE_ASCRIPTION ){ return cindexOf( item[0] ); }else{ Assert(n.hasAttribute(DTypeConsIndexAttr())); return n.getAttribute(DTypeConsIndexAttr()); } } void Datatype::resolve(const std::map& resolutions, const std::vector& placeholders, const std::vector& replacements, const std::vector& paramTypes, const std::vector& paramReplacements) { PrettyCheckArgument(!isResolved(), this, "cannot resolve a Datatype twice"); PrettyCheckArgument(resolutions.find(getName()) != resolutions.end(), resolutions, "Datatype::resolve(): resolutions doesn't contain me!"); PrettyCheckArgument(placeholders.size() == replacements.size(), placeholders, "placeholders and replacements must be the same size"); PrettyCheckArgument(paramTypes.size() == paramReplacements.size(), paramTypes, "paramTypes and paramReplacements must be the same size"); PrettyCheckArgument(getNumConstructors() > 0, *this, "cannot resolve a Datatype that has no constructors"); // we're using some internals, so we have to make sure that the Datatype's // ExprManager is active ExprManagerScope ems(*d_em); Trace("datatypes") << "Datatype::resolve: " << getName() << ", #placeholders=" << placeholders.size() << std::endl; std::map resolutionsn; std::vector placeholdersn; std::vector replacementsn; std::vector paramTypesn; std::vector paramReplacementsn; for (const std::pair& r : resolutions) { resolutionsn[r.first] = TypeNode::fromType(r.second); } for (const Type& t : placeholders) { placeholdersn.push_back(TypeNode::fromType(t)); } for (const Type& t : replacements) { replacementsn.push_back(TypeNode::fromType(t)); } for (const Type& t : paramTypes) { paramTypesn.push_back(TypeNode::fromType(t)); } for (const Type& t : paramReplacements) { paramReplacementsn.push_back(TypeNode::fromType(t)); } bool res = d_internal->resolve(resolutionsn, placeholdersn, replacementsn, paramTypesn, paramReplacementsn); if (!res) { IllegalArgument(*this, "could not resolve datatype that is not well formed"); } Trace("dt-debug") << "Datatype::resolve: finished " << getName() << " " << d_constructors.size() << std::endl; AlwaysAssert(isResolved()); // d_self = d_internal->getTypeNode().toType(); for (DatatypeConstructor& c : d_constructors) { AlwaysAssert(c.isResolved()); c.d_constructor = c.d_internal->getConstructor().toExpr(); for (size_t i = 0, nargs = c.getNumArgs(); i < nargs; i++) { AlwaysAssert(c.d_args[i].isResolved()); c.d_args[i].d_selector = c.d_args[i].d_internal->getSelector().toExpr(); } } if( d_isRecord ){ std::vector< std::pair > fields; for( unsigned i=0; i<(*this)[0].getNumArgs(); i++ ){ fields.push_back( std::pair( (*this)[0][i].getName(), (*this)[0][i].getRangeType() ) ); } d_record.reset(new Record(fields)); } } void Datatype::addConstructor(const DatatypeConstructor& c) { Trace("dt-debug") << "Datatype::addConstructor" << std::endl; PrettyCheckArgument( !isResolved(), this, "cannot add a constructor to a finalized Datatype"); d_constructors.push_back(c); d_internal->addConstructor(c.d_internal); Trace("dt-debug") << "Datatype::addConstructor: finished" << std::endl; } void Datatype::setSygus( Type st, Expr bvl, bool allow_const, bool allow_all ){ PrettyCheckArgument( !isResolved(), this, "cannot set sygus type to a finalized Datatype"); // We can be in a case where the only rule specified was // (Constant T), in which case we have not yet added a constructor. We // ensure an arbitrary constant is added in this case. We additionally // add a constant if the grammar has only non-nullary constructors, since this // ensures the datatype is well-founded (see 3423). // Notice we only want to do this for sygus datatypes that are user-provided. // At the moment, the condition !allow_all implies the grammar is // user-provided and hence may require a default constant. // TODO (https://github.com/CVC4/cvc4-projects/issues/38): // In an API for SyGuS, it probably makes more sense for the user to // explicitly add the "any constant" constructor with a call instead of // passing a flag. This would make the block of code unnecessary. if (allow_const && !allow_all) { // if i don't already have a constant (0-ary constructor) bool hasConstant = false; for (unsigned i = 0, ncons = getNumConstructors(); i < ncons; i++) { if ((*this)[i].getNumArgs() == 0) { hasConstant = true; break; } } if (!hasConstant) { // add an arbitrary one Expr op = st.mkGroundTerm(); std::stringstream cname; cname << op; std::vector cargs; addSygusConstructor(op, cname.str(), cargs); } } TypeNode stn = TypeNode::fromType(st); Node bvln = Node::fromExpr(bvl); d_internal->setSygus(stn, bvln, allow_const, allow_all); } void Datatype::addSygusConstructor(Expr op, const std::string& cname, const std::vector& cargs, std::shared_ptr spc, int weight) { // avoid name clashes std::stringstream ss; ss << getName() << "_" << getNumConstructors() << "_" << cname; std::string name = ss.str(); unsigned cweight = weight >= 0 ? weight : (cargs.empty() ? 0 : 1); DatatypeConstructor c(name, cweight); c.setSygus(op, spc); for( unsigned j=0; j& cargs, std::shared_ptr spc, int weight) { ExprManagerScope ems(*d_em); Expr op = d_em->operatorOf(k); addSygusConstructor(op, cname, cargs, spc, weight); } void Datatype::setTuple() { PrettyCheckArgument( !isResolved(), this, "cannot set tuple to a finalized Datatype"); d_internal->setTuple(); } void Datatype::setRecord() { PrettyCheckArgument( !isResolved(), this, "cannot set record to a finalized Datatype"); d_isRecord = true; } Cardinality Datatype::getCardinality(Type t) const { PrettyCheckArgument(isResolved(), this, "this datatype is not yet resolved"); Assert(t.isDatatype() && ((DatatypeType)t).getDatatype() == *this); ExprManagerScope ems(d_self); TypeNode tn = TypeNode::fromType(t); return d_internal->getCardinality(tn); } Cardinality Datatype::getCardinality() const { PrettyCheckArgument(!isParametric(), this, "for getCardinality, this datatype cannot be parametric"); ExprManagerScope ems(d_self); return d_internal->getCardinality(); } bool Datatype::isRecursiveSingleton(Type t) const { PrettyCheckArgument(isResolved(), this, "this datatype is not yet resolved"); Assert(t.isDatatype() && ((DatatypeType)t).getDatatype() == *this); ExprManagerScope ems(d_self); TypeNode tn = TypeNode::fromType(t); return d_internal->isRecursiveSingleton(tn); } bool Datatype::isRecursiveSingleton() const { PrettyCheckArgument(!isParametric(), this, "for isRecursiveSingleton, this datatype cannot be parametric"); ExprManagerScope ems(d_self); return d_internal->isRecursiveSingleton(); } unsigned Datatype::getNumRecursiveSingletonArgTypes(Type t) const { Assert(isRecursiveSingleton(t)); ExprManagerScope ems(d_self); TypeNode tn = TypeNode::fromType(t); return d_internal->getNumRecursiveSingletonArgTypes(tn); } unsigned Datatype::getNumRecursiveSingletonArgTypes() const { PrettyCheckArgument(!isParametric(), this, "for getNumRecursiveSingletonArgTypes, this datatype cannot be parametric"); ExprManagerScope ems(d_self); return d_internal->getNumRecursiveSingletonArgTypes(); } Type Datatype::getRecursiveSingletonArgType(Type t, unsigned i) const { Assert(isRecursiveSingleton(t)); ExprManagerScope ems(d_self); TypeNode tn = TypeNode::fromType(t); return d_internal->getRecursiveSingletonArgType(tn, i).toType(); } Type Datatype::getRecursiveSingletonArgType(unsigned i) const { PrettyCheckArgument(!isParametric(), this, "for getRecursiveSingletonArgType, this datatype cannot be parametric"); ExprManagerScope ems(d_self); return d_internal->getRecursiveSingletonArgType(i).toType(); } bool Datatype::isFinite(Type t) const { PrettyCheckArgument(isResolved(), this, "this datatype is not yet resolved"); Assert(t.isDatatype() && ((DatatypeType)t).getDatatype() == *this); ExprManagerScope ems(d_self); TypeNode tn = TypeNode::fromType(t); return d_internal->isFinite(tn); } bool Datatype::isFinite() const { PrettyCheckArgument(isResolved() && !isParametric(), this, "this datatype must be resolved and not parametric"); ExprManagerScope ems(d_self); return d_internal->isFinite(); } bool Datatype::isInterpretedFinite(Type t) const { PrettyCheckArgument(isResolved(), this, "this datatype is not yet resolved"); Assert(t.isDatatype() && ((DatatypeType)t).getDatatype() == *this); ExprManagerScope ems(d_self); TypeNode tn = TypeNode::fromType(t); return d_internal->isInterpretedFinite(tn); } bool Datatype::isInterpretedFinite() const { PrettyCheckArgument(isResolved() && !isParametric(), this, "this datatype must be resolved and not parametric"); ExprManagerScope ems(d_self); return d_internal->isInterpretedFinite(); } bool Datatype::isWellFounded() const { ExprManagerScope ems(d_self); return d_internal->isWellFounded(); } bool Datatype::hasNestedRecursion() const { ExprManagerScope ems(d_self); return d_internal->hasNestedRecursion(); } Expr Datatype::mkGroundTerm(Type t) const { PrettyCheckArgument(isResolved(), this, "this datatype is not yet resolved"); ExprManagerScope ems(d_self); TypeNode tn = TypeNode::fromType(t); Node gterm = d_internal->mkGroundTerm(tn); PrettyCheckArgument( !gterm.isNull(), this, "datatype is not well-founded, cannot construct a ground term!"); return gterm.toExpr(); } Expr Datatype::mkGroundValue(Type t) const { PrettyCheckArgument(isResolved(), this, "this datatype is not yet resolved"); ExprManagerScope ems(d_self); TypeNode tn = TypeNode::fromType(t); Node gvalue = d_internal->mkGroundValue(tn); PrettyCheckArgument( !gvalue.isNull(), this, "datatype is not well-founded, cannot construct a ground value!"); return gvalue.toExpr(); } DatatypeType Datatype::getDatatypeType() const { PrettyCheckArgument(isResolved(), *this, "Datatype must be resolved to get its DatatypeType"); ExprManagerScope ems(d_self); Type self = d_internal->getTypeNode().toType(); PrettyCheckArgument(!self.isNull(), *this); return DatatypeType(self); } DatatypeType Datatype::getDatatypeType(const std::vector& params) const { PrettyCheckArgument(isResolved(), *this, "Datatype must be resolved to get its DatatypeType"); ExprManagerScope ems(d_self); Type self = d_internal->getTypeNode().toType(); PrettyCheckArgument(!self.isNull() && DatatypeType(self).isParametric(), this); return DatatypeType(self).instantiate(params); } bool Datatype::operator==(const Datatype& other) const { // two datatypes are == iff the name is the same and they have // exactly matching constructors (in the same order) if(this == &other) { return true; } return true; } const DatatypeConstructor& Datatype::operator[](size_t index) const { PrettyCheckArgument(index < getNumConstructors(), index, "index out of bounds"); return d_constructors[index]; } const DatatypeConstructor& Datatype::operator[](std::string name) const { for(const_iterator i = begin(); i != end(); ++i) { if((*i).getName() == name) { return *i; } } std::string dname = getName(); IllegalArgument(name, "No such constructor `%s' of datatype `%s'", name.c_str(), dname.c_str()); } Expr Datatype::getConstructor(std::string name) const { return (*this)[name].getConstructor(); } Type Datatype::getSygusType() const { return d_internal->getSygusType().toType(); } Expr Datatype::getSygusVarList() const { return d_internal->getSygusVarList().toExpr(); } bool Datatype::getSygusAllowConst() const { return d_internal->getSygusAllowConst(); } bool Datatype::getSygusAllowAll() const { return d_internal->getSygusAllowAll(); } bool Datatype::involvesExternalType() const{ return d_internal->involvesExternalType(); } bool Datatype::involvesUninterpretedType() const{ return d_internal->involvesUninterpretedType(); } const std::vector* Datatype::getConstructors() const { return &d_constructors; } DatatypeConstructor::DatatypeConstructor(std::string name, unsigned weight) : d_internal(nullptr) { PrettyCheckArgument(name != "", name, "cannot construct a datatype constructor without a name"); d_internal = std::make_shared(name, weight); } void DatatypeConstructor::setSygus(Expr op, std::shared_ptr spc) { PrettyCheckArgument( !isResolved(), this, "cannot modify a finalized Datatype constructor"); Node opn = Node::fromExpr(op); d_internal->setSygus(op); // print callback lives at the expression level currently d_sygus_pc = spc; } const std::vector* DatatypeConstructor::getArgs() const { return &d_args; } void DatatypeConstructor::addArg(std::string selectorName, Type selectorType) { // We don't want to introduce a new data member, because eventually // we're going to be a constant stuffed inside a node. So we stow // the selector type away inside a var until resolution (when we can // create the proper selector type) PrettyCheckArgument(!isResolved(), this, "cannot modify a finalized Datatype constructor"); PrettyCheckArgument(!selectorType.isNull(), selectorType, "cannot add a null selector type"); // we're using some internals, so we have to set up this library context ExprManagerScope ems(selectorType); Expr type = NodeManager::currentNM()->mkSkolem("unresolved_" + selectorName, TypeNode::fromType(selectorType), "is an unresolved selector type placeholder", NodeManager::SKOLEM_EXACT_NAME | NodeManager::SKOLEM_NO_NOTIFY).toExpr(); Debug("datatypes") << type << endl; d_args.push_back(DatatypeConstructorArg(selectorName, type)); d_internal->addArg(d_args.back().d_internal); } void DatatypeConstructor::addArg(std::string selectorName, DatatypeUnresolvedType selectorType) { // We don't want to introduce a new data member, because eventually // we're going to be a constant stuffed inside a node. So we stow // the selector type away after a NUL in the name string until // resolution (when we can create the proper selector type) PrettyCheckArgument(!isResolved(), this, "cannot modify a finalized Datatype constructor"); PrettyCheckArgument(selectorType.getName() != "", selectorType, "cannot add a null selector type"); d_args.push_back(DatatypeConstructorArg(selectorName + '\0' + selectorType.getName(), Expr())); d_internal->addArg(d_args.back().d_internal); } void DatatypeConstructor::addArg(std::string selectorName, DatatypeSelfType) { // We don't want to introduce a new data member, because eventually // we're going to be a constant stuffed inside a node. So we mark // the name string with a NUL to indicate that we have a // self-selecting selector until resolution (when we can create the // proper selector type) PrettyCheckArgument(!isResolved(), this, "cannot modify a finalized Datatype constructor"); d_args.push_back(DatatypeConstructorArg(selectorName + '\0', Expr())); d_internal->addArg(d_args.back().d_internal); } std::string DatatypeConstructor::getName() const { return d_internal->getName(); } Expr DatatypeConstructor::getConstructor() const { PrettyCheckArgument(isResolved(), this, "this datatype constructor is not yet resolved"); return d_constructor; } Type DatatypeConstructor::getSpecializedConstructorType(Type returnType) const { PrettyCheckArgument(isResolved(), this, "this datatype constructor is not yet resolved"); PrettyCheckArgument(returnType.isDatatype(), this, "cannot get specialized constructor type for non-datatype type"); ExprManagerScope ems(d_constructor); TypeNode tn = TypeNode::fromType(returnType); return d_internal->getSpecializedConstructorType(tn).toType(); } Expr DatatypeConstructor::getTester() const { PrettyCheckArgument(isResolved(), this, "this datatype constructor is not yet resolved"); ExprManagerScope ems(d_constructor); return d_internal->getTester().toExpr(); } Expr DatatypeConstructor::getSygusOp() const { PrettyCheckArgument(isResolved(), this, "this datatype constructor is not yet resolved"); ExprManagerScope ems(d_constructor); return d_internal->getSygusOp().toExpr(); } bool DatatypeConstructor::isSygusIdFunc() const { PrettyCheckArgument(isResolved(), this, "this datatype constructor is not yet resolved"); ExprManagerScope ems(d_constructor); return d_internal->isSygusIdFunc(); } unsigned DatatypeConstructor::getWeight() const { PrettyCheckArgument( isResolved(), this, "this datatype constructor is not yet resolved"); ExprManagerScope ems(d_constructor); return d_internal->getWeight(); } std::shared_ptr DatatypeConstructor::getSygusPrintCallback() const { PrettyCheckArgument( isResolved(), this, "this datatype constructor is not yet resolved"); return d_sygus_pc; } Cardinality DatatypeConstructor::getCardinality(Type t) const { PrettyCheckArgument(isResolved(), this, "this datatype constructor is not yet resolved"); ExprManagerScope ems(d_constructor); TypeNode tn = TypeNode::fromType(t); return d_internal->getCardinality(tn); } bool DatatypeConstructor::isFinite(Type t) const { PrettyCheckArgument(isResolved(), this, "this datatype constructor is not yet resolved"); ExprManagerScope ems(d_constructor); TypeNode tn = TypeNode::fromType(t); return d_internal->isFinite(tn); } bool DatatypeConstructor::isInterpretedFinite(Type t) const { PrettyCheckArgument(isResolved(), this, "this datatype constructor is not yet resolved"); ExprManagerScope ems(d_constructor); TypeNode tn = TypeNode::fromType(t); return d_internal->isInterpretedFinite(tn); } const DatatypeConstructorArg& DatatypeConstructor::operator[](size_t index) const { PrettyCheckArgument(index < getNumArgs(), index, "index out of bounds"); return d_args[index]; } const DatatypeConstructorArg& DatatypeConstructor::operator[](std::string name) const { for(const_iterator i = begin(); i != end(); ++i) { if((*i).getName() == name) { return *i; } } std::string dname = getName(); IllegalArgument(name, "No such arg `%s' of constructor `%s'", name.c_str(), dname.c_str()); } Expr DatatypeConstructor::getSelector(std::string name) const { return (*this)[name].d_selector; } Type DatatypeConstructor::getArgType(unsigned index) const { PrettyCheckArgument(index < getNumArgs(), index, "index out of bounds"); ExprManagerScope ems(d_constructor); return d_internal->getArgType(index).toType(); } bool DatatypeConstructor::involvesExternalType() const{ ExprManagerScope ems(d_constructor); return d_internal->involvesExternalType(); } bool DatatypeConstructor::involvesUninterpretedType() const{ ExprManagerScope ems(d_constructor); return d_internal->involvesUninterpretedType(); } DatatypeConstructorArg::DatatypeConstructorArg(std::string name, Expr selector) : d_internal(nullptr) { PrettyCheckArgument(name != "", name, "cannot construct a datatype constructor arg without a name"); d_internal = std::make_shared(name, Node::fromExpr(selector)); } std::string DatatypeConstructorArg::getName() const { string name = d_internal->getName(); const size_t nul = name.find('\0'); if(nul != string::npos) { name.resize(nul); } return name; } Expr DatatypeConstructorArg::getSelector() const { PrettyCheckArgument(isResolved(), this, "cannot get a selector for an unresolved datatype constructor"); return d_selector; } Expr DatatypeConstructor::getSelectorInternal( Type domainType, size_t index ) const { PrettyCheckArgument(isResolved(), this, "cannot get an internal selector for an unresolved datatype constructor"); PrettyCheckArgument(index < getNumArgs(), index, "index out of bounds"); ExprManagerScope ems(d_constructor); TypeNode dtn = TypeNode::fromType(domainType); return d_internal->getSelectorInternal(dtn, index).toExpr(); } int DatatypeConstructor::getSelectorIndexInternal( Expr sel ) const { PrettyCheckArgument(isResolved(), this, "cannot get an internal selector index for an unresolved datatype constructor"); ExprManagerScope ems(d_constructor); Node seln = Node::fromExpr(sel); return d_internal->getSelectorIndexInternal(seln); } Expr DatatypeConstructorArg::getConstructor() const { PrettyCheckArgument(isResolved(), this, "cannot get a associated constructor for argument of an unresolved datatype constructor"); ExprManagerScope ems(d_selector); return d_internal->getConstructor().toExpr(); } SelectorType DatatypeConstructorArg::getType() const { return d_selector.getType(); } Type DatatypeConstructorArg::getRangeType() const { return getType().getRangeType(); } bool DatatypeConstructorArg::isUnresolvedSelf() const { return d_selector.isNull(); } bool DatatypeConstructorArg::isResolved() const { // We could just write: // // return !d_selector.isNull() && d_selector.getType().isSelector(); // // HOWEVER, this causes problems in ExprManager tear-down, because // the attributes are removed before the pool is purged. When the // pool is purged, this triggers an equality test between Datatypes, // and this triggers a call to isResolved(), which breaks because // d_selector has no type after attributes are stripped. // // This problem, coupled with the fact that this function is called // _often_, means we should just use a boolean flag. // return d_internal->isResolved(); } std::ostream& operator<<(std::ostream& os, const Datatype& dt) { // can only output datatypes in the CVC4 native language language::SetLanguage::Scope ls(os, language::output::LANG_CVC4); dt.toStream(os); return os; } void Datatype::toStream(std::ostream& out) const { out << "DATATYPE " << getName(); if (isParametric()) { out << '['; for (size_t i = 0; i < getNumParameters(); ++i) { if(i > 0) { out << ','; } out << getParameter(i); } out << ']'; } out << " =" << endl; Datatype::const_iterator i = begin(), i_end = end(); if(i != i_end) { out << " "; do { out << *i << endl; if(++i != i_end) { out << "| "; } } while(i != i_end); } out << "END;" << endl; } std::ostream& operator<<(std::ostream& os, const DatatypeConstructor& ctor) { // can only output datatypes in the CVC4 native language language::SetLanguage::Scope ls(os, language::output::LANG_CVC4); ctor.toStream(os); return os; } void DatatypeConstructor::toStream(std::ostream& out) const { out << getName(); DatatypeConstructor::const_iterator i = begin(), i_end = end(); if(i != i_end) { out << "("; do { out << *i; if(++i != i_end) { out << ", "; } } while(i != i_end); out << ")"; } } std::ostream& operator<<(std::ostream& os, const DatatypeConstructorArg& arg) { // can only output datatypes in the CVC4 native language language::SetLanguage::Scope ls(os, language::output::LANG_CVC4); arg.toStream(os); return os; } void DatatypeConstructorArg::toStream(std::ostream& out) const { std::string name = getName(); out << name << ": "; Type t; if (isResolved()) { t = getRangeType(); } else if (d_selector.isNull()) { string typeName = name.substr(name.find('\0') + 1); out << ((typeName == "") ? "[self]" : typeName); return; } else { t = d_selector.getType(); } out << t; } DatatypeIndexConstant::DatatypeIndexConstant(unsigned index) : d_index(index) {} std::ostream& operator<<(std::ostream& out, const DatatypeIndexConstant& dic) { return out << "index_" << dic.getIndex(); } std::string Datatype::getName() const { ExprManagerScope ems(*d_em); return d_internal->getName(); } size_t Datatype::getNumConstructors() const { return d_constructors.size(); } bool Datatype::isParametric() const { ExprManagerScope ems(*d_em); return d_internal->isParametric(); } size_t Datatype::getNumParameters() const { ExprManagerScope ems(*d_em); return d_internal->getNumParameters(); } Type Datatype::getParameter(unsigned int i) const { CheckArgument(isParametric(), this, "Cannot get type parameter of a non-parametric datatype."); CheckArgument(i < getNumParameters(), i, "Type parameter index out of range for datatype."); ExprManagerScope ems(*d_em); return d_internal->getParameter(i).toType(); } std::vector Datatype::getParameters() const { CheckArgument(isParametric(), this, "Cannot get type parameters of a non-parametric datatype."); std::vector params; std::vector paramsn = d_internal->getParameters(); // convert to type for (unsigned i = 0, nparams = paramsn.size(); i < nparams; i++) { params.push_back(paramsn[i].toType()); } return params; } bool Datatype::isCodatatype() const { ExprManagerScope ems(*d_em); return d_internal->isCodatatype(); } bool Datatype::isSygus() const { ExprManagerScope ems(*d_em); return d_internal->isSygus(); } bool Datatype::isTuple() const { ExprManagerScope ems(*d_em); return d_internal->isTuple(); } bool Datatype::isRecord() const { return d_isRecord; } Record* Datatype::getRecord() const { return d_record.get(); } bool Datatype::operator!=(const Datatype& other) const { return !(*this == other); } bool Datatype::isResolved() const { ExprManagerScope ems(*d_em); return d_internal->isResolved(); } Datatype::iterator Datatype::begin() { return iterator(d_constructors, true); } Datatype::iterator Datatype::end() { return iterator(d_constructors, false); } Datatype::const_iterator Datatype::begin() const { return const_iterator(d_constructors, true); } Datatype::const_iterator Datatype::end() const { return const_iterator(d_constructors, false); } bool DatatypeConstructor::isResolved() const { return d_internal->isResolved(); } size_t DatatypeConstructor::getNumArgs() const { return d_args.size(); } DatatypeConstructor::iterator DatatypeConstructor::begin() { return iterator(d_args, true); } DatatypeConstructor::iterator DatatypeConstructor::end() { return iterator(d_args, false); } DatatypeConstructor::const_iterator DatatypeConstructor::begin() const { return const_iterator(d_args, true); } DatatypeConstructor::const_iterator DatatypeConstructor::end() const { return const_iterator(d_args, false); } }/* CVC4 namespace */