1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Morgan Deters, Aina Niemetz, Dejan Jovanovic |
4 |
|
* |
5 |
|
* This file is part of the cvc5 project. |
6 |
|
* |
7 |
|
* Copyright (c) 2009-2021 by the authors listed in the file AUTHORS |
8 |
|
* in the top-level source directory and their institutional affiliations. |
9 |
|
* All rights reserved. See the file COPYING in the top-level source |
10 |
|
* directory for licensing information. |
11 |
|
* **************************************************************************** |
12 |
|
* |
13 |
|
* A node value. |
14 |
|
* |
15 |
|
* The actual node implementation. |
16 |
|
* Instances of this class are generally referenced through cvc5::Node rather |
17 |
|
* than by pointer. Note that cvc5::Node maintains the reference count on |
18 |
|
* NodeValue instances. |
19 |
|
*/ |
20 |
|
|
21 |
|
#include "cvc5_private.h" |
22 |
|
|
23 |
|
// circular dependency |
24 |
|
#include "expr/metakind.h" |
25 |
|
|
26 |
|
#ifndef CVC5__EXPR__NODE_VALUE_H |
27 |
|
#define CVC5__EXPR__NODE_VALUE_H |
28 |
|
|
29 |
|
#include <iterator> |
30 |
|
#include <string> |
31 |
|
|
32 |
|
#include "expr/kind.h" |
33 |
|
#include "options/language.h" |
34 |
|
|
35 |
|
namespace cvc5 { |
36 |
|
|
37 |
|
template <bool ref_count> class NodeTemplate; |
38 |
|
class TypeNode; |
39 |
|
class NodeBuilder; |
40 |
|
class NodeManager; |
41 |
|
|
42 |
|
namespace expr { |
43 |
|
class NodeValue; |
44 |
|
} |
45 |
|
|
46 |
|
namespace kind { |
47 |
|
namespace metakind { |
48 |
|
template < ::cvc5::Kind k, bool pool> |
49 |
|
struct NodeValueConstCompare; |
50 |
|
|
51 |
|
struct NodeValueCompare; |
52 |
|
struct NodeValueConstPrinter; |
53 |
|
|
54 |
|
void deleteNodeValueConstant(::cvc5::expr::NodeValue* nv); |
55 |
|
} // namespace metakind |
56 |
|
} // namespace kind |
57 |
|
|
58 |
|
namespace expr { |
59 |
|
|
60 |
|
/** |
61 |
|
* This is a NodeValue. |
62 |
|
*/ |
63 |
|
class NodeValue |
64 |
|
{ |
65 |
|
template <bool> |
66 |
|
friend class ::cvc5::NodeTemplate; |
67 |
|
friend class ::cvc5::TypeNode; |
68 |
|
friend class ::cvc5::NodeBuilder; |
69 |
|
friend class ::cvc5::NodeManager; |
70 |
|
|
71 |
|
template <Kind k, bool pool> |
72 |
|
friend struct ::cvc5::kind::metakind::NodeValueConstCompare; |
73 |
|
|
74 |
|
friend struct ::cvc5::kind::metakind::NodeValueCompare; |
75 |
|
friend struct ::cvc5::kind::metakind::NodeValueConstPrinter; |
76 |
|
|
77 |
|
friend void ::cvc5::kind::metakind::deleteNodeValueConstant(NodeValue* nv); |
78 |
|
|
79 |
|
friend class RefCountGuard; |
80 |
|
|
81 |
|
/* ------------------------------------------------------------------------ */ |
82 |
|
public: |
83 |
|
/* ------------------------------------------------------------------------ */ |
84 |
|
|
85 |
|
using nv_iterator = NodeValue**; |
86 |
|
using const_nv_iterator = NodeValue const* const*; |
87 |
|
|
88 |
|
template <class T> |
89 |
|
class iterator |
90 |
|
{ |
91 |
|
public: |
92 |
|
using iterator_category = std::random_access_iterator_tag; |
93 |
|
using value_type = T; |
94 |
|
using difference_type = std::ptrdiff_t; |
95 |
|
using pointer = T*; |
96 |
|
using reference = T; |
97 |
|
|
98 |
308211760 |
iterator() : d_i(NULL) {} |
99 |
1432668959 |
explicit iterator(const_nv_iterator i) : d_i(i) {} |
100 |
|
|
101 |
|
/** Conversion of a TNode iterator to a Node iterator. */ |
102 |
312869213 |
inline operator NodeValue::iterator<NodeTemplate<true> >() |
103 |
|
{ |
104 |
312869213 |
return iterator<NodeTemplate<true> >(d_i); |
105 |
|
} |
106 |
|
|
107 |
|
inline T operator*() const; |
108 |
|
|
109 |
642672196 |
bool operator==(const iterator& i) const { return d_i == i.d_i; } |
110 |
|
|
111 |
642827169 |
bool operator!=(const iterator& i) const { return d_i != i.d_i; } |
112 |
|
|
113 |
597411687 |
iterator& operator++() |
114 |
|
{ |
115 |
597411687 |
++d_i; |
116 |
597411687 |
return *this; |
117 |
|
} |
118 |
|
|
119 |
17226 |
iterator operator++(int) { return iterator(d_i++); } |
120 |
|
|
121 |
12 |
iterator& operator--() |
122 |
|
{ |
123 |
12 |
--d_i; |
124 |
12 |
return *this; |
125 |
|
} |
126 |
|
|
127 |
|
iterator operator--(int) { return iterator(d_i--); } |
128 |
|
|
129 |
12970768 |
iterator& operator+=(difference_type p) |
130 |
|
{ |
131 |
12970768 |
d_i += p; |
132 |
12970768 |
return *this; |
133 |
|
} |
134 |
|
|
135 |
|
iterator& operator-=(difference_type p) |
136 |
|
{ |
137 |
|
d_i -= p; |
138 |
|
return *this; |
139 |
|
} |
140 |
|
|
141 |
863350 |
iterator operator+(difference_type p) { return iterator(d_i + p); } |
142 |
|
|
143 |
994 |
iterator operator-(difference_type p) { return iterator(d_i - p); } |
144 |
|
|
145 |
57995306 |
difference_type operator-(iterator i) { return d_i - i.d_i; } |
146 |
|
|
147 |
|
private: |
148 |
|
const_nv_iterator d_i; |
149 |
|
|
150 |
|
}; /* class NodeValue::iterator<T> */ |
151 |
|
|
152 |
7946594726 |
uint64_t getId() const { return d_id; } |
153 |
|
|
154 |
8529478841 |
Kind getKind() const { return dKindToKind(d_kind); } |
155 |
|
|
156 |
4980344935 |
kind::MetaKind getMetaKind() const { return kind::metaKindOf(getKind()); } |
157 |
|
|
158 |
1291784754 |
uint32_t getNumChildren() const |
159 |
|
{ |
160 |
2494762952 |
return (getMetaKind() == kind::metakind::PARAMETERIZED) ? d_nchildren - 1 |
161 |
2494762952 |
: d_nchildren; |
162 |
|
} |
163 |
|
|
164 |
|
/* ------------------------------ Header ---------------------------------- */ |
165 |
|
/** Number of bits reserved for reference counting. */ |
166 |
|
static constexpr uint32_t NBITS_REFCOUNT = 20; |
167 |
|
/** Number of bits reserved for node kind. */ |
168 |
|
static constexpr uint32_t NBITS_KIND = 10; |
169 |
|
/** Number of bits reserved for node id. */ |
170 |
|
static constexpr uint32_t NBITS_ID = 40; |
171 |
|
/** Number of bits reserved for number of children. */ |
172 |
|
static const uint32_t NBITS_NCHILDREN = 26; |
173 |
|
static_assert(NBITS_REFCOUNT + NBITS_KIND + NBITS_ID + NBITS_NCHILDREN == 96, |
174 |
|
"NodeValue header bit assignment does not sum to 96 !"); |
175 |
|
/* ------------------- This header fits into 96 bits ---------------------- */ |
176 |
|
|
177 |
|
/** Maximum number of children possible. */ |
178 |
|
static constexpr uint32_t MAX_CHILDREN = |
179 |
|
(static_cast<uint32_t>(1) << NBITS_NCHILDREN) - 1; |
180 |
|
|
181 |
|
uint32_t getRefCount() const { return d_rc; } |
182 |
|
|
183 |
|
NodeValue* getOperator() const; |
184 |
|
NodeValue* getChild(int i) const; |
185 |
|
|
186 |
|
/** If this is a CONST_* Node, extract the constant from it. */ |
187 |
|
template <class T> |
188 |
|
inline const T& getConst() const; |
189 |
|
|
190 |
6421314959 |
static inline NodeValue& null() |
191 |
|
{ |
192 |
6421314959 |
static NodeValue* s_null = new NodeValue(0); |
193 |
6421314959 |
return *s_null; |
194 |
|
} |
195 |
|
|
196 |
|
/** |
197 |
|
* Hash this NodeValue. For hash_maps, hash_sets, etc.. but this is |
198 |
|
* for expr package internal use only at present! This is likely to |
199 |
|
* be POORLY PERFORMING for other uses! For example, this gives |
200 |
|
* collisions for all VARIABLEs. |
201 |
|
* @return the hash value of this expression. |
202 |
|
*/ |
203 |
607595906 |
size_t poolHash() const |
204 |
|
{ |
205 |
607595906 |
if (getMetaKind() == kind::metakind::CONSTANT) |
206 |
|
{ |
207 |
266731882 |
return kind::metakind::NodeValueCompare::constHash(this); |
208 |
|
} |
209 |
|
|
210 |
340864024 |
size_t hash = d_kind; |
211 |
340864024 |
const_nv_iterator i = nv_begin(); |
212 |
340864024 |
const_nv_iterator i_end = nv_end(); |
213 |
2003622764 |
while (i != i_end) |
214 |
|
{ |
215 |
831379370 |
hash ^= (*i)->d_id + 0x9e3779b9 + (hash << 6) + (hash >> 2); |
216 |
831379370 |
++i; |
217 |
|
} |
218 |
340864024 |
return hash; |
219 |
|
} |
220 |
|
|
221 |
276111120 |
static inline uint32_t kindToDKind(Kind k) |
222 |
|
{ |
223 |
276111120 |
return ((uint32_t)k) & kindMask; |
224 |
|
} |
225 |
|
|
226 |
8529478841 |
static inline Kind dKindToKind(uint32_t d) |
227 |
|
{ |
228 |
8529478841 |
return (d == kindMask) ? kind::UNDEFINED_KIND : Kind(d); |
229 |
|
} |
230 |
|
|
231 |
|
std::string toString() const; |
232 |
|
|
233 |
|
void toStream(std::ostream& out, |
234 |
|
int toDepth = -1, |
235 |
|
size_t dag = 1, |
236 |
|
Language = Language::LANG_AUTO) const; |
237 |
|
|
238 |
|
void printAst(std::ostream& out, int indent = 0) const; |
239 |
|
|
240 |
|
template <typename T> |
241 |
|
inline iterator<T> begin() const; |
242 |
|
template <typename T> |
243 |
|
inline iterator<T> end() const; |
244 |
|
|
245 |
|
/* ------------------------------------------------------------------------ */ |
246 |
|
private: |
247 |
|
/* ------------------------------------------------------------------------ */ |
248 |
|
|
249 |
|
/** |
250 |
|
* RAII guard that increases the reference count if the reference count to be |
251 |
|
* > 0. Otherwise, this does nothing. This does not just increment the |
252 |
|
* reference count to avoid maxing out the d_rc field. This is only for low |
253 |
|
* level functions. |
254 |
|
*/ |
255 |
|
class RefCountGuard |
256 |
|
{ |
257 |
|
public: |
258 |
86507 |
RefCountGuard(const NodeValue* nv) : d_nv(const_cast<NodeValue*>(nv)) |
259 |
|
{ |
260 |
86507 |
d_increased = (d_nv->d_rc == 0); |
261 |
86507 |
if (d_increased) |
262 |
|
{ |
263 |
|
d_nv->d_rc = 1; |
264 |
|
} |
265 |
86507 |
} |
266 |
86507 |
~RefCountGuard() |
267 |
86507 |
{ |
268 |
|
// dec() without marking for deletion: we don't want to garbage |
269 |
|
// collect this NodeValue if ours is the last reference to it. |
270 |
|
// E.g., this can happen when debugging code calls the print |
271 |
|
// routines below. As RefCountGuards are scoped on the stack, |
272 |
|
// this should be fine---but not in multithreaded contexts! |
273 |
86507 |
if (d_increased) |
274 |
|
{ |
275 |
|
--d_nv->d_rc; |
276 |
|
} |
277 |
86507 |
} |
278 |
|
|
279 |
|
private: |
280 |
|
NodeValue* d_nv; |
281 |
|
bool d_increased; |
282 |
|
}; /* NodeValue::RefCountGuard */ |
283 |
|
|
284 |
|
/** Maximum reference count possible. Used for sticky |
285 |
|
* reference-counting. Should be (1 << num_bits(d_rc)) - 1 */ |
286 |
|
static constexpr uint32_t MAX_RC = |
287 |
|
(static_cast<uint32_t>(1) << NBITS_REFCOUNT) - 1; |
288 |
|
|
289 |
|
/** A mask for d_kind */ |
290 |
|
static constexpr uint32_t kindMask = |
291 |
|
(static_cast<uint32_t>(1) << NBITS_KIND) - 1; |
292 |
|
|
293 |
|
/** Uninitializing constructor for NodeBuilder's use. */ |
294 |
566224209 |
NodeValue() |
295 |
566224209 |
{ /* do not initialize! */ |
296 |
566224209 |
} |
297 |
|
/** Private constructor for the null value. */ |
298 |
|
NodeValue(int); |
299 |
|
|
300 |
|
void inc(); |
301 |
|
void dec(); |
302 |
|
|
303 |
|
/** Decrement ref counts of children */ |
304 |
|
inline void decrRefCounts(); |
305 |
|
|
306 |
|
bool isBeingDeleted() const; |
307 |
|
|
308 |
|
/** Returns true if the reference count is maximized. */ |
309 |
14 |
inline bool HasMaximizedReferenceCount() { return d_rc == MAX_RC; } |
310 |
|
|
311 |
|
nv_iterator nv_begin(); |
312 |
|
nv_iterator nv_end(); |
313 |
|
|
314 |
|
const_nv_iterator nv_begin() const; |
315 |
|
const_nv_iterator nv_end() const; |
316 |
|
|
317 |
|
/** |
318 |
|
* Indents the given stream a given amount of spaces. |
319 |
|
* @param out the stream to indent |
320 |
|
* @param indent the numer of spaces |
321 |
|
*/ |
322 |
|
static inline void indent(std::ostream& out, int indent) |
323 |
|
{ |
324 |
|
for (int i = 0; i < indent; i++) |
325 |
|
{ |
326 |
|
out << ' '; |
327 |
|
} |
328 |
|
} |
329 |
|
|
330 |
|
/** The ID (0 is reserved for the null value) */ |
331 |
|
uint64_t d_id : NBITS_ID; |
332 |
|
|
333 |
|
/** The expression's reference count. */ |
334 |
|
uint32_t d_rc : NBITS_REFCOUNT; |
335 |
|
|
336 |
|
/** Kind of the expression */ |
337 |
|
uint32_t d_kind : NBITS_KIND; |
338 |
|
|
339 |
|
/** Number of children */ |
340 |
|
uint32_t d_nchildren : NBITS_NCHILDREN; |
341 |
|
|
342 |
|
/** Variable number of child nodes */ |
343 |
|
NodeValue* d_children[0]; |
344 |
|
}; /* class NodeValue */ |
345 |
|
|
346 |
|
/** |
347 |
|
* Provides a symmetric addition operator to that already defined in |
348 |
|
* the iterator class. |
349 |
|
*/ |
350 |
|
NodeValue::iterator<NodeTemplate<true> > operator+( |
351 |
|
NodeValue::iterator<NodeTemplate<true> >::difference_type p, |
352 |
|
NodeValue::iterator<NodeTemplate<true> > i); |
353 |
|
|
354 |
|
/** |
355 |
|
* Provides a symmetric addition operator to that already defined in |
356 |
|
* the iterator class. |
357 |
|
*/ |
358 |
|
NodeValue::iterator<NodeTemplate<false> > operator+( |
359 |
|
NodeValue::iterator<NodeTemplate<false> >::difference_type p, |
360 |
|
NodeValue::iterator<NodeTemplate<false> > i); |
361 |
|
|
362 |
|
/** |
363 |
|
* For hash_maps, hash_sets, etc.. but this is for expr package |
364 |
|
* internal use only at present! This is likely to be POORLY |
365 |
|
* PERFORMING for other uses! NodeValue::poolHash() will lead to |
366 |
|
* collisions for all VARIABLEs. |
367 |
|
*/ |
368 |
|
struct NodeValuePoolHashFunction { |
369 |
607595906 |
inline size_t operator()(const NodeValue* nv) const { |
370 |
607595906 |
return (size_t) nv->poolHash(); |
371 |
|
} |
372 |
|
};/* struct NodeValuePoolHashFunction */ |
373 |
|
|
374 |
|
/** |
375 |
|
* For hash_maps, hash_sets, etc. |
376 |
|
*/ |
377 |
|
struct NodeValueIDHashFunction { |
378 |
116986949 |
inline size_t operator()(const NodeValue* nv) const { |
379 |
116986949 |
return (size_t) nv->getId(); |
380 |
|
} |
381 |
|
};/* struct NodeValueIDHashFunction */ |
382 |
|
|
383 |
|
|
384 |
|
/** |
385 |
|
* An equality predicate that is applicable between pointers to fully |
386 |
|
* constructed NodeValues. |
387 |
|
*/ |
388 |
|
struct NodeValueIDEquality { |
389 |
52828489 |
inline bool operator()(const NodeValue* a, const NodeValue* b) const { |
390 |
52828489 |
return a->getId() == b->getId(); |
391 |
|
} |
392 |
|
}; |
393 |
|
|
394 |
|
|
395 |
|
inline std::ostream& operator<<(std::ostream& out, const NodeValue& nv); |
396 |
|
|
397 |
|
} // namespace expr |
398 |
|
} // namespace cvc5 |
399 |
|
|
400 |
|
#include "expr/node_manager.h" |
401 |
|
|
402 |
|
namespace cvc5 { |
403 |
|
namespace expr { |
404 |
|
|
405 |
9836 |
inline NodeValue::NodeValue(int) : |
406 |
|
d_id(0), |
407 |
|
d_rc(MAX_RC), |
408 |
|
d_kind(kind::NULL_EXPR), |
409 |
9836 |
d_nchildren(0) { |
410 |
9836 |
} |
411 |
|
|
412 |
31430884 |
inline void NodeValue::decrRefCounts() { |
413 |
114547446 |
for(nv_iterator i = nv_begin(); i != nv_end(); ++i) { |
414 |
83116562 |
(*i)->dec(); |
415 |
|
} |
416 |
31430884 |
} |
417 |
|
|
418 |
17821486222 |
inline void NodeValue::inc() { |
419 |
17821486222 |
Assert(!isBeingDeleted()) |
420 |
|
<< "NodeValue is currently being deleted " |
421 |
|
"and increment is being called on it. Don't Do That!"; |
422 |
|
// FIXME multithreading |
423 |
17821486222 |
if (__builtin_expect((d_rc < MAX_RC - 1), true)) { |
424 |
12989528435 |
++d_rc; |
425 |
4831957787 |
} else if (__builtin_expect((d_rc == MAX_RC - 1), false)) { |
426 |
7 |
++d_rc; |
427 |
7 |
Assert(NodeManager::currentNM() != NULL) |
428 |
|
<< "No current NodeManager on incrementing of NodeValue: " |
429 |
|
"maybe a public cvc5 interface function is missing a " |
430 |
|
"NodeManagerScope ?"; |
431 |
7 |
NodeManager::currentNM()->markRefCountMaxedOut(this); |
432 |
|
} |
433 |
17821486222 |
} |
434 |
|
|
435 |
19564430909 |
inline void NodeValue::dec() { |
436 |
|
// FIXME multithreading |
437 |
19564430909 |
if(__builtin_expect( ( d_rc < MAX_RC ), true )) { |
438 |
12981463447 |
--d_rc; |
439 |
12981463447 |
if(__builtin_expect( ( d_rc == 0 ), false )) { |
440 |
49688674 |
Assert(NodeManager::currentNM() != NULL) |
441 |
|
<< "No current NodeManager on destruction of NodeValue: " |
442 |
|
"maybe a public cvc5 interface function is missing a " |
443 |
|
"NodeManagerScope ?"; |
444 |
49688674 |
NodeManager::currentNM()->markForDeletion(this); |
445 |
|
} |
446 |
|
} |
447 |
19564430909 |
} |
448 |
|
|
449 |
553408690 |
inline NodeValue::nv_iterator NodeValue::nv_begin() { |
450 |
553408690 |
return d_children; |
451 |
|
} |
452 |
|
|
453 |
1012049274 |
inline NodeValue::nv_iterator NodeValue::nv_end() { |
454 |
1012049274 |
return d_children + d_nchildren; |
455 |
|
} |
456 |
|
|
457 |
861502582 |
inline NodeValue::const_nv_iterator NodeValue::nv_begin() const { |
458 |
861502582 |
return d_children; |
459 |
|
} |
460 |
|
|
461 |
601183303 |
inline NodeValue::const_nv_iterator NodeValue::nv_end() const { |
462 |
601183303 |
return d_children + d_nchildren; |
463 |
|
} |
464 |
|
|
465 |
|
template <typename T> |
466 |
275405903 |
inline NodeValue::iterator<T> NodeValue::begin() const { |
467 |
275405903 |
NodeValue* const* firstChild = d_children; |
468 |
275405903 |
if(getMetaKind() == kind::metakind::PARAMETERIZED) { |
469 |
13931111 |
++firstChild; |
470 |
|
} |
471 |
275405903 |
return iterator<T>(firstChild); |
472 |
|
} |
473 |
|
|
474 |
|
template <typename T> |
475 |
843512273 |
inline NodeValue::iterator<T> NodeValue::end() const { |
476 |
843512273 |
return iterator<T>(d_children + d_nchildren); |
477 |
|
} |
478 |
|
|
479 |
17821486222 |
inline bool NodeValue::isBeingDeleted() const { |
480 |
35642952772 |
return NodeManager::currentNM() != NULL && |
481 |
35642952772 |
NodeManager::currentNM()->isCurrentlyDeleting(this); |
482 |
|
} |
483 |
|
|
484 |
|
inline NodeValue* NodeValue::getOperator() const { |
485 |
|
Assert(getMetaKind() == kind::metakind::PARAMETERIZED); |
486 |
|
return d_children[0]; |
487 |
|
} |
488 |
|
|
489 |
1232846030 |
inline NodeValue* NodeValue::getChild(int i) const { |
490 |
1232846030 |
if(getMetaKind() == kind::metakind::PARAMETERIZED) { |
491 |
53516862 |
++i; |
492 |
|
} |
493 |
|
|
494 |
1232846030 |
Assert(i >= 0 && unsigned(i) < d_nchildren); |
495 |
1232846030 |
return d_children[i]; |
496 |
|
} |
497 |
|
|
498 |
|
} // namespace expr |
499 |
|
} // namespace cvc5 |
500 |
|
|
501 |
|
#include "expr/node.h" |
502 |
|
|
503 |
|
namespace cvc5 { |
504 |
|
namespace expr { |
505 |
|
|
506 |
|
template <typename T> |
507 |
754606702 |
inline T NodeValue::iterator<T>::operator*() const { |
508 |
754606702 |
return T(*d_i); |
509 |
|
} |
510 |
|
|
511 |
|
inline std::ostream& operator<<(std::ostream& out, const NodeValue& nv) { |
512 |
|
nv.toStream(out, |
513 |
|
Node::setdepth::getDepth(out), |
514 |
|
Node::dag::getDag(out), |
515 |
|
Node::setlanguage::getLanguage(out)); |
516 |
|
return out; |
517 |
|
} |
518 |
|
|
519 |
|
} // namespace expr |
520 |
|
|
521 |
|
#ifdef CVC5_DEBUG |
522 |
|
/** |
523 |
|
* Pretty printer for use within gdb. This is not intended to be used |
524 |
|
* outside of gdb. This writes to the Warning() stream and immediately |
525 |
|
* flushes the stream. |
526 |
|
*/ |
527 |
|
static void __attribute__((used)) debugPrintNodeValue(const expr::NodeValue* nv) { |
528 |
|
Warning() << Node::setdepth(-1) << Node::dag(true) |
529 |
|
<< Node::setlanguage(Language::LANG_AST) << *nv << std::endl; |
530 |
|
Warning().flush(); |
531 |
|
} |
532 |
|
static void __attribute__((used)) debugPrintNodeValueNoDag(const expr::NodeValue* nv) { |
533 |
|
Warning() << Node::setdepth(-1) << Node::dag(false) |
534 |
|
<< Node::setlanguage(Language::LANG_AST) << *nv << std::endl; |
535 |
|
Warning().flush(); |
536 |
|
} |
537 |
|
static void __attribute__((used)) debugPrintRawNodeValue(const expr::NodeValue* nv) { |
538 |
|
nv->printAst(Warning(), 0); |
539 |
|
Warning().flush(); |
540 |
|
} |
541 |
|
#endif /* CVC5_DEBUG */ |
542 |
|
|
543 |
|
} // namespace cvc5 |
544 |
|
|
545 |
|
#endif /* CVC5__EXPR__NODE_VALUE_H */ |