LCOV - code coverage report
Current view: top level - buildbot/coverage/build/src/main - driver_unified.cpp (source / functions) Hit Total Coverage
Test: coverage.info Lines: 57 88 64.8 %
Date: 2026-02-03 13:01:51 Functions: 1 1 100.0 %
Branches: 36 70 51.4 %

           Branch data     Line data    Source code
       1                 :            : /******************************************************************************
       2                 :            :  * Top contributors (to current version):
       3                 :            :  *   Andrew Reynolds, Gereon Kremer, Morgan Deters
       4                 :            :  *
       5                 :            :  * This file is part of the cvc5 project.
       6                 :            :  *
       7                 :            :  * Copyright (c) 2009-2025 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                 :            :  * Driver for cvc5 executable (cvc5).
      14                 :            :  */
      15                 :            : 
      16                 :            : #include <cvc5/cvc5.h>
      17                 :            : #include <cvc5/cvc5_parser.h>
      18                 :            : #include <stdio.h>
      19                 :            : #include <unistd.h>
      20                 :            : 
      21                 :            : #include <cstdlib>
      22                 :            : #include <cstring>
      23                 :            : #include <fstream>
      24                 :            : #include <iostream>
      25                 :            : #include <memory>
      26                 :            : #include <new>
      27                 :            : #include <optional>
      28                 :            : 
      29                 :            : #include "base/configuration.h"
      30                 :            : #include "base/cvc5config.h"
      31                 :            : #include "base/output.h"
      32                 :            : #include "main/command_executor.h"
      33                 :            : #include "main/interactive_shell.h"
      34                 :            : #include "main/main.h"
      35                 :            : #include "main/options.h"
      36                 :            : #include "main/portfolio_driver.h"
      37                 :            : #include "main/signal_handlers.h"
      38                 :            : #include "main/time_limit.h"
      39                 :            : #include "smt/solver_engine.h"
      40                 :            : #include "util/result.h"
      41                 :            : 
      42                 :            : using namespace std;
      43                 :            : using namespace cvc5::internal;
      44                 :            : using namespace cvc5::parser;
      45                 :            : using namespace cvc5::main;
      46                 :            : 
      47                 :            : namespace cvc5::main {
      48                 :            : 
      49                 :            : /** Full argv[0] */
      50                 :            : const char* progPath;
      51                 :            : 
      52                 :            : /** Just the basename component of argv[0] */
      53                 :            : std::string progName;
      54                 :            : 
      55                 :            : /** A pointer to the CommandExecutor (the signal handlers need it) */
      56                 :            : std::unique_ptr<CommandExecutor> pExecutor;
      57                 :            : 
      58                 :            : }  // namespace cvc5::main
      59                 :            : 
      60                 :      27848 : int runCvc5(int argc, char* argv[], std::unique_ptr<cvc5::Solver>& solver)
      61                 :            : {
      62                 :            :   // Initialize the signal handlers
      63                 :      27848 :   signal_handlers::install();
      64                 :            : 
      65                 :      27848 :   progPath = argv[0];
      66                 :            : 
      67                 :            :   // Create the command executor to execute the parsed commands
      68                 :      27848 :   pExecutor = std::make_unique<CommandExecutor>(solver);
      69                 :      27848 :   cvc5::DriverOptions dopts = solver->getDriverOptions();
      70                 :            : 
      71                 :            :   // Parse the options
      72                 :      51544 :   std::vector<string> filenames = parse(*solver, argc, argv, progName);
      73         [ +  + ]:      27843 :   if (solver->getOptionInfo("help").boolValue())
      74                 :            :   {
      75                 :          1 :     printUsage(progName, dopts.out());
      76                 :          1 :     exit(1);
      77                 :            :   }
      78         [ -  + ]:      27842 :   else if (solver->getOptionInfo("help-regular").boolValue())
      79                 :            :   {
      80                 :          0 :     printUsage(progName, dopts.out(), true);
      81                 :          0 :     exit(1);
      82                 :            :   }
      83         [ -  + ]:      27842 :   else if (solver->getOptionInfo("help-option-categories").boolValue())
      84                 :            :   {
      85                 :          0 :     printUsageCategories(*solver.get(), dopts.out());
      86                 :          0 :     exit(1);
      87                 :            :   }
      88                 :      94793 :   for (const auto& name : {"show-config",
      89                 :            :                            "copyright",
      90                 :            :                            "show-trace-tags",
      91         [ +  + ]:     122635 :                            "version"})
      92                 :            :   {
      93         [ +  + ]:      98939 :     if (solver->getOptionInfo(name).boolValue())
      94                 :            :     {
      95                 :       4146 :       std::exit(0);
      96                 :            :     }
      97                 :            :   }
      98                 :            : 
      99                 :      71088 :   auto limit = install_time_limit(solver->getOptionInfo("tlimit").uintValue());
     100                 :      23696 :   segvSpin = solver->getOptionInfo("segv-spin").boolValue();
     101                 :            : 
     102                 :            :   // If in competition mode, set output stream option to flush immediately
     103                 :            : #ifdef CVC5_COMPETITION_MODE
     104                 :            :   dopts.out() << unitbuf;
     105                 :            : #endif /* CVC5_COMPETITION_MODE */
     106                 :            : 
     107                 :            :   // We only accept one input file
     108         [ -  + ]:      23696 :   if(filenames.size() > 1) {
     109                 :          0 :     throw Exception("Too many input files specified.");
     110                 :            :   }
     111                 :            : 
     112                 :            :   // If no file supplied we will read from standard input
     113 [ +  - ][ -  + ]:      23696 :   const bool inputFromStdin = filenames.empty() || filenames[0] == "-";
     114                 :            : 
     115                 :            :   // If we're reading from stdin, use interactive mode if we are a TTY.
     116         [ +  - ]:      23696 :   if (!solver->getOptionInfo("interactive").setByUser)
     117                 :            :   {
     118         [ -  + ]:      23696 :     pExecutor->setOptionInternal(
     119                 :            :         "interactive",
     120         [ -  - ]:          0 :         (inputFromStdin && isatty(fileno(stdin))) ? "true"  : "false");
     121                 :            :   }
     122                 :            : 
     123                 :            :   // Auto-detect input language by filename extension
     124                 :      23756 :   std::string filenameStr("<stdin>");
     125         [ +  - ]:      23696 :   if (!inputFromStdin) {
     126                 :      23696 :     filenameStr = std::move(filenames[0]);
     127                 :            :   }
     128                 :      23696 :   const char* filename = filenameStr.c_str();
     129                 :            :   cvc5::modes::InputLanguage ilang;
     130         [ +  + ]:      23696 :   if (solver->getOption("input-language") == "LANG_AUTO")
     131                 :            :   {
     132         [ -  + ]:      18891 :     if( inputFromStdin ) {
     133                 :            :       // We can't do any fancy detection on stdin
     134                 :          0 :       pExecutor->setOptionInternal("input-language", "smt2");
     135                 :            :     } else {
     136                 :      18891 :       size_t len = filenameStr.size();
     137 [ +  - ][ +  + ]:      18891 :       if(len >= 5 && !strcmp(".smt2", filename + len - 5)) {
     138                 :      18712 :         pExecutor->setOptionInternal("input-language", "smt2");
     139 [ +  - ][ -  + ]:        179 :       } else if((len >= 3 && !strcmp(".sy", filename + len - 3))
     140 [ -  - ][ -  - ]:          0 :                 || (len >= 3 && !strcmp(".sl", filename + len - 3))) {
     141                 :            :         // version 2 sygus is the default
     142                 :        179 :         pExecutor->setOptionInternal("input-language", "sygus2");
     143                 :            :       }
     144                 :            :     }
     145                 :            :   }
     146         [ +  + ]:      23696 :   if (solver->getOption("input-language") == "LANG_SYGUS_V2")
     147                 :            :   {
     148                 :            :     // Enable the sygus API. We set this here instead of in set defaults 
     149                 :            :     // to simplify checking at the API level. In particular, the sygus
     150                 :            :     // option is the authority on whether sygus commands are currently
     151                 :            :     // allowed in the API.
     152                 :        962 :     pExecutor->setOptionInternal("sygus", "true");
     153                 :        962 :     ilang = cvc5::modes::InputLanguage::SYGUS_2_1;
     154                 :            :   }
     155                 :            :   else
     156                 :            :   {
     157                 :      22734 :     ilang = cvc5::modes::InputLanguage::SMT_LIB_2_6;
     158                 :            :   }
     159                 :            : 
     160         [ -  + ]:      23696 :   if (solver->getOption("output-language") == "LANG_AUTO")
     161                 :            :   {
     162                 :          0 :     pExecutor->setOptionInternal("output-language",
     163                 :          0 :                                  solver->getOption("input-language"));
     164                 :            :   }
     165                 :            : 
     166                 :            :   // Determine which messages to show based on smtcomp_mode and verbosity
     167         [ -  + ]:      23696 :   if(Configuration::isMuzzledBuild()) {
     168                 :          0 :     TraceChannel.setStream(&cvc5::internal::null_os);
     169                 :          0 :     WarningChannel.setStream(&cvc5::internal::null_os);
     170                 :            :   }
     171                 :            : 
     172                 :      23696 :   int returnValue = 0;
     173                 :            :   {
     174                 :      23696 :     solver->setInfo("filename", filenameStr);
     175                 :            : 
     176                 :            :     // Parse and execute commands until we are done
     177                 :      23696 :     if (solver->getOptionInfo("interactive").boolValue() && inputFromStdin)
     178                 :            :     {
     179                 :            :       // We use the interactive shell when piping from stdin, even some cases
     180                 :            :       // where the input stream is not a TTY. We do this to avoid memory issues
     181                 :            :       // involving tokens that span multiple lines.
     182                 :            :       // We compute whether the interactive shell is actually interactive
     183                 :            :       // (via isatty). If we are not interactive, we disable certain output
     184                 :            :       // information, e.g. for querying the user.
     185                 :          0 :       bool isInteractive = isatty(fileno(stdin));
     186                 :            :       // set incremental if we are in interactive mode
     187         [ -  - ]:          0 :       if (!solver->getOptionInfo("incremental").setByUser)
     188                 :            :       {
     189         [ -  - ]:          0 :         pExecutor->setOptionInternal("incremental",
     190                 :            :                                      isInteractive ? "true" : "false");
     191                 :            :       }
     192                 :            :       // now store options as original
     193                 :          0 :       pExecutor->storeOptionsAsOriginal();
     194                 :            :       InteractiveShell shell(
     195                 :          0 :           pExecutor.get(), dopts.in(), dopts.out(), isInteractive);
     196                 :            : 
     197         [ -  - ]:          0 :       if (isInteractive)
     198                 :            :       {
     199                 :          0 :         auto& out = solver->getDriverOptions().out();
     200                 :          0 :         out << Configuration::getPackageName() << " "
     201                 :          0 :             << Configuration::getVersionString();
     202         [ -  - ]:          0 :         if (Configuration::isGitBuild())
     203                 :            :         {
     204                 :          0 :           out << " [" << Configuration::getGitInfo() << "]";
     205                 :            :         }
     206                 :          0 :         out << (Configuration::isDebugBuild() ? " DEBUG" : "") << " assertions:"
     207                 :          0 :             << (Configuration::isAssertionBuild() ? "on" : "off") << std::endl
     208                 :          0 :             << std::endl
     209                 :          0 :             << Configuration::copyright() << std::endl;
     210                 :            :       }
     211                 :            : 
     212                 :            :       while (true)
     213                 :            :       {
     214                 :            :         // read and execute all available commands
     215         [ -  - ]:          0 :         if (!shell.readAndExecCommands())
     216                 :            :         {
     217                 :          0 :           break;
     218                 :            :         }
     219                 :            :       }
     220                 :            :     }
     221                 :            :     else
     222                 :            :     {
     223         [ +  + ]:      23696 :       if (!solver->getOptionInfo("incremental").setByUser)
     224                 :            :       {
     225                 :      22301 :         pExecutor->setOptionInternal("incremental", "false");
     226                 :            :       }
     227                 :            :       // we don't need to check that terms passed to API methods are well
     228                 :            :       // formed, since this should be an invariant of the parser
     229         [ +  - ]:      23696 :       if (!solver->getOptionInfo("wf-checking").setByUser)
     230                 :            :       {
     231                 :      23696 :         pExecutor->setOptionInternal("wf-checking", "false");
     232                 :            :       }
     233                 :            :       // now store options as original
     234                 :      23696 :       pExecutor->storeOptionsAsOriginal();
     235                 :            : 
     236                 :            :       std::unique_ptr<InputParser> parser(new InputParser(
     237                 :      23756 :           pExecutor->getSolver(), pExecutor->getSymbolManager()));
     238         [ -  + ]:      23696 :       if( inputFromStdin ) {
     239                 :          0 :         parser->setStreamInput(ilang, cin, filename);
     240                 :            :       }
     241                 :            :       else
     242                 :            :       {
     243                 :      23696 :         parser->setFileInput(ilang, filename);
     244                 :            :       }
     245                 :            : 
     246                 :      23696 :       PortfolioDriver driver(parser);
     247         [ +  + ]:      23696 :       returnValue = driver.solve(pExecutor) ? 0 : 1;
     248                 :            :     }
     249                 :            : 
     250                 :            : #ifdef CVC5_COMPETITION_MODE
     251                 :            :     dopts.out() << std::flush;
     252                 :            :     // exit, don't return (don't want destructors to run)
     253                 :            :     // _exit() from unistd.h doesn't run global destructors
     254                 :            :     // or other on_exit/atexit stuff.
     255                 :            :     _exit(returnValue);
     256                 :            : #endif /* CVC5_COMPETITION_MODE */
     257                 :            : 
     258                 :      23636 :     pExecutor->flushOutputStreams();
     259                 :            : 
     260                 :            : #ifdef CVC5_DEBUG
     261                 :            :     {
     262                 :      70908 :       auto info = solver->getOptionInfo("early-exit");
     263 [ +  + ][ -  + ]:      23636 :       if (info.boolValue() && info.setByUser)
                 [ -  + ]
     264                 :            :       {
     265                 :          0 :         _exit(returnValue);
     266                 :            :       }
     267                 :            :     }
     268                 :            : #else  /* CVC5_DEBUG */
     269                 :            :     if (solver->getOptionInfo("early-exit").boolValue())
     270                 :            :     {
     271                 :            :       _exit(returnValue);
     272                 :            :     }
     273                 :            : #endif /* CVC5_DEBUG */
     274                 :            :   }
     275                 :            : 
     276                 :      23636 :   pExecutor.reset();
     277                 :            : 
     278                 :      23636 :   signal_handlers::cleanup();
     279                 :            : 
     280                 :      47272 :   return returnValue;
     281                 :            : }

Generated by: LCOV version 1.14