Please wait. This can take some minutes ...
Many resources are needed to download a project. Please understand that we have to compensate our server costs. Thank you in advance.
Project price only 1 $
You can buy this project and download/modify it how often you want.
cvc5-cvc5-1.2.0.src.expr.node.h Maven / Gradle / Ivy
/******************************************************************************
* Top contributors (to current version):
* Morgan Deters, Dejan Jovanovic, Aina Niemetz
*
* This file is part of the cvc5 project.
*
* Copyright (c) 2009-2024 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.
* ****************************************************************************
*
* Reference-counted encapsulation of a pointer to node information.
*/
#include "cvc5_private.h"
#ifndef CVC5__NODE_H
#define CVC5__NODE_H
#include
#include
#include
#include
#include
#include
#include
#include
#include "base/check.h"
#include "base/exception.h"
#include "base/output.h"
#include "expr/kind.h"
#include "expr/metakind.h"
#include "expr/node_value.h"
#include "options/io_utils.h"
#include "options/language.h"
#include "util/hash.h"
#include "util/utility.h"
namespace cvc5::internal {
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;
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() override;
/**
* 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.
* We prefer toStream() to toString() because that keeps the expr-depth
* and expr-language settings present in the stream.
*/
void toStream(std::ostream& out) const override;
};/* class TypeCheckingExceptionPrivate */
class UnknownTypeException : public TypeCheckingExceptionPrivate {
public:
UnknownTypeException(NodeTemplate node);
};/* class UnknownTypeException */
/**
* \typedef NodeTemplate Node;
*
* The Node class encapsulates the NodeValue with reference counting.
*
* One should use generally use Nodes to manipulate expressions, to be safe.
* Every outstanding Node that references a NodeValue is counted in that
* NodeValue's reference count. Reference counts are maintained correctly
* on assignment of the Node object (to point to another NodeValue), and,
* upon destruction of the Node object, the NodeValue's reference count is
* decremented and, if zero, it becomes eligible for reclamation by the
* system.
*/
typedef NodeTemplate Node;
/**
* \typedef NodeTemplate TNode;
*
* The TNode class encapsulates the NodeValue but doesn't count references.
*
* TNodes are just like Nodes, but they don't update the reference count.
* Therefore, there is less overhead (copying a TNode is just the cost of
* the underlying pointer copy). Generally speaking, this is unsafe!
* However, there are certain situations where a TNode can be used safely.
*
* The largest class of uses for TNodes are when you need to use them in a
* "temporary," scoped fashion (hence the "T" in "TNode"). In general,
* it is safe to use TNode as a function parameter type, since the calling
* function (or some other function on the call stack) presumably has a Node
* reference to the expression data. It is generally _not_ safe, however,
* to return a TNode _from_ a function. (Functions that return Nodes often
* create the expression they return; such new expressions may not be
* referenced on the call stack, and have a reference count of 1 on
* creation. If this is returned as a TNode rather than a Node, the
* count drops to zero, marking the expression as eligible for reclamation.)
*
* More guidelines on when to use TNodes is available in the cvc5
* Developer's Guide:
* https://github.com/cvc5/cvc5/wiki/Developer-Guide#dealing-with-expressions-nodes-and-tnodes
*/
typedef NodeTemplate TNode;
} // namespace cvc5::internal
namespace std {
template <>
struct hash
{
size_t operator()(const cvc5::internal::Node& node) const;
};
template <>
struct hash
{
size_t operator()(const cvc5::internal::TNode& node) const;
};
} // namespace std
namespace cvc5::internal {
namespace expr {
class NodeValue;
namespace attr {
class AttributeManager;
struct SmtAttributes;
} // namespace attr
class ExprSetDepth;
} // namespace expr
/**
* 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 TypeNode;
friend class NodeManager;
friend class NodeBuilder;
friend class ::cvc5::internal::expr::attr::AttributeManager;
friend struct ::cvc5::internal::expr::attr::SmtAttributes;
/**
* 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);
// May throw an AssertionException if the Node is not live, i.e. the ref count
// is not positive.
inline void assertTNodeNotExpired() const
{
if(!ref_count) {
Assert(d_nv->d_rc > 0) << "TNode pointing to an expired NodeValue";
}
}
public:
/**
* Cache-aware, recursive version of substitute() used by the public
* member function with a similar signature.
*/
Node substitute(TNode node,
TNode replacement,
std::unordered_map& cache) const;
/**
* Cache-aware, recursive version of substitute() used by the public
* member function with a similar signature.
*/
template
Node substitute(Iterator1 nodesBegin,
Iterator1 nodesEnd,
Iterator2 replacementsBegin,
Iterator2 replacementsEnd,
std::unordered_map& cache) const;
/**
* Cache-aware, recursive version of substitute() used by the public
* member function with a similar signature.
*/
template
Node substitute(Iterator substitutionsBegin,
Iterator substitutionsEnd,
std::unordered_map& cache) const;
/** Default constructor, makes a null expression.
*
* This constructor is `explicit` to avoid accidentially creating a null node
* from an empty braced-init-list.
*/
explicit NodeTemplate() : d_nv(&expr::NodeValue::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();
/**
* 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::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));
}
/**
* Returns true if this node represents a constant
* @return true if const
*/
bool isConst() const;
/**
* Returns true if this node represents a variable
* @return true if variable
*/
inline bool isVar() const {
assertTNodeNotExpired();
return getMetaKind() == kind::metakind::VARIABLE;
}
/**
* Returns true if this node represents a nullary operator
*/
inline bool isNullaryOp() const {
assertTNodeNotExpired();
return getMetaKind() == kind::metakind::NULLARY_OPERATOR;
}
/**
* Returns true if this node represents a closure, that is an expression
* that binds variables.
*/
inline bool isClosure() const {
assertTNodeNotExpired();
return isClosureKind(getKind());
}
/**
* Returns the unique id of this node
* @return the ud
*/
uint64_t getId() const
{
assertTNodeNotExpired();
return d_nv->getId();
}
/**
* Returns a node representing the operator of this expression.
* If this is an APPLY_UF, 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;
/**
* Same as getType, but does not throw a type exception if this term is
* not well-typed. Instead, this method will return the null type.
*/
TypeNode getTypeOrNull(bool check = false) const;
/**
* Has name? Return true if this node has an associated variable
* name (via the attribute expr::VarNameAttr). This is true typically for
* user-created variables.
*/
bool hasName() const;
/**
* Get the name. Returns the string value of the expr::VarNameAttr attribute
* for this node.
*/
std::string getName() const;
/**
* Substitution of Nodes.
*/
Node substitute(TNode node, TNode replacement) const;
/**
* Simultaneous substitution of Nodes. Elements in the Iterator1
* range will be replaced by their corresponding element in the
* Iterator2 range. Both ranges should have the same size.
*/
template
Node substitute(Iterator1 nodesBegin,
Iterator1 nodesEnd,
Iterator2 replacementsBegin,
Iterator2 replacementsEnd) const;
/**
* Simultaneous substitution of Nodes. Iterators should be over
* pairs (x,y) for the rewrites [x->y].
*/
template
Node substitute(Iterator substitutionsBegin,
Iterator substitutionsEnd) const;
/**
* Simultaneous substitution of Nodes in cache.
*/
Node substitute(std::unordered_map& cache) 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 reference count of this node.
* @return the refcount
*/
unsigned getRefCount() const {
return d_nv->getRefCount();
}
/**
* 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. */
using const_iterator =
typename expr::NodeValue::iterator>;
/**
* Reverse constant iterator allowing for scanning through the children in
* reverse order.
*/
using const_reverse_iterator = std::reverse_iterator<
typename expr::NodeValue::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 std::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" ADD, for instance, since unary
* PLUSes don't exist---begin(ADD) will give an iterator over the
* children if the node's an ADD node, otherwise give an iterator
* over the node itself, as if it were a unary ADD.
* @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" ADD, for instance, since unary PLUSes
* don't exist---begin(ADD) will give an iterator over the children
* if the node's an ADD node, otherwise give an iterator over the
* node itself, as if it were a unary ADD.
* @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
*/
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.
*/
const_iterator end() const
{
assertTNodeNotExpired();
return d_nv->end< NodeTemplate >();
}
/**
* Returns the const_reverse_iterator pointing to the last child.
* @return the const_reverse_iterator
*/
const_reverse_iterator rbegin() const
{
assertTNodeNotExpired();
return std::make_reverse_iterator(d_nv->end>());
}
/**
* Returns the const_reverse_iterator pointing to one before the first child.
* @return the end of the const_reverse_iterator.
*/
const_reverse_iterator rend() const
{
assertTNodeNotExpired();
return std::make_reverse_iterator(d_nv->begin>());
}
/**
* 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" ADD, for instance, since unary
* PLUSes don't exist---begin(ADD) will give an iterator over the
* children if the node's an ADD node, otherwise give an iterator
* over the node itself, as if it were a unary ADD.
* @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" ADD, for instance, since unary PLUSes
* don't exist---begin(ADD) will give an iterator over the children
* if the node's an ADD node, otherwise give an iterator over the
* node itself, as if it were a unary ADD.
* @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();
}
/**
* Converts this node into a string representation and sends it to the
* given stream
*
* @param out the stream to serialize this node to
*/
inline void toStream(std::ostream& out) const
{
assertTNodeNotExpired();
d_nv->toStream(out);
}
void constToStream(std::ostream& out) const
{
kind::metakind::nodeValueConstantToStream(out, d_nv);
}
/**
* 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;
template
NodeTemplate eqNode(const NodeTemplate& right) const;
NodeTemplate notNode() const;
NodeTemplate negate() const;
template
NodeTemplate andNode(const NodeTemplate& right) const;
template
NodeTemplate orNode(const NodeTemplate& right) const;
template
NodeTemplate iteNode(const NodeTemplate& thenpart,
const NodeTemplate& elsepart) const;
template
NodeTemplate impNode(const NodeTemplate& right) const;
template
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);
return out;
}
/**
* Serialize a vector of nodes to given stream.
*
* @param out the output stream to use
* @param container the vector of nodes to output to the stream
* @return the stream
*/
template
std::ostream& operator<<(std::ostream& out,
const std::vector>& container)
{
container_to_stream(out, container);
return out;
}
/**
* Serialize a set of nodes to the given stream.
*
* @param out the output stream to use
* @param container the set of nodes to output to the stream
* @return the stream
*/
template
std::ostream& operator<<(std::ostream& out,
const std::set>& container)
{
container_to_stream(out, container);
return out;
}
/**
* Serialize an unordered_set of nodes to the given stream.
*
* @param out the output stream to use
* @param container the unordered_set of nodes to output to the stream
* @return the stream
*/
template
std::ostream& operator<<(
std::ostream& out,
const std::unordered_set, hash_function>& container)
{
container_to_stream(out, container);
return out;
}
/**
* Serialize a map of nodes to the given stream.
*
* @param out the output stream to use
* @param container the map of nodes to output to the stream
* @return the stream
*/
template
std::ostream& operator<<(
std::ostream& out,
const std::map, V>& container)
{
container_to_stream(out, container);
return out;
}
/**
* Serialize an unordered_map of nodes to the given stream.
*
* @param out the output stream to use
* @param container the unordered_map of nodes to output to the stream
* @return the stream
*/
template
std::ostream& operator<<(
std::ostream& out,
const std::unordered_map, V, HF>& container)
{
container_to_stream(out, container);
return out;
}
} // namespace cvc5::internal
//#include "expr/attribute.h"
#include "expr/node_manager.h"
namespace cvc5::internal {
using TNodePairHashFunction =
PairHashFunction, std::hash>;
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 {
assertTNodeNotExpired();
return NodeManager::currentNM()->getAttribute(*this, AttrKind());
}
template
template
inline bool NodeTemplate::
hasAttribute(const AttrKind&) const {
assertTNodeNotExpired();
return NodeManager::currentNM()->hasAttribute(*this, AttrKind());
}
template
template
inline bool NodeTemplate::getAttribute(const AttrKind&,
typename AttrKind::value_type& ret) const {
assertTNodeNotExpired();
return NodeManager::currentNM()->getAttribute(*this, AttrKind(), ret);
}
template
template
inline void NodeTemplate::
setAttribute(const AttrKind&, const typename AttrKind::value_type& value) {
assertTNodeNotExpired();
NodeManager::currentNM()->setAttribute(*this, AttrKind(), value);
}
template
NodeTemplate NodeTemplate::s_null(&expr::NodeValue::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 || d_nv == &expr::NodeValue::null())
<< "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() {
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(__builtin_expect( ( d_nv != e.d_nv ), true )) {
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(__builtin_expect( ( d_nv != e.d_nv ), true )) {
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
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::negate() const {
assertTNodeNotExpired();
return (getKind() == Kind::NOT)
? NodeTemplate(d_nv->getChild(0))
: NodeManager::currentNM()->mkNode(Kind::NOT, *this);
}
template
template
NodeTemplate
NodeTemplate::andNode(const NodeTemplate& right) const {
assertTNodeNotExpired();
return NodeManager::currentNM()->mkNode(Kind::AND, *this, right);
}
template
template
NodeTemplate
NodeTemplate::orNode(const NodeTemplate& right) const {
assertTNodeNotExpired();
return NodeManager::currentNM()->mkNode(Kind::OR, *this, right);
}
template
template
NodeTemplate
NodeTemplate::iteNode(const NodeTemplate& thenpart,
const NodeTemplate& elsepart) const {
assertTNodeNotExpired();
return NodeManager::currentNM()->mkNode(Kind::ITE, *this, thenpart, elsepart);
}
template
template
NodeTemplate
NodeTemplate::impNode(const NodeTemplate& right) const {
assertTNodeNotExpired();
return NodeManager::currentNM()->mkNode(Kind::IMPLIES, *this, right);
}
template
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_UF, then the operator will be a functional term.
* Otherwise, it will be a node with kind BUILTIN.
*/
template
NodeTemplate NodeTemplate::getOperator() const
{
assertTNodeNotExpired();
kind::MetaKind mk = getMetaKind();
if (mk == kind::metakind::OPERATOR)
{
/* Returns a BUILTIN node. */
return NodeManager::currentNM()->operatorOf(getKind());
}
Assert(mk == kind::metakind::PARAMETERIZED);
/* The operator is the first child. */
return Node(d_nv->d_children[0]);
}
/**
* 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
{
assertTNodeNotExpired();
TypeNode tn = NodeManager::currentNM()->getType(*this, check);
if (tn.isNull())
{
// recompute with an error stream and throw a type exception
std::stringstream errOutTmp;
tn = NodeManager::currentNM()->getType(*this, check, &errOutTmp);
throw TypeCheckingExceptionPrivate(*this, errOutTmp.str());
}
return tn;
}
template
TypeNode NodeTemplate::getTypeOrNull(bool check) const
{
assertTNodeNotExpired();
return NodeManager::currentNM()->getType(*this, check);
}
template
inline Node
NodeTemplate::substitute(TNode node, TNode replacement) const {
if (node == *this) {
return replacement;
}
std::unordered_map cache;
return substitute(node, replacement, cache);
}
template
Node NodeTemplate::substitute(
TNode node,
TNode replacement,
std::unordered_map& cache) const
{
Assert(node != *this);
if (getNumChildren() == 0 || node == replacement)
{
return *this;
}
// in cache?
typename std::unordered_map::const_iterator i =
cache.find(*this);
if(i != cache.end()) {
return (*i).second;
}
// otherwise compute
NodeBuilder nb(getKind());
if(getMetaKind() == kind::metakind::PARAMETERIZED) {
// push the operator
if(getOperator() == node) {
nb << replacement;
} else {
nb << getOperator().substitute(node, replacement, cache);
}
}
for (const_iterator it = begin(), iend = end(); it != iend; ++it)
{
if (*it == node)
{
nb << replacement;
}
else
{
nb << (*it).substitute(node, replacement, cache);
}
}
// put in cache
Node n = nb;
cache[*this] = n;
return n;
}
template
template
inline Node
NodeTemplate::substitute(Iterator1 nodesBegin,
Iterator1 nodesEnd,
Iterator2 replacementsBegin,
Iterator2 replacementsEnd) const {
std::unordered_map cache;
return substitute(nodesBegin, nodesEnd,
replacementsBegin, replacementsEnd, cache);
}
template
template
Node NodeTemplate::substitute(
Iterator1 nodesBegin,
Iterator1 nodesEnd,
Iterator2 replacementsBegin,
Iterator2 replacementsEnd,
std::unordered_map& cache) const
{
// in cache?
typename std::unordered_map::const_iterator i =
cache.find(*this);
if(i != cache.end()) {
return (*i).second;
}
// otherwise compute
Assert(std::distance(nodesBegin, nodesEnd)
== std::distance(replacementsBegin, replacementsEnd))
<< "Substitution iterator ranges must be equal size";
Iterator1 j = std::find(nodesBegin, nodesEnd, TNode(*this));
if(j != nodesEnd) {
Iterator2 b = replacementsBegin;
std::advance(b, std::distance(nodesBegin, j));
Node n = *b;
cache[*this] = n;
return n;
} else if(getNumChildren() == 0) {
cache[*this] = *this;
return *this;
} else {
NodeBuilder nb(getKind());
if(getMetaKind() == kind::metakind::PARAMETERIZED) {
// push the operator
nb << getOperator().substitute(nodesBegin, nodesEnd,
replacementsBegin, replacementsEnd,
cache);
}
for (const_iterator it = begin(), iend = end(); it != iend; ++it)
{
nb << (*it).substitute(
nodesBegin, nodesEnd, replacementsBegin, replacementsEnd, cache);
}
Node n = nb;
cache[*this] = n;
return n;
}
}
template
template
inline Node
NodeTemplate::substitute(Iterator substitutionsBegin,
Iterator substitutionsEnd) const {
std::unordered_map cache;
return substitute(substitutionsBegin, substitutionsEnd, cache);
}
template
inline Node NodeTemplate::substitute(
std::unordered_map& cache) const
{
// Since no substitution is given (other than what may already be in the
// cache), we pass dummy iterators to conform to the main substitute method,
// giving the same value to substitutionsBegin and substitutionsEnd.
return substitute(cache.cend(), cache.cend(), cache);
}
template
template
Node NodeTemplate::substitute(
Iterator substitutionsBegin,
Iterator substitutionsEnd,
std::unordered_map& cache) const
{
// in cache?
typename std::unordered_map::const_iterator i =
cache.find(*this);
if(i != cache.end()) {
return (*i).second;
}
// otherwise compute
Iterator j = find_if(
substitutionsBegin,
substitutionsEnd,
[this](const auto& subst){ return subst.first == *this; });
if(j != substitutionsEnd) {
Node n = (*j).second;
cache[*this] = n;
return n;
} else if(getNumChildren() == 0) {
cache[*this] = *this;
return *this;
} else {
NodeBuilder nb(getKind());
if(getMetaKind() == kind::metakind::PARAMETERIZED) {
// push the operator
nb << getOperator().substitute(substitutionsBegin, substitutionsEnd, cache);
}
for (const_iterator it = begin(), iend = end(); it != iend; ++it)
{
nb << (*it).substitute(substitutionsBegin, substitutionsEnd, cache);
}
Node n = nb;
cache[*this] = n;
return n;
}
}
} // namespace cvc5::internal
#endif /* CVC5__NODE_H */