GCC Code Coverage Report
Directory: . Exec Total Coverage
File: src/main/driver_unified.cpp Lines: 69 128 53.9 %
Date: 2021-11-05 Branches: 121 416 29.1 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Morgan Deters, Liana Hadarean, Tim King
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
 * Driver for cvc5 executable (cvc5).
14
 */
15
16
#include <stdio.h>
17
#include <unistd.h>
18
19
#include <cstdlib>
20
#include <cstring>
21
#include <fstream>
22
#include <iostream>
23
#include <memory>
24
#include <new>
25
26
#include "api/cpp/cvc5.h"
27
#include "base/configuration.h"
28
#include "base/cvc5config.h"
29
#include "base/output.h"
30
#include "main/command_executor.h"
31
#include "main/interactive_shell.h"
32
#include "main/main.h"
33
#include "main/options.h"
34
#include "main/signal_handlers.h"
35
#include "main/time_limit.h"
36
#include "parser/parser.h"
37
#include "parser/parser_builder.h"
38
#include "smt/command.h"
39
#include "smt/solver_engine.h"
40
#include "util/result.h"
41
42
using namespace std;
43
using namespace cvc5;
44
using namespace cvc5::parser;
45
using namespace cvc5::main;
46
47
namespace cvc5 {
48
namespace main {
49
50
/** Full argv[0] */
51
const char* progPath;
52
53
/** Just the basename component of argv[0] */
54
10366
std::string progName;
55
56
/** A pointer to the CommandExecutor (the signal handlers need it) */
57
10366
std::unique_ptr<cvc5::main::CommandExecutor> pExecutor;
58
59
}  // namespace main
60
}  // namespace cvc5
61
62
    void printUsage(const api::DriverOptions& dopts, bool full)
63
    {
64
      std::stringstream ss;
65
      ss << "usage: " << progName << " [options] [input-file]" << std::endl
66
         << std::endl
67
         << "Without an input file, or with `-', cvc5 reads from standard "
68
            "input."
69
         << std::endl
70
         << std::endl
71
         << "cvc5 options:" << std::endl;
72
      if (full)
73
      {
74
        main::printUsage(ss.str(), dopts.out());
75
      }
76
      else
77
      {
78
        main::printShortUsage(ss.str(), dopts.out());
79
      }
80
    }
