GCC Code Coverage Report
Directory: . Exec Total Coverage
File: test/api/ouroborous.cpp Lines: 71 78 91.0 %
Date: 2021-09-17 Branches: 130 257 50.6 %

Line Exec Source
1
/******************************************************************************
2
 * Top contributors (to current version):
3
 *   Aina Niemetz, Morgan Deters
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
 * "Ouroborous" test: does cvc5 read its own output?
14
 *
15
 * The "Ouroborous" test, named after the serpent that swallows its
16
 * own tail, ensures that cvc5 can parse some input, output it again
17
 * (in any of its languages) and then parse it again.  The result of
18
 * the first parse must be equal to the result of the second parse;
19
 * both strings and expressions are compared for equality.
20
 *
21
 * To add a new test, simply add a call to runTestString() under
22
 * runTest(), below.  If you don't specify an input language,
23
 * LANG_SMTLIB_V2 is used.  If your example depends on variables,
24
 * you'll need to declare them in the "declarations" global, just
25
 * below, in SMT-LIBv2 form (but they're good for all languages).
26
 */
27
28
#include <cassert>
29
#include <iostream>
30
#include <string>
31
32
#include "api/cpp/cvc5.h"
33
#include "options/set_language.h"
34
#include "parser/parser.h"
35
#include "parser/parser_builder.h"
36
#include "smt/command.h"
37
38
using namespace cvc5;
39
using namespace cvc5::parser;
40
using namespace cvc5::language;
41
42
int runTest();
43
44
1
int main()
45
{
46
  try
47
  {
48
1
    return runTest();
49
  }
50
  catch (api::CVC5ApiException& e)
51
  {
52
    std::cerr << e.getMessage() << std::endl;
53
  }
54
  catch (parser::ParserException& e)
55
  {
56
    std::cerr << e.getMessage() << std::endl;
57
  }
58
  catch (...)
59
  {
60
    std::cerr << "non-cvc5 exception thrown" << std::endl;
61
  }
62
  return 1;
63
}
64
65
24
std::string parse(std::string instr,
66
                  std::string input_language,
67
                  std::string output_language)
68
{
69
24
  assert(input_language == "smt2" || input_language == "cvc");
70
24
  assert(output_language == "smt2" || output_language == "cvc");
71
72
48
  std::string declarations;
73
74
24
  if (input_language == "smt2")
75
  {
76
13
    declarations =
77
        "\
78
  (declare-sort U 0)\n\
79
  (declare-fun f (U) U)\n\
80
  (declare-fun x () U)\n\
81
  (declare-fun y () U)\n\
82
  (assert (= (f x) x))\n\
83
  (declare-fun a () (Array U (Array U U)))\n\
84
  ";
85
  }
86
  else
87
  {
88
11
    declarations =
89
        "\
90
      U: TYPE;\n\
91
      f: U -> U;\n\
92
      x,y: U;\n\
93
      a: ARRAY U OF (ARRAY U OF U);\n\
94
      ASSERT f(x) = x;\n\
95
  ";
96
  }
97
98
48
  api::Solver solver;
99
  std::string ilang =
100
48
      input_language == "smt2" ? "LANG_SMTLIB_V2_6" : "LANG_CVC";
101
102
24
  solver.setOption("input-language", input_language);
103
24
  solver.setOption("output-language", output_language);
104
48
  SymbolManager symman(&solver);
105
  std::unique_ptr<Parser> parser(
106
48
      ParserBuilder(&solver, &symman, false)
107
48
          .withInputLanguage(solver.getOption("input-language"))
108
48
          .build());
109
24
  parser->setInput(
110
      Input::newStringInput(ilang, declarations, "internal-buffer"));
111
  // we don't need to execute the commands, but we DO need to parse them to
112
  // get the declarations
113
157
  while (Command* c = parser->nextCommand())
114
  {
115
133
    delete c;
116
133
  }
117
24
  assert(parser->done());  // parser should be done
118
24
  parser->setInput(Input::newStringInput(ilang, instr, "internal-buffer"));
119
48
  api::Term e = parser->nextExpression();
120
24
  std::string s = e.toString();
121
24
  assert(parser->nextExpression().isNull());  // next expr should be null
122
48
  return s;
123
}
124
125
12
std::string translate(std::string instr,
126
                      std::string input_language,
127
                      std::string output_language)
128
{
129
12
  assert(input_language == "smt2" || input_language == "cvc");
130
12
  assert(output_language == "smt2" || output_language == "cvc");
131
132
12
  std::cout << "==============================================" << std::endl
133
12
            << "translating from "
134
12
            << (input_language == "smt2" ? Language::LANG_SMTLIB_V2_6
135
12
                                         : Language::LANG_CVC)
136
12
            << " to "
137
12
            << (output_language == "smt2" ? Language::LANG_SMTLIB_V2_6
138
12
                                          : Language::LANG_CVC)
139
12
            << " this string:" << std::endl
140
12
            << instr << std::endl;
141
12
  std::string outstr = parse(instr, input_language, output_language);
142
12
  std::cout << "got this:" << std::endl
143
12
            << outstr << std::endl
144
12
            << "reparsing as "
145
12
            << (output_language == "smt2" ? Language::LANG_SMTLIB_V2_6
146
12
                                          : Language::LANG_CVC)
147
12
            << std::endl;
148
24
  std::string poutstr = parse(outstr, output_language, output_language);
149
12
  assert(outstr == poutstr);
150
12
  std::cout << "got same expressions " << outstr << " and " << poutstr
151
12
            << std::endl
152
12
            << "==============================================" << std::endl;
153
24
  return outstr;
154
}
155
156
4
void runTestString(std::string instr, std::string instr_language)
157
{
158
4
  std::cout << std::endl
159
4
            << "starting with: " << instr << std::endl
160
4
            << "   in language " << Language::LANG_SMTLIB_V2_6 << std::endl;
161
8
  std::string smt2str = translate(instr, instr_language, "smt2");
162
4
  std::cout << "in SMT2      : " << smt2str << std::endl;
163
8
  std::string cvcstr = translate(smt2str, "smt2", "cvc");
164
4
  std::cout << "in CVC       : " << cvcstr << std::endl;
165
8
  std::string outstr = translate(cvcstr, "cvc", "smt2");
166
4
  std::cout << "back to SMT2 : " << outstr << std::endl << std::endl;
167
168
4
  assert(outstr == smt2str);  // differences in output
169
4
}
170
171
1
int32_t runTest()
172
{
173
1
  runTestString("(= (f (f y)) x)", "smt2");
174
1
  runTestString("~BVPLUS(3, 0bin00, 0bin11)[2:1] = 0bin10", "cvc");
175
1
  runTestString("~BVPLUS(3, BVMULT(2, 0bin01, 0bin11), 0bin11)[2:0]", "cvc");
176
1
  runTestString("a[x][y] = a[y][x]", "cvc");
177
1
  return 0;
178
3
}