1 
2 /*
3  * File SMTLIB2.hpp.
4  *
5  * This file is part of the source code of the software program
6  * Vampire. It is protected by applicable
7  * copyright laws.
8  *
9  * This source code is distributed under the licence found here
10  * https://vprover.github.io/license.html
11  * and in the source directory
12  *
13  * In summary, you are allowed to use Vampire for non-commercial
14  * purposes but not allowed to distribute, modify, copy, create derivatives,
15  * or use in competitions.
16  * For other uses of Vampire please contact developers for a different
17  * licence, which we will make an effort to provide.
18  */
19 /**
20  * @file SMTLIB.hpp
21  * Defines class SMTLIB.
22  */
23 
24 #ifndef __SMTLIB2__
25 #define __SMTLIB2__
26 
27 #include "Forwards.hpp"
28 
29 #include "Lib/Set.hpp"
30 
31 #include "Kernel/Signature.hpp"
32 #include "Kernel/Sorts.hpp"
33 #include "Kernel/Term.hpp"
34 
35 #include "Shell/LispParser.hpp"
36 
37 
38 namespace Parse {
39 
40 using namespace Lib;
41 using namespace Kernel;
42 using namespace Shell;
43 
44 
45 class SMTLIB2 {
46 public:
47   SMTLIB2(const Options& opts);
48 
49   /** Parse from an open stream */
50   void parse(istream& str);
51   /** Parse a ready lisp expression */
52   void parse(LExpr* bench);
53 
54   /** Formulas obtained during parsing:
55    *  1) equations collected from "define-fun"
56    *  2) general formulas collected from "assert"
57    *
58    *  Global signature in env is updated on the fly.
59    *
60    *  We don't know what the conjecture is.
61    **/
getFormulas() const62   UnitList* getFormulas() const { return _formulas; }
63 
64   /**
65    * Return the parsed logic (or LO_INVALID if not set).
66    */
getLogic() const67   SMTLIBLogic getLogic() const {
68     return _logic;
69   }
70 
getStatus() const71   const vstring& getStatus() const {
72     return _statusStr;
73   }
74 
75 private:
76 
77   static const char * s_smtlibLogicNameStrings[];
78 
79   /**
80    * Maps a string to a SmtlibLogic value.
81    */
82   static SMTLIBLogic getLogicFromString(const vstring& str);
83 
84   /**
85    * Have we seen "set-logic" entry yet?
86    */
87   bool _logicSet;
88 
89   /**
90    * The advertised logic.
91    */
92   SMTLIBLogic _logic;
93 
94   /**
95    * Logics which contains only reals allow numerals (like '123') to be understood as reals.
96    * When both Ints and Reals are mixed numerals are Ints and decimals (like '123.0') are reals.
97    *
98    * This is determined based on the advertised logic (and not the actual content of the file).
99    */
100   bool _numeralsAreReal;
101 
102   /**
103    * Handle "set-logic" entry.
104    */
105   void readLogic(const vstring& logicStr);
106 
107   /** Content of the ":status: info entry. */
108   vstring _statusStr;
109   /** Content of the ":source: info entry. */
110   vstring _sourceInfo;
111 
112   enum BuiltInSorts
113   {
114     BS_ARRAY,
115     BS_BOOL,
116     BS_INT,
117     BS_REAL,
118 
119     BS_INVALID
120   };
121   static const char * s_builtInSortNameStrings[];
122 
123   /**
124    * Maps smtlib built-in sort name to BuiltInSorts value.
125    */
126   static BuiltInSorts getBuiltInSortFromString(const vstring& str);
127 
128   /**
129    * Test string for being either a built-in sort
130    * or a sort already declared or defined within this parser object.
131    */
132   bool isAlreadyKnownSortSymbol(const vstring& name);
133 
134   /** Maps smtlib name of a declared sort to its arity.
135    *
136    * Declared sorts are just names with arity-many "argument slots".
137    * However, this is just a way to make new sorts from old ones.
138    * There is no implied semantic relation to the argument sorts.
139    */
140   DHMap<vstring,unsigned> _declaredSorts;
141 
142   /**
143    * Handle "declare-sort" entry.
144    */
145   void readDeclareSort(const vstring& name, const vstring& arity);
146 
147   /**
148    * Sort definition is a macro (with arguments) for a complex sort expression.
149    *
150    * We don't parse the definition until it is used.
151    *
152    * Then a lookup context is created mapping
153    * symbolic arguments from the definition to actual arguments from the invocation
154    * and the invocation is parsed as the defined body in this context.
155    */
156   struct SortDefinition {
SortDefinitionParse::SMTLIB2::SortDefinition157     SortDefinition() : args(0), body(0) {}
SortDefinitionParse::SMTLIB2::SortDefinition158     SortDefinition(LExprList* args, LExpr* body)
159      : args(args), body(body) {}
160 
161     LExprList* args;
162     LExpr* body;
163   };
164 
165   /**
166    * Maps smtlib name of a defined sort to its SortDefinition struct.
167    */
168   DHMap<vstring,SortDefinition> _sortDefinitions;
169 
170   /**
171    * Handle "define-sort" entry.
172    */
173   void readDefineSort(const vstring& name, LExprList* args, LExpr* body);
174 
175   /**
176    * Take an smtlib sort expression, evaluate it in the context of previous
177    * sort declarations and definitions,
178    * register any missing sort in vampire and return vampire's sort id
179    * corresponding to the give expression.
180    */
181   unsigned declareSort(LExpr* sExpr);
182 
183   /**
184    * Some built-in symbols represent functions with result of sort Bool.
185    * They are listed here.
186    */
187   enum FormulaSymbol
188   {
189     FS_LESS,
190     FS_LESS_EQ,
191     FS_EQ,
192     FS_IMPLIES,
193     FS_GREATER,
194     FS_GREATER_EQ,
195     FS_AND,
196     FS_DISTINCT,
197     FS_EXISTS,
198     FS_FALSE,
199     FS_FORALL,
200     FS_IS_INT,
201     FS_NOT,
202     FS_OR,
203     FS_TRUE,
204     FS_XOR,
205 
206     FS_USER_PRED_SYMBOL
207   };
208   static const char * s_formulaSymbolNameStrings[];
209 
210   /**
211    * Lookup to see if vstring is a built-in FormulaSymbol.
212    */
213   static FormulaSymbol getBuiltInFormulaSymbol(const vstring& str);
214 
215   /**
216    * Some built-in symbols represent functions with not-Bool result of sort
217    * and are listed here.
218    */
219   enum TermSymbol
220   {
221     TS_MULTIPLY,
222     TS_PLUS,
223     TS_MINUS,
224     TS_DIVIDE,
225     TS_ABS,
226     TS_DIV,
227     TS_ITE,
228     TS_LET,
229     TS_MOD,
230     TS_SELECT,
231     TS_STORE,
232     TS_TO_INT,
233     TS_TO_REAL,
234 
235     TS_USER_FUNCTION
236   };
237   static const char * s_termSymbolNameStrings[];
238 
239   /**
240    * Lookup to see if vstring is a built-in TermSymbol.
241    */
242   static TermSymbol getBuiltInTermSymbol(const vstring& str);
243 
244   /**
245    * Is the given vstring a built-in FormulaSymbol, built-in TermSymbol or a declared function?
246    */
247   bool isAlreadyKnownFunctionSymbol(const vstring& name);
248 
249   /** <vampire signature id, is_function flag (otherwise it is a predicate) > */
250   typedef std::pair<unsigned,bool> DeclaredFunction;
251   /** functions are implicitly declared also when they are defined (see below) */
252   DHMap<vstring, DeclaredFunction> _declaredFunctions;
253 
254   /**
255    * Given a symbol name, range sort (which can be Bool) and argSorts,
256    * register a new function (or predicate) symbol in vampire,
257    * store the ensuing DeclaredFunction in _declaredFunctions
258    * and return it.
259    */
260   DeclaredFunction declareFunctionOrPredicate(const vstring& name, signed rangeSort, const Stack<unsigned>& argSorts);
261 
262   /**
263    * Handle "declare-fun" entry.
264    *
265    * Declaring a function just extends the signature.
266    */
267   void readDeclareFun(const vstring& name, LExprList* iSorts, LExpr* oSort);
268 
269   /**
270    * Handle "define-fun" entry.
271    *
272    * Defining a function extends the signature and adds the new function's definition into _formulas.
273    */
274   void readDefineFun(const vstring& name, LExprList* iArgs, LExpr* oSort, LExpr* body);
275 
276   void readDeclareDatatypes(LExprList* sorts, LExprList* datatypes, bool codatatype = false);
277 
278   TermAlgebraConstructor* buildTermAlgebraConstructor(vstring constrName, unsigned taSort,
279                                                       Stack<vstring> destructorNames, Stack<unsigned> argSorts);
280 
281   /**
282    * Parse result of parsing an smtlib term (which can be of sort Bool and therefore represented in vampire by a formula)
283    */
284   struct ParseResult {
285     /** Construct special separator value */
ParseResultParse::SMTLIB2::ParseResult286     ParseResult() : sort(0), formula(true), frm(nullptr) {}
287 
isSeparatorParse::SMTLIB2::ParseResult288     bool isSeparator() { return sort == 0 && formula && !frm; }
289 
isSharedTermParse::SMTLIB2::ParseResult290     bool isSharedTerm() { return !formula && (!trm.isTerm() || trm.term()->shared()); }
291 
292     /** Construct ParseResult from a formula */
ParseResultParse::SMTLIB2::ParseResult293     ParseResult(Formula* frm) : sort(Sorts::SRT_BOOL), formula(true), frm(frm) {}
294     /** Construct ParseResult from a term of a given sort */
ParseResultParse::SMTLIB2::ParseResult295     ParseResult(unsigned sort, TermList trm) : sort(sort), formula(false), trm(trm) {}
296 
297     unsigned sort;
298     bool formula;
299     union {
300       Formula* frm;
301       TermList trm;
302     };
303 
304     /**
305      * Try interpreting ParseResult as a formula
306      * (which may involve unwrapping a formula special term
307      * or wrapping a Bool sorted term as BoolTermFormula)
308      * and indicate success by returning true.
309      */
310     bool asFormula(Formula*& resFrm);
311     /**
312      * Interpret ParseResult as term
313      * and return its vampire sort (which may be Sorts::SRT_BOOL).
314      */
315     unsigned asTerm(TermList& resTrm);
316 
317     vstring toString();
318   };
319 
320   /** Return Theory::Interpretation for overloaded arithmetic comparison operators based on their argSort (either Int or Real) */
321   Interpretation getFormulaSymbolInterpretation(FormulaSymbol fs, unsigned firstArgSort);
322   /** Return Theory::Interpretation for overloaded unary minus operator based on its argSort (either Int or Real) */
323   Interpretation getUnaryMinusInterpretation(unsigned argSort);
324   /** Return Theory::Interpretation for overloaded arithmetic operators based on its argSort (either Int or Real) */
325   Interpretation getTermSymbolInterpretation(TermSymbol ts, unsigned firstArgSort);
326 
327 
328   // global parsing data structures -- BEGIN
329 
330   /** For generating fresh vampire variables */
331   unsigned _nextVar;
332 
333   /** < termlist, vampire sort id > */
334   typedef pair<TermList,unsigned> SortedTerm;
335   /** mast an identifier to SortedTerm */
336   typedef DHMap<vstring,SortedTerm> TermLookup;
337   typedef Stack<TermLookup*> Scopes;
338   /** Stack of parsing contexts:
339    * for variables from quantifiers and
340    * for symbols bound by let (which are variables from smtlib perspective,
341    * but require a true function/predicate symbol by vampire )
342    */
343   Scopes _scopes;
344 
345   /**
346    * Stack of partial results used by parseTermOrFormula below.
347    */
348   Stack<ParseResult> _results;
349 
350   /**
351    * Possible operations during parsing a term.
352    */
353   enum ParseOperation {
354     // general top level parsing request
355     PO_PARSE,              // takes LExpr*
356     // when parsing "(something args...)" the following operation will be scheduled for "something"
357     PO_PARSE_APPLICATION,  // takes LExpr* (the whole term again, for better error reporting)
358     // after "(something args...)" is parsed the following makes sure that there is exactly one proper result on the result stack above a previously inserted separator
359     PO_CHECK_ARITY,        // takes LExpr* (again the whole, just for error reporting)
360     // these two are intermediate cases for handling let
361     PO_LET_PREPARE_LOOKUP, // takes LExpr* (the whole let expression again, why not)
362     PO_LET_END             // takes LExpr* (the whole let expression again, why not)
363   };
364   /**
365    * Main smtlib term parsing stack.
366    */
367   Stack<pair<ParseOperation,LExpr*> > _todo;
368 
369   // global parsing data structures -- END
370 
371   // a few helper functions enabling the body of parseTermOrFormula be of reasonable size
372 
373   void complainAboutArgShortageOrWrongSorts(const vstring& symbolClass, LExpr* exp) NO_RETURN;
374 
375   void parseLetBegin(LExpr* exp);
376   void parseLetPrepareLookup(LExpr* exp);
377   void parseLetEnd(LExpr* exp);
378 
379   void parseQuantBegin(LExpr* exp);
380 
381   void parseAnnotatedTerm(LExpr* exp);
382 
383   /** Scope's are filled by forall, exists, and let */
384   bool parseAsScopeLookup(const vstring& id);
385   /** Currently either numeral or decimal */
386   bool parseAsSpecConstant(const vstring& id);
387   /** Declared or defined functions (and predicates) - which includes 0-arity ones */
388   bool parseAsUserDefinedSymbol(const vstring& id, LExpr* exp);
389   /** Whatever is built-in and looks like a formula from vampire perspective (see FormulaSymbol)
390    * - includes the second half of parsing quantifiers */
391   bool parseAsBuiltinFormulaSymbol(const vstring& id, LExpr* exp);
392   /** Whatever is built-in and looks like a term from vampire perspective (see TermSymbol)
393    * - excludes parts for dealing with let */
394   bool parseAsBuiltinTermSymbol(const vstring& id, LExpr* exp);
395 
396   /** Parsing things like "((_ divisible 5) x)" */
397   void parseRankedFunctionApplication(LExpr* exp);
398 
399   /**
400    * Main term parsing routine.
401    * Assumes "global parsing data structures" initialized.
402    * Returns the body's value as a ParseResult.
403    *
404    * Currently unsupported features (see http://smtlib.cs.uiowa.edu/papers/smt-lib-reference-v2.5-r2015-06-28.pdf):
405    * - qualified identifiers "(as f s)"
406    * - hexadecimal, binary and string spec_constants
407    * - :named expressions "(! (> x y) :named p1)" cause a user error.
408    *    They could also be ignored, but smtlib dictates that
409    *    1) the named term has to be closed (needs an extra check),
410    *    2) the new name can be used elsewhere (also already in the term being parsed in the in-order traversal)
411    *   So the proper behavior would be more difficult to support.
412    * - "define-funs-rec" and "define-fun-rec"; syntactically these would be fine,
413    *  but any reasonable use will rely on some well-founded semantics which can only be supported with care
414    *
415    * Ignored feature:
416    * - quantifier patterns: " (forall (( x0 A) (x1 A) (x2 A)) (! (=> (and (r x0 x1) (r x1 x2 )) (r x0 x2 )) : pattern ((r x0 x1) (r x1 x2 )) : pattern ((p x0 a)) ))
417    *  the patter information is lost and the pattern data is not checked semantically.
418    *
419    * Violates standard:
420    * - requires variables under a single quantifier to be distinct
421    * - the rule that "variables cannot have the same name as a theory function symbol in the same scope" is currently ignored
422    */
423   ParseResult parseTermOrFormula(LExpr* body);
424 
425   /**
426    * Handle "assert" entry.
427    *
428    * On success results in a single formula added to _formulas.
429    */
430   void readAssert(LExpr* body);
431 
432   /**
433    * Unofficial command
434    *
435    * Behaves like conjecture declaration in TPTP
436    */
437   void readAssertNot(LExpr* body);
438 
439   /**
440    * Unofficial command
441    *
442    * Behaves like conjecture declaration in TPTP
443    */
444   void colorSymbol(const vstring& name, Color color);
445 
446   /**
447    * Units collected during parsing.
448    */
449   UnitList* _formulas;
450 
451   /**
452    * To support a mechanism for dealing with large arithmetic constants.
453    * Adapted from the tptp parser.
454    */
455   Set<vstring> _overflow;
456 
457   /**
458    * Toplevel parsing dispatch for a benchmark.
459    */
460   void readBenchmark(LExprList* bench);
461 };
462 
463 }
464 
465 #endif // __SMTLIB2__
466