Add Driver options (#7078)
[cvc5.git] / src / main / driver_unified.cpp
index 2481eda1072b8a8ac13335a387df34c6b76bf61b..005de6a34044e80e6bf6b6744b36e12094800ddf 100644 (file)
@@ -10,7 +10,7 @@
  * directory for licensing information.
  * ****************************************************************************
  *
- * Driver for cvc5 executable (cvc4).
+ * Driver for cvc5 executable (cvc5).
  */
 
 #include <stdio.h>
 
 #include "api/cpp/cvc5.h"
 #include "base/configuration.h"
+#include "base/cvc5config.h"
 #include "base/output.h"
-#include "cvc4autoconfig.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"
@@ -48,14 +54,12 @@ using namespace cvc5::main;
 
 namespace cvc5 {
 namespace main {
-/** Global options variable */
-thread_local Options* pOptions;
 
 /** Full argv[0] */
 const char* progPath;
 
 /** Just the basename component of argv[0] */
-const std::string* progName;
+std::string progName;
 
 /** A pointer to the CommandExecutor (the signal handlers need it) */
 std::unique_ptr<cvc5::main::CommandExecutor> pExecutor;
@@ -76,55 +80,66 @@ TotalTimer::~TotalTimer()
     }  // namespace main
     }  // namespace cvc5
 
-void printUsage(Options& opts, bool full) {
-  stringstream ss;
-  ss << "usage: " << opts.getBinaryName() << " [options] [input-file]" << endl
-     << endl
-     << "Without an input file, or with `-', cvc5 reads from standard input."
-     << endl
-     << endl
-     << "cvc5 options:" << endl;
-  if(full) {
-    Options::printUsage( ss.str(), *(opts.getOut()) );
-  } else {
-    Options::printShortUsage( ss.str(), *(opts.getOut()) );
-  }
-}
+    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());
+      }
+    }
 
