Add Driver options (#7078)
[cvc5.git] / src / main / driver_unified.cpp
index c29ba55a4c5c7d413180655111be7baad28cc255..005de6a34044e80e6bf6b6744b36e12094800ddf 100644 (file)
-/*********************                                                        */
-/*! \file driver_unified.cpp
- ** \verbatim
- ** Original author: Kshitij Bansal
- ** Major contributors: Morgan Deters
- ** Minor contributors (to current version): Francois Bobot
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2014  New York University and The University of Iowa
- ** See the file COPYING in the top-level source directory for licensing
- ** information.\endverbatim
- **
- ** \brief Driver for CVC4 executable (cvc4) unified for both
- ** sequential and portfolio versions
- **/
+/******************************************************************************
+ * Top contributors (to current version):
+ *   Morgan Deters, Liana Hadarean, Tim King
+ *
+ * This file is part of the cvc5 project.
+ *
+ * Copyright (c) 2009-2021 by the authors listed in the file AUTHORS
+ * in the top-level source directory and their institutional affiliations.
+ * All rights reserved.  See the file COPYING in the top-level source
+ * directory for licensing information.
+ * ****************************************************************************
+ *
+ * Driver for cvc5 executable (cvc5).
+ */
 
+#include <stdio.h>
+#include <unistd.h>
+
+#include <chrono>
 #include <cstdlib>
 #include <cstring>
 #include <fstream>
 #include <iostream>
+#include <memory>
 #include <new>
-#include <unistd.h>
-
-#include <stdio.h>
-#include <unistd.h>
 
-#include "cvc4autoconfig.h"
-#include "main/main.h"
+#include "api/cpp/cvc5.h"
+#include "base/configuration.h"
+#include "base/cvc5config.h"
+#include "base/output.h"
+#include "main/command_executor.h"
 #include "main/interactive_shell.h"
+#include "main/main.h"
 #include "main/options.h"
+#include "main/signal_handlers.h"
+#include "main/time_limit.h"
+#include "options/base_options.h"
+#include "options/main_options.h"
+#include "options/option_exception.h"
+#include "options/options.h"
+#include "options/options_public.h"
+#include "options/parser_options.h"
+#include "options/set_language.h"
 #include "parser/parser.h"
 #include "parser/parser_builder.h"
-#include "parser/parser_exception.h"
-#include "expr/expr_manager.h"
-#include "expr/command.h"
-#include "util/configuration.h"
-#include "options/options.h"
-#include "theory/quantifiers/options.h"
-#include "main/command_executor.h"
-
-#ifdef PORTFOLIO_BUILD
-#  include "main/command_executor_portfolio.h"
-#endif
-
-#include "main/options.h"
-#include "smt/options.h"
-#include "util/output.h"
+#include "smt/command.h"
+#include "smt/smt_engine.h"
 #include "util/result.h"
-#include "util/statistics_registry.h"
 
 using namespace std;
-using namespace CVC4;
-using namespace CVC4::parser;
-using namespace CVC4::main;
-
-namespace CVC4 {
-  namespace main {
-    /** Global options variable */
-    CVC4_THREADLOCAL(Options*) pOptions;
-
-    /** Full argv[0] */
-    const char *progPath;
-
-    /** Just the basename component of argv[0] */
-    const char *progName;
-
-    /** A pointer to the CommandExecutor (the signal handlers need it) */
-    CVC4::main::CommandExecutor* pExecutor = NULL;
-
-    /** A pointer to the totalTime driver stat (the signal handlers need it) */
-    CVC4::TimerStat* pTotalTime = NULL;
-
-  }/* CVC4::main namespace */
-}/* CVC4 namespace */
-
-
-void printUsage(Options& opts, bool full) {
-  stringstream ss;
-  ss << "usage: " << opts[options::binary_name] << " [options] [input-file]" << endl
-      << endl
-      << "Without an input file, or with `-', CVC4 reads from standard input." << endl
-      << endl
-      << "CVC4 options:" << endl;
-  if(full) {
-    Options::printUsage( ss.str(), *opts[options::out] );
-  } else {
-    Options::printShortUsage( ss.str(), *opts[options::out] );
-  }
-}
-
-void printStatsFilterZeros(std::ostream& out, const std::string& statsString) {
-  // read each line, if a number, check zero and skip if so
-  // Stat are assumed to one-per line: "<statName>, <statValue>"
+using namespace cvc5;
+using namespace cvc5::parser;
+using namespace cvc5::main;
 
-  std::istringstream iss(statsString);
-  std::string statName, statValue;
+namespace cvc5 {
+namespace main {
 
-  std::getline(iss, statName, ',');
+/** Full argv[0] */
+const char* progPath;
 
-  while( !iss.eof() ) {
+/** Just the basename component of argv[0] */
+std::string progName;
 
-    std::getline(iss, statValue, '\n');
+/** A pointer to the CommandExecutor (the signal handlers need it) */
+std::unique_ptr<cvc5::main::CommandExecutor> pExecutor;
 
-    double curFloat;
-    bool isFloat = (std::istringstream(statValue) >> curFloat);
+/** The time point the binary started, accessible to signal handlers */
+std::unique_ptr<TotalTimer> totalTime;
 
-    if( (isFloat && curFloat == 0) ||
-        statValue == " \"0\"" ||
-        statValue == " \"[]\"") {
-      // skip
-    } else {
-      out << statName << "," << statValue << std::endl;
-    }
-
-    std::getline(iss, statName, ',');
+TotalTimer::~TotalTimer()
+{
+  if (pExecutor != nullptr)
+  {
+    auto duration = std::chrono::steady_clock::now() - d_start;
+    pExecutor->getSmtEngine()->setTotalTimeStatistic(
+        std::chrono::duration<double>(duration).count());
   }
+    }
 
-}
-
-int runCvc4(int argc, char* argv[], Options& opts) {
-
-  // Timer statistic
-  pTotalTime = new TimerStat("totalTime");
-  pTotalTime->start();
+    }  // namespace main
+    }  // namespace cvc5
+
+    void printUsage(const api::DriverOptions& dopts, bool full)
+    {
+      std::stringstream ss;
+      ss << "usage: " << progName << " [options] [input-file]" << std::endl
+         << std::endl
+         << "Without an input file, or with `-', cvc5 reads from standard "
+            "input."
+         << std::endl
+         << std::endl
+         << "cvc5 options:" << std::endl;
+      if (full)
+      {
+        main::printUsage(ss.str(), dopts.out());
+      }
+      else
+      {
+        main::printShortUsage(ss.str(), dopts.out());
+      }
+    }
 
-  // For the signal handlers' benefit
-  pOptions = &opts;
+int runCvc5(int argc, char* argv[], std::unique_ptr<api::Solver>& solver)
+{
+  main::totalTime = std::make_unique<TotalTimer>();
 
   // Initialize the signal handlers
-  cvc4_init();
+  signal_handlers::install();
 
   progPath = argv[0];
 
-  // Parse the options
-  vector<string> filenames = opts.parseOptions(argc, argv);
+  // Create the command executor to execute the parsed commands
+  pExecutor = std::make_unique<CommandExecutor>(solver);
+  api::DriverOptions dopts = solver->getDriverOptions();
+  Options* opts = &pExecutor->getOptions();
 
-# ifndef PORTFOLIO_BUILD
-  if( opts.wasSetByUser(options::threads) ||
-      opts.wasSetByUser(options::threadStackSize) ||
-      ! opts[options::threadArgv].empty() ) {
-    throw OptionException("Thread options cannot be used with sequential CVC4.  Please build and use the portfolio binary `pcvc4'.");
-  }
-# endif
+  // Parse the options
+  std::vector<string> filenames = main::parse(*solver, argc, argv, progName);
 
-  progName = opts[options::binary_name].c_str();
+  auto limit = install_time_limit(*opts);
 
-  if( opts[options::help] ) {
-    printUsage(opts, true);
+  if (opts->driver.help)
+  {
+    printUsage(dopts, true);
     exit(1);
-  } else if( opts[options::languageHelp] ) {
-    Options::printLanguageHelp(*opts[options::out]);
+  }
+  else if (opts->base.languageHelp)
+  {
+    main::printLanguageHelp(dopts.out());
     exit(1);
-  } else if( opts[options::version] ) {
-    *opts[options::out] << Configuration::about().c_str() << flush;
+  }
+  else if (opts->driver.version)
+  {
+    dopts.out() << Configuration::about().c_str() << flush;
     exit(0);
   }
 
-  segvSpin = opts[options::segvSpin];
+  segvSpin = opts->driver.segvSpin;
 
   // If in competition mode, set output stream option to flush immediately
-#ifdef CVC4_COMPETITION_MODE
-  *opts[options::out] << unitbuf;
-#endif /* CVC4_COMPETITION_MODE */
+#ifdef CVC5_COMPETITION_MODE
+  dopts.out() << unitbuf;
+#endif /* CVC5_COMPETITION_MODE */
 
   // We only accept one input file
   if(filenames.size() > 1) {
@@ -170,383 +151,160 @@ int runCvc4(int argc, char* argv[], Options& opts) {
   const bool inputFromStdin = filenames.empty() || filenames[0] == "-";
 
   // if we're reading from stdin on a TTY, default to interactive mode
-  if(!opts.wasSetByUser(options::interactive)) {
-    opts.set(options::interactive, inputFromStdin && isatty(fileno(stdin)));
+  if (!opts->driver.interactiveWasSetByUser)
+  {
+    opts->driver.interactive = inputFromStdin && isatty(fileno(stdin));
   }
 
   // Auto-detect input language by filename extension
-  const char* filename = inputFromStdin ? "<stdin>" : filenames[0].c_str();
+  std::string filenameStr("<stdin>");
+  if (!inputFromStdin) {
+    filenameStr = std::move(filenames[0]);
+  }
+  const char* filename = filenameStr.c_str();
 
-  if(opts[options::inputLanguage] == language::input::LANG_AUTO) {
+  if (solver->getOption("input-language") == "LANG_AUTO")
+  {
     if( inputFromStdin ) {
       // We can't do any fancy detection on stdin
-      opts.set(options::inputLanguage, language::input::LANG_CVC4);
+      solver->setOption("input-language", "cvc");
     } else {
-      unsigned len = strlen(filename);
+      size_t len = filenameStr.size();
       if(len >= 5 && !strcmp(".smt2", filename + len - 5)) {
-        opts.set(options::inputLanguage, language::input::LANG_SMTLIB_V2_0);
-      } else if(len >= 4 && !strcmp(".smt", filename + len - 4)) {
-        opts.set(options::inputLanguage, language::input::LANG_SMTLIB_V1);
-      } else if(len >= 5 && !strcmp(".smt1", filename + len - 5)) {
-        opts.set(options::inputLanguage, language::input::LANG_SMTLIB_V1);
+        solver->setOption("input-language", "smt2");
       } else if((len >= 2 && !strcmp(".p", filename + len - 2))
                 || (len >= 5 && !strcmp(".tptp", filename + len - 5))) {
-        opts.set(options::inputLanguage, language::input::LANG_TPTP);
+        solver->setOption("input-language", "tptp");
       } else if(( len >= 4 && !strcmp(".cvc", filename + len - 4) )
                 || ( len >= 5 && !strcmp(".cvc4", filename + len - 5) )) {
-        opts.set(options::inputLanguage, language::input::LANG_CVC4);
+        solver->setOption("input-language", "cvc");
       } else if((len >= 3 && !strcmp(".sy", filename + len - 3))
                 || (len >= 3 && !strcmp(".sl", filename + len - 3))) {
-        opts.set(options::inputLanguage, language::input::LANG_SYGUS);
-        //since there is no sygus output language, set this to SMT lib 2
-        //opts.set(options::outputLanguage, language::output::LANG_SMTLIB_V2_0);
+        // version 2 sygus is the default
+        solver->setOption("input-language", "sygus2");
       }
     }
   }
 
-  if(opts[options::outputLanguage] == language::output::LANG_AUTO) {
-    opts.set(options::outputLanguage, language::toOutputLanguage(opts[options::inputLanguage]));
-  }
-
-  // if doing sygus, turn on CEGQI by default
-  if(opts[options::inputLanguage] == language::input::LANG_SYGUS ){
-    if( !opts.wasSetByUser(options::ceGuidedInst)) {
-      opts.set(options::ceGuidedInst, true);
-    }
-    if( !opts.wasSetByUser(options::dumpSynth)) {
-      opts.set(options::dumpSynth, true);
-    }
+  if (solver->getOption("output-language") == "LANG_AUTO")
+  {
+    solver->setOption("output-language", solver->getOption("input-language"));
   }
+  pExecutor->storeOptionsAsOriginal();
 
   // Determine which messages to show based on smtcomp_mode and verbosity
   if(Configuration::isMuzzledBuild()) {
-    DebugChannel.setStream(CVC4::null_os);
-    TraceChannel.setStream(CVC4::null_os);
-    NoticeChannel.setStream(CVC4::null_os);
-    ChatChannel.setStream(CVC4::null_os);
-    MessageChannel.setStream(CVC4::null_os);
-    WarningChannel.setStream(CVC4::null_os);
-  }
-
-  // important even for muzzled builds (to get result output right)
-  *opts[options::out] << Expr::setlanguage(opts[options::outputLanguage]);
-
-  // Create the expression manager using appropriate options
-  ExprManager* exprMgr;
-# ifndef PORTFOLIO_BUILD
-  exprMgr = new ExprManager(opts);
-  pExecutor = new CommandExecutor(*exprMgr, opts);
-# else
-  vector<Options> threadOpts = parseThreadSpecificOptions(opts);
-  bool useParallelExecutor = true;
-  // incremental?
-  if(opts.wasSetByUser(options::incrementalSolving) &&
-     opts[options::incrementalSolving] &&
-     !opts[options::incrementalParallel]) {
-    Notice() << "Notice: In --incremental mode, using the sequential solver unless forced by...\n"
-             << "Notice: ...the experimental --incremental-parallel option.\n";
-    useParallelExecutor = false;
-  }
-  // proofs?
-  if(opts[options::checkProofs]) {
-    if(opts[options::fallbackSequential]) {
-      Warning() << "Warning: Falling back to sequential mode, as cannot run portfolio in check-proofs mode.\n";
-      useParallelExecutor = false;
-    }
-    else {
-      throw OptionException("Cannot run portfolio in check-proofs mode.");
-    }
-  }
-  // pick appropriate one
-  if(useParallelExecutor) {
-    exprMgr = new ExprManager(threadOpts[0]);
-    pExecutor = new CommandExecutorPortfolio(*exprMgr, opts, threadOpts);
-  } else {
-    exprMgr = new ExprManager(opts);
-    pExecutor = new CommandExecutor(*exprMgr, opts);
-  }
-# endif
-
-  Parser* replayParser = NULL;
-  if( opts[options::replayFilename] != "" ) {
-    ParserBuilder replayParserBuilder(exprMgr, opts[options::replayFilename], opts);
-
-    if( opts[options::replayFilename] == "-") {
-      if( inputFromStdin ) {
-        throw OptionException("Replay file and input file can't both be stdin.");
-      }
-      replayParserBuilder.withStreamInput(cin);
-    }
-    replayParser = replayParserBuilder.build();
-    opts.set(options::replayStream, new Parser::ExprStream(replayParser));
-  }
-  if( opts[options::replayLog] != NULL ) {
-    *opts[options::replayLog] << Expr::setlanguage(opts[options::outputLanguage]) << Expr::setdepth(-1);
+    DebugChannel.setStream(&cvc5::null_os);
+    TraceChannel.setStream(&cvc5::null_os);
+    NoticeChannel.setStream(&cvc5::null_os);
+    ChatChannel.setStream(&cvc5::null_os);
+    MessageChannel.setStream(&cvc5::null_os);
+    WarningChannel.setStream(&cvc5::null_os);
   }
 
   int returnValue = 0;
   {
-    // Timer statistic
-    RegisterStatistic statTotalTime(&pExecutor->getStatisticsRegistry(), pTotalTime);
-
-    // Filename statistics
-    ReferenceStat< const char* > s_statFilename("filename", filename);
-    RegisterStatistic statFilenameReg(&pExecutor->getStatisticsRegistry(), &s_statFilename);
+    // notify SmtEngine that we are starting to parse
+    pExecutor->getSmtEngine()->notifyStartParsing(filenameStr);
 
     // Parse and execute commands until we are done
-    Command* cmd;
+    std::unique_ptr<Command> cmd;
     bool status = true;
-    if(opts[options::interactive] && inputFromStdin) {
-      if(opts[options::tearDownIncremental]) {
-        throw OptionException("--tear-down-incremental doesn't work in interactive mode");
-      }
-#ifndef PORTFOLIO_BUILD
-      if(!opts.wasSetByUser(options::incrementalSolving)) {
-        cmd = new SetOptionCommand("incremental", true);
+    if (opts->driver.interactive && inputFromStdin)
+    {
+      if (!opts->base.incrementalSolvingWasSetByUser)
+      {
+        cmd.reset(new SetOptionCommand("incremental", "true"));
         cmd->setMuted(true);
         pExecutor->doCommand(cmd);
-        delete cmd;
       }
-#endif /* PORTFOLIO_BUILD */
-      InteractiveShell shell(*exprMgr, opts);
-      if(opts[options::interactivePrompt]) {
-        Message() << Configuration::getPackageName()
-                  << " " << Configuration::getVersionString();
-        if(Configuration::isGitBuild()) {
-          Message() << " [" << Configuration::getGitId() << "]";
-        } else if(Configuration::isSubversionBuild()) {
-          Message() << " [" << Configuration::getSubversionId() << "]";
-        }
-        Message() << (Configuration::isDebugBuild() ? " DEBUG" : "")
-                  << " assertions:"
-                  << (Configuration::isAssertionBuild() ? "on" : "off")
-                  << endl;
-      }
-      if(replayParser != NULL) {
-        // have the replay parser use the declarations input interactively
-        replayParser->useDeclarationsFrom(shell.getParser());
+      InteractiveShell shell(pExecutor->getSolver(),
+                             pExecutor->getSymbolManager());
+
+      CVC5Message() << Configuration::getPackageName() << " "
+                    << Configuration::getVersionString();
+      if (Configuration::isGitBuild())
+      {
+        CVC5Message() << " [" << Configuration::getGitId() << "]";
       }
+      CVC5Message() << (Configuration::isDebugBuild() ? " DEBUG" : "")
+                    << " assertions:"
+                    << (Configuration::isAssertionBuild() ? "on" : "off")
+                    << endl
+                    << endl;
+      CVC5Message() << Configuration::copyright() << endl;
 
       while(true) {
         try {
-          cmd = shell.readCommand();
+          cmd.reset(shell.readCommand());
         } catch(UnsafeInterruptException& e) {
-          *opts[options::out] << CommandInterrupted();
+          dopts.out() << CommandInterrupted();
           break;
         }
-        if (cmd == NULL)
+        if (cmd == nullptr)
           break;
         status = pExecutor->doCommand(cmd) && status;
+        opts = &pExecutor->getOptions();
         if (cmd->interrupted()) {
-          delete cmd;
           break;
         }
-        delete cmd;
       }
-    } else if(opts[options::tearDownIncremental]) {
-      if(opts[options::incrementalSolving]) {
-        if(opts.wasSetByUser(options::incrementalSolving)) {
-          throw OptionException("--tear-down-incremental incompatible with --incremental");
-        }
-
-        cmd = new SetOptionCommand("incremental", false);
+    }
+    else
+    {
+      if (!opts->base.incrementalSolvingWasSetByUser)
+      {
+        cmd.reset(new SetOptionCommand("incremental", "false"));
         cmd->setMuted(true);
         pExecutor->doCommand(cmd);
-        delete cmd;
       }
 
-      ParserBuilder parserBuilder(exprMgr, filename, opts);
-
+      ParserBuilder parserBuilder(
+          pExecutor->getSolver(), pExecutor->getSymbolManager(), true);
+      std::unique_ptr<Parser> parser(parserBuilder.build());
       if( inputFromStdin ) {
-#if defined(CVC4_COMPETITION_MODE) && !defined(CVC4_SMTCOMP_APPLICATION_TRACK)
-        parserBuilder.withStreamInput(cin);
-#else /* CVC4_COMPETITION_MODE && !CVC4_SMTCOMP_APPLICATION_TRACK */
-        parserBuilder.withLineBufferedStreamInput(cin);
-#endif /* CVC4_COMPETITION_MODE && !CVC4_SMTCOMP_APPLICATION_TRACK */
+        parser->setInput(Input::newStreamInput(
+            solver->getOption("input-language"), cin, filename));
       }
-
-      vector< vector<Command*> > allCommands;
-      allCommands.push_back(vector<Command*>());
-      Parser *parser = parserBuilder.build();
-      if(replayParser != NULL) {
-        // have the replay parser use the file's declarations
-        replayParser->useDeclarationsFrom(parser);
+      else
+      {
+        parser->setInput(
+            Input::newFileInput(solver->getOption("input-language"),
+                                filename,
+                                solver->getOption("mmap") == "true"));
       }
-      bool needReset = false;
-      // true if one of the commands was interrupted
-      bool interrupted = false;
-      while (status || opts[options::continuedExecution]) {
-        if (interrupted) {
-          *opts[options::out] << CommandInterrupted();
-          break;
-        }
 
-        try {
-          cmd = parser->nextCommand();
-          if (cmd == NULL) break;
-        } catch (UnsafeInterruptException& e) {
-          interrupted = true;
-          continue;
-        }
-
-        if(dynamic_cast<PushCommand*>(cmd) != NULL) {
-          if(needReset) {
-            pExecutor->reset();
-            for(size_t i = 0; i < allCommands.size() && !interrupted; ++i) {
-              if (interrupted) break;
-              for(size_t j = 0; j < allCommands[i].size() && !interrupted; ++j) {
-                Command* cmd = allCommands[i][j]->clone();
-                cmd->setMuted(true);
-                pExecutor->doCommand(cmd);
-                if(cmd->interrupted()) {
-                  interrupted = true;
-                }
-                delete cmd;
-              }
-            }
-            needReset = false;
-          }
-          *opts[options::out] << CommandSuccess();
-          allCommands.push_back(vector<Command*>());
-        } else if(dynamic_cast<PopCommand*>(cmd) != NULL) {
-          allCommands.pop_back(); // fixme leaks cmds here
-          pExecutor->reset();
-          for(size_t i = 0; i < allCommands.size() && !interrupted; ++i) {
-            for(size_t j = 0; j < allCommands[i].size() && !interrupted; ++j) {
-              Command* cmd = allCommands[i][j]->clone();
-              cmd->setMuted(true);
-              pExecutor->doCommand(cmd);
-              if(cmd->interrupted()) {
-                interrupted = true;
-              }
-              delete cmd;
-            }
-          }
-          if (interrupted) continue;
-          *opts[options::out] << CommandSuccess();
-        } else if(dynamic_cast<CheckSatCommand*>(cmd) != NULL ||
-                  dynamic_cast<QueryCommand*>(cmd) != NULL) {
-          if(needReset) {
-            pExecutor->reset();
-            for(size_t i = 0; i < allCommands.size() && !interrupted; ++i) {
-              for(size_t j = 0; j < allCommands[i].size() && !interrupted; ++j) {
-                Command* cmd = allCommands[i][j]->clone();
-                cmd->setMuted(true);
-                pExecutor->doCommand(cmd);
-                if(cmd->interrupted()) {
-                  interrupted = true;
-                }
-                delete cmd;
-              }
-            }
-          }
-          if (interrupted) {
-            continue;
-          }
-
-          status = pExecutor->doCommand(cmd);
-          if(cmd->interrupted()) {
-            interrupted = true;
-            continue;
-          }
-          needReset = true;
-        } else if(dynamic_cast<ResetCommand*>(cmd) != NULL) {
-          pExecutor->doCommand(cmd);
-          allCommands.clear();
-          allCommands.push_back(vector<Command*>());
-        } else {
-          // We shouldn't copy certain commands, because they can cause
-          // an error on replay since there's no associated sat/unsat check
-          // preceding them.
-          if(dynamic_cast<GetUnsatCoreCommand*>(cmd) == NULL &&
-             dynamic_cast<GetProofCommand*>(cmd) == NULL &&
-             dynamic_cast<GetValueCommand*>(cmd) == NULL &&
-             dynamic_cast<GetModelCommand*>(cmd) == NULL &&
-             dynamic_cast<GetAssignmentCommand*>(cmd) == NULL &&
-             dynamic_cast<GetInstantiationsCommand*>(cmd) == NULL &&
-             dynamic_cast<GetAssertionsCommand*>(cmd) == NULL &&
-             dynamic_cast<GetInfoCommand*>(cmd) == NULL &&
-             dynamic_cast<GetOptionCommand*>(cmd) == NULL &&
-             dynamic_cast<EchoCommand*>(cmd) == NULL) {
-            Command* copy = cmd->clone();
-            allCommands.back().push_back(copy);
-          }
-          status = pExecutor->doCommand(cmd);
-          if(cmd->interrupted()) {
-            interrupted = true;
-            continue;
-          }
-
-          if(dynamic_cast<QuitCommand*>(cmd) != NULL) {
-            delete cmd;
-            break;
-          }
-        }
-        delete cmd;
-      }
-      // Remove the parser
-      delete parser;
-    } else {
-      if(!opts.wasSetByUser(options::incrementalSolving)) {
-        cmd = new SetOptionCommand("incremental", false);
-        cmd->setMuted(true);
-        pExecutor->doCommand(cmd);
-        delete cmd;
-      }
-
-      ParserBuilder parserBuilder(exprMgr, filename, opts);
-
-      if( inputFromStdin ) {
-#if defined(CVC4_COMPETITION_MODE) && !defined(CVC4_SMTCOMP_APPLICATION_TRACK)
-        parserBuilder.withStreamInput(cin);
-#else /* CVC4_COMPETITION_MODE && !CVC4_SMTCOMP_APPLICATION_TRACK */
-        parserBuilder.withLineBufferedStreamInput(cin);
-#endif /* CVC4_COMPETITION_MODE && !CVC4_SMTCOMP_APPLICATION_TRACK */
-      }
-
-      Parser *parser = parserBuilder.build();
-      if(replayParser != NULL) {
-        // have the replay parser use the file's declarations
-        replayParser->useDeclarationsFrom(parser);
-      }
       bool interrupted = false;
-      while(status || opts[options::continuedExecution]) {
+      while (status)
+      {
         if (interrupted) {
-          *opts[options::out] << CommandInterrupted();
+          dopts.out() << CommandInterrupted();
           pExecutor->reset();
+          opts = &pExecutor->getOptions();
           break;
         }
         try {
-          cmd = parser->nextCommand();
-          if (cmd == NULL) break;
+          cmd.reset(parser->nextCommand());
+          if (cmd == nullptr) break;
         } catch (UnsafeInterruptException& e) {
           interrupted = true;
           continue;
         }
 
         status = pExecutor->doCommand(cmd);
+        opts = &pExecutor->getOptions();
         if (cmd->interrupted() && status == 0) {
           interrupted = true;
           break;
         }
 
-        if(dynamic_cast<QuitCommand*>(cmd) != NULL) {
-          delete cmd;
+        if(dynamic_cast<QuitCommand*>(cmd.get()) != nullptr) {
           break;
         }
-        delete cmd;
       }
-      // Remove the parser
-      delete parser;
-    }
-
-    if( opts[options::replayStream] != NULL ) {
-      // this deletes the expression parser too
-      delete opts[options::replayStream];
-      opts.set(options::replayStream, NULL);
     }
 
-    Result result;
+    api::Result result;
     if(status) {
       result = pExecutor->getResult();
       returnValue = 0;
@@ -555,61 +313,33 @@ int runCvc4(int argc, char* argv[], Options& opts) {
       returnValue = 1;
     }
 
-#ifdef CVC4_COMPETITION_MODE
-    *opts[options::out] << flush;
+#ifdef CVC5_COMPETITION_MODE
+    dopts.out() << std::flush;
     // exit, don't return (don't want destructors to run)
     // _exit() from unistd.h doesn't run global destructors
     // or other on_exit/atexit stuff.
     _exit(returnValue);
-#endif /* CVC4_COMPETITION_MODE */
-
-    ReferenceStat< Result > s_statSatResult("sat/unsat", result);
-    RegisterStatistic statSatResultReg(&pExecutor->getStatisticsRegistry(), &s_statSatResult);
-
-    pTotalTime->stop();
-
-    // Set the global executor pointer to NULL first.  If we get a
-    // signal while dumping statistics, we don't want to try again.
-    if(opts[options::statistics]) {
-      if(opts[options::statsHideZeros] == false) {
-        pExecutor->flushStatistics(*opts[options::err]);
-      } else {
-        std::ostringstream ossStats;
-        pExecutor->flushStatistics(ossStats);
-        printStatsFilterZeros(*opts[options::err], ossStats.str());
-      }
-    }
+#endif /* CVC5_COMPETITION_MODE */
 
-    // make sure to flush replay output log before early-exit
-    if( opts[options::replayLog] != NULL ) {
-      *opts[options::replayLog] << flush;
-    }
-
-    // make sure out and err streams are flushed too
-    *opts[options::out] << flush;
-    *opts[options::err] << flush;
+    totalTime.reset();
+    pExecutor->flushOutputStreams();
 
-#ifdef CVC4_DEBUG
-    if(opts[options::earlyExit] && opts.wasSetByUser(options::earlyExit)) {
+#ifdef CVC5_DEBUG
+    if (opts->driver.earlyExit && opts->driver.earlyExitWasSetByUser)
+    {
       _exit(returnValue);
     }
-#else /* CVC4_DEBUG */
-    if(opts[options::earlyExit]) {
+#else  /* CVC5_DEBUG */
+    if (opts->driver.earlyExit)
+    {
       _exit(returnValue);
     }
-#endif /* CVC4_DEBUG */
+#endif /* CVC5_DEBUG */
   }
 
-  // On exceptional exit, these are leaked, but that's okay... they
-  // need to be around in that case for main() to print statistics.
-  delete pTotalTime;
-  delete pExecutor;
-  delete exprMgr;
-
-  pTotalTime = NULL;
-  pExecutor = NULL;
+  pExecutor.reset();
 
-  cvc4_shutdown();
+  signal_handlers::cleanup();
 
   return returnValue;
 }