Remove replay and use-theory options and idl (#4186)
[cvc5.git] / src / main / driver_unified.cpp
1 /********************* */
2 /*! \file driver_unified.cpp
3 ** \verbatim
4 ** Top contributors (to current version):
5 ** Morgan Deters, Tim King, Liana Hadarean
6 ** This file is part of the CVC4 project.
7 ** Copyright (c) 2009-2019 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.\endverbatim
11 **
12 ** \brief Driver for CVC4 executable (cvc4)
13 **/
14
15 #include <stdio.h>
16 #include <unistd.h>
17
18 #include <cstdlib>
19 #include <cstring>
20 #include <fstream>
21 #include <iostream>
22 #include <memory>
23 #include <new>
24
25 #include "cvc4autoconfig.h"
26
27 #include "api/cvc4cpp.h"
28 #include "base/configuration.h"
29 #include "base/output.h"
30 #include "expr/expr_iomanip.h"
31 #include "expr/expr_manager.h"
32 #include "main/command_executor.h"
33 #include "main/interactive_shell.h"
34 #include "main/main.h"
35 #include "options/options.h"
36 #include "options/set_language.h"
37 #include "parser/parser.h"
38 #include "parser/parser_builder.h"
39 #include "parser/parser_exception.h"
40 #include "smt/command.h"
41 #include "util/result.h"
42 #include "util/statistics_registry.h"
43
44 using namespace std;
45 using namespace CVC4;
46 using namespace CVC4::parser;
47 using namespace CVC4::main;
48
49 namespace CVC4 {
50 namespace main {
51 /** Global options variable */
52 thread_local Options* pOptions;
53
54 /** Full argv[0] */
55 const char *progPath;
56
57 /** Just the basename component of argv[0] */
58 const std::string *progName;
59
60 /** A pointer to the CommandExecutor (the signal handlers need it) */
61 CVC4::main::CommandExecutor* pExecutor = NULL;
62
63 /** A pointer to the totalTime driver stat (the signal handlers need it) */
64 CVC4::TimerStat* pTotalTime = NULL;
65
66 }/* CVC4::main namespace */
67 }/* CVC4 namespace */
68
69
70 void printUsage(Options& opts, bool full) {
71 stringstream ss;
72 ss << "usage: " << opts.getBinaryName() << " [options] [input-file]"
73 << endl << endl
74 << "Without an input file, or with `-', CVC4 reads from standard input."
75 << endl << endl
76 << "CVC4 options:" << endl;
77 if(full) {
78 Options::printUsage( ss.str(), *(opts.getOut()) );
79 } else {
80 Options::printShortUsage( ss.str(), *(opts.getOut()) );
81 }
82 }
83
84 int runCvc4(int argc, char* argv[], Options& opts) {
85
86 // Timer statistic
87 pTotalTime = new TimerStat("totalTime");
88 pTotalTime->start();
89
90 // For the signal handlers' benefit
91 pOptions = &opts;
92
93 // Initialize the signal handlers
94 cvc4_init();
95
96 progPath = argv[0];
97
98 // Parse the options
99 vector<string> filenames = Options::parseOptions(&opts, argc, argv);
100
101 string progNameStr = opts.getBinaryName();
102 progName = &progNameStr;
103
104 if( opts.getHelp() ) {
105 printUsage(opts, true);
106 exit(1);
107 } else if( opts.getLanguageHelp() ) {
108 Options::printLanguageHelp(*(opts.getOut()));
109 exit(1);
110 } else if( opts.getVersion() ) {
111 *(opts.getOut()) << Configuration::about().c_str() << flush;
112 exit(0);
113 }
114
115 segvSpin = opts.getSegvSpin();
116
117 // If in competition mode, set output stream option to flush immediately
118 #ifdef CVC4_COMPETITION_MODE
119 *(opts.getOut()) << unitbuf;
120 #endif /* CVC4_COMPETITION_MODE */
121
122 // We only accept one input file
123 if(filenames.size() > 1) {
124 throw Exception("Too many input files specified.");
125 }
126
127 // If no file supplied we will read from standard input
128 const bool inputFromStdin = filenames.empty() || filenames[0] == "-";
129
130 // if we're reading from stdin on a TTY, default to interactive mode
131 if(!opts.wasSetByUserInteractive()) {
132 opts.setInteractive(inputFromStdin && isatty(fileno(stdin)));
133 }
134
135 // Auto-detect input language by filename extension
136 std::string filenameStr("<stdin>");
137 if (!inputFromStdin) {
138 // Use swap to avoid copying the string
139 // TODO: use std::move() when switching to c++11
140 filenameStr.swap(filenames[0]);
141 }
142 const char* filename = filenameStr.c_str();
143
144 if(opts.getInputLanguage() == language::input::LANG_AUTO) {
145 if( inputFromStdin ) {
146 // We can't do any fancy detection on stdin
147 opts.setInputLanguage(language::input::LANG_CVC4);
148 } else {
149 unsigned len = filenameStr.size();
150 if(len >= 5 && !strcmp(".smt2", filename + len - 5)) {
151 opts.setInputLanguage(language::input::LANG_SMTLIB_V2_6);
152 } else if((len >= 2 && !strcmp(".p", filename + len - 2))
153 || (len >= 5 && !strcmp(".tptp", filename + len - 5))) {
154 opts.setInputLanguage(language::input::LANG_TPTP);
155 } else if(( len >= 4 && !strcmp(".cvc", filename + len - 4) )
156 || ( len >= 5 && !strcmp(".cvc4", filename + len - 5) )) {
157 opts.setInputLanguage(language::input::LANG_CVC4);
158 } else if((len >= 3 && !strcmp(".sy", filename + len - 3))
159 || (len >= 3 && !strcmp(".sl", filename + len - 3))) {
160 opts.setInputLanguage(language::input::LANG_SYGUS);
161 //since there is no sygus output language, set this to SMT lib 2
162 //opts.setOutputLanguage(language::output::LANG_SMTLIB_V2_0);
163 }
164 }
165 }
166
167 if(opts.getOutputLanguage() == language::output::LANG_AUTO) {
168 opts.setOutputLanguage(language::toOutputLanguage(opts.getInputLanguage()));
169 }
170
171 // Determine which messages to show based on smtcomp_mode and verbosity
172 if(Configuration::isMuzzledBuild()) {
173 DebugChannel.setStream(&CVC4::null_os);
174 TraceChannel.setStream(&CVC4::null_os);
175 NoticeChannel.setStream(&CVC4::null_os);
176 ChatChannel.setStream(&CVC4::null_os);
177 MessageChannel.setStream(&CVC4::null_os);
178 WarningChannel.setStream(&CVC4::null_os);
179 }
180
181 // important even for muzzled builds (to get result output right)
182 (*(opts.getOut())) << language::SetLanguage(opts.getOutputLanguage());
183
184 // Create the command executor to execute the parsed commands
185 pExecutor = new CommandExecutor(opts);
186
187 int returnValue = 0;
188 {
189 // Timer statistic
190 RegisterStatistic statTotalTime(&pExecutor->getStatisticsRegistry(),
191 pTotalTime);
192
193 // Filename statistics
194 ReferenceStat<std::string> s_statFilename("filename", filenameStr);
195 RegisterStatistic statFilenameReg(&pExecutor->getStatisticsRegistry(),
196 &s_statFilename);
197 // set filename in smt engine
198 pExecutor->getSmtEngine()->setFilename(filenameStr);
199
200 // Parse and execute commands until we are done
201 Command* cmd;
202 bool status = true;
203 if(opts.getInteractive() && inputFromStdin) {
204 if(opts.getTearDownIncremental() > 0) {
205 throw OptionException(
206 "--tear-down-incremental doesn't work in interactive mode");
207 }
208 if(!opts.wasSetByUserIncrementalSolving()) {
209 cmd = new SetOptionCommand("incremental", SExpr(true));
210 cmd->setMuted(true);
211 pExecutor->doCommand(cmd);
212 delete cmd;
213 }
214 InteractiveShell shell(pExecutor->getSolver());
215 if(opts.getInteractivePrompt()) {
216 Message() << Configuration::getPackageName()
217 << " " << Configuration::getVersionString();
218 if(Configuration::isGitBuild()) {
219 Message() << " [" << Configuration::getGitId() << "]";
220 }
221 Message() << (Configuration::isDebugBuild() ? " DEBUG" : "")
222 << " assertions:"
223 << (Configuration::isAssertionBuild() ? "on" : "off")
224 << endl << endl;
225 Message() << Configuration::copyright() << endl;
226 }
227
228 while(true) {
229 try {
230 cmd = shell.readCommand();
231 } catch(UnsafeInterruptException& e) {
232 (*opts.getOut()) << CommandInterrupted();
233 break;
234 }
235 if (cmd == NULL)
236 break;
237 status = pExecutor->doCommand(cmd) && status;
238 if (cmd->interrupted()) {
239 delete cmd;
240 break;
241 }
242 delete cmd;
243 }
244 } else if( opts.getTearDownIncremental() > 0) {
245 if(!opts.getIncrementalSolving() && opts.getTearDownIncremental() > 1) {
246 // For tear-down-incremental values greater than 1, need incremental
247 // on too.
248 cmd = new SetOptionCommand("incremental", SExpr(true));
249 cmd->setMuted(true);
250 pExecutor->doCommand(cmd);
251 delete cmd;
252 // if(opts.wasSetByUserIncrementalSolving()) {
253 // throw OptionException(
254 // "--tear-down-incremental incompatible with --incremental");
255 // }
256
257 // cmd = new SetOptionCommand("incremental", SExpr(false));
258 // cmd->setMuted(true);
259 // pExecutor->doCommand(cmd);
260 // delete cmd;
261 }
262
263 ParserBuilder parserBuilder(pExecutor->getSolver(), filename, opts);
264
265 if( inputFromStdin ) {
266 #if defined(CVC4_COMPETITION_MODE) && !defined(CVC4_SMTCOMP_APPLICATION_TRACK)
267 parserBuilder.withStreamInput(cin);
268 #else /* CVC4_COMPETITION_MODE && !CVC4_SMTCOMP_APPLICATION_TRACK */
269 parserBuilder.withLineBufferedStreamInput(cin);
270 #endif /* CVC4_COMPETITION_MODE && !CVC4_SMTCOMP_APPLICATION_TRACK */
271 }
272
273 vector< vector<Command*> > allCommands;
274 allCommands.push_back(vector<Command*>());
275 std::unique_ptr<Parser> parser(parserBuilder.build());
276 int needReset = 0;
277 // true if one of the commands was interrupted
278 bool interrupted = false;
279 while (status)
280 {
281 if (interrupted) {
282 (*opts.getOut()) << CommandInterrupted();
283 break;
284 }
285
286 try {
287 cmd = parser->nextCommand();
288 if (cmd == NULL) break;
289 } catch (UnsafeInterruptException& e) {
290 interrupted = true;
291 continue;
292 }
293
294 if(dynamic_cast<PushCommand*>(cmd) != NULL) {
295 if(needReset >= opts.getTearDownIncremental()) {
296 pExecutor->reset();
297 for(size_t i = 0; i < allCommands.size() && !interrupted; ++i) {
298 if (interrupted) break;
299 for(size_t j = 0; j < allCommands[i].size() && !interrupted; ++j)
300 {
301 Command* ccmd = allCommands[i][j]->clone();
302 ccmd->setMuted(true);
303 pExecutor->doCommand(ccmd);
304 if (ccmd->interrupted())
305 {
306 interrupted = true;
307 }
308 delete ccmd;
309 }
310 }
311 needReset = 0;
312 }
313 allCommands.push_back(vector<Command*>());
314 Command* copy = cmd->clone();
315 allCommands.back().push_back(copy);
316 status = pExecutor->doCommand(cmd);
317 if(cmd->interrupted()) {
318 interrupted = true;
319 continue;
320 }
321 } else if(dynamic_cast<PopCommand*>(cmd) != NULL) {
322 allCommands.pop_back(); // fixme leaks cmds here
323 if (needReset >= opts.getTearDownIncremental()) {
324 pExecutor->reset();
325 for(size_t i = 0; i < allCommands.size() && !interrupted; ++i) {
326 for(size_t j = 0; j < allCommands[i].size() && !interrupted; ++j)
327 {
328 Command* ccmd = allCommands[i][j]->clone();
329 ccmd->setMuted(true);
330 pExecutor->doCommand(ccmd);
331 if (ccmd->interrupted())
332 {
333 interrupted = true;
334 }
335 delete ccmd;
336 }
337 }
338 if (interrupted) continue;
339 (*opts.getOut()) << CommandSuccess();
340 needReset = 0;
341 } else {
342 status = pExecutor->doCommand(cmd);
343 if(cmd->interrupted()) {
344 interrupted = true;
345 continue;
346 }
347 }
348 } else if(dynamic_cast<CheckSatCommand*>(cmd) != NULL ||
349 dynamic_cast<QueryCommand*>(cmd) != NULL) {
350 if(needReset >= opts.getTearDownIncremental()) {
351 pExecutor->reset();
352 for(size_t i = 0; i < allCommands.size() && !interrupted; ++i) {
353 for(size_t j = 0; j < allCommands[i].size() && !interrupted; ++j)
354 {
355 Command* ccmd = allCommands[i][j]->clone();
356 ccmd->setMuted(true);
357 pExecutor->doCommand(ccmd);
358 if (ccmd->interrupted())
359 {
360 interrupted = true;
361 }
362 delete ccmd;
363 }
364 }
365 needReset = 0;
366 } else {
367 ++needReset;
368 }
369 if (interrupted) {
370 continue;
371 }
372
373 status = pExecutor->doCommand(cmd);
374 if(cmd->interrupted()) {
375 interrupted = true;
376 continue;
377 }
378 } else if(dynamic_cast<ResetCommand*>(cmd) != NULL) {
379 pExecutor->doCommand(cmd);
380 allCommands.clear();
381 allCommands.push_back(vector<Command*>());
382 } else {
383 // We shouldn't copy certain commands, because they can cause
384 // an error on replay since there's no associated sat/unsat check
385 // preceding them.
386 if(dynamic_cast<GetUnsatCoreCommand*>(cmd) == NULL &&
387 dynamic_cast<GetProofCommand*>(cmd) == NULL &&
388 dynamic_cast<GetValueCommand*>(cmd) == NULL &&
389 dynamic_cast<GetModelCommand*>(cmd) == NULL &&
390 dynamic_cast<GetAssignmentCommand*>(cmd) == NULL &&
391 dynamic_cast<GetInstantiationsCommand*>(cmd) == NULL &&
392 dynamic_cast<GetAssertionsCommand*>(cmd) == NULL &&
393 dynamic_cast<GetInfoCommand*>(cmd) == NULL &&
394 dynamic_cast<GetOptionCommand*>(cmd) == NULL &&
395 dynamic_cast<EchoCommand*>(cmd) == NULL) {
396 Command* copy = cmd->clone();
397 allCommands.back().push_back(copy);
398 }
399 status = pExecutor->doCommand(cmd);
400 if(cmd->interrupted()) {
401 interrupted = true;
402 continue;
403 }
404
405 if(dynamic_cast<QuitCommand*>(cmd) != NULL) {
406 delete cmd;
407 break;
408 }
409 }
410 delete cmd;
411 }
412 } else {
413 if(!opts.wasSetByUserIncrementalSolving()) {
414 cmd = new SetOptionCommand("incremental", SExpr(false));
415 cmd->setMuted(true);
416 pExecutor->doCommand(cmd);
417 delete cmd;
418 }
419
420 ParserBuilder parserBuilder(pExecutor->getSolver(), filename, opts);
421
422 if( inputFromStdin ) {
423 #if defined(CVC4_COMPETITION_MODE) && !defined(CVC4_SMTCOMP_APPLICATION_TRACK)
424 parserBuilder.withStreamInput(cin);
425 #else /* CVC4_COMPETITION_MODE && !CVC4_SMTCOMP_APPLICATION_TRACK */
426 parserBuilder.withLineBufferedStreamInput(cin);
427 #endif /* CVC4_COMPETITION_MODE && !CVC4_SMTCOMP_APPLICATION_TRACK */
428 }
429
430 std::unique_ptr<Parser> parser(parserBuilder.build());
431 bool interrupted = false;
432 while (status)
433 {
434 if (interrupted) {
435 (*opts.getOut()) << CommandInterrupted();
436 pExecutor->reset();
437 break;
438 }
439 try {
440 cmd = parser->nextCommand();
441 if (cmd == NULL) break;
442 } catch (UnsafeInterruptException& e) {
443 interrupted = true;
444 continue;
445 }
446
447 status = pExecutor->doCommand(cmd);
448 if (cmd->interrupted() && status == 0) {
449 interrupted = true;
450 break;
451 }
452
453 if(dynamic_cast<QuitCommand*>(cmd) != NULL) {
454 delete cmd;
455 break;
456 }
457 delete cmd;
458 }
459 }
460
461 Result result;
462 if(status) {
463 result = pExecutor->getResult();
464 returnValue = 0;
465 } else {
466 // there was some kind of error
467 returnValue = 1;
468 }
469
470 #ifdef CVC4_COMPETITION_MODE
471 opts.flushOut();
472 // exit, don't return (don't want destructors to run)
473 // _exit() from unistd.h doesn't run global destructors
474 // or other on_exit/atexit stuff.
475 _exit(returnValue);
476 #endif /* CVC4_COMPETITION_MODE */
477
478 ReferenceStat< Result > s_statSatResult("sat/unsat", result);
479 RegisterStatistic statSatResultReg(&pExecutor->getStatisticsRegistry(),
480 &s_statSatResult);
481
482 pTotalTime->stop();
483
484 // Tim: I think that following comment is out of date?
485 // Set the global executor pointer to NULL first. If we get a
486 // signal while dumping statistics, we don't want to try again.
487 pExecutor->flushOutputStreams();
488
489 #ifdef CVC4_DEBUG
490 if(opts.getEarlyExit() && opts.wasSetByUserEarlyExit()) {
491 _exit(returnValue);
492 }
493 #else /* CVC4_DEBUG */
494 if(opts.getEarlyExit()) {
495 _exit(returnValue);
496 }
497 #endif /* CVC4_DEBUG */
498 }
499
500 // On exceptional exit, these are leaked, but that's okay... they
501 // need to be around in that case for main() to print statistics.
502 delete pTotalTime;
503 delete pExecutor;
504
505 pTotalTime = NULL;
506 pExecutor = NULL;
507
508 cvc4_shutdown();
509
510 return returnValue;
511 }