1 |
|
/****************************************************************************** |
2 |
|
* Top contributors (to current version): |
3 |
|
* Andrew Reynolds, Morgan Deters, 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 collection of state for use by parser implementations. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "cvc5parser_public.h" |
17 |
|
|
18 |
|
#ifndef CVC5__PARSER__PARSER_H |
19 |
|
#define CVC5__PARSER__PARSER_H |
20 |
|
|
21 |
|
#include <list> |
22 |
|
#include <memory> |
23 |
|
#include <set> |
24 |
|
#include <string> |
25 |
|
|
26 |
|
#include "api/cpp/cvc5.h" |
27 |
|
#include "cvc5_export.h" |
28 |
|
#include "expr/kind.h" |
29 |
|
#include "expr/symbol_manager.h" |
30 |
|
#include "expr/symbol_table.h" |
31 |
|
#include "parser/input.h" |
32 |
|
#include "parser/parse_op.h" |
33 |
|
#include "parser/parser_exception.h" |
34 |
|
#include "util/unsafe_interrupt_exception.h" |
35 |
|
|
36 |
|
namespace cvc5 { |
37 |
|
|
38 |
|
// Forward declarations |
39 |
|
class Command; |
40 |
|
class ResourceManager; |
41 |
|
|
42 |
|
namespace parser { |
43 |
|
|
44 |
|
class Input; |
45 |
|
|
46 |
|
/** Types of checks for the symbols */ |
47 |
|
enum DeclarationCheck { |
48 |
|
/** Enforce that the symbol has been declared */ |
49 |
|
CHECK_DECLARED, |
50 |
|
/** Enforce that the symbol has not been declared */ |
51 |
|
CHECK_UNDECLARED, |
52 |
|
/** Don't check anything */ |
53 |
|
CHECK_NONE |
54 |
|
};/* enum DeclarationCheck */ |
55 |
|
|
56 |
|
/** |
57 |
|
* Returns a string representation of the given object (for |
58 |
|
* debugging). |
59 |
|
*/ |
60 |
|
inline std::ostream& operator<<(std::ostream& out, DeclarationCheck check); |
61 |
|
inline std::ostream& operator<<(std::ostream& out, DeclarationCheck check) { |
62 |
|
switch(check) { |
63 |
|
case CHECK_NONE: |
64 |
|
return out << "CHECK_NONE"; |
65 |
|
case CHECK_DECLARED: |
66 |
|
return out << "CHECK_DECLARED"; |
67 |
|
case CHECK_UNDECLARED: |
68 |
|
return out << "CHECK_UNDECLARED"; |
69 |
|
default: |
70 |
|
return out << "DeclarationCheck!UNKNOWN"; |
71 |
|
} |
72 |
|
} |
73 |
|
|
74 |
|
/** |
75 |
|
* Types of symbols. Used to define namespaces. |
76 |
|
*/ |
77 |
|
enum SymbolType { |
78 |
|
/** Variables */ |
79 |
|
SYM_VARIABLE, |
80 |
|
/** Sorts */ |
81 |
|
SYM_SORT |
82 |
|
};/* enum SymbolType */ |
83 |
|
|
84 |
|
/** |
85 |
|
* Returns a string representation of the given object (for |
86 |
|
* debugging). |
87 |
|
*/ |
88 |
|
inline std::ostream& operator<<(std::ostream& out, SymbolType type); |
89 |
|
inline std::ostream& operator<<(std::ostream& out, SymbolType type) { |
90 |
|
switch(type) { |
91 |
|
case SYM_VARIABLE: |
92 |
|
return out << "SYM_VARIABLE"; |
93 |
|
case SYM_SORT: |
94 |
|
return out << "SYM_SORT"; |
95 |
|
default: |
96 |
|
return out << "SymbolType!UNKNOWN"; |
97 |
|
} |
98 |
|
} |
99 |
|
|
100 |
|
/** |
101 |
|
* This class encapsulates all of the state of a parser, including the |
102 |
|
* name of the file, line number and column information, and in-scope |
103 |
|
* declarations. |
104 |
|
*/ |
105 |
|
class CVC5_EXPORT Parser |
106 |
|
{ |
107 |
|
friend class ParserBuilder; |
108 |
|
private: |
109 |
|
|
110 |
|
/** The input that we're parsing. */ |
111 |
|
std::unique_ptr<Input> d_input; |
112 |
|
|
113 |
|
/** |
114 |
|
* Reference to the symbol manager, which manages the symbol table used by |
115 |
|
* this parser. |
116 |
|
*/ |
117 |
|
SymbolManager* d_symman; |
118 |
|
|
119 |
|
/** |
120 |
|
* This current symbol table used by this parser, from symbol manager. |
121 |
|
*/ |
122 |
|
SymbolTable* d_symtab; |
123 |
|
|
124 |
|
/** |
125 |
|
* The level of the assertions in the declaration scope. Things declared |
126 |
|
* after this level are bindings from e.g. a let, a quantifier, or a |
127 |
|
* lambda. |
128 |
|
*/ |
129 |
|
size_t d_assertionLevel; |
130 |
|
|
131 |
|
/** How many anonymous functions we've created. */ |
132 |
|
size_t d_anonymousFunctionCount; |
133 |
|
|
134 |
|
/** Are we done */ |
135 |
|
bool d_done; |
136 |
|
|
137 |
|
/** Are semantic checks enabled during parsing? */ |
138 |
|
bool d_checksEnabled; |
139 |
|
|
140 |
|
/** Are we parsing in strict mode? */ |
141 |
|
bool d_strictMode; |
142 |
|
|
143 |
|
/** Are we only parsing? */ |
144 |
|
bool d_parseOnly; |
145 |
|
|
146 |
|
/** |
147 |
|
* Can we include files? (Set to false for security purposes in |
148 |
|
* e.g. the online version.) |
149 |
|
*/ |
150 |
|
bool d_canIncludeFile; |
151 |
|
|
152 |
|
/** |
153 |
|
* Whether the logic has been forced with --force-logic. |
154 |
|
*/ |
155 |
|
bool d_logicIsForced; |
156 |
|
|
157 |
|
/** |
158 |
|
* The logic, if d_logicIsForced == true. |
159 |
|
*/ |
160 |
|
std::string d_forcedLogic; |
161 |
|
|
162 |
|
/** The set of operators available in the current logic. */ |
163 |
|
std::set<api::Kind> d_logicOperators; |
164 |
|
|
165 |
|
/** The set of attributes already warned about. */ |
166 |
|
std::set<std::string> d_attributesWarnedAbout; |
167 |
|
|
168 |
|
/** |
169 |
|
* The current set of unresolved types. We can get by with this NOT |
170 |
|
* being on the scope, because we can only have one DATATYPE |
171 |
|
* definition going on at one time. This is a bit hackish; we |
172 |
|
* depend on mkMutualDatatypeTypes() to check everything and clear |
173 |
|
* this out. |
174 |
|
*/ |
175 |
|
std::set<api::Sort> d_unresolved; |
176 |
|
|
177 |
|
/** |
178 |
|
* "Preemption commands": extra commands implied by subterms that |
179 |
|
* should be issued before the currently-being-parsed command is |
180 |
|
* issued. Used to support SMT-LIBv2 ":named" attribute on terms. |
181 |
|
* |
182 |
|
* Owns the memory of the Commands in the queue. |
183 |
|
*/ |
184 |
|
std::list<Command*> d_commandQueue; |
185 |
|
|
186 |
|
/** Lookup a symbol in the given namespace (as specified by the type). |
187 |
|
* Only returns a symbol if it is not overloaded, returns null otherwise. |
188 |
|
*/ |
189 |
|
api::Term getSymbol(const std::string& var_name, SymbolType type); |
190 |
|
|
191 |
|
protected: |
192 |
|
/** The API Solver object. */ |
193 |
|
api::Solver* d_solver; |
194 |
|
|
195 |
|
/** |
196 |
|
* Create a parser state. |
197 |
|
* |
198 |
|
* @attention The parser takes "ownership" of the given |
199 |
|
* input and will delete it on destruction. |
200 |
|
* |
201 |
|
* @param solver solver API object |
202 |
|
* @param symm reference to the symbol manager |
203 |
|
* @param input the parser input |
204 |
|
* @param strictMode whether to incorporate strict(er) compliance checks |
205 |
|
* @param parseOnly whether we are parsing only (and therefore certain checks |
206 |
|
* need not be performed, like those about unimplemented features, @see |
207 |
|
* unimplementedFeature()) |
208 |
|
*/ |
209 |
|
Parser(api::Solver* solver, |
210 |
|
SymbolManager* sm, |
211 |
|
bool strictMode = false, |
212 |
|
bool parseOnly = false); |
213 |
|
|
214 |
|
public: |
215 |
|
|
216 |
|
virtual ~Parser(); |
217 |
|
|
218 |
|
/** Get the associated solver. */ |
219 |
|
api::Solver* getSolver() const; |
220 |
|
|
221 |
|
/** Get the associated input. */ |
222 |
96 |
Input* getInput() const { return d_input.get(); } |
223 |
|
|
224 |
|
/** Get unresolved sorts */ |
225 |
|
inline std::set<api::Sort>& getUnresolvedSorts() { return d_unresolved; } |
226 |
|
|
227 |
|
/** Deletes and replaces the current parser input. */ |
228 |
6468 |
void setInput(Input* input) { |
229 |
6468 |
d_input.reset(input); |
230 |
6468 |
d_input->setParser(*this); |
231 |
6468 |
d_done = false; |
232 |
6468 |
} |
233 |
|
|
234 |
|
/** |
235 |
|
* Check if we are done -- either the end of input has been reached, or some |
236 |
|
* error has been encountered. |
237 |
|
* @return true if parser is done |
238 |
|
*/ |
239 |
488 |
inline bool done() const { |
240 |
488 |
return d_done; |
241 |
|
} |
242 |
|
|
243 |
|
/** Sets the done flag */ |
244 |
296351 |
inline void setDone(bool done = true) { |
245 |
296351 |
d_done = done; |
246 |
296351 |
} |
247 |
|
|
248 |
|
/** Enable semantic checks during parsing. */ |
249 |
6440 |
void enableChecks() { d_checksEnabled = true; } |
250 |
|
|
251 |
|
/** Disable semantic checks during parsing. Disabling checks may lead to crashes on bad inputs. */ |
252 |
|
void disableChecks() { d_checksEnabled = false; } |
253 |
|
|
254 |
|
/** Enable strict parsing, according to the language standards. */ |
255 |
|
void enableStrictMode() { d_strictMode = true; } |
256 |
|
|
257 |
|
/** Disable strict parsing. Allows certain syntactic infelicities to |
258 |
|
pass without comment. */ |
259 |
|
void disableStrictMode() { d_strictMode = false; } |
260 |
|
|
261 |
4091208 |
bool strictModeEnabled() { return d_strictMode; } |
262 |
|
|
263 |
6440 |
void allowIncludeFile() { d_canIncludeFile = true; } |
264 |
|
void disallowIncludeFile() { d_canIncludeFile = false; } |
265 |
7 |
bool canIncludeFile() const { return d_canIncludeFile; } |
266 |
|
|
267 |
|
/** Expose the functionality from SMT/SMT2 parsers, while making |
268 |
|
implementation optional by returning false by default. */ |
269 |
|
virtual bool logicIsSet() { return false; } |
270 |
|
|
271 |
|
virtual void forceLogic(const std::string& logic); |
272 |
|
|
273 |
8 |
const std::string& getForcedLogic() const { return d_forcedLogic; } |
274 |
5436 |
bool logicIsForced() const { return d_logicIsForced; } |
275 |
|
|
276 |
|
/** |
277 |
|
* Gets the variable currently bound to name. |
278 |
|
* |
279 |
|
* @param name the name of the variable |
280 |
|
* @return the variable expression |
281 |
|
* Only returns a variable if its name is not overloaded, returns null otherwise. |
282 |
|
*/ |
283 |
|
api::Term getVariable(const std::string& name); |
284 |
|
|
285 |
|
/** |
286 |
|
* Gets the function currently bound to name. |
287 |
|
* |
288 |
|
* @param name the name of the variable |
289 |
|
* @return the variable expression |
290 |
|
* Only returns a function if its name is not overloaded, returns null otherwise. |
291 |
|
*/ |
292 |
|
api::Term getFunction(const std::string& name); |
293 |
|
|
294 |
|
/** |
295 |
|
* Returns the expression that name should be interpreted as, based on the current binding. |
296 |
|
* |
297 |
|
* The symbol name should be declared. |
298 |
|
* This creates the expression that the string "name" should be interpreted as. |
299 |
|
* Typically this corresponds to a variable, but it may also correspond to |
300 |
|
* a nullary constructor or a defined function. |
301 |
|
* Only returns an expression if its name is not overloaded, returns null otherwise. |
302 |
|
*/ |
303 |
|
virtual api::Term getExpressionForName(const std::string& name); |
304 |
|
|
305 |
|
/** |
306 |
|
* Returns the expression that name should be interpreted as, based on the |
307 |
|
* current binding. |
308 |
|
* |
309 |
|
* This is the same as above but where the name has been type cast to t. |
310 |
|
*/ |
311 |
|
virtual api::Term getExpressionForNameAndType(const std::string& name, |
312 |
|
api::Sort t); |
313 |
|
|
314 |
|
/** |
315 |
|
* If this method returns true, then name is updated with the tester name |
316 |
|
* for constructor cons. |
317 |
|
* |
318 |
|
* In detail, notice that (user-defined) datatypes associate a unary predicate |
319 |
|
* for each constructor, called its "tester". This symbol is automatically |
320 |
|
* defined when a datatype is defined. The tester name for a constructor |
321 |
|
* (e.g. "cons") depends on the language: |
322 |
|
* - In smt versions < 2.6, the (non-standard) syntax is "is-cons", |
323 |
|
* - In smt versions >= 2.6, the indexed symbol "(_ is cons)" is used. Thus, |
324 |
|
* no tester symbol is necessary, since "is" is a builtin symbol. We still use |
325 |
|
* the above syntax if strict mode is disabled. |
326 |
|
* - In cvc, the syntax for testers is "is_cons". |
327 |
|
*/ |
328 |
|
virtual bool getTesterName(api::Term cons, std::string& name); |
329 |
|
|
330 |
|
/** |
331 |
|
* Returns the kind that should be used for applications of expression fun. |
332 |
|
* This is a generalization of ExprManager::operatorToKind that also |
333 |
|
* handles variables whose types are "function-like", i.e. where |
334 |
|
* checkFunctionLike(fun) returns true. |
335 |
|
* |
336 |
|
* For examples of the latter, this function returns |
337 |
|
* APPLY_UF if fun has function type, |
338 |
|
* APPLY_CONSTRUCTOR if fun has constructor type. |
339 |
|
*/ |
340 |
|
api::Kind getKindForFunction(api::Term fun); |
341 |
|
|
342 |
|
/** |
343 |
|
* Returns a sort, given a name. |
344 |
|
* @param sort_name the name to look up |
345 |
|
*/ |
346 |
|
api::Sort getSort(const std::string& sort_name); |
347 |
|
|
348 |
|
/** |
349 |
|
* Returns a (parameterized) sort, given a name and args. |
350 |
|
*/ |
351 |
|
api::Sort getSort(const std::string& sort_name, |
352 |
|
const std::vector<api::Sort>& params); |
353 |
|
|
354 |
|
/** |
355 |
|
* Returns arity of a (parameterized) sort, given a name and args. |
356 |
|
*/ |
357 |
|
size_t getArity(const std::string& sort_name); |
358 |
|
|
359 |
|
/** |
360 |
|
* Checks if a symbol has been declared. |
361 |
|
* @param name the symbol name |
362 |
|
* @param type the symbol type |
363 |
|
* @return true iff the symbol has been declared with the given type |
364 |
|
*/ |
365 |
|
bool isDeclared(const std::string& name, SymbolType type = SYM_VARIABLE); |
366 |
|
|
367 |
|
/** |
368 |
|
* Checks if the declaration policy we want to enforce holds |
369 |
|
* for the given symbol. |
370 |
|
* @param name the symbol to check |
371 |
|
* @param check the kind of check to perform |
372 |
|
* @param type the type of the symbol |
373 |
|
* @param notes notes to add to a parse error (if one is generated) |
374 |
|
* @throws ParserException if checks are enabled and the check fails |
375 |
|
*/ |
376 |
|
void checkDeclaration(const std::string& name, |
377 |
|
DeclarationCheck check, |
378 |
|
SymbolType type = SYM_VARIABLE, |
379 |
|
std::string notes = ""); |
380 |
|
|
381 |
|
/** |
382 |
|
* Checks whether the given expression is function-like, i.e. |
383 |
|
* it expects arguments. This is checked by looking at the type |
384 |
|
* of fun. Examples of function types are function, constructor, |
385 |
|
* selector, tester. |
386 |
|
* @param fun the expression to check |
387 |
|
* @throws ParserException if checks are enabled and fun is not |
388 |
|
* a function |
389 |
|
*/ |
390 |
|
void checkFunctionLike(api::Term fun); |
391 |
|
|
392 |
|
/** Create a new cvc5 variable expression of the given type. |
393 |
|
* |
394 |
|
* It is inserted at context level zero in the symbol table if levelZero is |
395 |
|
* true, or if we are using global declarations. |
396 |
|
* |
397 |
|
* If a symbol with name already exists, |
398 |
|
* then if doOverload is true, we create overloaded operators. |
399 |
|
* else if doOverload is false, the existing expression is shadowed by the |
400 |
|
* new expression. |
401 |
|
*/ |
402 |
|
api::Term bindVar(const std::string& name, |
403 |
|
const api::Sort& type, |
404 |
|
bool levelZero = false, |
405 |
|
bool doOverload = false); |
406 |
|
|
407 |
|
/** |
408 |
|
* Create a set of new cvc5 variable expressions of the given type. |
409 |
|
* |
410 |
|
* It is inserted at context level zero in the symbol table if levelZero is |
411 |
|
* true, or if we are using global declarations. |
412 |
|
* |
413 |
|
* For each name, if a symbol with name already exists, |
414 |
|
* then if doOverload is true, we create overloaded operators. |
415 |
|
* else if doOverload is false, the existing expression is shadowed by the |
416 |
|
* new expression. |
417 |
|
*/ |
418 |
|
std::vector<api::Term> bindVars(const std::vector<std::string> names, |
419 |
|
const api::Sort& type, |
420 |
|
bool levelZero = false, |
421 |
|
bool doOverload = false); |
422 |
|
|
423 |
|
/** |
424 |
|
* Create a new cvc5 bound variable expression of the given type. This binds |
425 |
|
* the symbol name to that variable in the current scope. |
426 |
|
*/ |
427 |
|
api::Term bindBoundVar(const std::string& name, const api::Sort& type); |
428 |
|
/** |
429 |
|
* Create a new cvc5 bound variable expressions of the given names and types. |
430 |
|
* Like the method above, this binds these names to those variables in the |
431 |
|
* current scope. |
432 |
|
*/ |
433 |
|
std::vector<api::Term> bindBoundVars( |
434 |
|
std::vector<std::pair<std::string, api::Sort> >& sortedVarNames); |
435 |
|
|
436 |
|
/** |
437 |
|
* Create a set of new cvc5 bound variable expressions of the given type. |
438 |
|
* |
439 |
|
* For each name, if a symbol with name already exists, |
440 |
|
* then if doOverload is true, we create overloaded operators. |
441 |
|
* else if doOverload is false, the existing expression is shadowed by the |
442 |
|
* new expression. |
443 |
|
*/ |
444 |
|
std::vector<api::Term> bindBoundVars(const std::vector<std::string> names, |
445 |
|
const api::Sort& type); |
446 |
|
|
447 |
|
/** Create a new variable definition (e.g., from a let binding). |
448 |
|
* levelZero is set if the binding must be done at level 0. |
449 |
|
* If a symbol with name already exists, |
450 |
|
* then if doOverload is true, we create overloaded operators. |
451 |
|
* else if doOverload is false, the existing expression is shadowed by the |
452 |
|
* new expression. |
453 |
|
*/ |
454 |
|
void defineVar(const std::string& name, |
455 |
|
const api::Term& val, |
456 |
|
bool levelZero = false, |
457 |
|
bool doOverload = false); |
458 |
|
|
459 |
|
/** |
460 |
|
* Create a new type definition. |
461 |
|
* |
462 |
|
* @param name The name of the type |
463 |
|
* @param type The type that should be associated with the name |
464 |
|
* @param levelZero If true, the type definition is considered global and |
465 |
|
* cannot be removed by popping the user context |
466 |
|
* @param skipExisting If true, the type definition is ignored if the same |
467 |
|
* symbol has already been defined. It is assumed that |
468 |
|
* the definition is the exact same as the existing one. |
469 |
|
*/ |
470 |
|
void defineType(const std::string& name, |
471 |
|
const api::Sort& type, |
472 |
|
bool levelZero = false, |
473 |
|
bool skipExisting = false); |
474 |
|
|
475 |
|
/** |
476 |
|
* Create a new (parameterized) type definition. |
477 |
|
* |
478 |
|
* @param name The name of the type |
479 |
|
* @param params The type parameters |
480 |
|
* @param type The type that should be associated with the name |
481 |
|
* @param levelZero If true, the type definition is considered global and |
482 |
|
* cannot be removed by poppoing the user context |
483 |
|
*/ |
484 |
|
void defineType(const std::string& name, |
485 |
|
const std::vector<api::Sort>& params, |
486 |
|
const api::Sort& type, |
487 |
|
bool levelZero = false); |
488 |
|
|
489 |
|
/** Create a new type definition (e.g., from an SMT-LIBv2 define-sort). */ |
490 |
|
void defineParameterizedType(const std::string& name, |
491 |
|
const std::vector<api::Sort>& params, |
492 |
|
const api::Sort& type); |
493 |
|
|
494 |
|
/** |
495 |
|
* Creates a new sort with the given name. |
496 |
|
*/ |
497 |
|
api::Sort mkSort(const std::string& name); |
498 |
|
|
499 |
|
/** |
500 |
|
* Creates a new sort constructor with the given name and arity. |
501 |
|
*/ |
502 |
|
api::Sort mkSortConstructor(const std::string& name, size_t arity); |
503 |
|
|
504 |
|
/** |
505 |
|
* Creates a new "unresolved type," used only during parsing. |
506 |
|
*/ |
507 |
|
api::Sort mkUnresolvedType(const std::string& name); |
508 |
|
|
509 |
|
/** |
510 |
|
* Creates a new unresolved (parameterized) type constructor of the given |
511 |
|
* arity. |
512 |
|
*/ |
513 |
|
api::Sort mkUnresolvedTypeConstructor(const std::string& name, size_t arity); |
514 |
|
/** |
515 |
|
* Creates a new unresolved (parameterized) type constructor given the type |
516 |
|
* parameters. |
517 |
|
*/ |
518 |
|
api::Sort mkUnresolvedTypeConstructor(const std::string& name, |
519 |
|
const std::vector<api::Sort>& params); |
520 |
|
|
521 |
|
/** |
522 |
|
* Creates a new unresolved (parameterized) type constructor of the given |
523 |
|
* arity. Calls either mkUnresolvedType or mkUnresolvedTypeConstructor |
524 |
|
* depending on the arity. |
525 |
|
*/ |
526 |
|
api::Sort mkUnresolvedType(const std::string& name, size_t arity); |
527 |
|
|
528 |
|
/** |
529 |
|
* Returns true IFF name is an unresolved type. |
530 |
|
*/ |
531 |
|
bool isUnresolvedType(const std::string& name); |
532 |
|
|
533 |
|
/** |
534 |
|
* Creates and binds sorts of a list of mutually-recursive datatype |
535 |
|
* declarations. |
536 |
|
* |
537 |
|
* For each symbol defined by the datatype, if a symbol with name already |
538 |
|
* exists, then if doOverload is true, we create overloaded operators. Else, if |
539 |
|
* doOverload is false, the existing expression is shadowed by the new |
540 |
|
* expression. |
541 |
|
*/ |
542 |
|
std::vector<api::Sort> bindMutualDatatypeTypes( |
543 |
|
std::vector<api::DatatypeDecl>& datatypes, bool doOverload = false); |
544 |
|
|
545 |
|
/** make flat function type |
546 |
|
* |
547 |
|
* Returns the "flat" function type corresponding to the function taking |
548 |
|
* argument types "sorts" and range type "range". A flat function type is |
549 |
|
* one whose range is not a function. Notice that if sorts is empty and range |
550 |
|
* is not a function, then this function returns range itself. |
551 |
|
* |
552 |
|
* If range is a function type, we add its function argument sorts to sorts |
553 |
|
* and consider its function range as the new range. For each sort S added |
554 |
|
* to sorts in this process, we add a new bound variable of sort S to |
555 |
|
* flattenVars. |
556 |
|
* |
557 |
|
* For example: |
558 |
|
* mkFlattenFunctionType( { Int, (-> Real Real) }, (-> Int Bool), {} ): |
559 |
|
* - returns the the function type (-> Int (-> Real Real) Int Bool) |
560 |
|
* - updates sorts to { Int, (-> Real Real), Int }, |
561 |
|
* - updates flattenVars to { x }, where x is bound variable of type Int. |
562 |
|
* |
563 |
|
* Notice that this method performs only one level of flattening, for example, |
564 |
|
* mkFlattenFunctionType({ Int, (-> Real Real) }, (-> Int (-> Int Bool)), {}): |
565 |
|
* - returns the the function type (-> Int (-> Real Real) Int (-> Int Bool)) |
566 |
|
* - updates sorts to { Int, (-> Real Real), Int }, |
567 |
|
* - updates flattenVars to { x }, where x is bound variable of type Int. |
568 |
|
* |
569 |
|
* This method is required so that we do not return functions |
570 |
|
* that have function return type (these give an unhandled exception |
571 |
|
* in the ExprManager). For examples of the equivalence between function |
572 |
|
* definitions in the proposed higher-order extension of the smt2 language, |
573 |
|
* see page 3 of http://matryoshka.gforge.inria.fr/pubs/PxTP2017.pdf. |
574 |
|
* |
575 |
|
* The argument flattenVars is needed in the case of defined functions |
576 |
|
* with function return type. These have implicit arguments, for instance: |
577 |
|
* (define-fun Q ((x Int)) (-> Int Int) (lambda y (P x))) |
578 |
|
* is equivalent to the command: |
579 |
|
* (define-fun Q ((x Int) (z Int)) Int (@ (lambda y (P x)) z)) |
580 |
|
* where @ is (higher-order) application. In this example, z is added to |
581 |
|
* flattenVars. |
582 |
|
*/ |
583 |
|
api::Sort mkFlatFunctionType(std::vector<api::Sort>& sorts, |
584 |
|
api::Sort range, |
585 |
|
std::vector<api::Term>& flattenVars); |
586 |
|
|
587 |
|
/** make flat function type |
588 |
|
* |
589 |
|
* Same as above, but does not take argument flattenVars. |
590 |
|
* This is used when the arguments of the function are not important (for |
591 |
|
* instance, if we are only using this type in a declare-fun). |
592 |
|
*/ |
593 |
|
api::Sort mkFlatFunctionType(std::vector<api::Sort>& sorts, api::Sort range); |
594 |
|
|
595 |
|
/** make higher-order apply |
596 |
|
* |
597 |
|
* This returns the left-associative curried application of (function) expr to |
598 |
|
* the arguments in args. |
599 |
|
* |
600 |
|
* For example, mkHoApply( f, { a, b }, 0 ) returns |
601 |
|
* (HO_APPLY (HO_APPLY f a) b) |
602 |
|
* |
603 |
|
* If args is non-empty, the expected type of expr is (-> T0 ... Tn T), where |
604 |
|
* args[i].getType() = Ti |
605 |
|
* for each i where 0 <= i < args.size(). If expr is not of this |
606 |
|
* type, the expression returned by this method will not be well typed. |
607 |
|
*/ |
608 |
|
api::Term mkHoApply(api::Term expr, const std::vector<api::Term>& args); |
609 |
|
|
610 |
|
/** Apply type ascription |
611 |
|
* |
612 |
|
* Return term t with a type ascription applied to it. This is used for |
613 |
|
* syntax like (as t T) in smt2 and t::T in the CVC language. This includes: |
614 |
|
* - (as emptyset (Set T)) |
615 |
|
* - (as emptybag (Bag T)) |
616 |
|
* - (as univset (Set T)) |
617 |
|
* - (as sep.nil T) |
618 |
|
* - (cons T) |
619 |
|
* - ((as cons T) t1 ... tn) where cons is a parametric datatype constructor. |
620 |
|
* |
621 |
|
* The term to ascribe t is a term whose kind and children (but not type) |
622 |
|
* are equivalent to that of the term returned by this method. |
623 |
|
* |
624 |
|
* Notice that method is not necessarily a cast. In actuality, the above terms |
625 |
|
* should be understood as symbols indexed by types. However, SMT-LIB does not |
626 |
|
* permit types as indices, so we must use, e.g. (as emptyset (Set T)) |
627 |
|
* instead of (_ emptyset (Set T)). |
628 |
|
* |
629 |
|
* @param t The term to ascribe a type |
630 |
|
* @param s The sort to ascribe |
631 |
|
* @return Term t with sort s ascribed. |
632 |
|
*/ |
633 |
|
api::Term applyTypeAscription(api::Term t, api::Sort s); |
634 |
|
|
635 |
|
/** |
636 |
|
* Add an operator to the current legal set. |
637 |
|
* |
638 |
|
* @param kind the built-in operator to add |
639 |
|
*/ |
640 |
|
void addOperator(api::Kind kind); |
641 |
|
|
642 |
|
/** |
643 |
|
* Preempt the next returned command with other ones; used to |
644 |
|
* support the :named attribute in SMT-LIBv2, which implicitly |
645 |
|
* inserts a new command before the current one. Also used in TPTP |
646 |
|
* because function and predicate symbols are implicitly declared. |
647 |
|
*/ |
648 |
|
void preemptCommand(Command* cmd); |
649 |
|
|
650 |
|
/** Is the symbol bound to a boolean variable? */ |
651 |
|
bool isBoolean(const std::string& name); |
652 |
|
|
653 |
|
/** Is fun a function (or function-like thing)? |
654 |
|
* Currently this means its type is either a function, constructor, tester, or |
655 |
|
* selector. |
656 |
|
*/ |
657 |
|
bool isFunctionLike(api::Term fun); |
658 |
|
|
659 |
|
/** Is the symbol bound to a predicate? */ |
660 |
|
bool isPredicate(const std::string& name); |
661 |
|
|
662 |
|
/** Parse and return the next command. */ |
663 |
|
Command* nextCommand(); |
664 |
|
|
665 |
|
/** Parse and return the next expression. */ |
666 |
|
api::Term nextExpression(); |
667 |
|
|
668 |
|
/** Issue a warning to the user. */ |
669 |
273 |
void warning(const std::string& msg) { d_input->warning(msg); } |
670 |
|
/** Issue a warning to the user, but only once per attribute. */ |
671 |
|
void attributeNotSupported(const std::string& attr); |
672 |
|
|
673 |
|
/** Raise a parse error with the given message. */ |
674 |
73 |
inline void parseError(const std::string& msg) { d_input->parseError(msg); } |
675 |
|
/** Unexpectedly encountered an EOF */ |
676 |
|
inline void unexpectedEOF(const std::string& msg) |
677 |
|
{ |
678 |
|
d_input->parseError(msg, true); |
679 |
|
} |
680 |
|
|
681 |
|
/** |
682 |
|
* If we are parsing only, don't raise an exception; if we are not, |
683 |
|
* raise a parse error with the given message. There is no actual |
684 |
|
* parse error, everything is as expected, but we cannot create the |
685 |
|
* Expr, Type, or other requested thing yet due to internal |
686 |
|
* limitations. Even though it's not a parse error, we throw a |
687 |
|
* parse error so that the input line and column information is |
688 |
|
* available. |
689 |
|
* |
690 |
|
* Think quantifiers. We don't have a TheoryQuantifiers yet, so we |
691 |
|
* have no kind::FORALL or kind::EXISTS. But we might want to |
692 |
|
* support parsing quantifiers (just not doing anything with them). |
693 |
|
* So this mechanism gives you a way to do it with --parse-only. |
694 |
|
*/ |
695 |
|
inline void unimplementedFeature(const std::string& msg) |
696 |
|
{ |
697 |
|
if(!d_parseOnly) { |
698 |
|
parseError("Unimplemented feature: " + msg); |
699 |
|
} |
700 |
|
} |
701 |
|
|
702 |
|
/** |
703 |
|
* Gets the current declaration level. |
704 |
|
*/ |
705 |
|
size_t scopeLevel() const; |
706 |
|
|
707 |
|
/** |
708 |
|
* Pushes a scope. All subsequent symbol declarations made are only valid in |
709 |
|
* this scope, i.e. they are deleted on the next call to popScope. |
710 |
|
* |
711 |
|
* The argument isUserContext is true, when we are pushing a user context |
712 |
|
* e.g. via the smt2 command (push n). This may also include one initial |
713 |
|
* pushScope when the parser is initialized. User-context pushes and pops |
714 |
|
* have an impact on both expression names and the symbol table, whereas |
715 |
|
* other pushes and pops only have an impact on the symbol table. |
716 |
|
*/ |
717 |
|
void pushScope(bool isUserContext = false); |
718 |
|
|
719 |
|
void popScope(); |
720 |
|
|
721 |
|
virtual void reset(); |
722 |
|
|
723 |
|
/** Return the symbol manager used by this parser. */ |
724 |
|
SymbolManager* getSymbolManager(); |
725 |
|
|
726 |
|
//------------------------ operator overloading |
727 |
|
/** is this function overloaded? */ |
728 |
|
bool isOverloadedFunction(api::Term fun) |
729 |
|
{ |
730 |
|
return d_symtab->isOverloadedFunction(fun); |
731 |
|
} |
732 |
|
|
733 |
|
/** Get overloaded constant for type. |
734 |
|
* If possible, it returns a defined symbol with name |
735 |
|
* that has type t. Otherwise returns null expression. |
736 |
|
*/ |
737 |
6 |
api::Term getOverloadedConstantForType(const std::string& name, api::Sort t) |
738 |
|
{ |
739 |
6 |
return d_symtab->getOverloadedConstantForType(name, t); |
740 |
|
} |
741 |
|
|
742 |
|
/** |
743 |
|
* If possible, returns a defined function for a name |
744 |
|
* and a vector of expected argument types. Otherwise returns |
745 |
|
* null expression. |
746 |
|
*/ |
747 |
122 |
api::Term getOverloadedFunctionForTypes(const std::string& name, |
748 |
|
std::vector<api::Sort>& argTypes) |
749 |
|
{ |
750 |
122 |
return d_symtab->getOverloadedFunctionForTypes(name, argTypes); |
751 |
|
} |
752 |
|
//------------------------ end operator overloading |
753 |
|
/** |
754 |
|
* Make string constant |
755 |
|
* |
756 |
|
* This makes the string constant based on the string s. This may involve |
757 |
|
* processing ad-hoc escape sequences (if the language is not |
758 |
|
* SMT-LIB 2.6 or higher), or otherwise calling the solver to construct |
759 |
|
* the string. |
760 |
|
*/ |
761 |
|
api::Term mkStringConstant(const std::string& s); |
762 |
|
|
763 |
|
/** |
764 |
|
* Make string constant from a single character in hex representation |
765 |
|
* |
766 |
|
* This makes the string constant based on the character from the strings, |
767 |
|
* represented as a hexadecimal code point. |
768 |
|
*/ |
769 |
|
api::Term mkCharConstant(const std::string& s); |
770 |
|
|
771 |
|
/** ad-hoc string escaping |
772 |
|
* |
773 |
|
* Returns the (internal) vector of code points corresponding to processing |
774 |
|
* the escape sequences in string s. This is to support string inputs that |
775 |
|
* do no comply with the SMT-LIB standard. |
776 |
|
* |
777 |
|
* This method handles escape sequences, including \n, \t, \v, \b, \r, \f, \a, |
778 |
|
* \\, \x[N] and octal escape sequences of the form \[c1]([c2]([c3])?)? where |
779 |
|
* c1, c2, c3 are digits from 0 to 7. |
780 |
|
*/ |
781 |
|
std::wstring processAdHocStringEsc(const std::string& s); |
782 |
|
}; /* class Parser */ |
783 |
|
|
784 |
|
} // namespace parser |
785 |
|
} // namespace cvc5 |
786 |
|
|
787 |
|
#endif /* CVC5__PARSER__PARSER_STATE_H */ |