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