-int runCvc4(int argc, char* argv[], Options& opts) {
+int runCvc5(int argc, char* argv[], std::unique_ptr<api::Solver>& solver)
+{
   main::totalTime = std::make_unique<TotalTimer>();
-  // For the signal handlers' benefit
-  pOptions = &opts;
 
   // Initialize the signal handlers
   signal_handlers::install();
 
   progPath = argv[0];
 
-  // Parse the options
-  vector<string> filenames = Options::parseOptions(&opts, 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();
 
-  auto limit = install_time_limit(opts);
+  // Parse the options
+  std::vector<string> filenames = main::parse(*solver, argc, argv, progName);
 
-  string progNameStr = opts.getBinaryName();
-  progName = &progNameStr;
+  auto limit = install_time_limit(*opts);
 
-  if( opts.getHelp() ) {
-    printUsage(opts, true);
+  if (opts->driver.help)
+  {
+    printUsage(dopts, true);
     exit(1);
-  } else if( opts.getLanguageHelp() ) {
-    Options::printLanguageHelp(*(opts.getOut()));
+  }
+  else if (opts->base.languageHelp)
+  {
+    main::printLanguageHelp(dopts.out());
     exit(1);
-  } else if( opts.getVersion() ) {
-    *(opts.getOut()) << Configuration::about().c_str() << flush;
+  }
+  else if (opts->driver.version)
+  {
+    dopts.out() << Configuration::about().c_str() << flush;
     exit(0);
   }
 
-  segvSpin = opts.getSegvSpin();
+  segvSpin = opts->driver.segvSpin;
 
   // If in competition mode, set output stream option to flush immediately
 #ifdef CVC5_COMPETITION_MODE
-  *(opts.getOut()) << unitbuf;
+  dopts.out() << unitbuf;
 #endif /* CVC5_COMPETITION_MODE */
 
   // We only accept one input file
@@ -136,44 +151,46 @@ 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.wasSetByUserInteractive()) {
-    opts.setInteractive(inputFromStdin && isatty(fileno(stdin)));
+  if (!opts->driver.interactiveWasSetByUser)
+  {
+    opts->driver.interactive = inputFromStdin && isatty(fileno(stdin));
   }
 
   // Auto-detect input language by filename extension
   std::string filenameStr("<stdin>");
   if (!inputFromStdin) {
-    // Use swap to avoid copying the string
-    // TODO: use std::move() when switching to c++11
-    filenameStr.swap(filenames[0]);
+    filenameStr = std::move(filenames[0]);
   }
   const char* filename = filenameStr.c_str();
 
-  if(opts.getInputLanguage() == language::input::LANG_AUTO) {
+  if (solver->getOption("input-language") == "LANG_AUTO")
+  {
     if( inputFromStdin ) {
       // We can't do any fancy detection on stdin
-      opts.setInputLanguage(language::input::LANG_CVC);
+      solver->setOption("input-language", "cvc");
     } else {
-      unsigned len = filenameStr.size();
+      size_t len = filenameStr.size();
       if(len >= 5 && !strcmp(".smt2", filename + len - 5)) {
-        opts.setInputLanguage(language::input::LANG_SMTLIB_V2_6);
+        solver->setOption("input-language", "smt2");
       } else if((len >= 2 && !strcmp(".p", filename + len - 2))
                 || (len >= 5 && !strcmp(".tptp", filename + len - 5))) {
-        opts.setInputLanguage(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.setInputLanguage(language::input::LANG_CVC);
+        solver->setOption("input-language", "cvc");
       } else if((len >= 3 && !strcmp(".sy", filename + len - 3))
                 || (len >= 3 && !strcmp(".sl", filename + len - 3))) {
         // version 2 sygus is the default
-        opts.setInputLanguage(language::input::LANG_SYGUS_V2);
+        solver->setOption("input-language", "sygus2");
       }
     }
   }
 
-  if(opts.getOutputLanguage() == language::output::LANG_AUTO) {
-    opts.setOutputLanguage(language::toOutputLanguage(opts.getInputLanguage()));
+  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()) {
@@ -185,12 +202,6 @@ int runCvc4(int argc, char* argv[], Options& opts) {
     WarningChannel.setStream(&cvc5::null_os);
   }
 
-  // important even for muzzled builds (to get result output right)
-  (*(opts.getOut())) << language::SetLanguage(opts.getOutputLanguage());
-
-  // Create the command executor to execute the parsed commands
-  pExecutor = std::make_unique<CommandExecutor>(opts);
-
   int returnValue = 0;
   {
     // notify SmtEngine that we are starting to parse
@@ -199,239 +210,77 @@ int runCvc4(int argc, char* argv[], Options& opts) {
     // Parse and execute commands until we are done
     std::unique_ptr<Command> cmd;
     bool status = true;
-    if(opts.getInteractive() && inputFromStdin) {
-      if(opts.getTearDownIncremental() > 0) {
-        throw Exception(
-            "--tear-down-incremental doesn't work in interactive mode");
-      }
-      if(!opts.wasSetByUserIncrementalSolving()) {
+    if (opts->driver.interactive && inputFromStdin)
+    {
+      if (!opts->base.incrementalSolvingWasSetByUser)
+      {
         cmd.reset(new SetOptionCommand("incremental", "true"));
         cmd->setMuted(true);
         pExecutor->doCommand(cmd);
       }
       InteractiveShell shell(pExecutor->getSolver(),
                              pExecutor->getSymbolManager());
-      if(opts.getInteractivePrompt()) {
-        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;
+
+      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.reset(shell.readCommand());
         } catch(UnsafeInterruptException& e) {
-          (*opts.getOut()) << CommandInterrupted();
+          dopts.out() << CommandInterrupted();
           break;
         }
         if (cmd == nullptr)
           break;
         status = pExecutor->doCommand(cmd) && status;
+        opts = &pExecutor->getOptions();
         if (cmd->interrupted()) {
           break;
         }
       }
-    } else if( opts.getTearDownIncremental() > 0) {
-      if(!opts.getIncrementalSolving() && opts.getTearDownIncremental() > 1) {
-        // For tear-down-incremental values greater than 1, need incremental
-        // on too.
-        cmd.reset(new SetOptionCommand("incremental", "true"));
-        cmd->setMuted(true);
-        pExecutor->doCommand(cmd);
-        // if(opts.wasSetByUserIncrementalSolving()) {
-        //   throw OptionException(
-        //     "--tear-down-incremental incompatible with --incremental");
-        // }
-
-        // cmd.reset(new SetOptionCommand("incremental", "false"));
-        // cmd->setMuted(true);
-        // pExecutor->doCommand(cmd);
-      }
-
-      ParserBuilder parserBuilder(pExecutor->getSolver(),
-                                  pExecutor->getSymbolManager(),
-                                  filename,
-                                  opts);
-
-      if( inputFromStdin ) {
-#if defined(CVC5_COMPETITION_MODE) && !defined(CVC5_SMTCOMP_APPLICATION_TRACK)
-        parserBuilder.withStreamInput(cin);
-#else  /* CVC5_COMPETITION_MODE && !CVC5_SMTCOMP_APPLICATION_TRACK */
-        parserBuilder.withLineBufferedStreamInput(cin);
-#endif /* CVC5_COMPETITION_MODE && !CVC5_SMTCOMP_APPLICATION_TRACK */
-      }
-
-      vector< vector<Command*> > allCommands;
-      allCommands.push_back(vector<Command*>());
-      std::unique_ptr<Parser> parser(parserBuilder.build());
-      int needReset = 0;
-      // true if one of the commands was interrupted
-      bool interrupted = false;
-      while (status)
+    }
+    else
+    {
+      if (!opts->base.incrementalSolvingWasSetByUser)
       {
-        if (interrupted) {
-          (*opts.getOut()) << CommandInterrupted();
-          break;
-        }
-
-        try {
-          cmd.reset(parser->nextCommand());
-          if (cmd == nullptr) break;
-        } catch (UnsafeInterruptException& e) {
-          interrupted = true;
-          continue;
-        }
-
-        if(dynamic_cast<PushCommand*>(cmd.get()) != nullptr) {
-          if(needReset >= opts.getTearDownIncremental()) {
-            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* ccmd = allCommands[i][j]->clone();
-                ccmd->setMuted(true);
-                pExecutor->doCommand(ccmd);
-                if (ccmd->interrupted())
-                {
-                  interrupted = true;
-                }
-                delete ccmd;
-              }
-            }
-            needReset = 0;
-          }
-          allCommands.push_back(vector<Command*>());
-          Command* copy = cmd->clone();
-          allCommands.back().push_back(copy);
-          status = pExecutor->doCommand(cmd);
-          if(cmd->interrupted()) {
-            interrupted = true;
-            continue;
-          }
-        } else if(dynamic_cast<PopCommand*>(cmd.get()) != nullptr) {
-          allCommands.pop_back(); // fixme leaks cmds here
-          if (needReset >= opts.getTearDownIncremental()) {
-            pExecutor->reset();
-            for(size_t i = 0; i < allCommands.size() && !interrupted; ++i) {
-              for(size_t j = 0; j < allCommands[i].size() && !interrupted; ++j)
-              {
-                std::unique_ptr<Command> ccmd(allCommands[i][j]->clone());
-                ccmd->setMuted(true);
-                pExecutor->doCommand(ccmd);
-                if (ccmd->interrupted())
-                {
-                  interrupted = true;
-                }
-              }
-            }
-            if (interrupted) continue;
-            (*opts.getOut()) << CommandSuccess();
-            needReset = 0;
-          } else {
-            status = pExecutor->doCommand(cmd);
-            if(cmd->interrupted()) {
-              interrupted = true;
-              continue;
-            }
-          }
-        } else if(dynamic_cast<CheckSatCommand*>(cmd.get()) != nullptr ||
-                  dynamic_cast<QueryCommand*>(cmd.get()) != nullptr) {
-          if(needReset >= opts.getTearDownIncremental()) {
-            pExecutor->reset();
-            for(size_t i = 0; i < allCommands.size() && !interrupted; ++i) {
-              for(size_t j = 0; j < allCommands[i].size() && !interrupted; ++j)
-              {
-                Command* ccmd = allCommands[i][j]->clone();
-                ccmd->setMuted(true);
-                pExecutor->doCommand(ccmd);
-                if (ccmd->interrupted())
-                {
-                  interrupted = true;
-                }
-                delete ccmd;
-              }
-            }
-            needReset = 0;
-          } else {
-            ++needReset;
-          }
-          if (interrupted) {
-            continue;
-          }
-
-          status = pExecutor->doCommand(cmd);
-          if(cmd->interrupted()) {
-            interrupted = true;
-            continue;
-          }
-        } else if(dynamic_cast<ResetCommand*>(cmd.get()) != nullptr) {
-          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.get()) == nullptr &&
-             dynamic_cast<GetProofCommand*>(cmd.get()) == nullptr &&
-             dynamic_cast<GetValueCommand*>(cmd.get()) == nullptr &&
-             dynamic_cast<GetModelCommand*>(cmd.get()) == nullptr &&
-             dynamic_cast<GetAssignmentCommand*>(cmd.get()) == nullptr &&
-             dynamic_cast<GetInstantiationsCommand*>(cmd.get()) == nullptr &&
-             dynamic_cast<GetAssertionsCommand*>(cmd.get()) == nullptr &&
-             dynamic_cast<GetInfoCommand*>(cmd.get()) == nullptr &&
-             dynamic_cast<GetOptionCommand*>(cmd.get()) == nullptr &&
-             dynamic_cast<EchoCommand*>(cmd.get()) == nullptr) {
-            Command* copy = cmd->clone();
-            allCommands.back().push_back(copy);
-          }
-          status = pExecutor->doCommand(cmd);
-          if(cmd->interrupted()) {
-            interrupted = true;
-            continue;
-          }
-
-          if(dynamic_cast<QuitCommand*>(cmd.get()) != nullptr) {
-            break;
-          }
-        }
-      }
-    } else {
-      if(!opts.wasSetByUserIncrementalSolving()) {
         cmd.reset(new SetOptionCommand("incremental", "false"));
         cmd->setMuted(true);
         pExecutor->doCommand(cmd);
       }
 
-      ParserBuilder parserBuilder(pExecutor->getSolver(),
-                                  pExecutor->getSymbolManager(),
-                                  filename,
-                                  opts);
-
+      ParserBuilder parserBuilder(
+          pExecutor->getSolver(), pExecutor->getSymbolManager(), true);
+      std::unique_ptr<Parser> parser(parserBuilder.build());
       if( inputFromStdin ) {
-#if defined(CVC5_COMPETITION_MODE) && !defined(CVC5_SMTCOMP_APPLICATION_TRACK)
-        parserBuilder.withStreamInput(cin);
-#else  /* CVC5_COMPETITION_MODE && !CVC5_SMTCOMP_APPLICATION_TRACK */
-        parserBuilder.withLineBufferedStreamInput(cin);
-#endif /* CVC5_COMPETITION_MODE && !CVC5_SMTCOMP_APPLICATION_TRACK */
+        parser->setInput(Input::newStreamInput(
+            solver->getOption("input-language"), cin, filename));
+      }
+      else
+      {
+        parser->setInput(
+            Input::newFileInput(solver->getOption("input-language"),
+                                filename,
+                                solver->getOption("mmap") == "true"));
       }
 
-      std::unique_ptr<Parser> parser(parserBuilder.build());
       bool interrupted = false;
       while (status)
       {
         if (interrupted) {
-          (*opts.getOut()) << CommandInterrupted();
+          dopts.out() << CommandInterrupted();
           pExecutor->reset();
+          opts = &pExecutor->getOptions();
           break;
         }
         try {
@@ -443,6 +292,7 @@ int runCvc4(int argc, char* argv[], Options& opts) {
         }
 
         status = pExecutor->doCommand(cmd);
+        opts = &pExecutor->getOptions();
         if (cmd->interrupted() && status == 0) {
           interrupted = true;
           break;
@@ -464,7 +314,7 @@ int runCvc4(int argc, char* argv[], Options& opts) {
     }
 
 #ifdef CVC5_COMPETITION_MODE
-    opts.flushOut();
+    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.
@@ -475,11 +325,13 @@ int runCvc4(int argc, char* argv[], Options& opts) {
     pExecutor->flushOutputStreams();
 
 #ifdef CVC5_DEBUG
-    if(opts.getEarlyExit() && opts.wasSetByUserEarlyExit()) {
+    if (opts->driver.earlyExit && opts->driver.earlyExitWasSetByUser)
+    {
       _exit(returnValue);
     }
 #else  /* CVC5_DEBUG */
-    if(opts.getEarlyExit()) {
+    if (opts->driver.earlyExit)
+    {
       _exit(returnValue);
     }
 #endif /* CVC5_DEBUG */