81
82
9308
int runCvc5(int argc, char* argv[], std::unique_ptr<api::Solver>& solver)
83
{
84
  // Initialize the signal handlers
85
9308
  signal_handlers::install();
86
87
9308
  progPath = argv[0];
88
89
  // Create the command executor to execute the parsed commands
90
9308
  pExecutor = std::make_unique<CommandExecutor>(solver);
91
9308
  api::DriverOptions dopts = solver->getDriverOptions();
92
93
  // Parse the options
94
15889
  std::vector<string> filenames = main::parse(*solver, argc, argv, progName);
95
96
13162
  auto limit = install_time_limit(solver->getOptionInfo("tlimit").uintValue());
97
98
6581
  if (solver->getOptionInfo("help").boolValue())
99
  {
100
    printUsage(dopts, true);
101
    exit(1);
102
  }
103
104
6581
  segvSpin = solver->getOptionInfo("segv-spin").boolValue();
105
106
  // If in competition mode, set output stream option to flush immediately
107
#ifdef CVC5_COMPETITION_MODE
108
  dopts.out() << unitbuf;
109
#endif /* CVC5_COMPETITION_MODE */
110
111
  // We only accept one input file
112
6581
  if(filenames.size() > 1) {
113
    throw Exception("Too many input files specified.");
114
  }
115
116
  // If no file supplied we will read from standard input
117
6581
  const bool inputFromStdin = filenames.empty() || filenames[0] == "-";
118
119
  // if we're reading from stdin on a TTY, default to interactive mode
120
6581
  if (!solver->getOptionInfo("interactive").setByUser)
121
  {
122
6581
    solver->setOption("interactive", (inputFromStdin && isatty(fileno(stdin))) ? "true" : "false");
123
  }
124
125
  // Auto-detect input language by filename extension
126
13162
  std::string filenameStr("<stdin>");
127
6581
  if (!inputFromStdin) {
128
6581
    filenameStr = std::move(filenames[0]);
129
  }
130
6581
  const char* filename = filenameStr.c_str();
131
132
6581
  if (solver->getOption("input-language") == "LANG_AUTO")
133
  {
134
6190
    if( inputFromStdin ) {
135
      // We can't do any fancy detection on stdin
136
      solver->setOption("input-language", "smt2");
137
    } else {
138
6190
      size_t len = filenameStr.size();
139
6190
      if(len >= 5 && !strcmp(".smt2", filename + len - 5)) {
140
6111
        solver->setOption("input-language", "smt2");
141
79
      } else if((len >= 2 && !strcmp(".p", filename + len - 2))
142
37
                || (len >= 5 && !strcmp(".tptp", filename + len - 5))) {
143
42
        solver->setOption("input-language", "tptp");
144
37
      } else if((len >= 3 && !strcmp(".sy", filename + len - 3))
145
                || (len >= 3 && !strcmp(".sl", filename + len - 3))) {
146
        // version 2 sygus is the default
147
37
        solver->setOption("input-language", "sygus2");
148
      }
149
    }
150
  }
151
152
6581
  if (solver->getOption("output-language") == "LANG_AUTO")
153
  {
154
6581
    solver->setOption("output-language", solver->getOption("input-language"));
155
  }
156
6581
  pExecutor->storeOptionsAsOriginal();
157
158
  // Determine which messages to show based on smtcomp_mode and verbosity
159
6581
  if(Configuration::isMuzzledBuild()) {
160
    DebugChannel.setStream(&cvc5::null_os);
161
    TraceChannel.setStream(&cvc5::null_os);
162
    NoticeChannel.setStream(&cvc5::null_os);
163
    ChatChannel.setStream(&cvc5::null_os);
164
    MessageChannel.setStream(&cvc5::null_os);
165
    WarningChannel.setStream(&cvc5::null_os);
166
  }
167
168
6581
  int returnValue = 0;
169
  {
170
6581
    solver->setInfo("filename", filenameStr);
171
172
    // Parse and execute commands until we are done
173
13162
    std::unique_ptr<Command> cmd;
174
6581
    bool status = true;
175
6581
    if (solver->getOptionInfo("interactive").boolValue() && inputFromStdin)
176
    {
177
      if (!solver->getOptionInfo("incremental").setByUser)
178
      {
179
        cmd.reset(new SetOptionCommand("incremental", "true"));
180
        cmd->setMuted(true);
181
        pExecutor->doCommand(cmd);
182
      }
183
      InteractiveShell shell(pExecutor->getSolver(),
184
                             pExecutor->getSymbolManager(),
185
                             dopts.in(),
186
                             dopts.out());
187
188
      CVC5Message() << Configuration::getPackageName() << " "
189
                    << Configuration::getVersionString();
190
      if (Configuration::isGitBuild())
191
      {
192
        CVC5Message() << " [" << Configuration::getGitInfo() << "]";
193
      }
194
      CVC5Message() << (Configuration::isDebugBuild() ? " DEBUG" : "")
195
                    << " assertions:"
196
                    << (Configuration::isAssertionBuild() ? "on" : "off")
197
                    << endl
198
                    << endl;
199
      CVC5Message() << Configuration::copyright() << endl;
200
201
      while(true) {
202
        try {
203
          cmd.reset(shell.readCommand());
204
        } catch(UnsafeInterruptException& e) {
205
          dopts.out() << CommandInterrupted();
206
          break;
207
        }
208
        if (cmd == nullptr)
209
          break;
210
        status = pExecutor->doCommand(cmd) && status;
211
        if (cmd->interrupted()) {
212
          break;
213
        }
214
      }
215
    }
216
    else
217
    {
218
6581
      if (!solver->getOptionInfo("incremental").setByUser)
219
      {
220
5905
        cmd.reset(new SetOptionCommand("incremental", "false"));
221
5905
        cmd->setMuted(true);
222
5905
        pExecutor->doCommand(cmd);
223
      }
224
225
      ParserBuilder parserBuilder(
226
13162
          pExecutor->getSolver(), pExecutor->getSymbolManager(), true);
227
13162
      std::unique_ptr<Parser> parser(parserBuilder.build());
228
6581
      if( inputFromStdin ) {
229
        parser->setInput(Input::newStreamInput(
230
            solver->getOption("input-language"), cin, filename));
231
      }
232
      else
233
      {
234
26324
        parser->setInput(
235
13162
            Input::newFileInput(solver->getOption("input-language"),
236
                                filename,
237
13162
                                solver->getOptionInfo("mmap").boolValue()));
238
      }
239
240
6581
      bool interrupted = false;
241
477743
      while (status)
242
      {
243
242114
        if (interrupted) {
244
          dopts.out() << CommandInterrupted();
245
          pExecutor->reset();
246
          break;
247
        }
248
        try {
249
242114
          cmd.reset(parser->nextCommand());
250
242094
          if (cmd == nullptr) break;
251
        } catch (UnsafeInterruptException& e) {
252
          interrupted = true;
253
          continue;
254
        }
255
256
236321
        status = pExecutor->doCommand(cmd);
257
236321
        if (cmd->interrupted() && status == 0) {
258
          interrupted = true;
259
          break;
260
        }
261
262
236321
        if(dynamic_cast<QuitCommand*>(cmd.get()) != nullptr) {
263
740
          break;
264
        }
265
      }
266
    }
267
268
13122
    api::Result result;
269
6561
    if(status) {
270
6513
      result = pExecutor->getResult();
271
6513
      returnValue = 0;
272
    } else {
273
      // there was some kind of error
274
48
      returnValue = 1;
275
    }
276
277
#ifdef CVC5_COMPETITION_MODE
278
    dopts.out() << std::flush;
279
    // exit, don't return (don't want destructors to run)
280
    // _exit() from unistd.h doesn't run global destructors
281
    // or other on_exit/atexit stuff.
282
    _exit(returnValue);
283
#endif /* CVC5_COMPETITION_MODE */
284
285
6561
    pExecutor->flushOutputStreams();
286
287
#ifdef CVC5_DEBUG
288
    {
289
13122
      auto info = solver->getOptionInfo("early-exit");
290
6561
      if (info.boolValue() && info.setByUser)
291
      {
292
        _exit(returnValue);
293
      }
294
    }
295
#else  /* CVC5_DEBUG */
296
    if (solver->getOptionInfo("early-exit").boolValue())
297
    {
298
      _exit(returnValue);
299
    }
300
#endif /* CVC5_DEBUG */
301
  }
302
303
6561
  pExecutor.reset();
304
305
6561
  signal_handlers::cleanup();
306
307
13122
  return returnValue;
308
31098
}