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