/********************* */ /*! \file node.h ** \verbatim ** Original author: mdeters ** Major contributors: dejan ** Minor contributors (to current version): taking, cconway ** This file is part of the CVC4 prototype. ** Copyright (c) 2009, 2010 The Analysis of Computer Systems Group (ACSys) ** Courant Institute of Mathematical Sciences ** New York University ** See the file COPYING in the top-level source directory for licensing ** information.\endverbatim ** ** \brief Reference-counted encapsulation of a pointer to node information. ** ** Reference-counted encapsulation of a pointer to node information. **/ #include "cvc4_private.h" // circular dependency #include "expr/node_value.h" #ifndef __CVC4__NODE_H #define __CVC4__NODE_H #include #include #include #include #include "type.h" #include "expr/kind.h" #include "expr/metakind.h" #include "expr/expr.h" #include "util/Assert.h" #include "util/configuration.h" #include "util/output.h" #include "util/exception.h" #include "util/language.h" namespace CVC4 { class TypeNode; class NodeManager; template class NodeTemplate; /** * Exception thrown during the type-checking phase, it can be * thrown by node.getType(). */ class TypeCheckingExceptionPrivate : public Exception { private: /** The node responsible for the failure */ NodeTemplate* d_node; protected: TypeCheckingExceptionPrivate() : Exception() {} public: /** * Construct the exception with the problematic node and the message * @param node the problematic node * @param message the message explaining the failure */ TypeCheckingExceptionPrivate(NodeTemplate node, std::string message); /** Destructor */ ~TypeCheckingExceptionPrivate() throw (); /** * Get the Node that caused the type-checking to fail. * @return the node */ NodeTemplate getNode() const; /** Returns the message corresponding to the type-checking failure */ std::string toString() const; }; /** * The Node class encapsulates the NodeValue with reference counting. */ typedef NodeTemplate Node; /** * The TNode class encapsulates the NodeValue but doesn't count references. */ typedef NodeTemplate TNode; namespace expr { class NodeValue; namespace attr { class AttributeManager; }/* CVC4::expr::attr namespace */ class ExprSetDepth; }/* CVC4::expr namespace */ namespace kind { namespace metakind { struct NodeValueConstPrinter; }/* CVC4::kind::metakind namespace */ }/* CVC4::kind namespace */ /** * Encapsulation of an NodeValue pointer. The reference count is * maintained in the NodeValue if ref_count is true. * @param ref_count if true reference are counted in the NodeValue */ template class NodeTemplate { /** * The NodeValue has access to the private constructors, so that the * iterators can can create new nodes. */ friend class expr::NodeValue; /** A convenient null-valued encapsulated pointer */ static NodeTemplate s_null; /** The referenced NodeValue */ expr::NodeValue* d_nv; /** * This constructor is reserved for use by the NodeTemplate package; one * must construct an NodeTemplate using one of the build mechanisms of the * NodeTemplate package. * * FIXME: there's a type-system escape here to cast away the const, * since the refcount needs to be updated. But conceptually Nodes * don't change their arguments, and it's nice to have * const_iterators over them. * * This really does needs to be explicit to avoid hard to track errors with * Nodes implicitly wrapping NodeValues */ explicit NodeTemplate(const expr::NodeValue*); friend class NodeTemplate; friend class NodeTemplate; friend class NodeManager; template friend class NodeBuilder; friend class ::CVC4::expr::attr::AttributeManager; friend struct ::CVC4::kind::metakind::NodeValueConstPrinter; /** * Assigns the expression value and does reference counting. No assumptions * are made on the expression, and should only be used if we know what we * are doing. * * @param ev the expression value to assign */ void assignNodeValue(expr::NodeValue* ev); inline void assertTNodeNotExpired() const throw(AssertionException) { if(!ref_count) { Assert( d_nv->d_rc > 0, "TNode pointing to an expired NodeValue" ); } } public: /** Default constructor, makes a null expression. */ NodeTemplate() : d_nv(&expr::NodeValue::s_null) { } /** * Conversion between nodes that are reference-counted and those that are * not. * @param node the node to make copy of */ NodeTemplate(const NodeTemplate& node); /** * Copy constructor. Note that GCC does NOT recognize an instantiation of * the above template as a copy constructor and problems ensue. So we * provide an explicit one here. * @param node the node to make copy of */ NodeTemplate(const NodeTemplate& node); /** * Assignment operator for nodes, copies the relevant information from node * to this node. * @param node the node to copy * @return reference to this node */ NodeTemplate& operator=(const NodeTemplate& node); /** * Assignment operator for nodes, copies the relevant information from node * to this node. * @param node the node to copy * @return reference to this node */ NodeTemplate& operator=(const NodeTemplate& node); /** * Destructor. If ref_count is true it will decrement the reference count * and, if zero, collect the NodeValue. */ ~NodeTemplate() throw(AssertionException); /** * Return the null node. * @return the null node */ static NodeTemplate null() { return s_null; } /** * Returns true if this expression is a null expression. * @return true if null */ bool isNull() const { assertTNodeNotExpired(); return d_nv == &expr::NodeValue::s_null; } /** * Structural comparison operator for expressions. * @param node the node to compare to * @return true if expressions are equal, false otherwise */ template bool operator==(const NodeTemplate& node) const { assertTNodeNotExpired(); node.assertTNodeNotExpired(); return d_nv == node.d_nv; } /** * Structural comparison operator for expressions. * @param node the node to compare to * @return false if expressions are equal, true otherwise */ template bool operator!=(const NodeTemplate& node) const { assertTNodeNotExpired(); node.assertTNodeNotExpired(); return d_nv != node.d_nv; } /** * We compare by expression ids so, keeping things deterministic and having * that subexpressions have to be smaller than the enclosing expressions. * @param node the node to compare to * @return true if this expression is smaller */ template inline bool operator<(const NodeTemplate& node) const { assertTNodeNotExpired(); node.assertTNodeNotExpired(); return d_nv->d_id < node.d_nv->d_id; } /** * We compare by expression ids so, keeping things deterministic and having * that subexpressions have to be smaller than the enclosing expressions. * @param node the node to compare to * @return true if this expression is greater */ template inline bool operator>(const NodeTemplate& node) const { assertTNodeNotExpired(); node.assertTNodeNotExpired(); return d_nv->d_id > node.d_nv->d_id; } /** * We compare by expression ids so, keeping things deterministic and having * that subexpressions have to be smaller than the enclosing expressions. * @param node the node to compare to * @return true if this expression is smaller than or equal to */ template inline bool operator<=(const NodeTemplate& node) const { assertTNodeNotExpired(); node.assertTNodeNotExpired(); return d_nv->d_id <= node.d_nv->d_id; } /** * We compare by expression ids so, keeping things deterministic and having * that subexpressions have to be smaller than the enclosing expressions. * @param node the node to compare to * @return true if this expression is greater than or equal to */ template inline bool operator>=(const NodeTemplate& node) const { assertTNodeNotExpired(); node.assertTNodeNotExpired(); return d_nv->d_id >= node.d_nv->d_id; } /** * Returns the i-th child of this node. * @param i the index of the child * @return the node representing the i-th child */ NodeTemplate operator[](int i) const { assertTNodeNotExpired(); return NodeTemplate(d_nv->getChild(i)); } /* A note on isAtomic() and isAtomicFormula() (in CVC3 parlance).. * * It has been decided for now to hold off on implementations of * these functions, as they may only be needed in CNF conversion, * where it's pointless to do a lazy isAtomic determination by * searching through the DAG, and storing it, since the result will * only be used once. For more details see the 4/27/2010 CVC4 * developer's meeting notes at: * * http://goedel.cims.nyu.edu/wiki/Meeting_Minutes_-_April_27,_2010#isAtomic.28.29_and_isAtomicFormula.28.29 */ // bool containsDecision(); // is "atomic" // bool properlyContainsDecision(); // maybe not atomic but all children are /** * Returns true if this node represents a constant * @return true if const */ inline bool isConst() const { assertTNodeNotExpired(); return getMetaKind() == kind::metakind::CONSTANT; } /** * Returns the unique id of this node * @return the ud */ unsigned getId() const { assertTNodeNotExpired(); return d_nv->getId(); } /** * Returns a node representing the operator of this expression. * If this is an APPLY, then the operator will be a functional term. * Otherwise, it will be a node with kind BUILTIN. */ NodeTemplate getOperator() const; /** * Returns true if the node has an operator (i.e., it's not a * variable or a constant). */ inline bool hasOperator() const; /** * Get the type for the node and optionally do type checking. * * Initial type computation will be near-constant time if * type checking is not requested. Results are memoized, so that * subsequent calls to getType() without type checking will be * constant time. * * Initial type checking is linear in the size of the expression. * Again, the results are memoized, so that subsequent calls to * getType(), with or without type checking, will be constant * time. * * NOTE: A TypeCheckingException can be thrown even when type * checking is not requested. getType() will always return a * valid and correct type and, thus, an exception will be thrown * when no valid or correct type can be computed (e.g., if the * arguments to a bit-vector operation aren't bit-vectors). When * type checking is not requested, getType() will do the minimum * amount of checking required to return a valid result. * * @param check whether we should check the type as we compute it * (default: false) */ TypeNode getType(bool check = false) const throw (CVC4::TypeCheckingExceptionPrivate, CVC4::AssertionException); /** * Substitution of Nodes. */ Node substitute(TNode node, TNode replacement) const; /** * Simultaneous substitution of Nodes. */ template Node substitute(Iterator1 nodesBegin, Iterator1 nodesEnd, Iterator2 replacementsBegin, Iterator2 replacementsEnd) const; /** * Returns the kind of this node. * @return the kind */ inline Kind getKind() const { assertTNodeNotExpired(); return Kind(d_nv->d_kind); } /** * Returns the metakind of this node. * @return the metakind */ inline kind::MetaKind getMetaKind() const { assertTNodeNotExpired(); return kind::metaKindOf(getKind()); } /** * Returns the number of children this node has. * @return the number of children */ inline size_t getNumChildren() const; /** * If this is a CONST_* Node, extract the constant from it. */ template inline const T& getConst() const; /** * Returns the value of the given attribute that this has been attached. * @param attKind the kind of the attribute * @return the value of the attribute */ template inline typename AttrKind::value_type getAttribute(const AttrKind& attKind) const; // Note that there are two, distinct hasAttribute() declarations for // a reason (rather than using a pointer-valued argument with a // default value): they permit more optimized code in the underlying // hasAttribute() implementations. /** * Returns true if this node has been associated an attribute of given kind. * Additionaly, if a pointer to the value_kind is give, and the attribute * value has been set for this node, it will be returned. * @param attKind the kind of the attribute * @return true if this node has the requested attribute */ template inline bool hasAttribute(const AttrKind& attKind) const; /** * Returns true if this node has been associated an attribute of given kind. * Additionaly, if a pointer to the value_kind is give, and the attribute * value has been set for this node, it will be returned. * @param attKind the kind of the attribute * @param value where to store the value if it exists * @return true if this node has the requested attribute */ template inline bool getAttribute(const AttrKind& attKind, typename AttrKind::value_type& value) const; /** * Sets the given attribute of this node to the given value. * @param attKind the kind of the atribute * @param value the value to set the attribute to */ template inline void setAttribute(const AttrKind& attKind, const typename AttrKind::value_type& value); /** Iterator allowing for scanning through the children. */ typedef typename expr::NodeValue::iterator< NodeTemplate > iterator; /** Constant iterator allowing for scanning through the children. */ typedef typename expr::NodeValue::iterator< NodeTemplate > const_iterator; class kinded_iterator { friend class NodeTemplate; NodeTemplate d_node; ssize_t d_child; kinded_iterator(TNode node, ssize_t child) : d_node(node), d_child(child) { } // These are factories to serve as clients to Node::begin() and // Node::end(). static kinded_iterator begin(TNode n, Kind k) { return kinded_iterator(n, n.getKind() == k ? 0 : -2); } static kinded_iterator end(TNode n, Kind k) { return kinded_iterator(n, n.getKind() == k ? n.getNumChildren() : -1); } public: typedef NodeTemplate value_type; typedef ptrdiff_t difference_type; typedef NodeTemplate* pointer; typedef NodeTemplate& reference; kinded_iterator() : d_node(NodeTemplate::null()), d_child(-2) { } kinded_iterator(const kinded_iterator& i) : d_node(i.d_node), d_child(i.d_child) { } NodeTemplate operator*() { return d_child < 0 ? d_node : d_node[d_child]; } bool operator==(const kinded_iterator& i) { return d_node == i.d_node && d_child == i.d_child; } bool operator!=(const kinded_iterator& i) { return !(*this == i); } kinded_iterator& operator++() { if(d_child != -1) { ++d_child; } return *this; } kinded_iterator operator++(int) { kinded_iterator i = *this; ++*this; return i; } };/* class NodeTemplate::kinded_iterator */ typedef kinded_iterator const_kinded_iterator; /** * Returns the iterator pointing to the first child. * @return the iterator */ inline iterator begin() { assertTNodeNotExpired(); return d_nv->begin< NodeTemplate >(); } /** * Returns the iterator pointing to the end of the children (one beyond the * last one). * @return the end of the children iterator. */ inline iterator end() { assertTNodeNotExpired(); return d_nv->end< NodeTemplate >(); } /** * Returns the iterator pointing to the first child, if the node's * kind is the same as the parameter, otherwise returns the iterator * pointing to the node itself. This is useful if you want to * pretend to iterate over a "unary" PLUS, for instance, since unary * PLUSes don't exist---begin(PLUS) will give an iterator over the * children if the node's a PLUS node, otherwise give an iterator * over the node itself, as if it were a unary PLUS. * @param kind the kind to match * @return the kinded_iterator iterating over this Node (if its kind * is not the passed kind) or its children */ inline kinded_iterator begin(Kind kind) { assertTNodeNotExpired(); return kinded_iterator::begin(*this, kind); } /** * Returns the iterator pointing to the end of the children (one * beyond the last one), if the node's kind is the same as the * parameter, otherwise returns the iterator pointing to the * one-of-the-node-itself. This is useful if you want to pretend to * iterate over a "unary" PLUS, for instance, since unary PLUSes * don't exist---begin(PLUS) will give an iterator over the children * if the node's a PLUS node, otherwise give an iterator over the * node itself, as if it were a unary PLUS. * @param kind the kind to match * @return the kinded_iterator pointing off-the-end of this Node (if * its kind is not the passed kind) or off-the-end of its children */ inline kinded_iterator end(Kind kind) { assertTNodeNotExpired(); return kinded_iterator::end(*this, kind); } /** * Returns the const_iterator pointing to the first child. * @return the const_iterator */ inline const_iterator begin() const { assertTNodeNotExpired(); return d_nv->begin< NodeTemplate >(); } /** * Returns the const_iterator pointing to the end of the children (one * beyond the last one. * @return the end of the children const_iterator. */ inline const_iterator end() const { assertTNodeNotExpired(); return d_nv->end< NodeTemplate >(); } /** * Returns the iterator pointing to the first child, if the node's * kind is the same as the parameter, otherwise returns the iterator * pointing to the node itself. This is useful if you want to * pretend to iterate over a "unary" PLUS, for instance, since unary * PLUSes don't exist---begin(PLUS) will give an iterator over the * children if the node's a PLUS node, otherwise give an iterator * over the node itself, as if it were a unary PLUS. * @param kind the kind to match * @return the kinded_iterator iterating over this Node (if its kind * is not the passed kind) or its children */ inline const_kinded_iterator begin(Kind kind) const { assertTNodeNotExpired(); return const_kinded_iterator::begin(*this, kind); } /** * Returns the iterator pointing to the end of the children (one * beyond the last one), if the node's kind is the same as the * parameter, otherwise returns the iterator pointing to the * one-of-the-node-itself. This is useful if you want to pretend to * iterate over a "unary" PLUS, for instance, since unary PLUSes * don't exist---begin(PLUS) will give an iterator over the children * if the node's a PLUS node, otherwise give an iterator over the * node itself, as if it were a unary PLUS. * @param kind the kind to match * @return the kinded_iterator pointing off-the-end of this Node (if * its kind is not the passed kind) or off-the-end of its children */ inline const_kinded_iterator end(Kind kind) const { assertTNodeNotExpired(); return const_kinded_iterator::end(*this, kind); } /** * Converts this node into a string representation. * @return the string representation of this node. */ inline std::string toString() const { assertTNodeNotExpired(); return d_nv->toString(); } /** * Converst this node into a string representation and sends it to the * given stream * * @param out the stream to serialize this node to * @param toDepth the depth to which to print this expression, or -1 to * print it fully * @param types set to true to ascribe types to the output expressions * (might break language compliance, but good for debugging expressions) * @param language the language in which to output */ inline void toStream(std::ostream& out, int toDepth = -1, bool types = false, OutputLanguage language = language::output::LANG_AST) const { assertTNodeNotExpired(); d_nv->toStream(out, toDepth, types, language); } /** * IOStream manipulator to set the maximum depth of Nodes when * pretty-printing. -1 means print to any depth. E.g.: * * // let a, b, c, and d be VARIABLEs * Node n = nm->mkNode(OR, a, b, nm->mkNode(AND, c, nm->mkNode(NOT, d))) * out << setdepth(3) << n; * * gives "(OR a b (AND c (NOT d)))", but * * out << setdepth(1) << [same node as above] * * gives "(OR a b (...))" */ typedef expr::ExprSetDepth setdepth; /** * IOStream manipulator to print type ascriptions or not. * * // let a, b, c, and d be variables of sort U * Node n = nm->mkNode(OR, a, b, nm->mkNode(AND, c, nm->mkNode(NOT, d))) * out << n; * * gives "(OR a:U b:U (AND c:U (NOT d:U)))", but */ typedef expr::ExprPrintTypes printtypes; /** * IOStream manipulator to set the output language for Exprs. */ typedef expr::ExprSetLanguage setlanguage; /** * Very basic pretty printer for Node. * @param out output stream to print to. * @param indent number of spaces to indent the formula by. */ inline void printAst(std::ostream& out, int indent = 0) const; NodeTemplate eqNode(const NodeTemplate& right) const; NodeTemplate notNode() const; NodeTemplate andNode(const NodeTemplate& right) const; NodeTemplate orNode(const NodeTemplate& right) const; NodeTemplate iteNode(const NodeTemplate& thenpart, const NodeTemplate& elsepart) const; NodeTemplate iffNode(const NodeTemplate& right) const; NodeTemplate impNode(const NodeTemplate& right) const; NodeTemplate xorNode(const NodeTemplate& right) const; };/* class NodeTemplate */ /** * Serializes a given node to the given stream. * @param out the output stream to use * @param n the node to output to the stream * @return the stream */ inline std::ostream& operator<<(std::ostream& out, TNode n) { n.toStream(out, Node::setdepth::getDepth(out), Node::printtypes::getPrintTypes(out), Node::setlanguage::getLanguage(out)); return out; } }/* CVC4 namespace */ #include #include "expr/attribute.h" #include "expr/node_manager.h" namespace CVC4 { // for hash_maps, hash_sets.. struct NodeHashFunction { size_t operator()(const CVC4::Node& node) const { return (size_t) node.getId(); } };/* struct NodeHashFunction */ // for hash_maps, hash_sets.. struct TNodeHashFunction { size_t operator()(CVC4::TNode node) const { return (size_t) node.getId(); } };/* struct TNodeHashFunction */ template inline size_t NodeTemplate::getNumChildren() const { assertTNodeNotExpired(); return d_nv->getNumChildren(); } template template inline const T& NodeTemplate::getConst() const { assertTNodeNotExpired(); return d_nv->getConst(); } template template inline typename AttrKind::value_type NodeTemplate:: getAttribute(const AttrKind&) const { Assert( NodeManager::currentNM() != NULL, "There is no current CVC4::NodeManager associated to this thread.\n" "Perhaps a public-facing function is missing a NodeManagerScope ?" ); assertTNodeNotExpired(); return NodeManager::currentNM()->getAttribute(*this, AttrKind()); } template template inline bool NodeTemplate:: hasAttribute(const AttrKind&) const { Assert( NodeManager::currentNM() != NULL, "There is no current CVC4::NodeManager associated to this thread.\n" "Perhaps a public-facing function is missing a NodeManagerScope ?" ); assertTNodeNotExpired(); return NodeManager::currentNM()->hasAttribute(*this, AttrKind()); } template template inline bool NodeTemplate::getAttribute(const AttrKind&, typename AttrKind::value_type& ret) const { Assert( NodeManager::currentNM() != NULL, "There is no current CVC4::NodeManager associated to this thread.\n" "Perhaps a public-facing function is missing a NodeManagerScope ?" ); assertTNodeNotExpired(); return NodeManager::currentNM()->getAttribute(*this, AttrKind(), ret); } template template inline void NodeTemplate:: setAttribute(const AttrKind&, const typename AttrKind::value_type& value) { Assert( NodeManager::currentNM() != NULL, "There is no current CVC4::NodeManager associated to this thread.\n" "Perhaps a public-facing function is missing a NodeManagerScope ?" ); assertTNodeNotExpired(); NodeManager::currentNM()->setAttribute(*this, AttrKind(), value); } template NodeTemplate NodeTemplate::s_null(&expr::NodeValue::s_null); // FIXME: escape from type system convenient but is there a better // way? Nodes conceptually don't change their expr values but of // course they do modify the refcount. But it's nice to be able to // support node_iterators over const NodeValue*. So.... hm. template NodeTemplate::NodeTemplate(const expr::NodeValue* ev) : d_nv(const_cast (ev)) { Assert(d_nv != NULL, "Expecting a non-NULL expression value!"); if(ref_count) { d_nv->inc(); } else { Assert(d_nv->d_rc > 0, "TNode constructed from NodeValue with rc == 0"); } } // the code for these two following constructors ("conversion/copy // constructors") is identical, but we need both. see comment in the // class. template NodeTemplate::NodeTemplate(const NodeTemplate& e) { Assert(e.d_nv != NULL, "Expecting a non-NULL expression value!"); d_nv = e.d_nv; if(ref_count) { Assert(d_nv->d_rc > 0, "Node constructed from TNode with rc == 0"); d_nv->inc(); } else { // shouldn't ever fail Assert(d_nv->d_rc > 0, "TNode constructed from Node with rc == 0"); } } template NodeTemplate::NodeTemplate(const NodeTemplate& e) { Assert(e.d_nv != NULL, "Expecting a non-NULL expression value!"); d_nv = e.d_nv; if(ref_count) { // shouldn't ever fail Assert(d_nv->d_rc > 0, "Node constructed from Node with rc == 0"); d_nv->inc(); } else { Assert(d_nv->d_rc > 0, "TNode constructed from TNode with rc == 0"); } } template NodeTemplate::~NodeTemplate() throw(AssertionException) { Assert(d_nv != NULL, "Expecting a non-NULL expression value!"); if(ref_count) { // shouldn't ever fail Assert(d_nv->d_rc > 0, "Node reference count would be negative"); d_nv->dec(); } } template void NodeTemplate::assignNodeValue(expr::NodeValue* ev) { d_nv = ev; if(ref_count) { d_nv->inc(); } else { Assert(d_nv->d_rc > 0, "TNode assigned to NodeValue with rc == 0"); } } template NodeTemplate& NodeTemplate:: operator=(const NodeTemplate& e) { Assert(d_nv != NULL, "Expecting a non-NULL expression value!"); Assert(e.d_nv != NULL, "Expecting a non-NULL expression value on RHS!"); if(EXPECT_TRUE( d_nv != e.d_nv )) { if(ref_count) { // shouldn't ever fail Assert(d_nv->d_rc > 0, "Node reference count would be negative"); d_nv->dec(); } d_nv = e.d_nv; if(ref_count) { // shouldn't ever fail Assert(d_nv->d_rc > 0, "Node assigned from Node with rc == 0"); d_nv->inc(); } else { Assert(d_nv->d_rc > 0, "TNode assigned from TNode with rc == 0"); } } return *this; } template NodeTemplate& NodeTemplate:: operator=(const NodeTemplate& e) { Assert(d_nv != NULL, "Expecting a non-NULL expression value!"); Assert(e.d_nv != NULL, "Expecting a non-NULL expression value on RHS!"); if(EXPECT_TRUE( d_nv != e.d_nv )) { if(ref_count) { // shouldn't ever fail Assert(d_nv->d_rc > 0, "Node reference count would be negative"); d_nv->dec(); } d_nv = e.d_nv; if(ref_count) { Assert(d_nv->d_rc > 0, "Node assigned from TNode with rc == 0"); d_nv->inc(); } else { // shouldn't ever happen Assert(d_nv->d_rc > 0, "TNode assigned from Node with rc == 0"); } } return *this; } template NodeTemplate NodeTemplate::eqNode(const NodeTemplate& right) const { assertTNodeNotExpired(); return NodeManager::currentNM()->mkNode(kind::EQUAL, *this, right); } template NodeTemplate NodeTemplate::notNode() const { assertTNodeNotExpired(); return NodeManager::currentNM()->mkNode(kind::NOT, *this); } template NodeTemplate NodeTemplate::andNode(const NodeTemplate& right) const { assertTNodeNotExpired(); return NodeManager::currentNM()->mkNode(kind::AND, *this, right); } template NodeTemplate NodeTemplate::orNode(const NodeTemplate& right) const { assertTNodeNotExpired(); return NodeManager::currentNM()->mkNode(kind::OR, *this, right); } template NodeTemplate NodeTemplate::iteNode(const NodeTemplate& thenpart, const NodeTemplate& elsepart) const { assertTNodeNotExpired(); return NodeManager::currentNM()->mkNode(kind::ITE, *this, thenpart, elsepart); } template NodeTemplate NodeTemplate::iffNode(const NodeTemplate& right) const { assertTNodeNotExpired(); return NodeManager::currentNM()->mkNode(kind::IFF, *this, right); } template NodeTemplate NodeTemplate::impNode(const NodeTemplate& right) const { assertTNodeNotExpired(); return NodeManager::currentNM()->mkNode(kind::IMPLIES, *this, right); } template NodeTemplate NodeTemplate::xorNode(const NodeTemplate& right) const { assertTNodeNotExpired(); return NodeManager::currentNM()->mkNode(kind::XOR, *this, right); } template inline void NodeTemplate::printAst(std::ostream& out, int indent) const { assertTNodeNotExpired(); d_nv->printAst(out, indent); } /** * Returns a node representing the operator of this expression. * If this is an APPLY, then the operator will be a functional term. * Otherwise, it will be a node with kind BUILTIN. */ template NodeTemplate NodeTemplate::getOperator() const { Assert( NodeManager::currentNM() != NULL, "There is no current CVC4::NodeManager associated to this thread.\n" "Perhaps a public-facing function is missing a NodeManagerScope ?" ); assertTNodeNotExpired(); switch(kind::MetaKind mk = getMetaKind()) { case kind::metakind::INVALID: IllegalArgument(*this, "getOperator() called on Node with INVALID-kinded kind"); case kind::metakind::VARIABLE: IllegalArgument(*this, "getOperator() called on Node with VARIABLE-kinded kind"); case kind::metakind::OPERATOR: { /* Returns a BUILTIN node. */ return NodeManager::currentNM()->operatorOf(getKind()); } case kind::metakind::PARAMETERIZED: /* The operator is the first child. */ return Node(d_nv->d_children[0]); case kind::metakind::CONSTANT: IllegalArgument(*this, "getOperator() called on Node with CONSTANT-kinded kind"); default: Unhandled(mk); } } /** * Returns true if the node has an operator (i.e., it's not a variable * or a constant). */ template inline bool NodeTemplate::hasOperator() const { assertTNodeNotExpired(); return NodeManager::hasOperator(getKind()); } template TypeNode NodeTemplate::getType(bool check) const throw (CVC4::TypeCheckingExceptionPrivate, CVC4::AssertionException) { Assert( NodeManager::currentNM() != NULL, "There is no current CVC4::NodeManager associated to this thread.\n" "Perhaps a public-facing function is missing a NodeManagerScope ?" ); assertTNodeNotExpired(); return NodeManager::currentNM()->getType(*this, check); } template Node NodeTemplate::substitute(TNode node, TNode replacement) const { NodeBuilder<> nb(getKind()); if(getMetaKind() == kind::metakind::PARAMETERIZED) { // push the operator nb << getOperator(); } for(TNode::const_iterator i = begin(), iend = end(); i != iend; ++i) { if(*i == node) { nb << replacement; } else { (*i).substitute(node, replacement); } } Node n = nb; return n; } template template Node NodeTemplate::substitute(Iterator1 nodesBegin, Iterator1 nodesEnd, Iterator2 replacementsBegin, Iterator2 replacementsEnd) const { Assert( nodesEnd - nodesBegin == replacementsEnd - replacementsBegin, "Substitution iterator ranges must be equal size" ); Iterator1 j = find(nodesBegin, nodesEnd, *this); if(j != nodesEnd) { return *(replacementsBegin + (j - nodesBegin)); } else if(getNumChildren() == 0) { return *this; } else { NodeBuilder<> nb(getKind()); if(getMetaKind() == kind::metakind::PARAMETERIZED) { // push the operator nb << getOperator(); } for(TNode::const_iterator i = begin(), iend = end(); i != iend; ++i) { nb << (*i).substitute(nodesBegin, nodesEnd, replacementsBegin, replacementsEnd); } Node n = nb; return n; } } #ifdef CVC4_DEBUG /** * Pretty printer for use within gdb. This is not intended to be used * outside of gdb. This writes to the Warning() stream and immediately * flushes the stream. * * Note that this function cannot be a template, since the compiler * won't instantiate it. Even if we explicitly instantiate. (Odd?) * So we implement twice. We mark as __attribute__((used)) so that * GCC emits code for it even though static analysis indicates it's * never called. * * Tim's Note: I moved this into the node.h file because this allows gdb * to find the symbol, and use it, which is the first standard this code needs * to meet. A cleaner solution is welcomed. */ static void __attribute__((used)) debugPrintNode(const NodeTemplate& n) { Warning() << Node::setdepth(-1) << Node::setlanguage(language::output::LANG_AST) << n << std::endl; Warning().flush(); } static void __attribute__((used)) debugPrintRawNode(const NodeTemplate& n) { n.printAst(Warning(), 0); Warning().flush(); } static void __attribute__((used)) debugPrintTNode(const NodeTemplate& n) { Warning() << Node::setdepth(-1) << Node::setlanguage(language::output::LANG_AST) << n << std::endl; Warning().flush(); } static void __attribute__((used)) debugPrintRawTNode(const NodeTemplate& n) { n.printAst(Warning(), 0); Warning().flush(); } #endif /* CVC4_DEBUG */ }/* CVC4 namespace */ #endif /* __CVC4__NODE_H */