1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Morgan Deters, Andrew Reynolds, Christopher L. Conway |
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 manager for Nodes. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "cvc5_private.h" |
17 |
|
|
18 |
|
/* circular dependency; force node.h first */ |
19 |
|
//#include "expr/attribute.h" |
20 |
|
#include "expr/node.h" |
21 |
|
#include "expr/type_node.h" |
22 |
|
|
23 |
|
#ifndef CVC5__NODE_MANAGER_H |
24 |
|
#define CVC5__NODE_MANAGER_H |
25 |
|
|
26 |
|
#include <vector> |
27 |
|
#include <string> |
28 |
|
#include <unordered_set> |
29 |
|
|
30 |
|
#include "base/check.h" |
31 |
|
#include "expr/kind.h" |
32 |
|
#include "expr/metakind.h" |
33 |
|
#include "expr/node_value.h" |
34 |
|
|
35 |
|
namespace cvc5 { |
36 |
|
|
37 |
|
using Record = std::vector<std::pair<std::string, TypeNode>>; |
38 |
|
|
39 |
|
namespace api { |
40 |
|
class Solver; |
41 |
|
} |
42 |
|
|
43 |
|
class ResourceManager; |
44 |
|
class SkolemManager; |
45 |
|
class BoundVarManager; |
46 |
|
|
47 |
|
class DType; |
48 |
|
|
49 |
|
namespace expr { |
50 |
|
namespace attr { |
51 |
|
class AttributeUniqueId; |
52 |
|
class AttributeManager; |
53 |
|
} // namespace attr |
54 |
|
|
55 |
|
class TypeChecker; |
56 |
|
} // namespace expr |
57 |
|
|
58 |
|
/** |
59 |
|
* An interface that an interested party can implement and then subscribe |
60 |
|
* to NodeManager events via NodeManager::subscribeEvents(this). |
61 |
|
*/ |
62 |
18541 |
class NodeManagerListener { |
63 |
|
public: |
64 |
18541 |
virtual ~NodeManagerListener() {} |
65 |
2826 |
virtual void nmNotifyNewSort(TypeNode tn, uint32_t flags) {} |
66 |
6 |
virtual void nmNotifyNewSortConstructor(TypeNode tn, uint32_t flags) {} |
67 |
629 |
virtual void nmNotifyInstantiateSortConstructor(TypeNode ctor, TypeNode sort, |
68 |
629 |
uint32_t flags) {} |
69 |
1222 |
virtual void nmNotifyNewDatatypes(const std::vector<TypeNode>& datatypes, |
70 |
|
uint32_t flags) |
71 |
|
{ |
72 |
1222 |
} |
73 |
|
virtual void nmNotifyNewVar(TNode n) {} |
74 |
|
virtual void nmNotifyNewSkolem(TNode n, const std::string& comment, |
75 |
|
uint32_t flags) {} |
76 |
|
/** |
77 |
|
* Notify a listener of a Node that's being GCed. If this function stores a |
78 |
|
* reference |
79 |
|
* to the Node somewhere, very bad things will happen. |
80 |
|
*/ |
81 |
8171866 |
virtual void nmNotifyDeleteNode(TNode n) {} |
82 |
|
}; /* class NodeManagerListener */ |
83 |
|
|
84 |
|
class NodeManager |
85 |
|
{ |
86 |
|
friend class api::Solver; |
87 |
|
friend class expr::NodeValue; |
88 |
|
friend class expr::TypeChecker; |
89 |
|
friend class SkolemManager; |
90 |
|
|
91 |
|
friend class NodeBuilder; |
92 |
|
friend class NodeManagerScope; |
93 |
|
|
94 |
|
public: |
95 |
|
/** |
96 |
|
* Return true if given kind is n-ary. The test is based on n-ary kinds |
97 |
|
* having their maximal arity as the maximal possible number of children |
98 |
|
* of a node. |
99 |
|
*/ |
100 |
|
static bool isNAryKind(Kind k); |
101 |
|
|
102 |
|
private: |
103 |
|
/** Predicate for use with STL algorithms */ |
104 |
|
struct NodeValueReferenceCountNonZero { |
105 |
29140686 |
bool operator()(expr::NodeValue* nv) { return nv->d_rc > 0; } |
106 |
|
}; |
107 |
|
|
108 |
|
typedef std::unordered_set<expr::NodeValue*, |
109 |
|
expr::NodeValuePoolHashFunction, |
110 |
|
expr::NodeValuePoolEq> NodeValuePool; |
111 |
|
typedef std::unordered_set<expr::NodeValue*, |
112 |
|
expr::NodeValueIDHashFunction, |
113 |
|
expr::NodeValueIDEquality> NodeValueIDSet; |
114 |
|
|
115 |
|
static thread_local NodeManager* s_current; |
116 |
|
|
117 |
|
/** The skolem manager */ |
118 |
|
std::unique_ptr<SkolemManager> d_skManager; |
119 |
|
/** The bound variable manager */ |
120 |
|
std::unique_ptr<BoundVarManager> d_bvManager; |
121 |
|
|
122 |
|
NodeValuePool d_nodeValuePool; |
123 |
|
|
124 |
|
size_t next_id; |
125 |
|
|
126 |
|
expr::attr::AttributeManager* d_attrManager; |
127 |
|
|
128 |
|
/** |
129 |
|
* The node value we're currently freeing. This unique node value |
130 |
|
* is permitted to have outstanding TNodes to it (in "soft" |
131 |
|
* contexts, like as a key in attribute tables), even though |
132 |
|
* normally it's an error to have a TNode to a node value with a |
133 |
|
* reference count of 0. Being "under deletion" also enables |
134 |
|
* assertions that inc() is not called on it. |
135 |
|
*/ |
136 |
|
expr::NodeValue* d_nodeUnderDeletion; |
137 |
|
|
138 |
|
/** |
139 |
|
* True iff we are in reclaimZombies(). This avoids unnecessary |
140 |
|
* recursion; a NodeValue being deleted might zombify other |
141 |
|
* NodeValues, but these shouldn't trigger a (recursive) call to |
142 |
|
* reclaimZombies(). |
143 |
|
*/ |
144 |
|
bool d_inReclaimZombies; |
145 |
|
|
146 |
|
/** |
147 |
|
* The set of zombie nodes. We may want to revisit this design, as |
148 |
|
* we might like to delete nodes in least-recently-used order. But |
149 |
|
* we also need to avoid processing a zombie twice. |
150 |
|
*/ |
151 |
|
NodeValueIDSet d_zombies; |
152 |
|
|
153 |
|
/** |
154 |
|
* NodeValues with maxed out reference counts. These live as long as the |
155 |
|
* NodeManager. They have a custom deallocation procedure at the very end. |
156 |
|
*/ |
157 |
|
std::vector<expr::NodeValue*> d_maxedOut; |
158 |
|
|
159 |
|
/** |
160 |
|
* A set of operator singletons (w.r.t. to this NodeManager |
161 |
|
* instance) for operators. Conceptually, Nodes with kind, say, |
162 |
|
* PLUS, are APPLYs of a PLUS operator to arguments. This array |
163 |
|
* holds the set of operators for these things. A PLUS operator is |
164 |
|
* a Node with kind "BUILTIN", and if you call |
165 |
|
* plusOperator->getConst<cvc5::Kind>(), you get kind::PLUS back. |
166 |
|
*/ |
167 |
|
Node d_operators[kind::LAST_KIND]; |
168 |
|
|
169 |
|
/** unique vars per (Kind,Type) */ |
170 |
|
std::map< Kind, std::map< TypeNode, Node > > d_unique_vars; |
171 |
|
|
172 |
|
/** |
173 |
|
* A list of subscribers for NodeManager events. |
174 |
|
*/ |
175 |
|
std::vector<NodeManagerListener*> d_listeners; |
176 |
|
|
177 |
|
/** A list of datatypes owned by this node manager */ |
178 |
|
std::vector<std::unique_ptr<DType> > d_dtypes; |
179 |
|
|
180 |
|
/** |
181 |
|
* A map of tuple and record types to their corresponding datatype. |
182 |
|
*/ |
183 |
16756 |
class TupleTypeCache { |
184 |
|
public: |
185 |
|
std::map< TypeNode, TupleTypeCache > d_children; |
186 |
|
TypeNode d_data; |
187 |
|
TypeNode getTupleType( NodeManager * nm, std::vector< TypeNode >& types, unsigned index = 0 ); |
188 |
|
}; |
189 |
15264 |
class RecTypeCache { |
190 |
|
public: |
191 |
|
std::map< TypeNode, std::map< std::string, RecTypeCache > > d_children; |
192 |
|
TypeNode d_data; |
193 |
|
TypeNode getRecordType( NodeManager * nm, const Record& rec, unsigned index = 0 ); |
194 |
|
}; |
195 |
|
TupleTypeCache d_tt_cache; |
196 |
|
RecTypeCache d_rt_cache; |
197 |
|
|
198 |
|
/** |
199 |
|
* Keep a count of all abstract values produced by this NodeManager. |
200 |
|
* Abstract values have a type attribute, so if multiple SmtEngines |
201 |
|
* are attached to this NodeManager, we don't want their abstract |
202 |
|
* values to overlap. |
203 |
|
*/ |
204 |
|
unsigned d_abstractValueCount; |
205 |
|
|
206 |
|
/** |
207 |
|
* A counter used to produce unique skolem names. |
208 |
|
* |
209 |
|
* Note that it is NOT incremented when skolems are created using |
210 |
|
* SKOLEM_EXACT_NAME, so it is NOT a count of the skolems produced |
211 |
|
* by this node manager. |
212 |
|
*/ |
213 |
|
unsigned d_skolemCounter; |
214 |
|
|
215 |
|
/** |
216 |
|
* Look up a NodeValue in the pool associated to this NodeManager. |
217 |
|
* The NodeValue argument need not be a "completely-constructed" |
218 |
|
* NodeValue. In particular, "non-inlined" constants are permitted |
219 |
|
* (see below). |
220 |
|
* |
221 |
|
* For non-CONSTANT metakinds, nv's d_kind and d_nchildren should be |
222 |
|
* correctly set, and d_children[0..n-1] should be valid (extant) |
223 |
|
* NodeValues for lookup. |
224 |
|
* |
225 |
|
* For CONSTANT metakinds, nv's d_kind should be set correctly. |
226 |
|
* Normally a CONSTANT would have d_nchildren == 0 and the constant |
227 |
|
* value inlined in the d_children space. However, here we permit |
228 |
|
* "non-inlined" NodeValues to avoid unnecessary copying. For |
229 |
|
* these, d_nchildren == 1, and d_nchildren is a pointer to the |
230 |
|
* constant value. |
231 |
|
* |
232 |
|
* The point of this complex design is to permit efficient lookups |
233 |
|
* (without fully constructing a NodeValue). In the case that the |
234 |
|
* argument is not fully constructed, and this function returns |
235 |
|
* NULL, the caller should fully construct an equivalent one before |
236 |
|
* calling poolInsert(). NON-FULLY-CONSTRUCTED NODEVALUES are not |
237 |
|
* permitted in the pool! |
238 |
|
*/ |
239 |
|
inline expr::NodeValue* poolLookup(expr::NodeValue* nv) const; |
240 |
|
|
241 |
|
/** |
242 |
|
* Insert a NodeValue into the NodeManager's pool. |
243 |
|
* |
244 |
|
* It is an error to insert a NodeValue already in the pool. |
245 |
|
* Enquire first with poolLookup(). |
246 |
|
*/ |
247 |
|
inline void poolInsert(expr::NodeValue* nv); |
248 |
|
|
249 |
|
/** |
250 |
|
* Remove a NodeValue from the NodeManager's pool. |
251 |
|
* |
252 |
|
* It is an error to request the removal of a NodeValue from the |
253 |
|
* pool that is not in the pool. |
254 |
|
*/ |
255 |
|
inline void poolRemove(expr::NodeValue* nv); |
256 |
|
|
257 |
|
/** |
258 |
|
* Determine if nv is currently being deleted by the NodeManager. |
259 |
|
*/ |
260 |
15462166350 |
inline bool isCurrentlyDeleting(const expr::NodeValue* nv) const { |
261 |
15462166350 |
return d_nodeUnderDeletion == nv; |
262 |
|
} |
263 |
|
|
264 |
|
/** |
265 |
|
* Register a NodeValue as a zombie. |
266 |
|
*/ |
267 |
45516116 |
inline void markForDeletion(expr::NodeValue* nv) { |
268 |
45516116 |
Assert(nv->d_rc == 0); |
269 |
|
|
270 |
|
// if d_reclaiming is set, make sure we don't call |
271 |
|
// reclaimZombies(), because it's already running. |
272 |
45516116 |
if(Debug.isOn("gc")) { |
273 |
|
Debug("gc") << "zombifying node value " << nv |
274 |
|
<< " [" << nv->d_id << "]: "; |
275 |
|
nv->printAst(Debug("gc")); |
276 |
|
Debug("gc") << (d_inReclaimZombies ? " [CURRENTLY-RECLAIMING]" : "") |
277 |
|
<< std::endl; |
278 |
|
} |
279 |
|
|
280 |
|
// `d_zombies` uses the node id to hash and compare nodes. If `d_zombies` |
281 |
|
// already contains a node value with the same id as `nv`, but the pointers |
282 |
|
// are different, then the wrong `NodeManager` was in scope for one of the |
283 |
|
// two nodes when it reached refcount zero. |
284 |
45516116 |
Assert(d_zombies.find(nv) == d_zombies.end() || *d_zombies.find(nv) == nv); |
285 |
|
|
286 |
45516116 |
d_zombies.insert(nv); |
287 |
|
|
288 |
45516116 |
if(safeToReclaimZombies()) { |
289 |
30622611 |
if(d_zombies.size() > 5000) { |
290 |
2502 |
reclaimZombies(); |
291 |
|
} |
292 |
|
} |
293 |
45516116 |
} |
294 |
|
|
295 |
|
/** |
296 |
|
* Register a NodeValue as having a maxed out reference count. This NodeValue |
297 |
|
* will live as long as its containing NodeManager. |
298 |
|
*/ |
299 |
7 |
inline void markRefCountMaxedOut(expr::NodeValue* nv) { |
300 |
7 |
Assert(nv->HasMaximizedReferenceCount()); |
301 |
7 |
if(Debug.isOn("gc")) { |
302 |
|
Debug("gc") << "marking node value " << nv |
303 |
|
<< " [" << nv->d_id << "]: as maxed out" << std::endl; |
304 |
|
} |
305 |
7 |
d_maxedOut.push_back(nv); |
306 |
7 |
} |
307 |
|
|
308 |
|
/** |
309 |
|
* Reclaim all zombies. |
310 |
|
*/ |
311 |
|
void reclaimZombies(); |
312 |
|
|
313 |
|
/** |
314 |
|
* It is safe to collect zombies. |
315 |
|
*/ |
316 |
|
bool safeToReclaimZombies() const; |
317 |
|
|
318 |
|
/** |
319 |
|
* Returns a reverse topological sort of a list of NodeValues. The NodeValues |
320 |
|
* must be valid and have ids. The NodeValues are not modified (including ref |
321 |
|
* counts). |
322 |
|
*/ |
323 |
|
static std::vector<expr::NodeValue*> TopologicalSort( |
324 |
|
const std::vector<expr::NodeValue*>& roots); |
325 |
|
|
326 |
|
/** |
327 |
|
* This template gives a mechanism to stack-allocate a NodeValue |
328 |
|
* with enough space for N children (where N is a compile-time |
329 |
|
* constant). You use it like this: |
330 |
|
* |
331 |
|
* NVStorage<4> nvStorage; |
332 |
|
* NodeValue& nvStack = reinterpret_cast<NodeValue&>(nvStorage); |
333 |
|
* |
334 |
|
* ...and then you can use nvStack as a NodeValue that you know has |
335 |
|
* room for 4 children. |
336 |
|
*/ |
337 |
|
template <size_t N> |
338 |
218512464 |
struct NVStorage { |
339 |
|
expr::NodeValue nv; |
340 |
|
expr::NodeValue* child[N]; |
341 |
|
};/* struct NodeManager::NVStorage<N> */ |
342 |
|
|
343 |
|
// undefined private copy constructor (disallow copy) |
344 |
|
NodeManager(const NodeManager&) = delete; |
345 |
|
|
346 |
|
NodeManager& operator=(const NodeManager&) = delete; |
347 |
|
|
348 |
|
void init(); |
349 |
|
|
350 |
|
/** |
351 |
|
* Create a variable with the given name and type. NOTE that no |
352 |
|
* lookup is done on the name. If you mkVar("a", type) and then |
353 |
|
* mkVar("a", type) again, you have two variables. The NodeManager |
354 |
|
* version of this is private to avoid internal uses of mkVar() from |
355 |
|
* within cvc5. Such uses should employ SkolemManager::mkSkolem() instead. |
356 |
|
*/ |
357 |
|
Node mkVar(const std::string& name, const TypeNode& type); |
358 |
|
|
359 |
|
/** Create a variable with the given type. */ |
360 |
|
Node mkVar(const TypeNode& type); |
361 |
|
|
362 |
|
/** |
363 |
|
* Create a skolem constant with the given name, type, and comment. For |
364 |
|
* details, see SkolemManager::mkDummySkolem, which calls this method. |
365 |
|
* |
366 |
|
* This method is intentionally private. To create skolems, one should |
367 |
|
* call a method from SkolemManager for allocating a skolem in a standard |
368 |
|
* way, or otherwise use SkolemManager::mkDummySkolem. |
369 |
|
*/ |
370 |
|
Node mkSkolem(const std::string& prefix, |
371 |
|
const TypeNode& type, |
372 |
|
const std::string& comment = "", |
373 |
|
int flags = SKOLEM_DEFAULT); |
374 |
|
|
375 |
|
public: |
376 |
|
explicit NodeManager(); |
377 |
|
~NodeManager(); |
378 |
|
|
379 |
|
/** The node manager in the current public-facing cvc5 library context */ |
380 |
71271209994 |
static NodeManager* currentNM() { return s_current; } |
381 |
|
/** Get this node manager's skolem manager */ |
382 |
209079 |
SkolemManager* getSkolemManager() { return d_skManager.get(); } |
383 |
|
/** Get this node manager's bound variable manager */ |
384 |
694976 |
BoundVarManager* getBoundVarManager() { return d_bvManager.get(); } |
385 |
|
|
386 |
|
/** Subscribe to NodeManager events */ |
387 |
16929 |
void subscribeEvents(NodeManagerListener* listener) { |
388 |
16929 |
Assert(std::find(d_listeners.begin(), d_listeners.end(), listener) |
389 |
|
== d_listeners.end()) |
390 |
|
<< "listener already subscribed"; |
391 |
16929 |
d_listeners.push_back(listener); |
392 |
16929 |
} |
393 |
|
|
394 |
|
/** Unsubscribe from NodeManager events */ |
395 |
16929 |
void unsubscribeEvents(NodeManagerListener* listener) { |
396 |
16929 |
std::vector<NodeManagerListener*>::iterator elt = std::find(d_listeners.begin(), d_listeners.end(), listener); |
397 |
16929 |
Assert(elt != d_listeners.end()) << "listener not subscribed"; |
398 |
16929 |
d_listeners.erase(elt); |
399 |
16929 |
} |
400 |
|
|
401 |
|
/** |
402 |
|
* Return the datatype at the given index owned by this class. Type nodes are |
403 |
|
* associated with datatypes through the DatatypeIndexConstant class. The |
404 |
|
* argument index is intended to be a value taken from that class. |
405 |
|
* |
406 |
|
* Type nodes must access their DTypes through a level of indirection to |
407 |
|
* prevent cycles in the Node AST (as DTypes themselves contain Nodes), which |
408 |
|
* would lead to memory leaks. Thus TypeNode are given a DatatypeIndexConstant |
409 |
|
* which is used as an index to retrieve the DType via this call. |
410 |
|
*/ |
411 |
|
const DType& getDTypeForIndex(size_t index) const; |
412 |
|
|
413 |
|
/** Get a Kind from an operator expression */ |
414 |
|
static inline Kind operatorToKind(TNode n); |
415 |
|
|
416 |
|
/** Get corresponding application kind for function |
417 |
|
* |
418 |
|
* Different functional nodes are applied differently, according to their |
419 |
|
* type. For example, uninterpreted functions (of FUNCTION_TYPE) are applied |
420 |
|
* via APPLY_UF, while constructors (of CONSTRUCTOR_TYPE) via |
421 |
|
* APPLY_CONSTRUCTOR. This method provides the correct application according |
422 |
|
* to which functional type fun has. |
423 |
|
* |
424 |
|
* @param fun The functional node |
425 |
|
* @return the correct application kind for fun. If fun's type is not function |
426 |
|
* like (see TypeNode::isFunctionLike), then UNDEFINED_KIND is returned. |
427 |
|
*/ |
428 |
|
static Kind getKindForFunction(TNode fun); |
429 |
|
|
430 |
|
// general expression-builders |
431 |
|
|
432 |
|
/** Create a node with one child. */ |
433 |
|
Node mkNode(Kind kind, TNode child1); |
434 |
|
|
435 |
|
/** Create a node with two children. */ |
436 |
|
Node mkNode(Kind kind, TNode child1, TNode child2); |
437 |
|
|
438 |
|
/** Create a node with three children. */ |
439 |
|
Node mkNode(Kind kind, TNode child1, TNode child2, TNode child3); |
440 |
|
|
441 |
|
/** Create a node with four children. */ |
442 |
|
Node mkNode(Kind kind, TNode child1, TNode child2, TNode child3, |
443 |
|
TNode child4); |
444 |
|
|
445 |
|
/** Create a node with five children. */ |
446 |
|
Node mkNode(Kind kind, TNode child1, TNode child2, TNode child3, |
447 |
|
TNode child4, TNode child5); |
448 |
|
|
449 |
|
/** Create a node with an arbitrary number of children. */ |
450 |
|
template <bool ref_count> |
451 |
|
Node mkNode(Kind kind, const std::vector<NodeTemplate<ref_count> >& children); |
452 |
|
|
453 |
|
/** |
454 |
|
* Create an AND node with arbitrary number of children. This returns the |
455 |
|
* true node if children is empty, or the single node in children if |
456 |
|
* it contains only one node. |
457 |
|
* |
458 |
|
* We define construction of AND as a special case here since it is widely |
459 |
|
* used for e.g. constructing explanations. |
460 |
|
*/ |
461 |
|
template <bool ref_count> |
462 |
|
Node mkAnd(const std::vector<NodeTemplate<ref_count> >& children); |
463 |
|
|
464 |
|
/** |
465 |
|
* Create an OR node with arbitrary number of children. This returns the |
466 |
|
* false node if children is empty, or the single node in children if |
467 |
|
* it contains only one node. |
468 |
|
* |
469 |
|
* We define construction of OR as a special case here since it is widely |
470 |
|
* used for e.g. constructing explanations or lemmas. |
471 |
|
*/ |
472 |
|
template <bool ref_count> |
473 |
|
Node mkOr(const std::vector<NodeTemplate<ref_count> >& children); |
474 |
|
|
475 |
|
/** Create a node (with no children) by operator. */ |
476 |
|
Node mkNode(TNode opNode); |
477 |
|
|
478 |
|
/** Create a node with one child by operator. */ |
479 |
|
Node mkNode(TNode opNode, TNode child1); |
480 |
|
|
481 |
|
/** Create a node with two children by operator. */ |
482 |
|
Node mkNode(TNode opNode, TNode child1, TNode child2); |
483 |
|
|
484 |
|
/** Create a node with three children by operator. */ |
485 |
|
Node mkNode(TNode opNode, TNode child1, TNode child2, TNode child3); |
486 |
|
|
487 |
|
/** Create a node with four children by operator. */ |
488 |
|
Node mkNode(TNode opNode, TNode child1, TNode child2, TNode child3, |
489 |
|
TNode child4); |
490 |
|
|
491 |
|
/** Create a node with five children by operator. */ |
492 |
|
Node mkNode(TNode opNode, TNode child1, TNode child2, TNode child3, |
493 |
|
TNode child4, TNode child5); |
494 |
|
|
495 |
|
/** Create a node by applying an operator to the children. */ |
496 |
|
template <bool ref_count> |
497 |
|
Node mkNode(TNode opNode, const std::vector<NodeTemplate<ref_count> >& children); |
498 |
|
|
499 |
|
Node mkBoundVar(const std::string& name, const TypeNode& type); |
500 |
|
|
501 |
|
Node mkBoundVar(const TypeNode& type); |
502 |
|
|
503 |
|
/** get the canonical bound variable list for function type tn */ |
504 |
|
Node getBoundVarListForFunctionType( TypeNode tn ); |
505 |
|
|
506 |
|
/** |
507 |
|
* Create an Node by applying an associative operator to the children. |
508 |
|
* If <code>children.size()</code> is greater than the max arity for |
509 |
|
* <code>kind</code>, then the expression will be broken up into |
510 |
|
* suitably-sized chunks, taking advantage of the associativity of |
511 |
|
* <code>kind</code>. For example, if kind <code>FOO</code> has max arity |
512 |
|
* 2, then calling <code>mkAssociative(FOO,a,b,c)</code> will return |
513 |
|
* <code>(FOO (FOO a b) c)</code> or <code>(FOO a (FOO b c))</code>. |
514 |
|
* The order of the arguments will be preserved in a left-to-right |
515 |
|
* traversal of the resulting tree. |
516 |
|
*/ |
517 |
|
Node mkAssociative(Kind kind, const std::vector<Node>& children); |
518 |
|
|
519 |
|
/** |
520 |
|
* Create an Node by applying an binary left-associative operator to the |
521 |
|
* children. For example, mkLeftAssociative( f, { a, b, c } ) returns |
522 |
|
* f( f( a, b ), c ). |
523 |
|
*/ |
524 |
|
Node mkLeftAssociative(Kind kind, const std::vector<Node>& children); |
525 |
|
/** |
526 |
|
* Create an Node by applying an binary right-associative operator to the |
527 |
|
* children. For example, mkRightAssociative( f, { a, b, c } ) returns |
528 |
|
* f( a, f( b, c ) ). |
529 |
|
*/ |
530 |
|
Node mkRightAssociative(Kind kind, const std::vector<Node>& children); |
531 |
|
|
532 |
|
/** make chain |
533 |
|
* |
534 |
|
* Given a kind k and arguments t_1, ..., t_n, this returns the |
535 |
|
* conjunction of: |
536 |
|
* (k t_1 t_2) .... (k t_{n-1} t_n) |
537 |
|
* It is expected that k is a kind denoting a predicate, and args is a list |
538 |
|
* of terms of size >= 2 such that the terms above are well-typed. |
539 |
|
*/ |
540 |
|
Node mkChain(Kind kind, const std::vector<Node>& children); |
541 |
|
|
542 |
|
/** |
543 |
|
* Optional flags used to control behavior of NodeManager::mkSkolem(). |
544 |
|
* They should be composed with a bitwise OR (e.g., |
545 |
|
* "SKOLEM_NO_NOTIFY | SKOLEM_EXACT_NAME"). Of course, SKOLEM_DEFAULT |
546 |
|
* cannot be composed in such a manner. |
547 |
|
*/ |
548 |
|
enum SkolemFlags |
549 |
|
{ |
550 |
|
SKOLEM_DEFAULT = 0, /**< default behavior */ |
551 |
|
SKOLEM_NO_NOTIFY = 1, /**< do not notify subscribers */ |
552 |
|
SKOLEM_EXACT_NAME = 2, /**< do not make the name unique by adding the id */ |
553 |
|
SKOLEM_IS_GLOBAL = 4, /**< global vars appear in models even after a pop */ |
554 |
|
SKOLEM_BOOL_TERM_VAR = 8 /**< vars requiring kind BOOLEAN_TERM_VARIABLE */ |
555 |
|
}; /* enum SkolemFlags */ |
556 |
|
|
557 |
|
/** Create a instantiation constant with the given type. */ |
558 |
|
Node mkInstConstant(const TypeNode& type); |
559 |
|
|
560 |
|
/** Create a boolean term variable. */ |
561 |
|
Node mkBooleanTermVariable(); |
562 |
|
|
563 |
|
/** Make a new abstract value with the given type. */ |
564 |
|
Node mkAbstractValue(const TypeNode& type); |
565 |
|
|
566 |
|
/** make unique (per Type,Kind) variable. */ |
567 |
|
Node mkNullaryOperator(const TypeNode& type, Kind k); |
568 |
|
|
569 |
|
/** |
570 |
|
* Create a singleton set from the given element n. |
571 |
|
* @param t the element type of the returned set. |
572 |
|
* Note that the type of n needs to be a subtype of t. |
573 |
|
* @param n the single element in the singleton. |
574 |
|
* @return a singleton set constructed from the element n. |
575 |
|
*/ |
576 |
|
Node mkSingleton(const TypeNode& t, const TNode n); |
577 |
|
|
578 |
|
/** |
579 |
|
* Create a bag from the given element n along with its multiplicity m. |
580 |
|
* @param t the element type of the returned bag. |
581 |
|
* Note that the type of n needs to be a subtype of t. |
582 |
|
* @param n the element that is used to to construct the bag |
583 |
|
* @param m the multiplicity of the element n |
584 |
|
* @return a bag that contains m occurrences of n. |
585 |
|
*/ |
586 |
|
Node mkBag(const TypeNode& t, const TNode n, const TNode m); |
587 |
|
|
588 |
|
/** |
589 |
|
* Create a constant of type T. It will have the appropriate |
590 |
|
* CONST_* kind defined for T. |
591 |
|
*/ |
592 |
|
template <class T> |
593 |
|
Node mkConst(const T&); |
594 |
|
|
595 |
|
template <class T> |
596 |
|
TypeNode mkTypeConst(const T&); |
597 |
|
|
598 |
|
template <class NodeClass, class T> |
599 |
|
NodeClass mkConstInternal(const T&); |
600 |
|
|
601 |
|
/** Create a node with children. */ |
602 |
|
TypeNode mkTypeNode(Kind kind, TypeNode child1); |
603 |
|
TypeNode mkTypeNode(Kind kind, TypeNode child1, TypeNode child2); |
604 |
|
TypeNode mkTypeNode(Kind kind, TypeNode child1, TypeNode child2, |
605 |
|
TypeNode child3); |
606 |
|
TypeNode mkTypeNode(Kind kind, const std::vector<TypeNode>& children); |
607 |
|
|
608 |
|
/** |
609 |
|
* Determine whether Nodes of a particular Kind have operators. |
610 |
|
* @returns true if Nodes of Kind k have operators. |
611 |
|
*/ |
612 |
|
static inline bool hasOperator(Kind k); |
613 |
|
|
614 |
|
/** |
615 |
|
* Get the (singleton) operator of an OPERATOR-kinded kind. The |
616 |
|
* returned node n will have kind BUILTIN, and calling |
617 |
|
* n.getConst<cvc5::Kind>() will yield k. |
618 |
|
*/ |
619 |
5294819 |
inline TNode operatorOf(Kind k) { |
620 |
5294819 |
AssertArgument( kind::metaKindOf(k) == kind::metakind::OPERATOR, k, |
621 |
|
"Kind is not an OPERATOR-kinded kind " |
622 |
|
"in NodeManager::operatorOf()" ); |
623 |
5294819 |
return d_operators[k]; |
624 |
|
} |
625 |
|
|
626 |
|
/** |
627 |
|
* Retrieve an attribute for a node. |
628 |
|
* |
629 |
|
* @param nv the node value |
630 |
|
* @param attr an instance of the attribute kind to retrieve. |
631 |
|
* @returns the attribute, if set, or a default-constructed |
632 |
|
* <code>AttrKind::value_type</code> if not. |
633 |
|
*/ |
634 |
|
template <class AttrKind> |
635 |
|
inline typename AttrKind::value_type getAttribute(expr::NodeValue* nv, |
636 |
|
const AttrKind& attr) const; |
637 |
|
|
638 |
|
/** |
639 |
|
* Check whether an attribute is set for a node. |
640 |
|
* |
641 |
|
* @param nv the node value |
642 |
|
* @param attr an instance of the attribute kind to check |
643 |
|
* @returns <code>true</code> iff <code>attr</code> is set for |
644 |
|
* <code>nv</code>. |
645 |
|
*/ |
646 |
|
template <class AttrKind> |
647 |
|
inline bool hasAttribute(expr::NodeValue* nv, |
648 |
|
const AttrKind& attr) const; |
649 |
|
|
650 |
|
/** |
651 |
|
* Check whether an attribute is set for a node, and, if so, |
652 |
|
* retrieve it. |
653 |
|
* |
654 |
|
* @param nv the node value |
655 |
|
* @param attr an instance of the attribute kind to check |
656 |
|
* @param value a reference to an object of the attribute's value type. |
657 |
|
* <code>value</code> will be set to the value of the attribute, if it is |
658 |
|
* set for <code>nv</code>; otherwise, it will be set to the default |
659 |
|
* value of the attribute. |
660 |
|
* @returns <code>true</code> iff <code>attr</code> is set for |
661 |
|
* <code>nv</code>. |
662 |
|
*/ |
663 |
|
template <class AttrKind> |
664 |
|
inline bool getAttribute(expr::NodeValue* nv, |
665 |
|
const AttrKind& attr, |
666 |
|
typename AttrKind::value_type& value) const; |
667 |
|
|
668 |
|
/** |
669 |
|
* Set an attribute for a node. If the node doesn't have the |
670 |
|
* attribute, this function assigns one. If the node has one, this |
671 |
|
* overwrites it. |
672 |
|
* |
673 |
|
* @param nv the node value |
674 |
|
* @param attr an instance of the attribute kind to set |
675 |
|
* @param value the value of <code>attr</code> for <code>nv</code> |
676 |
|
*/ |
677 |
|
template <class AttrKind> |
678 |
|
inline void setAttribute(expr::NodeValue* nv, |
679 |
|
const AttrKind& attr, |
680 |
|
const typename AttrKind::value_type& value); |
681 |
|
|
682 |
|
/** |
683 |
|
* Retrieve an attribute for a TNode. |
684 |
|
* |
685 |
|
* @param n the node |
686 |
|
* @param attr an instance of the attribute kind to retrieve. |
687 |
|
* @returns the attribute, if set, or a default-constructed |
688 |
|
* <code>AttrKind::value_type</code> if not. |
689 |
|
*/ |
690 |
|
template <class AttrKind> |
691 |
|
inline typename AttrKind::value_type |
692 |
|
getAttribute(TNode n, const AttrKind& attr) const; |
693 |
|
|
694 |
|
/** |
695 |
|
* Check whether an attribute is set for a TNode. |
696 |
|
* |
697 |
|
* @param n the node |
698 |
|
* @param attr an instance of the attribute kind to check |
699 |
|
* @returns <code>true</code> iff <code>attr</code> is set for <code>n</code>. |
700 |
|
*/ |
701 |
|
template <class AttrKind> |
702 |
|
inline bool hasAttribute(TNode n, |
703 |
|
const AttrKind& attr) const; |
704 |
|
|
705 |
|
/** |
706 |
|
* Check whether an attribute is set for a TNode and, if so, retieve |
707 |
|
* it. |
708 |
|
* |
709 |
|
* @param n the node |
710 |
|
* @param attr an instance of the attribute kind to check |
711 |
|
* @param value a reference to an object of the attribute's value type. |
712 |
|
* <code>value</code> will be set to the value of the attribute, if it is |
713 |
|
* set for <code>nv</code>; otherwise, it will be set to the default value of |
714 |
|
* the attribute. |
715 |
|
* @returns <code>true</code> iff <code>attr</code> is set for <code>n</code>. |
716 |
|
*/ |
717 |
|
template <class AttrKind> |
718 |
|
inline bool getAttribute(TNode n, |
719 |
|
const AttrKind& attr, |
720 |
|
typename AttrKind::value_type& value) const; |
721 |
|
|
722 |
|
/** |
723 |
|
* Set an attribute for a node. If the node doesn't have the |
724 |
|
* attribute, this function assigns one. If the node has one, this |
725 |
|
* overwrites it. |
726 |
|
* |
727 |
|
* @param n the node |
728 |
|
* @param attr an instance of the attribute kind to set |
729 |
|
* @param value the value of <code>attr</code> for <code>n</code> |
730 |
|
*/ |
731 |
|
template <class AttrKind> |
732 |
|
inline void setAttribute(TNode n, |
733 |
|
const AttrKind& attr, |
734 |
|
const typename AttrKind::value_type& value); |
735 |
|
|
736 |
|
/** |
737 |
|
* Retrieve an attribute for a TypeNode. |
738 |
|
* |
739 |
|
* @param n the type node |
740 |
|
* @param attr an instance of the attribute kind to retrieve. |
741 |
|
* @returns the attribute, if set, or a default-constructed |
742 |
|
* <code>AttrKind::value_type</code> if not. |
743 |
|
*/ |
744 |
|
template <class AttrKind> |
745 |
|
inline typename AttrKind::value_type |
746 |
|
getAttribute(TypeNode n, const AttrKind& attr) const; |
747 |
|
|
748 |
|
/** |
749 |
|
* Check whether an attribute is set for a TypeNode. |
750 |
|
* |
751 |
|
* @param n the type node |
752 |
|
* @param attr an instance of the attribute kind to check |
753 |
|
* @returns <code>true</code> iff <code>attr</code> is set for <code>n</code>. |
754 |
|
*/ |
755 |
|
template <class AttrKind> |
756 |
|
inline bool hasAttribute(TypeNode n, |
757 |
|
const AttrKind& attr) const; |
758 |
|
|
759 |
|
/** |
760 |
|
* Check whether an attribute is set for a TypeNode and, if so, retieve |
761 |
|
* it. |
762 |
|
* |
763 |
|
* @param n the type node |
764 |
|
* @param attr an instance of the attribute kind to check |
765 |
|
* @param value a reference to an object of the attribute's value type. |
766 |
|
* <code>value</code> will be set to the value of the attribute, if it is |
767 |
|
* set for <code>nv</code>; otherwise, it will be set to the default value of |
768 |
|
* the attribute. |
769 |
|
* @returns <code>true</code> iff <code>attr</code> is set for <code>n</code>. |
770 |
|
*/ |
771 |
|
template <class AttrKind> |
772 |
|
inline bool getAttribute(TypeNode n, |
773 |
|
const AttrKind& attr, |
774 |
|
typename AttrKind::value_type& value) const; |
775 |
|
|
776 |
|
/** |
777 |
|
* Set an attribute for a type node. If the node doesn't have the |
778 |
|
* attribute, this function assigns one. If the type node has one, |
779 |
|
* this overwrites it. |
780 |
|
* |
781 |
|
* @param n the type node |
782 |
|
* @param attr an instance of the attribute kind to set |
783 |
|
* @param value the value of <code>attr</code> for <code>n</code> |
784 |
|
*/ |
785 |
|
template <class AttrKind> |
786 |
|
inline void setAttribute(TypeNode n, |
787 |
|
const AttrKind& attr, |
788 |
|
const typename AttrKind::value_type& value); |
789 |
|
|
790 |
|
/** Get the (singleton) type for Booleans. */ |
791 |
|
TypeNode booleanType(); |
792 |
|
|
793 |
|
/** Get the (singleton) type for integers. */ |
794 |
|
TypeNode integerType(); |
795 |
|
|
796 |
|
/** Get the (singleton) type for reals. */ |
797 |
|
TypeNode realType(); |
798 |
|
|
799 |
|
/** Get the (singleton) type for strings. */ |
800 |
|
TypeNode stringType(); |
801 |
|
|
802 |
|
/** Get the (singleton) type for RegExp. */ |
803 |
|
TypeNode regExpType(); |
804 |
|
|
805 |
|
/** Get the (singleton) type for rounding modes. */ |
806 |
|
TypeNode roundingModeType(); |
807 |
|
|
808 |
|
/** Get the bound var list type. */ |
809 |
|
TypeNode boundVarListType(); |
810 |
|
|
811 |
|
/** Get the instantiation pattern type. */ |
812 |
|
TypeNode instPatternType(); |
813 |
|
|
814 |
|
/** Get the instantiation pattern type. */ |
815 |
|
TypeNode instPatternListType(); |
816 |
|
|
817 |
|
/** |
818 |
|
* Get the (singleton) type for builtin operators (that is, the type |
819 |
|
* of the Node returned from Node::getOperator() when the operator |
820 |
|
* is built-in, like EQUAL). */ |
821 |
|
TypeNode builtinOperatorType(); |
822 |
|
|
823 |
|
/** |
824 |
|
* Make a function type from domain to range. |
825 |
|
* |
826 |
|
* @param domain the domain type |
827 |
|
* @param range the range type |
828 |
|
* @returns the functional type domain -> range |
829 |
|
*/ |
830 |
|
TypeNode mkFunctionType(const TypeNode& domain, |
831 |
|
const TypeNode& range); |
832 |
|
|
833 |
|
/** |
834 |
|
* Make a function type with input types from |
835 |
|
* argTypes. <code>argTypes</code> must have at least one element. |
836 |
|
* |
837 |
|
* @param argTypes the domain is a tuple (argTypes[0], ..., argTypes[n]) |
838 |
|
* @param range the range type |
839 |
|
* @returns the functional type (argTypes[0], ..., argTypes[n]) -> range |
840 |
|
*/ |
841 |
|
TypeNode mkFunctionType(const std::vector<TypeNode>& argTypes, |
842 |
|
const TypeNode& range); |
843 |
|
|
844 |
|
/** |
845 |
|
* Make a function type with input types from |
846 |
|
* <code>sorts[0..sorts.size()-2]</code> and result type |
847 |
|
* <code>sorts[sorts.size()-1]</code>. <code>sorts</code> must have |
848 |
|
* at least 2 elements. |
849 |
|
* |
850 |
|
* @param sorts The argument and range sort of the function type, where the |
851 |
|
* range type is the last in this vector. |
852 |
|
* @return the function type |
853 |
|
*/ |
854 |
|
TypeNode mkFunctionType(const std::vector<TypeNode>& sorts); |
855 |
|
|
856 |
|
/** |
857 |
|
* Make a predicate type with input types from |
858 |
|
* <code>sorts</code>. The result with be a function type with range |
859 |
|
* <code>BOOLEAN</code>. <code>sorts</code> must have at least one |
860 |
|
* element. |
861 |
|
*/ |
862 |
|
TypeNode mkPredicateType(const std::vector<TypeNode>& sorts); |
863 |
|
|
864 |
|
/** |
865 |
|
* Make a tuple type with types from |
866 |
|
* <code>types</code>. <code>types</code> must have at least one |
867 |
|
* element. |
868 |
|
* |
869 |
|
* @param types a vector of types |
870 |
|
* @returns the tuple type (types[0], ..., types[n]) |
871 |
|
*/ |
872 |
|
TypeNode mkTupleType(const std::vector<TypeNode>& types); |
873 |
|
|
874 |
|
/** |
875 |
|
* Make a record type with the description from rec. |
876 |
|
* |
877 |
|
* @param rec a description of the record |
878 |
|
* @returns the record type |
879 |
|
*/ |
880 |
|
TypeNode mkRecordType(const Record& rec); |
881 |
|
|
882 |
|
/** |
883 |
|
* @returns the symbolic expression type |
884 |
|
*/ |
885 |
|
TypeNode sExprType(); |
886 |
|
|
887 |
|
/** Make the type of floating-point with <code>exp</code> bit exponent and |
888 |
|
<code>sig</code> bit significand */ |
889 |
|
TypeNode mkFloatingPointType(unsigned exp, unsigned sig); |
890 |
|
TypeNode mkFloatingPointType(FloatingPointSize fs); |
891 |
|
|
892 |
|
/** Make the type of bitvectors of size <code>size</code> */ |
893 |
|
TypeNode mkBitVectorType(unsigned size); |
894 |
|
|
895 |
|
/** Make the type of arrays with the given parameterization */ |
896 |
|
inline TypeNode mkArrayType(TypeNode indexType, TypeNode constituentType); |
897 |
|
|
898 |
|
/** Make the type of set with the given parameterization */ |
899 |
|
inline TypeNode mkSetType(TypeNode elementType); |
900 |
|
|
901 |
|
/** Make the type of bags with the given parameterization */ |
902 |
|
TypeNode mkBagType(TypeNode elementType); |
903 |
|
|
904 |
|
/** Make the type of sequences with the given parameterization */ |
905 |
|
TypeNode mkSequenceType(TypeNode elementType); |
906 |
|
|
907 |
|
/** Bits for use in mkDatatypeType() flags. |
908 |
|
* |
909 |
|
* DATATYPE_FLAG_PLACEHOLDER indicates that the type should not be printed |
910 |
|
* out as a definition, for example, in models or during dumping. |
911 |
|
*/ |
912 |
|
enum |
913 |
|
{ |
914 |
|
DATATYPE_FLAG_NONE = 0, |
915 |
|
DATATYPE_FLAG_PLACEHOLDER = 1 |
916 |
|
}; /* enum */ |
917 |
|
|
918 |
|
/** Make a type representing the given datatype. */ |
919 |
|
TypeNode mkDatatypeType(DType& datatype, uint32_t flags = DATATYPE_FLAG_NONE); |
920 |
|
|
921 |
|
/** |
922 |
|
* Make a set of types representing the given datatypes, which may be |
923 |
|
* mutually recursive. |
924 |
|
*/ |
925 |
|
std::vector<TypeNode> mkMutualDatatypeTypes( |
926 |
|
const std::vector<DType>& datatypes, uint32_t flags = DATATYPE_FLAG_NONE); |
927 |
|
|
928 |
|
/** |
929 |
|
* Make a set of types representing the given datatypes, which may |
930 |
|
* be mutually recursive. unresolvedTypes is a set of SortTypes |
931 |
|
* that were used as placeholders in the Datatypes for the Datatypes |
932 |
|
* of the same name. This is just a more complicated version of the |
933 |
|
* above mkMutualDatatypeTypes() function, but is required to handle |
934 |
|
* complex types. |
935 |
|
* |
936 |
|
* For example, unresolvedTypes might contain the single sort "list" |
937 |
|
* (with that name reported from SortType::getName()). The |
938 |
|
* datatypes list might have the single datatype |
939 |
|
* |
940 |
|
* DATATYPE |
941 |
|
* list = cons(car:ARRAY INT OF list, cdr:list) | nil; |
942 |
|
* END; |
943 |
|
* |
944 |
|
* To represent the Type of the array, the user had to create a |
945 |
|
* placeholder type (an uninterpreted sort) to stand for "list" in |
946 |
|
* the type of "car". It is this placeholder sort that should be |
947 |
|
* passed in unresolvedTypes. If the datatype was of the simpler |
948 |
|
* form: |
949 |
|
* |
950 |
|
* DATATYPE |
951 |
|
* list = cons(car:list, cdr:list) | nil; |
952 |
|
* END; |
953 |
|
* |
954 |
|
* then no complicated Type needs to be created, and the above, |
955 |
|
* simpler form of mkMutualDatatypeTypes() is enough. |
956 |
|
*/ |
957 |
|
std::vector<TypeNode> mkMutualDatatypeTypes( |
958 |
|
const std::vector<DType>& datatypes, |
959 |
|
const std::set<TypeNode>& unresolvedTypes, |
960 |
|
uint32_t flags = DATATYPE_FLAG_NONE); |
961 |
|
|
962 |
|
/** |
963 |
|
* Make a type representing a constructor with the given argument (subfield) |
964 |
|
* types and return type range. |
965 |
|
*/ |
966 |
|
TypeNode mkConstructorType(const std::vector<TypeNode>& args, TypeNode range); |
967 |
|
|
968 |
|
/** Make a type representing a selector with the given parameterization */ |
969 |
|
TypeNode mkSelectorType(TypeNode domain, TypeNode range); |
970 |
|
|
971 |
|
/** Make a type representing a tester with given parameterization */ |
972 |
|
TypeNode mkTesterType(TypeNode domain); |
973 |
|
|
974 |
|
/** Make a type representing an updater with the given parameterization */ |
975 |
|
TypeNode mkDatatypeUpdateType(TypeNode domain, TypeNode range); |
976 |
|
|
977 |
|
/** Bits for use in mkSort() flags. */ |
978 |
|
enum |
979 |
|
{ |
980 |
|
SORT_FLAG_NONE = 0, |
981 |
|
SORT_FLAG_PLACEHOLDER = 1 |
982 |
|
}; /* enum */ |
983 |
|
|
984 |
|
/** Make a new (anonymous) sort of arity 0. */ |
985 |
|
TypeNode mkSort(uint32_t flags = SORT_FLAG_NONE); |
986 |
|
|
987 |
|
/** Make a new sort with the given name of arity 0. */ |
988 |
|
TypeNode mkSort(const std::string& name, uint32_t flags = SORT_FLAG_NONE); |
989 |
|
|
990 |
|
/** Make a new sort by parameterizing the given sort constructor. */ |
991 |
|
TypeNode mkSort(TypeNode constructor, |
992 |
|
const std::vector<TypeNode>& children, |
993 |
|
uint32_t flags = SORT_FLAG_NONE); |
994 |
|
|
995 |
|
/** Make a new sort with the given name and arity. */ |
996 |
|
TypeNode mkSortConstructor(const std::string& name, |
997 |
|
size_t arity, |
998 |
|
uint32_t flags = SORT_FLAG_NONE); |
999 |
|
|
1000 |
|
/** |
1001 |
|
* Get the type for the given node and optionally do type checking. |
1002 |
|
* |
1003 |
|
* Initial type computation will be near-constant time if |
1004 |
|
* type checking is not requested. Results are memoized, so that |
1005 |
|
* subsequent calls to getType() without type checking will be |
1006 |
|
* constant time. |
1007 |
|
* |
1008 |
|
* Initial type checking is linear in the size of the expression. |
1009 |
|
* Again, the results are memoized, so that subsequent calls to |
1010 |
|
* getType(), with or without type checking, will be constant |
1011 |
|
* time. |
1012 |
|
* |
1013 |
|
* NOTE: A TypeCheckingException can be thrown even when type |
1014 |
|
* checking is not requested. getType() will always return a |
1015 |
|
* valid and correct type and, thus, an exception will be thrown |
1016 |
|
* when no valid or correct type can be computed (e.g., if the |
1017 |
|
* arguments to a bit-vector operation aren't bit-vectors). When |
1018 |
|
* type checking is not requested, getType() will do the minimum |
1019 |
|
* amount of checking required to return a valid result. |
1020 |
|
* |
1021 |
|
* @param n the Node for which we want a type |
1022 |
|
* @param check whether we should check the type as we compute it |
1023 |
|
* (default: false) |
1024 |
|
*/ |
1025 |
|
TypeNode getType(TNode n, bool check = false); |
1026 |
|
|
1027 |
|
/** Reclaim zombies while there are more than k nodes in the pool (if possible).*/ |
1028 |
|
void reclaimZombiesUntil(uint32_t k); |
1029 |
|
|
1030 |
|
/** Reclaims all zombies (if possible).*/ |
1031 |
|
void reclaimAllZombies(); |
1032 |
|
|
1033 |
|
/** Size of the node pool. */ |
1034 |
|
size_t poolSize() const; |
1035 |
|
|
1036 |
|
/** Deletes a list of attributes from the NM's AttributeManager.*/ |
1037 |
|
void deleteAttributes(const std::vector< const expr::attr::AttributeUniqueId* >& ids); |
1038 |
|
|
1039 |
|
/** |
1040 |
|
* This function gives developers a hook into the NodeManager. |
1041 |
|
* This can be changed in node_manager.cpp without recompiling most of cvc5. |
1042 |
|
* |
1043 |
|
* debugHook is a debugging only function, and should not be present in |
1044 |
|
* any published code! |
1045 |
|
*/ |
1046 |
|
void debugHook(int debugFlag); |
1047 |
|
}; /* class NodeManager */ |
1048 |
|
|
1049 |
|
/** |
1050 |
|
* This class changes the "current" thread-global |
1051 |
|
* <code>NodeManager</code> when it is created and reinstates the |
1052 |
|
* previous thread-global <code>NodeManager</code> when it is |
1053 |
|
* destroyed, effectively maintaining a set of nested |
1054 |
|
* <code>NodeManager</code> scopes. This is especially useful on |
1055 |
|
* public-interface calls into the cvc5 library, where cvc5's notion |
1056 |
|
* of the "current" <code>NodeManager</code> should be set to match |
1057 |
|
* the calling context. See, for example, the implementations of |
1058 |
|
* public calls in the <code>SmtEngine</code> class. |
1059 |
|
* |
1060 |
|
* The client must be careful to create and destroy |
1061 |
|
* <code>NodeManagerScope</code> objects in a well-nested manner (such |
1062 |
|
* as on the stack). You may create a <code>NodeManagerScope</code> |
1063 |
|
* with <code>new</code> and destroy it with <code>delete</code>, or |
1064 |
|
* place it as a data member of an object that is, but if the scope of |
1065 |
|
* these <code>new</code>/<code>delete</code> pairs isn't properly |
1066 |
|
* maintained, the incorrect "current" <code>NodeManager</code> |
1067 |
|
* pointer may be restored after a delete. |
1068 |
|
*/ |
1069 |
|
class NodeManagerScope { |
1070 |
|
/** The old NodeManager, to be restored on destruction. */ |
1071 |
|
NodeManager* d_oldNodeManager; |
1072 |
|
public: |
1073 |
965717028 |
NodeManagerScope(NodeManager* nm) : d_oldNodeManager(NodeManager::s_current) |
1074 |
|
{ |
1075 |
965717028 |
NodeManager::s_current = nm; |
1076 |
965717028 |
Debug("current") << "node manager scope: " << NodeManager::s_current << "\n"; |
1077 |
965717028 |
} |
1078 |
|
|
1079 |
1931434056 |
~NodeManagerScope() { |
1080 |
965717028 |
NodeManager::s_current = d_oldNodeManager; |
1081 |
1931434056 |
Debug("current") << "node manager scope: " |
1082 |
965717028 |
<< "returning to " << NodeManager::s_current << "\n"; |
1083 |
965717028 |
} |
1084 |
|
};/* class NodeManagerScope */ |
1085 |
|
|
1086 |
10445 |
inline TypeNode NodeManager::mkArrayType(TypeNode indexType, |
1087 |
|
TypeNode constituentType) { |
1088 |
10445 |
CheckArgument(!indexType.isNull(), indexType, |
1089 |
|
"unexpected NULL index type"); |
1090 |
10445 |
CheckArgument(!constituentType.isNull(), constituentType, |
1091 |
|
"unexpected NULL constituent type"); |
1092 |
10445 |
CheckArgument(indexType.isFirstClass(), |
1093 |
|
indexType, |
1094 |
|
"cannot index arrays by types that are not first-class. Try " |
1095 |
|
"option --uf-ho."); |
1096 |
10445 |
CheckArgument(constituentType.isFirstClass(), |
1097 |
|
constituentType, |
1098 |
|
"cannot store types that are not first-class in arrays. Try " |
1099 |
|
"option --uf-ho."); |
1100 |
20890 |
Debug("arrays") << "making array type " << indexType << " " |
1101 |
10445 |
<< constituentType << std::endl; |
1102 |
10445 |
return mkTypeNode(kind::ARRAY_TYPE, indexType, constituentType); |
1103 |
|
} |
1104 |
|
|
1105 |
12916 |
inline TypeNode NodeManager::mkSetType(TypeNode elementType) { |
1106 |
12916 |
CheckArgument(!elementType.isNull(), elementType, |
1107 |
|
"unexpected NULL element type"); |
1108 |
12916 |
CheckArgument(elementType.isFirstClass(), |
1109 |
|
elementType, |
1110 |
|
"cannot store types that are not first-class in sets. Try " |
1111 |
|
"option --uf-ho."); |
1112 |
12916 |
Debug("sets") << "making sets type " << elementType << std::endl; |
1113 |
12916 |
return mkTypeNode(kind::SET_TYPE, elementType); |
1114 |
|
} |
1115 |
|
|
1116 |
432298478 |
inline expr::NodeValue* NodeManager::poolLookup(expr::NodeValue* nv) const { |
1117 |
432298478 |
NodeValuePool::const_iterator find = d_nodeValuePool.find(nv); |
1118 |
432298478 |
if(find == d_nodeValuePool.end()) { |
1119 |
27633253 |
return NULL; |
1120 |
|
} else { |
1121 |
404665225 |
return *find; |
1122 |
|
} |
1123 |
|
} |
1124 |
|
|
1125 |
27640772 |
inline void NodeManager::poolInsert(expr::NodeValue* nv) { |
1126 |
27640772 |
Assert(d_nodeValuePool.find(nv) == d_nodeValuePool.end()) |
1127 |
|
<< "NodeValue already in the pool!"; |
1128 |
27640772 |
d_nodeValuePool.insert(nv);// FIXME multithreading |
1129 |
27640772 |
} |
1130 |
|
|
1131 |
27640772 |
inline void NodeManager::poolRemove(expr::NodeValue* nv) { |
1132 |
27640772 |
Assert(d_nodeValuePool.find(nv) != d_nodeValuePool.end()) |
1133 |
|
<< "NodeValue is not in the pool!"; |
1134 |
|
|
1135 |
27640772 |
d_nodeValuePool.erase(nv);// FIXME multithreading |
1136 |
27640772 |
} |
1137 |
|
|
1138 |
|
} // namespace cvc5 |
1139 |
|
|
1140 |
|
#define CVC5__NODE_MANAGER_NEEDS_CONSTANT_MAP |
1141 |
|
#include "expr/metakind.h" |
1142 |
|
#undef CVC5__NODE_MANAGER_NEEDS_CONSTANT_MAP |
1143 |
|
|
1144 |
|
#include "expr/node_builder.h" |
1145 |
|
|
1146 |
|
namespace cvc5 { |
1147 |
|
|
1148 |
|
// general expression-builders |
1149 |
|
|
1150 |
17002561 |
inline bool NodeManager::hasOperator(Kind k) { |
1151 |
17002561 |
switch(kind::MetaKind mk = kind::metaKindOf(k)) { |
1152 |
|
|
1153 |
1924561 |
case kind::metakind::INVALID: |
1154 |
|
case kind::metakind::VARIABLE: |
1155 |
|
case kind::metakind::NULLARY_OPERATOR: |
1156 |
1924561 |
return false; |
1157 |
|
|
1158 |
13323027 |
case kind::metakind::OPERATOR: |
1159 |
|
case kind::metakind::PARAMETERIZED: |
1160 |
13323027 |
return true; |
1161 |
|
|
1162 |
1754973 |
case kind::metakind::CONSTANT: |
1163 |
1754973 |
return false; |
1164 |
|
|
1165 |
|
default: Unhandled() << mk; |
1166 |
|
} |
1167 |
|
} |
1168 |
|
|
1169 |
576599 |
inline Kind NodeManager::operatorToKind(TNode n) { |
1170 |
576599 |
return kind::operatorToKind(n.d_nv); |
1171 |
|
} |
1172 |
|
|
1173 |
49508086 |
inline Node NodeManager::mkNode(Kind kind, TNode child1) { |
1174 |
99016172 |
NodeBuilder nb(this, kind); |
1175 |
49508086 |
nb << child1; |
1176 |
99016160 |
return nb.constructNode(); |
1177 |
|
} |
1178 |
|
|
1179 |
107028604 |
inline Node NodeManager::mkNode(Kind kind, TNode child1, TNode child2) { |
1180 |
214057208 |
NodeBuilder nb(this, kind); |
1181 |
107028604 |
nb << child1 << child2; |
1182 |
214056834 |
return nb.constructNode(); |
1183 |
|
} |
1184 |
|
|
1185 |
826025 |
inline Node NodeManager::mkNode(Kind kind, TNode child1, TNode child2, |
1186 |
|
TNode child3) { |
1187 |
1652050 |
NodeBuilder nb(this, kind); |
1188 |
826025 |
nb << child1 << child2 << child3; |
1189 |
1652018 |
return nb.constructNode(); |
1190 |
|
} |
1191 |
|
|
1192 |
1186 |
inline Node NodeManager::mkNode(Kind kind, TNode child1, TNode child2, |
1193 |
|
TNode child3, TNode child4) { |
1194 |
2372 |
NodeBuilder nb(this, kind); |
1195 |
1186 |
nb << child1 << child2 << child3 << child4; |
1196 |
2372 |
return nb.constructNode(); |
1197 |
|
} |
1198 |
|
|
1199 |
28 |
inline Node NodeManager::mkNode(Kind kind, TNode child1, TNode child2, |
1200 |
|
TNode child3, TNode child4, TNode child5) { |
1201 |
56 |
NodeBuilder nb(this, kind); |
1202 |
28 |
nb << child1 << child2 << child3 << child4 << child5; |
1203 |
56 |
return nb.constructNode(); |
1204 |
|
} |
1205 |
|
|
1206 |
|
// N-ary version |
1207 |
|
template <bool ref_count> |
1208 |
14733742 |
inline Node NodeManager::mkNode(Kind kind, |
1209 |
|
const std::vector<NodeTemplate<ref_count> >& |
1210 |
|
children) { |
1211 |
29467484 |
NodeBuilder nb(this, kind); |
1212 |
14733742 |
nb.append(children); |
1213 |
29467455 |
return nb.constructNode(); |
1214 |
|
} |
1215 |
|
|
1216 |
|
template <bool ref_count> |
1217 |
649052 |
Node NodeManager::mkAnd(const std::vector<NodeTemplate<ref_count> >& children) |
1218 |
|
{ |
1219 |
649052 |
if (children.empty()) |
1220 |
|
{ |
1221 |
34841 |
return mkConst(true); |
1222 |
|
} |
1223 |
614211 |
else if (children.size() == 1) |
1224 |
|
{ |
1225 |
394805 |
return children[0]; |
1226 |
|
} |
1227 |
219406 |
return mkNode(kind::AND, children); |
1228 |
|
} |
1229 |
|
|
1230 |
|
template <bool ref_count> |
1231 |
|
Node NodeManager::mkOr(const std::vector<NodeTemplate<ref_count> >& children) |
1232 |
|
{ |
1233 |
|
if (children.empty()) |
1234 |
|
{ |
1235 |
|
return mkConst(false); |
1236 |
|
} |
1237 |
|
else if (children.size() == 1) |
1238 |
|
{ |
1239 |
|
return children[0]; |
1240 |
|
} |
1241 |
|
return mkNode(kind::OR, children); |
1242 |
|
} |
1243 |
|
|
1244 |
|
// for operators |
1245 |
|
inline Node NodeManager::mkNode(TNode opNode) { |
1246 |
|
NodeBuilder nb(this, operatorToKind(opNode)); |
1247 |
|
if(opNode.getKind() != kind::BUILTIN) { |
1248 |
|
nb << opNode; |
1249 |
|
} |
1250 |
|
return nb.constructNode(); |
1251 |
|
} |
1252 |
|
|
1253 |
257349 |
inline Node NodeManager::mkNode(TNode opNode, TNode child1) { |
1254 |
514698 |
NodeBuilder nb(this, operatorToKind(opNode)); |
1255 |
257349 |
if(opNode.getKind() != kind::BUILTIN) { |
1256 |
257349 |
nb << opNode; |
1257 |
|
} |
1258 |
257349 |
nb << child1; |
1259 |
514698 |
return nb.constructNode(); |
1260 |
|
} |
1261 |
|
|
1262 |
64 |
inline Node NodeManager::mkNode(TNode opNode, TNode child1, TNode child2) { |
1263 |
128 |
NodeBuilder nb(this, operatorToKind(opNode)); |
1264 |
64 |
if(opNode.getKind() != kind::BUILTIN) { |
1265 |
64 |
nb << opNode; |
1266 |
|
} |
1267 |
64 |
nb << child1 << child2; |
1268 |
128 |
return nb.constructNode(); |
1269 |
|
} |
1270 |
|
|
1271 |
|
inline Node NodeManager::mkNode(TNode opNode, TNode child1, TNode child2, |
1272 |
|
TNode child3) { |
1273 |
|
NodeBuilder nb(this, operatorToKind(opNode)); |
1274 |
|
if(opNode.getKind() != kind::BUILTIN) { |
1275 |
|
nb << opNode; |
1276 |
|
} |
1277 |
|
nb << child1 << child2 << child3; |
1278 |
|
return nb.constructNode(); |
1279 |
|
} |
1280 |
|
|
1281 |
|
inline Node NodeManager::mkNode(TNode opNode, TNode child1, TNode child2, |
1282 |
|
TNode child3, TNode child4) { |
1283 |
|
NodeBuilder nb(this, operatorToKind(opNode)); |
1284 |
|
if(opNode.getKind() != kind::BUILTIN) { |
1285 |
|
nb << opNode; |
1286 |
|
} |
1287 |
|
nb << child1 << child2 << child3 << child4; |
1288 |
|
return nb.constructNode(); |
1289 |
|
} |
1290 |
|
|
1291 |
|
inline Node NodeManager::mkNode(TNode opNode, TNode child1, TNode child2, |
1292 |
|
TNode child3, TNode child4, TNode child5) { |
1293 |
|
NodeBuilder nb(this, operatorToKind(opNode)); |
1294 |
|
if(opNode.getKind() != kind::BUILTIN) { |
1295 |
|
nb << opNode; |
1296 |
|
} |
1297 |
|
nb << child1 << child2 << child3 << child4 << child5; |
1298 |
|
return nb.constructNode(); |
1299 |
|
} |
1300 |
|
|
1301 |
|
// N-ary version for operators |
1302 |
|
template <bool ref_count> |
1303 |
46635 |
inline Node NodeManager::mkNode(TNode opNode, |
1304 |
|
const std::vector<NodeTemplate<ref_count> >& |
1305 |
|
children) { |
1306 |
93270 |
NodeBuilder nb(this, operatorToKind(opNode)); |
1307 |
46635 |
if(opNode.getKind() != kind::BUILTIN) { |
1308 |
866 |
nb << opNode; |
1309 |
|
} |
1310 |
46635 |
nb.append(children); |
1311 |
93270 |
return nb.constructNode(); |
1312 |
|
} |
1313 |
|
|
1314 |
29056 |
inline TypeNode NodeManager::mkTypeNode(Kind kind, TypeNode child1) { |
1315 |
29056 |
return (NodeBuilder(this, kind) << child1).constructTypeNode(); |
1316 |
|
} |
1317 |
|
|
1318 |
43030 |
inline TypeNode NodeManager::mkTypeNode(Kind kind, TypeNode child1, |
1319 |
|
TypeNode child2) { |
1320 |
43030 |
return (NodeBuilder(this, kind) << child1 << child2).constructTypeNode(); |
1321 |
|
} |
1322 |
|
|
1323 |
|
inline TypeNode NodeManager::mkTypeNode(Kind kind, TypeNode child1, |
1324 |
|
TypeNode child2, TypeNode child3) { |
1325 |
|
return (NodeBuilder(this, kind) << child1 << child2 << child3) |
1326 |
|
.constructTypeNode(); |
1327 |
|
} |
1328 |
|
|
1329 |
|
// N-ary version for types |
1330 |
72682 |
inline TypeNode NodeManager::mkTypeNode(Kind kind, |
1331 |
|
const std::vector<TypeNode>& children) { |
1332 |
72682 |
return NodeBuilder(this, kind).append(children).constructTypeNode(); |
1333 |
|
} |
1334 |
|
|
1335 |
|
template <class T> |
1336 |
189573137 |
Node NodeManager::mkConst(const T& val) { |
1337 |
189573137 |
return mkConstInternal<Node, T>(val); |
1338 |
|
} |
1339 |
|
|
1340 |
|
template <class T> |
1341 |
28939327 |
TypeNode NodeManager::mkTypeConst(const T& val) { |
1342 |
28939327 |
return mkConstInternal<TypeNode, T>(val); |
1343 |
|
} |
1344 |
|
|
1345 |
|
template <class NodeClass, class T> |
1346 |
218512464 |
NodeClass NodeManager::mkConstInternal(const T& val) { |
1347 |
|
// This method indirectly calls `NodeValue::inc()`, which relies on having |
1348 |
|
// the correct `NodeManager` in scope. |
1349 |
437024928 |
NodeManagerScope nms(this); |
1350 |
|
|
1351 |
|
// typedef typename kind::metakind::constantMap<T>::OwningTheory theory_t; |
1352 |
218512464 |
NVStorage<1> nvStorage; |
1353 |
218512464 |
expr::NodeValue& nvStack = reinterpret_cast<expr::NodeValue&>(nvStorage); |
1354 |
|
|
1355 |
218512464 |
nvStack.d_id = 0; |
1356 |
218512464 |
nvStack.d_kind = kind::metakind::ConstantMap<T>::kind; |
1357 |
218512464 |
nvStack.d_rc = 0; |
1358 |
218512464 |
nvStack.d_nchildren = 1; |
1359 |
|
|
1360 |
|
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) |
1361 |
|
#pragma GCC diagnostic push |
1362 |
|
#pragma GCC diagnostic ignored "-Warray-bounds" |
1363 |
|
#endif |
1364 |
|
|
1365 |
218512464 |
nvStack.d_children[0] = |
1366 |
|
const_cast<expr::NodeValue*>(reinterpret_cast<const expr::NodeValue*>(&val)); |
1367 |
218512464 |
expr::NodeValue* nv = poolLookup(&nvStack); |
1368 |
|
|
1369 |
|
#if defined(__GNUC__) && (__GNUC__ > 4 || (__GNUC__ == 4 && __GNUC_MINOR__ >= 6)) |
1370 |
|
#pragma GCC diagnostic pop |
1371 |
|
#endif |
1372 |
|
|
1373 |
218512464 |
if(nv != NULL) { |
1374 |
215967533 |
return NodeClass(nv); |
1375 |
|
} |
1376 |
|
|
1377 |
2544931 |
nv = (expr::NodeValue*) |
1378 |
2544931 |
std::malloc(sizeof(expr::NodeValue) + sizeof(T)); |
1379 |
2544931 |
if(nv == NULL) { |
1380 |
|
throw std::bad_alloc(); |
1381 |
|
} |
1382 |
|
|
1383 |
2544931 |
nv->d_nchildren = 0; |
1384 |
2544931 |
nv->d_kind = kind::metakind::ConstantMap<T>::kind; |
1385 |
2544931 |
nv->d_id = next_id++;// FIXME multithreading |
1386 |
2544931 |
nv->d_rc = 0; |
1387 |
|
|
1388 |
|
//OwningTheory::mkConst(val); |
1389 |
2544931 |
new (&nv->d_children) T(val); |
1390 |
|
|
1391 |
2544931 |
poolInsert(nv); |
1392 |
2544931 |
if(Debug.isOn("gc")) { |
1393 |
|
Debug("gc") << "creating node value " << nv |
1394 |
|
<< " [" << nv->d_id << "]: "; |
1395 |
|
nv->printAst(Debug("gc")); |
1396 |
|
Debug("gc") << std::endl; |
1397 |
|
} |
1398 |
|
|
1399 |
2544931 |
return NodeClass(nv); |
1400 |
|
} |
1401 |
|
|
1402 |
|
} // namespace cvc5 |
1403 |
|
|
1404 |
|
#endif /* CVC5__NODE_MANAGER_H */ |