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 |
|
* Parser state implementation. |
14 |
|
*/ |
15 |
|
|
16 |
|
#include "parser/parser.h" |
17 |
|
|
18 |
|
#include <clocale> |
19 |
|
#include <fstream> |
20 |
|
#include <iostream> |
21 |
|
#include <iterator> |
22 |
|
#include <sstream> |
23 |
|
#include <unordered_set> |
24 |
|
|
25 |
|
#include "api/cpp/cvc5.h" |
26 |
|
#include "base/check.h" |
27 |
|
#include "base/output.h" |
28 |
|
#include "expr/kind.h" |
29 |
|
#include "parser/input.h" |
30 |
|
#include "parser/parser_exception.h" |
31 |
|
#include "smt/command.h" |
32 |
|
|
33 |
|
using namespace std; |
34 |
|
using namespace cvc5::kind; |
35 |
|
|
36 |
|
namespace cvc5 { |
37 |
|
namespace parser { |
38 |
|
|
39 |
6736 |
Parser::Parser(api::Solver* solver, |
40 |
|
SymbolManager* sm, |
41 |
|
bool strictMode, |
42 |
6736 |
bool parseOnly) |
43 |
|
: d_symman(sm), |
44 |
6736 |
d_symtab(sm->getSymbolTable()), |
45 |
|
d_assertionLevel(0), |
46 |
|
d_anonymousFunctionCount(0), |
47 |
|
d_done(true), |
48 |
|
d_checksEnabled(true), |
49 |
|
d_strictMode(strictMode), |
50 |
|
d_parseOnly(parseOnly), |
51 |
|
d_canIncludeFile(true), |
52 |
|
d_logicIsForced(false), |
53 |
|
d_forcedLogic(), |
54 |
13472 |
d_solver(solver) |
55 |
|
{ |
56 |
6736 |
} |
57 |
|
|
58 |
13472 |
Parser::~Parser() { |
59 |
6738 |
for (std::list<Command*>::iterator iter = d_commandQueue.begin(); |
60 |
6738 |
iter != d_commandQueue.end(); ++iter) { |
61 |
2 |
Command* command = *iter; |
62 |
2 |
delete command; |
63 |
|
} |
64 |
6736 |
d_commandQueue.clear(); |
65 |
6736 |
} |
66 |
|
|
67 |
651231 |
api::Solver* Parser::getSolver() const { return d_solver; } |
68 |
|
|
69 |
2854675 |
api::Term Parser::getSymbol(const std::string& name, SymbolType type) |
70 |
|
{ |
71 |
2854675 |
checkDeclaration(name, CHECK_DECLARED, type); |
72 |
2854675 |
Assert(isDeclared(name, type)); |
73 |
2854675 |
Assert(type == SYM_VARIABLE); |
74 |
|
// Functions share var namespace |
75 |
2854675 |
return d_symtab->lookup(name); |
76 |
|
} |
77 |
|
|
78 |
9 |
void Parser::forceLogic(const std::string& logic) |
79 |
|
{ |
80 |
9 |
Assert(!d_logicIsForced); |
81 |
9 |
d_logicIsForced = true; |
82 |
9 |
d_forcedLogic = logic; |
83 |
9 |
} |
84 |
|
|
85 |
2854675 |
api::Term Parser::getVariable(const std::string& name) |
86 |
|
{ |
87 |
2854675 |
return getSymbol(name, SYM_VARIABLE); |
88 |
|
} |
89 |
|
|
90 |
|
api::Term Parser::getFunction(const std::string& name) |
91 |
|
{ |
92 |
|
return getSymbol(name, SYM_VARIABLE); |
93 |
|
} |
94 |
|
|
95 |
2513346 |
api::Term Parser::getExpressionForName(const std::string& name) |
96 |
|
{ |
97 |
5026692 |
api::Sort t; |
98 |
5026692 |
return getExpressionForNameAndType(name, t); |
99 |
|
} |
100 |
|
|
101 |
2513717 |
api::Term Parser::getExpressionForNameAndType(const std::string& name, |
102 |
|
api::Sort t) |
103 |
|
{ |
104 |
2513717 |
Assert(isDeclared(name)); |
105 |
|
// first check if the variable is declared and not overloaded |
106 |
2513717 |
api::Term expr = getVariable(name); |
107 |
2513717 |
if(expr.isNull()) { |
108 |
|
// the variable is overloaded, try with type if the type exists |
109 |
6 |
if(!t.isNull()) { |
110 |
|
// if we decide later to support annotations for function types, this will |
111 |
|
// update to separate t into ( argument types, return type ) |
112 |
6 |
expr = getOverloadedConstantForType(name, t); |
113 |
6 |
if(expr.isNull()) { |
114 |
|
parseError("Cannot get overloaded constant for type ascription."); |
115 |
|
} |
116 |
|
}else{ |
117 |
|
parseError("Overloaded constants must be type cast."); |
118 |
|
} |
119 |
|
} |
120 |
|
// now, post-process the expression |
121 |
2513717 |
Assert(!expr.isNull()); |
122 |
5027434 |
api::Sort te = expr.getSort(); |
123 |
2513717 |
if (te.isConstructor() && te.getConstructorArity() == 0) |
124 |
|
{ |
125 |
|
// nullary constructors have APPLY_CONSTRUCTOR kind with no children |
126 |
2669 |
expr = d_solver->mkTerm(api::APPLY_CONSTRUCTOR, expr); |
127 |
|
} |
128 |
5027434 |
return expr; |
129 |
|
} |
130 |
|
|
131 |
|
bool Parser::getTesterName(api::Term cons, std::string& name) { return false; } |
132 |
|
|
133 |
331336 |
api::Kind Parser::getKindForFunction(api::Term fun) |
134 |
|
{ |
135 |
662672 |
api::Sort t = fun.getSort(); |
136 |
331336 |
if (t.isFunction()) |
137 |
|
{ |
138 |
313701 |
return api::APPLY_UF; |
139 |
|
} |
140 |
17635 |
else if (t.isConstructor()) |
141 |
|
{ |
142 |
5280 |
return api::APPLY_CONSTRUCTOR; |
143 |
|
} |
144 |
12355 |
else if (t.isSelector()) |
145 |
|
{ |
146 |
10574 |
return api::APPLY_SELECTOR; |
147 |
|
} |
148 |
1781 |
else if (t.isTester()) |
149 |
|
{ |
150 |
1750 |
return api::APPLY_TESTER; |
151 |
|
} |
152 |
31 |
else if (t.isUpdater()) |
153 |
|
{ |
154 |
31 |
return api::APPLY_UPDATER; |
155 |
|
} |
156 |
|
return api::UNDEFINED_KIND; |
157 |
|
} |
158 |
|
|
159 |
219618 |
api::Sort Parser::getSort(const std::string& name) |
160 |
|
{ |
161 |
219619 |
checkDeclaration(name, CHECK_DECLARED, SYM_SORT); |
162 |
219617 |
Assert(isDeclared(name, SYM_SORT)); |
163 |
219617 |
api::Sort t = d_symtab->lookupType(name); |
164 |
219617 |
return t; |
165 |
|
} |
166 |
|
|
167 |
594 |
api::Sort Parser::getSort(const std::string& name, |
168 |
|
const std::vector<api::Sort>& params) |
169 |
|
{ |
170 |
596 |
checkDeclaration(name, CHECK_DECLARED, SYM_SORT); |
171 |
592 |
Assert(isDeclared(name, SYM_SORT)); |
172 |
592 |
api::Sort t = d_symtab->lookupType(name, params); |
173 |
592 |
return t; |
174 |
|
} |
175 |
|
|
176 |
|
size_t Parser::getArity(const std::string& sort_name) { |
177 |
|
checkDeclaration(sort_name, CHECK_DECLARED, SYM_SORT); |
178 |
|
Assert(isDeclared(sort_name, SYM_SORT)); |
179 |
|
return d_symtab->lookupArity(sort_name); |
180 |
|
} |
181 |
|
|
182 |
|
/* Returns true if name is bound to a boolean variable. */ |
183 |
|
bool Parser::isBoolean(const std::string& name) { |
184 |
|
api::Term expr = getVariable(name); |
185 |
|
return !expr.isNull() && expr.getSort().isBoolean(); |
186 |
|
} |
187 |
|
|
188 |
329609 |
bool Parser::isFunctionLike(api::Term fun) |
189 |
|
{ |
190 |
329609 |
if(fun.isNull()) { |
191 |
|
return false; |
192 |
|
} |
193 |
659218 |
api::Sort type = fun.getSort(); |
194 |
340185 |
return type.isFunction() || type.isConstructor() || type.isTester() || |
195 |
340185 |
type.isSelector(); |
196 |
|
} |
197 |
|
|
198 |
|
/* Returns true if name is bound to a function returning boolean. */ |
199 |
|
bool Parser::isPredicate(const std::string& name) { |
200 |
|
api::Term expr = getVariable(name); |
201 |
|
return !expr.isNull() && expr.getSort().isPredicate(); |
202 |
|
} |
203 |
|
|
204 |
106641 |
api::Term Parser::bindVar(const std::string& name, |
205 |
|
const api::Sort& type, |
206 |
|
bool levelZero, |
207 |
|
bool doOverload) |
208 |
|
{ |
209 |
106641 |
bool globalDecls = d_symman->getGlobalDeclarations(); |
210 |
106641 |
Debug("parser") << "bindVar(" << name << ", " << type << ")" << std::endl; |
211 |
106641 |
api::Term expr = d_solver->mkConst(type, name); |
212 |
106641 |
defineVar(name, expr, globalDecls || levelZero, doOverload); |
213 |
106641 |
return expr; |
214 |
|
} |
215 |
|
|
216 |
60574 |
api::Term Parser::bindBoundVar(const std::string& name, const api::Sort& type) |
217 |
|
{ |
218 |
121148 |
Debug("parser") << "bindBoundVar(" << name << ", " << type << ")" |
219 |
60574 |
<< std::endl; |
220 |
60574 |
api::Term expr = d_solver->mkVar(type, name); |
221 |
60574 |
defineVar(name, expr); |
222 |
60574 |
return expr; |
223 |
|
} |
224 |
|
|
225 |
31708 |
std::vector<api::Term> Parser::bindBoundVars( |
226 |
|
std::vector<std::pair<std::string, api::Sort> >& sortedVarNames) |
227 |
|
{ |
228 |
31708 |
std::vector<api::Term> vars; |
229 |
88476 |
for (std::pair<std::string, api::Sort>& i : sortedVarNames) |
230 |
|
{ |
231 |
56768 |
vars.push_back(bindBoundVar(i.first, i.second)); |
232 |
|
} |
233 |
31708 |
return vars; |
234 |
|
} |
235 |
|
|
236 |
|
std::vector<api::Term> Parser::bindVars(const std::vector<std::string> names, |
237 |
|
const api::Sort& type, |
238 |
|
bool levelZero, |
239 |
|
bool doOverload) |
240 |
|
{ |
241 |
|
std::vector<api::Term> vars; |
242 |
|
for (unsigned i = 0; i < names.size(); ++i) { |
243 |
|
vars.push_back(bindVar(names[i], type, levelZero, doOverload)); |
244 |
|
} |
245 |
|
return vars; |
246 |
|
} |
247 |
|
|
248 |
|
std::vector<api::Term> Parser::bindBoundVars( |
249 |
|
const std::vector<std::string> names, const api::Sort& type) |
250 |
|
{ |
251 |
|
std::vector<api::Term> vars; |
252 |
|
for (unsigned i = 0; i < names.size(); ++i) { |
253 |
|
vars.push_back(bindBoundVar(names[i], type)); |
254 |
|
} |
255 |
|
return vars; |
256 |
|
} |
257 |
|
|
258 |
333612 |
void Parser::defineVar(const std::string& name, |
259 |
|
const api::Term& val, |
260 |
|
bool levelZero, |
261 |
|
bool doOverload) |
262 |
|
{ |
263 |
333612 |
Debug("parser") << "defineVar( " << name << " := " << val << ")" << std::endl; |
264 |
333612 |
if (!d_symtab->bind(name, val, levelZero, doOverload)) |
265 |
|
{ |
266 |
|
std::stringstream ss; |
267 |
|
ss << "Cannot bind " << name << " to symbol of type " << val.getSort(); |
268 |
|
ss << ", maybe the symbol has already been defined?"; |
269 |
|
parseError(ss.str()); |
270 |
|
} |
271 |
333612 |
Assert(isDeclared(name)); |
272 |
333612 |
} |
273 |
|
|
274 |
46349 |
void Parser::defineType(const std::string& name, |
275 |
|
const api::Sort& type, |
276 |
|
bool levelZero, |
277 |
|
bool skipExisting) |
278 |
|
{ |
279 |
46349 |
if (skipExisting && isDeclared(name, SYM_SORT)) |
280 |
|
{ |
281 |
2908 |
Assert(d_symtab->lookupType(name) == type); |
282 |
2908 |
return; |
283 |
|
} |
284 |
43441 |
d_symtab->bindType(name, type, levelZero); |
285 |
43441 |
Assert(isDeclared(name, SYM_SORT)); |
286 |
|
} |
287 |
|
|
288 |
354 |
void Parser::defineType(const std::string& name, |
289 |
|
const std::vector<api::Sort>& params, |
290 |
|
const api::Sort& type, |
291 |
|
bool levelZero) |
292 |
|
{ |
293 |
354 |
d_symtab->bindType(name, params, type, levelZero); |
294 |
354 |
Assert(isDeclared(name, SYM_SORT)); |
295 |
354 |
} |
296 |
|
|
297 |
217 |
void Parser::defineParameterizedType(const std::string& name, |
298 |
|
const std::vector<api::Sort>& params, |
299 |
|
const api::Sort& type) |
300 |
|
{ |
301 |
217 |
if (Debug.isOn("parser")) { |
302 |
|
Debug("parser") << "defineParameterizedType(" << name << ", " |
303 |
|
<< params.size() << ", ["; |
304 |
|
if (params.size() > 0) { |
305 |
|
copy(params.begin(), |
306 |
|
params.end() - 1, |
307 |
|
ostream_iterator<api::Sort>(Debug("parser"), ", ")); |
308 |
|
Debug("parser") << params.back(); |
309 |
|
} |
310 |
|
Debug("parser") << "], " << type << ")" << std::endl; |
311 |
|
} |
312 |
217 |
defineType(name, params, type); |
313 |
217 |
} |
314 |
|
|
315 |
4168 |
api::Sort Parser::mkSort(const std::string& name) |
316 |
|
{ |
317 |
4168 |
Debug("parser") << "newSort(" << name << ")" << std::endl; |
318 |
4168 |
bool globalDecls = d_symman->getGlobalDeclarations(); |
319 |
4168 |
api::Sort type = d_solver->mkUninterpretedSort(name); |
320 |
4168 |
defineType(name, type, globalDecls); |
321 |
4168 |
return type; |
322 |
|
} |
323 |
|
|
324 |
23 |
api::Sort Parser::mkSortConstructor(const std::string& name, size_t arity) |
325 |
|
{ |
326 |
46 |
Debug("parser") << "newSortConstructor(" << name << ", " << arity << ")" |
327 |
23 |
<< std::endl; |
328 |
23 |
bool globalDecls = d_symman->getGlobalDeclarations(); |
329 |
23 |
api::Sort type = d_solver->mkSortConstructorSort(name, arity); |
330 |
23 |
defineType(name, vector<api::Sort>(arity), type, globalDecls); |
331 |
23 |
return type; |
332 |
|
} |
333 |
|
|
334 |
1465 |
api::Sort Parser::mkUnresolvedType(const std::string& name) |
335 |
|
{ |
336 |
1465 |
api::Sort unresolved = d_solver->mkUninterpretedSort(name); |
337 |
1465 |
defineType(name, unresolved); |
338 |
1465 |
d_unresolved.insert(unresolved); |
339 |
1465 |
return unresolved; |
340 |
|
} |
341 |
|
|
342 |
57 |
api::Sort Parser::mkUnresolvedTypeConstructor(const std::string& name, |
343 |
|
size_t arity) |
344 |
|
{ |
345 |
57 |
api::Sort unresolved = d_solver->mkSortConstructorSort(name, arity); |
346 |
57 |
defineType(name, vector<api::Sort>(arity), unresolved); |
347 |
57 |
d_unresolved.insert(unresolved); |
348 |
57 |
return unresolved; |
349 |
|
} |
350 |
|
|
351 |
|
api::Sort Parser::mkUnresolvedTypeConstructor( |
352 |
|
const std::string& name, const std::vector<api::Sort>& params) |
353 |
|
{ |
354 |
|
Debug("parser") << "newSortConstructor(P)(" << name << ", " << params.size() |
355 |
|
<< ")" << std::endl; |
356 |
|
api::Sort unresolved = d_solver->mkSortConstructorSort(name, params.size()); |
357 |
|
defineType(name, params, unresolved); |
358 |
|
api::Sort t = getSort(name, params); |
359 |
|
d_unresolved.insert(unresolved); |
360 |
|
return unresolved; |
361 |
|
} |
362 |
|
|
363 |
1522 |
api::Sort Parser::mkUnresolvedType(const std::string& name, size_t arity) |
364 |
|
{ |
365 |
1522 |
if (arity == 0) |
366 |
|
{ |
367 |
1465 |
return mkUnresolvedType(name); |
368 |
|
} |
369 |
57 |
return mkUnresolvedTypeConstructor(name, arity); |
370 |
|
} |
371 |
|
|
372 |
|
bool Parser::isUnresolvedType(const std::string& name) { |
373 |
|
if (!isDeclared(name, SYM_SORT)) { |
374 |
|
return false; |
375 |
|
} |
376 |
|
return d_unresolved.find(getSort(name)) != d_unresolved.end(); |
377 |
|
} |
378 |
|
|
379 |
1164 |
std::vector<api::Sort> Parser::bindMutualDatatypeTypes( |
380 |
|
std::vector<api::DatatypeDecl>& datatypes, bool doOverload) |
381 |
|
{ |
382 |
|
try { |
383 |
|
std::vector<api::Sort> types = |
384 |
2328 |
d_solver->mkDatatypeSorts(datatypes, d_unresolved); |
385 |
|
|
386 |
1164 |
Assert(datatypes.size() == types.size()); |
387 |
1164 |
bool globalDecls = d_symman->getGlobalDeclarations(); |
388 |
|
|
389 |
2686 |
for (unsigned i = 0; i < datatypes.size(); ++i) { |
390 |
3044 |
api::Sort t = types[i]; |
391 |
3044 |
const api::Datatype& dt = t.getDatatype(); |
392 |
3044 |
const std::string& name = dt.getName(); |
393 |
1522 |
Debug("parser-idt") << "define " << name << " as " << t << std::endl; |
394 |
1522 |
if (isDeclared(name, SYM_SORT)) { |
395 |
|
throw ParserException(name + " already declared"); |
396 |
|
} |
397 |
1522 |
if (t.isParametricDatatype()) |
398 |
|
{ |
399 |
114 |
std::vector<api::Sort> paramTypes = t.getDatatypeParamSorts(); |
400 |
57 |
defineType(name, paramTypes, t, globalDecls); |
401 |
|
} |
402 |
|
else |
403 |
|
{ |
404 |
1465 |
defineType(name, t, globalDecls); |
405 |
|
} |
406 |
3044 |
std::unordered_set< std::string > consNames; |
407 |
3044 |
std::unordered_set< std::string > selNames; |
408 |
4419 |
for (size_t j = 0, ncons = dt.getNumConstructors(); j < ncons; j++) |
409 |
|
{ |
410 |
5794 |
const api::DatatypeConstructor& ctor = dt[j]; |
411 |
5794 |
api::Term constructor = ctor.getConstructorTerm(); |
412 |
2897 |
Debug("parser-idt") << "+ define " << constructor << std::endl; |
413 |
5794 |
string constructorName = ctor.getName(); |
414 |
2897 |
if(consNames.find(constructorName)==consNames.end()) { |
415 |
2897 |
if(!doOverload) { |
416 |
|
checkDeclaration(constructorName, CHECK_UNDECLARED); |
417 |
|
} |
418 |
2897 |
defineVar(constructorName, constructor, globalDecls, doOverload); |
419 |
2897 |
consNames.insert(constructorName); |
420 |
|
}else{ |
421 |
|
throw ParserException(constructorName + " already declared in this datatype"); |
422 |
|
} |
423 |
5794 |
std::string testerName; |
424 |
2897 |
if (getTesterName(constructor, testerName)) |
425 |
|
{ |
426 |
5794 |
api::Term tester = ctor.getTesterTerm(); |
427 |
2897 |
Debug("parser-idt") << "+ define " << testerName << std::endl; |
428 |
2897 |
if (!doOverload) |
429 |
|
{ |
430 |
|
checkDeclaration(testerName, CHECK_UNDECLARED); |
431 |
|
} |
432 |
2897 |
defineVar(testerName, tester, globalDecls, doOverload); |
433 |
|
} |
434 |
5764 |
for (size_t k = 0, nargs = ctor.getNumSelectors(); k < nargs; k++) |
435 |
|
{ |
436 |
5734 |
const api::DatatypeSelector& sel = ctor[k]; |
437 |
5734 |
api::Term selector = sel.getSelectorTerm(); |
438 |
2867 |
Debug("parser-idt") << "+++ define " << selector << std::endl; |
439 |
5734 |
string selectorName = sel.getName(); |
440 |
2867 |
if(selNames.find(selectorName)==selNames.end()) { |
441 |
2867 |
if(!doOverload) { |
442 |
|
checkDeclaration(selectorName, CHECK_UNDECLARED); |
443 |
|
} |
444 |
2867 |
defineVar(selectorName, selector, globalDecls, doOverload); |
445 |
2867 |
selNames.insert(selectorName); |
446 |
|
}else{ |
447 |
|
throw ParserException(selectorName + " already declared in this datatype"); |
448 |
|
} |
449 |
|
} |
450 |
|
} |
451 |
|
} |
452 |
|
|
453 |
|
// These are no longer used, and the ExprManager would have |
454 |
|
// complained of a bad substitution if anything is left unresolved. |
455 |
|
// Clear out the set. |
456 |
1164 |
d_unresolved.clear(); |
457 |
|
|
458 |
|
// throw exception if any datatype is not well-founded |
459 |
2686 |
for (unsigned i = 0; i < datatypes.size(); ++i) { |
460 |
3044 |
const api::Datatype& dt = types[i].getDatatype(); |
461 |
1522 |
if (!dt.isCodatatype() && !dt.isWellFounded()) { |
462 |
|
throw ParserException(dt.getName() + " is not well-founded"); |
463 |
|
} |
464 |
|
} |
465 |
2328 |
return types; |
466 |
|
} catch (IllegalArgumentException& ie) { |
467 |
|
throw ParserException(ie.getMessage()); |
468 |
|
} |
469 |
|
} |
470 |
|
|
471 |
4024 |
api::Sort Parser::mkFlatFunctionType(std::vector<api::Sort>& sorts, |
472 |
|
api::Sort range, |
473 |
|
std::vector<api::Term>& flattenVars) |
474 |
|
{ |
475 |
4024 |
if (range.isFunction()) |
476 |
|
{ |
477 |
16 |
std::vector<api::Sort> domainTypes = range.getFunctionDomainSorts(); |
478 |
17 |
for (unsigned i = 0, size = domainTypes.size(); i < size; i++) |
479 |
|
{ |
480 |
9 |
sorts.push_back(domainTypes[i]); |
481 |
|
// the introduced variable is internal (not parsable) |
482 |
18 |
std::stringstream ss; |
483 |
9 |
ss << "__flatten_var_" << i; |
484 |
18 |
api::Term v = d_solver->mkVar(domainTypes[i], ss.str()); |
485 |
9 |
flattenVars.push_back(v); |
486 |
|
} |
487 |
8 |
range = range.getFunctionCodomainSort(); |
488 |
|
} |
489 |
4024 |
if (sorts.empty()) |
490 |
|
{ |
491 |
2359 |
return range; |
492 |
|
} |
493 |
1665 |
return d_solver->mkFunctionSort(sorts, range); |
494 |
|
} |
495 |
|
|
496 |
19122 |
api::Sort Parser::mkFlatFunctionType(std::vector<api::Sort>& sorts, |
497 |
|
api::Sort range) |
498 |
|
{ |
499 |
19122 |
if (sorts.empty()) |
500 |
|
{ |
501 |
|
// no difference |
502 |
1176 |
return range; |
503 |
|
} |
504 |
17946 |
if (Debug.isOn("parser")) |
505 |
|
{ |
506 |
|
Debug("parser") << "mkFlatFunctionType: range " << range << " and domains "; |
507 |
|
for (api::Sort t : sorts) |
508 |
|
{ |
509 |
|
Debug("parser") << " " << t; |
510 |
|
} |
511 |
|
Debug("parser") << "\n"; |
512 |
|
} |
513 |
18148 |
while (range.isFunction()) |
514 |
|
{ |
515 |
202 |
std::vector<api::Sort> domainTypes = range.getFunctionDomainSorts(); |
516 |
101 |
sorts.insert(sorts.end(), domainTypes.begin(), domainTypes.end()); |
517 |
101 |
range = range.getFunctionCodomainSort(); |
518 |
|
} |
519 |
17946 |
return d_solver->mkFunctionSort(sorts, range); |
520 |
|
} |
521 |
|
|
522 |
8 |
api::Term Parser::mkHoApply(api::Term expr, const std::vector<api::Term>& args) |
523 |
|
{ |
524 |
17 |
for (unsigned i = 0; i < args.size(); i++) |
525 |
|
{ |
526 |
9 |
expr = d_solver->mkTerm(api::HO_APPLY, expr, args[i]); |
527 |
|
} |
528 |
8 |
return expr; |
529 |
|
} |
530 |
|
|
531 |
405 |
api::Term Parser::applyTypeAscription(api::Term t, api::Sort s) |
532 |
|
{ |
533 |
405 |
api::Kind k = t.getKind(); |
534 |
405 |
if (k == api::EMPTYSET) |
535 |
|
{ |
536 |
162 |
t = d_solver->mkEmptySet(s); |
537 |
|
} |
538 |
243 |
else if (k == api::EMPTYBAG) |
539 |
|
{ |
540 |
19 |
t = d_solver->mkEmptyBag(s); |
541 |
|
} |
542 |
224 |
else if (k == api::CONST_SEQUENCE) |
543 |
|
{ |
544 |
11 |
if (!s.isSequence()) |
545 |
|
{ |
546 |
|
std::stringstream ss; |
547 |
|
ss << "Type ascription on empty sequence must be a sequence, got " << s; |
548 |
|
parseError(ss.str()); |
549 |
|
} |
550 |
11 |
if (!t.getSequenceValue().empty()) |
551 |
|
{ |
552 |
|
std::stringstream ss; |
553 |
|
ss << "Cannot apply a type ascription to a non-empty sequence"; |
554 |
|
parseError(ss.str()); |
555 |
|
} |
556 |
11 |
t = d_solver->mkEmptySequence(s.getSequenceElementSort()); |
557 |
|
} |
558 |
213 |
else if (k == api::UNIVERSE_SET) |
559 |
|
{ |
560 |
88 |
t = d_solver->mkUniverseSet(s); |
561 |
|
} |
562 |
125 |
else if (k == api::SEP_NIL) |
563 |
|
{ |
564 |
43 |
t = d_solver->mkSepNil(s); |
565 |
|
} |
566 |
82 |
else if (k == api::APPLY_CONSTRUCTOR) |
567 |
|
{ |
568 |
68 |
std::vector<api::Term> children(t.begin(), t.end()); |
569 |
|
// apply type ascription to the operator and reconstruct |
570 |
34 |
children[0] = applyTypeAscription(children[0], s); |
571 |
34 |
t = d_solver->mkTerm(api::APPLY_CONSTRUCTOR, children); |
572 |
|
} |
573 |
|
// !!! temporary until datatypes are refactored in the new API |
574 |
810 |
api::Sort etype = t.getSort(); |
575 |
405 |
if (etype.isConstructor()) |
576 |
|
{ |
577 |
|
// Type ascriptions only have an effect on the node structure if this is a |
578 |
|
// parametric datatype. |
579 |
42 |
if (s.isParametricDatatype()) |
580 |
|
{ |
581 |
|
// get the datatype that t belongs to |
582 |
72 |
api::Sort etyped = etype.getConstructorCodomainSort(); |
583 |
72 |
api::Datatype d = etyped.getDatatype(); |
584 |
|
// lookup by name |
585 |
72 |
api::DatatypeConstructor dc = d.getConstructor(t.toString()); |
586 |
|
// ask the constructor for the specialized constructor term |
587 |
36 |
t = dc.getSpecializedConstructorTerm(s); |
588 |
|
} |
589 |
|
// the type of t does not match the sort s by design (constructor type |
590 |
|
// vs datatype type), thus we use an alternative check here. |
591 |
42 |
if (t.getSort().getConstructorCodomainSort() != s) |
592 |
|
{ |
593 |
|
std::stringstream ss; |
594 |
|
ss << "Type ascription on constructor not satisfied, term " << t |
595 |
|
<< " expected sort " << s << " but has sort " |
596 |
|
<< t.getSort().getConstructorCodomainSort(); |
597 |
|
parseError(ss.str()); |
598 |
|
} |
599 |
42 |
return t; |
600 |
|
} |
601 |
|
// Otherwise, check that the type is correct. Type ascriptions in SMT-LIB 2.6 |
602 |
|
// referred to the range of function sorts. Note that this is only a check |
603 |
|
// and does not impact the returned term. |
604 |
726 |
api::Sort checkSort = t.getSort(); |
605 |
363 |
if (checkSort.isFunction()) |
606 |
|
{ |
607 |
2 |
checkSort = checkSort.getFunctionCodomainSort(); |
608 |
|
} |
609 |
363 |
if (checkSort != s) |
610 |
|
{ |
611 |
|
std::stringstream ss; |
612 |
|
ss << "Type ascription not satisfied, term " << t |
613 |
|
<< " expected (codomain) sort " << s << " but has sort " << t.getSort(); |
614 |
|
parseError(ss.str()); |
615 |
|
} |
616 |
363 |
return t; |
617 |
|
} |
618 |
|
|
619 |
11950104 |
bool Parser::isDeclared(const std::string& name, SymbolType type) { |
620 |
11950104 |
switch (type) { |
621 |
11415720 |
case SYM_VARIABLE: return d_symtab->isBound(name); |
622 |
534384 |
case SYM_SORT: |
623 |
534384 |
return d_symtab->isBoundType(name); |
624 |
|
} |
625 |
|
Assert(false); // Unhandled(type); |
626 |
|
return false; |
627 |
|
} |
628 |
|
|
629 |
8801220 |
void Parser::checkDeclaration(const std::string& varName, |
630 |
|
DeclarationCheck check, |
631 |
|
SymbolType type, |
632 |
|
std::string notes) |
633 |
|
{ |
634 |
8801220 |
if (!d_checksEnabled) { |
635 |
|
return; |
636 |
|
} |
637 |
|
|
638 |
8801220 |
switch (check) { |
639 |
3404655 |
case CHECK_DECLARED: |
640 |
3404655 |
if (!isDeclared(varName, type)) { |
641 |
78 |
parseError("Symbol '" + varName + "' not declared as a " + |
642 |
52 |
(type == SYM_VARIABLE ? "variable" : "type") + |
643 |
52 |
(notes.size() == 0 ? notes : "\n" + notes)); |
644 |
|
} |
645 |
3404629 |
break; |
646 |
|
|
647 |
15504 |
case CHECK_UNDECLARED: |
648 |
15504 |
if (isDeclared(varName, type)) { |
649 |
6 |
parseError("Symbol '" + varName + "' previously declared as a " + |
650 |
4 |
(type == SYM_VARIABLE ? "variable" : "type") + |
651 |
4 |
(notes.size() == 0 ? notes : "\n" + notes)); |
652 |
|
} |
653 |
15502 |
break; |
654 |
|
|
655 |
5381061 |
case CHECK_NONE: |
656 |
5381061 |
break; |
657 |
|
|
658 |
|
default: Assert(false); // Unhandled(check); |
659 |
|
} |
660 |
|
} |
661 |
|
|
662 |
329609 |
void Parser::checkFunctionLike(api::Term fun) |
663 |
|
{ |
664 |
329609 |
if (d_checksEnabled && !isFunctionLike(fun)) { |
665 |
4 |
stringstream ss; |
666 |
2 |
ss << "Expecting function-like symbol, found '"; |
667 |
2 |
ss << fun; |
668 |
2 |
ss << "'"; |
669 |
4 |
parseError(ss.str()); |
670 |
|
} |
671 |
329607 |
} |
672 |
|
|
673 |
724849 |
void Parser::addOperator(api::Kind kind) { d_logicOperators.insert(kind); } |
674 |
|
|
675 |
5201 |
void Parser::preemptCommand(Command* cmd) { d_commandQueue.push_back(cmd); } |
676 |
242362 |
Command* Parser::nextCommand() |
677 |
|
{ |
678 |
242362 |
Debug("parser") << "nextCommand()" << std::endl; |
679 |
242362 |
Command* cmd = NULL; |
680 |
242362 |
if (!d_commandQueue.empty()) { |
681 |
5199 |
cmd = d_commandQueue.front(); |
682 |
5199 |
d_commandQueue.pop_front(); |
683 |
5199 |
setDone(cmd == NULL); |
684 |
|
} else { |
685 |
|
try { |
686 |
237163 |
cmd = d_input->parseCommand(); |
687 |
237127 |
d_commandQueue.push_back(cmd); |
688 |
237127 |
cmd = d_commandQueue.front(); |
689 |
237127 |
d_commandQueue.pop_front(); |
690 |
237127 |
setDone(cmd == NULL); |
691 |
64 |
} catch (ParserException& e) { |
692 |
32 |
setDone(); |
693 |
32 |
throw; |
694 |
8 |
} catch (exception& e) { |
695 |
4 |
setDone(); |
696 |
8 |
parseError(e.what()); |
697 |
|
} |
698 |
|
} |
699 |
242326 |
Debug("parser") << "nextCommand() => " << cmd << std::endl; |
700 |
242326 |
return cmd; |
701 |
|
} |
702 |
|
|
703 |
120 |
api::Term Parser::nextExpression() |
704 |
|
{ |
705 |
120 |
Debug("parser") << "nextExpression()" << std::endl; |
706 |
120 |
api::Term result; |
707 |
120 |
if (!done()) { |
708 |
|
try { |
709 |
120 |
result = d_input->parseExpr(); |
710 |
78 |
setDone(result.isNull()); |
711 |
84 |
} catch (ParserException& e) { |
712 |
42 |
setDone(); |
713 |
42 |
throw; |
714 |
|
} catch (exception& e) { |
715 |
|
setDone(); |
716 |
|
parseError(e.what()); |
717 |
|
} |
718 |
|
} |
719 |
78 |
Debug("parser") << "nextExpression() => " << result << std::endl; |
720 |
78 |
return result; |
721 |
|
} |
722 |
|
|
723 |
167 |
void Parser::attributeNotSupported(const std::string& attr) { |
724 |
167 |
if (d_attributesWarnedAbout.find(attr) == d_attributesWarnedAbout.end()) { |
725 |
40 |
stringstream ss; |
726 |
|
ss << "warning: Attribute '" << attr |
727 |
20 |
<< "' not supported (ignoring this and all following uses)"; |
728 |
20 |
d_input->warning(ss.str()); |
729 |
20 |
d_attributesWarnedAbout.insert(attr); |
730 |
|
} |
731 |
167 |
} |
732 |
|
|
733 |
2568 |
size_t Parser::scopeLevel() const { return d_symman->scopeLevel(); } |
734 |
|
|
735 |
103450 |
void Parser::pushScope(bool isUserContext) |
736 |
|
{ |
737 |
103450 |
d_symman->pushScope(isUserContext); |
738 |
103450 |
} |
739 |
|
|
740 |
68 |
void Parser::pushGetValueScope() |
741 |
|
{ |
742 |
68 |
pushScope(); |
743 |
|
// we must bind all relevant uninterpreted constants, which coincide with |
744 |
|
// the set of uninterpreted constants that are printed in the definition |
745 |
|
// of a model. |
746 |
136 |
std::vector<api::Sort> declareSorts = d_symman->getModelDeclareSorts(); |
747 |
136 |
Trace("parser") << "Push get value scope, with " << declareSorts.size() |
748 |
68 |
<< " declared sorts" << std::endl; |
749 |
72 |
for (const api::Sort& s : declareSorts) |
750 |
|
{ |
751 |
8 |
std::vector<api::Term> elements = d_solver->getModelDomainElements(s); |
752 |
8 |
for (const api::Term& e : elements) |
753 |
|
{ |
754 |
|
// Uninterpreted constants are abstract values, which by SMT-LIB are |
755 |
|
// required to be annotated with their type, e.g. (as @uc_Foo_0 Foo). |
756 |
|
// Thus, the element is not printed simply as its name. |
757 |
8 |
std::string en = e.toString(); |
758 |
4 |
size_t index = en.find("(as "); |
759 |
4 |
if (index == 0) |
760 |
|
{ |
761 |
4 |
index = en.find(" ", 4); |
762 |
4 |
en = en.substr(4, index - 4); |
763 |
|
} |
764 |
4 |
Trace("parser") << "Get value scope : " << en << " -> " << e << std::endl; |
765 |
4 |
defineVar(en, e); |
766 |
|
} |
767 |
|
} |
768 |
68 |
} |
769 |
|
|
770 |
102884 |
void Parser::popScope() |
771 |
|
{ |
772 |
102884 |
d_symman->popScope(); |
773 |
102884 |
} |
774 |
|
|
775 |
|
void Parser::reset() {} |
776 |
|
|
777 |
11145 |
SymbolManager* Parser::getSymbolManager() { return d_symman; } |
778 |
|
|
779 |
9476 |
std::wstring Parser::processAdHocStringEsc(const std::string& s) |
780 |
|
{ |
781 |
18952 |
std::wstring ws; |
782 |
|
{ |
783 |
9476 |
std::setlocale(LC_ALL, "en_US.utf8"); |
784 |
9476 |
std::mbtowc(nullptr, nullptr, 0); |
785 |
9476 |
const char* end = s.data() + s.size(); |
786 |
9476 |
const char* ptr = s.data(); |
787 |
223480 |
for (wchar_t c; ptr != end; ) { |
788 |
107002 |
int res = std::mbtowc(&c, ptr, end - ptr); |
789 |
107002 |
if (res == -1) { |
790 |
|
std::cerr << "Invalid escape sequence in " << s << std::endl; |
791 |
|
break; |
792 |
107002 |
} else if (res == 0) { |
793 |
|
break; |
794 |
|
} else { |
795 |
107002 |
ws += c; |
796 |
107002 |
ptr += res; |
797 |
|
} |
798 |
|
} |
799 |
|
} |
800 |
|
|
801 |
9476 |
std::wstring res; |
802 |
9476 |
unsigned i = 0; |
803 |
223480 |
while (i < ws.size()) |
804 |
|
{ |
805 |
|
// get the current character |
806 |
214004 |
if (ws[i] != '\\') |
807 |
|
{ |
808 |
|
// don't worry about printable here |
809 |
107002 |
res.push_back(ws[i]); |
810 |
107002 |
++i; |
811 |
107002 |
continue; |
812 |
|
} |
813 |
|
// slash is always escaped |
814 |
|
++i; |
815 |
|
if (i >= ws.size()) |
816 |
|
{ |
817 |
|
// slash cannot be the last character if we are parsing escape sequences |
818 |
|
std::stringstream serr; |
819 |
|
serr << "Escape sequence at the end of string: \"" << s |
820 |
|
<< "\" should be handled by lexer"; |
821 |
|
parseError(serr.str()); |
822 |
|
} |
823 |
|
switch (ws[i]) |
824 |
|
{ |
825 |
|
case 'n': |
826 |
|
{ |
827 |
|
res.push_back('\n'); |
828 |
|
i++; |
829 |
|
} |
830 |
|
break; |
831 |
|
case 't': |
832 |
|
{ |
833 |
|
res.push_back('\t'); |
834 |
|
i++; |
835 |
|
} |
836 |
|
break; |
837 |
|
case 'v': |
838 |
|
{ |
839 |
|
res.push_back('\v'); |
840 |
|
i++; |
841 |
|
} |
842 |
|
break; |
843 |
|
case 'b': |
844 |
|
{ |
845 |
|
res.push_back('\b'); |
846 |
|
i++; |
847 |
|
} |
848 |
|
break; |
849 |
|
case 'r': |
850 |
|
{ |
851 |
|
res.push_back('\r'); |
852 |
|
i++; |
853 |
|
} |
854 |
|
break; |
855 |
|
case 'f': |
856 |
|
{ |
857 |
|
res.push_back('\f'); |
858 |
|
i++; |
859 |
|
} |
860 |
|
break; |
861 |
|
case 'a': |
862 |
|
{ |
863 |
|
res.push_back('\a'); |
864 |
|
i++; |
865 |
|
} |
866 |
|
break; |
867 |
|
case '\\': |
868 |
|
{ |
869 |
|
res.push_back('\\'); |
870 |
|
i++; |
871 |
|
} |
872 |
|
break; |
873 |
|
case 'x': |
874 |
|
{ |
875 |
|
bool isValid = false; |
876 |
|
if (i + 2 < ws.size()) |
877 |
|
{ |
878 |
|
if (std::isxdigit(ws[i + 1]) && std::isxdigit(ws[i + 2])) |
879 |
|
{ |
880 |
|
std::wstringstream shex; |
881 |
|
shex << ws[i + 1] << ws[i + 2]; |
882 |
|
unsigned val; |
883 |
|
shex >> std::hex >> val; |
884 |
|
res.push_back(val); |
885 |
|
i += 3; |
886 |
|
isValid = true; |
887 |
|
} |
888 |
|
} |
889 |
|
if (!isValid) |
890 |
|
{ |
891 |
|
std::stringstream serr; |
892 |
|
serr << "Illegal String Literal: \"" << s |
893 |
|
<< "\", must have two digits after \\x"; |
894 |
|
parseError(serr.str()); |
895 |
|
} |
896 |
|
} |
897 |
|
break; |
898 |
|
default: |
899 |
|
{ |
900 |
|
if (std::isdigit(ws[i])) |
901 |
|
{ |
902 |
|
// octal escape sequences TODO : revisit (issue #1251). |
903 |
|
unsigned num = static_cast<unsigned>(ws[i]) - 48; |
904 |
|
bool flag = num < 4; |
905 |
|
if (i + 1 < ws.size() && num < 8 && std::isdigit(ws[i + 1]) |
906 |
|
&& ws[i + 1] < '8') |
907 |
|
{ |
908 |
|
num = num * 8 + static_cast<unsigned>(ws[i + 1]) - 48; |
909 |
|
if (flag && i + 2 < ws.size() && std::isdigit(ws[i + 2]) |
910 |
|
&& ws[i + 2] < '8') |
911 |
|
{ |
912 |
|
num = num * 8 + static_cast<unsigned>(ws[i + 2]) - 48; |
913 |
|
res.push_back(num); |
914 |
|
i += 3; |
915 |
|
} |
916 |
|
else |
917 |
|
{ |
918 |
|
res.push_back(num); |
919 |
|
i += 2; |
920 |
|
} |
921 |
|
} |
922 |
|
else |
923 |
|
{ |
924 |
|
res.push_back(num); |
925 |
|
i++; |
926 |
|
} |
927 |
|
} |
928 |
|
} |
929 |
|
} |
930 |
|
} |
931 |
18952 |
return res; |
932 |
|
} |
933 |
|
|
934 |
9779 |
api::Term Parser::mkStringConstant(const std::string& s) |
935 |
|
{ |
936 |
9779 |
if (d_solver->getOption("input-language") == "LANG_SMTLIB_V2_6") |
937 |
|
{ |
938 |
8896 |
return d_solver->mkString(s, true); |
939 |
|
} |
940 |
|
// otherwise, we must process ad-hoc escape sequences |
941 |
1766 |
std::wstring str = processAdHocStringEsc(s); |
942 |
883 |
return d_solver->mkString(str); |
943 |
|
} |
944 |
|
|
945 |
8 |
api::Term Parser::mkCharConstant(const std::string& s) |
946 |
|
{ |
947 |
8 |
Assert(s.find_first_not_of("0123456789abcdefABCDEF", 0) == std::string::npos |
948 |
|
&& s.size() <= 5 && s.size() > 0) |
949 |
|
<< "Unexpected string for hexadecimal character " << s; |
950 |
8 |
wchar_t val = static_cast<wchar_t>(std::stoul(s, 0, 16)); |
951 |
8 |
return d_solver->mkString(std::wstring(1, val)); |
952 |
|
} |
953 |
|
|
954 |
|
} // namespace parser |
955 |
31104 |
} // namespace cvc5 |