New C++ Api: Rename and move headers. (#6292)
authorAina Niemetz <aina.niemetz@gmail.com>
Tue, 6 Apr 2021 02:31:28 +0000 (19:31 -0700)
committerGitHub <noreply@github.com>
Tue, 6 Apr 2021 02:31:28 +0000 (19:31 -0700)
73 files changed:
.github/workflows/ci.yml
examples/api/bitvectors.cpp
examples/api/bitvectors_and_arrays.cpp
examples/api/combination.cpp
examples/api/datatypes.cpp
examples/api/extract.cpp
examples/api/helloworld.cpp
examples/api/linear_arith.cpp
examples/api/sequences.cpp
examples/api/sets.cpp
examples/api/strings.cpp
examples/api/sygus-fun.cpp
examples/api/sygus-grammar.cpp
examples/api/sygus-inv.cpp
examples/nra-translate/normalize.cpp
examples/nra-translate/smt2info.cpp
examples/nra-translate/smt2todreal.cpp
examples/nra-translate/smt2toisat.cpp
examples/nra-translate/smt2tomathematica.cpp
examples/nra-translate/smt2toqepcad.cpp
examples/nra-translate/smt2toredlog.cpp
examples/sets-translate/sets_translate.cpp
examples/simple_vc_cxx.cpp
examples/simple_vc_quant_cxx.cpp
examples/translator.cpp
src/CMakeLists.txt
src/api/cpp/cvc5.cpp [new file with mode: 0644]
src/api/cpp/cvc5.h [new file with mode: 0644]
src/api/cpp/cvc5_kind.h [new file with mode: 0644]
src/api/cvc4cpp.cpp [deleted file]
src/api/cvc4cpp.h [deleted file]
src/api/cvc4cppkind.h [deleted file]
src/api/java/CMakeLists.txt
src/api/java/genkinds.py
src/api/parsekinds.py
src/api/python/CMakeLists.txt
src/api/python/cvc4.pxd
src/api/python/genkinds.py.in
src/expr/symbol_manager.h
src/expr/symbol_table.cpp
src/fix-install-headers.sh
src/main/command_executor.h
src/main/driver_unified.cpp
src/main/interactive_shell.cpp
src/parser/cvc/cvc.h
src/parser/input.h
src/parser/parse_op.h
src/parser/parser.cpp
src/parser/parser.h
src/parser/parser_builder.cpp
src/parser/smt2/Smt2.g
src/parser/smt2/smt2.h
src/parser/tptp/Tptp.g
src/parser/tptp/tptp.cpp
src/parser/tptp/tptp.h
src/printer/smt2/smt2_printer.cpp
src/smt/command.cpp
src/smt/command.h
test/api/boilerplate.cpp
test/api/issue4889.cpp
test/api/issue5074.cpp
test/api/ouroborous.cpp
test/api/reset_assertions.cpp
test/api/sep_log_api.cpp
test/api/smt2_compliance.cpp
test/api/two_solvers.cpp
test/unit/main/interactive_shell_black.cpp
test/unit/node/node_black.cpp
test/unit/parser/parser_black.cpp
test/unit/parser/parser_builder_black.cpp
test/unit/printer/smt2_printer_black.cpp
test/unit/test_api.h
test/unit/theory/regexp_operation_black.cpp

index 8d8104385b2102eefa25b841831bdaa7a76d3cb4..8925b06d9caae7773563fa853700f6fa93aa406b 100644 (file)
@@ -194,7 +194,7 @@ jobs:
     - name: Install Check
       run: |
         make -j2 install
-        echo -e "#include <cvc4/api/cvc4cpp.h>\nint main() { cvc5::api::Solver s; return 0; }" > /tmp/test.cpp
+        echo -e "#include <cvc5/cvc5.h>\nint main() { cvc5::api::Solver s; return 0; }" > /tmp/test.cpp
         g++ -std=c++11 /tmp/test.cpp -I install/include -L install/lib -lcvc4
       working-directory: build
 
index 043bbf8aaf394f0d8c08da5ec4cf7dd325087704..be9557c994e0670fe644d0422c86d5dbbdbf9925 100644 (file)
@@ -14,9 +14,9 @@
  **
  **/
 
-#include <iostream>
+#include <cvc5/cvc5.h>
 
-#include <cvc4/api/cvc4cpp.h>
+#include <iostream>
 
 using namespace std;
 using namespace cvc5::api;
index 2bca1eb4cf531351845638e79ffca91770b2b4d2..ca9869503467947106becffde97486b1b2d3c296 100644 (file)
  **
  **/
 
-#include <iostream>
-#include <cmath>
+#include <cvc5/cvc5.h>
 
-#include <cvc4/api/cvc4cpp.h>
+#include <cmath>
+#include <iostream>
 
 using namespace std;
 using namespace cvc5::api;
index 9ea2f55ed9c65848c5204c49a4051e7ac7133542..82c2978e61b3083aef13e42eb4104721a2d71703 100644 (file)
@@ -16,9 +16,9 @@
  ** The model is displayed using getValue().
  **/
 
-#include <iostream>
+#include <cvc5/cvc5.h>
 
-#include <cvc4/api/cvc4cpp.h>
+#include <iostream>
 
 using namespace std;
 using namespace cvc5::api;
index 49253e4662dc5d7c51296ef865af77721612bbf6..f9a1484da0cbd0a84605b4cb29e428c98d1640cd 100644 (file)
@@ -14,9 +14,9 @@
  ** An example of using inductive datatypes in CVC4.
  **/
 
-#include <iostream>
+#include <cvc5/cvc5.h>
 
-#include <cvc4/api/cvc4cpp.h>
+#include <iostream>
 
 using namespace cvc5::api;
 
index 760f5d0feeab77b72a81da3f81323b792aaaadc0..d2f631d2591a8dd3e5b38a237f56167fc740981d 100644 (file)
@@ -14,9 +14,9 @@
  **
  **/
 
-#include <iostream>
+#include <cvc5/cvc5.h>
 
-#include <cvc4/api/cvc4cpp.h>
+#include <iostream>
 
 using namespace std;
 using namespace cvc5::api;
index 092e2a79a00fdfd4238bec786afa0b77094e8de1..b5881f31208e7f6b776516c444a207b09212a730 100644 (file)
@@ -14,9 +14,9 @@
  ** A very simple CVC4 tutorial example.
  **/
 
-#include <iostream>
+#include <cvc5/cvc5.h>
 
-#include <cvc4/api/cvc4cpp.h>
+#include <iostream>
 
 using namespace cvc5::api;
 
index b56982daa7ba4561dc7c26a6461135d76af418c7..ee9663455ec9b4d22bf107b8a1238b92613568c9 100644 (file)
@@ -17,7 +17,7 @@
 
 #include <iostream>
 
-#include "cvc4/api/cvc4cpp.h"
+#include <cvc5/cvc5.h>
 
 using namespace std;
 using namespace cvc5::api;
index 3498b327518d17718db0d853b693c6c54ec52705..39117c090a95802449cd18e758c6e340eacc9372 100644 (file)
@@ -14,7 +14,7 @@
  ** A simple demonstration of reasoning about sequences with CVC4 via C++ API.
  **/
 
-#include <cvc4/api/cvc4cpp.h>
+#include <cvc5/cvc5.h>
 
 #include <iostream>
 
index 59385896c7f9a9c355aabfc17c2ba62933f0b311..c8b8bcc9e457e1da6d55f939dd5efa95ffc132b1 100644 (file)
@@ -14,9 +14,9 @@
  ** A simple demonstration of reasoning about sets with CVC4.
  **/
 
-#include <iostream>
+#include <cvc5/cvc5.h>
 
-#include <cvc4/api/cvc4cpp.h>
+#include <iostream>
 
 using namespace std;
 using namespace cvc5::api;
index 53352d266066e95a51edeb35cfa9e77202469393..548d25b811fe0fe6f1cbdf26db95ee458012970d 100644 (file)
@@ -14,9 +14,9 @@
  ** A simple demonstration of reasoning about strings with CVC4 via C++ API.
  **/
 
-#include <iostream>
+#include <cvc5/cvc5.h>
 
-#include <cvc4/api/cvc4cpp.h>
+#include <iostream>
 
 using namespace cvc5::api;
 
index be4d3e8d5437b85844ee02856b00c9e2664e5182..44e276ddc78d8fbff21b731c9393c1101c4f28e0 100644 (file)
@@ -45,7 +45,7 @@
  ** (define-fun min ((x Int) (y Int)) Int (ite (<= x y) x y))
  **/
 
-#include <cvc4/api/cvc4cpp.h>
+#include <cvc5/cvc5.h>
 
 #include <iostream>
 
index 61b00f6de3fcb2aef76baa66d573a091cfe17877..441cfa30cbf860b9168c6376eb3c103ad6e578a1 100644 (file)
@@ -42,7 +42,7 @@
  ** (define-fun id4 ((x Int)) Int (+ x (+ x (- x))))
  **/
 
-#include <cvc4/api/cvc4cpp.h>
+#include <cvc5/cvc5.h>
 
 #include <iostream>
 
index 56b5a0aaa4aafb5a86fc7ba58476a1935ac94f4e..5d678975954eb17766537e6603881ac43511ebf7 100644 (file)
@@ -33,7 +33,7 @@
  ** (define-fun inv-f ((x Int)) Bool (not (>= x 11)))
  **/
 
-#include <cvc4/api/cvc4cpp.h>
+#include <cvc5/cvc5.h>
 
 #include <iostream>
 
index ba495e1fd98024d5f9b8be652fc164015f1303df..635c369a0160573dbc8d98aac53e1ab79ddbbf85 100644 (file)
  ** \todo document this file
  **/
 
+#include <cvc5/cvc5.h>
+#include <cvc4/expr/expr_iomanip.h>
+#include <cvc4/options/set_language.h>
+
 #include <cassert>
 #include <iostream>
 #include <map>
 #include <typeinfo>
 #include <vector>
 
-#include <cvc4/api/cvc4cpp.h>
-#include <cvc4/cvc4.h>
-#include <cvc4/expr/expr_iomanip.h>
-#include <cvc4/options/set_language.h>
-
 using namespace std;
 using namespace cvc5;
 using namespace cvc5::parser;
index 1eb4b3d4d49ef91d88be52b5224df6175b08f661..4136017690506bebcf327310208f36f9b1ad6324 100644 (file)
  ** \todo document this file
  **/
 
+#include <cvc5/cvc5.h>
+
 #include <cassert>
 #include <iostream>
 #include <string>
 #include <typeinfo>
 #include <vector>
 
-#include <cvc4/api/cvc4cpp.h>
-#include <cvc4/cvc4.h>
-
 using namespace std;
 using namespace cvc5;
 using namespace cvc5::parser;
index 8139a4d91cd241e9b2d5d07370ed023aeaed82c8..62a1f4b5e9102272c0d29efcbd08c86765824144 100644 (file)
  ** \todo document this file
  **/
 
+#include <cvc5/cvc5.h>
+#include <cvc4/expr/expr_iomanip.h>
+#include <cvc4/options/set_language.h>
+
 #include <cassert>
 #include <iostream>
 #include <map>
 #include <typeinfo>
 #include <vector>
 
-#include <cvc4/api/cvc4cpp.h>
-#include <cvc4/cvc4.h>
-#include <cvc4/expr/expr_iomanip.h>
-#include <cvc4/options/set_language.h>
-
 using namespace std;
 using namespace cvc5;
 using namespace cvc5::parser;
index 09b0c69d83b33024125ecd603a00dab71edd6389..5898e5cff8c4b7bce9609421a1f18d30ca66e03c 100644 (file)
@@ -15,6 +15,8 @@
  ** \todo document this file
  **/
 
+#include <cvc5/cvc5.h>
+
 #include <cassert>
 #include <iostream>
 #include <map>
@@ -22,9 +24,6 @@
 #include <typeinfo>
 #include <vector>
 
-#include <cvc4/api/cvc4cpp.h>
-#include <cvc4/cvc4.h>
-
 using namespace std;
 using namespace cvc5;
 using namespace cvc5::parser;
index 6cb51f17c7099a99877182cfb4a583854423a7e1..b2c73d48ebbec58e98a40f6b2c6154e931954c66 100644 (file)
@@ -15,6 +15,8 @@
  ** \todo document this file
  **/
 
+#include <cvc5/cvc5.h>
+
 #include <cassert>
 #include <iostream>
 #include <map>
@@ -22,9 +24,6 @@
 #include <typeinfo>
 #include <vector>
 
-#include <cvc4/api/cvc4cpp.h>
-#include <cvc4/cvc4.h>
-
 using namespace std;
 using namespace cvc5;
 using namespace cvc5::parser;
index afd468d5d341a3346558a46338f82fe6f5c67bfe..760a7024cd09db2e2ae0554efb7c73ba188f99e6 100644 (file)
@@ -15,6 +15,8 @@
  ** \todo document this file
  **/
 
+#include <cvc5/cvc5.h>
+
 #include <cassert>
 #include <iostream>
 #include <map>
@@ -22,9 +24,6 @@
 #include <typeinfo>
 #include <vector>
 
-#include <cvc4/api/cvc4cpp.h>
-#include <cvc4/cvc4.h>
-
 using namespace std;
 using namespace cvc5;
 using namespace cvc5::parser;
index d9bd6012a30c06406d2199cd09da37e09b201b76..dd6fb9bb6a37409157c3cf2351a0ff7d25a30b05 100644 (file)
@@ -15,6 +15,8 @@
  ** \todo document this file
  **/
 
+#include <cvc5/cvc5.h>
+
 #include <cassert>
 #include <iostream>
 #include <map>
@@ -22,9 +24,6 @@
 #include <typeinfo>
 #include <vector>
 
-#include <cvc4/api/cvc4cpp.h>
-#include <cvc4/cvc4.h>
-
 using namespace std;
 using namespace cvc5;
 using namespace cvc5::parser;
index ec95b5f70fcdccf9dc471ed4d59d47a3e908e875..0f924072c3a318221c26b0e3d1ce67cda139c183 100644 (file)
  ** \todo document this file
  **/
 
-#include <boost/algorithm/string.hpp> // include Boost, a C++ library
+#include <cvc5/cvc5.h>
+#include <cvc4/options/set_language.h>
+
+#include <boost/algorithm/string.hpp>  // include Boost, a C++ library
 #include <cassert>
 #include <iostream>
 #include <string>
 #include <unordered_map>
 #include <vector>
 
-#include <cvc4/api/cvc4cpp.h>
-#include <cvc4/cvc4.h>
-#include <cvc4/options/set_language.h>
-
 using namespace std;
 using namespace cvc5;
 using namespace cvc5::parser;
index b97b86bb8bc353cf188f3f11bdc74811ee7708db..4042e15cb9eddf2df94353583dd69c192974392a 100644 (file)
@@ -16,7 +16,7 @@
  ** identical.
  **/
 
-#include <cvc4/api/cvc4cpp.h>
+#include <cvc5/cvc5.h>
 
 #include <iostream>
 
index 73dbfe34f8e46041a8c4ae8c1e63ad4cee38fcbf..3d6a6e1032a198daa5e8419c350c83661409f38d 100644 (file)
@@ -14,7 +14,7 @@
  ** A simple demonstration of the C++ interface for quantifiers.
  **/
 
-#include <cvc4/api/cvc4cpp.h>
+#include <cvc5/cvc5.h>
 
 #include <iostream>
 
index 4838e06fbc1e8311e9af82dbf67b491df9d312c1..bcdf2b2d29a8068a4d0171ba2bd337c43582e4ba 100644 (file)
  ** CVC4's input languages to one of its output languages.
  **/
 
+#include <cvc5/cvc5.h>
+#include <cvc4/expr/expr_iomanip.h>
+#include <cvc4/options/set_language.h>
+#include <getopt.h>
+
 #include <cerrno>
 #include <cstdlib>
 #include <cstring>
 #include <fstream>
-#include <getopt.h>
 #include <iostream>
 
-#include <cvc4/api/cvc4cpp.h>
-#include <cvc4/cvc4.h>
-#include <cvc4/expr/expr_iomanip.h>
-#include <cvc4/options/set_language.h>
-
 using namespace std;
 using namespace cvc5;
 using namespace cvc5::language;
index 6c2af82262def390a4ed48b18504a8da1014e7f0..04ad27b5c2c17ce79bbd6caa52fddc5b83eda794 100644 (file)
@@ -13,9 +13,9 @@
 
 libcvc4_add_sources(
   api/checks.h
-  api/cvc4cpp.cpp
-  api/cvc4cpp.h
-  api/cvc4cppkind.h
+  api/cpp/cvc5.cpp
+  api/cpp/cvc5.h
+  api/cpp/cvc5_kind.h
   context/backtrackable.h
   context/cddense_set.h
   context/cdhashmap.h
@@ -1182,14 +1182,14 @@ endif()
 # Install public API headers
 
 install(FILES
-          api/cvc4cpp.h
-          api/cvc4cppkind.h
+          api/cpp/cvc5.h
+          api/cpp/cvc5_kind.h
         DESTINATION
-          ${CMAKE_INSTALL_INCLUDEDIR}/cvc4/api)
+          ${CMAKE_INSTALL_INCLUDEDIR}/cvc5/)
 install(FILES
           ${CMAKE_CURRENT_BINARY_DIR}/cvc4_export.h
         DESTINATION
-          ${CMAKE_INSTALL_INCLUDEDIR}/cvc4/)
+          ${CMAKE_INSTALL_INCLUDEDIR}/cvc5/)
 
 # Fix include paths for all public headers.
 # Note: This is a temporary fix until the new C++ API is in place.
diff --git a/src/api/cpp/cvc5.cpp b/src/api/cpp/cvc5.cpp
new file mode 100644 (file)
index 0000000..b965d55
--- /dev/null
@@ -0,0 +1,6897 @@
+/*********************                                                        */
+/*! \file cvc5.cpp
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Aina Niemetz, Andrew Reynolds, Andres Noetzli
+ ** This file is part of the CVC4 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.\endverbatim
+ **
+ ** \brief The CVC4 C++ API.
+ **
+ ** The CVC4 C++ API.
+ **
+ ** A brief note on how to guard API functions:
+ **
+ ** In general, we think of API guards as a fence -- they are supposed to make
+ ** sure that no invalid arguments get passed into internal realms of CVC4.
+ ** Thus we always want to catch such cases on the API level (and can then
+ ** assert internally that no invalid argument is passed in).
+ **
+ ** The only special case is when we use 3rd party back-ends we have no control
+ ** over, and which throw (invalid_argument) exceptions anyways. In this case,
+ ** we do not replicate argument checks but delegate them to the back-end,
+ ** catch thrown exceptions, and raise a CVC4ApiException.
+ **
+ ** Our Integer implementation, e.g., is such a special case since we support
+ ** two different back end implementations (GMP, CLN). Be aware that they do
+ ** not fully agree on what is (in)valid input, which requires extra checks for
+ ** consistent behavior (see Solver::mkRealFromStrHelper for an example).
+ **/
+
+#include "api/cpp/cvc5.h"
+
+#include <cstring>
+#include <sstream>
+
+#include "api/checks.h"
+#include "base/check.h"
+#include "base/configuration.h"
+#include "expr/dtype.h"
+#include "expr/dtype_cons.h"
+#include "expr/dtype_selector.h"
+#include "expr/kind.h"
+#include "expr/metakind.h"
+#include "expr/node.h"
+#include "expr/node_algorithm.h"
+#include "expr/node_manager.h"
+#include "expr/sequence.h"
+#include "expr/type_node.h"
+#include "options/main_options.h"
+#include "options/options.h"
+#include "options/smt_options.h"
+#include "proof/unsat_core.h"
+#include "smt/model.h"
+#include "smt/smt_engine.h"
+#include "smt/smt_mode.h"
+#include "theory/logic_info.h"
+#include "theory/theory_model.h"
+#include "util/random.h"
+#include "util/result.h"
+#include "util/statistics_registry.h"
+#include "util/stats_histogram.h"
+#include "util/utility.h"
+
+namespace cvc5 {
+namespace api {
+
+/* -------------------------------------------------------------------------- */
+/* Statistics                                                                 */
+/* -------------------------------------------------------------------------- */
+
+struct Statistics
+{
+  Statistics()
+      : d_consts("api::CONSTANT"), d_vars("api::VARIABLE"), d_terms("api::TERM")
+  {
+  }
+  IntegralHistogramStat<TypeConstant> d_consts;
+  IntegralHistogramStat<TypeConstant> d_vars;
+  IntegralHistogramStat<Kind> d_terms;
+};
+
+/* -------------------------------------------------------------------------- */
+/* Kind                                                                       */
+/* -------------------------------------------------------------------------- */
+
+/* Mapping from external (API) kind to internal kind. */
+const static std::unordered_map<Kind, cvc5::Kind, KindHashFunction> s_kinds{
+    {INTERNAL_KIND, cvc5::Kind::UNDEFINED_KIND},
+    {UNDEFINED_KIND, cvc5::Kind::UNDEFINED_KIND},
+    {NULL_EXPR, cvc5::Kind::NULL_EXPR},
+    /* Builtin ------------------------------------------------------------- */
+    {UNINTERPRETED_CONSTANT, cvc5::Kind::UNINTERPRETED_CONSTANT},
+    {ABSTRACT_VALUE, cvc5::Kind::ABSTRACT_VALUE},
+    {EQUAL, cvc5::Kind::EQUAL},
+    {DISTINCT, cvc5::Kind::DISTINCT},
+    {CONSTANT, cvc5::Kind::VARIABLE},
+    {VARIABLE, cvc5::Kind::BOUND_VARIABLE},
+    {SEXPR, cvc5::Kind::SEXPR},
+    {LAMBDA, cvc5::Kind::LAMBDA},
+    {WITNESS, cvc5::Kind::WITNESS},
+    /* Boolean ------------------------------------------------------------- */
+    {CONST_BOOLEAN, cvc5::Kind::CONST_BOOLEAN},
+    {NOT, cvc5::Kind::NOT},
+    {AND, cvc5::Kind::AND},
+    {IMPLIES, cvc5::Kind::IMPLIES},
+    {OR, cvc5::Kind::OR},
+    {XOR, cvc5::Kind::XOR},
+    {ITE, cvc5::Kind::ITE},
+    {MATCH, cvc5::Kind::MATCH},
+    {MATCH_CASE, cvc5::Kind::MATCH_CASE},
+    {MATCH_BIND_CASE, cvc5::Kind::MATCH_BIND_CASE},
+    /* UF ------------------------------------------------------------------ */
+    {APPLY_UF, cvc5::Kind::APPLY_UF},
+    {CARDINALITY_CONSTRAINT, cvc5::Kind::CARDINALITY_CONSTRAINT},
+    {CARDINALITY_VALUE, cvc5::Kind::CARDINALITY_VALUE},
+    {HO_APPLY, cvc5::Kind::HO_APPLY},
+    /* Arithmetic ---------------------------------------------------------- */
+    {PLUS, cvc5::Kind::PLUS},
+    {MULT, cvc5::Kind::MULT},
+    {IAND, cvc5::Kind::IAND},
+    {MINUS, cvc5::Kind::MINUS},
+    {UMINUS, cvc5::Kind::UMINUS},
+    {DIVISION, cvc5::Kind::DIVISION},
+    {INTS_DIVISION, cvc5::Kind::INTS_DIVISION},
+    {INTS_MODULUS, cvc5::Kind::INTS_MODULUS},
+    {ABS, cvc5::Kind::ABS},
+    {DIVISIBLE, cvc5::Kind::DIVISIBLE},
+    {POW, cvc5::Kind::POW},
+    {EXPONENTIAL, cvc5::Kind::EXPONENTIAL},
+    {SINE, cvc5::Kind::SINE},
+    {COSINE, cvc5::Kind::COSINE},
+    {TANGENT, cvc5::Kind::TANGENT},
+    {COSECANT, cvc5::Kind::COSECANT},
+    {SECANT, cvc5::Kind::SECANT},
+    {COTANGENT, cvc5::Kind::COTANGENT},
+    {ARCSINE, cvc5::Kind::ARCSINE},
+    {ARCCOSINE, cvc5::Kind::ARCCOSINE},
+    {ARCTANGENT, cvc5::Kind::ARCTANGENT},
+    {ARCCOSECANT, cvc5::Kind::ARCCOSECANT},
+    {ARCSECANT, cvc5::Kind::ARCSECANT},
+    {ARCCOTANGENT, cvc5::Kind::ARCCOTANGENT},
+    {SQRT, cvc5::Kind::SQRT},
+    {CONST_RATIONAL, cvc5::Kind::CONST_RATIONAL},
+    {LT, cvc5::Kind::LT},
+    {LEQ, cvc5::Kind::LEQ},
+    {GT, cvc5::Kind::GT},
+    {GEQ, cvc5::Kind::GEQ},
+    {IS_INTEGER, cvc5::Kind::IS_INTEGER},
+    {TO_INTEGER, cvc5::Kind::TO_INTEGER},
+    {TO_REAL, cvc5::Kind::TO_REAL},
+    {PI, cvc5::Kind::PI},
+    /* BV ------------------------------------------------------------------ */
+    {CONST_BITVECTOR, cvc5::Kind::CONST_BITVECTOR},
+    {BITVECTOR_CONCAT, cvc5::Kind::BITVECTOR_CONCAT},
+    {BITVECTOR_AND, cvc5::Kind::BITVECTOR_AND},
+    {BITVECTOR_OR, cvc5::Kind::BITVECTOR_OR},
+    {BITVECTOR_XOR, cvc5::Kind::BITVECTOR_XOR},
+    {BITVECTOR_NOT, cvc5::Kind::BITVECTOR_NOT},
+    {BITVECTOR_NAND, cvc5::Kind::BITVECTOR_NAND},
+    {BITVECTOR_NOR, cvc5::Kind::BITVECTOR_NOR},
+    {BITVECTOR_XNOR, cvc5::Kind::BITVECTOR_XNOR},
+    {BITVECTOR_COMP, cvc5::Kind::BITVECTOR_COMP},
+    {BITVECTOR_MULT, cvc5::Kind::BITVECTOR_MULT},
+    {BITVECTOR_PLUS, cvc5::Kind::BITVECTOR_PLUS},
+    {BITVECTOR_SUB, cvc5::Kind::BITVECTOR_SUB},
+    {BITVECTOR_NEG, cvc5::Kind::BITVECTOR_NEG},
+    {BITVECTOR_UDIV, cvc5::Kind::BITVECTOR_UDIV},
+    {BITVECTOR_UREM, cvc5::Kind::BITVECTOR_UREM},
+    {BITVECTOR_SDIV, cvc5::Kind::BITVECTOR_SDIV},
+    {BITVECTOR_SREM, cvc5::Kind::BITVECTOR_SREM},
+    {BITVECTOR_SMOD, cvc5::Kind::BITVECTOR_SMOD},
+    {BITVECTOR_SHL, cvc5::Kind::BITVECTOR_SHL},
+    {BITVECTOR_LSHR, cvc5::Kind::BITVECTOR_LSHR},
+    {BITVECTOR_ASHR, cvc5::Kind::BITVECTOR_ASHR},
+    {BITVECTOR_ULT, cvc5::Kind::BITVECTOR_ULT},
+    {BITVECTOR_ULE, cvc5::Kind::BITVECTOR_ULE},
+    {BITVECTOR_UGT, cvc5::Kind::BITVECTOR_UGT},
+    {BITVECTOR_UGE, cvc5::Kind::BITVECTOR_UGE},
+    {BITVECTOR_SLT, cvc5::Kind::BITVECTOR_SLT},
+    {BITVECTOR_SLE, cvc5::Kind::BITVECTOR_SLE},
+    {BITVECTOR_SGT, cvc5::Kind::BITVECTOR_SGT},
+    {BITVECTOR_SGE, cvc5::Kind::BITVECTOR_SGE},
+    {BITVECTOR_ULTBV, cvc5::Kind::BITVECTOR_ULTBV},
+    {BITVECTOR_SLTBV, cvc5::Kind::BITVECTOR_SLTBV},
+    {BITVECTOR_ITE, cvc5::Kind::BITVECTOR_ITE},
+    {BITVECTOR_REDOR, cvc5::Kind::BITVECTOR_REDOR},
+    {BITVECTOR_REDAND, cvc5::Kind::BITVECTOR_REDAND},
+    {BITVECTOR_EXTRACT, cvc5::Kind::BITVECTOR_EXTRACT},
+    {BITVECTOR_REPEAT, cvc5::Kind::BITVECTOR_REPEAT},
+    {BITVECTOR_ZERO_EXTEND, cvc5::Kind::BITVECTOR_ZERO_EXTEND},
+    {BITVECTOR_SIGN_EXTEND, cvc5::Kind::BITVECTOR_SIGN_EXTEND},
+    {BITVECTOR_ROTATE_LEFT, cvc5::Kind::BITVECTOR_ROTATE_LEFT},
+    {BITVECTOR_ROTATE_RIGHT, cvc5::Kind::BITVECTOR_ROTATE_RIGHT},
+    {INT_TO_BITVECTOR, cvc5::Kind::INT_TO_BITVECTOR},
+    {BITVECTOR_TO_NAT, cvc5::Kind::BITVECTOR_TO_NAT},
+    /* FP ------------------------------------------------------------------ */
+    {CONST_FLOATINGPOINT, cvc5::Kind::CONST_FLOATINGPOINT},
+    {CONST_ROUNDINGMODE, cvc5::Kind::CONST_ROUNDINGMODE},
+    {FLOATINGPOINT_FP, cvc5::Kind::FLOATINGPOINT_FP},
+    {FLOATINGPOINT_EQ, cvc5::Kind::FLOATINGPOINT_EQ},
+    {FLOATINGPOINT_ABS, cvc5::Kind::FLOATINGPOINT_ABS},
+    {FLOATINGPOINT_NEG, cvc5::Kind::FLOATINGPOINT_NEG},
+    {FLOATINGPOINT_PLUS, cvc5::Kind::FLOATINGPOINT_PLUS},
+    {FLOATINGPOINT_SUB, cvc5::Kind::FLOATINGPOINT_SUB},
+    {FLOATINGPOINT_MULT, cvc5::Kind::FLOATINGPOINT_MULT},
+    {FLOATINGPOINT_DIV, cvc5::Kind::FLOATINGPOINT_DIV},
+    {FLOATINGPOINT_FMA, cvc5::Kind::FLOATINGPOINT_FMA},
+    {FLOATINGPOINT_SQRT, cvc5::Kind::FLOATINGPOINT_SQRT},
+    {FLOATINGPOINT_REM, cvc5::Kind::FLOATINGPOINT_REM},
+    {FLOATINGPOINT_RTI, cvc5::Kind::FLOATINGPOINT_RTI},
+    {FLOATINGPOINT_MIN, cvc5::Kind::FLOATINGPOINT_MIN},
+    {FLOATINGPOINT_MAX, cvc5::Kind::FLOATINGPOINT_MAX},
+    {FLOATINGPOINT_LEQ, cvc5::Kind::FLOATINGPOINT_LEQ},
+    {FLOATINGPOINT_LT, cvc5::Kind::FLOATINGPOINT_LT},
+    {FLOATINGPOINT_GEQ, cvc5::Kind::FLOATINGPOINT_GEQ},
+    {FLOATINGPOINT_GT, cvc5::Kind::FLOATINGPOINT_GT},
+    {FLOATINGPOINT_ISN, cvc5::Kind::FLOATINGPOINT_ISN},
+    {FLOATINGPOINT_ISSN, cvc5::Kind::FLOATINGPOINT_ISSN},
+    {FLOATINGPOINT_ISZ, cvc5::Kind::FLOATINGPOINT_ISZ},
+    {FLOATINGPOINT_ISINF, cvc5::Kind::FLOATINGPOINT_ISINF},
+    {FLOATINGPOINT_ISNAN, cvc5::Kind::FLOATINGPOINT_ISNAN},
+    {FLOATINGPOINT_ISNEG, cvc5::Kind::FLOATINGPOINT_ISNEG},
+    {FLOATINGPOINT_ISPOS, cvc5::Kind::FLOATINGPOINT_ISPOS},
+    {FLOATINGPOINT_TO_FP_FLOATINGPOINT,
+     cvc5::Kind::FLOATINGPOINT_TO_FP_FLOATINGPOINT},
+    {FLOATINGPOINT_TO_FP_REAL, cvc5::Kind::FLOATINGPOINT_TO_FP_REAL},
+    {FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR,
+     cvc5::Kind::FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR},
+    {FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR,
+     cvc5::Kind::FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR},
+    {FLOATINGPOINT_TO_FP_GENERIC, cvc5::Kind::FLOATINGPOINT_TO_FP_GENERIC},
+    {FLOATINGPOINT_TO_UBV, cvc5::Kind::FLOATINGPOINT_TO_UBV},
+    {FLOATINGPOINT_TO_SBV, cvc5::Kind::FLOATINGPOINT_TO_SBV},
+    {FLOATINGPOINT_TO_REAL, cvc5::Kind::FLOATINGPOINT_TO_REAL},
+    /* Arrays -------------------------------------------------------------- */
+    {SELECT, cvc5::Kind::SELECT},
+    {STORE, cvc5::Kind::STORE},
+    {CONST_ARRAY, cvc5::Kind::STORE_ALL},
+    {EQ_RANGE, cvc5::Kind::EQ_RANGE},
+    /* Datatypes ----------------------------------------------------------- */
+    {APPLY_SELECTOR, cvc5::Kind::APPLY_SELECTOR},
+    {APPLY_CONSTRUCTOR, cvc5::Kind::APPLY_CONSTRUCTOR},
+    {APPLY_TESTER, cvc5::Kind::APPLY_TESTER},
+    {TUPLE_UPDATE, cvc5::Kind::TUPLE_UPDATE},
+    {RECORD_UPDATE, cvc5::Kind::RECORD_UPDATE},
+    {DT_SIZE, cvc5::Kind::DT_SIZE},
+    {TUPLE_PROJECT, cvc5::Kind::TUPLE_PROJECT},
+    /* Separation Logic ---------------------------------------------------- */
+    {SEP_NIL, cvc5::Kind::SEP_NIL},
+    {SEP_EMP, cvc5::Kind::SEP_EMP},
+    {SEP_PTO, cvc5::Kind::SEP_PTO},
+    {SEP_STAR, cvc5::Kind::SEP_STAR},
+    {SEP_WAND, cvc5::Kind::SEP_WAND},
+    /* Sets ---------------------------------------------------------------- */
+    {EMPTYSET, cvc5::Kind::EMPTYSET},
+    {UNION, cvc5::Kind::UNION},
+    {INTERSECTION, cvc5::Kind::INTERSECTION},
+    {SETMINUS, cvc5::Kind::SETMINUS},
+    {SUBSET, cvc5::Kind::SUBSET},
+    {MEMBER, cvc5::Kind::MEMBER},
+    {SINGLETON, cvc5::Kind::SINGLETON},
+    {INSERT, cvc5::Kind::INSERT},
+    {CARD, cvc5::Kind::CARD},
+    {COMPLEMENT, cvc5::Kind::COMPLEMENT},
+    {UNIVERSE_SET, cvc5::Kind::UNIVERSE_SET},
+    {JOIN, cvc5::Kind::JOIN},
+    {PRODUCT, cvc5::Kind::PRODUCT},
+    {TRANSPOSE, cvc5::Kind::TRANSPOSE},
+    {TCLOSURE, cvc5::Kind::TCLOSURE},
+    {JOIN_IMAGE, cvc5::Kind::JOIN_IMAGE},
+    {IDEN, cvc5::Kind::IDEN},
+    {COMPREHENSION, cvc5::Kind::COMPREHENSION},
+    {CHOOSE, cvc5::Kind::CHOOSE},
+    {IS_SINGLETON, cvc5::Kind::IS_SINGLETON},
+    /* Bags ---------------------------------------------------------------- */
+    {UNION_MAX, cvc5::Kind::UNION_MAX},
+    {UNION_DISJOINT, cvc5::Kind::UNION_DISJOINT},
+    {INTERSECTION_MIN, cvc5::Kind::INTERSECTION_MIN},
+    {DIFFERENCE_SUBTRACT, cvc5::Kind::DIFFERENCE_SUBTRACT},
+    {DIFFERENCE_REMOVE, cvc5::Kind::DIFFERENCE_REMOVE},
+    {SUBBAG, cvc5::Kind::SUBBAG},
+    {BAG_COUNT, cvc5::Kind::BAG_COUNT},
+    {DUPLICATE_REMOVAL, cvc5::Kind::DUPLICATE_REMOVAL},
+    {MK_BAG, cvc5::Kind::MK_BAG},
+    {EMPTYBAG, cvc5::Kind::EMPTYBAG},
+    {BAG_CARD, cvc5::Kind::BAG_CARD},
+    {BAG_CHOOSE, cvc5::Kind::BAG_CHOOSE},
+    {BAG_IS_SINGLETON, cvc5::Kind::BAG_IS_SINGLETON},
+    {BAG_FROM_SET, cvc5::Kind::BAG_FROM_SET},
+    {BAG_TO_SET, cvc5::Kind::BAG_TO_SET},
+    /* Strings ------------------------------------------------------------- */
+    {STRING_CONCAT, cvc5::Kind::STRING_CONCAT},
+    {STRING_IN_REGEXP, cvc5::Kind::STRING_IN_REGEXP},
+    {STRING_LENGTH, cvc5::Kind::STRING_LENGTH},
+    {STRING_SUBSTR, cvc5::Kind::STRING_SUBSTR},
+    {STRING_UPDATE, cvc5::Kind::STRING_UPDATE},
+    {STRING_CHARAT, cvc5::Kind::STRING_CHARAT},
+    {STRING_CONTAINS, cvc5::Kind::STRING_STRCTN},
+    {STRING_INDEXOF, cvc5::Kind::STRING_STRIDOF},
+    {STRING_REPLACE, cvc5::Kind::STRING_STRREPL},
+    {STRING_REPLACE_ALL, cvc5::Kind::STRING_STRREPLALL},
+    {STRING_REPLACE_RE, cvc5::Kind::STRING_REPLACE_RE},
+    {STRING_REPLACE_RE_ALL, cvc5::Kind::STRING_REPLACE_RE_ALL},
+    {STRING_TOLOWER, cvc5::Kind::STRING_TOLOWER},
+    {STRING_TOUPPER, cvc5::Kind::STRING_TOUPPER},
+    {STRING_REV, cvc5::Kind::STRING_REV},
+    {STRING_FROM_CODE, cvc5::Kind::STRING_FROM_CODE},
+    {STRING_TO_CODE, cvc5::Kind::STRING_TO_CODE},
+    {STRING_LT, cvc5::Kind::STRING_LT},
+    {STRING_LEQ, cvc5::Kind::STRING_LEQ},
+    {STRING_PREFIX, cvc5::Kind::STRING_PREFIX},
+    {STRING_SUFFIX, cvc5::Kind::STRING_SUFFIX},
+    {STRING_IS_DIGIT, cvc5::Kind::STRING_IS_DIGIT},
+    {STRING_FROM_INT, cvc5::Kind::STRING_ITOS},
+    {STRING_TO_INT, cvc5::Kind::STRING_STOI},
+    {CONST_STRING, cvc5::Kind::CONST_STRING},
+    {STRING_TO_REGEXP, cvc5::Kind::STRING_TO_REGEXP},
+    {REGEXP_CONCAT, cvc5::Kind::REGEXP_CONCAT},
+    {REGEXP_UNION, cvc5::Kind::REGEXP_UNION},
+    {REGEXP_INTER, cvc5::Kind::REGEXP_INTER},
+    {REGEXP_DIFF, cvc5::Kind::REGEXP_DIFF},
+    {REGEXP_STAR, cvc5::Kind::REGEXP_STAR},
+    {REGEXP_PLUS, cvc5::Kind::REGEXP_PLUS},
+    {REGEXP_OPT, cvc5::Kind::REGEXP_OPT},
+    {REGEXP_RANGE, cvc5::Kind::REGEXP_RANGE},
+    {REGEXP_REPEAT, cvc5::Kind::REGEXP_REPEAT},
+    {REGEXP_LOOP, cvc5::Kind::REGEXP_LOOP},
+    {REGEXP_EMPTY, cvc5::Kind::REGEXP_EMPTY},
+    {REGEXP_SIGMA, cvc5::Kind::REGEXP_SIGMA},
+    {REGEXP_COMPLEMENT, cvc5::Kind::REGEXP_COMPLEMENT},
+    // maps to the same kind as the string versions
+    {SEQ_CONCAT, cvc5::Kind::STRING_CONCAT},
+    {SEQ_LENGTH, cvc5::Kind::STRING_LENGTH},
+    {SEQ_EXTRACT, cvc5::Kind::STRING_SUBSTR},
+    {SEQ_UPDATE, cvc5::Kind::STRING_UPDATE},
+    {SEQ_AT, cvc5::Kind::STRING_CHARAT},
+    {SEQ_CONTAINS, cvc5::Kind::STRING_STRCTN},
+    {SEQ_INDEXOF, cvc5::Kind::STRING_STRIDOF},
+    {SEQ_REPLACE, cvc5::Kind::STRING_STRREPL},
+    {SEQ_REPLACE_ALL, cvc5::Kind::STRING_STRREPLALL},
+    {SEQ_REV, cvc5::Kind::STRING_REV},
+    {SEQ_PREFIX, cvc5::Kind::STRING_PREFIX},
+    {SEQ_SUFFIX, cvc5::Kind::STRING_SUFFIX},
+    {CONST_SEQUENCE, cvc5::Kind::CONST_SEQUENCE},
+    {SEQ_UNIT, cvc5::Kind::SEQ_UNIT},
+    {SEQ_NTH, cvc5::Kind::SEQ_NTH},
+    /* Quantifiers --------------------------------------------------------- */
+    {FORALL, cvc5::Kind::FORALL},
+    {EXISTS, cvc5::Kind::EXISTS},
+    {BOUND_VAR_LIST, cvc5::Kind::BOUND_VAR_LIST},
+    {INST_PATTERN, cvc5::Kind::INST_PATTERN},
+    {INST_NO_PATTERN, cvc5::Kind::INST_NO_PATTERN},
+    {INST_ATTRIBUTE, cvc5::Kind::INST_ATTRIBUTE},
+    {INST_PATTERN_LIST, cvc5::Kind::INST_PATTERN_LIST},
+    {LAST_KIND, cvc5::Kind::LAST_KIND},
+};
+
+/* Mapping from internal kind to external (API) kind. */
+const static std::unordered_map<cvc5::Kind, Kind, cvc5::kind::KindHashFunction>
+    s_kinds_internal{
+        {cvc5::Kind::UNDEFINED_KIND, UNDEFINED_KIND},
+        {cvc5::Kind::NULL_EXPR, NULL_EXPR},
+        /* Builtin --------------------------------------------------------- */
+        {cvc5::Kind::UNINTERPRETED_CONSTANT, UNINTERPRETED_CONSTANT},
+        {cvc5::Kind::ABSTRACT_VALUE, ABSTRACT_VALUE},
+        {cvc5::Kind::EQUAL, EQUAL},
+        {cvc5::Kind::DISTINCT, DISTINCT},
+        {cvc5::Kind::VARIABLE, CONSTANT},
+        {cvc5::Kind::BOUND_VARIABLE, VARIABLE},
+        {cvc5::Kind::SEXPR, SEXPR},
+        {cvc5::Kind::LAMBDA, LAMBDA},
+        {cvc5::Kind::WITNESS, WITNESS},
+        /* Boolean --------------------------------------------------------- */
+        {cvc5::Kind::CONST_BOOLEAN, CONST_BOOLEAN},
+        {cvc5::Kind::NOT, NOT},
+        {cvc5::Kind::AND, AND},
+        {cvc5::Kind::IMPLIES, IMPLIES},
+        {cvc5::Kind::OR, OR},
+        {cvc5::Kind::XOR, XOR},
+        {cvc5::Kind::ITE, ITE},
+        {cvc5::Kind::MATCH, MATCH},
+        {cvc5::Kind::MATCH_CASE, MATCH_CASE},
+        {cvc5::Kind::MATCH_BIND_CASE, MATCH_BIND_CASE},
+        /* UF -------------------------------------------------------------- */
+        {cvc5::Kind::APPLY_UF, APPLY_UF},
+        {cvc5::Kind::CARDINALITY_CONSTRAINT, CARDINALITY_CONSTRAINT},
+        {cvc5::Kind::CARDINALITY_VALUE, CARDINALITY_VALUE},
+        {cvc5::Kind::HO_APPLY, HO_APPLY},
+        /* Arithmetic ------------------------------------------------------ */
+        {cvc5::Kind::PLUS, PLUS},
+        {cvc5::Kind::MULT, MULT},
+        {cvc5::Kind::IAND, IAND},
+        {cvc5::Kind::MINUS, MINUS},
+        {cvc5::Kind::UMINUS, UMINUS},
+        {cvc5::Kind::DIVISION, DIVISION},
+        {cvc5::Kind::DIVISION_TOTAL, INTERNAL_KIND},
+        {cvc5::Kind::INTS_DIVISION, INTS_DIVISION},
+        {cvc5::Kind::INTS_DIVISION_TOTAL, INTERNAL_KIND},
+        {cvc5::Kind::INTS_MODULUS, INTS_MODULUS},
+        {cvc5::Kind::INTS_MODULUS_TOTAL, INTERNAL_KIND},
+        {cvc5::Kind::ABS, ABS},
+        {cvc5::Kind::DIVISIBLE, DIVISIBLE},
+        {cvc5::Kind::POW, POW},
+        {cvc5::Kind::EXPONENTIAL, EXPONENTIAL},
+        {cvc5::Kind::SINE, SINE},
+        {cvc5::Kind::COSINE, COSINE},
+        {cvc5::Kind::TANGENT, TANGENT},
+        {cvc5::Kind::COSECANT, COSECANT},
+        {cvc5::Kind::SECANT, SECANT},
+        {cvc5::Kind::COTANGENT, COTANGENT},
+        {cvc5::Kind::ARCSINE, ARCSINE},
+        {cvc5::Kind::ARCCOSINE, ARCCOSINE},
+        {cvc5::Kind::ARCTANGENT, ARCTANGENT},
+        {cvc5::Kind::ARCCOSECANT, ARCCOSECANT},
+        {cvc5::Kind::ARCSECANT, ARCSECANT},
+        {cvc5::Kind::ARCCOTANGENT, ARCCOTANGENT},
+        {cvc5::Kind::SQRT, SQRT},
+        {cvc5::Kind::DIVISIBLE_OP, DIVISIBLE},
+        {cvc5::Kind::CONST_RATIONAL, CONST_RATIONAL},
+        {cvc5::Kind::LT, LT},
+        {cvc5::Kind::LEQ, LEQ},
+        {cvc5::Kind::GT, GT},
+        {cvc5::Kind::GEQ, GEQ},
+        {cvc5::Kind::IS_INTEGER, IS_INTEGER},
+        {cvc5::Kind::TO_INTEGER, TO_INTEGER},
+        {cvc5::Kind::TO_REAL, TO_REAL},
+        {cvc5::Kind::PI, PI},
+        /* BV -------------------------------------------------------------- */
+        {cvc5::Kind::CONST_BITVECTOR, CONST_BITVECTOR},
+        {cvc5::Kind::BITVECTOR_CONCAT, BITVECTOR_CONCAT},
+        {cvc5::Kind::BITVECTOR_AND, BITVECTOR_AND},
+        {cvc5::Kind::BITVECTOR_OR, BITVECTOR_OR},
+        {cvc5::Kind::BITVECTOR_XOR, BITVECTOR_XOR},
+        {cvc5::Kind::BITVECTOR_NOT, BITVECTOR_NOT},
+        {cvc5::Kind::BITVECTOR_NAND, BITVECTOR_NAND},
+        {cvc5::Kind::BITVECTOR_NOR, BITVECTOR_NOR},
+        {cvc5::Kind::BITVECTOR_XNOR, BITVECTOR_XNOR},
+        {cvc5::Kind::BITVECTOR_COMP, BITVECTOR_COMP},
+        {cvc5::Kind::BITVECTOR_MULT, BITVECTOR_MULT},
+        {cvc5::Kind::BITVECTOR_PLUS, BITVECTOR_PLUS},
+        {cvc5::Kind::BITVECTOR_SUB, BITVECTOR_SUB},
+        {cvc5::Kind::BITVECTOR_NEG, BITVECTOR_NEG},
+        {cvc5::Kind::BITVECTOR_UDIV, BITVECTOR_UDIV},
+        {cvc5::Kind::BITVECTOR_UREM, BITVECTOR_UREM},
+        {cvc5::Kind::BITVECTOR_SDIV, BITVECTOR_SDIV},
+        {cvc5::Kind::BITVECTOR_SREM, BITVECTOR_SREM},
+        {cvc5::Kind::BITVECTOR_SMOD, BITVECTOR_SMOD},
+        {cvc5::Kind::BITVECTOR_SHL, BITVECTOR_SHL},
+        {cvc5::Kind::BITVECTOR_LSHR, BITVECTOR_LSHR},
+        {cvc5::Kind::BITVECTOR_ASHR, BITVECTOR_ASHR},
+        {cvc5::Kind::BITVECTOR_ULT, BITVECTOR_ULT},
+        {cvc5::Kind::BITVECTOR_ULE, BITVECTOR_ULE},
+        {cvc5::Kind::BITVECTOR_UGT, BITVECTOR_UGT},
+        {cvc5::Kind::BITVECTOR_UGE, BITVECTOR_UGE},
+        {cvc5::Kind::BITVECTOR_SLT, BITVECTOR_SLT},
+        {cvc5::Kind::BITVECTOR_SLE, BITVECTOR_SLE},
+        {cvc5::Kind::BITVECTOR_SGT, BITVECTOR_SGT},
+        {cvc5::Kind::BITVECTOR_SGE, BITVECTOR_SGE},
+        {cvc5::Kind::BITVECTOR_ULTBV, BITVECTOR_ULTBV},
+        {cvc5::Kind::BITVECTOR_SLTBV, BITVECTOR_SLTBV},
+        {cvc5::Kind::BITVECTOR_ITE, BITVECTOR_ITE},
+        {cvc5::Kind::BITVECTOR_REDOR, BITVECTOR_REDOR},
+        {cvc5::Kind::BITVECTOR_REDAND, BITVECTOR_REDAND},
+        {cvc5::Kind::BITVECTOR_EXTRACT_OP, BITVECTOR_EXTRACT},
+        {cvc5::Kind::BITVECTOR_REPEAT_OP, BITVECTOR_REPEAT},
+        {cvc5::Kind::BITVECTOR_ZERO_EXTEND_OP, BITVECTOR_ZERO_EXTEND},
+        {cvc5::Kind::BITVECTOR_SIGN_EXTEND_OP, BITVECTOR_SIGN_EXTEND},
+        {cvc5::Kind::BITVECTOR_ROTATE_LEFT_OP, BITVECTOR_ROTATE_LEFT},
+        {cvc5::Kind::BITVECTOR_ROTATE_RIGHT_OP, BITVECTOR_ROTATE_RIGHT},
+        {cvc5::Kind::BITVECTOR_EXTRACT, BITVECTOR_EXTRACT},
+        {cvc5::Kind::BITVECTOR_REPEAT, BITVECTOR_REPEAT},
+        {cvc5::Kind::BITVECTOR_ZERO_EXTEND, BITVECTOR_ZERO_EXTEND},
+        {cvc5::Kind::BITVECTOR_SIGN_EXTEND, BITVECTOR_SIGN_EXTEND},
+        {cvc5::Kind::BITVECTOR_ROTATE_LEFT, BITVECTOR_ROTATE_LEFT},
+        {cvc5::Kind::BITVECTOR_ROTATE_RIGHT, BITVECTOR_ROTATE_RIGHT},
+        {cvc5::Kind::INT_TO_BITVECTOR_OP, INT_TO_BITVECTOR},
+        {cvc5::Kind::INT_TO_BITVECTOR, INT_TO_BITVECTOR},
+        {cvc5::Kind::BITVECTOR_TO_NAT, BITVECTOR_TO_NAT},
+        /* FP -------------------------------------------------------------- */
+        {cvc5::Kind::CONST_FLOATINGPOINT, CONST_FLOATINGPOINT},
+        {cvc5::Kind::CONST_ROUNDINGMODE, CONST_ROUNDINGMODE},
+        {cvc5::Kind::FLOATINGPOINT_FP, FLOATINGPOINT_FP},
+        {cvc5::Kind::FLOATINGPOINT_EQ, FLOATINGPOINT_EQ},
+        {cvc5::Kind::FLOATINGPOINT_ABS, FLOATINGPOINT_ABS},
+        {cvc5::Kind::FLOATINGPOINT_NEG, FLOATINGPOINT_NEG},
+        {cvc5::Kind::FLOATINGPOINT_PLUS, FLOATINGPOINT_PLUS},
+        {cvc5::Kind::FLOATINGPOINT_SUB, FLOATINGPOINT_SUB},
+        {cvc5::Kind::FLOATINGPOINT_MULT, FLOATINGPOINT_MULT},
+        {cvc5::Kind::FLOATINGPOINT_DIV, FLOATINGPOINT_DIV},
+        {cvc5::Kind::FLOATINGPOINT_FMA, FLOATINGPOINT_FMA},
+        {cvc5::Kind::FLOATINGPOINT_SQRT, FLOATINGPOINT_SQRT},
+        {cvc5::Kind::FLOATINGPOINT_REM, FLOATINGPOINT_REM},
+        {cvc5::Kind::FLOATINGPOINT_RTI, FLOATINGPOINT_RTI},
+        {cvc5::Kind::FLOATINGPOINT_MIN, FLOATINGPOINT_MIN},
+        {cvc5::Kind::FLOATINGPOINT_MAX, FLOATINGPOINT_MAX},
+        {cvc5::Kind::FLOATINGPOINT_LEQ, FLOATINGPOINT_LEQ},
+        {cvc5::Kind::FLOATINGPOINT_LT, FLOATINGPOINT_LT},
+        {cvc5::Kind::FLOATINGPOINT_GEQ, FLOATINGPOINT_GEQ},
+        {cvc5::Kind::FLOATINGPOINT_GT, FLOATINGPOINT_GT},
+        {cvc5::Kind::FLOATINGPOINT_ISN, FLOATINGPOINT_ISN},
+        {cvc5::Kind::FLOATINGPOINT_ISSN, FLOATINGPOINT_ISSN},
+        {cvc5::Kind::FLOATINGPOINT_ISZ, FLOATINGPOINT_ISZ},
+        {cvc5::Kind::FLOATINGPOINT_ISINF, FLOATINGPOINT_ISINF},
+        {cvc5::Kind::FLOATINGPOINT_ISNAN, FLOATINGPOINT_ISNAN},
+        {cvc5::Kind::FLOATINGPOINT_ISNEG, FLOATINGPOINT_ISNEG},
+        {cvc5::Kind::FLOATINGPOINT_ISPOS, FLOATINGPOINT_ISPOS},
+        {cvc5::Kind::FLOATINGPOINT_TO_FP_IEEE_BITVECTOR_OP,
+         FLOATINGPOINT_TO_FP_IEEE_BITVECTOR},
+        {cvc5::Kind::FLOATINGPOINT_TO_FP_IEEE_BITVECTOR,
+         FLOATINGPOINT_TO_FP_IEEE_BITVECTOR},
+        {cvc5::Kind::FLOATINGPOINT_TO_FP_FLOATINGPOINT_OP,
+         FLOATINGPOINT_TO_FP_FLOATINGPOINT},
+        {cvc5::Kind::FLOATINGPOINT_TO_FP_FLOATINGPOINT,
+         FLOATINGPOINT_TO_FP_FLOATINGPOINT},
+        {cvc5::Kind::FLOATINGPOINT_TO_FP_REAL_OP, FLOATINGPOINT_TO_FP_REAL},
+        {cvc5::Kind::FLOATINGPOINT_TO_FP_REAL, FLOATINGPOINT_TO_FP_REAL},
+        {cvc5::Kind::FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR_OP,
+         FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR},
+        {cvc5::Kind::FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR,
+         FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR},
+        {cvc5::Kind::FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR_OP,
+         FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR},
+        {cvc5::Kind::FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR,
+         FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR},
+        {cvc5::Kind::FLOATINGPOINT_TO_FP_GENERIC_OP,
+         FLOATINGPOINT_TO_FP_GENERIC},
+        {cvc5::Kind::FLOATINGPOINT_TO_FP_GENERIC, FLOATINGPOINT_TO_FP_GENERIC},
+        {cvc5::Kind::FLOATINGPOINT_TO_UBV_OP, FLOATINGPOINT_TO_UBV},
+        {cvc5::Kind::FLOATINGPOINT_TO_UBV, FLOATINGPOINT_TO_UBV},
+        {cvc5::Kind::FLOATINGPOINT_TO_UBV_TOTAL_OP, INTERNAL_KIND},
+        {cvc5::Kind::FLOATINGPOINT_TO_UBV_TOTAL, INTERNAL_KIND},
+        {cvc5::Kind::FLOATINGPOINT_TO_SBV_OP, FLOATINGPOINT_TO_SBV},
+        {cvc5::Kind::FLOATINGPOINT_TO_SBV, FLOATINGPOINT_TO_SBV},
+        {cvc5::Kind::FLOATINGPOINT_TO_SBV_TOTAL_OP, INTERNAL_KIND},
+        {cvc5::Kind::FLOATINGPOINT_TO_SBV_TOTAL, INTERNAL_KIND},
+        {cvc5::Kind::FLOATINGPOINT_TO_REAL, FLOATINGPOINT_TO_REAL},
+        {cvc5::Kind::FLOATINGPOINT_TO_REAL_TOTAL, INTERNAL_KIND},
+        /* Arrays ---------------------------------------------------------- */
+        {cvc5::Kind::SELECT, SELECT},
+        {cvc5::Kind::STORE, STORE},
+        {cvc5::Kind::STORE_ALL, CONST_ARRAY},
+        /* Datatypes ------------------------------------------------------- */
+        {cvc5::Kind::APPLY_SELECTOR, APPLY_SELECTOR},
+        {cvc5::Kind::APPLY_CONSTRUCTOR, APPLY_CONSTRUCTOR},
+        {cvc5::Kind::APPLY_SELECTOR_TOTAL, INTERNAL_KIND},
+        {cvc5::Kind::APPLY_TESTER, APPLY_TESTER},
+        {cvc5::Kind::TUPLE_UPDATE_OP, TUPLE_UPDATE},
+        {cvc5::Kind::TUPLE_UPDATE, TUPLE_UPDATE},
+        {cvc5::Kind::RECORD_UPDATE_OP, RECORD_UPDATE},
+        {cvc5::Kind::RECORD_UPDATE, RECORD_UPDATE},
+        {cvc5::Kind::DT_SIZE, DT_SIZE},
+        {cvc5::Kind::TUPLE_PROJECT, TUPLE_PROJECT},
+        /* Separation Logic ------------------------------------------------ */
+        {cvc5::Kind::SEP_NIL, SEP_NIL},
+        {cvc5::Kind::SEP_EMP, SEP_EMP},
+        {cvc5::Kind::SEP_PTO, SEP_PTO},
+        {cvc5::Kind::SEP_STAR, SEP_STAR},
+        {cvc5::Kind::SEP_WAND, SEP_WAND},
+        /* Sets ------------------------------------------------------------ */
+        {cvc5::Kind::EMPTYSET, EMPTYSET},
+        {cvc5::Kind::UNION, UNION},
+        {cvc5::Kind::INTERSECTION, INTERSECTION},
+        {cvc5::Kind::SETMINUS, SETMINUS},
+        {cvc5::Kind::SUBSET, SUBSET},
+        {cvc5::Kind::MEMBER, MEMBER},
+        {cvc5::Kind::SINGLETON, SINGLETON},
+        {cvc5::Kind::INSERT, INSERT},
+        {cvc5::Kind::CARD, CARD},
+        {cvc5::Kind::COMPLEMENT, COMPLEMENT},
+        {cvc5::Kind::UNIVERSE_SET, UNIVERSE_SET},
+        {cvc5::Kind::JOIN, JOIN},
+        {cvc5::Kind::PRODUCT, PRODUCT},
+        {cvc5::Kind::TRANSPOSE, TRANSPOSE},
+        {cvc5::Kind::TCLOSURE, TCLOSURE},
+        {cvc5::Kind::JOIN_IMAGE, JOIN_IMAGE},
+        {cvc5::Kind::IDEN, IDEN},
+        {cvc5::Kind::COMPREHENSION, COMPREHENSION},
+        {cvc5::Kind::CHOOSE, CHOOSE},
+        {cvc5::Kind::IS_SINGLETON, IS_SINGLETON},
+        /* Bags ------------------------------------------------------------ */
+        {cvc5::Kind::UNION_MAX, UNION_MAX},
+        {cvc5::Kind::UNION_DISJOINT, UNION_DISJOINT},
+        {cvc5::Kind::INTERSECTION_MIN, INTERSECTION_MIN},
+        {cvc5::Kind::DIFFERENCE_SUBTRACT, DIFFERENCE_SUBTRACT},
+        {cvc5::Kind::DIFFERENCE_REMOVE, DIFFERENCE_REMOVE},
+        {cvc5::Kind::SUBBAG, SUBBAG},
+        {cvc5::Kind::BAG_COUNT, BAG_COUNT},
+        {cvc5::Kind::DUPLICATE_REMOVAL, DUPLICATE_REMOVAL},
+        {cvc5::Kind::MK_BAG, MK_BAG},
+        {cvc5::Kind::EMPTYBAG, EMPTYBAG},
+        {cvc5::Kind::BAG_CARD, BAG_CARD},
+        {cvc5::Kind::BAG_CHOOSE, BAG_CHOOSE},
+        {cvc5::Kind::BAG_IS_SINGLETON, BAG_IS_SINGLETON},
+        {cvc5::Kind::BAG_FROM_SET, BAG_FROM_SET},
+        {cvc5::Kind::BAG_TO_SET, BAG_TO_SET},
+        /* Strings --------------------------------------------------------- */
+        {cvc5::Kind::STRING_CONCAT, STRING_CONCAT},
+        {cvc5::Kind::STRING_IN_REGEXP, STRING_IN_REGEXP},
+        {cvc5::Kind::STRING_LENGTH, STRING_LENGTH},
+        {cvc5::Kind::STRING_SUBSTR, STRING_SUBSTR},
+        {cvc5::Kind::STRING_UPDATE, STRING_UPDATE},
+        {cvc5::Kind::STRING_CHARAT, STRING_CHARAT},
+        {cvc5::Kind::STRING_STRCTN, STRING_CONTAINS},
+        {cvc5::Kind::STRING_STRIDOF, STRING_INDEXOF},
+        {cvc5::Kind::STRING_STRREPL, STRING_REPLACE},
+        {cvc5::Kind::STRING_STRREPLALL, STRING_REPLACE_ALL},
+        {cvc5::Kind::STRING_REPLACE_RE, STRING_REPLACE_RE},
+        {cvc5::Kind::STRING_REPLACE_RE_ALL, STRING_REPLACE_RE_ALL},
+        {cvc5::Kind::STRING_TOLOWER, STRING_TOLOWER},
+        {cvc5::Kind::STRING_TOUPPER, STRING_TOUPPER},
+        {cvc5::Kind::STRING_REV, STRING_REV},
+        {cvc5::Kind::STRING_FROM_CODE, STRING_FROM_CODE},
+        {cvc5::Kind::STRING_TO_CODE, STRING_TO_CODE},
+        {cvc5::Kind::STRING_LT, STRING_LT},
+        {cvc5::Kind::STRING_LEQ, STRING_LEQ},
+        {cvc5::Kind::STRING_PREFIX, STRING_PREFIX},
+        {cvc5::Kind::STRING_SUFFIX, STRING_SUFFIX},
+        {cvc5::Kind::STRING_IS_DIGIT, STRING_IS_DIGIT},
+        {cvc5::Kind::STRING_ITOS, STRING_FROM_INT},
+        {cvc5::Kind::STRING_STOI, STRING_TO_INT},
+        {cvc5::Kind::CONST_STRING, CONST_STRING},
+        {cvc5::Kind::STRING_TO_REGEXP, STRING_TO_REGEXP},
+        {cvc5::Kind::REGEXP_CONCAT, REGEXP_CONCAT},
+        {cvc5::Kind::REGEXP_UNION, REGEXP_UNION},
+        {cvc5::Kind::REGEXP_INTER, REGEXP_INTER},
+        {cvc5::Kind::REGEXP_DIFF, REGEXP_DIFF},
+        {cvc5::Kind::REGEXP_STAR, REGEXP_STAR},
+        {cvc5::Kind::REGEXP_PLUS, REGEXP_PLUS},
+        {cvc5::Kind::REGEXP_OPT, REGEXP_OPT},
+        {cvc5::Kind::REGEXP_RANGE, REGEXP_RANGE},
+        {cvc5::Kind::REGEXP_REPEAT, REGEXP_REPEAT},
+        {cvc5::Kind::REGEXP_REPEAT_OP, REGEXP_REPEAT},
+        {cvc5::Kind::REGEXP_LOOP, REGEXP_LOOP},
+        {cvc5::Kind::REGEXP_LOOP_OP, REGEXP_LOOP},
+        {cvc5::Kind::REGEXP_EMPTY, REGEXP_EMPTY},
+        {cvc5::Kind::REGEXP_SIGMA, REGEXP_SIGMA},
+        {cvc5::Kind::REGEXP_COMPLEMENT, REGEXP_COMPLEMENT},
+        {cvc5::Kind::CONST_SEQUENCE, CONST_SEQUENCE},
+        {cvc5::Kind::SEQ_UNIT, SEQ_UNIT},
+        {cvc5::Kind::SEQ_NTH, SEQ_NTH},
+        /* Quantifiers ----------------------------------------------------- */
+        {cvc5::Kind::FORALL, FORALL},
+        {cvc5::Kind::EXISTS, EXISTS},
+        {cvc5::Kind::BOUND_VAR_LIST, BOUND_VAR_LIST},
+        {cvc5::Kind::INST_PATTERN, INST_PATTERN},
+        {cvc5::Kind::INST_NO_PATTERN, INST_NO_PATTERN},
+        {cvc5::Kind::INST_ATTRIBUTE, INST_ATTRIBUTE},
+        {cvc5::Kind::INST_PATTERN_LIST, INST_PATTERN_LIST},
+        /* ----------------------------------------------------------------- */
+        {cvc5::Kind::LAST_KIND, LAST_KIND},
+    };
+
+/* Set of kinds for indexed operators */
+const static std::unordered_set<Kind, KindHashFunction> s_indexed_kinds(
+    {RECORD_UPDATE,
+     DIVISIBLE,
+     IAND,
+     BITVECTOR_REPEAT,
+     BITVECTOR_ZERO_EXTEND,
+     BITVECTOR_SIGN_EXTEND,
+     BITVECTOR_ROTATE_LEFT,
+     BITVECTOR_ROTATE_RIGHT,
+     INT_TO_BITVECTOR,
+     FLOATINGPOINT_TO_UBV,
+     FLOATINGPOINT_TO_SBV,
+     TUPLE_UPDATE,
+     BITVECTOR_EXTRACT,
+     FLOATINGPOINT_TO_FP_IEEE_BITVECTOR,
+     FLOATINGPOINT_TO_FP_FLOATINGPOINT,
+     FLOATINGPOINT_TO_FP_REAL,
+     FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR,
+     FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR,
+     FLOATINGPOINT_TO_FP_GENERIC});
+
+namespace {
+
+/** Convert a cvc5::Kind (internal) to a cvc5::api::Kind (external). */
+cvc5::api::Kind intToExtKind(cvc5::Kind k)
+{
+  auto it = api::s_kinds_internal.find(k);
+  if (it == api::s_kinds_internal.end())
+  {
+    return api::INTERNAL_KIND;
+  }
+  return it->second;
+}
+
+/** Convert a cvc5::api::Kind (external) to a cvc5::Kind (internal). */
+cvc5::Kind extToIntKind(cvc5::api::Kind k)
+{
+  auto it = api::s_kinds.find(k);
+  if (it == api::s_kinds.end())
+  {
+    return cvc5::Kind::UNDEFINED_KIND;
+  }
+  return it->second;
+}
+
+/** Return true if given kind is a defined external kind. */
+bool isDefinedKind(Kind k) { return k > UNDEFINED_KIND && k < LAST_KIND; }
+
+/**
+ * Return true if the internal kind is one where the API term structure
+ * differs from internal structure. This happens for APPLY_* kinds.
+ * The API takes a "higher-order" perspective and treats functions as well
+ * as datatype constructors/selectors/testers as terms
+ * but interally they are not
+ */
+bool isApplyKind(cvc5::Kind k)
+{
+  return (k == cvc5::Kind::APPLY_UF || k == cvc5::Kind::APPLY_CONSTRUCTOR
+          || k == cvc5::Kind::APPLY_SELECTOR || k == cvc5::Kind::APPLY_TESTER);
+}
+
+#ifdef CVC4_ASSERTIONS
+/** Return true if given kind is a defined internal kind. */
+bool isDefinedIntKind(cvc5::Kind k)
+{
+  return k != cvc5::Kind::UNDEFINED_KIND && k != cvc5::Kind::LAST_KIND;
+}
+#endif
+
+/** Return the minimum arity of given kind. */
+uint32_t minArity(Kind k)
+{
+  Assert(isDefinedKind(k));
+  Assert(isDefinedIntKind(extToIntKind(k)));
+  uint32_t min = cvc5::kind::metakind::getMinArityForKind(extToIntKind(k));
+
+  // At the API level, we treat functions/constructors/selectors/testers as
+  // normal terms instead of making them part of the operator
+  if (isApplyKind(extToIntKind(k)))
+  {
+    min++;
+  }
+  return min;
+}
+
+/** Return the maximum arity of given kind. */
+uint32_t maxArity(Kind k)
+{
+  Assert(isDefinedKind(k));
+  Assert(isDefinedIntKind(extToIntKind(k)));
+  uint32_t max = cvc5::kind::metakind::getMaxArityForKind(extToIntKind(k));
+
+  // At the API level, we treat functions/constructors/selectors/testers as
+  // normal terms instead of making them part of the operator
+  if (isApplyKind(extToIntKind(k))
+      && max != std::numeric_limits<uint32_t>::max())  // be careful not to
+                                                       // overflow
+  {
+    max++;
+  }
+  return max;
+}
+
+}  // namespace
+
+std::string kindToString(Kind k)
+{
+  return k == INTERNAL_KIND ? "INTERNAL_KIND"
+                            : cvc5::kind::kindToString(extToIntKind(k));
+}
+
+std::ostream& operator<<(std::ostream& out, Kind k)
+{
+  switch (k)
+  {
+    case INTERNAL_KIND: out << "INTERNAL_KIND"; break;
+    default: out << extToIntKind(k);
+  }
+  return out;
+}
+
+size_t KindHashFunction::operator()(Kind k) const { return k; }
+
+/* -------------------------------------------------------------------------- */
+/* API guard helpers                                                          */
+/* -------------------------------------------------------------------------- */
+
+namespace {
+
+class CVC4ApiExceptionStream
+{
+ public:
+  CVC4ApiExceptionStream() {}
+  /* Note: This needs to be explicitly set to 'noexcept(false)' since it is
+   * a destructor that throws an exception and in C++11 all destructors
+   * default to noexcept(true) (else this triggers a call to std::terminate). */
+  ~CVC4ApiExceptionStream() noexcept(false)
+  {
+    if (std::uncaught_exceptions() == 0)
+    {
+      throw CVC4ApiException(d_stream.str());
+    }
+  }
+
+  std::ostream& ostream() { return d_stream; }
+
+ private:
+  std::stringstream d_stream;
+};
+
+class CVC4ApiRecoverableExceptionStream
+{
+ public:
+  CVC4ApiRecoverableExceptionStream() {}
+  /* Note: This needs to be explicitly set to 'noexcept(false)' since it is
+   * a destructor that throws an exception and in C++11 all destructors
+   * default to noexcept(true) (else this triggers a call to std::terminate). */
+  ~CVC4ApiRecoverableExceptionStream() noexcept(false)
+  {
+    if (std::uncaught_exceptions() == 0)
+    {
+      throw CVC4ApiRecoverableException(d_stream.str());
+    }
+  }
+
+  std::ostream& ostream() { return d_stream; }
+
+ private:
+  std::stringstream d_stream;
+};
+
+#define CVC4_API_TRY_CATCH_BEGIN \
+  try                            \
+  {
+#define CVC4_API_TRY_CATCH_END                                                 \
+  }                                                                            \
+  catch (const UnrecognizedOptionException& e)                                 \
+  {                                                                            \
+    throw CVC4ApiRecoverableException(e.getMessage());                         \
+  }                                                                            \
+  catch (const cvc5::RecoverableModalException& e)                             \
+  {                                                                            \
+    throw CVC4ApiRecoverableException(e.getMessage());                         \
+  }                                                                            \
+  catch (const cvc5::Exception& e) { throw CVC4ApiException(e.getMessage()); } \
+  catch (const std::invalid_argument& e) { throw CVC4ApiException(e.what()); }
+
+}  // namespace
+
+/* -------------------------------------------------------------------------- */
+/* Result                                                                     */
+/* -------------------------------------------------------------------------- */
+
+Result::Result(const cvc5::Result& r) : d_result(new cvc5::Result(r)) {}
+
+Result::Result() : d_result(new cvc5::Result()) {}
+
+bool Result::isNull() const
+{
+  return d_result->getType() == cvc5::Result::TYPE_NONE;
+}
+
+bool Result::isSat(void) const
+{
+  return d_result->getType() == cvc5::Result::TYPE_SAT
+         && d_result->isSat() == cvc5::Result::SAT;
+}
+
+bool Result::isUnsat(void) const
+{
+  return d_result->getType() == cvc5::Result::TYPE_SAT
+         && d_result->isSat() == cvc5::Result::UNSAT;
+}
+
+bool Result::isSatUnknown(void) const
+{
+  return d_result->getType() == cvc5::Result::TYPE_SAT
+         && d_result->isSat() == cvc5::Result::SAT_UNKNOWN;
+}
+
+bool Result::isEntailed(void) const
+{
+  return d_result->getType() == cvc5::Result::TYPE_ENTAILMENT
+         && d_result->isEntailed() == cvc5::Result::ENTAILED;
+}
+
+bool Result::isNotEntailed(void) const
+{
+  return d_result->getType() == cvc5::Result::TYPE_ENTAILMENT
+         && d_result->isEntailed() == cvc5::Result::NOT_ENTAILED;
+}
+
+bool Result::isEntailmentUnknown(void) const
+{
+  return d_result->getType() == cvc5::Result::TYPE_ENTAILMENT
+         && d_result->isEntailed() == cvc5::Result::ENTAILMENT_UNKNOWN;
+}
+
+bool Result::operator==(const Result& r) const
+{
+  return *d_result == *r.d_result;
+}
+
+bool Result::operator!=(const Result& r) const
+{
+  return *d_result != *r.d_result;
+}
+
+Result::UnknownExplanation Result::getUnknownExplanation(void) const
+{
+  cvc5::Result::UnknownExplanation expl = d_result->whyUnknown();
+  switch (expl)
+  {
+    case cvc5::Result::REQUIRES_FULL_CHECK: return REQUIRES_FULL_CHECK;
+    case cvc5::Result::INCOMPLETE: return INCOMPLETE;
+    case cvc5::Result::TIMEOUT: return TIMEOUT;
+    case cvc5::Result::RESOURCEOUT: return RESOURCEOUT;
+    case cvc5::Result::MEMOUT: return MEMOUT;
+    case cvc5::Result::INTERRUPTED: return INTERRUPTED;
+    case cvc5::Result::NO_STATUS: return NO_STATUS;
+    case cvc5::Result::UNSUPPORTED: return UNSUPPORTED;
+    case cvc5::Result::OTHER: return OTHER;
+    default: return UNKNOWN_REASON;
+  }
+  return UNKNOWN_REASON;
+}
+
+std::string Result::toString(void) const { return d_result->toString(); }
+
+std::ostream& operator<<(std::ostream& out, const Result& r)
+{
+  out << r.toString();
+  return out;
+}
+
+std::ostream& operator<<(std::ostream& out, enum Result::UnknownExplanation e)
+{
+  switch (e)
+  {
+    case Result::REQUIRES_FULL_CHECK: out << "REQUIRES_FULL_CHECK"; break;
+    case Result::INCOMPLETE: out << "INCOMPLETE"; break;
+    case Result::TIMEOUT: out << "TIMEOUT"; break;
+    case Result::RESOURCEOUT: out << "RESOURCEOUT"; break;
+    case Result::MEMOUT: out << "MEMOUT"; break;
+    case Result::INTERRUPTED: out << "INTERRUPTED"; break;
+    case Result::NO_STATUS: out << "NO_STATUS"; break;
+    case Result::UNSUPPORTED: out << "UNSUPPORTED"; break;
+    case Result::OTHER: out << "OTHER"; break;
+    case Result::UNKNOWN_REASON: out << "UNKNOWN_REASON"; break;
+    default: Unhandled() << e;
+  }
+  return out;
+}
+
+/* -------------------------------------------------------------------------- */
+/* Sort                                                                       */
+/* -------------------------------------------------------------------------- */
+
+Sort::Sort(const Solver* slv, const cvc5::TypeNode& t)
+    : d_solver(slv), d_type(new cvc5::TypeNode(t))
+{
+}
+
+Sort::Sort() : d_solver(nullptr), d_type(new cvc5::TypeNode()) {}
+
+Sort::~Sort()
+{
+  if (d_solver != nullptr)
+  {
+    // Ensure that the correct node manager is in scope when the node is
+    // destroyed.
+    NodeManagerScope scope(d_solver->getNodeManager());
+    d_type.reset();
+  }
+}
+
+std::set<TypeNode> Sort::sortSetToTypeNodes(const std::set<Sort>& sorts)
+{
+  std::set<TypeNode> types;
+  for (const Sort& s : sorts)
+  {
+    types.insert(s.getTypeNode());
+  }
+  return types;
+}
+
+std::vector<TypeNode> Sort::sortVectorToTypeNodes(
+    const std::vector<Sort>& sorts)
+{
+  std::vector<TypeNode> typeNodes;
+  for (const Sort& sort : sorts)
+  {
+    typeNodes.push_back(sort.getTypeNode());
+  }
+  return typeNodes;
+}
+
+std::vector<Sort> Sort::typeNodeVectorToSorts(
+    const Solver* slv, const std::vector<TypeNode>& types)
+{
+  std::vector<Sort> sorts;
+  for (size_t i = 0, tsize = types.size(); i < tsize; i++)
+  {
+    sorts.push_back(Sort(slv, types[i]));
+  }
+  return sorts;
+}
+
+bool Sort::operator==(const Sort& s) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return *d_type == *s.d_type;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::operator!=(const Sort& s) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return *d_type != *s.d_type;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::operator<(const Sort& s) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return *d_type < *s.d_type;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::operator>(const Sort& s) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return *d_type > *s.d_type;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::operator<=(const Sort& s) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return *d_type <= *s.d_type;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::operator>=(const Sort& s) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return *d_type >= *s.d_type;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isNull() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return isNullHelper();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isBoolean() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return d_type->isBoolean();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isInteger() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return d_type->isInteger();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isReal() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  // notice that we do not expose internal subtyping to the user
+  return d_type->isReal() && !d_type->isInteger();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isString() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return d_type->isString();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isRegExp() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return d_type->isRegExp();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isRoundingMode() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return d_type->isRoundingMode();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isBitVector() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return d_type->isBitVector();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isFloatingPoint() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return d_type->isFloatingPoint();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isDatatype() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return d_type->isDatatype();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isParametricDatatype() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  if (!d_type->isDatatype()) return false;
+  return d_type->isParametricDatatype();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isConstructor() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return d_type->isConstructor();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isSelector() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return d_type->isSelector();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isTester() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return d_type->isTester();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isFunction() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return d_type->isFunction();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isPredicate() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return d_type->isPredicate();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isTuple() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return d_type->isTuple();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isRecord() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return d_type->isRecord();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isArray() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return d_type->isArray();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isSet() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return d_type->isSet();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isBag() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return d_type->isBag();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isSequence() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return d_type->isSequence();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isUninterpretedSort() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return d_type->isSort();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isSortConstructor() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return d_type->isSortConstructor();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isFirstClass() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return d_type->isFirstClass();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isFunctionLike() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return d_type->isFunctionLike();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isSubsortOf(const Sort& s) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_ARG_CHECK_SOLVER("sort", s);
+  //////// all checks before this line
+  return d_type->isSubtypeOf(*s.d_type);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isComparableTo(const Sort& s) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_ARG_CHECK_SOLVER("sort", s);
+  //////// all checks before this line
+  return d_type->isComparableTo(*s.d_type);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Datatype Sort::getDatatype() const
+{
+  NodeManagerScope scope(d_solver->getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isDatatype()) << "Expected datatype sort.";
+  //////// all checks before this line
+  return Datatype(d_solver, d_type->getDType());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Sort::instantiate(const std::vector<Sort>& params) const
+{
+  NodeManagerScope scope(d_solver->getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK_SORTS(params);
+  CVC4_API_CHECK(isParametricDatatype() || isSortConstructor())
+      << "Expected parametric datatype or sort constructor sort.";
+  //////// all checks before this line
+  std::vector<cvc5::TypeNode> tparams = sortVectorToTypeNodes(params);
+  if (d_type->isDatatype())
+  {
+    return Sort(d_solver, d_type->instantiateParametricDatatype(tparams));
+  }
+  Assert(d_type->isSortConstructor());
+  return Sort(d_solver, d_solver->getNodeManager()->mkSort(*d_type, tparams));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Sort::substitute(const Sort& sort, const Sort& replacement) const
+{
+  NodeManagerScope scope(d_solver->getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK_SORT(sort);
+  CVC4_API_CHECK_SORT(replacement);
+  //////// all checks before this line
+  return Sort(
+      d_solver,
+      d_type->substitute(sort.getTypeNode(), replacement.getTypeNode()));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Sort::substitute(const std::vector<Sort>& sorts,
+                      const std::vector<Sort>& replacements) const
+{
+  NodeManagerScope scope(d_solver->getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK_SORTS(sorts);
+  CVC4_API_CHECK_SORTS(replacements);
+  //////// all checks before this line
+
+  std::vector<cvc5::TypeNode> tSorts = sortVectorToTypeNodes(sorts),
+                              tReplacements =
+                                  sortVectorToTypeNodes(replacements);
+  return Sort(d_solver,
+              d_type->substitute(tSorts.begin(),
+                                 tSorts.end(),
+                                 tReplacements.begin(),
+                                 tReplacements.end()));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+std::string Sort::toString() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  if (d_solver != nullptr)
+  {
+    NodeManagerScope scope(d_solver->getNodeManager());
+    return d_type->toString();
+  }
+  return d_type->toString();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+const cvc5::TypeNode& Sort::getTypeNode(void) const { return *d_type; }
+
+/* Constructor sort ------------------------------------------------------- */
+
+size_t Sort::getConstructorArity() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isConstructor()) << "Not a constructor sort: " << (*this);
+  //////// all checks before this line
+  return d_type->getNumChildren() - 1;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+std::vector<Sort> Sort::getConstructorDomainSorts() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isConstructor()) << "Not a constructor sort: " << (*this);
+  //////// all checks before this line
+  return typeNodeVectorToSorts(d_solver, d_type->getArgTypes());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Sort::getConstructorCodomainSort() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isConstructor()) << "Not a constructor sort: " << (*this);
+  //////// all checks before this line
+  return Sort(d_solver, d_type->getConstructorRangeType());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/* Selector sort ------------------------------------------------------- */
+
+Sort Sort::getSelectorDomainSort() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isSelector()) << "Not a selector sort: " << (*this);
+  //////// all checks before this line
+  return Sort(d_solver, d_type->getSelectorDomainType());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Sort::getSelectorCodomainSort() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isSelector()) << "Not a selector sort: " << (*this);
+  //////// all checks before this line
+  return Sort(d_solver, d_type->getSelectorRangeType());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/* Tester sort ------------------------------------------------------- */
+
+Sort Sort::getTesterDomainSort() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isTester()) << "Not a tester sort: " << (*this);
+  //////// all checks before this line
+  return Sort(d_solver, d_type->getTesterDomainType());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Sort::getTesterCodomainSort() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isTester()) << "Not a tester sort: " << (*this);
+  //////// all checks before this line
+  return d_solver->getBooleanSort();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/* Function sort ------------------------------------------------------- */
+
+size_t Sort::getFunctionArity() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isFunction()) << "Not a function sort: " << (*this);
+  //////// all checks before this line
+  return d_type->getNumChildren() - 1;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+std::vector<Sort> Sort::getFunctionDomainSorts() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isFunction()) << "Not a function sort: " << (*this);
+  //////// all checks before this line
+  return typeNodeVectorToSorts(d_solver, d_type->getArgTypes());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Sort::getFunctionCodomainSort() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isFunction()) << "Not a function sort" << (*this);
+  //////// all checks before this line
+  return Sort(d_solver, d_type->getRangeType());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/* Array sort ---------------------------------------------------------- */
+
+Sort Sort::getArrayIndexSort() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isArray()) << "Not an array sort.";
+  //////// all checks before this line
+  return Sort(d_solver, d_type->getArrayIndexType());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Sort::getArrayElementSort() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isArray()) << "Not an array sort.";
+  //////// all checks before this line
+  return Sort(d_solver, d_type->getArrayConstituentType());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/* Set sort ------------------------------------------------------------ */
+
+Sort Sort::getSetElementSort() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isSet()) << "Not a set sort.";
+  //////// all checks before this line
+  return Sort(d_solver, d_type->getSetElementType());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/* Bag sort ------------------------------------------------------------ */
+
+Sort Sort::getBagElementSort() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isBag()) << "Not a bag sort.";
+  //////// all checks before this line
+  return Sort(d_solver, d_type->getBagElementType());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/* Sequence sort ------------------------------------------------------- */
+
+Sort Sort::getSequenceElementSort() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isSequence()) << "Not a sequence sort.";
+  //////// all checks before this line
+  return Sort(d_solver, d_type->getSequenceElementType());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/* Uninterpreted sort -------------------------------------------------- */
+
+std::string Sort::getUninterpretedSortName() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isUninterpretedSort()) << "Not an uninterpreted sort.";
+  //////// all checks before this line
+  return d_type->getName();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Sort::isUninterpretedSortParameterized() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isUninterpretedSort()) << "Not an uninterpreted sort.";
+  //////// all checks before this line
+
+  /* This method is not implemented in the NodeManager, since whether a
+   * uninterpreted sort is parameterized is irrelevant for solving. */
+  return d_type->getNumChildren() > 0;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+std::vector<Sort> Sort::getUninterpretedSortParamSorts() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isUninterpretedSort()) << "Not an uninterpreted sort.";
+  //////// all checks before this line
+
+  /* This method is not implemented in the NodeManager, since whether a
+   * uninterpreted sort is parameterized is irrelevant for solving. */
+  std::vector<TypeNode> params;
+  for (size_t i = 0, nchildren = d_type->getNumChildren(); i < nchildren; i++)
+  {
+    params.push_back((*d_type)[i]);
+  }
+  return typeNodeVectorToSorts(d_solver, params);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/* Sort constructor sort ----------------------------------------------- */
+
+std::string Sort::getSortConstructorName() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isSortConstructor()) << "Not a sort constructor sort.";
+  //////// all checks before this line
+  return d_type->getName();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+size_t Sort::getSortConstructorArity() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isSortConstructor()) << "Not a sort constructor sort.";
+  //////// all checks before this line
+  return d_type->getSortConstructorArity();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/* Bit-vector sort ----------------------------------------------------- */
+
+uint32_t Sort::getBVSize() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isBitVector()) << "Not a bit-vector sort.";
+  //////// all checks before this line
+  return d_type->getBitVectorSize();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/* Floating-point sort ------------------------------------------------- */
+
+uint32_t Sort::getFPExponentSize() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isFloatingPoint()) << "Not a floating-point sort.";
+  //////// all checks before this line
+  return d_type->getFloatingPointExponentSize();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+uint32_t Sort::getFPSignificandSize() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isFloatingPoint()) << "Not a floating-point sort.";
+  //////// all checks before this line
+  return d_type->getFloatingPointSignificandSize();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/* Datatype sort ------------------------------------------------------- */
+
+std::vector<Sort> Sort::getDatatypeParamSorts() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isParametricDatatype()) << "Not a parametric datatype sort.";
+  //////// all checks before this line
+  return typeNodeVectorToSorts(d_solver, d_type->getParamTypes());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+size_t Sort::getDatatypeArity() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isDatatype()) << "Not a datatype sort.";
+  //////// all checks before this line
+  return d_type->getNumChildren() - 1;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/* Tuple sort ---------------------------------------------------------- */
+
+size_t Sort::getTupleLength() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isTuple()) << "Not a tuple sort.";
+  //////// all checks before this line
+  return d_type->getTupleLength();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+std::vector<Sort> Sort::getTupleSorts() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(isTuple()) << "Not a tuple sort.";
+  //////// all checks before this line
+  return typeNodeVectorToSorts(d_solver, d_type->getTupleTypes());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/* --------------------------------------------------------------------- */
+
+std::ostream& operator<<(std::ostream& out, const Sort& s)
+{
+  out << s.toString();
+  return out;
+}
+
+size_t SortHashFunction::operator()(const Sort& s) const
+{
+  return TypeNodeHashFunction()(*s.d_type);
+}
+
+/* Helpers                                                                    */
+/* -------------------------------------------------------------------------- */
+
+/* Split out to avoid nested API calls (problematic with API tracing).        */
+/* .......................................................................... */
+
+bool Sort::isNullHelper() const { return d_type->isNull(); }
+
+/* -------------------------------------------------------------------------- */
+/* Op                                                                     */
+/* -------------------------------------------------------------------------- */
+
+Op::Op() : d_solver(nullptr), d_kind(NULL_EXPR), d_node(new cvc5::Node()) {}
+
+Op::Op(const Solver* slv, const Kind k)
+    : d_solver(slv), d_kind(k), d_node(new cvc5::Node())
+{
+}
+
+Op::Op(const Solver* slv, const Kind k, const cvc5::Node& n)
+    : d_solver(slv), d_kind(k), d_node(new cvc5::Node(n))
+{
+}
+
+Op::~Op()
+{
+  if (d_solver != nullptr)
+  {
+    // Ensure that the correct node manager is in scope when the type node is
+    // destroyed.
+    NodeManagerScope scope(d_solver->getNodeManager());
+    d_node.reset();
+  }
+}
+
+/* Public methods                                                             */
+bool Op::operator==(const Op& t) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  if (d_node->isNull() && t.d_node->isNull())
+  {
+    return (d_kind == t.d_kind);
+  }
+  else if (d_node->isNull() || t.d_node->isNull())
+  {
+    return false;
+  }
+  return (d_kind == t.d_kind) && (*d_node == *t.d_node);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Op::operator!=(const Op& t) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return !(*this == t);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Kind Op::getKind() const
+{
+  CVC4_API_CHECK(d_kind != NULL_EXPR) << "Expecting a non-null Kind";
+  //////// all checks before this line
+  return d_kind;
+}
+
+bool Op::isNull() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return isNullHelper();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Op::isIndexed() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return isIndexedHelper();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+template <>
+std::string Op::getIndices() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(!d_node->isNull())
+      << "Expecting a non-null internal expression. This Op is not indexed.";
+  Kind k = intToExtKind(d_node->getKind());
+  CVC4_API_CHECK(k == DIVISIBLE || k == RECORD_UPDATE)
+      << "Can't get string index from"
+      << " kind " << kindToString(k);
+  //////// all checks before this line
+  return k == DIVISIBLE ? d_node->getConst<Divisible>().k.toString()
+                        : d_node->getConst<RecordUpdate>().getField();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+template <>
+uint32_t Op::getIndices() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(!d_node->isNull())
+      << "Expecting a non-null internal expression. This Op is not indexed.";
+  //////// all checks before this line
+
+  uint32_t i = 0;
+  Kind k = intToExtKind(d_node->getKind());
+  switch (k)
+  {
+    case BITVECTOR_REPEAT:
+      i = d_node->getConst<BitVectorRepeat>().d_repeatAmount;
+      break;
+    case BITVECTOR_ZERO_EXTEND:
+      i = d_node->getConst<BitVectorZeroExtend>().d_zeroExtendAmount;
+      break;
+    case BITVECTOR_SIGN_EXTEND:
+      i = d_node->getConst<BitVectorSignExtend>().d_signExtendAmount;
+      break;
+    case BITVECTOR_ROTATE_LEFT:
+      i = d_node->getConst<BitVectorRotateLeft>().d_rotateLeftAmount;
+      break;
+    case BITVECTOR_ROTATE_RIGHT:
+      i = d_node->getConst<BitVectorRotateRight>().d_rotateRightAmount;
+      break;
+    case INT_TO_BITVECTOR: i = d_node->getConst<IntToBitVector>().d_size; break;
+    case IAND: i = d_node->getConst<IntAnd>().d_size; break;
+    case FLOATINGPOINT_TO_UBV:
+      i = d_node->getConst<FloatingPointToUBV>().d_bv_size.d_size;
+      break;
+    case FLOATINGPOINT_TO_SBV:
+      i = d_node->getConst<FloatingPointToSBV>().d_bv_size.d_size;
+      break;
+    case TUPLE_UPDATE: i = d_node->getConst<TupleUpdate>().getIndex(); break;
+    case REGEXP_REPEAT:
+      i = d_node->getConst<RegExpRepeat>().d_repeatAmount;
+      break;
+    default:
+      CVC4_API_CHECK(false) << "Can't get uint32_t index from"
+                            << " kind " << kindToString(k);
+  }
+  return i;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+template <>
+std::pair<uint32_t, uint32_t> Op::getIndices() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(!d_node->isNull())
+      << "Expecting a non-null internal expression. This Op is not indexed.";
+  //////// all checks before this line
+
+  std::pair<uint32_t, uint32_t> indices;
+  Kind k = intToExtKind(d_node->getKind());
+
+  // using if/else instead of case statement because want local variables
+  if (k == BITVECTOR_EXTRACT)
+  {
+    cvc5::BitVectorExtract ext = d_node->getConst<BitVectorExtract>();
+    indices = std::make_pair(ext.d_high, ext.d_low);
+  }
+  else if (k == FLOATINGPOINT_TO_FP_IEEE_BITVECTOR)
+  {
+    cvc5::FloatingPointToFPIEEEBitVector ext =
+        d_node->getConst<FloatingPointToFPIEEEBitVector>();
+    indices = std::make_pair(ext.getSize().exponentWidth(),
+                             ext.getSize().significandWidth());
+  }
+  else if (k == FLOATINGPOINT_TO_FP_FLOATINGPOINT)
+  {
+    cvc5::FloatingPointToFPFloatingPoint ext =
+        d_node->getConst<FloatingPointToFPFloatingPoint>();
+    indices = std::make_pair(ext.getSize().exponentWidth(),
+                             ext.getSize().significandWidth());
+  }
+  else if (k == FLOATINGPOINT_TO_FP_REAL)
+  {
+    cvc5::FloatingPointToFPReal ext = d_node->getConst<FloatingPointToFPReal>();
+    indices = std::make_pair(ext.getSize().exponentWidth(),
+                             ext.getSize().significandWidth());
+  }
+  else if (k == FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR)
+  {
+    cvc5::FloatingPointToFPSignedBitVector ext =
+        d_node->getConst<FloatingPointToFPSignedBitVector>();
+    indices = std::make_pair(ext.getSize().exponentWidth(),
+                             ext.getSize().significandWidth());
+  }
+  else if (k == FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR)
+  {
+    cvc5::FloatingPointToFPUnsignedBitVector ext =
+        d_node->getConst<FloatingPointToFPUnsignedBitVector>();
+    indices = std::make_pair(ext.getSize().exponentWidth(),
+                             ext.getSize().significandWidth());
+  }
+  else if (k == FLOATINGPOINT_TO_FP_GENERIC)
+  {
+    cvc5::FloatingPointToFPGeneric ext =
+        d_node->getConst<FloatingPointToFPGeneric>();
+    indices = std::make_pair(ext.getSize().exponentWidth(),
+                             ext.getSize().significandWidth());
+  }
+  else if (k == REGEXP_LOOP)
+  {
+    cvc5::RegExpLoop ext = d_node->getConst<RegExpLoop>();
+    indices = std::make_pair(ext.d_loopMinOcc, ext.d_loopMaxOcc);
+  }
+  else
+  {
+    CVC4_API_CHECK(false) << "Can't get pair<uint32_t, uint32_t> indices from"
+                          << " kind " << kindToString(k);
+  }
+  return indices;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+std::string Op::toString() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  if (d_node->isNull())
+  {
+    return kindToString(d_kind);
+  }
+  else
+  {
+    CVC4_API_CHECK(!d_node->isNull())
+        << "Expecting a non-null internal expression";
+    if (d_solver != nullptr)
+    {
+      NodeManagerScope scope(d_solver->getNodeManager());
+      return d_node->toString();
+    }
+    return d_node->toString();
+  }
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+std::ostream& operator<<(std::ostream& out, const Op& t)
+{
+  out << t.toString();
+  return out;
+}
+
+size_t OpHashFunction::operator()(const Op& t) const
+{
+  if (t.isIndexedHelper())
+  {
+    return NodeHashFunction()(*t.d_node);
+  }
+  else
+  {
+    return KindHashFunction()(t.d_kind);
+  }
+}
+
+/* Helpers                                                                    */
+/* -------------------------------------------------------------------------- */
+
+/* Split out to avoid nested API calls (problematic with API tracing).        */
+/* .......................................................................... */
+
+bool Op::isNullHelper() const
+{
+  return (d_node->isNull() && (d_kind == NULL_EXPR));
+}
+
+bool Op::isIndexedHelper() const { return !d_node->isNull(); }
+
+/* -------------------------------------------------------------------------- */
+/* Term                                                                       */
+/* -------------------------------------------------------------------------- */
+
+Term::Term() : d_solver(nullptr), d_node(new cvc5::Node()) {}
+
+Term::Term(const Solver* slv, const cvc5::Node& n) : d_solver(slv)
+{
+  // Ensure that we create the node in the correct node manager.
+  NodeManagerScope scope(d_solver->getNodeManager());
+  d_node.reset(new cvc5::Node(n));
+}
+
+Term::~Term()
+{
+  if (d_solver != nullptr)
+  {
+    // Ensure that the correct node manager is in scope when the node is
+    // destroyed.
+    NodeManagerScope scope(d_solver->getNodeManager());
+    d_node.reset();
+  }
+}
+
+bool Term::operator==(const Term& t) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return *d_node == *t.d_node;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Term::operator!=(const Term& t) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return *d_node != *t.d_node;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Term::operator<(const Term& t) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return *d_node < *t.d_node;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Term::operator>(const Term& t) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return *d_node > *t.d_node;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Term::operator<=(const Term& t) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return *d_node <= *t.d_node;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Term::operator>=(const Term& t) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return *d_node >= *t.d_node;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+size_t Term::getNumChildren() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+
+  // special case for apply kinds
+  if (isApplyKind(d_node->getKind()))
+  {
+    return d_node->getNumChildren() + 1;
+  }
+  if (isCastedReal())
+  {
+    return 0;
+  }
+  return d_node->getNumChildren();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Term::operator[](size_t index) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(index < getNumChildren()) << "index out of bound";
+  CVC4_API_CHECK(!isApplyKind(d_node->getKind()) || d_node->hasOperator())
+      << "Expected apply kind to have operator when accessing child of Term";
+  //////// all checks before this line
+
+  // special cases for apply kinds
+  if (isApplyKind(d_node->getKind()))
+  {
+    if (index == 0)
+    {
+      // return the operator
+      return Term(d_solver, d_node->getOperator());
+    }
+    else
+    {
+      index -= 1;
+    }
+  }
+  // otherwise we are looking up child at (index-1)
+  return Term(d_solver, (*d_node)[index]);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+uint64_t Term::getId() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return d_node->getId();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Kind Term::getKind() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return getKindHelper();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Term::getSort() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  NodeManagerScope scope(d_solver->getNodeManager());
+  //////// all checks before this line
+  return Sort(d_solver, d_node->getType());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Term::substitute(const Term& term, const Term& replacement) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK_TERM(term);
+  CVC4_API_CHECK_TERM(replacement);
+  CVC4_API_CHECK(term.getSort().isComparableTo(replacement.getSort()))
+      << "Expecting terms of comparable sort in substitute";
+  //////// all checks before this line
+  return Term(
+      d_solver,
+      d_node->substitute(TNode(*term.d_node), TNode(*replacement.d_node)));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Term::substitute(const std::vector<Term>& terms,
+                      const std::vector<Term>& replacements) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(terms.size() == replacements.size())
+      << "Expecting vectors of the same arity in substitute";
+  CVC4_API_TERM_CHECK_TERMS_WITH_TERMS_COMPARABLE_TO(terms, replacements);
+  //////// all checks before this line
+  std::vector<Node> nodes = Term::termVectorToNodes(terms);
+  std::vector<Node> nodeReplacements = Term::termVectorToNodes(replacements);
+  return Term(d_solver,
+              d_node->substitute(nodes.begin(),
+                                 nodes.end(),
+                                 nodeReplacements.begin(),
+                                 nodeReplacements.end()));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Term::hasOp() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return d_node->hasOperator();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Op Term::getOp() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(d_node->hasOperator())
+      << "Expecting Term to have an Op when calling getOp()";
+  //////// all checks before this line
+
+  // special cases for parameterized operators that are not indexed operators
+  // the API level differs from the internal structure
+  // indexed operators are stored in Ops
+  // whereas functions and datatype operators are terms, and the Op
+  // is one of the APPLY_* kinds
+  if (isApplyKind(d_node->getKind()))
+  {
+    return Op(d_solver, intToExtKind(d_node->getKind()));
+  }
+  else if (d_node->getMetaKind() == kind::metakind::PARAMETERIZED)
+  {
+    // it's an indexed operator
+    // so we should return the indexed op
+    cvc5::Node op = d_node->getOperator();
+    return Op(d_solver, intToExtKind(d_node->getKind()), op);
+  }
+  // Notice this is the only case where getKindHelper is used, since the
+  // cases above do not have special cases for intToExtKind.
+  return Op(d_solver, getKindHelper());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Term::isNull() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return isNullHelper();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Term::getConstArrayBase() const
+{
+  NodeManagerScope scope(d_solver->getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  // CONST_ARRAY kind maps to STORE_ALL internal kind
+  CVC4_API_CHECK(d_node->getKind() == cvc5::Kind::STORE_ALL)
+      << "Expecting a CONST_ARRAY Term when calling getConstArrayBase()";
+  //////// all checks before this line
+  return Term(d_solver, d_node->getConst<ArrayStoreAll>().getValue());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+std::vector<Term> Term::getConstSequenceElements() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(d_node->getKind() == cvc5::Kind::CONST_SEQUENCE)
+      << "Expecting a CONST_SEQUENCE Term when calling "
+         "getConstSequenceElements()";
+  //////// all checks before this line
+  const std::vector<Node>& elems = d_node->getConst<Sequence>().getVec();
+  std::vector<Term> terms;
+  for (const Node& t : elems)
+  {
+    terms.push_back(Term(d_solver, t));
+  }
+  return terms;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Term::notTerm() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  Node res = d_node->notNode();
+  (void)res.getType(true); /* kick off type checking */
+  return Term(d_solver, res);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Term::andTerm(const Term& t) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK_TERM(t);
+  //////// all checks before this line
+  Node res = d_node->andNode(*t.d_node);
+  (void)res.getType(true); /* kick off type checking */
+  return Term(d_solver, res);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Term::orTerm(const Term& t) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK_TERM(t);
+  //////// all checks before this line
+  Node res = d_node->orNode(*t.d_node);
+  (void)res.getType(true); /* kick off type checking */
+  return Term(d_solver, res);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Term::xorTerm(const Term& t) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK_TERM(t);
+  //////// all checks before this line
+  Node res = d_node->xorNode(*t.d_node);
+  (void)res.getType(true); /* kick off type checking */
+  return Term(d_solver, res);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Term::eqTerm(const Term& t) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK_TERM(t);
+  //////// all checks before this line
+  Node res = d_node->eqNode(*t.d_node);
+  (void)res.getType(true); /* kick off type checking */
+  return Term(d_solver, res);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Term::impTerm(const Term& t) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK_TERM(t);
+  //////// all checks before this line
+  Node res = d_node->impNode(*t.d_node);
+  (void)res.getType(true); /* kick off type checking */
+  return Term(d_solver, res);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Term::iteTerm(const Term& then_t, const Term& else_t) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK_TERM(then_t);
+  CVC4_API_CHECK_TERM(else_t);
+  //////// all checks before this line
+  Node res = d_node->iteNode(*then_t.d_node, *else_t.d_node);
+  (void)res.getType(true); /* kick off type checking */
+  return Term(d_solver, res);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+std::string Term::toString() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  if (d_solver != nullptr)
+  {
+    NodeManagerScope scope(d_solver->getNodeManager());
+    return d_node->toString();
+  }
+  return d_node->toString();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term::const_iterator::const_iterator()
+    : d_solver(nullptr), d_origNode(nullptr), d_pos(0)
+{
+}
+
+Term::const_iterator::const_iterator(const Solver* slv,
+                                     const std::shared_ptr<cvc5::Node>& n,
+                                     uint32_t p)
+    : d_solver(slv), d_origNode(n), d_pos(p)
+{
+}
+
+Term::const_iterator::const_iterator(const const_iterator& it)
+    : d_solver(nullptr), d_origNode(nullptr)
+{
+  if (it.d_origNode != nullptr)
+  {
+    d_solver = it.d_solver;
+    d_origNode = it.d_origNode;
+    d_pos = it.d_pos;
+  }
+}
+
+Term::const_iterator& Term::const_iterator::operator=(const const_iterator& it)
+{
+  d_solver = it.d_solver;
+  d_origNode = it.d_origNode;
+  d_pos = it.d_pos;
+  return *this;
+}
+
+bool Term::const_iterator::operator==(const const_iterator& it) const
+{
+  if (d_origNode == nullptr || it.d_origNode == nullptr)
+  {
+    return false;
+  }
+  return (d_solver == it.d_solver && *d_origNode == *it.d_origNode)
+         && (d_pos == it.d_pos);
+}
+
+bool Term::const_iterator::operator!=(const const_iterator& it) const
+{
+  return !(*this == it);
+}
+
+Term::const_iterator& Term::const_iterator::operator++()
+{
+  Assert(d_origNode != nullptr);
+  ++d_pos;
+  return *this;
+}
+
+Term::const_iterator Term::const_iterator::operator++(int)
+{
+  Assert(d_origNode != nullptr);
+  const_iterator it = *this;
+  ++d_pos;
+  return it;
+}
+
+Term Term::const_iterator::operator*() const
+{
+  Assert(d_origNode != nullptr);
+  // this term has an extra child (mismatch between API and internal structure)
+  // the extra child will be the first child
+  bool extra_child = isApplyKind(d_origNode->getKind());
+
+  if (!d_pos && extra_child)
+  {
+    return Term(d_solver, d_origNode->getOperator());
+  }
+  else
+  {
+    uint32_t idx = d_pos;
+    if (extra_child)
+    {
+      Assert(idx > 0);
+      --idx;
+    }
+    Assert(idx >= 0);
+    return Term(d_solver, (*d_origNode)[idx]);
+  }
+}
+
+Term::const_iterator Term::begin() const
+{
+  return Term::const_iterator(d_solver, d_node, 0);
+}
+
+Term::const_iterator Term::end() const
+{
+  int endpos = d_node->getNumChildren();
+  // special cases for APPLY_*
+  // the API differs from the internal structure
+  // the API takes a "higher-order" perspective and the applied
+  //   function or datatype constructor/selector/tester is a Term
+  // which means it needs to be one of the children, even though
+  //   internally it is not
+  if (isApplyKind(d_node->getKind()))
+  {
+    // one more child if this is a UF application (count the UF as a child)
+    ++endpos;
+  }
+  return Term::const_iterator(d_solver, d_node, endpos);
+}
+
+const cvc5::Node& Term::getNode(void) const { return *d_node; }
+
+namespace detail {
+const Rational& getRational(const cvc5::Node& node)
+{
+  return node.getConst<Rational>();
+}
+Integer getInteger(const cvc5::Node& node)
+{
+  return node.getConst<Rational>().getNumerator();
+}
+template <typename T>
+bool checkIntegerBounds(const Integer& i)
+{
+  return i >= std::numeric_limits<T>::min()
+         && i <= std::numeric_limits<T>::max();
+}
+bool checkReal32Bounds(const Rational& r)
+{
+  return checkIntegerBounds<std::int32_t>(r.getNumerator())
+         && checkIntegerBounds<std::uint32_t>(r.getDenominator());
+}
+bool checkReal64Bounds(const Rational& r)
+{
+  return checkIntegerBounds<std::int64_t>(r.getNumerator())
+         && checkIntegerBounds<std::uint64_t>(r.getDenominator());
+}
+
+bool isInteger(const Node& node)
+{
+  return node.getKind() == cvc5::Kind::CONST_RATIONAL
+         && node.getConst<Rational>().isIntegral();
+}
+bool isInt32(const Node& node)
+{
+  return isInteger(node) && checkIntegerBounds<std::int32_t>(getInteger(node));
+}
+bool isUInt32(const Node& node)
+{
+  return isInteger(node) && checkIntegerBounds<std::uint32_t>(getInteger(node));
+}
+bool isInt64(const Node& node)
+{
+  return isInteger(node) && checkIntegerBounds<std::int64_t>(getInteger(node));
+}
+bool isUInt64(const Node& node)
+{
+  return isInteger(node) && checkIntegerBounds<std::uint64_t>(getInteger(node));
+}
+}  // namespace detail
+
+bool Term::isInt32() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return detail::isInt32(*d_node);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+std::int32_t Term::getInt32() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(detail::isInt32(*d_node))
+      << "Term should be a Int32 when calling getInt32()";
+  //////// all checks before this line
+  return detail::getInteger(*d_node).getSignedInt();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Term::isUInt32() const { return detail::isUInt32(*d_node); }
+std::uint32_t Term::getUInt32() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(detail::isUInt32(*d_node))
+      << "Term should be a UInt32 when calling getUInt32()";
+  //////// all checks before this line
+  return detail::getInteger(*d_node).getUnsignedInt();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Term::isInt64() const { return detail::isInt64(*d_node); }
+std::int64_t Term::getInt64() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(detail::isInt64(*d_node))
+      << "Term should be a Int64 when calling getInt64()";
+  //////// all checks before this line
+  return detail::getInteger(*d_node).getLong();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Term::isUInt64() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return detail::isUInt64(*d_node);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+std::uint64_t Term::getUInt64() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(detail::isUInt64(*d_node))
+      << "Term should be a UInt64 when calling getUInt64()";
+  //////// all checks before this line
+  return detail::getInteger(*d_node).getUnsignedLong();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Term::isInteger() const { return detail::isInteger(*d_node); }
+std::string Term::getInteger() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(detail::isInteger(*d_node))
+      << "Term should be an Int when calling getIntString()";
+  //////// all checks before this line
+  return detail::getInteger(*d_node).toString();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Term::isString() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return d_node->getKind() == cvc5::Kind::CONST_STRING;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+std::wstring Term::getString() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(d_node->getKind() == cvc5::Kind::CONST_STRING)
+      << "Term should be a String when calling getString()";
+  //////// all checks before this line
+  return d_node->getConst<cvc5::String>().toWString();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+std::vector<Node> Term::termVectorToNodes(const std::vector<Term>& terms)
+{
+  std::vector<Node> res;
+  for (const Term& t : terms)
+  {
+    res.push_back(t.getNode());
+  }
+  return res;
+}
+
+std::ostream& operator<<(std::ostream& out, const Term& t)
+{
+  out << t.toString();
+  return out;
+}
+
+std::ostream& operator<<(std::ostream& out, const std::vector<Term>& vector)
+{
+  container_to_stream(out, vector);
+  return out;
+}
+
+std::ostream& operator<<(std::ostream& out, const std::set<Term>& set)
+{
+  container_to_stream(out, set);
+  return out;
+}
+
+std::ostream& operator<<(
+    std::ostream& out,
+    const std::unordered_set<Term, TermHashFunction>& unordered_set)
+{
+  container_to_stream(out, unordered_set);
+  return out;
+}
+
+template <typename V>
+std::ostream& operator<<(std::ostream& out, const std::map<Term, V>& map)
+{
+  container_to_stream(out, map);
+  return out;
+}
+
+template <typename V>
+std::ostream& operator<<(
+    std::ostream& out,
+    const std::unordered_map<Term, V, TermHashFunction>& unordered_map)
+{
+  container_to_stream(out, unordered_map);
+  return out;
+}
+
+size_t TermHashFunction::operator()(const Term& t) const
+{
+  return NodeHashFunction()(*t.d_node);
+}
+
+/* Helpers                                                                    */
+/* -------------------------------------------------------------------------- */
+
+/* Split out to avoid nested API calls (problematic with API tracing).        */
+/* .......................................................................... */
+
+bool Term::isNullHelper() const
+{
+  /* Split out to avoid nested API calls (problematic with API tracing). */
+  return d_node->isNull();
+}
+
+Kind Term::getKindHelper() const
+{
+  /* Sequence kinds do not exist internally, so we must convert their internal
+   * (string) versions back to sequence. All operators where this is
+   * necessary are such that their first child is of sequence type, which
+   * we check here. */
+  if (d_node->getNumChildren() > 0 && (*d_node)[0].getType().isSequence())
+  {
+    switch (d_node->getKind())
+    {
+      case cvc5::Kind::STRING_CONCAT: return SEQ_CONCAT;
+      case cvc5::Kind::STRING_LENGTH: return SEQ_LENGTH;
+      case cvc5::Kind::STRING_SUBSTR: return SEQ_EXTRACT;
+      case cvc5::Kind::STRING_UPDATE: return SEQ_UPDATE;
+      case cvc5::Kind::STRING_CHARAT: return SEQ_AT;
+      case cvc5::Kind::STRING_STRCTN: return SEQ_CONTAINS;
+      case cvc5::Kind::STRING_STRIDOF: return SEQ_INDEXOF;
+      case cvc5::Kind::STRING_STRREPL: return SEQ_REPLACE;
+      case cvc5::Kind::STRING_STRREPLALL: return SEQ_REPLACE_ALL;
+      case cvc5::Kind::STRING_REV: return SEQ_REV;
+      case cvc5::Kind::STRING_PREFIX: return SEQ_PREFIX;
+      case cvc5::Kind::STRING_SUFFIX: return SEQ_SUFFIX;
+      default:
+        // fall through to conversion below
+        break;
+    }
+  }
+  // Notice that kinds like APPLY_TYPE_ASCRIPTION will be converted to
+  // INTERNAL_KIND.
+  if (isCastedReal())
+  {
+    return CONST_RATIONAL;
+  }
+  return intToExtKind(d_node->getKind());
+}
+
+bool Term::isCastedReal() const
+{
+  if (d_node->getKind() == kind::CAST_TO_REAL)
+  {
+    return (*d_node)[0].isConst() && (*d_node)[0].getType().isInteger();
+  }
+  return false;
+}
+
+/* -------------------------------------------------------------------------- */
+/* Datatypes                                                                  */
+/* -------------------------------------------------------------------------- */
+
+/* DatatypeConstructorDecl -------------------------------------------------- */
+
+DatatypeConstructorDecl::DatatypeConstructorDecl()
+    : d_solver(nullptr), d_ctor(nullptr)
+{
+}
+
+DatatypeConstructorDecl::DatatypeConstructorDecl(const Solver* slv,
+                                                 const std::string& name)
+    : d_solver(slv), d_ctor(new cvc5::DTypeConstructor(name))
+{
+}
+DatatypeConstructorDecl::~DatatypeConstructorDecl()
+{
+  if (d_ctor != nullptr)
+  {
+    // ensure proper node manager is in scope
+    NodeManagerScope scope(d_solver->getNodeManager());
+    d_ctor.reset();
+  }
+}
+
+void DatatypeConstructorDecl::addSelector(const std::string& name,
+                                          const Sort& sort)
+{
+  NodeManagerScope scope(d_solver->getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK_SORT(sort);
+  CVC4_API_ARG_CHECK_EXPECTED(!sort.isNull(), sort)
+      << "non-null range sort for selector";
+  //////// all checks before this line
+  d_ctor->addArg(name, *sort.d_type);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+void DatatypeConstructorDecl::addSelectorSelf(const std::string& name)
+{
+  NodeManagerScope scope(d_solver->getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  d_ctor->addArgSelf(name);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool DatatypeConstructorDecl::isNull() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return isNullHelper();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+std::string DatatypeConstructorDecl::toString() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  std::stringstream ss;
+  ss << *d_ctor;
+  return ss.str();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+std::ostream& operator<<(std::ostream& out,
+                         const DatatypeConstructorDecl& ctordecl)
+{
+  out << ctordecl.toString();
+  return out;
+}
+
+std::ostream& operator<<(std::ostream& out,
+                         const std::vector<DatatypeConstructorDecl>& vector)
+{
+  container_to_stream(out, vector);
+  return out;
+}
+
+bool DatatypeConstructorDecl::isNullHelper() const { return d_ctor == nullptr; }
+
+/* DatatypeDecl ------------------------------------------------------------- */
+
+DatatypeDecl::DatatypeDecl() : d_solver(nullptr), d_dtype(nullptr) {}
+
+DatatypeDecl::DatatypeDecl(const Solver* slv,
+                           const std::string& name,
+                           bool isCoDatatype)
+    : d_solver(slv), d_dtype(new cvc5::DType(name, isCoDatatype))
+{
+}
+
+DatatypeDecl::DatatypeDecl(const Solver* slv,
+                           const std::string& name,
+                           const Sort& param,
+                           bool isCoDatatype)
+    : d_solver(slv),
+      d_dtype(new cvc5::DType(
+          name, std::vector<TypeNode>{*param.d_type}, isCoDatatype))
+{
+}
+
+DatatypeDecl::DatatypeDecl(const Solver* slv,
+                           const std::string& name,
+                           const std::vector<Sort>& params,
+                           bool isCoDatatype)
+    : d_solver(slv)
+{
+  std::vector<TypeNode> tparams = Sort::sortVectorToTypeNodes(params);
+  d_dtype = std::shared_ptr<cvc5::DType>(
+      new cvc5::DType(name, tparams, isCoDatatype));
+}
+
+bool DatatypeDecl::isNullHelper() const { return !d_dtype; }
+
+DatatypeDecl::~DatatypeDecl()
+{
+  if (d_dtype != nullptr)
+  {
+    // ensure proper node manager is in scope
+    NodeManagerScope scope(d_solver->getNodeManager());
+    d_dtype.reset();
+  }
+}
+
+void DatatypeDecl::addConstructor(const DatatypeConstructorDecl& ctor)
+{
+  NodeManagerScope scope(d_solver->getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_ARG_CHECK_NOT_NULL(ctor);
+  CVC4_API_ARG_CHECK_SOLVER("datatype constructor declaration", ctor);
+  //////// all checks before this line
+  d_dtype->addConstructor(ctor.d_ctor);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+size_t DatatypeDecl::getNumConstructors() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return d_dtype->getNumConstructors();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool DatatypeDecl::isParametric() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return d_dtype->isParametric();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+std::string DatatypeDecl::toString() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  std::stringstream ss;
+  ss << *d_dtype;
+  return ss.str();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+std::string DatatypeDecl::getName() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return d_dtype->getName();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool DatatypeDecl::isNull() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return isNullHelper();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+std::ostream& operator<<(std::ostream& out, const DatatypeDecl& dtdecl)
+{
+  out << dtdecl.toString();
+  return out;
+}
+
+cvc5::DType& DatatypeDecl::getDatatype(void) const { return *d_dtype; }
+
+/* DatatypeSelector --------------------------------------------------------- */
+
+DatatypeSelector::DatatypeSelector() : d_solver(nullptr), d_stor(nullptr) {}
+
+DatatypeSelector::DatatypeSelector(const Solver* slv,
+                                   const cvc5::DTypeSelector& stor)
+    : d_solver(slv), d_stor(new cvc5::DTypeSelector(stor))
+{
+  CVC4_API_CHECK(d_stor->isResolved()) << "Expected resolved datatype selector";
+}
+
+DatatypeSelector::~DatatypeSelector()
+{
+  if (d_stor != nullptr)
+  {
+    // ensure proper node manager is in scope
+    NodeManagerScope scope(d_solver->getNodeManager());
+    d_stor.reset();
+  }
+}
+
+std::string DatatypeSelector::getName() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return d_stor->getName();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term DatatypeSelector::getSelectorTerm() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return Term(d_solver, d_stor->getSelector());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort DatatypeSelector::getRangeSort() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return Sort(d_solver, d_stor->getRangeType());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool DatatypeSelector::isNull() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return isNullHelper();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+std::string DatatypeSelector::toString() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  std::stringstream ss;
+  ss << *d_stor;
+  return ss.str();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+std::ostream& operator<<(std::ostream& out, const DatatypeSelector& stor)
+{
+  out << stor.toString();
+  return out;
+}
+
+bool DatatypeSelector::isNullHelper() const { return d_stor == nullptr; }
+
+/* DatatypeConstructor ------------------------------------------------------ */
+
+DatatypeConstructor::DatatypeConstructor() : d_solver(nullptr), d_ctor(nullptr)
+{
+}
+
+DatatypeConstructor::DatatypeConstructor(const Solver* slv,
+                                         const cvc5::DTypeConstructor& ctor)
+    : d_solver(slv), d_ctor(new cvc5::DTypeConstructor(ctor))
+{
+  CVC4_API_CHECK(d_ctor->isResolved())
+      << "Expected resolved datatype constructor";
+}
+
+DatatypeConstructor::~DatatypeConstructor()
+{
+  if (d_ctor != nullptr)
+  {
+    // ensure proper node manager is in scope
+    NodeManagerScope scope(d_solver->getNodeManager());
+    d_ctor.reset();
+  }
+}
+
+std::string DatatypeConstructor::getName() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return d_ctor->getName();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term DatatypeConstructor::getConstructorTerm() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return Term(d_solver, d_ctor->getConstructor());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term DatatypeConstructor::getSpecializedConstructorTerm(
+    const Sort& retSort) const
+{
+  NodeManagerScope scope(d_solver->getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(d_ctor->isResolved())
+      << "Expected resolved datatype constructor";
+  CVC4_API_CHECK(retSort.isDatatype())
+      << "Cannot get specialized constructor type for non-datatype type "
+      << retSort;
+  //////// all checks before this line
+
+  NodeManager* nm = d_solver->getNodeManager();
+  Node ret =
+      nm->mkNode(kind::APPLY_TYPE_ASCRIPTION,
+                 nm->mkConst(AscriptionType(
+                     d_ctor->getSpecializedConstructorType(*retSort.d_type))),
+                 d_ctor->getConstructor());
+  (void)ret.getType(true); /* kick off type checking */
+  // apply type ascription to the operator
+  Term sctor = api::Term(d_solver, ret);
+  return sctor;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term DatatypeConstructor::getTesterTerm() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return Term(d_solver, d_ctor->getTester());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+size_t DatatypeConstructor::getNumSelectors() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return d_ctor->getNumArgs();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+DatatypeSelector DatatypeConstructor::operator[](size_t index) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return DatatypeSelector(d_solver, (*d_ctor)[index]);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+DatatypeSelector DatatypeConstructor::operator[](const std::string& name) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return getSelectorForName(name);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+DatatypeSelector DatatypeConstructor::getSelector(const std::string& name) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return getSelectorForName(name);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term DatatypeConstructor::getSelectorTerm(const std::string& name) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return getSelector(name).getSelectorTerm();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+DatatypeConstructor::const_iterator DatatypeConstructor::begin() const
+{
+  return DatatypeConstructor::const_iterator(d_solver, *d_ctor, true);
+}
+
+DatatypeConstructor::const_iterator DatatypeConstructor::end() const
+{
+  return DatatypeConstructor::const_iterator(d_solver, *d_ctor, false);
+}
+
+DatatypeConstructor::const_iterator::const_iterator(
+    const Solver* slv, const cvc5::DTypeConstructor& ctor, bool begin)
+{
+  d_solver = slv;
+  d_int_stors = &ctor.getArgs();
+
+  const std::vector<std::shared_ptr<cvc5::DTypeSelector>>& sels =
+      ctor.getArgs();
+  for (const std::shared_ptr<cvc5::DTypeSelector>& s : sels)
+  {
+    /* Can not use emplace_back here since constructor is private. */
+    d_stors.push_back(DatatypeSelector(d_solver, *s.get()));
+  }
+  d_idx = begin ? 0 : sels.size();
+}
+
+DatatypeConstructor::const_iterator::const_iterator()
+    : d_solver(nullptr), d_int_stors(nullptr), d_idx(0)
+{
+}
+
+DatatypeConstructor::const_iterator&
+DatatypeConstructor::const_iterator::operator=(
+    const DatatypeConstructor::const_iterator& it)
+{
+  d_solver = it.d_solver;
+  d_int_stors = it.d_int_stors;
+  d_stors = it.d_stors;
+  d_idx = it.d_idx;
+  return *this;
+}
+
+const DatatypeSelector& DatatypeConstructor::const_iterator::operator*() const
+{
+  return d_stors[d_idx];
+}
+
+const DatatypeSelector* DatatypeConstructor::const_iterator::operator->() const
+{
+  return &d_stors[d_idx];
+}
+
+DatatypeConstructor::const_iterator&
+DatatypeConstructor::const_iterator::operator++()
+{
+  ++d_idx;
+  return *this;
+}
+
+DatatypeConstructor::const_iterator
+DatatypeConstructor::const_iterator::operator++(int)
+{
+  DatatypeConstructor::const_iterator it(*this);
+  ++d_idx;
+  return it;
+}
+
+bool DatatypeConstructor::const_iterator::operator==(
+    const DatatypeConstructor::const_iterator& other) const
+{
+  return d_int_stors == other.d_int_stors && d_idx == other.d_idx;
+}
+
+bool DatatypeConstructor::const_iterator::operator!=(
+    const DatatypeConstructor::const_iterator& other) const
+{
+  return d_int_stors != other.d_int_stors || d_idx != other.d_idx;
+}
+
+bool DatatypeConstructor::isNull() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return isNullHelper();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+std::string DatatypeConstructor::toString() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  std::stringstream ss;
+  ss << *d_ctor;
+  return ss.str();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool DatatypeConstructor::isNullHelper() const { return d_ctor == nullptr; }
+
+DatatypeSelector DatatypeConstructor::getSelectorForName(
+    const std::string& name) const
+{
+  bool foundSel = false;
+  size_t index = 0;
+  for (size_t i = 0, nsels = getNumSelectors(); i < nsels; i++)
+  {
+    if ((*d_ctor)[i].getName() == name)
+    {
+      index = i;
+      foundSel = true;
+      break;
+    }
+  }
+  if (!foundSel)
+  {
+    std::stringstream snames;
+    snames << "{ ";
+    for (size_t i = 0, ncons = getNumSelectors(); i < ncons; i++)
+    {
+      snames << (*d_ctor)[i].getName() << " ";
+    }
+    snames << "} ";
+    CVC4_API_CHECK(foundSel) << "No selector " << name << " for constructor "
+                             << getName() << " exists among " << snames.str();
+  }
+  return DatatypeSelector(d_solver, (*d_ctor)[index]);
+}
+
+std::ostream& operator<<(std::ostream& out, const DatatypeConstructor& ctor)
+{
+  out << ctor.toString();
+  return out;
+}
+
+/* Datatype ----------------------------------------------------------------- */
+
+Datatype::Datatype(const Solver* slv, const cvc5::DType& dtype)
+    : d_solver(slv), d_dtype(new cvc5::DType(dtype))
+{
+  CVC4_API_CHECK(d_dtype->isResolved()) << "Expected resolved datatype";
+}
+
+Datatype::Datatype() : d_solver(nullptr), d_dtype(nullptr) {}
+
+Datatype::~Datatype()
+{
+  if (d_dtype != nullptr)
+  {
+    // ensure proper node manager is in scope
+    NodeManagerScope scope(d_solver->getNodeManager());
+    d_dtype.reset();
+  }
+}
+
+DatatypeConstructor Datatype::operator[](size_t idx) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  CVC4_API_CHECK(idx < getNumConstructors()) << "Index out of bounds.";
+  //////// all checks before this line
+  return DatatypeConstructor(d_solver, (*d_dtype)[idx]);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+DatatypeConstructor Datatype::operator[](const std::string& name) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return getConstructorForName(name);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+DatatypeConstructor Datatype::getConstructor(const std::string& name) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return getConstructorForName(name);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Datatype::getConstructorTerm(const std::string& name) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return getConstructor(name).getConstructorTerm();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+std::string Datatype::getName() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return d_dtype->getName();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+size_t Datatype::getNumConstructors() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return d_dtype->getNumConstructors();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Datatype::isParametric() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return d_dtype->isParametric();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Datatype::isCodatatype() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return d_dtype->isCodatatype();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Datatype::isTuple() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return d_dtype->isTuple();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Datatype::isRecord() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return d_dtype->isRecord();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Datatype::isFinite() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return d_dtype->isFinite();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Datatype::isWellFounded() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return d_dtype->isWellFounded();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+bool Datatype::hasNestedRecursion() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return d_dtype->hasNestedRecursion();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Datatype::isNull() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return isNullHelper();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+std::string Datatype::toString() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_NOT_NULL;
+  //////// all checks before this line
+  return d_dtype->getName();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Datatype::const_iterator Datatype::begin() const
+{
+  return Datatype::const_iterator(d_solver, *d_dtype, true);
+}
+
+Datatype::const_iterator Datatype::end() const
+{
+  return Datatype::const_iterator(d_solver, *d_dtype, false);
+}
+
+DatatypeConstructor Datatype::getConstructorForName(
+    const std::string& name) const
+{
+  bool foundCons = false;
+  size_t index = 0;
+  for (size_t i = 0, ncons = getNumConstructors(); i < ncons; i++)
+  {
+    if ((*d_dtype)[i].getName() == name)
+    {
+      index = i;
+      foundCons = true;
+      break;
+    }
+  }
+  if (!foundCons)
+  {
+    std::stringstream snames;
+    snames << "{ ";
+    for (size_t i = 0, ncons = getNumConstructors(); i < ncons; i++)
+    {
+      snames << (*d_dtype)[i].getName() << " ";
+    }
+    snames << "}";
+    CVC4_API_CHECK(foundCons) << "No constructor " << name << " for datatype "
+                              << getName() << " exists, among " << snames.str();
+  }
+  return DatatypeConstructor(d_solver, (*d_dtype)[index]);
+}
+
+Datatype::const_iterator::const_iterator(const Solver* slv,
+                                         const cvc5::DType& dtype,
+                                         bool begin)
+    : d_solver(slv), d_int_ctors(&dtype.getConstructors())
+{
+  const std::vector<std::shared_ptr<DTypeConstructor>>& cons =
+      dtype.getConstructors();
+  for (const std::shared_ptr<DTypeConstructor>& c : cons)
+  {
+    /* Can not use emplace_back here since constructor is private. */
+    d_ctors.push_back(DatatypeConstructor(d_solver, *c.get()));
+  }
+  d_idx = begin ? 0 : cons.size();
+}
+
+Datatype::const_iterator::const_iterator()
+    : d_solver(nullptr), d_int_ctors(nullptr), d_idx(0)
+{
+}
+
+Datatype::const_iterator& Datatype::const_iterator::operator=(
+    const Datatype::const_iterator& it)
+{
+  d_solver = it.d_solver;
+  d_int_ctors = it.d_int_ctors;
+  d_ctors = it.d_ctors;
+  d_idx = it.d_idx;
+  return *this;
+}
+
+const DatatypeConstructor& Datatype::const_iterator::operator*() const
+{
+  return d_ctors[d_idx];
+}
+
+const DatatypeConstructor* Datatype::const_iterator::operator->() const
+{
+  return &d_ctors[d_idx];
+}
+
+Datatype::const_iterator& Datatype::const_iterator::operator++()
+{
+  ++d_idx;
+  return *this;
+}
+
+Datatype::const_iterator Datatype::const_iterator::operator++(int)
+{
+  Datatype::const_iterator it(*this);
+  ++d_idx;
+  return it;
+}
+
+bool Datatype::const_iterator::operator==(
+    const Datatype::const_iterator& other) const
+{
+  return d_int_ctors == other.d_int_ctors && d_idx == other.d_idx;
+}
+
+bool Datatype::const_iterator::operator!=(
+    const Datatype::const_iterator& other) const
+{
+  return d_int_ctors != other.d_int_ctors || d_idx != other.d_idx;
+}
+
+bool Datatype::isNullHelper() const { return d_dtype == nullptr; }
+
+/* -------------------------------------------------------------------------- */
+/* Grammar                                                                    */
+/* -------------------------------------------------------------------------- */
+
+Grammar::Grammar()
+    : d_solver(nullptr),
+      d_sygusVars(),
+      d_ntSyms(),
+      d_ntsToTerms(0),
+      d_allowConst(),
+      d_allowVars(),
+      d_isResolved(false)
+{
+}
+
+Grammar::Grammar(const Solver* slv,
+                 const std::vector<Term>& sygusVars,
+                 const std::vector<Term>& ntSymbols)
+    : d_solver(slv),
+      d_sygusVars(sygusVars),
+      d_ntSyms(ntSymbols),
+      d_ntsToTerms(ntSymbols.size()),
+      d_allowConst(),
+      d_allowVars(),
+      d_isResolved(false)
+{
+  for (Term ntsymbol : d_ntSyms)
+  {
+    d_ntsToTerms.emplace(ntsymbol, std::vector<Term>());
+  }
+}
+
+void Grammar::addRule(const Term& ntSymbol, const Term& rule)
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK(!d_isResolved) << "Grammar cannot be modified after passing "
+                                   "it as an argument to synthFun/synthInv";
+  CVC4_API_CHECK_TERM(ntSymbol);
+  CVC4_API_CHECK_TERM(rule);
+  CVC4_API_ARG_CHECK_EXPECTED(
+      d_ntsToTerms.find(ntSymbol) != d_ntsToTerms.cend(), ntSymbol)
+      << "ntSymbol to be one of the non-terminal symbols given in the "
+         "predeclaration";
+  CVC4_API_CHECK(ntSymbol.d_node->getType() == rule.d_node->getType())
+      << "Expected ntSymbol and rule to have the same sort";
+  CVC4_API_ARG_CHECK_EXPECTED(!containsFreeVariables(rule), rule)
+      << "a term whose free variables are limited to synthFun/synthInv "
+         "parameters and non-terminal symbols of the grammar";
+  //////// all checks before this line
+  d_ntsToTerms[ntSymbol].push_back(rule);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+void Grammar::addRules(const Term& ntSymbol, const std::vector<Term>& rules)
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK(!d_isResolved) << "Grammar cannot be modified after passing "
+                                   "it as an argument to synthFun/synthInv";
+  CVC4_API_CHECK_TERM(ntSymbol);
+  CVC4_API_CHECK_TERMS_WITH_SORT(rules, ntSymbol.getSort());
+  CVC4_API_ARG_CHECK_EXPECTED(
+      d_ntsToTerms.find(ntSymbol) != d_ntsToTerms.cend(), ntSymbol)
+      << "ntSymbol to be one of the non-terminal symbols given in the "
+         "predeclaration";
+  for (size_t i = 0, n = rules.size(); i < n; ++i)
+  {
+    CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
+        !containsFreeVariables(rules[i]), rules[i], rules, i)
+        << "a term whose free variables are limited to synthFun/synthInv "
+           "parameters and non-terminal symbols of the grammar";
+  }
+  //////// all checks before this line
+  d_ntsToTerms[ntSymbol].insert(
+      d_ntsToTerms[ntSymbol].cend(), rules.cbegin(), rules.cend());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+void Grammar::addAnyConstant(const Term& ntSymbol)
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK(!d_isResolved) << "Grammar cannot be modified after passing "
+                                   "it as an argument to synthFun/synthInv";
+  CVC4_API_CHECK_TERM(ntSymbol);
+  CVC4_API_ARG_CHECK_EXPECTED(
+      d_ntsToTerms.find(ntSymbol) != d_ntsToTerms.cend(), ntSymbol)
+      << "ntSymbol to be one of the non-terminal symbols given in the "
+         "predeclaration";
+  //////// all checks before this line
+  d_allowConst.insert(ntSymbol);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+void Grammar::addAnyVariable(const Term& ntSymbol)
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK(!d_isResolved) << "Grammar cannot be modified after passing "
+                                   "it as an argument to synthFun/synthInv";
+  CVC4_API_CHECK_TERM(ntSymbol);
+  CVC4_API_ARG_CHECK_EXPECTED(
+      d_ntsToTerms.find(ntSymbol) != d_ntsToTerms.cend(), ntSymbol)
+      << "ntSymbol to be one of the non-terminal symbols given in the "
+         "predeclaration";
+  //////// all checks before this line
+  d_allowVars.insert(ntSymbol);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/**
+ * this function concatinates the outputs of calling f on each element between
+ * first and last, seperated by sep.
+ * @param first the beginning of the range
+ * @param last the end of the range
+ * @param f the function to call on each element in the range, its output must
+ *          be overloaded for operator<<
+ * @param sep the string to add between successive calls to f
+ */
+template <typename Iterator, typename Function>
+std::string join(Iterator first, Iterator last, Function f, std::string sep)
+{
+  std::stringstream ss;
+  Iterator i = first;
+
+  if (i != last)
+  {
+    ss << f(*i);
+    ++i;
+  }
+
+  while (i != last)
+  {
+    ss << sep << f(*i);
+    ++i;
+  }
+
+  return ss.str();
+}
+
+std::string Grammar::toString() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  std::stringstream ss;
+  ss << "  ("  // pre-declaration
+     << join(
+            d_ntSyms.cbegin(),
+            d_ntSyms.cend(),
+            [](const Term& t) {
+              std::stringstream s;
+              s << '(' << t << ' ' << t.getSort() << ')';
+              return s.str();
+            },
+            " ")
+     << ")\n  ("  // grouped rule listing
+     << join(
+            d_ntSyms.cbegin(),
+            d_ntSyms.cend(),
+            [this](const Term& t) {
+              bool allowConst = d_allowConst.find(t) != d_allowConst.cend(),
+                   allowVars = d_allowVars.find(t) != d_allowVars.cend();
+              const std::vector<Term>& rules = d_ntsToTerms.at(t);
+              std::stringstream s;
+              s << '(' << t << ' ' << t.getSort() << " ("
+                << (allowConst ? "(Constant " + t.getSort().toString() + ")"
+                               : "")
+                << (allowConst && allowVars ? " " : "")
+                << (allowVars ? "(Var " + t.getSort().toString() + ")" : "")
+                << ((allowConst || allowVars) && !rules.empty() ? " " : "")
+                << join(
+                       rules.cbegin(),
+                       rules.cend(),
+                       [](const Term& rule) { return rule.toString(); },
+                       " ")
+                << "))";
+              return s.str();
+            },
+            "\n   ")
+     << ')';
+
+  return ss.str();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Grammar::resolve()
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+
+  d_isResolved = true;
+
+  Term bvl;
+
+  if (!d_sygusVars.empty())
+  {
+    bvl = Term(
+        d_solver,
+        d_solver->getNodeManager()->mkNode(
+            cvc5::kind::BOUND_VAR_LIST, Term::termVectorToNodes(d_sygusVars)));
+  }
+
+  std::unordered_map<Term, Sort, TermHashFunction> ntsToUnres(d_ntSyms.size());
+
+  for (Term ntsymbol : d_ntSyms)
+  {
+    // make the unresolved type, used for referencing the final version of
+    // the ntsymbol's datatype
+    ntsToUnres[ntsymbol] =
+        Sort(d_solver, d_solver->getNodeManager()->mkSort(ntsymbol.toString()));
+  }
+
+  std::vector<cvc5::DType> datatypes;
+  std::set<TypeNode> unresTypes;
+
+  datatypes.reserve(d_ntSyms.size());
+
+  for (const Term& ntSym : d_ntSyms)
+  {
+    // make the datatype, which encodes terms generated by this non-terminal
+    DatatypeDecl dtDecl(d_solver, ntSym.toString());
+
+    for (const Term& consTerm : d_ntsToTerms[ntSym])
+    {
+      addSygusConstructorTerm(dtDecl, consTerm, ntsToUnres);
+    }
+
+    if (d_allowVars.find(ntSym) != d_allowVars.cend())
+    {
+      addSygusConstructorVariables(dtDecl,
+                                   Sort(d_solver, ntSym.d_node->getType()));
+    }
+
+    bool aci = d_allowConst.find(ntSym) != d_allowConst.end();
+    TypeNode btt = ntSym.d_node->getType();
+    dtDecl.d_dtype->setSygus(btt, *bvl.d_node, aci, false);
+
+    // We can be in a case where the only rule specified was (Variable T)
+    // and there are no variables of type T, in which case this is a bogus
+    // grammar. This results in the error below.
+    CVC4_API_CHECK(dtDecl.d_dtype->getNumConstructors() != 0)
+        << "Grouped rule listing for " << *dtDecl.d_dtype
+        << " produced an empty rule list";
+
+    datatypes.push_back(*dtDecl.d_dtype);
+    unresTypes.insert(*ntsToUnres[ntSym].d_type);
+  }
+
+  std::vector<TypeNode> datatypeTypes =
+      d_solver->getNodeManager()->mkMutualDatatypeTypes(
+          datatypes, unresTypes, NodeManager::DATATYPE_FLAG_PLACEHOLDER);
+
+  // return is the first datatype
+  return Sort(d_solver, datatypeTypes[0]);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+void Grammar::addSygusConstructorTerm(
+    DatatypeDecl& dt,
+    const Term& term,
+    const std::unordered_map<Term, Sort, TermHashFunction>& ntsToUnres) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_DTDECL(dt);
+  CVC4_API_CHECK_TERM(term);
+  CVC4_API_CHECK_TERMS_MAP(ntsToUnres);
+  //////// all checks before this line
+
+  // At this point, we should know that dt is well founded, and that its
+  // builtin sygus operators are well-typed.
+  // Now, purify each occurrence of a non-terminal symbol in term, replace by
+  // free variables. These become arguments to constructors. Notice we must do
+  // a tree traversal in this function, since unique paths to the same term
+  // should be treated as distinct terms.
+  // Notice that let expressions are forbidden in the input syntax of term, so
+  // this does not lead to exponential behavior with respect to input size.
+  std::vector<Term> args;
+  std::vector<Sort> cargs;
+  Term op = purifySygusGTerm(term, args, cargs, ntsToUnres);
+  std::stringstream ssCName;
+  ssCName << op.getKind();
+  if (!args.empty())
+  {
+    Term lbvl =
+        Term(d_solver,
+             d_solver->getNodeManager()->mkNode(cvc5::kind::BOUND_VAR_LIST,
+                                                Term::termVectorToNodes(args)));
+    // its operator is a lambda
+    op = Term(d_solver,
+              d_solver->getNodeManager()->mkNode(
+                  cvc5::kind::LAMBDA, *lbvl.d_node, *op.d_node));
+  }
+  std::vector<TypeNode> cargst = Sort::sortVectorToTypeNodes(cargs);
+  dt.d_dtype->addSygusConstructor(*op.d_node, ssCName.str(), cargst);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Grammar::purifySygusGTerm(
+    const Term& term,
+    std::vector<Term>& args,
+    std::vector<Sort>& cargs,
+    const std::unordered_map<Term, Sort, TermHashFunction>& ntsToUnres) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_TERM(term);
+  CVC4_API_CHECK_TERMS(args);
+  CVC4_API_CHECK_SORTS(cargs);
+  CVC4_API_CHECK_TERMS_MAP(ntsToUnres);
+  //////// all checks before this line
+
+  std::unordered_map<Term, Sort, TermHashFunction>::const_iterator itn =
+      ntsToUnres.find(term);
+  if (itn != ntsToUnres.cend())
+  {
+    Term ret =
+        Term(d_solver,
+             d_solver->getNodeManager()->mkBoundVar(term.d_node->getType()));
+    args.push_back(ret);
+    cargs.push_back(itn->second);
+    return ret;
+  }
+  std::vector<Term> pchildren;
+  bool childChanged = false;
+  for (unsigned i = 0, nchild = term.d_node->getNumChildren(); i < nchild; i++)
+  {
+    Term ptermc = purifySygusGTerm(
+        Term(d_solver, (*term.d_node)[i]), args, cargs, ntsToUnres);
+    pchildren.push_back(ptermc);
+    childChanged = childChanged || *ptermc.d_node != (*term.d_node)[i];
+  }
+  if (!childChanged)
+  {
+    return term;
+  }
+
+  Node nret;
+
+  if (term.d_node->getMetaKind() == kind::metakind::PARAMETERIZED)
+  {
+    // it's an indexed operator so we should provide the op
+    NodeBuilder<> nb(term.d_node->getKind());
+    nb << term.d_node->getOperator();
+    nb.append(Term::termVectorToNodes(pchildren));
+    nret = nb.constructNode();
+  }
+  else
+  {
+    nret = d_solver->getNodeManager()->mkNode(
+        term.d_node->getKind(), Term::termVectorToNodes(pchildren));
+  }
+
+  return Term(d_solver, nret);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+void Grammar::addSygusConstructorVariables(DatatypeDecl& dt,
+                                           const Sort& sort) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK_DTDECL(dt);
+  CVC4_API_CHECK_SORT(sort);
+  //////// all checks before this line
+
+  // each variable of appropriate type becomes a sygus constructor in dt.
+  for (unsigned i = 0, size = d_sygusVars.size(); i < size; i++)
+  {
+    Term v = d_sygusVars[i];
+    if (v.d_node->getType() == *sort.d_type)
+    {
+      std::stringstream ss;
+      ss << v;
+      std::vector<TypeNode> cargs;
+      dt.d_dtype->addSygusConstructor(*v.d_node, ss.str(), cargs);
+    }
+  }
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Grammar::containsFreeVariables(const Term& rule) const
+{
+  std::unordered_set<TNode, TNodeHashFunction> scope;
+
+  for (const Term& sygusVar : d_sygusVars)
+  {
+    scope.emplace(*sygusVar.d_node);
+  }
+
+  for (const Term& ntsymbol : d_ntSyms)
+  {
+    scope.emplace(*ntsymbol.d_node);
+  }
+
+  std::unordered_set<Node, NodeHashFunction> fvs;
+  return expr::getFreeVariablesScope(*rule.d_node, fvs, scope, false);
+}
+
+std::ostream& operator<<(std::ostream& out, const Grammar& grammar)
+{
+  return out << grammar.toString();
+}
+
+/* -------------------------------------------------------------------------- */
+/* Rounding Mode for Floating Points                                          */
+/* -------------------------------------------------------------------------- */
+
+const static std::
+    unordered_map<RoundingMode, cvc5::RoundingMode, RoundingModeHashFunction>
+        s_rmodes{
+            {ROUND_NEAREST_TIES_TO_EVEN,
+             cvc5::RoundingMode::ROUND_NEAREST_TIES_TO_EVEN},
+            {ROUND_TOWARD_POSITIVE, cvc5::RoundingMode::ROUND_TOWARD_POSITIVE},
+            {ROUND_TOWARD_NEGATIVE, cvc5::RoundingMode::ROUND_TOWARD_NEGATIVE},
+            {ROUND_TOWARD_ZERO, cvc5::RoundingMode::ROUND_TOWARD_ZERO},
+            {ROUND_NEAREST_TIES_TO_AWAY,
+             cvc5::RoundingMode::ROUND_NEAREST_TIES_TO_AWAY},
+        };
+
+const static std::unordered_map<cvc5::RoundingMode,
+                                RoundingMode,
+                                cvc5::RoundingModeHashFunction>
+    s_rmodes_internal{
+        {cvc5::RoundingMode::ROUND_NEAREST_TIES_TO_EVEN,
+         ROUND_NEAREST_TIES_TO_EVEN},
+        {cvc5::RoundingMode::ROUND_TOWARD_POSITIVE, ROUND_TOWARD_POSITIVE},
+        {cvc5::RoundingMode::ROUND_TOWARD_POSITIVE, ROUND_TOWARD_NEGATIVE},
+        {cvc5::RoundingMode::ROUND_TOWARD_ZERO, ROUND_TOWARD_ZERO},
+        {cvc5::RoundingMode::ROUND_NEAREST_TIES_TO_AWAY,
+         ROUND_NEAREST_TIES_TO_AWAY},
+    };
+
+size_t RoundingModeHashFunction::operator()(const RoundingMode& rm) const
+{
+  return size_t(rm);
+}
+
+/* -------------------------------------------------------------------------- */
+/* Solver                                                                     */
+/* -------------------------------------------------------------------------- */
+
+Solver::Solver(Options* opts)
+{
+  d_nodeMgr.reset(new NodeManager());
+  d_originalOptions.reset(new Options());
+  if (opts != nullptr)
+  {
+    d_originalOptions->copyValues(*opts);
+  }
+  d_smtEngine.reset(new SmtEngine(d_nodeMgr.get(), d_originalOptions.get()));
+  d_smtEngine->setSolver(this);
+  d_rng.reset(new Random(d_smtEngine->getOptions()[options::seed]));
+#if CVC4_STATISTICS_ON
+  d_stats.reset(new Statistics());
+  d_smtEngine->getStatisticsRegistry().registerStat(&d_stats->d_consts);
+  d_smtEngine->getStatisticsRegistry().registerStat(&d_stats->d_vars);
+  d_smtEngine->getStatisticsRegistry().registerStat(&d_stats->d_terms);
+#endif
+}
+
+Solver::~Solver() {}
+
+/* Helpers and private functions                                              */
+/* -------------------------------------------------------------------------- */
+
+NodeManager* Solver::getNodeManager(void) const { return d_nodeMgr.get(); }
+
+void Solver::increment_term_stats(Kind kind) const
+{
+#ifdef CVC4_STATISTICS_ON
+  d_stats->d_terms << kind;
+#endif
+}
+
+void Solver::increment_vars_consts_stats(const Sort& sort, bool is_var) const
+{
+#ifdef CVC4_STATISTICS_ON
+  const TypeNode tn = sort.getTypeNode();
+  TypeConstant tc = tn.getKind() == cvc5::kind::TYPE_CONSTANT
+                        ? tn.getConst<TypeConstant>()
+                        : LAST_TYPE;
+  if (is_var)
+  {
+    d_stats->d_vars << tc;
+  }
+  else
+  {
+    d_stats->d_consts << tc;
+  }
+#endif
+}
+
+/* Split out to avoid nested API calls (problematic with API tracing).        */
+/* .......................................................................... */
+
+template <typename T>
+Term Solver::mkValHelper(T t) const
+{
+  //////// all checks before this line
+  Node res = getNodeManager()->mkConst(t);
+  (void)res.getType(true); /* kick off type checking */
+  return Term(this, res);
+}
+
+Term Solver::mkRealFromStrHelper(const std::string& s) const
+{
+  //////// all checks before this line
+  try
+  {
+    cvc5::Rational r = s.find('/') != std::string::npos
+                           ? cvc5::Rational(s)
+                           : cvc5::Rational::fromDecimal(s);
+    return mkValHelper<cvc5::Rational>(r);
+  }
+  catch (const std::invalid_argument& e)
+  {
+    /* Catch to throw with a more meaningful error message. To be caught in
+     * enclosing CVC4_API_TRY_CATCH_* block to throw CVC4ApiException. */
+    std::stringstream message;
+    message << "Cannot construct Real or Int from string argument '" << s << "'"
+            << std::endl;
+    throw std::invalid_argument(message.str());
+  }
+}
+
+Term Solver::mkBVFromIntHelper(uint32_t size, uint64_t val) const
+{
+  CVC4_API_ARG_CHECK_EXPECTED(size > 0, size) << "a bit-width > 0";
+  //////// all checks before this line
+  return mkValHelper<cvc5::BitVector>(cvc5::BitVector(size, val));
+}
+
+Term Solver::mkBVFromStrHelper(const std::string& s, uint32_t base) const
+{
+  CVC4_API_ARG_CHECK_EXPECTED(!s.empty(), s) << "a non-empty string";
+  CVC4_API_ARG_CHECK_EXPECTED(base == 2 || base == 10 || base == 16, base)
+      << "base 2, 10, or 16";
+  //////// all checks before this line
+  return mkValHelper<cvc5::BitVector>(cvc5::BitVector(s, base));
+}
+
+Term Solver::mkBVFromStrHelper(uint32_t size,
+                               const std::string& s,
+                               uint32_t base) const
+{
+  CVC4_API_ARG_CHECK_EXPECTED(!s.empty(), s) << "a non-empty string";
+  CVC4_API_ARG_CHECK_EXPECTED(base == 2 || base == 10 || base == 16, base)
+      << "base 2, 10, or 16";
+  //////// all checks before this line
+
+  Integer val(s, base);
+
+  if (val.strictlyNegative())
+  {
+    CVC4_API_CHECK(val >= -Integer("2", 10).pow(size - 1))
+        << "Overflow in bitvector construction (specified bitvector size "
+        << size << " too small to hold value " << s << ")";
+  }
+  else
+  {
+    CVC4_API_CHECK(val.modByPow2(size) == val)
+        << "Overflow in bitvector construction (specified bitvector size "
+        << size << " too small to hold value " << s << ")";
+  }
+
+  return mkValHelper<cvc5::BitVector>(cvc5::BitVector(size, val));
+}
+
+Term Solver::mkCharFromStrHelper(const std::string& s) const
+{
+  CVC4_API_CHECK(s.find_first_not_of("0123456789abcdefABCDEF", 0)
+                     == std::string::npos
+                 && s.size() <= 5 && s.size() > 0)
+      << "Unexpected string for hexadecimal character " << s;
+  uint32_t val = static_cast<uint32_t>(std::stoul(s, 0, 16));
+  CVC4_API_CHECK(val < String::num_codes())
+      << "Not a valid code point for hexadecimal character " << s;
+  //////// all checks before this line
+  std::vector<unsigned> cpts;
+  cpts.push_back(val);
+  return mkValHelper<cvc5::String>(cvc5::String(cpts));
+}
+
+Term Solver::getValueHelper(const Term& term) const
+{
+  // Note: Term is checked in the caller to avoid double checks
+  //////// all checks before this line
+  Node value = d_smtEngine->getValue(*term.d_node);
+  Term res = Term(this, value);
+  // May need to wrap in real cast so that user know this is a real.
+  TypeNode tn = (*term.d_node).getType();
+  if (!tn.isInteger() && value.getType().isInteger())
+  {
+    return ensureRealSort(res);
+  }
+  return res;
+}
+
+Sort Solver::mkTupleSortHelper(const std::vector<Sort>& sorts) const
+{
+  // Note: Sorts are checked in the caller to avoid double checks
+  //////// all checks before this line
+  std::vector<TypeNode> typeNodes = Sort::sortVectorToTypeNodes(sorts);
+  return Sort(this, getNodeManager()->mkTupleType(typeNodes));
+}
+
+Term Solver::mkTermFromKind(Kind kind) const
+{
+  CVC4_API_KIND_CHECK_EXPECTED(
+      kind == PI || kind == REGEXP_EMPTY || kind == REGEXP_SIGMA, kind)
+      << "PI or REGEXP_EMPTY or REGEXP_SIGMA";
+  //////// all checks before this line
+  Node res;
+  if (kind == REGEXP_EMPTY || kind == REGEXP_SIGMA)
+  {
+    cvc5::Kind k = extToIntKind(kind);
+    Assert(isDefinedIntKind(k));
+    res = d_nodeMgr->mkNode(k, std::vector<Node>());
+  }
+  else
+  {
+    Assert(kind == PI);
+    res = d_nodeMgr->mkNullaryOperator(d_nodeMgr->realType(), cvc5::kind::PI);
+  }
+  (void)res.getType(true); /* kick off type checking */
+  increment_term_stats(kind);
+  return Term(this, res);
+}
+
+Term Solver::mkTermHelper(Kind kind, const std::vector<Term>& children) const
+{
+  // Note: Kind and children are checked in the caller to avoid double checks
+  //////// all checks before this line
+
+  std::vector<Node> echildren = Term::termVectorToNodes(children);
+  cvc5::Kind k = extToIntKind(kind);
+  Node res;
+  if (echildren.size() > 2)
+  {
+    if (kind == INTS_DIVISION || kind == XOR || kind == MINUS
+        || kind == DIVISION || kind == HO_APPLY || kind == REGEXP_DIFF)
+    {
+      // left-associative, but CVC4 internally only supports 2 args
+      res = d_nodeMgr->mkLeftAssociative(k, echildren);
+    }
+    else if (kind == IMPLIES)
+    {
+      // right-associative, but CVC4 internally only supports 2 args
+      res = d_nodeMgr->mkRightAssociative(k, echildren);
+    }
+    else if (kind == EQUAL || kind == LT || kind == GT || kind == LEQ
+             || kind == GEQ)
+    {
+      // "chainable", but CVC4 internally only supports 2 args
+      res = d_nodeMgr->mkChain(k, echildren);
+    }
+    else if (kind::isAssociative(k))
+    {
+      // mkAssociative has special treatment for associative operators with lots
+      // of children
+      res = d_nodeMgr->mkAssociative(k, echildren);
+    }
+    else
+    {
+      // default case, must check kind
+      checkMkTerm(kind, children.size());
+      res = d_nodeMgr->mkNode(k, echildren);
+    }
+  }
+  else if (kind::isAssociative(k))
+  {
+    // associative case, same as above
+    res = d_nodeMgr->mkAssociative(k, echildren);
+  }
+  else
+  {
+    // default case, same as above
+    checkMkTerm(kind, children.size());
+    if (kind == api::SINGLETON)
+    {
+      // the type of the term is the same as the type of the internal node
+      // see Term::getSort()
+      TypeNode type = children[0].d_node->getType();
+      // Internally NodeManager::mkSingleton needs a type argument
+      // to construct a singleton, since there is no difference between
+      // integers and reals (both are Rationals).
+      // At the API, mkReal and mkInteger are different and therefore the
+      // element type can be used safely here.
+      res = getNodeManager()->mkSingleton(type, *children[0].d_node);
+    }
+    else if (kind == api::MK_BAG)
+    {
+      // the type of the term is the same as the type of the internal node
+      // see Term::getSort()
+      TypeNode type = children[0].d_node->getType();
+      // Internally NodeManager::mkBag needs a type argument
+      // to construct a bag, since there is no difference between
+      // integers and reals (both are Rationals).
+      // At the API, mkReal and mkInteger are different and therefore the
+      // element type can be used safely here.
+      res = getNodeManager()->mkBag(
+          type, *children[0].d_node, *children[1].d_node);
+    }
+    else
+    {
+      res = d_nodeMgr->mkNode(k, echildren);
+    }
+  }
+
+  (void)res.getType(true); /* kick off type checking */
+  increment_term_stats(kind);
+  return Term(this, res);
+}
+
+Term Solver::mkTermHelper(const Op& op, const std::vector<Term>& children) const
+{
+  // Note: Op and children are checked in the caller to avoid double checks
+  checkMkTerm(op.d_kind, children.size());
+  //////// all checks before this line
+
+  if (!op.isIndexedHelper())
+  {
+    return mkTermHelper(op.d_kind, children);
+  }
+
+  const cvc5::Kind int_kind = extToIntKind(op.d_kind);
+  std::vector<Node> echildren = Term::termVectorToNodes(children);
+
+  NodeBuilder<> nb(int_kind);
+  nb << *op.d_node;
+  nb.append(echildren);
+  Node res = nb.constructNode();
+
+  (void)res.getType(true); /* kick off type checking */
+  return Term(this, res);
+}
+
+std::vector<Sort> Solver::mkDatatypeSortsInternal(
+    const std::vector<DatatypeDecl>& dtypedecls,
+    const std::set<Sort>& unresolvedSorts) const
+{
+  // Note: dtypedecls and unresolvedSorts are checked in the caller to avoid
+  //       double checks
+  //////// all checks before this line
+
+  std::vector<cvc5::DType> datatypes;
+  for (size_t i = 0, ndts = dtypedecls.size(); i < ndts; ++i)
+  {
+    datatypes.push_back(dtypedecls[i].getDatatype());
+  }
+
+  std::set<TypeNode> utypes = Sort::sortSetToTypeNodes(unresolvedSorts);
+  std::vector<cvc5::TypeNode> dtypes =
+      getNodeManager()->mkMutualDatatypeTypes(datatypes, utypes);
+  std::vector<Sort> retTypes = Sort::typeNodeVectorToSorts(this, dtypes);
+  return retTypes;
+}
+
+Term Solver::synthFunHelper(const std::string& symbol,
+                            const std::vector<Term>& boundVars,
+                            const Sort& sort,
+                            bool isInv,
+                            Grammar* grammar) const
+{
+  // Note: boundVars, sort and grammar are checked in the caller to avoid
+  //       double checks.
+  std::vector<TypeNode> varTypes;
+  for (const auto& bv : boundVars)
+  {
+    if (grammar)
+    {
+      CVC4_API_CHECK(grammar->d_ntSyms[0].d_node->getType() == *sort.d_type)
+          << "Invalid Start symbol for grammar, Expected Start's sort to be "
+          << *sort.d_type << " but found "
+          << grammar->d_ntSyms[0].d_node->getType();
+    }
+    varTypes.push_back(bv.d_node->getType());
+  }
+  //////// all checks before this line
+
+  TypeNode funType = varTypes.empty() ? *sort.d_type
+                                      : getNodeManager()->mkFunctionType(
+                                          varTypes, *sort.d_type);
+
+  Node fun = getNodeManager()->mkBoundVar(symbol, funType);
+  (void)fun.getType(true); /* kick off type checking */
+
+  std::vector<Node> bvns = Term::termVectorToNodes(boundVars);
+
+  d_smtEngine->declareSynthFun(
+      fun,
+      grammar == nullptr ? funType : *grammar->resolve().d_type,
+      isInv,
+      bvns);
+
+  return Term(this, fun);
+}
+
+Term Solver::ensureTermSort(const Term& term, const Sort& sort) const
+{
+  // Note: Term and sort are checked in the caller to avoid double checks
+  CVC4_API_CHECK(term.getSort() == sort
+                 || (term.getSort().isInteger() && sort.isReal()))
+      << "Expected conversion from Int to Real";
+  //////// all checks before this line
+
+  Sort t = term.getSort();
+  if (term.getSort() == sort)
+  {
+    return term;
+  }
+
+  // Integers are reals, too
+  Assert(t.d_type->isReal());
+  Term res = term;
+  if (t.isInteger())
+  {
+    // Must cast to Real to ensure correct type is passed to parametric type
+    // constructors. We do this cast using division with 1. This has the
+    // advantage wrt using TO_REAL since (constant) division is always included
+    // in the theory.
+    res = Term(this,
+               d_nodeMgr->mkNode(extToIntKind(DIVISION),
+                                 *res.d_node,
+                                 d_nodeMgr->mkConst(cvc5::Rational(1))));
+  }
+  Assert(res.getSort() == sort);
+  return res;
+}
+
+Term Solver::ensureRealSort(const Term& t) const
+{
+  Assert(this == t.d_solver);
+  CVC4_API_ARG_CHECK_EXPECTED(
+      t.getSort() == getIntegerSort() || t.getSort() == getRealSort(),
+      " an integer or real term");
+  // Note: Term is checked in the caller to avoid double checks
+  //////// all checks before this line
+  if (t.getSort() == getIntegerSort())
+  {
+    Node n = getNodeManager()->mkNode(kind::CAST_TO_REAL, *t.d_node);
+    return Term(this, n);
+  }
+  return t;
+}
+
+bool Solver::isValidInteger(const std::string& s) const
+{
+  //////// all checks before this line
+  if (s.length() == 0)
+  {
+    // string should not be empty
+    return false;
+  }
+
+  size_t index = 0;
+  if (s[index] == '-')
+  {
+    if (s.length() == 1)
+    {
+      // negative integers should contain at least one digit
+      return false;
+    }
+    index = 1;
+  }
+
+  if (s[index] == '0' && s.length() > (index + 1))
+  {
+    // From SMT-Lib 2.6: A <numeral> is the digit 0 or a non-empty sequence of
+    // digits not starting with 0. So integers like 001, 000 are not allowed
+    return false;
+  }
+
+  // all remaining characters should be decimal digits
+  for (; index < s.length(); ++index)
+  {
+    if (!std::isdigit(s[index]))
+    {
+      return false;
+    }
+  }
+
+  return true;
+}
+
+/* Helpers for mkTerm checks.                                                 */
+/* .......................................................................... */
+
+void Solver::checkMkTerm(Kind kind, uint32_t nchildren) const
+{
+  CVC4_API_KIND_CHECK(kind);
+  Assert(isDefinedIntKind(extToIntKind(kind)));
+  const cvc5::kind::MetaKind mk = kind::metaKindOf(extToIntKind(kind));
+  CVC4_API_KIND_CHECK_EXPECTED(
+      mk == kind::metakind::PARAMETERIZED || mk == kind::metakind::OPERATOR,
+      kind)
+      << "Only operator-style terms are created with mkTerm(), "
+         "to create variables, constants and values see mkVar(), mkConst() "
+         "and the respective theory-specific functions to create values, "
+         "e.g., mkBitVector().";
+  CVC4_API_KIND_CHECK_EXPECTED(
+      nchildren >= minArity(kind) && nchildren <= maxArity(kind), kind)
+      << "Terms with kind " << kindToString(kind) << " must have at least "
+      << minArity(kind) << " children and at most " << maxArity(kind)
+      << " children (the one under construction has " << nchildren << ")";
+}
+
+/* Solver Configuration                                                       */
+/* -------------------------------------------------------------------------- */
+
+bool Solver::supportsFloatingPoint() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return Configuration::isBuiltWithSymFPU();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/* Sorts Handling                                                             */
+/* -------------------------------------------------------------------------- */
+
+Sort Solver::getNullSort(void) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return Sort(this, TypeNode());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Solver::getBooleanSort(void) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return Sort(this, getNodeManager()->booleanType());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Solver::getIntegerSort(void) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return Sort(this, getNodeManager()->integerType());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Solver::getRealSort(void) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return Sort(this, getNodeManager()->realType());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Solver::getRegExpSort(void) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return Sort(this, getNodeManager()->regExpType());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Solver::getStringSort(void) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return Sort(this, getNodeManager()->stringType());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Solver::getRoundingModeSort(void) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK(Configuration::isBuiltWithSymFPU())
+      << "Expected CVC4 to be compiled with SymFPU support";
+  //////// all checks before this line
+  return Sort(this, getNodeManager()->roundingModeType());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/* Create sorts ------------------------------------------------------- */
+
+Sort Solver::mkArraySort(const Sort& indexSort, const Sort& elemSort) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_SORT(indexSort);
+  CVC4_API_SOLVER_CHECK_SORT(elemSort);
+  //////// all checks before this line
+  return Sort(
+      this, getNodeManager()->mkArrayType(*indexSort.d_type, *elemSort.d_type));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Solver::mkBitVectorSort(uint32_t size) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_ARG_CHECK_EXPECTED(size > 0, size) << "size > 0";
+  //////// all checks before this line
+  return Sort(this, getNodeManager()->mkBitVectorType(size));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Solver::mkFloatingPointSort(uint32_t exp, uint32_t sig) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK(Configuration::isBuiltWithSymFPU())
+      << "Expected CVC4 to be compiled with SymFPU support";
+  CVC4_API_ARG_CHECK_EXPECTED(exp > 0, exp) << "exponent size > 0";
+  CVC4_API_ARG_CHECK_EXPECTED(sig > 0, sig) << "significand size > 0";
+  //////// all checks before this line
+  return Sort(this, getNodeManager()->mkFloatingPointType(exp, sig));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Solver::mkDatatypeSort(const DatatypeDecl& dtypedecl) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_DTDECL(dtypedecl);
+  //////// all checks before this line
+  return Sort(this, getNodeManager()->mkDatatypeType(*dtypedecl.d_dtype));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+std::vector<Sort> Solver::mkDatatypeSorts(
+    const std::vector<DatatypeDecl>& dtypedecls) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_SOLVER_CHECK_DTDECLS(dtypedecls);
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return mkDatatypeSortsInternal(dtypedecls, {});
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+std::vector<Sort> Solver::mkDatatypeSorts(
+    const std::vector<DatatypeDecl>& dtypedecls,
+    const std::set<Sort>& unresolvedSorts) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_DTDECLS(dtypedecls);
+  CVC4_API_SOLVER_CHECK_SORTS(unresolvedSorts);
+  //////// all checks before this line
+  return mkDatatypeSortsInternal(dtypedecls, unresolvedSorts);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Solver::mkFunctionSort(const Sort& domain, const Sort& codomain) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_DOMAIN_SORT(domain);
+  CVC4_API_SOLVER_CHECK_CODOMAIN_SORT(codomain);
+  //////// all checks before this line
+  return Sort(
+      this, getNodeManager()->mkFunctionType(*domain.d_type, *codomain.d_type));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Solver::mkFunctionSort(const std::vector<Sort>& sorts,
+                            const Sort& codomain) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_ARG_SIZE_CHECK_EXPECTED(sorts.size() >= 1, sorts)
+      << "at least one parameter sort for function sort";
+  CVC4_API_SOLVER_CHECK_DOMAIN_SORTS(sorts);
+  CVC4_API_SOLVER_CHECK_CODOMAIN_SORT(codomain);
+  //////// all checks before this line
+  std::vector<TypeNode> argTypes = Sort::sortVectorToTypeNodes(sorts);
+  return Sort(this,
+              getNodeManager()->mkFunctionType(argTypes, *codomain.d_type));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Solver::mkParamSort(const std::string& symbol) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return Sort(
+      this,
+      getNodeManager()->mkSort(symbol, NodeManager::SORT_FLAG_PLACEHOLDER));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Solver::mkPredicateSort(const std::vector<Sort>& sorts) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_ARG_SIZE_CHECK_EXPECTED(sorts.size() >= 1, sorts)
+      << "at least one parameter sort for predicate sort";
+  CVC4_API_SOLVER_CHECK_DOMAIN_SORTS(sorts);
+  //////// all checks before this line
+  return Sort(
+      this,
+      getNodeManager()->mkPredicateType(Sort::sortVectorToTypeNodes(sorts)));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Solver::mkRecordSort(
+    const std::vector<std::pair<std::string, Sort>>& fields) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  std::vector<std::pair<std::string, TypeNode>> f;
+  for (size_t i = 0, size = fields.size(); i < size; ++i)
+  {
+    const auto& p = fields[i];
+    CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(!p.second.isNull(), "sort", fields, i)
+        << "non-null sort";
+    CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
+        this == p.second.d_solver, "sort", fields, i)
+        << "sort associated with this solver object";
+    f.emplace_back(p.first, *p.second.d_type);
+  }
+  //////// all checks before this line
+  return Sort(this, getNodeManager()->mkRecordType(f));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Solver::mkSetSort(const Sort& elemSort) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_SORT(elemSort);
+  //////// all checks before this line
+  return Sort(this, getNodeManager()->mkSetType(*elemSort.d_type));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Solver::mkBagSort(const Sort& elemSort) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_SORT(elemSort);
+  //////// all checks before this line
+  return Sort(this, getNodeManager()->mkBagType(*elemSort.d_type));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Solver::mkSequenceSort(const Sort& elemSort) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_SORT(elemSort);
+  //////// all checks before this line
+  return Sort(this, getNodeManager()->mkSequenceType(*elemSort.d_type));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Solver::mkUninterpretedSort(const std::string& symbol) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return Sort(this, getNodeManager()->mkSort(symbol));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Solver::mkSortConstructorSort(const std::string& symbol,
+                                   size_t arity) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_ARG_CHECK_EXPECTED(arity > 0, arity) << "an arity > 0";
+  //////// all checks before this line
+  return Sort(this, getNodeManager()->mkSortConstructor(symbol, arity));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Sort Solver::mkTupleSort(const std::vector<Sort>& sorts) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_SORTS_NOT_FUNCTION_LIKE(sorts);
+  //////// all checks before this line
+  return mkTupleSortHelper(sorts);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/* Create consts                                                              */
+/* -------------------------------------------------------------------------- */
+
+Term Solver::mkTrue(void) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return Term(this, d_nodeMgr->mkConst<bool>(true));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkFalse(void) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return Term(this, d_nodeMgr->mkConst<bool>(false));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkBoolean(bool val) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return Term(this, d_nodeMgr->mkConst<bool>(val));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkPi() const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  Node res =
+      d_nodeMgr->mkNullaryOperator(d_nodeMgr->realType(), cvc5::kind::PI);
+  (void)res.getType(true); /* kick off type checking */
+  return Term(this, res);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkInteger(const std::string& s) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_ARG_CHECK_EXPECTED(isValidInteger(s), s) << " an integer ";
+  Term integer = mkRealFromStrHelper(s);
+  CVC4_API_ARG_CHECK_EXPECTED(integer.getSort() == getIntegerSort(), s)
+      << " a string representing an integer";
+  //////// all checks before this line
+  return integer;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkInteger(int64_t val) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  Term integer = mkValHelper<cvc5::Rational>(cvc5::Rational(val));
+  Assert(integer.getSort() == getIntegerSort());
+  return integer;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkReal(const std::string& s) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  /* CLN and GMP handle this case differently, CLN interprets it as 0, GMP
+   * throws an std::invalid_argument exception. For consistency, we treat it
+   * as invalid. */
+  CVC4_API_ARG_CHECK_EXPECTED(s != ".", s)
+      << "a string representing a real or rational value.";
+  //////// all checks before this line
+  Term rational = mkRealFromStrHelper(s);
+  return ensureRealSort(rational);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkReal(int64_t val) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  Term rational = mkValHelper<cvc5::Rational>(cvc5::Rational(val));
+  return ensureRealSort(rational);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkReal(int64_t num, int64_t den) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  Term rational = mkValHelper<cvc5::Rational>(cvc5::Rational(num, den));
+  return ensureRealSort(rational);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkRegexpEmpty() const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  Node res =
+      d_nodeMgr->mkNode(cvc5::kind::REGEXP_EMPTY, std::vector<cvc5::Node>());
+  (void)res.getType(true); /* kick off type checking */
+  return Term(this, res);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkRegexpSigma() const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  Node res =
+      d_nodeMgr->mkNode(cvc5::kind::REGEXP_SIGMA, std::vector<cvc5::Node>());
+  (void)res.getType(true); /* kick off type checking */
+  return Term(this, res);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkEmptySet(const Sort& sort) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_ARG_CHECK_EXPECTED(sort.isNull() || sort.isSet(), sort)
+      << "null sort or set sort";
+  CVC4_API_ARG_CHECK_EXPECTED(sort.isNull() || this == sort.d_solver, sort)
+      << "set sort associated with this solver object";
+  //////// all checks before this line
+  return mkValHelper<cvc5::EmptySet>(cvc5::EmptySet(*sort.d_type));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkEmptyBag(const Sort& sort) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_ARG_CHECK_EXPECTED(sort.isNull() || sort.isBag(), sort)
+      << "null sort or bag sort";
+  CVC4_API_ARG_CHECK_EXPECTED(sort.isNull() || this == sort.d_solver, sort)
+      << "bag sort associated with this solver object";
+  //////// all checks before this line
+  return mkValHelper<cvc5::EmptyBag>(cvc5::EmptyBag(*sort.d_type));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkSepNil(const Sort& sort) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_SORT(sort);
+  //////// all checks before this line
+  Node res =
+      getNodeManager()->mkNullaryOperator(*sort.d_type, cvc5::kind::SEP_NIL);
+  (void)res.getType(true); /* kick off type checking */
+  return Term(this, res);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkString(const std::string& s, bool useEscSequences) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return mkValHelper<cvc5::String>(cvc5::String(s, useEscSequences));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkString(const unsigned char c) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return mkValHelper<cvc5::String>(cvc5::String(std::string(1, c)));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkString(const std::vector<uint32_t>& s) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return mkValHelper<cvc5::String>(cvc5::String(s));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkChar(const std::string& s) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return mkCharFromStrHelper(s);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkEmptySequence(const Sort& sort) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_SORT(sort);
+  //////// all checks before this line
+  std::vector<Node> seq;
+  Node res = d_nodeMgr->mkConst(Sequence(*sort.d_type, seq));
+  return Term(this, res);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkUniverseSet(const Sort& sort) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_SORT(sort);
+  //////// all checks before this line
+
+  Node res = getNodeManager()->mkNullaryOperator(*sort.d_type,
+                                                 cvc5::kind::UNIVERSE_SET);
+  // TODO(#2771): Reenable?
+  // (void)res->getType(true); /* kick off type checking */
+  return Term(this, res);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkBitVector(uint32_t size, uint64_t val) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return mkBVFromIntHelper(size, val);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkBitVector(const std::string& s, uint32_t base) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return mkBVFromStrHelper(s, base);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkBitVector(uint32_t size,
+                         const std::string& s,
+                         uint32_t base) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return mkBVFromStrHelper(size, s, base);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkConstArray(const Sort& sort, const Term& val) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_SORT(sort);
+  CVC4_API_SOLVER_CHECK_TERM(val);
+  CVC4_API_ARG_CHECK_EXPECTED(sort.isArray(), sort) << "an array sort";
+  CVC4_API_CHECK(val.getSort().isSubsortOf(sort.getArrayElementSort()))
+      << "Value does not match element sort";
+  //////// all checks before this line
+
+  // handle the special case of (CAST_TO_REAL n) where n is an integer
+  Node n = *val.d_node;
+  if (val.isCastedReal())
+  {
+    // this is safe because the constant array stores its type
+    n = n[0];
+  }
+  Term res =
+      mkValHelper<cvc5::ArrayStoreAll>(cvc5::ArrayStoreAll(*sort.d_type, n));
+  return res;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkPosInf(uint32_t exp, uint32_t sig) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK(Configuration::isBuiltWithSymFPU())
+      << "Expected CVC4 to be compiled with SymFPU support";
+  //////// all checks before this line
+  return mkValHelper<cvc5::FloatingPoint>(
+      FloatingPoint::makeInf(FloatingPointSize(exp, sig), false));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkNegInf(uint32_t exp, uint32_t sig) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK(Configuration::isBuiltWithSymFPU())
+      << "Expected CVC4 to be compiled with SymFPU support";
+  //////// all checks before this line
+  return mkValHelper<cvc5::FloatingPoint>(
+      FloatingPoint::makeInf(FloatingPointSize(exp, sig), true));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkNaN(uint32_t exp, uint32_t sig) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK(Configuration::isBuiltWithSymFPU())
+      << "Expected CVC4 to be compiled with SymFPU support";
+  //////// all checks before this line
+  return mkValHelper<cvc5::FloatingPoint>(
+      FloatingPoint::makeNaN(FloatingPointSize(exp, sig)));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkPosZero(uint32_t exp, uint32_t sig) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK(Configuration::isBuiltWithSymFPU())
+      << "Expected CVC4 to be compiled with SymFPU support";
+  //////// all checks before this line
+  return mkValHelper<cvc5::FloatingPoint>(
+      FloatingPoint::makeZero(FloatingPointSize(exp, sig), false));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkNegZero(uint32_t exp, uint32_t sig) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK(Configuration::isBuiltWithSymFPU())
+      << "Expected CVC4 to be compiled with SymFPU support";
+  //////// all checks before this line
+  return mkValHelper<cvc5::FloatingPoint>(
+      FloatingPoint::makeZero(FloatingPointSize(exp, sig), true));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkRoundingMode(RoundingMode rm) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK(Configuration::isBuiltWithSymFPU())
+      << "Expected CVC4 to be compiled with SymFPU support";
+  //////// all checks before this line
+  return mkValHelper<cvc5::RoundingMode>(s_rmodes.at(rm));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkUninterpretedConst(const Sort& sort, int32_t index) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_SORT(sort);
+  //////// all checks before this line
+  return mkValHelper<cvc5::UninterpretedConstant>(
+      cvc5::UninterpretedConstant(*sort.d_type, index));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkAbstractValue(const std::string& index) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_ARG_CHECK_EXPECTED(!index.empty(), index) << "a non-empty string";
+
+  cvc5::Integer idx(index, 10);
+  CVC4_API_ARG_CHECK_EXPECTED(idx > 0, index)
+      << "a string representing an integer > 0";
+  //////// all checks before this line
+  return Term(this, getNodeManager()->mkConst(cvc5::AbstractValue(idx)));
+  // do not call getType(), for abstract values, type can not be computed
+  // until it is substituted away
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkAbstractValue(uint64_t index) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_ARG_CHECK_EXPECTED(index > 0, index) << "an integer > 0";
+  //////// all checks before this line
+  return Term(this,
+              getNodeManager()->mkConst(cvc5::AbstractValue(Integer(index))));
+  // do not call getType(), for abstract values, type can not be computed
+  // until it is substituted away
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkFloatingPoint(uint32_t exp, uint32_t sig, Term val) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK(Configuration::isBuiltWithSymFPU())
+      << "Expected CVC4 to be compiled with SymFPU support";
+  CVC4_API_SOLVER_CHECK_TERM(val);
+  CVC4_API_ARG_CHECK_EXPECTED(exp > 0, exp) << "a value > 0";
+  CVC4_API_ARG_CHECK_EXPECTED(sig > 0, sig) << "a value > 0";
+  uint32_t bw = exp + sig;
+  CVC4_API_ARG_CHECK_EXPECTED(bw == val.getSort().getBVSize(), val)
+      << "a bit-vector constant with bit-width '" << bw << "'";
+  CVC4_API_ARG_CHECK_EXPECTED(
+      val.getSort().isBitVector() && val.d_node->isConst(), val)
+      << "bit-vector constant";
+  //////// all checks before this line
+  return mkValHelper<cvc5::FloatingPoint>(
+      cvc5::FloatingPoint(exp, sig, val.d_node->getConst<BitVector>()));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/* Create constants                                                           */
+/* -------------------------------------------------------------------------- */
+
+Term Solver::mkConst(const Sort& sort, const std::string& symbol) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_SORT(sort);
+  //////// all checks before this line
+  Node res = d_nodeMgr->mkVar(symbol, *sort.d_type);
+  (void)res.getType(true); /* kick off type checking */
+  increment_vars_consts_stats(sort, false);
+  return Term(this, res);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkConst(const Sort& sort) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_SORT(sort);
+  //////// all checks before this line
+  Node res = d_nodeMgr->mkVar(*sort.d_type);
+  (void)res.getType(true); /* kick off type checking */
+  increment_vars_consts_stats(sort, false);
+  return Term(this, res);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/* Create variables                                                           */
+/* -------------------------------------------------------------------------- */
+
+Term Solver::mkVar(const Sort& sort, const std::string& symbol) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_SORT(sort);
+  //////// all checks before this line
+  Node res = symbol.empty() ? d_nodeMgr->mkBoundVar(*sort.d_type)
+                            : d_nodeMgr->mkBoundVar(symbol, *sort.d_type);
+  (void)res.getType(true); /* kick off type checking */
+  increment_vars_consts_stats(sort, true);
+  return Term(this, res);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/* Create datatype constructor declarations                                   */
+/* -------------------------------------------------------------------------- */
+
+DatatypeConstructorDecl Solver::mkDatatypeConstructorDecl(
+    const std::string& name)
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return DatatypeConstructorDecl(this, name);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/* Create datatype declarations                                               */
+/* -------------------------------------------------------------------------- */
+
+DatatypeDecl Solver::mkDatatypeDecl(const std::string& name, bool isCoDatatype)
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return DatatypeDecl(this, name, isCoDatatype);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+DatatypeDecl Solver::mkDatatypeDecl(const std::string& name,
+                                    Sort param,
+                                    bool isCoDatatype)
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_SORT(param);
+  //////// all checks before this line
+  return DatatypeDecl(this, name, param, isCoDatatype);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+DatatypeDecl Solver::mkDatatypeDecl(const std::string& name,
+                                    const std::vector<Sort>& params,
+                                    bool isCoDatatype)
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_SORTS(params);
+  //////// all checks before this line
+  return DatatypeDecl(this, name, params, isCoDatatype);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/* Create terms                                                               */
+/* -------------------------------------------------------------------------- */
+
+Term Solver::mkTerm(Kind kind) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_KIND_CHECK(kind);
+  //////// all checks before this line
+  return mkTermFromKind(kind);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkTerm(Kind kind, const Term& child) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_KIND_CHECK(kind);
+  CVC4_API_SOLVER_CHECK_TERM(child);
+  //////// all checks before this line
+  return mkTermHelper(kind, std::vector<Term>{child});
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkTerm(Kind kind, const Term& child1, const Term& child2) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_KIND_CHECK(kind);
+  CVC4_API_SOLVER_CHECK_TERM(child1);
+  CVC4_API_SOLVER_CHECK_TERM(child2);
+  //////// all checks before this line
+  return mkTermHelper(kind, std::vector<Term>{child1, child2});
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkTerm(Kind kind,
+                    const Term& child1,
+                    const Term& child2,
+                    const Term& child3) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_KIND_CHECK(kind);
+  CVC4_API_SOLVER_CHECK_TERM(child1);
+  CVC4_API_SOLVER_CHECK_TERM(child2);
+  CVC4_API_SOLVER_CHECK_TERM(child3);
+  //////// all checks before this line
+  // need to use internal term call to check e.g. associative construction
+  return mkTermHelper(kind, std::vector<Term>{child1, child2, child3});
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkTerm(Kind kind, const std::vector<Term>& children) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_KIND_CHECK(kind);
+  CVC4_API_SOLVER_CHECK_TERMS(children);
+  //////// all checks before this line
+  return mkTermHelper(kind, children);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkTerm(const Op& op) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_OP(op);
+  checkMkTerm(op.d_kind, 0);
+  //////// all checks before this line
+
+  if (!op.isIndexedHelper())
+  {
+    return mkTermFromKind(op.d_kind);
+  }
+
+  const cvc5::Kind int_kind = extToIntKind(op.d_kind);
+  Term res = Term(this, getNodeManager()->mkNode(int_kind, *op.d_node));
+
+  (void)res.d_node->getType(true); /* kick off type checking */
+  return res;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkTerm(const Op& op, const Term& child) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_OP(op);
+  CVC4_API_SOLVER_CHECK_TERM(child);
+  //////// all checks before this line
+  return mkTermHelper(op, std::vector<Term>{child});
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkTerm(const Op& op, const Term& child1, const Term& child2) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_OP(op);
+  CVC4_API_SOLVER_CHECK_TERM(child1);
+  CVC4_API_SOLVER_CHECK_TERM(child2);
+  //////// all checks before this line
+  return mkTermHelper(op, std::vector<Term>{child1, child2});
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkTerm(const Op& op,
+                    const Term& child1,
+                    const Term& child2,
+                    const Term& child3) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_OP(op);
+  CVC4_API_SOLVER_CHECK_TERM(child1);
+  CVC4_API_SOLVER_CHECK_TERM(child2);
+  CVC4_API_SOLVER_CHECK_TERM(child3);
+  //////// all checks before this line
+  return mkTermHelper(op, std::vector<Term>{child1, child2, child3});
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkTerm(const Op& op, const std::vector<Term>& children) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_OP(op);
+  CVC4_API_SOLVER_CHECK_TERMS(children);
+  //////// all checks before this line
+  return mkTermHelper(op, children);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkTuple(const std::vector<Sort>& sorts,
+                     const std::vector<Term>& terms) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK(sorts.size() == terms.size())
+      << "Expected the same number of sorts and elements";
+  CVC4_API_SOLVER_CHECK_SORTS(sorts);
+  CVC4_API_SOLVER_CHECK_TERMS(terms);
+  //////// all checks before this line
+  std::vector<cvc5::Node> args;
+  for (size_t i = 0, size = sorts.size(); i < size; i++)
+  {
+    args.push_back(*(ensureTermSort(terms[i], sorts[i])).d_node);
+  }
+
+  Sort s = mkTupleSortHelper(sorts);
+  Datatype dt = s.getDatatype();
+  NodeBuilder<> nb(extToIntKind(APPLY_CONSTRUCTOR));
+  nb << *dt[0].getConstructorTerm().d_node;
+  nb.append(args);
+  Node res = nb.constructNode();
+  (void)res.getType(true); /* kick off type checking */
+  return Term(this, res);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/* Create operators                                                           */
+/* -------------------------------------------------------------------------- */
+
+Op Solver::mkOp(Kind kind) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_KIND_CHECK(kind);
+  CVC4_API_CHECK(s_indexed_kinds.find(kind) == s_indexed_kinds.end())
+      << "Expected a kind for a non-indexed operator.";
+  //////// all checks before this line
+  return Op(this, kind);
+  ////////
+  CVC4_API_TRY_CATCH_END
+}
+
+Op Solver::mkOp(Kind kind, const std::string& arg) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_KIND_CHECK(kind);
+  CVC4_API_KIND_CHECK_EXPECTED((kind == RECORD_UPDATE) || (kind == DIVISIBLE),
+                               kind)
+      << "RECORD_UPDATE or DIVISIBLE";
+  //////// all checks before this line
+  Op res;
+  if (kind == RECORD_UPDATE)
+  {
+    res = Op(this,
+             kind,
+             *mkValHelper<cvc5::RecordUpdate>(cvc5::RecordUpdate(arg)).d_node);
+  }
+  else
+  {
+    /* CLN and GMP handle this case differently, CLN interprets it as 0, GMP
+     * throws an std::invalid_argument exception. For consistency, we treat it
+     * as invalid. */
+    CVC4_API_ARG_CHECK_EXPECTED(arg != ".", arg)
+        << "a string representing an integer, real or rational value.";
+    res = Op(this,
+             kind,
+             *mkValHelper<cvc5::Divisible>(cvc5::Divisible(cvc5::Integer(arg)))
+                  .d_node);
+  }
+  return res;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Op Solver::mkOp(Kind kind, uint32_t arg) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_KIND_CHECK(kind);
+  //////// all checks before this line
+  Op res;
+  switch (kind)
+  {
+    case DIVISIBLE:
+      res = Op(this,
+               kind,
+               *mkValHelper<cvc5::Divisible>(cvc5::Divisible(arg)).d_node);
+      break;
+    case BITVECTOR_REPEAT:
+      res = Op(this,
+               kind,
+               *mkValHelper<cvc5::BitVectorRepeat>(cvc5::BitVectorRepeat(arg))
+                    .d_node);
+      break;
+    case BITVECTOR_ZERO_EXTEND:
+      res = Op(this,
+               kind,
+               *mkValHelper<cvc5::BitVectorZeroExtend>(
+                    cvc5::BitVectorZeroExtend(arg))
+                    .d_node);
+      break;
+    case BITVECTOR_SIGN_EXTEND:
+      res = Op(this,
+               kind,
+               *mkValHelper<cvc5::BitVectorSignExtend>(
+                    cvc5::BitVectorSignExtend(arg))
+                    .d_node);
+      break;
+    case BITVECTOR_ROTATE_LEFT:
+      res = Op(this,
+               kind,
+               *mkValHelper<cvc5::BitVectorRotateLeft>(
+                    cvc5::BitVectorRotateLeft(arg))
+                    .d_node);
+      break;
+    case BITVECTOR_ROTATE_RIGHT:
+      res = Op(this,
+               kind,
+               *mkValHelper<cvc5::BitVectorRotateRight>(
+                    cvc5::BitVectorRotateRight(arg))
+                    .d_node);
+      break;
+    case INT_TO_BITVECTOR:
+      res = Op(
+          this,
+          kind,
+          *mkValHelper<cvc5::IntToBitVector>(cvc5::IntToBitVector(arg)).d_node);
+      break;
+    case IAND:
+      res =
+          Op(this, kind, *mkValHelper<cvc5::IntAnd>(cvc5::IntAnd(arg)).d_node);
+      break;
+    case FLOATINGPOINT_TO_UBV:
+      res = Op(
+          this,
+          kind,
+          *mkValHelper<cvc5::FloatingPointToUBV>(cvc5::FloatingPointToUBV(arg))
+               .d_node);
+      break;
+    case FLOATINGPOINT_TO_SBV:
+      res = Op(
+          this,
+          kind,
+          *mkValHelper<cvc5::FloatingPointToSBV>(cvc5::FloatingPointToSBV(arg))
+               .d_node);
+      break;
+    case TUPLE_UPDATE:
+      res = Op(this,
+               kind,
+               *mkValHelper<cvc5::TupleUpdate>(cvc5::TupleUpdate(arg)).d_node);
+      break;
+    case REGEXP_REPEAT:
+      res =
+          Op(this,
+             kind,
+             *mkValHelper<cvc5::RegExpRepeat>(cvc5::RegExpRepeat(arg)).d_node);
+      break;
+    default:
+      CVC4_API_KIND_CHECK_EXPECTED(false, kind)
+          << "operator kind with uint32_t argument";
+  }
+  Assert(!res.isNull());
+  return res;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Op Solver::mkOp(Kind kind, uint32_t arg1, uint32_t arg2) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_KIND_CHECK(kind);
+  //////// all checks before this line
+
+  Op res;
+  switch (kind)
+  {
+    case BITVECTOR_EXTRACT:
+      res = Op(this,
+               kind,
+               *mkValHelper<cvc5::BitVectorExtract>(
+                    cvc5::BitVectorExtract(arg1, arg2))
+                    .d_node);
+      break;
+    case FLOATINGPOINT_TO_FP_IEEE_BITVECTOR:
+      res = Op(this,
+               kind,
+               *mkValHelper<cvc5::FloatingPointToFPIEEEBitVector>(
+                    cvc5::FloatingPointToFPIEEEBitVector(arg1, arg2))
+                    .d_node);
+      break;
+    case FLOATINGPOINT_TO_FP_FLOATINGPOINT:
+      res = Op(this,
+               kind,
+               *mkValHelper<cvc5::FloatingPointToFPFloatingPoint>(
+                    cvc5::FloatingPointToFPFloatingPoint(arg1, arg2))
+                    .d_node);
+      break;
+    case FLOATINGPOINT_TO_FP_REAL:
+      res = Op(this,
+               kind,
+               *mkValHelper<cvc5::FloatingPointToFPReal>(
+                    cvc5::FloatingPointToFPReal(arg1, arg2))
+                    .d_node);
+      break;
+    case FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR:
+      res = Op(this,
+               kind,
+               *mkValHelper<cvc5::FloatingPointToFPSignedBitVector>(
+                    cvc5::FloatingPointToFPSignedBitVector(arg1, arg2))
+                    .d_node);
+      break;
+    case FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR:
+      res = Op(this,
+               kind,
+               *mkValHelper<cvc5::FloatingPointToFPUnsignedBitVector>(
+                    cvc5::FloatingPointToFPUnsignedBitVector(arg1, arg2))
+                    .d_node);
+      break;
+    case FLOATINGPOINT_TO_FP_GENERIC:
+      res = Op(this,
+               kind,
+               *mkValHelper<cvc5::FloatingPointToFPGeneric>(
+                    cvc5::FloatingPointToFPGeneric(arg1, arg2))
+                    .d_node);
+      break;
+    case REGEXP_LOOP:
+      res = Op(
+          this,
+          kind,
+          *mkValHelper<cvc5::RegExpLoop>(cvc5::RegExpLoop(arg1, arg2)).d_node);
+      break;
+    default:
+      CVC4_API_KIND_CHECK_EXPECTED(false, kind)
+          << "operator kind with two uint32_t arguments";
+  }
+  Assert(!res.isNull());
+  return res;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Op Solver::mkOp(Kind kind, const std::vector<uint32_t>& args) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_KIND_CHECK(kind);
+  //////// all checks before this line
+
+  Op res;
+  switch (kind)
+  {
+    case TUPLE_PROJECT:
+    {
+      res = Op(this,
+               kind,
+               *mkValHelper<cvc5::TupleProjectOp>(cvc5::TupleProjectOp(args))
+                    .d_node);
+    }
+    break;
+    default:
+    {
+      std::string message = "operator kind with " + std::to_string(args.size())
+                            + " uint32_t arguments";
+      CVC4_API_KIND_CHECK_EXPECTED(false, kind) << message;
+    }
+  }
+  Assert(!res.isNull());
+  return res;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/* Non-SMT-LIB commands                                                       */
+/* -------------------------------------------------------------------------- */
+
+Term Solver::simplify(const Term& term)
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_TERM(term);
+  //////// all checks before this line
+  return Term(this, d_smtEngine->simplify(*term.d_node));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Result Solver::checkEntailed(const Term& term) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK(!d_smtEngine->isQueryMade()
+                 || d_smtEngine->getOptions()[options::incrementalSolving])
+      << "Cannot make multiple queries unless incremental solving is enabled "
+         "(try --incremental)";
+  CVC4_API_SOLVER_CHECK_TERM(term);
+  //////// all checks before this line
+  cvc5::Result r = d_smtEngine->checkEntailed(*term.d_node);
+  return Result(r);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Result Solver::checkEntailed(const std::vector<Term>& terms) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_CHECK(!d_smtEngine->isQueryMade()
+                 || d_smtEngine->getOptions()[options::incrementalSolving])
+      << "Cannot make multiple queries unless incremental solving is enabled "
+         "(try --incremental)";
+  CVC4_API_SOLVER_CHECK_TERMS(terms);
+  //////// all checks before this line
+  return d_smtEngine->checkEntailed(Term::termVectorToNodes(terms));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/* SMT-LIB commands                                                           */
+/* -------------------------------------------------------------------------- */
+
+/**
+ *  ( assert <term> )
+ */
+void Solver::assertFormula(const Term& term) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_TERM(term);
+  CVC4_API_SOLVER_CHECK_TERM_WITH_SORT(term, getBooleanSort());
+  //////// all checks before this line
+  d_smtEngine->assertFormula(*term.d_node);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/**
+ *  ( check-sat )
+ */
+Result Solver::checkSat(void) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_CHECK(!d_smtEngine->isQueryMade()
+                 || d_smtEngine->getOptions()[options::incrementalSolving])
+      << "Cannot make multiple queries unless incremental solving is enabled "
+         "(try --incremental)";
+  //////// all checks before this line
+  cvc5::Result r = d_smtEngine->checkSat();
+  return Result(r);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/**
+ *  ( check-sat-assuming ( <prop_literal> ) )
+ */
+Result Solver::checkSatAssuming(const Term& assumption) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_CHECK(!d_smtEngine->isQueryMade()
+                 || d_smtEngine->getOptions()[options::incrementalSolving])
+      << "Cannot make multiple queries unless incremental solving is enabled "
+         "(try --incremental)";
+  CVC4_API_SOLVER_CHECK_TERM_WITH_SORT(assumption, getBooleanSort());
+  //////// all checks before this line
+  cvc5::Result r = d_smtEngine->checkSat(*assumption.d_node);
+  return Result(r);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/**
+ *  ( check-sat-assuming ( <prop_literal>* ) )
+ */
+Result Solver::checkSatAssuming(const std::vector<Term>& assumptions) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_CHECK(!d_smtEngine->isQueryMade() || assumptions.size() == 0
+                 || d_smtEngine->getOptions()[options::incrementalSolving])
+      << "Cannot make multiple queries unless incremental solving is enabled "
+         "(try --incremental)";
+  CVC4_API_SOLVER_CHECK_TERMS_WITH_SORT(assumptions, getBooleanSort());
+  //////// all checks before this line
+  for (const Term& term : assumptions)
+  {
+    CVC4_API_SOLVER_CHECK_TERM(term);
+  }
+  std::vector<Node> eassumptions = Term::termVectorToNodes(assumptions);
+  cvc5::Result r = d_smtEngine->checkSat(eassumptions);
+  return Result(r);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/**
+ *  ( declare-datatype <symbol> <datatype_decl> )
+ */
+Sort Solver::declareDatatype(
+    const std::string& symbol,
+    const std::vector<DatatypeConstructorDecl>& ctors) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_ARG_CHECK_EXPECTED(ctors.size() > 0, ctors)
+      << "a datatype declaration with at least one constructor";
+  CVC4_API_SOLVER_CHECK_DTCTORDECLS(ctors);
+  //////// all checks before this line
+  DatatypeDecl dtdecl(this, symbol);
+  for (size_t i = 0, size = ctors.size(); i < size; i++)
+  {
+    dtdecl.addConstructor(ctors[i]);
+  }
+  return Sort(this, getNodeManager()->mkDatatypeType(*dtdecl.d_dtype));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/**
+ *  ( declare-fun <symbol> ( <sort>* ) <sort> )
+ */
+Term Solver::declareFun(const std::string& symbol,
+                        const std::vector<Sort>& sorts,
+                        const Sort& sort) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_DOMAIN_SORTS(sorts);
+  CVC4_API_SOLVER_CHECK_CODOMAIN_SORT(sort);
+  //////// all checks before this line
+
+  TypeNode type = *sort.d_type;
+  if (!sorts.empty())
+  {
+    std::vector<TypeNode> types = Sort::sortVectorToTypeNodes(sorts);
+    type = getNodeManager()->mkFunctionType(types, type);
+  }
+  return Term(this, d_nodeMgr->mkVar(symbol, type));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/**
+ *  ( declare-sort <symbol> <numeral> )
+ */
+Sort Solver::declareSort(const std::string& symbol, uint32_t arity) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  if (arity == 0)
+  {
+    return Sort(this, getNodeManager()->mkSort(symbol));
+  }
+  return Sort(this, getNodeManager()->mkSortConstructor(symbol, arity));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/**
+ *  ( define-fun <function_def> )
+ */
+Term Solver::defineFun(const std::string& symbol,
+                       const std::vector<Term>& bound_vars,
+                       const Sort& sort,
+                       const Term& term,
+                       bool global) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_CODOMAIN_SORT(sort);
+  CVC4_API_SOLVER_CHECK_TERM(term);
+  CVC4_API_CHECK(sort == term.getSort())
+      << "Invalid sort of function body '" << term << "', expected '" << sort
+      << "'";
+
+  std::vector<Sort> domain_sorts;
+  for (const auto& bv : bound_vars)
+  {
+    domain_sorts.push_back(bv.getSort());
+  }
+  Sort fun_sort =
+      domain_sorts.empty()
+          ? sort
+          : Sort(this,
+                 getNodeManager()->mkFunctionType(
+                     Sort::sortVectorToTypeNodes(domain_sorts), *sort.d_type));
+  Term fun = mkConst(fun_sort, symbol);
+
+  CVC4_API_SOLVER_CHECK_BOUND_VARS_DEF_FUN(fun, bound_vars, domain_sorts);
+  //////// all checks before this line
+
+  d_smtEngine->defineFunction(
+      *fun.d_node, Term::termVectorToNodes(bound_vars), *term.d_node, global);
+  return fun;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::defineFun(const Term& fun,
+                       const std::vector<Term>& bound_vars,
+                       const Term& term,
+                       bool global) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_TERM(fun);
+  CVC4_API_SOLVER_CHECK_TERM(term);
+  if (fun.getSort().isFunction())
+  {
+    std::vector<Sort> domain_sorts = fun.getSort().getFunctionDomainSorts();
+    CVC4_API_SOLVER_CHECK_BOUND_VARS_DEF_FUN(fun, bound_vars, domain_sorts);
+    Sort codomain = fun.getSort().getFunctionCodomainSort();
+    CVC4_API_CHECK(codomain == term.getSort())
+        << "Invalid sort of function body '" << term << "', expected '"
+        << codomain << "'";
+  }
+  else
+  {
+    CVC4_API_SOLVER_CHECK_BOUND_VARS(bound_vars);
+    CVC4_API_ARG_CHECK_EXPECTED(bound_vars.size() == 0, fun)
+        << "function or nullary symbol";
+  }
+  //////// all checks before this line
+  std::vector<Node> ebound_vars = Term::termVectorToNodes(bound_vars);
+  d_smtEngine->defineFunction(*fun.d_node, ebound_vars, *term.d_node, global);
+  return fun;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/**
+ *  ( define-fun-rec <function_def> )
+ */
+Term Solver::defineFunRec(const std::string& symbol,
+                          const std::vector<Term>& bound_vars,
+                          const Sort& sort,
+                          const Term& term,
+                          bool global) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+
+  CVC4_API_CHECK(d_smtEngine->getUserLogicInfo().isQuantified())
+      << "recursive function definitions require a logic with quantifiers";
+  CVC4_API_CHECK(
+      d_smtEngine->getUserLogicInfo().isTheoryEnabled(theory::THEORY_UF))
+      << "recursive function definitions require a logic with uninterpreted "
+         "functions";
+
+  CVC4_API_SOLVER_CHECK_TERM(term);
+  CVC4_API_SOLVER_CHECK_CODOMAIN_SORT(sort);
+  CVC4_API_CHECK(sort == term.getSort())
+      << "Invalid sort of function body '" << term << "', expected '" << sort
+      << "'";
+
+  std::vector<Sort> domain_sorts;
+  for (const auto& bv : bound_vars)
+  {
+    domain_sorts.push_back(bv.getSort());
+  }
+  Sort fun_sort =
+      domain_sorts.empty()
+          ? sort
+          : Sort(this,
+                 getNodeManager()->mkFunctionType(
+                     Sort::sortVectorToTypeNodes(domain_sorts), *sort.d_type));
+  Term fun = mkConst(fun_sort, symbol);
+
+  CVC4_API_SOLVER_CHECK_BOUND_VARS_DEF_FUN(fun, bound_vars, domain_sorts);
+  //////// all checks before this line
+
+  d_smtEngine->defineFunctionRec(
+      *fun.d_node, Term::termVectorToNodes(bound_vars), *term.d_node, global);
+
+  return fun;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::defineFunRec(const Term& fun,
+                          const std::vector<Term>& bound_vars,
+                          const Term& term,
+                          bool global) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+
+  CVC4_API_CHECK(d_smtEngine->getUserLogicInfo().isQuantified())
+      << "recursive function definitions require a logic with quantifiers";
+  CVC4_API_CHECK(
+      d_smtEngine->getUserLogicInfo().isTheoryEnabled(theory::THEORY_UF))
+      << "recursive function definitions require a logic with uninterpreted "
+         "functions";
+
+  CVC4_API_SOLVER_CHECK_TERM(fun);
+  CVC4_API_SOLVER_CHECK_TERM(term);
+  if (fun.getSort().isFunction())
+  {
+    std::vector<Sort> domain_sorts = fun.getSort().getFunctionDomainSorts();
+    CVC4_API_SOLVER_CHECK_BOUND_VARS_DEF_FUN(fun, bound_vars, domain_sorts);
+    Sort codomain = fun.getSort().getFunctionCodomainSort();
+    CVC4_API_CHECK(codomain == term.getSort())
+        << "Invalid sort of function body '" << term << "', expected '"
+        << codomain << "'";
+  }
+  else
+  {
+    CVC4_API_SOLVER_CHECK_BOUND_VARS(bound_vars);
+    CVC4_API_ARG_CHECK_EXPECTED(bound_vars.size() == 0, fun)
+        << "function or nullary symbol";
+  }
+  //////// all checks before this line
+
+  std::vector<Node> ebound_vars = Term::termVectorToNodes(bound_vars);
+  d_smtEngine->defineFunctionRec(
+      *fun.d_node, ebound_vars, *term.d_node, global);
+  return fun;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/**
+ *  ( define-funs-rec ( <function_decl>^{n+1} ) ( <term>^{n+1} ) )
+ */
+void Solver::defineFunsRec(const std::vector<Term>& funs,
+                           const std::vector<std::vector<Term>>& bound_vars,
+                           const std::vector<Term>& terms,
+                           bool global) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+
+  CVC4_API_CHECK(d_smtEngine->getUserLogicInfo().isQuantified())
+      << "recursive function definitions require a logic with quantifiers";
+  CVC4_API_CHECK(
+      d_smtEngine->getUserLogicInfo().isTheoryEnabled(theory::THEORY_UF))
+      << "recursive function definitions require a logic with uninterpreted "
+         "functions";
+  CVC4_API_SOLVER_CHECK_TERMS(funs);
+  CVC4_API_SOLVER_CHECK_TERMS(terms);
+
+  size_t funs_size = funs.size();
+  CVC4_API_ARG_SIZE_CHECK_EXPECTED(funs_size == bound_vars.size(), bound_vars)
+      << "'" << funs_size << "'";
+  CVC4_API_ARG_SIZE_CHECK_EXPECTED(funs_size == terms.size(), terms)
+      << "'" << funs_size << "'";
+
+  for (size_t j = 0; j < funs_size; ++j)
+  {
+    const Term& fun = funs[j];
+    const std::vector<Term>& bvars = bound_vars[j];
+    const Term& term = terms[j];
+
+    CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
+        this == fun.d_solver, "function", funs, j)
+        << "function associated with this solver object";
+    CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
+        this == term.d_solver, "term", terms, j)
+        << "term associated with this solver object";
+
+    if (fun.getSort().isFunction())
+    {
+      std::vector<Sort> domain_sorts = fun.getSort().getFunctionDomainSorts();
+      CVC4_API_SOLVER_CHECK_BOUND_VARS_DEF_FUN(fun, bvars, domain_sorts);
+      Sort codomain = fun.getSort().getFunctionCodomainSort();
+      CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
+          codomain == term.getSort(), "sort of function body", terms, j)
+          << "'" << codomain << "'";
+    }
+    else
+    {
+      CVC4_API_SOLVER_CHECK_BOUND_VARS(bvars);
+      CVC4_API_ARG_CHECK_EXPECTED(bvars.size() == 0, fun)
+          << "function or nullary symbol";
+    }
+  }
+  //////// all checks before this line
+  std::vector<Node> efuns = Term::termVectorToNodes(funs);
+  std::vector<std::vector<Node>> ebound_vars;
+  for (const auto& v : bound_vars)
+  {
+    ebound_vars.push_back(Term::termVectorToNodes(v));
+  }
+  std::vector<Node> nodes = Term::termVectorToNodes(terms);
+  d_smtEngine->defineFunctionsRec(efuns, ebound_vars, nodes, global);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/**
+ *  ( echo <std::string> )
+ */
+void Solver::echo(std::ostream& out, const std::string& str) const
+{
+  out << str;
+}
+
+/**
+ *  ( get-assertions )
+ */
+std::vector<Term> Solver::getAssertions(void) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  std::vector<Node> assertions = d_smtEngine->getAssertions();
+  /* Can not use
+   *   return std::vector<Term>(assertions.begin(), assertions.end());
+   * here since constructor is private */
+  std::vector<Term> res;
+  for (const Node& e : assertions)
+  {
+    res.push_back(Term(this, e));
+  }
+  return res;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/**
+ *  ( get-info <info_flag> )
+ */
+std::string Solver::getInfo(const std::string& flag) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_RECOVERABLE_CHECK(d_smtEngine->isValidGetInfoFlag(flag))
+      << "Unrecognized flag for getInfo.";
+  //////// all checks before this line
+  return d_smtEngine->getInfo(flag).toString();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/**
+ *  ( get-option <keyword> )
+ */
+std::string Solver::getOption(const std::string& option) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  Node res = d_smtEngine->getOption(option);
+  return res.toString();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/**
+ *  ( get-unsat-assumptions )
+ */
+std::vector<Term> Solver::getUnsatAssumptions(void) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_CHECK(d_smtEngine->getOptions()[options::incrementalSolving])
+      << "Cannot get unsat assumptions unless incremental solving is enabled "
+         "(try --incremental)";
+  CVC4_API_CHECK(d_smtEngine->getOptions()[options::unsatAssumptions])
+      << "Cannot get unsat assumptions unless explicitly enabled "
+         "(try --produce-unsat-assumptions)";
+  CVC4_API_CHECK(d_smtEngine->getSmtMode() == SmtMode::UNSAT)
+      << "Cannot get unsat assumptions unless in unsat mode.";
+  //////// all checks before this line
+
+  std::vector<Node> uassumptions = d_smtEngine->getUnsatAssumptions();
+  /* Can not use
+   *   return std::vector<Term>(uassumptions.begin(), uassumptions.end());
+   * here since constructor is private */
+  std::vector<Term> res;
+  for (const Node& n : uassumptions)
+  {
+    res.push_back(Term(this, n));
+  }
+  return res;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/**
+ *  ( get-unsat-core )
+ */
+std::vector<Term> Solver::getUnsatCore(void) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_CHECK(d_smtEngine->getOptions()[options::unsatCores])
+      << "Cannot get unsat core unless explicitly enabled "
+         "(try --produce-unsat-cores)";
+  CVC4_API_RECOVERABLE_CHECK(d_smtEngine->getSmtMode() == SmtMode::UNSAT)
+      << "Cannot get unsat core unless in unsat mode.";
+  //////// all checks before this line
+  UnsatCore core = d_smtEngine->getUnsatCore();
+  /* Can not use
+   *   return std::vector<Term>(core.begin(), core.end());
+   * here since constructor is private */
+  std::vector<Term> res;
+  for (const Node& e : core)
+  {
+    res.push_back(Term(this, e));
+  }
+  return res;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/**
+ *  ( get-value ( <term> ) )
+ */
+Term Solver::getValue(const Term& term) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_TERM(term);
+  //////// all checks before this line
+  return getValueHelper(term);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/**
+ *  ( get-value ( <term>+ ) )
+ */
+std::vector<Term> Solver::getValue(const std::vector<Term>& terms) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_RECOVERABLE_CHECK(d_smtEngine->getOptions()[options::produceModels])
+      << "Cannot get value unless model generation is enabled "
+         "(try --produce-models)";
+  CVC4_API_RECOVERABLE_CHECK(d_smtEngine->isSmtModeSat())
+      << "Cannot get value unless after a SAT or unknown response.";
+  CVC4_API_SOLVER_CHECK_TERMS(terms);
+  //////// all checks before this line
+
+  std::vector<Term> res;
+  for (size_t i = 0, n = terms.size(); i < n; ++i)
+  {
+    /* Can not use emplace_back here since constructor is private. */
+    res.push_back(getValueHelper(terms[i]));
+  }
+  return res;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::getQuantifierElimination(const Term& q) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_TERM(q);
+  //////// all checks before this line
+  return Term(this,
+              d_smtEngine->getQuantifierElimination(q.getNode(), true, true));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::getQuantifierEliminationDisjunct(const Term& q) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_TERM(q);
+  //////// all checks before this line
+  return Term(this,
+              d_smtEngine->getQuantifierElimination(q.getNode(), false, true));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+void Solver::declareSeparationHeap(const Sort& locSort,
+                                   const Sort& dataSort) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_SORT(locSort);
+  CVC4_API_SOLVER_CHECK_SORT(dataSort);
+  CVC4_API_CHECK(
+      d_smtEngine->getLogicInfo().isTheoryEnabled(theory::THEORY_SEP))
+      << "Cannot obtain separation logic expressions if not using the "
+         "separation logic theory.";
+  //////// all checks before this line
+  d_smtEngine->declareSepHeap(locSort.getTypeNode(), dataSort.getTypeNode());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::getSeparationHeap() const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK(
+      d_smtEngine->getLogicInfo().isTheoryEnabled(theory::THEORY_SEP))
+      << "Cannot obtain separation logic expressions if not using the "
+         "separation logic theory.";
+  CVC4_API_CHECK(d_smtEngine->getOptions()[options::produceModels])
+      << "Cannot get separation heap term unless model generation is enabled "
+         "(try --produce-models)";
+  CVC4_API_RECOVERABLE_CHECK(d_smtEngine->isSmtModeSat())
+      << "Can only get separtion heap term after sat or unknown response.";
+  //////// all checks before this line
+  return Term(this, d_smtEngine->getSepHeapExpr());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::getSeparationNilTerm() const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK(
+      d_smtEngine->getLogicInfo().isTheoryEnabled(theory::THEORY_SEP))
+      << "Cannot obtain separation logic expressions if not using the "
+         "separation logic theory.";
+  CVC4_API_CHECK(d_smtEngine->getOptions()[options::produceModels])
+      << "Cannot get separation nil term unless model generation is enabled "
+         "(try --produce-models)";
+  CVC4_API_RECOVERABLE_CHECK(d_smtEngine->isSmtModeSat())
+      << "Can only get separtion nil term after sat or unknown response.";
+  //////// all checks before this line
+  return Term(this, d_smtEngine->getSepNilExpr());
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/**
+ *  ( pop <numeral> )
+ */
+void Solver::pop(uint32_t nscopes) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK(d_smtEngine->getOptions()[options::incrementalSolving])
+      << "Cannot pop when not solving incrementally (use --incremental)";
+  CVC4_API_CHECK(nscopes <= d_smtEngine->getNumUserLevels())
+      << "Cannot pop beyond first pushed context";
+  //////// all checks before this line
+  for (uint32_t n = 0; n < nscopes; ++n)
+  {
+    d_smtEngine->pop();
+  }
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Solver::getInterpolant(const Term& conj, Term& output) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_TERM(conj);
+  //////// all checks before this line
+  Node result;
+  bool success = d_smtEngine->getInterpol(*conj.d_node, result);
+  if (success)
+  {
+    output = Term(this, result);
+  }
+  return success;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Solver::getInterpolant(const Term& conj,
+                            Grammar& grammar,
+                            Term& output) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_TERM(conj);
+  //////// all checks before this line
+  Node result;
+  bool success =
+      d_smtEngine->getInterpol(*conj.d_node, *grammar.resolve().d_type, result);
+  if (success)
+  {
+    output = Term(this, result);
+  }
+  return success;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Solver::getAbduct(const Term& conj, Term& output) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_TERM(conj);
+  //////// all checks before this line
+  Node result;
+  bool success = d_smtEngine->getAbduct(*conj.d_node, result);
+  if (success)
+  {
+    output = Term(this, result);
+  }
+  return success;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+bool Solver::getAbduct(const Term& conj, Grammar& grammar, Term& output) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_TERM(conj);
+  //////// all checks before this line
+  Node result;
+  bool success =
+      d_smtEngine->getAbduct(*conj.d_node, *grammar.resolve().d_type, result);
+  if (success)
+  {
+    output = Term(this, result);
+  }
+  return success;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+void Solver::blockModel() const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK(d_smtEngine->getOptions()[options::produceModels])
+      << "Cannot get value unless model generation is enabled "
+         "(try --produce-models)";
+  CVC4_API_RECOVERABLE_CHECK(d_smtEngine->isSmtModeSat())
+      << "Can only block model after sat or unknown response.";
+  //////// all checks before this line
+  d_smtEngine->blockModel();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+void Solver::blockModelValues(const std::vector<Term>& terms) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK(d_smtEngine->getOptions()[options::produceModels])
+      << "Cannot get value unless model generation is enabled "
+         "(try --produce-models)";
+  CVC4_API_RECOVERABLE_CHECK(d_smtEngine->isSmtModeSat())
+      << "Can only block model values after sat or unknown response.";
+  CVC4_API_ARG_SIZE_CHECK_EXPECTED(!terms.empty(), terms)
+      << "a non-empty set of terms";
+  CVC4_API_SOLVER_CHECK_TERMS(terms);
+  //////// all checks before this line
+  d_smtEngine->blockModelValues(Term::termVectorToNodes(terms));
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+void Solver::printInstantiations(std::ostream& out) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  d_smtEngine->printInstantiations(out);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/**
+ *  ( push <numeral> )
+ */
+void Solver::push(uint32_t nscopes) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK(d_smtEngine->getOptions()[options::incrementalSolving])
+      << "Cannot push when not solving incrementally (use --incremental)";
+  //////// all checks before this line
+  for (uint32_t n = 0; n < nscopes; ++n)
+  {
+    d_smtEngine->push();
+  }
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/**
+ *  ( reset-assertions )
+ */
+void Solver::resetAssertions(void) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  d_smtEngine->resetAssertions();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/**
+ *  ( set-info <attribute> )
+ */
+void Solver::setInfo(const std::string& keyword, const std::string& value) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_RECOVERABLE_ARG_CHECK_EXPECTED(
+      keyword == "source" || keyword == "category" || keyword == "difficulty"
+          || keyword == "filename" || keyword == "license" || keyword == "name"
+          || keyword == "notes" || keyword == "smt-lib-version"
+          || keyword == "status",
+      keyword)
+      << "'source', 'category', 'difficulty', 'filename', 'license', 'name', "
+         "'notes', 'smt-lib-version' or 'status'";
+  CVC4_API_RECOVERABLE_ARG_CHECK_EXPECTED(
+      keyword != "smt-lib-version" || value == "2" || value == "2.0"
+          || value == "2.5" || value == "2.6",
+      value)
+      << "'2.0', '2.5', '2.6'";
+  CVC4_API_ARG_CHECK_EXPECTED(keyword != "status" || value == "sat"
+                                  || value == "unsat" || value == "unknown",
+                              value)
+      << "'sat', 'unsat' or 'unknown'";
+  //////// all checks before this line
+  d_smtEngine->setInfo(keyword, value);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/**
+ *  ( set-logic <symbol> )
+ */
+void Solver::setLogic(const std::string& logic) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK(!d_smtEngine->isFullyInited())
+      << "Invalid call to 'setLogic', solver is already fully initialized";
+  cvc5::LogicInfo logic_info(logic);
+  //////// all checks before this line
+  d_smtEngine->setLogic(logic_info);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/**
+ *  ( set-option <option> )
+ */
+void Solver::setOption(const std::string& option,
+                       const std::string& value) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_CHECK(!d_smtEngine->isFullyInited())
+      << "Invalid call to 'setOption', solver is already fully initialized";
+  //////// all checks before this line
+  d_smtEngine->setOption(option, value);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::mkSygusVar(const Sort& sort, const std::string& symbol) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_SORT(sort);
+  //////// all checks before this line
+  Node res = getNodeManager()->mkBoundVar(symbol, *sort.d_type);
+  (void)res.getType(true); /* kick off type checking */
+
+  d_smtEngine->declareSygusVar(res);
+
+  return Term(this, res);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Grammar Solver::mkSygusGrammar(const std::vector<Term>& boundVars,
+                               const std::vector<Term>& ntSymbols) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_ARG_SIZE_CHECK_EXPECTED(!ntSymbols.empty(), ntSymbols)
+      << "a non-empty vector";
+  CVC4_API_SOLVER_CHECK_BOUND_VARS(boundVars);
+  CVC4_API_SOLVER_CHECK_BOUND_VARS(ntSymbols);
+  //////// all checks before this line
+  return Grammar(this, boundVars, ntSymbols);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::synthFun(const std::string& symbol,
+                      const std::vector<Term>& boundVars,
+                      const Sort& sort) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_BOUND_VARS(boundVars);
+  CVC4_API_SOLVER_CHECK_SORT(sort);
+  //////// all checks before this line
+  return synthFunHelper(symbol, boundVars, sort);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::synthFun(const std::string& symbol,
+                      const std::vector<Term>& boundVars,
+                      Sort sort,
+                      Grammar& grammar) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_BOUND_VARS(boundVars);
+  CVC4_API_SOLVER_CHECK_SORT(sort);
+  //////// all checks before this line
+  return synthFunHelper(symbol, boundVars, sort, false, &grammar);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::synthInv(const std::string& symbol,
+                      const std::vector<Term>& boundVars) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_BOUND_VARS(boundVars);
+  //////// all checks before this line
+  return synthFunHelper(
+      symbol, boundVars, Sort(this, getNodeManager()->booleanType()), true);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::synthInv(const std::string& symbol,
+                      const std::vector<Term>& boundVars,
+                      Grammar& grammar) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_BOUND_VARS(boundVars);
+  //////// all checks before this line
+  return synthFunHelper(symbol,
+                        boundVars,
+                        Sort(this, getNodeManager()->booleanType()),
+                        true,
+                        &grammar);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+void Solver::addSygusConstraint(const Term& term) const
+{
+  NodeManagerScope scope(getNodeManager());
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_TERM(term);
+  CVC4_API_ARG_CHECK_EXPECTED(
+      term.d_node->getType() == getNodeManager()->booleanType(), term)
+      << "boolean term";
+  //////// all checks before this line
+  d_smtEngine->assertSygusConstraint(*term.d_node);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+void Solver::addSygusInvConstraint(Term inv,
+                                   Term pre,
+                                   Term trans,
+                                   Term post) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_TERM(inv);
+  CVC4_API_SOLVER_CHECK_TERM(pre);
+  CVC4_API_SOLVER_CHECK_TERM(trans);
+  CVC4_API_SOLVER_CHECK_TERM(post);
+
+  CVC4_API_ARG_CHECK_EXPECTED(inv.d_node->getType().isFunction(), inv)
+      << "a function";
+
+  TypeNode invType = inv.d_node->getType();
+
+  CVC4_API_ARG_CHECK_EXPECTED(invType.getRangeType().isBoolean(), inv)
+      << "boolean range";
+
+  CVC4_API_CHECK(pre.d_node->getType() == invType)
+      << "Expected inv and pre to have the same sort";
+
+  CVC4_API_CHECK(post.d_node->getType() == invType)
+      << "Expected inv and post to have the same sort";
+  //////// all checks before this line
+
+  const std::vector<TypeNode>& invArgTypes = invType.getArgTypes();
+
+  std::vector<TypeNode> expectedTypes;
+  expectedTypes.reserve(2 * invArgTypes.size() + 1);
+
+  for (size_t i = 0, n = invArgTypes.size(); i < 2 * n; i += 2)
+  {
+    expectedTypes.push_back(invArgTypes[i % n]);
+    expectedTypes.push_back(invArgTypes[(i + 1) % n]);
+  }
+
+  expectedTypes.push_back(invType.getRangeType());
+  TypeNode expectedTransType = getNodeManager()->mkFunctionType(expectedTypes);
+
+  CVC4_API_CHECK(trans.d_node->getType() == expectedTransType)
+      << "Expected trans's sort to be " << invType;
+
+  d_smtEngine->assertSygusInvConstraint(
+      *inv.d_node, *pre.d_node, *trans.d_node, *post.d_node);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Result Solver::checkSynth() const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  return d_smtEngine->checkSynth();
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+Term Solver::getSynthSolution(Term term) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_SOLVER_CHECK_TERM(term);
+
+  std::map<cvc5::Node, cvc5::Node> map;
+  CVC4_API_CHECK(d_smtEngine->getSynthSolutions(map))
+      << "The solver is not in a state immediately preceded by a "
+         "successful call to checkSynth";
+
+  std::map<cvc5::Node, cvc5::Node>::const_iterator it = map.find(*term.d_node);
+
+  CVC4_API_CHECK(it != map.cend()) << "Synth solution not found for given term";
+  //////// all checks before this line
+  return Term(this, it->second);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+std::vector<Term> Solver::getSynthSolutions(
+    const std::vector<Term>& terms) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  CVC4_API_ARG_SIZE_CHECK_EXPECTED(!terms.empty(), terms) << "non-empty vector";
+  CVC4_API_SOLVER_CHECK_TERMS(terms);
+
+  std::map<cvc5::Node, cvc5::Node> map;
+  CVC4_API_CHECK(d_smtEngine->getSynthSolutions(map))
+      << "The solver is not in a state immediately preceded by a "
+         "successful call to checkSynth";
+  //////// all checks before this line
+
+  std::vector<Term> synthSolution;
+  synthSolution.reserve(terms.size());
+
+  for (size_t i = 0, n = terms.size(); i < n; ++i)
+  {
+    std::map<cvc5::Node, cvc5::Node>::const_iterator it =
+        map.find(*terms[i].d_node);
+
+    CVC4_API_CHECK(it != map.cend())
+        << "Synth solution not found for term at index " << i;
+
+    synthSolution.push_back(Term(this, it->second));
+  }
+
+  return synthSolution;
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+void Solver::printSynthSolution(std::ostream& out) const
+{
+  CVC4_API_TRY_CATCH_BEGIN;
+  //////// all checks before this line
+  d_smtEngine->printSynthSolution(out);
+  ////////
+  CVC4_API_TRY_CATCH_END;
+}
+
+/**
+ * !!! This is only temporarily available until the parser is fully migrated to
+ * the new API. !!!
+ */
+SmtEngine* Solver::getSmtEngine(void) const { return d_smtEngine.get(); }
+
+/**
+ * !!! This is only temporarily available until the parser is fully migrated to
+ * the new API. !!!
+ */
+Options& Solver::getOptions(void) { return d_smtEngine->getOptions(); }
+
+}  // namespace api
+
+}  // namespace cvc5
diff --git a/src/api/cpp/cvc5.h b/src/api/cpp/cvc5.h
new file mode 100644 (file)
index 0000000..ec2f32c
--- /dev/null
@@ -0,0 +1,3658 @@
+/*********************                                                        */
+/*! \file cvc5.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Aina Niemetz, Andrew Reynolds, Abdalrhman Mohamed
+ ** This file is part of the CVC4 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.\endverbatim
+ **
+ ** \brief The CVC4 C++ API.
+ **
+ ** The CVC4 C++ API.
+ **/
+
+#include "cvc4_export.h"
+
+#ifndef CVC5__API__CVC5_H
+#define CVC5__API__CVC5_H
+
+#include <map>
+#include <memory>
+#include <set>
+#include <sstream>
+#include <string>
+#include <unordered_map>
+#include <unordered_set>
+#include <vector>
+
+#include "api/cpp/cvc5_kind.h"
+
+namespace cvc5 {
+
+template <bool ref_count>
+class NodeTemplate;
+typedef NodeTemplate<true> Node;
+
+class Command;
+class DType;
+class DTypeConstructor;
+class DTypeSelector;
+class NodeManager;
+class SmtEngine;
+class TypeNode;
+class Options;
+class Random;
+class Result;
+
+namespace api {
+
+class Solver;
+struct Statistics;
+
+/* -------------------------------------------------------------------------- */
+/* Exception                                                                  */
+/* -------------------------------------------------------------------------- */
+
+class CVC4_EXPORT CVC4ApiException : public std::exception
+{
+ public:
+  CVC4ApiException(const std::string& str) : d_msg(str) {}
+  CVC4ApiException(const std::stringstream& stream) : d_msg(stream.str()) {}
+  std::string getMessage() const { return d_msg; }
+  const char* what() const noexcept override { return d_msg.c_str(); }
+
+ private:
+  std::string d_msg;
+};
+
+class CVC4_EXPORT CVC4ApiRecoverableException : public CVC4ApiException
+{
+ public:
+  CVC4ApiRecoverableException(const std::string& str) : CVC4ApiException(str) {}
+  CVC4ApiRecoverableException(const std::stringstream& stream)
+      : CVC4ApiException(stream.str())
+  {
+  }
+};
+
+/* -------------------------------------------------------------------------- */
+/* Result                                                                     */
+/* -------------------------------------------------------------------------- */
+
+/**
+ * Encapsulation of a three-valued solver result, with explanations.
+ */
+class CVC4_EXPORT Result
+{
+  friend class Solver;
+
+ public:
+  enum UnknownExplanation
+  {
+    REQUIRES_FULL_CHECK,
+    INCOMPLETE,
+    TIMEOUT,
+    RESOURCEOUT,
+    MEMOUT,
+    INTERRUPTED,
+    NO_STATUS,
+    UNSUPPORTED,
+    OTHER,
+    UNKNOWN_REASON
+  };
+
+  /** Constructor. */
+  Result();
+
+  /**
+   * Return true if Result is empty, i.e., a nullary Result, and not an actual
+   * result returned from a checkSat() (and friends) query.
+   */
+  bool isNull() const;
+
+  /**
+   * Return true if query was a satisfiable checkSat() or checkSatAssuming()
+   * query.
+   */
+  bool isSat() const;
+
+  /**
+   * Return true if query was an unsatisfiable checkSat() or
+   * checkSatAssuming() query.
+   */
+  bool isUnsat() const;
+
+  /**
+   * Return true if query was a checkSat() or checkSatAssuming() query and
+   * CVC4 was not able to determine (un)satisfiability.
+   */
+  bool isSatUnknown() const;
+
+  /**
+   * Return true if corresponding query was an entailed checkEntailed() query.
+   */
+  bool isEntailed() const;
+
+  /**
+   * Return true if corresponding query was a checkEntailed() query that is
+   * not entailed.
+   */
+  bool isNotEntailed() const;
+
+  /**
+   * Return true if query was a checkEntailed() () query and CVC4 was not able
+   * to determine if it is entailed.
+   */
+  bool isEntailmentUnknown() const;
+
+  /**
+   * Operator overloading for equality of two results.
+   * @param r the result to compare to for equality
+   * @return true if the results are equal
+   */
+  bool operator==(const Result& r) const;
+
+  /**
+   * Operator overloading for disequality of two results.
+   * @param r the result to compare to for disequality
+   * @return true if the results are disequal
+   */
+  bool operator!=(const Result& r) const;
+
+  /**
+   * @return an explanation for an unknown query result.
+   */
+  UnknownExplanation getUnknownExplanation() const;
+
+  /**
+   * @return a string representation of this result.
+   */
+  std::string toString() const;
+
+ private:
+  /**
+   * Constructor.
+   * @param r the internal result that is to be wrapped by this result
+   * @return the Result
+   */
+  Result(const cvc5::Result& r);
+
+  /**
+   * The interal result wrapped by this result.
+   * Note: This is a shared_ptr rather than a unique_ptr since cvc5::Result is
+   *       not ref counted.
+   */
+  std::shared_ptr<cvc5::Result> d_result;
+};
+
+/**
+ * Serialize a Result to given stream.
+ * @param out the output stream
+ * @param r the result to be serialized to the given output stream
+ * @return the output stream
+ */
+std::ostream& operator<<(std::ostream& out, const Result& r) CVC4_EXPORT;
+
+/**
+ * Serialize an UnknownExplanation to given stream.
+ * @param out the output stream
+ * @param r the explanation to be serialized to the given output stream
+ * @return the output stream
+ */
+std::ostream& operator<<(std::ostream& out,
+                         enum Result::UnknownExplanation e) CVC4_EXPORT;
+
+/* -------------------------------------------------------------------------- */
+/* Sort                                                                       */
+/* -------------------------------------------------------------------------- */
+
+class Datatype;
+
+/**
+ * The sort of a CVC4 term.
+ */
+class CVC4_EXPORT Sort
+{
+  friend class cvc5::Command;
+  friend class DatatypeConstructor;
+  friend class DatatypeConstructorDecl;
+  friend class DatatypeSelector;
+  friend class DatatypeDecl;
+  friend class Op;
+  friend class Solver;
+  friend class Grammar;
+  friend struct SortHashFunction;
+  friend class Term;
+
+ public:
+  /**
+   * Constructor.
+   */
+  Sort();
+
+  /**
+   * Destructor.
+   */
+  ~Sort();
+
+  /**
+   * Comparison for structural equality.
+   * @param s the sort to compare to
+   * @return true if the sorts are equal
+   */
+  bool operator==(const Sort& s) const;
+
+  /**
+   * Comparison for structural disequality.
+   * @param s the sort to compare to
+   * @return true if the sorts are not equal
+   */
+  bool operator!=(const Sort& s) const;
+
+  /**
+   * Comparison for ordering on sorts.
+   * @param s the sort to compare to
+   * @return true if this sort is less than s
+   */
+  bool operator<(const Sort& s) const;
+
+  /**
+   * Comparison for ordering on sorts.
+   * @param s the sort to compare to
+   * @return true if this sort is greater than s
+   */
+  bool operator>(const Sort& s) const;
+
+  /**
+   * Comparison for ordering on sorts.
+   * @param s the sort to compare to
+   * @return true if this sort is less than or equal to s
+   */
+  bool operator<=(const Sort& s) const;
+
+  /**
+   * Comparison for ordering on sorts.
+   * @param s the sort to compare to
+   * @return true if this sort is greater than or equal to s
+   */
+  bool operator>=(const Sort& s) const;
+
+  /**
+   * @return true if this Sort is a null sort.
+   */
+  bool isNull() const;
+
+  /**
+   * Is this a Boolean sort?
+   * @return true if the sort is a Boolean sort
+   */
+  bool isBoolean() const;
+
+  /**
+   * Is this a integer sort?
+   * @return true if the sort is a integer sort
+   */
+  bool isInteger() const;
+
+  /**
+   * Is this a real sort?
+   * @return true if the sort is a real sort
+   */
+  bool isReal() const;
+
+  /**
+   * Is this a string sort?
+   * @return true if the sort is the string sort
+   */
+  bool isString() const;
+
+  /**
+   * Is this a regexp sort?
+   * @return true if the sort is the regexp sort
+   */
+  bool isRegExp() const;
+
+  /**
+   * Is this a rounding mode sort?
+   * @return true if the sort is the rounding mode sort
+   */
+  bool isRoundingMode() const;
+
+  /**
+   * Is this a bit-vector sort?
+   * @return true if the sort is a bit-vector sort
+   */
+  bool isBitVector() const;
+
+  /**
+   * Is this a floating-point sort?
+   * @return true if the sort is a floating-point sort
+   */
+  bool isFloatingPoint() const;
+
+  /**
+   * Is this a datatype sort?
+   * @return true if the sort is a datatype sort
+   */
+  bool isDatatype() const;
+
+  /**
+   * Is this a parametric datatype sort?
+   * @return true if the sort is a parametric datatype sort
+   */
+  bool isParametricDatatype() const;
+
+  /**
+   * Is this a constructor sort?
+   * @return true if the sort is a constructor sort
+   */
+  bool isConstructor() const;
+
+  /**
+   * Is this a selector sort?
+   * @return true if the sort is a selector sort
+   */
+  bool isSelector() const;
+
+  /**
+   * Is this a tester sort?
+   * @return true if the sort is a tester sort
+   */
+  bool isTester() const;
+  /**
+   * Is this a function sort?
+   * @return true if the sort is a function sort
+   */
+  bool isFunction() const;
+
+  /**
+   * Is this a predicate sort?
+   * That is, is this a function sort mapping to Boolean? All predicate
+   * sorts are also function sorts.
+   * @return true if the sort is a predicate sort
+   */
+  bool isPredicate() const;
+
+  /**
+   * Is this a tuple sort?
+   * @return true if the sort is a tuple sort
+   */
+  bool isTuple() const;
+
+  /**
+   * Is this a record sort?
+   * @return true if the sort is a record sort
+   */
+  bool isRecord() const;
+
+  /**
+   * Is this an array sort?
+   * @return true if the sort is a array sort
+   */
+  bool isArray() const;
+
+  /**
+   * Is this a Set sort?
+   * @return true if the sort is a Set sort
+   */
+  bool isSet() const;
+
+  /**
+   * Is this a Bag sort?
+   * @return true if the sort is a Bag sort
+   */
+  bool isBag() const;
+
+  /**
+   * Is this a Sequence sort?
+   * @return true if the sort is a Sequence sort
+   */
+  bool isSequence() const;
+
+  /**
+   * Is this a sort kind?
+   * @return true if this is a sort kind
+   */
+  bool isUninterpretedSort() const;
+
+  /**
+   * Is this a sort constructor kind?
+   * @return true if this is a sort constructor kind
+   */
+  bool isSortConstructor() const;
+
+  /**
+   * Is this a first-class sort?
+   * First-class sorts are sorts for which:
+   * (1) we handle equalities between terms of that type, and
+   * (2) they are allowed to be parameters of parametric sorts (e.g. index or
+   *     element sorts of arrays).
+   *
+   * Examples of sorts that are not first-class include sort constructor sorts
+   * and regular expression sorts.
+   *
+   * @return true if this is a first-class sort
+   */
+  bool isFirstClass() const;
+
+  /**
+   * Is this a function-LIKE sort?
+   *
+   * Anything function-like except arrays (e.g., datatype selectors) is
+   * considered a function here. Function-like terms can not be the argument
+   * or return value for any term that is function-like.
+   * This is mainly to avoid higher order.
+   *
+   * Note that arrays are explicitly not considered function-like here.
+   *
+   * @return true if this is a function-like sort
+   */
+  bool isFunctionLike() const;
+
+  /**
+   * Is this sort a subsort of the given sort?
+   * @return true if this sort is a subsort of s
+   */
+  bool isSubsortOf(const Sort& s) const;
+
+  /**
+   * Is this sort comparable to the given sort (i.e., do they share
+   * a common ancestor in the subsort tree)?
+   * @return true if this sort is comparable to s
+   */
+  bool isComparableTo(const Sort& s) const;
+
+  /**
+   * @return the underlying datatype of a datatype sort
+   */
+  Datatype getDatatype() const;
+
+  /**
+   * Instantiate a parameterized datatype/sort sort.
+   * Create sorts parameter with Solver::mkParamSort().
+   * @param params the list of sort parameters to instantiate with
+   */
+  Sort instantiate(const std::vector<Sort>& params) const;
+
+  /**
+   * Substitution of Sorts.
+   * @param sort the subsort to be substituted within this sort.
+   * @param replacement the sort replacing the substituted subsort.
+   */
+  Sort substitute(const Sort& sort, const Sort& replacement) const;
+
+  /**
+   * Simultaneous substitution of Sorts.
+   * @param sorts the subsorts to be substituted within this sort.
+   * @param replacements the sort replacing the substituted subsorts.
+   */
+  Sort substitute(const std::vector<Sort>& sorts,
+                  const std::vector<Sort>& replacements) const;
+
+  /**
+   * Output a string representation of this sort to a given stream.
+   * @param out the output stream
+   */
+  void toStream(std::ostream& out) const;
+
+  /**
+   * @return a string representation of this sort
+   */
+  std::string toString() const;
+
+  /* Constructor sort ------------------------------------------------------- */
+
+  /**
+   * @return the arity of a constructor sort
+   */
+  size_t getConstructorArity() const;
+
+  /**
+   * @return the domain sorts of a constructor sort
+   */
+  std::vector<Sort> getConstructorDomainSorts() const;
+
+  /**
+   * @return the codomain sort of a constructor sort
+   */
+  Sort getConstructorCodomainSort() const;
+
+  /* Selector sort ------------------------------------------------------- */
+
+  /**
+   * @return the domain sort of a selector sort
+   */
+  Sort getSelectorDomainSort() const;
+
+  /**
+   * @return the codomain sort of a selector sort
+   */
+  Sort getSelectorCodomainSort() const;
+
+  /* Tester sort ------------------------------------------------------- */
+
+  /**
+   * @return the domain sort of a tester sort
+   */
+  Sort getTesterDomainSort() const;
+
+  /**
+   * @return the codomain sort of a tester sort, which is the Boolean sort
+   */
+  Sort getTesterCodomainSort() const;
+
+  /* Function sort ------------------------------------------------------- */
+
+  /**
+   * @return the arity of a function sort
+   */
+  size_t getFunctionArity() const;
+
+  /**
+   * @return the domain sorts of a function sort
+   */
+  std::vector<Sort> getFunctionDomainSorts() const;
+
+  /**
+   * @return the codomain sort of a function sort
+   */
+  Sort getFunctionCodomainSort() const;
+
+  /* Array sort ---------------------------------------------------------- */
+
+  /**
+   * @return the array index sort of an array sort
+   */
+  Sort getArrayIndexSort() const;
+
+  /**
+   * @return the array element sort of an array element sort
+   */
+  Sort getArrayElementSort() const;
+
+  /* Set sort ------------------------------------------------------------ */
+
+  /**
+   * @return the element sort of a set sort
+   */
+  Sort getSetElementSort() const;
+
+  /* Bag sort ------------------------------------------------------------ */
+
+  /**
+   * @return the element sort of a bag sort
+   */
+  Sort getBagElementSort() const;
+
+  /* Sequence sort ------------------------------------------------------- */
+
+  /**
+   * @return the element sort of a sequence sort
+   */
+  Sort getSequenceElementSort() const;
+
+  /* Uninterpreted sort -------------------------------------------------- */
+
+  /**
+   * @return the name of an uninterpreted sort
+   */
+  std::string getUninterpretedSortName() const;
+
+  /**
+   * @return true if an uninterpreted sort is parameterezied
+   */
+  bool isUninterpretedSortParameterized() const;
+
+  /**
+   * @return the parameter sorts of an uninterpreted sort
+   */
+  std::vector<Sort> getUninterpretedSortParamSorts() const;
+
+  /* Sort constructor sort ----------------------------------------------- */
+
+  /**
+   * @return the name of a sort constructor sort
+   */
+  std::string getSortConstructorName() const;
+
+  /**
+   * @return the arity of a sort constructor sort
+   */
+  size_t getSortConstructorArity() const;
+
+  /* Bit-vector sort ----------------------------------------------------- */
+
+  /**
+   * @return the bit-width of the bit-vector sort
+   */
+  uint32_t getBVSize() const;
+
+  /* Floating-point sort ------------------------------------------------- */
+
+  /**
+   * @return the bit-width of the exponent of the floating-point sort
+   */
+  uint32_t getFPExponentSize() const;
+
+  /**
+   * @return the width of the significand of the floating-point sort
+   */
+  uint32_t getFPSignificandSize() const;
+
+  /* Datatype sort ------------------------------------------------------- */
+
+  /**
+   * @return the parameter sorts of a datatype sort
+   */
+  std::vector<Sort> getDatatypeParamSorts() const;
+
+  /**
+   * @return the arity of a datatype sort
+   */
+  size_t getDatatypeArity() const;
+
+  /* Tuple sort ---------------------------------------------------------- */
+
+  /**
+   * @return the length of a tuple sort
+   */
+  size_t getTupleLength() const;
+
+  /**
+   * @return the element sorts of a tuple sort
+   */
+  std::vector<Sort> getTupleSorts() const;
+
+ private:
+  /** @return the internal wrapped TypeNode of this sort. */
+  const cvc5::TypeNode& getTypeNode(void) const;
+
+  /** Helper to convert a set of Sorts to internal TypeNodes. */
+  std::set<TypeNode> static sortSetToTypeNodes(const std::set<Sort>& sorts);
+  /** Helper to convert a vector of Sorts to internal TypeNodes. */
+  std::vector<TypeNode> static sortVectorToTypeNodes(
+      const std::vector<Sort>& sorts);
+  /** Helper to convert a vector of internal TypeNodes to Sorts. */
+  std::vector<Sort> static typeNodeVectorToSorts(
+      const Solver* slv, const std::vector<TypeNode>& types);
+
+  /**
+   * Constructor.
+   * @param slv the associated solver object
+   * @param t the internal type that is to be wrapped by this sort
+   * @return the Sort
+   */
+  Sort(const Solver* slv, const cvc5::TypeNode& t);
+
+  /**
+   * Helper for isNull checks. This prevents calling an API function with
+   * CVC4_API_CHECK_NOT_NULL
+   */
+  bool isNullHelper() const;
+
+  /**
+   * The associated solver object.
+   */
+  const Solver* d_solver;
+
+  /**
+   * The interal type wrapped by this sort.
+   * Note: This is a shared_ptr rather than a unique_ptr to avoid overhead due
+   *       to memory allocation (cvc5::Type is already ref counted, so this
+   *       could be a unique_ptr instead).
+   */
+  std::shared_ptr<cvc5::TypeNode> d_type;
+};
+
+/**
+ * Serialize a sort to given stream.
+ * @param out the output stream
+ * @param s the sort to be serialized to the given output stream
+ * @return the output stream
+ */
+std::ostream& operator<<(std::ostream& out, const Sort& s) CVC4_EXPORT;
+
+/**
+ * Hash function for Sorts.
+ */
+struct CVC4_EXPORT SortHashFunction
+{
+  size_t operator()(const Sort& s) const;
+};
+
+/* -------------------------------------------------------------------------- */
+/* Op                                                                     */
+/* -------------------------------------------------------------------------- */
+
+/**
+ * A CVC4 operator.
+ * An operator is a term that represents certain operators, instantiated
+ * with its required parameters, e.g., a term of kind BITVECTOR_EXTRACT.
+ */
+class CVC4_EXPORT Op
+{
+  friend class Solver;
+  friend class Term;
+  friend struct OpHashFunction;
+
+ public:
+  /**
+   * Constructor.
+   */
+  Op();
+
+  /**
+   * Destructor.
+   */
+  ~Op();
+
+  /**
+   * Syntactic equality operator.
+   * Return true if both operators are syntactically identical.
+   * Both operators must belong to the same solver object.
+   * @param t the operator to compare to for equality
+   * @return true if the operators are equal
+   */
+  bool operator==(const Op& t) const;
+
+  /**
+   * Syntactic disequality operator.
+   * Return true if both operators differ syntactically.
+   * Both terms must belong to the same solver object.
+   * @param t the operator to compare to for disequality
+   * @return true if operators are disequal
+   */
+  bool operator!=(const Op& t) const;
+
+  /**
+   * @return the kind of this operator
+   */
+  Kind getKind() const;
+
+  /**
+   * @return true if this operator is a null term
+   */
+  bool isNull() const;
+
+  /**
+   * @return true iff this operator is indexed
+   */
+  bool isIndexed() const;
+
+  /**
+   * Get the indices used to create this Op.
+   * Supports the following template arguments:
+   *   - string
+   *   - Kind
+   *   - uint32_t
+   *   - pair<uint32_t, uint32_t>
+   * Check the Op Kind with getKind() to determine which argument to use.
+   * @return the indices used to create this Op
+   */
+  template <typename T>
+  T getIndices() const;
+
+  /**
+   * @return a string representation of this operator
+   */
+  std::string toString() const;
+
+ private:
+  /**
+   * Constructor for a single kind (non-indexed operator).
+   * @param slv the associated solver object
+   * @param k the kind of this Op
+   */
+  Op(const Solver* slv, const Kind k);
+
+  /**
+   * Constructor.
+   * @param slv the associated solver object
+   * @param k the kind of this Op
+   * @param n the internal node that is to be wrapped by this term
+   * @return the Term
+   */
+  Op(const Solver* slv, const Kind k, const cvc5::Node& n);
+
+  /**
+   * Helper for isNull checks. This prevents calling an API function with
+   * CVC4_API_CHECK_NOT_NULL
+   */
+  bool isNullHelper() const;
+
+  /**
+   * Note: An indexed operator has a non-null internal node, d_node
+   * Note 2: We use a helper method to avoid having API functions call
+   *         other API functions (we need to call this internally)
+   * @return true iff this Op is indexed
+   */
+  bool isIndexedHelper() const;
+
+  /**
+   * The associated solver object.
+   */
+  const Solver* d_solver;
+
+  /** The kind of this operator. */
+  Kind d_kind;
+
+  /**
+   * The internal node wrapped by this operator.
+   * Note: This is a shared_ptr rather than a unique_ptr to avoid overhead due
+   *       to memory allocation (cvc5::Node is already ref counted, so this
+   *       could be a unique_ptr instead).
+   */
+  std::shared_ptr<cvc5::Node> d_node;
+};
+
+/* -------------------------------------------------------------------------- */
+/* Term                                                                       */
+/* -------------------------------------------------------------------------- */
+
+/**
+ * A CVC4 Term.
+ */
+class CVC4_EXPORT Term
+{
+  friend class cvc5::Command;
+  friend class Datatype;
+  friend class DatatypeConstructor;
+  friend class DatatypeSelector;
+  friend class Solver;
+  friend class Grammar;
+  friend struct TermHashFunction;
+
+ public:
+  /**
+   * Constructor.
+   */
+  Term();
+
+  /**
+   * Destructor.
+   */
+  ~Term();
+
+  /**
+   * Syntactic equality operator.
+   * Return true if both terms are syntactically identical.
+   * Both terms must belong to the same solver object.
+   * @param t the term to compare to for equality
+   * @return true if the terms are equal
+   */
+  bool operator==(const Term& t) const;
+
+  /**
+   * Syntactic disequality operator.
+   * Return true if both terms differ syntactically.
+   * Both terms must belong to the same solver object.
+   * @param t the term to compare to for disequality
+   * @return true if terms are disequal
+   */
+  bool operator!=(const Term& t) const;
+
+  /**
+   * Comparison for ordering on terms.
+   * @param t the term to compare to
+   * @return true if this term is less than t
+   */
+  bool operator<(const Term& t) const;
+
+  /**
+   * Comparison for ordering on terms.
+   * @param t the term to compare to
+   * @return true if this term is greater than t
+   */
+  bool operator>(const Term& t) const;
+
+  /**
+   * Comparison for ordering on terms.
+   * @param t the term to compare to
+   * @return true if this term is less than or equal to t
+   */
+  bool operator<=(const Term& t) const;
+
+  /**
+   * Comparison for ordering on terms.
+   * @param t the term to compare to
+   * @return true if this term is greater than or equal to t
+   */
+  bool operator>=(const Term& t) const;
+
+  /** @return the number of children of this term  */
+  size_t getNumChildren() const;
+
+  /**
+   * Get the child term at a given index.
+   * @param index the index of the child term to return
+   * @return the child term with the given index
+   */
+  Term operator[](size_t index) const;
+
+  /**
+   * @return the id of this term
+   */
+  uint64_t getId() const;
+
+  /**
+   * @return the kind of this term
+   */
+  Kind getKind() const;
+
+  /**
+   * @return the sort of this term
+   */
+  Sort getSort() const;
+
+  /**
+   * @return the result of replacing 'term' by 'replacement' in this term
+   */
+  Term substitute(const Term& term, const Term& replacement) const;
+
+  /**
+   * @return the result of simulatenously replacing 'terms' by 'replacements'
+   * in this term
+   */
+  Term substitute(const std::vector<Term>& terms,
+                  const std::vector<Term>& replacements) const;
+
+  /**
+   * @return true iff this term has an operator
+   */
+  bool hasOp() const;
+
+  /**
+   * @return the Op used to create this term
+   * Note: This is safe to call when hasOp() returns true.
+   */
+  Op getOp() const;
+
+  /**
+   * @return true if this Term is a null term
+   */
+  bool isNull() const;
+
+  /**
+   *  Return the base (element stored at all indices) of a constant array
+   *  throws an exception if the kind is not CONST_ARRAY
+   *  @return the base value
+   */
+  Term getConstArrayBase() const;
+
+  /**
+   *  Return the elements of a constant sequence
+   *  throws an exception if the kind is not CONST_SEQUENCE
+   *  @return the elements of the constant sequence.
+   */
+  std::vector<Term> getConstSequenceElements() const;
+
+  /**
+   * Boolean negation.
+   * @return the Boolean negation of this term
+   */
+  Term notTerm() const;
+
+  /**
+   * Boolean and.
+   * @param t a Boolean term
+   * @return the conjunction of this term and the given term
+   */
+  Term andTerm(const Term& t) const;
+
+  /**
+   * Boolean or.
+   * @param t a Boolean term
+   * @return the disjunction of this term and the given term
+   */
+  Term orTerm(const Term& t) const;
+
+  /**
+   * Boolean exclusive or.
+   * @param t a Boolean term
+   * @return the exclusive disjunction of this term and the given term
+   */
+  Term xorTerm(const Term& t) const;
+
+  /**
+   * Equality.
+   * @param t a Boolean term
+   * @return the Boolean equivalence of this term and the given term
+   */
+  Term eqTerm(const Term& t) const;
+
+  /**
+   * Boolean implication.
+   * @param t a Boolean term
+   * @return the implication of this term and the given term
+   */
+  Term impTerm(const Term& t) const;
+
+  /**
+   * If-then-else with this term as the Boolean condition.
+   * @param then_t the 'then' term
+   * @param else_t the 'else' term
+   * @return the if-then-else term with this term as the Boolean condition
+   */
+  Term iteTerm(const Term& then_t, const Term& else_t) const;
+
+  /**
+   * @return a string representation of this term
+   */
+  std::string toString() const;
+
+  /**
+   * Iterator for the children of a Term.
+   * Note: This treats uninterpreted functions as Term just like any other term
+   *       for example, the term f(x, y) will have Kind APPLY_UF and three
+   *       children: f, x, and y
+   */
+  class const_iterator : public std::iterator<std::input_iterator_tag, Term>
+  {
+    friend class Term;
+
+   public:
+    /**
+     * Null Constructor.
+     */
+    const_iterator();
+
+    /**
+     * Constructor
+     * @param slv the associated solver object
+     * @param e a shared pointer to the node that we're iterating over
+     * @param p the position of the iterator (e.g. which child it's on)
+     */
+    const_iterator(const Solver* slv,
+                   const std::shared_ptr<cvc5::Node>& e,
+                   uint32_t p);
+
+    /**
+     * Copy constructor.
+     */
+    const_iterator(const const_iterator& it);
+
+    /**
+     * Assignment operator.
+     * @param it the iterator to assign to
+     * @return the reference to the iterator after assignment
+     */
+    const_iterator& operator=(const const_iterator& it);
+
+    /**
+     * Equality operator.
+     * @param it the iterator to compare to for equality
+     * @return true if the iterators are equal
+     */
+    bool operator==(const const_iterator& it) const;
+
+    /**
+     * Disequality operator.
+     * @param it the iterator to compare to for disequality
+     * @return true if the iterators are disequal
+     */
+    bool operator!=(const const_iterator& it) const;
+
+    /**
+     * Increment operator (prefix).
+     * @return a reference to the iterator after incrementing by one
+     */
+    const_iterator& operator++();
+
+    /**
+     * Increment operator (postfix).
+     * @return a reference to the iterator after incrementing by one
+     */
+    const_iterator operator++(int);
+
+    /**
+     * Dereference operator.
+     * @return the term this iterator points to
+     */
+    Term operator*() const;
+
+   private:
+    /**
+     * The associated solver object.
+     */
+    const Solver* d_solver;
+    /** The original node to be iterated over. */
+    std::shared_ptr<cvc5::Node> d_origNode;
+    /** Keeps track of the iteration position. */
+    uint32_t d_pos;
+  };
+
+  /**
+   * @return an iterator to the first child of this Term
+   */
+  const_iterator begin() const;
+
+  /**
+   * @return an iterator to one-off-the-last child of this Term
+   */
+  const_iterator end() const;
+
+  /**
+   * @return true if the term is an integer that fits within std::int32_t.
+   */
+  bool isInt32() const;
+  /**
+   * @return the stored integer as a std::int32_t.
+   * Note: Asserts isInt32().
+   */
+  std::int32_t getInt32() const;
+  /**
+   * @return true if the term is an integer that fits within std::uint32_t.
+   */
+  bool isUInt32() const;
+  /**
+   * @return the stored integer as a std::uint32_t.
+   * Note: Asserts isUInt32().
+   */
+  std::uint32_t getUInt32() const;
+  /**
+   * @return true if the term is an integer that fits within std::int64_t.
+   */
+  bool isInt64() const;
+  /**
+   * @return the stored integer as a std::int64_t.
+   * Note: Asserts isInt64().
+   */
+  std::int64_t getInt64() const;
+  /**
+   * @return true if the term is an integer that fits within std::uint64_t.
+   */
+  bool isUInt64() const;
+  /**
+   * @return the stored integer as a std::uint64_t.
+   * Note: Asserts isUInt64().
+   */
+  std::uint64_t getUInt64() const;
+  /**
+   * @return true if the term is an integer.
+   */
+  bool isInteger() const;
+  /**
+   * @return the stored integer in (decimal) string representation.
+   * Note: Asserts isInteger().
+   */
+  std::string getInteger() const;
+
+  /**
+   * @return true if the term is a string constant.
+   */
+  bool isString() const;
+  /**
+   * @return the stored string constant.
+   *
+   * Note: This method is not to be confused with toString() which returns the
+   *       term in some string representation, whatever data it may hold.
+   *       Asserts isString().
+   */
+  std::wstring getString() const;
+
+ protected:
+  /**
+   * The associated solver object.
+   */
+  const Solver* d_solver;
+
+ private:
+  /** Helper to convert a vector of Terms to internal Nodes. */
+  std::vector<Node> static termVectorToNodes(const std::vector<Term>& terms);
+
+  /**
+   * Constructor.
+   * @param slv the associated solver object
+   * @param n the internal node that is to be wrapped by this term
+   * @return the Term
+   */
+  Term(const Solver* slv, const cvc5::Node& n);
+
+  /** @return the internal wrapped Node of this term. */
+  const cvc5::Node& getNode(void) const;
+
+  /**
+   * Helper for isNull checks. This prevents calling an API function with
+   * CVC4_API_CHECK_NOT_NULL
+   */
+  bool isNullHelper() const;
+
+  /**
+   * Helper function that returns the kind of the term, which takes into
+   * account special cases of the conversion for internal to external kinds.
+   * @return the kind of this term
+   */
+  Kind getKindHelper() const;
+
+  /**
+   * @return true if the current term is a constant integer that is casted into
+   * real using the operator CAST_TO_REAL, and returns false otherwise
+   */
+  bool isCastedReal() const;
+  /**
+   * The internal node wrapped by this term.
+   * Note: This is a shared_ptr rather than a unique_ptr to avoid overhead due
+   *       to memory allocation (cvc5::Node is already ref counted, so this
+   *       could be a unique_ptr instead).
+   */
+  std::shared_ptr<cvc5::Node> d_node;
+};
+
+/**
+ * Hash function for Terms.
+ */
+struct CVC4_EXPORT TermHashFunction
+{
+  size_t operator()(const Term& t) const;
+};
+
+/**
+ * Serialize a term to given stream.
+ * @param out the output stream
+ * @param t the term to be serialized to the given output stream
+ * @return the output stream
+ */
+std::ostream& operator<<(std::ostream& out, const Term& t) CVC4_EXPORT;
+
+/**
+ * Serialize a vector of terms to given stream.
+ * @param out the output stream
+ * @param vector the vector of terms to be serialized to the given stream
+ * @return the output stream
+ */
+std::ostream& operator<<(std::ostream& out,
+                         const std::vector<Term>& vector) CVC4_EXPORT;
+
+/**
+ * Serialize a set of terms to the given stream.
+ * @param out the output stream
+ * @param set the set of terms to be serialized to the given stream
+ * @return the output stream
+ */
+std::ostream& operator<<(std::ostream& out,
+                         const std::set<Term>& set) CVC4_EXPORT;
+
+/**
+ * Serialize an unordered_set of terms to the given stream.
+ *
+ * @param out the output stream
+ * @param unordered_set the set of terms to be serialized to the given stream
+ * @return the output stream
+ */
+std::ostream& operator<<(std::ostream& out,
+                         const std::unordered_set<Term, TermHashFunction>&
+                             unordered_set) CVC4_EXPORT;
+
+/**
+ * Serialize a map of terms to the given stream.
+ *
+ * @param out the output stream
+ * @param map the map of terms to be serialized to the given stream
+ * @return the output stream
+ */
+template <typename V>
+std::ostream& operator<<(std::ostream& out,
+                         const std::map<Term, V>& map) CVC4_EXPORT;
+
+/**
+ * Serialize an unordered_map of terms to the given stream.
+ *
+ * @param out the output stream
+ * @param unordered_map the map of terms to be serialized to the given stream
+ * @return the output stream
+ */
+template <typename V>
+std::ostream& operator<<(std::ostream& out,
+                         const std::unordered_map<Term, V, TermHashFunction>&
+                             unordered_map) CVC4_EXPORT;
+
+/**
+ * Serialize an operator to given stream.
+ * @param out the output stream
+ * @param t the operator to be serialized to the given output stream
+ * @return the output stream
+ */
+std::ostream& operator<<(std::ostream& out, const Op& t) CVC4_EXPORT;
+
+/**
+ * Hash function for Ops.
+ */
+struct CVC4_EXPORT OpHashFunction
+{
+  size_t operator()(const Op& t) const;
+};
+
+/* -------------------------------------------------------------------------- */
+/* Datatypes                                                                  */
+/* -------------------------------------------------------------------------- */
+
+class DatatypeConstructorIterator;
+class DatatypeIterator;
+
+/**
+ * A CVC4 datatype constructor declaration.
+ */
+class CVC4_EXPORT DatatypeConstructorDecl
+{
+  friend class DatatypeDecl;
+  friend class Solver;
+
+ public:
+  /** Constructor.  */
+  DatatypeConstructorDecl();
+
+  /**
+   * Destructor.
+   */
+  ~DatatypeConstructorDecl();
+
+  /**
+   * Add datatype selector declaration.
+   * @param name the name of the datatype selector declaration to add
+   * @param sort the range sort of the datatype selector declaration to add
+   */
+  void addSelector(const std::string& name, const Sort& sort);
+  /**
+   * Add datatype selector declaration whose range type is the datatype itself.
+   * @param name the name of the datatype selector declaration to add
+   */
+  void addSelectorSelf(const std::string& name);
+
+  /**
+   * @return true if this DatatypeConstructorDecl is a null declaration.
+   */
+  bool isNull() const;
+
+  /**
+   * @return a string representation of this datatype constructor declaration
+   */
+  std::string toString() const;
+
+ private:
+  /**
+   * Constructor.
+   * @param slv the associated solver object
+   * @param name the name of the datatype constructor
+   * @return the DatatypeConstructorDecl
+   */
+  DatatypeConstructorDecl(const Solver* slv, const std::string& name);
+
+  /**
+   * Helper for isNull checks. This prevents calling an API function with
+   * CVC4_API_CHECK_NOT_NULL
+   */
+  bool isNullHelper() const;
+
+  /**
+   * The associated solver object.
+   */
+  const Solver* d_solver;
+
+  /**
+   * The internal (intermediate) datatype constructor wrapped by this
+   * datatype constructor declaration.
+   * Note: This is a shared_ptr rather than a unique_ptr since
+   *       cvc5::DTypeConstructor is not ref counted.
+   */
+  std::shared_ptr<cvc5::DTypeConstructor> d_ctor;
+};
+
+class Solver;
+
+/**
+ * A CVC4 datatype declaration.
+ */
+class CVC4_EXPORT DatatypeDecl
+{
+  friend class DatatypeConstructorArg;
+  friend class Solver;
+  friend class Grammar;
+
+ public:
+  /** Constructor.  */
+  DatatypeDecl();
+
+  /**
+   * Destructor.
+   */
+  ~DatatypeDecl();
+
+  /**
+   * Add datatype constructor declaration.
+   * @param ctor the datatype constructor declaration to add
+   */
+  void addConstructor(const DatatypeConstructorDecl& ctor);
+
+  /** Get the number of constructors (so far) for this Datatype declaration. */
+  size_t getNumConstructors() const;
+
+  /** Is this Datatype declaration parametric? */
+  bool isParametric() const;
+
+  /**
+   * @return true if this DatatypeDecl is a null object
+   */
+  bool isNull() const;
+
+  /**
+   * @return a string representation of this datatype declaration
+   */
+  std::string toString() const;
+
+  /** @return the name of this datatype declaration. */
+  std::string getName() const;
+
+ private:
+  /**
+   * Constructor.
+   * @param slv the associated solver object
+   * @param name the name of the datatype
+   * @param isCoDatatype true if a codatatype is to be constructed
+   * @return the DatatypeDecl
+   */
+  DatatypeDecl(const Solver* slv,
+               const std::string& name,
+               bool isCoDatatype = false);
+
+  /**
+   * Constructor for parameterized datatype declaration.
+   * Create sorts parameter with Solver::mkParamSort().
+   * @param slv the associated solver object
+   * @param name the name of the datatype
+   * @param param the sort parameter
+   * @param isCoDatatype true if a codatatype is to be constructed
+   */
+  DatatypeDecl(const Solver* slv,
+               const std::string& name,
+               const Sort& param,
+               bool isCoDatatype = false);
+
+  /**
+   * Constructor for parameterized datatype declaration.
+   * Create sorts parameter with Solver::mkParamSort().
+   * @param slv the associated solver object
+   * @param name the name of the datatype
+   * @param params a list of sort parameters
+   * @param isCoDatatype true if a codatatype is to be constructed
+   */
+  DatatypeDecl(const Solver* slv,
+               const std::string& name,
+               const std::vector<Sort>& params,
+               bool isCoDatatype = false);
+
+  /** @return the internal wrapped Dtype of this datatype declaration. */
+  cvc5::DType& getDatatype(void) const;
+
+  /**
+   * Helper for isNull checks. This prevents calling an API function with
+   * CVC4_API_CHECK_NOT_NULL
+   */
+  bool isNullHelper() const;
+
+  /**
+   * The associated solver object.
+   */
+  const Solver* d_solver;
+
+  /**
+   * The internal (intermediate) datatype wrapped by this datatype
+   * declaration.
+   * Note: This is a shared_ptr rather than a unique_ptr since cvc5::DType is
+   *       not ref counted.
+   */
+  std::shared_ptr<cvc5::DType> d_dtype;
+};
+
+/**
+ * A CVC4 datatype selector.
+ */
+class CVC4_EXPORT DatatypeSelector
+{
+  friend class DatatypeConstructor;
+  friend class Solver;
+
+ public:
+  /**
+   * Constructor.
+   */
+  DatatypeSelector();
+
+  /**
+   * Destructor.
+   */
+  ~DatatypeSelector();
+
+  /** @return the name of this Datatype selector. */
+  std::string getName() const;
+
+  /**
+   * Get the selector operator of this datatype selector.
+   * @return the selector term
+   */
+  Term getSelectorTerm() const;
+
+  /** @return the range sort of this argument. */
+  Sort getRangeSort() const;
+
+  /**
+   * @return true if this DatatypeSelector is a null object
+   */
+  bool isNull() const;
+
+  /**
+   * @return a string representation of this datatype selector
+   */
+  std::string toString() const;
+
+ private:
+  /**
+   * Constructor.
+   * @param slv the associated solver object
+   * @param stor the internal datatype selector to be wrapped
+   * @return the DatatypeSelector
+   */
+  DatatypeSelector(const Solver* slv, const cvc5::DTypeSelector& stor);
+
+  /**
+   * Helper for isNull checks. This prevents calling an API function with
+   * CVC4_API_CHECK_NOT_NULL
+   */
+  bool isNullHelper() const;
+
+  /**
+   * The associated solver object.
+   */
+  const Solver* d_solver;
+
+  /**
+   * The internal datatype selector wrapped by this datatype selector.
+   * Note: This is a shared_ptr rather than a unique_ptr since cvc5::DType is
+   *       not ref counted.
+   */
+  std::shared_ptr<cvc5::DTypeSelector> d_stor;
+};
+
+/**
+ * A CVC4 datatype constructor.
+ */
+class CVC4_EXPORT DatatypeConstructor
+{
+  friend class Datatype;
+  friend class Solver;
+
+ public:
+  /**
+   * Constructor.
+   */
+  DatatypeConstructor();
+
+  /**
+   * Destructor.
+   */
+  ~DatatypeConstructor();
+
+  /** @return the name of this Datatype constructor. */
+  std::string getName() const;
+
+  /**
+   * Get the constructor operator of this datatype constructor.
+   * @return the constructor term
+   */
+  Term getConstructorTerm() const;
+
+  /**
+   * Get the constructor operator of this datatype constructor whose return
+   * type is retSort. This method is intended to be used on constructors of
+   * parametric datatypes and can be seen as returning the constructor
+   * term that has been explicitly cast to the given sort.
+   *
+   * This method is required for constructors of parametric datatypes whose
+   * return type cannot be determined by type inference. For example, given:
+   *   (declare-datatype List (par (T) ((nil) (cons (head T) (tail (List T))))))
+   * The type of nil terms need to be provided by the user. In SMT version 2.6,
+   * this is done via the syntax for qualified identifiers:
+   *   (as nil (List Int))
+   * This method is equivalent of applying the above, where this
+   * DatatypeConstructor is the one corresponding to nil, and retSort is
+   * (List Int).
+   *
+   * Furthermore note that the returned constructor term t is an operator,
+   * while Solver::mkTerm(APPLY_CONSTRUCTOR, t) is used to construct the above
+   * (nullary) application of nil.
+   *
+   * @param retSort the desired return sort of the constructor
+   * @return the constructor term
+   */
+  Term getSpecializedConstructorTerm(const Sort& retSort) const;
+
+  /**
+   * Get the tester operator of this datatype constructor.
+   * @return the tester operator
+   */
+  Term getTesterTerm() const;
+
+  /**
+   * @return the number of selectors (so far) of this Datatype constructor.
+   */
+  size_t getNumSelectors() const;
+
+  /** @return the i^th DatatypeSelector. */
+  DatatypeSelector operator[](size_t index) const;
+  /**
+   * Get the datatype selector with the given name.
+   * This is a linear search through the selectors, so in case of
+   * multiple, similarly-named selectors, the first is returned.
+   * @param name the name of the datatype selector
+   * @return the first datatype selector with the given name
+   */
+  DatatypeSelector operator[](const std::string& name) const;
+  DatatypeSelector getSelector(const std::string& name) const;
+
+  /**
+   * Get the term representation of the datatype selector with the given name.
+   * This is a linear search through the arguments, so in case of multiple,
+   * similarly-named arguments, the selector for the first is returned.
+   * @param name the name of the datatype selector
+   * @return a term representing the datatype selector with the given name
+   */
+  Term getSelectorTerm(const std::string& name) const;
+
+  /**
+   * @return true if this DatatypeConstructor is a null object
+   */
+  bool isNull() const;
+
+  /**
+   * @return a string representation of this datatype constructor
+   */
+  std::string toString() const;
+
+  /**
+   * Iterator for the selectors of a datatype constructor.
+   */
+  class const_iterator
+      : public std::iterator<std::input_iterator_tag, DatatypeConstructor>
+  {
+    friend class DatatypeConstructor;  // to access constructor
+
+   public:
+    /** Nullary constructor (required for Cython). */
+    const_iterator();
+
+    /**
+     * Assignment operator.
+     * @param it the iterator to assign to
+     * @return the reference to the iterator after assignment
+     */
+    const_iterator& operator=(const const_iterator& it);
+
+    /**
+     * Equality operator.
+     * @param it the iterator to compare to for equality
+     * @return true if the iterators are equal
+     */
+    bool operator==(const const_iterator& it) const;
+
+    /**
+     * Disequality operator.
+     * @param it the iterator to compare to for disequality
+     * @return true if the iterators are disequal
+     */
+    bool operator!=(const const_iterator& it) const;
+
+    /**
+     * Increment operator (prefix).
+     * @return a reference to the iterator after incrementing by one
+     */
+    const_iterator& operator++();
+
+    /**
+     * Increment operator (postfix).
+     * @return a reference to the iterator after incrementing by one
+     */
+    const_iterator operator++(int);
+
+    /**
+     * Dereference operator.
+     * @return a reference to the selector this iterator points to
+     */
+    const DatatypeSelector& operator*() const;
+
+    /**
+     * Dereference operator.
+     * @return a pointer to the selector this iterator points to
+     */
+    const DatatypeSelector* operator->() const;
+
+   private:
+    /**
+     * Constructor.
+     * @param slv the associated Solver object
+     * @param ctor the internal datatype constructor to iterate over
+     * @param true if this is a begin() iterator
+     */
+    const_iterator(const Solver* slv,
+                   const cvc5::DTypeConstructor& ctor,
+                   bool begin);
+
+    /**
+     * The associated solver object.
+     */
+    const Solver* d_solver;
+
+    /**
+     * A pointer to the list of selectors of the internal datatype
+     * constructor to iterate over.
+     * This pointer is maintained for operators == and != only.
+     */
+    const void* d_int_stors;
+
+    /** The list of datatype selector (wrappers) to iterate over. */
+    std::vector<DatatypeSelector> d_stors;
+
+    /** The current index of the iterator. */
+    size_t d_idx;
+  };
+
+  /**
+   * @return an iterator to the first selector of this constructor
+   */
+  const_iterator begin() const;
+
+  /**
+   * @return an iterator to one-off-the-last selector of this constructor
+   */
+  const_iterator end() const;
+
+ private:
+  /**
+   * Constructor.
+   * @param ctor the internal datatype constructor to be wrapped
+   * @return the DatatypeConstructor
+   */
+  DatatypeConstructor(const Solver* slv, const cvc5::DTypeConstructor& ctor);
+
+  /**
+   * Return selector for name.
+   * @param name The name of selector to find
+   * @return the selector object for the name
+   */
+  DatatypeSelector getSelectorForName(const std::string& name) const;
+
+  /**
+   * Helper for isNull checks. This prevents calling an API function with
+   * CVC4_API_CHECK_NOT_NULL
+   */
+  bool isNullHelper() const;
+
+  /**
+   * The associated solver object.
+   */
+  const Solver* d_solver;
+
+  /**
+   * The internal datatype constructor wrapped by this datatype constructor.
+   * Note: This is a shared_ptr rather than a unique_ptr since cvc5::DType is
+   *       not ref counted.
+   */
+  std::shared_ptr<cvc5::DTypeConstructor> d_ctor;
+};
+
+/*
+ * A CVC4 datatype.
+ */
+class CVC4_EXPORT Datatype
+{
+  friend class Solver;
+  friend class Sort;
+
+ public:
+  /** Constructor. */
+  Datatype();
+
+  /**
+   * Destructor.
+   */
+  ~Datatype();
+
+  /**
+   * Get the datatype constructor at a given index.
+   * @param idx the index of the datatype constructor to return
+   * @return the datatype constructor with the given index
+   */
+  DatatypeConstructor operator[](size_t idx) const;
+
+  /**
+   * Get the datatype constructor with the given name.
+   * This is a linear search through the constructors, so in case of multiple,
+   * similarly-named constructors, the first is returned.
+   * @param name the name of the datatype constructor
+   * @return the datatype constructor with the given name
+   */
+  DatatypeConstructor operator[](const std::string& name) const;
+  DatatypeConstructor getConstructor(const std::string& name) const;
+
+  /**
+   * Get a term representing the datatype constructor with the given name.
+   * This is a linear search through the constructors, so in case of multiple,
+   * similarly-named constructors, the
+   * first is returned.
+   */
+  Term getConstructorTerm(const std::string& name) const;
+
+  /** @return the name of this Datatype. */
+  std::string getName() const;
+
+  /** @return the number of constructors for this Datatype. */
+  size_t getNumConstructors() const;
+
+  /** @return true if this datatype is parametric */
+  bool isParametric() const;
+
+  /** @return true if this datatype corresponds to a co-datatype */
+  bool isCodatatype() const;
+
+  /** @return true if this datatype corresponds to a tuple */
+  bool isTuple() const;
+
+  /** @return true if this datatype corresponds to a record */
+  bool isRecord() const;
+
+  /** @return true if this datatype is finite */
+  bool isFinite() const;
+
+  /**
+   * Is this datatype well-founded? If this datatype is not a codatatype,
+   * this returns false if there are no values of this datatype that are of
+   * finite size.
+   *
+   * @return true if this datatype is well-founded
+   */
+  bool isWellFounded() const;
+
+  /**
+   * Does this datatype have nested recursion? This method returns false if a
+   * value of this datatype includes a subterm of its type that is nested
+   * beneath a non-datatype type constructor. For example, a datatype
+   * T containing a constructor having a selector with range type (Set T) has
+   * nested recursion.
+   *
+   * @return true if this datatype has nested recursion
+   */
+  bool hasNestedRecursion() const;
+
+  /**
+   * @return true if this Datatype is a null object
+   */
+  bool isNull() const;
+
+  /**
+   * @return a string representation of this datatype
+   */
+  std::string toString() const;
+
+  /**
+   * Iterator for the constructors of a datatype.
+   */
+  class const_iterator : public std::iterator<std::input_iterator_tag, Datatype>
+  {
+    friend class Datatype;  // to access constructor
+
+   public:
+    /** Nullary constructor (required for Cython). */
+    const_iterator();
+
+    /**
+     * Assignment operator.
+     * @param it the iterator to assign to
+     * @return the reference to the iterator after assignment
+     */
+    const_iterator& operator=(const const_iterator& it);
+
+    /**
+     * Equality operator.
+     * @param it the iterator to compare to for equality
+     * @return true if the iterators are equal
+     */
+    bool operator==(const const_iterator& it) const;
+
+    /**
+     * Disequality operator.
+     * @param it the iterator to compare to for disequality
+     * @return true if the iterators are disequal
+     */
+    bool operator!=(const const_iterator& it) const;
+
+    /**
+     * Increment operator (prefix).
+     * @return a reference to the iterator after incrementing by one
+     */
+    const_iterator& operator++();
+
+    /**
+     * Increment operator (postfix).
+     * @return a reference to the iterator after incrementing by one
+     */
+    const_iterator operator++(int);
+
+    /**
+     * Dereference operator.
+     * @return a reference to the constructor this iterator points to
+     */
+    const DatatypeConstructor& operator*() const;
+
+    /**
+     * Dereference operator.
+     * @return a pointer to the constructor this iterator points to
+     */
+    const DatatypeConstructor* operator->() const;
+
+   private:
+    /**
+     * Constructor.
+     * @param slv the associated Solver object
+     * @param dtype the internal datatype to iterate over
+     * @param true if this is a begin() iterator
+     */
+    const_iterator(const Solver* slv, const cvc5::DType& dtype, bool begin);
+
+    /**
+     * The associated solver object.
+     */
+    const Solver* d_solver;
+
+    /**
+     * A pointer to the list of constructors of the internal datatype
+     * to iterate over.
+     * This pointer is maintained for operators == and != only.
+     */
+    const void* d_int_ctors;
+
+    /** The list of datatype constructor (wrappers) to iterate over. */
+    std::vector<DatatypeConstructor> d_ctors;
+
+    /** The current index of the iterator. */
+    size_t d_idx;
+  };
+
+  /**
+   * @return an iterator to the first constructor of this datatype
+   */
+  const_iterator begin() const;
+
+  /**
+   * @return an iterator to one-off-the-last constructor of this datatype
+   */
+  const_iterator end() const;
+
+ private:
+  /**
+   * Constructor.
+   * @param dtype the internal datatype to be wrapped
+   * @return the Datatype
+   */
+  Datatype(const Solver* slv, const cvc5::DType& dtype);
+
+  /**
+   * Return constructor for name.
+   * @param name The name of constructor to find
+   * @return the constructor object for the name
+   */
+  DatatypeConstructor getConstructorForName(const std::string& name) const;
+
+  /**
+   * Helper for isNull checks. This prevents calling an API function with
+   * CVC4_API_CHECK_NOT_NULL
+   */
+  bool isNullHelper() const;
+
+  /**
+   * The associated solver object.
+   */
+  const Solver* d_solver;
+
+  /**
+   * The internal datatype wrapped by this datatype.
+   * Note: This is a shared_ptr rather than a unique_ptr since cvc5::DType is
+   *       not ref counted.
+   */
+  std::shared_ptr<cvc5::DType> d_dtype;
+};
+
+/**
+ * Serialize a datatype declaration to given stream.
+ * @param out the output stream
+ * @param dtdecl the datatype declaration to be serialized to the given stream
+ * @return the output stream
+ */
+std::ostream& operator<<(std::ostream& out,
+                         const DatatypeDecl& dtdecl) CVC4_EXPORT;
+
+/**
+ * Serialize a datatype constructor declaration to given stream.
+ * @param out the output stream
+ * @param ctordecl the datatype constructor declaration to be serialized
+ * @return the output stream
+ */
+std::ostream& operator<<(std::ostream& out,
+                         const DatatypeConstructorDecl& ctordecl) CVC4_EXPORT;
+
+/**
+ * Serialize a vector of datatype constructor declarations to given stream.
+ * @param out the output stream
+ * @param vector the vector of datatype constructor declarations to be
+ * serialized to the given stream
+ * @return the output stream
+ */
+std::ostream& operator<<(std::ostream& out,
+                         const std::vector<DatatypeConstructorDecl>& vector);
+
+/**
+ * Serialize a datatype to given stream.
+ * @param out the output stream
+ * @param dtdecl the datatype to be serialized to given stream
+ * @return the output stream
+ */
+std::ostream& operator<<(std::ostream& out, const Datatype& dtype) CVC4_EXPORT;
+
+/**
+ * Serialize a datatype constructor to given stream.
+ * @param out the output stream
+ * @param ctor the datatype constructor to be serialized to given stream
+ * @return the output stream
+ */
+std::ostream& operator<<(std::ostream& out,
+                         const DatatypeConstructor& ctor) CVC4_EXPORT;
+
+/**
+ * Serialize a datatype selector to given stream.
+ * @param out the output stream
+ * @param ctor the datatype selector to be serialized to given stream
+ * @return the output stream
+ */
+std::ostream& operator<<(std::ostream& out,
+                         const DatatypeSelector& stor) CVC4_EXPORT;
+
+/* -------------------------------------------------------------------------- */
+/* Grammar                                                                    */
+/* -------------------------------------------------------------------------- */
+
+/**
+ * A Sygus Grammar.
+ */
+class CVC4_EXPORT Grammar
+{
+  friend class cvc5::Command;
+  friend class Solver;
+
+ public:
+  /**
+   * Add <rule> to the set of rules corresponding to <ntSymbol>.
+   * @param ntSymbol the non-terminal to which the rule is added
+   * @param rule the rule to add
+   */
+  void addRule(const Term& ntSymbol, const Term& rule);
+
+  /**
+   * Add <rules> to the set of rules corresponding to <ntSymbol>.
+   * @param ntSymbol the non-terminal to which the rules are added
+   * @param rule the rules to add
+   */
+  void addRules(const Term& ntSymbol, const std::vector<Term>& rules);
+
+  /**
+   * Allow <ntSymbol> to be an arbitrary constant.
+   * @param ntSymbol the non-terminal allowed to be any constant
+   */
+  void addAnyConstant(const Term& ntSymbol);
+
+  /**
+   * Allow <ntSymbol> to be any input variable to corresponding
+   * synth-fun/synth-inv with the same sort as <ntSymbol>.
+   * @param ntSymbol the non-terminal allowed to be any input constant
+   */
+  void addAnyVariable(const Term& ntSymbol);
+
+  /**
+   * @return a string representation of this grammar.
+   */
+  std::string toString() const;
+
+  /**
+   * Nullary constructor. Needed for the Cython API.
+   */
+  Grammar();
+
+ private:
+  /**
+   * Constructor.
+   * @param slv the solver that created this grammar
+   * @param sygusVars the input variables to synth-fun/synth-var
+   * @param ntSymbols the non-terminals of this grammar
+   */
+  Grammar(const Solver* slv,
+          const std::vector<Term>& sygusVars,
+          const std::vector<Term>& ntSymbols);
+
+  /**
+   * @return the resolved datatype of the Start symbol of the grammar
+   */
+  Sort resolve();
+
+  /**
+   * Adds a constructor to sygus datatype <dt> whose sygus operator is <term>.
+   *
+   * <ntsToUnres> contains a mapping from non-terminal symbols to the
+   * unresolved sorts they correspond to. This map indicates how the argument
+   * <term> should be interpreted (instances of symbols from the domain of
+   * <ntsToUnres> correspond to constructor arguments).
+   *
+   * The sygus operator that is actually added to <dt> corresponds to replacing
+   * each occurrence of non-terminal symbols from the domain of <ntsToUnres>
+   * with bound variables via purifySygusGTerm, and binding these variables
+   * via a lambda.
+   *
+   * @param dt the non-terminal's datatype to which a constructor is added
+   * @param term the sygus operator of the constructor
+   * @param ntsToUnres mapping from non-terminals to their unresolved sorts
+   */
+  void addSygusConstructorTerm(
+      DatatypeDecl& dt,
+      const Term& term,
+      const std::unordered_map<Term, Sort, TermHashFunction>& ntsToUnres) const;
+
+  /**
+   * Purify SyGuS grammar term.
+   *
+   * This returns a term where all occurrences of non-terminal symbols (those
+   * in the domain of <ntsToUnres>) are replaced by fresh variables. For
+   * each variable replaced in this way, we add the fresh variable it is
+   * replaced with to <args>, and the unresolved sorts corresponding to the
+   * non-terminal symbol to <cargs> (constructor args). In other words, <args>
+   * contains the free variables in the term returned by this method (which
+   * should be bound by a lambda), and <cargs> contains the sorts of the
+   * arguments of the sygus constructor.
+   *
+   * @param term the term to purify
+   * @param args the free variables in the term returned by this method
+   * @param cargs the sorts of the arguments of the sygus constructor
+   * @param ntsToUnres mapping from non-terminals to their unresolved sorts
+   * @return the purfied term
+   */
+  Term purifySygusGTerm(
+      const Term& term,
+      std::vector<Term>& args,
+      std::vector<Sort>& cargs,
+      const std::unordered_map<Term, Sort, TermHashFunction>& ntsToUnres) const;
+
+  /**
+   * This adds constructors to <dt> for sygus variables in <d_sygusVars> whose
+   * sort is argument <sort>. This method should be called when the sygus
+   * grammar term (Variable sort) is encountered.
+   *
+   * @param dt the non-terminal's datatype to which the constructors are added
+   * @param sort the sort of the sygus variables to add
+   */
+  void addSygusConstructorVariables(DatatypeDecl& dt, const Sort& sort) const;
+
+  /**
+   * Check if <rule> contains variables that are neither parameters of
+   * the corresponding synthFun/synthInv nor non-terminals.
+   * @param rule the non-terminal allowed to be any constant
+   * @return <true> if <rule> contains free variables and <false> otherwise
+   */
+  bool containsFreeVariables(const Term& rule) const;
+
+  /** The solver that created this grammar. */
+  const Solver* d_solver;
+  /** Input variables to the corresponding function/invariant to synthesize.*/
+  std::vector<Term> d_sygusVars;
+  /** The non-terminal symbols of this grammar. */
+  std::vector<Term> d_ntSyms;
+  /** The mapping from non-terminal symbols to their production terms. */
+  std::unordered_map<Term, std::vector<Term>, TermHashFunction> d_ntsToTerms;
+  /** The set of non-terminals that can be arbitrary constants. */
+  std::unordered_set<Term, TermHashFunction> d_allowConst;
+  /** The set of non-terminals that can be sygus variables. */
+  std::unordered_set<Term, TermHashFunction> d_allowVars;
+  /** Did we call resolve() before? */
+  bool d_isResolved;
+};
+
+/**
+ * Serialize a grammar to given stream.
+ * @param out the output stream
+ * @param g the grammar to be serialized to the given output stream
+ * @return the output stream
+ */
+std::ostream& operator<<(std::ostream& out, const Grammar& g) CVC4_EXPORT;
+
+/* -------------------------------------------------------------------------- */
+/* Rounding Mode for Floating Points                                          */
+/* -------------------------------------------------------------------------- */
+
+/**
+ * A CVC4 floating point rounding mode.
+ */
+enum CVC4_EXPORT RoundingMode
+{
+  ROUND_NEAREST_TIES_TO_EVEN,
+  ROUND_TOWARD_POSITIVE,
+  ROUND_TOWARD_NEGATIVE,
+  ROUND_TOWARD_ZERO,
+  ROUND_NEAREST_TIES_TO_AWAY,
+};
+
+/**
+ * Hash function for RoundingModes.
+ */
+struct CVC4_EXPORT RoundingModeHashFunction
+{
+  inline size_t operator()(const RoundingMode& rm) const;
+};
+
+/* -------------------------------------------------------------------------- */
+/* Solver                                                                     */
+/* -------------------------------------------------------------------------- */
+
+/*
+ * A CVC4 solver.
+ */
+class CVC4_EXPORT Solver
+{
+  friend class Datatype;
+  friend class DatatypeDecl;
+  friend class DatatypeConstructor;
+  friend class DatatypeConstructorDecl;
+  friend class DatatypeSelector;
+  friend class Grammar;
+  friend class Op;
+  friend class cvc5::Command;
+  friend class Sort;
+  friend class Term;
+
+ public:
+  /* .................................................................... */
+  /* Constructors/Destructors                                             */
+  /* .................................................................... */
+
+  /**
+   * Constructor.
+   * @param opts an optional pointer to a solver options object
+   * @return the Solver
+   */
+  Solver(Options* opts = nullptr);
+
+  /**
+   * Destructor.
+   */
+  ~Solver();
+
+  /**
+   * Disallow copy/assignment.
+   */
+  Solver(const Solver&) = delete;
+  Solver& operator=(const Solver&) = delete;
+
+  /* .................................................................... */
+  /* Solver Configuration                                                 */
+  /* .................................................................... */
+
+  bool supportsFloatingPoint() const;
+
+  /* .................................................................... */
+  /* Sorts Handling                                                       */
+  /* .................................................................... */
+
+  /**
+   * @return sort null
+   */
+  Sort getNullSort() const;
+
+  /**
+   * @return sort Boolean
+   */
+  Sort getBooleanSort() const;
+
+  /**
+   * @return sort Integer (in CVC4, Integer is a subtype of Real)
+   */
+  Sort getIntegerSort() const;
+
+  /**
+   * @return sort Real
+   */
+  Sort getRealSort() const;
+
+  /**
+   * @return sort RegExp
+   */
+  Sort getRegExpSort() const;
+
+  /**
+   * @return sort RoundingMode
+   */
+  Sort getRoundingModeSort() const;
+
+  /**
+   * @return sort String
+   */
+  Sort getStringSort() const;
+
+  /**
+   * Create an array sort.
+   * @param indexSort the array index sort
+   * @param elemSort the array element sort
+   * @return the array sort
+   */
+  Sort mkArraySort(const Sort& indexSort, const Sort& elemSort) const;
+
+  /**
+   * Create a bit-vector sort.
+   * @param size the bit-width of the bit-vector sort
+   * @return the bit-vector sort
+   */
+  Sort mkBitVectorSort(uint32_t size) const;
+
+  /**
+   * Create a floating-point sort.
+   * @param exp the bit-width of the exponent of the floating-point sort.
+   * @param sig the bit-width of the significand of the floating-point sort.
+   */
+  Sort mkFloatingPointSort(uint32_t exp, uint32_t sig) const;
+
+  /**
+   * Create a datatype sort.
+   * @param dtypedecl the datatype declaration from which the sort is created
+   * @return the datatype sort
+   */
+  Sort mkDatatypeSort(const DatatypeDecl& dtypedecl) const;
+
+  /**
+   * Create a vector of datatype sorts. The names of the datatype declarations
+   * must be distinct.
+   *
+   * @param dtypedecls the datatype declarations from which the sort is created
+   * @return the datatype sorts
+   */
+  std::vector<Sort> mkDatatypeSorts(
+      const std::vector<DatatypeDecl>& dtypedecls) const;
+
+  /**
+   * Create a vector of datatype sorts using unresolved sorts. The names of
+   * the datatype declarations in dtypedecls must be distinct.
+   *
+   * This method is called when the DatatypeDecl objects dtypedecls have been
+   * built using "unresolved" sorts.
+   *
+   * We associate each sort in unresolvedSorts with exacly one datatype from
+   * dtypedecls. In particular, it must have the same name as exactly one
+   * datatype declaration in dtypedecls.
+   *
+   * When constructing datatypes, unresolved sorts are replaced by the datatype
+   * sort constructed for the datatype declaration it is associated with.
+   *
+   * @param dtypedecls the datatype declarations from which the sort is created
+   * @param unresolvedSorts the list of unresolved sorts
+   * @return the datatype sorts
+   */
+  std::vector<Sort> mkDatatypeSorts(
+      const std::vector<DatatypeDecl>& dtypedecls,
+      const std::set<Sort>& unresolvedSorts) const;
+
+  /**
+   * Create function sort.
+   * @param domain the sort of the fuction argument
+   * @param codomain the sort of the function return value
+   * @return the function sort
+   */
+  Sort mkFunctionSort(const Sort& domain, const Sort& codomain) const;
+
+  /**
+   * Create function sort.
+   * @param sorts the sort of the function arguments
+   * @param codomain the sort of the function return value
+   * @return the function sort
+   */
+  Sort mkFunctionSort(const std::vector<Sort>& sorts,
+                      const Sort& codomain) const;
+
+  /**
+   * Create a sort parameter.
+   * @param symbol the name of the sort
+   * @return the sort parameter
+   */
+  Sort mkParamSort(const std::string& symbol) const;
+
+  /**
+   * Create a predicate sort.
+   * @param sorts the list of sorts of the predicate
+   * @return the predicate sort
+   */
+  Sort mkPredicateSort(const std::vector<Sort>& sorts) const;
+
+  /**
+   * Create a record sort
+   * @param fields the list of fields of the record
+   * @return the record sort
+   */
+  Sort mkRecordSort(
+      const std::vector<std::pair<std::string, Sort>>& fields) const;
+
+  /**
+   * Create a set sort.
+   * @param elemSort the sort of the set elements
+   * @return the set sort
+   */
+  Sort mkSetSort(const Sort& elemSort) const;
+
+  /**
+   * Create a bag sort.
+   * @param elemSort the sort of the bag elements
+   * @return the bag sort
+   */
+  Sort mkBagSort(const Sort& elemSort) const;
+
+  /**
+   * Create a sequence sort.
+   * @param elemSort the sort of the sequence elements
+   * @return the sequence sort
+   */
+  Sort mkSequenceSort(const Sort& elemSort) const;
+
+  /**
+   * Create an uninterpreted sort.
+   * @param symbol the name of the sort
+   * @return the uninterpreted sort
+   */
+  Sort mkUninterpretedSort(const std::string& symbol) const;
+
+  /**
+   * Create a sort constructor sort.
+   * @param symbol the symbol of the sort
+   * @param arity the arity of the sort
+   * @return the sort constructor sort
+   */
+  Sort mkSortConstructorSort(const std::string& symbol, size_t arity) const;
+
+  /**
+   * Create a tuple sort.
+   * @param sorts of the elements of the tuple
+   * @return the tuple sort
+   */
+  Sort mkTupleSort(const std::vector<Sort>& sorts) const;
+
+  /* .................................................................... */
+  /* Create Terms                                                         */
+  /* .................................................................... */
+
+  /**
+   * Create 0-ary term of given kind.
+   * @param kind the kind of the term
+   * @return the Term
+   */
+  Term mkTerm(Kind kind) const;
+
+  /**
+   * Create a unary term of given kind.
+   * @param kind the kind of the term
+   * @param child the child of the term
+   * @return the Term
+   */
+  Term mkTerm(Kind kind, const Term& child) const;
+
+  /**
+   * Create binary term of given kind.
+   * @param kind the kind of the term
+   * @param child1 the first child of the term
+   * @param child2 the second child of the term
+   * @return the Term
+   */
+  Term mkTerm(Kind kind, const Term& child1, const Term& child2) const;
+
+  /**
+   * Create ternary term of given kind.
+   * @param kind the kind of the term
+   * @param child1 the first child of the term
+   * @param child2 the second child of the term
+   * @param child3 the third child of the term
+   * @return the Term
+   */
+  Term mkTerm(Kind kind,
+              const Term& child1,
+              const Term& child2,
+              const Term& child3) const;
+
+  /**
+   * Create n-ary term of given kind.
+   * @param kind the kind of the term
+   * @param children the children of the term
+   * @return the Term
+   */
+  Term mkTerm(Kind kind, const std::vector<Term>& children) const;
+
+  /**
+   * Create nullary term of given kind from a given operator.
+   * Create operators with mkOp().
+   * @param the operator
+   * @return the Term
+   */
+  Term mkTerm(const Op& op) const;
+
+  /**
+   * Create unary term of given kind from a given operator.
+   * Create operators with mkOp().
+   * @param the operator
+   * @child the child of the term
+   * @return the Term
+   */
+  Term mkTerm(const Op& op, const Term& child) const;
+
+  /**
+   * Create binary term of given kind from a given operator.
+   * Create operators with mkOp().
+   * @param the operator
+   * @child1 the first child of the term
+   * @child2 the second child of the term
+   * @return the Term
+   */
+  Term mkTerm(const Op& op, const Term& child1, const Term& child2) const;
+
+  /**
+   * Create ternary term of given kind from a given operator.
+   * Create operators with mkOp().
+   * @param the operator
+   * @child1 the first child of the term
+   * @child2 the second child of the term
+   * @child3 the third child of the term
+   * @return the Term
+   */
+  Term mkTerm(const Op& op,
+              const Term& child1,
+              const Term& child2,
+              const Term& child3) const;
+
+  /**
+   * Create n-ary term of given kind from a given operator.
+   * Create operators with mkOp().
+   * @param op the operator
+   * @children the children of the term
+   * @return the Term
+   */
+  Term mkTerm(const Op& op, const std::vector<Term>& children) const;
+
+  /**
+   * Create a tuple term. Terms are automatically converted if sorts are
+   * compatible.
+   * @param sorts The sorts of the elements in the tuple
+   * @param terms The elements in the tuple
+   * @return the tuple Term
+   */
+  Term mkTuple(const std::vector<Sort>& sorts,
+               const std::vector<Term>& terms) const;
+
+  /* .................................................................... */
+  /* Create Operators                                                     */
+  /* .................................................................... */
+
+  /**
+   * Create an operator for a builtin Kind
+   * The Kind may not be the Kind for an indexed operator
+   *   (e.g. BITVECTOR_EXTRACT)
+   * Note: in this case, the Op simply wraps the Kind.
+   * The Kind can be used in mkTerm directly without
+   *   creating an op first.
+   * @param kind the kind to wrap
+   */
+  Op mkOp(Kind kind) const;
+
+  /**
+   * Create operator of kind:
+   *   - RECORD_UPDATE
+   *   - DIVISIBLE (to support arbitrary precision integers)
+   * See enum Kind for a description of the parameters.
+   * @param kind the kind of the operator
+   * @param arg the string argument to this operator
+   */
+  Op mkOp(Kind kind, const std::string& arg) const;
+
+  /**
+   * Create operator of kind:
+   *   - DIVISIBLE
+   *   - BITVECTOR_REPEAT
+   *   - BITVECTOR_ZERO_EXTEND
+   *   - BITVECTOR_SIGN_EXTEND
+   *   - BITVECTOR_ROTATE_LEFT
+   *   - BITVECTOR_ROTATE_RIGHT
+   *   - INT_TO_BITVECTOR
+   *   - FLOATINGPOINT_TO_UBV
+   *   - FLOATINGPOINT_TO_UBV_TOTAL
+   *   - FLOATINGPOINT_TO_SBV
+   *   - FLOATINGPOINT_TO_SBV_TOTAL
+   *   - TUPLE_UPDATE
+   * See enum Kind for a description of the parameters.
+   * @param kind the kind of the operator
+   * @param arg the uint32_t argument to this operator
+   */
+  Op mkOp(Kind kind, uint32_t arg) const;
+
+  /**
+   * Create operator of Kind:
+   *   - BITVECTOR_EXTRACT
+   *   - FLOATINGPOINT_TO_FP_IEEE_BITVECTOR
+   *   - FLOATINGPOINT_TO_FP_FLOATINGPOINT
+   *   - FLOATINGPOINT_TO_FP_REAL
+   *   - FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR
+   *   - FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR
+   *   - FLOATINGPOINT_TO_FP_GENERIC
+   * See enum Kind for a description of the parameters.
+   * @param kind the kind of the operator
+   * @param arg1 the first uint32_t argument to this operator
+   * @param arg2 the second uint32_t argument to this operator
+   */
+  Op mkOp(Kind kind, uint32_t arg1, uint32_t arg2) const;
+
+  /**
+   * Create operator of Kind:
+   *   - TUPLE_PROJECT
+   * See enum Kind for a description of the parameters.
+   * @param kind the kind of the operator
+   */
+  Op mkOp(Kind kind, const std::vector<uint32_t>& args) const;
+
+  /* .................................................................... */
+  /* Create Constants                                                     */
+  /* .................................................................... */
+
+  /**
+   * Create a Boolean true constant.
+   * @return the true constant
+   */
+  Term mkTrue() const;
+
+  /**
+   * Create a Boolean false constant.
+   * @return the false constant
+   */
+  Term mkFalse() const;
+
+  /**
+   * Create a Boolean constant.
+   * @return the Boolean constant
+   * @param val the value of the constant
+   */
+  Term mkBoolean(bool val) const;
+
+  /**
+   * Create a constant representing the number Pi.
+   * @return a constant representing Pi
+   */
+  Term mkPi() const;
+  /**
+   * Create an integer constant from a string.
+   * @param s the string representation of the constant, may represent an
+   *          integer (e.g., "123").
+   * @return a constant of sort Integer assuming 's' represents an integer)
+   */
+  Term mkInteger(const std::string& s) const;
+
+  /**
+   * Create an integer constant from a c++ int.
+   * @param val the value of the constant
+   * @return a constant of sort Integer
+   */
+  Term mkInteger(int64_t val) const;
+
+  /**
+   * Create a real constant from a string.
+   * @param s the string representation of the constant, may represent an
+   *          integer (e.g., "123") or real constant (e.g., "12.34" or "12/34").
+   * @return a constant of sort Real
+   */
+  Term mkReal(const std::string& s) const;
+
+  /**
+   * Create a real constant from an integer.
+   * @param val the value of the constant
+   * @return a constant of sort Integer
+   */
+  Term mkReal(int64_t val) const;
+
+  /**
+   * Create a real constant from a rational.
+   * @param num the value of the numerator
+   * @param den the value of the denominator
+   * @return a constant of sort Real
+   */
+  Term mkReal(int64_t num, int64_t den) const;
+
+  /**
+   * Create a regular expression empty term.
+   * @return the empty term
+   */
+  Term mkRegexpEmpty() const;
+
+  /**
+   * Create a regular expression sigma term.
+   * @return the sigma term
+   */
+  Term mkRegexpSigma() const;
+
+  /**
+   * Create a constant representing an empty set of the given sort.
+   * @param sort the sort of the set elements.
+   * @return the empty set constant
+   */
+  Term mkEmptySet(const Sort& sort) const;
+
+  /**
+   * Create a constant representing an empty bag of the given sort.
+   * @param sort the sort of the bag elements.
+   * @return the empty bag constant
+   */
+  Term mkEmptyBag(const Sort& sort) const;
+
+  /**
+   * Create a separation logic nil term.
+   * @param sort the sort of the nil term
+   * @return the separation logic nil term
+   */
+  Term mkSepNil(const Sort& sort) const;
+
+  /**
+   * Create a String constant.
+   * @param s the string this constant represents
+   * @param useEscSequences determines whether escape sequences in \p s should
+   * be converted to the corresponding character
+   * @return the String constant
+   */
+  Term mkString(const std::string& s, bool useEscSequences = false) const;
+
+  /**
+   * Create a String constant.
+   * @param c the character this constant represents
+   * @return the String constant
+   */
+  Term mkString(const unsigned char c) const;
+
+  /**
+   * Create a String constant.
+   * @param s a list of unsigned (unicode) values this constant represents as
+   * string
+   * @return the String constant
+   */
+  Term mkString(const std::vector<uint32_t>& s) const;
+
+  /**
+   * Create a character constant from a given string.
+   * @param s the string denoting the code point of the character (in base 16)
+   * @return the character constant
+   */
+  Term mkChar(const std::string& s) const;
+
+  /**
+   * Create an empty sequence of the given element sort.
+   * @param sort The element sort of the sequence.
+   * @return the empty sequence with given element sort.
+   */
+  Term mkEmptySequence(const Sort& sort) const;
+
+  /**
+   * Create a universe set of the given sort.
+   * @param sort the sort of the set elements
+   * @return the universe set constant
+   */
+  Term mkUniverseSet(const Sort& sort) const;
+
+  /**
+   * Create a bit-vector constant of given size and value.
+   * @param size the bit-width of the bit-vector sort
+   * @param val the value of the constant
+   * @return the bit-vector constant
+   */
+  Term mkBitVector(uint32_t size, uint64_t val = 0) const;
+
+  /**
+   * Create a bit-vector constant from a given string of base 2, 10 or 16.
+   *
+   * The size of resulting bit-vector is
+   * - base  2: the size of the binary string
+   * - base 10: the min. size required to represent the decimal as a bit-vector
+   * - base 16: the max. size required to represent the hexadecimal as a
+   *            bit-vector (4 * size of the given value string)
+   *
+   * @param s the string representation of the constant
+   * @param base the base of the string representation (2, 10, or 16)
+   * @return the bit-vector constant
+   */
+  Term mkBitVector(const std::string& s, uint32_t base = 2) const;
+
+  /**
+   * Create a bit-vector constant of a given bit-width from a given string of
+   * base 2, 10 or 16.
+   * @param size the bit-width of the constant
+   * @param s the string representation of the constant
+   * @param base the base of the string representation (2, 10, or 16)
+   * @return the bit-vector constant
+   */
+  Term mkBitVector(uint32_t size, const std::string& s, uint32_t base) const;
+
+  /**
+   * Create a constant array with the provided constant value stored at every
+   * index
+   * @param sort the sort of the constant array (must be an array sort)
+   * @param val the constant value to store (must match the sort's element sort)
+   * @return the constant array term
+   */
+  Term mkConstArray(const Sort& sort, const Term& val) const;
+
+  /**
+   * Create a positive infinity floating-point constant. Requires CVC4 to be
+   * compiled with SymFPU support.
+   * @param exp Number of bits in the exponent
+   * @param sig Number of bits in the significand
+   * @return the floating-point constant
+   */
+  Term mkPosInf(uint32_t exp, uint32_t sig) const;
+
+  /**
+   * Create a negative infinity floating-point constant. Requires CVC4 to be
+   * compiled with SymFPU support.
+   * @param exp Number of bits in the exponent
+   * @param sig Number of bits in the significand
+   * @return the floating-point constant
+   */
+  Term mkNegInf(uint32_t exp, uint32_t sig) const;
+
+  /**
+   * Create a not-a-number (NaN) floating-point constant. Requires CVC4 to be
+   * compiled with SymFPU support.
+   * @param exp Number of bits in the exponent
+   * @param sig Number of bits in the significand
+   * @return the floating-point constant
+   */
+  Term mkNaN(uint32_t exp, uint32_t sig) const;
+
+  /**
+   * Create a positive zero (+0.0) floating-point constant. Requires CVC4 to be
+   * compiled with SymFPU support.
+   * @param exp Number of bits in the exponent
+   * @param sig Number of bits in the significand
+   * @return the floating-point constant
+   */
+  Term mkPosZero(uint32_t exp, uint32_t sig) const;
+
+  /**
+   * Create a negative zero (-0.0) floating-point constant. Requires CVC4 to be
+   * compiled with SymFPU support.
+   * @param exp Number of bits in the exponent
+   * @param sig Number of bits in the significand
+   * @return the floating-point constant
+   */
+  Term mkNegZero(uint32_t exp, uint32_t sig) const;
+
+  /**
+   * Create a roundingmode constant.
+   * @param rm the floating point rounding mode this constant represents
+   */
+  Term mkRoundingMode(RoundingMode rm) const;
+
+  /**
+   * Create uninterpreted constant.
+   * @param arg1 Sort of the constant
+   * @param arg2 Index of the constant
+   */
+  Term mkUninterpretedConst(const Sort& sort, int32_t index) const;
+
+  /**
+   * Create an abstract value constant.
+   * @param index Index of the abstract value
+   */
+  Term mkAbstractValue(const std::string& index) const;
+
+  /**
+   * Create an abstract value constant.
+   * @param index Index of the abstract value
+   */
+  Term mkAbstractValue(uint64_t index) const;
+
+  /**
+   * Create a floating-point constant (requires CVC4 to be compiled with symFPU
+   * support).
+   * @param exp Size of the exponent
+   * @param sig Size of the significand
+   * @param val Value of the floating-point constant as a bit-vector term
+   */
+  Term mkFloatingPoint(uint32_t exp, uint32_t sig, Term val) const;
+
+  /* .................................................................... */
+  /* Create Variables                                                     */
+  /* .................................................................... */
+
+  /**
+   * Create (first-order) constant (0-arity function symbol).
+   * SMT-LIB: ( declare-const <symbol> <sort> )
+   * SMT-LIB: ( declare-fun <symbol> ( ) <sort> )
+   *
+   * @param sort the sort of the constant
+   * @param symbol the name of the constant
+   * @return the first-order constant
+   */
+  Term mkConst(const Sort& sort, const std::string& symbol) const;
+  /**
+   * Create (first-order) constant (0-arity function symbol), with a default
+   * symbol name.
+   *
+   * @param sort the sort of the constant
+   * @return the first-order constant
+   */
+  Term mkConst(const Sort& sort) const;
+
+  /**
+   * Create a bound variable to be used in a binder (i.e. a quantifier, a
+   * lambda, or a witness binder).
+   * @param sort the sort of the variable
+   * @param symbol the name of the variable
+   * @return the variable
+   */
+  Term mkVar(const Sort& sort, const std::string& symbol = std::string()) const;
+
+  /* .................................................................... */
+  /* Create datatype constructor declarations                             */
+  /* .................................................................... */
+
+  DatatypeConstructorDecl mkDatatypeConstructorDecl(const std::string& name);
+
+  /* .................................................................... */
+  /* Create datatype declarations                                         */
+  /* .................................................................... */
+
+  /**
+   * Create a datatype declaration.
+   * @param name the name of the datatype
+   * @param isCoDatatype true if a codatatype is to be constructed
+   * @return the DatatypeDecl
+   */
+  DatatypeDecl mkDatatypeDecl(const std::string& name,
+                              bool isCoDatatype = false);
+
+  /**
+   * Create a datatype declaration.
+   * Create sorts parameter with Solver::mkParamSort().
+   * @param name the name of the datatype
+   * @param param the sort parameter
+   * @param isCoDatatype true if a codatatype is to be constructed
+   * @return the DatatypeDecl
+   */
+  DatatypeDecl mkDatatypeDecl(const std::string& name,
+                              Sort param,
+                              bool isCoDatatype = false);
+
+  /**
+   * Create a datatype declaration.
+   * Create sorts parameter with Solver::mkParamSort().
+   * @param name the name of the datatype
+   * @param params a list of sort parameters
+   * @param isCoDatatype true if a codatatype is to be constructed
+   * @return the DatatypeDecl
+   */
+  DatatypeDecl mkDatatypeDecl(const std::string& name,
+                              const std::vector<Sort>& params,
+                              bool isCoDatatype = false);
+
+  /* .................................................................... */
+  /* Formula Handling                                                     */
+  /* .................................................................... */
+
+  /**
+   * Simplify a formula without doing "much" work.  Does not involve
+   * the SAT Engine in the simplification, but uses the current
+   * definitions, assertions, and the current partial model, if one
+   * has been constructed.  It also involves theory normalization.
+   * @param t the formula to simplify
+   * @return the simplified formula
+   */
+  Term simplify(const Term& t);
+
+  /**
+   * Assert a formula.
+   * SMT-LIB: ( assert <term> )
+   * @param term the formula to assert
+   */
+  void assertFormula(const Term& term) const;
+
+  /**
+   * Check satisfiability.
+   * SMT-LIB: ( check-sat )
+   * @return the result of the satisfiability check.
+   */
+  Result checkSat() const;
+
+  /**
+   * Check satisfiability assuming the given formula.
+   * SMT-LIB: ( check-sat-assuming ( <prop_literal> ) )
+   * @param assumption the formula to assume
+   * @return the result of the satisfiability check.
+   */
+  Result checkSatAssuming(const Term& assumption) const;
+
+  /**
+   * Check satisfiability assuming the given formulas.
+   * SMT-LIB: ( check-sat-assuming ( <prop_literal>+ ) )
+   * @param assumptions the formulas to assume
+   * @return the result of the satisfiability check.
+   */
+  Result checkSatAssuming(const std::vector<Term>& assumptions) const;
+
+  /**
+   * Check entailment of the given formula w.r.t. the current set of assertions.
+   * @param term the formula to check entailment for
+   * @return the result of the entailment check.
+   */
+  Result checkEntailed(const Term& term) const;
+
+  /**
+   * Check entailment of the given set of given formulas w.r.t. the current
+   * set of assertions.
+   * @param terms the terms to check entailment for
+   * @return the result of the entailmentcheck.
+   */
+  Result checkEntailed(const std::vector<Term>& terms) const;
+
+  /**
+   * Create datatype sort.
+   * SMT-LIB: ( declare-datatype <symbol> <datatype_decl> )
+   * @param symbol the name of the datatype sort
+   * @param ctors the constructor declarations of the datatype sort
+   * @return the datatype sort
+   */
+  Sort declareDatatype(const std::string& symbol,
+                       const std::vector<DatatypeConstructorDecl>& ctors) const;
+
+  /**
+   * Declare n-ary function symbol.
+   * SMT-LIB: ( declare-fun <symbol> ( <sort>* ) <sort> )
+   * @param symbol the name of the function
+   * @param sorts the sorts of the parameters to this function
+   * @param sort the sort of the return value of this function
+   * @return the function
+   */
+  Term declareFun(const std::string& symbol,
+                  const std::vector<Sort>& sorts,
+                  const Sort& sort) const;
+
+  /**
+   * Declare uninterpreted sort.
+   * SMT-LIB: ( declare-sort <symbol> <numeral> )
+   * @param symbol the name of the sort
+   * @param arity the arity of the sort
+   * @return the sort
+   */
+  Sort declareSort(const std::string& symbol, uint32_t arity) const;
+
+  /**
+   * Define n-ary function.
+   * SMT-LIB: ( define-fun <function_def> )
+   * @param symbol the name of the function
+   * @param bound_vars the parameters to this function
+   * @param sort the sort of the return value of this function
+   * @param term the function body
+   * @param global determines whether this definition is global (i.e. persists
+   *               when popping the context)
+   * @return the function
+   */
+  Term defineFun(const std::string& symbol,
+                 const std::vector<Term>& bound_vars,
+                 const Sort& sort,
+                 const Term& term,
+                 bool global = false) const;
+  /**
+   * Define n-ary function.
+   * SMT-LIB: ( define-fun <function_def> )
+   * Create parameter 'fun' with mkConst().
+   * @param fun the sorted function
+   * @param bound_vars the parameters to this function
+   * @param term the function body
+   * @param global determines whether this definition is global (i.e. persists
+   *               when popping the context)
+   * @return the function
+   */
+  Term defineFun(const Term& fun,
+                 const std::vector<Term>& bound_vars,
+                 const Term& term,
+                 bool global = false) const;
+
+  /**
+   * Define recursive function.
+   * SMT-LIB: ( define-fun-rec <function_def> )
+   * @param symbol the name of the function
+   * @param bound_vars the parameters to this function
+   * @param sort the sort of the return value of this function
+   * @param term the function body
+   * @param global determines whether this definition is global (i.e. persists
+   *               when popping the context)
+   * @return the function
+   */
+  Term defineFunRec(const std::string& symbol,
+                    const std::vector<Term>& bound_vars,
+                    const Sort& sort,
+                    const Term& term,
+                    bool global = false) const;
+
+  /**
+   * Define recursive function.
+   * SMT-LIB: ( define-fun-rec <function_def> )
+   * Create parameter 'fun' with mkConst().
+   * @param fun the sorted function
+   * @param bound_vars the parameters to this function
+   * @param term the function body
+   * @param global determines whether this definition is global (i.e. persists
+   *               when popping the context)
+   * @return the function
+   */
+  Term defineFunRec(const Term& fun,
+                    const std::vector<Term>& bound_vars,
+                    const Term& term,
+                    bool global = false) const;
+
+  /**
+   * Define recursive functions.
+   * SMT-LIB: ( define-funs-rec ( <function_decl>^{n+1} ) ( <term>^{n+1} ) )
+   * Create elements of parameter 'funs' with mkConst().
+   * @param funs the sorted functions
+   * @param bound_vars the list of parameters to the functions
+   * @param term the list of function bodies of the functions
+   * @param global determines whether this definition is global (i.e. persists
+   *               when popping the context)
+   * @return the function
+   */
+  void defineFunsRec(const std::vector<Term>& funs,
+                     const std::vector<std::vector<Term>>& bound_vars,
+                     const std::vector<Term>& terms,
+                     bool global = false) const;
+
+  /**
+   * Echo a given string to the given output stream.
+   * SMT-LIB: ( echo <std::string> )
+   * @param out the output stream
+   * @param str the string to echo
+   */
+  void echo(std::ostream& out, const std::string& str) const;
+
+  /**
+   * Get the list of asserted formulas.
+   * SMT-LIB: ( get-assertions )
+   * @return the list of asserted formulas
+   */
+  std::vector<Term> getAssertions() const;
+
+  /**
+   * Get info from the solver.
+   * SMT-LIB: ( get-info <info_flag> )
+   * @return the info
+   */
+  std::string getInfo(const std::string& flag) const;
+
+  /**
+   * Get the value of a given option.
+   * SMT-LIB: ( get-option <keyword> )
+   * @param option the option for which the value is queried
+   * @return a string representation of the option value
+   */
+  std::string getOption(const std::string& option) const;
+
+  /**
+   * Get the set of unsat ("failed") assumptions.
+   * SMT-LIB: ( get-unsat-assumptions )
+   * Requires to enable option 'produce-unsat-assumptions'.
+   * @return the set of unsat assumptions.
+   */
+  std::vector<Term> getUnsatAssumptions() const;
+
+  /**
+   * Get the unsatisfiable core.
+   * SMT-LIB: ( get-unsat-core )
+   * Requires to enable option 'produce-unsat-cores'.
+   * @return a set of terms representing the unsatisfiable core
+   */
+  std::vector<Term> getUnsatCore() const;
+
+  /**
+   * Get the value of the given term.
+   * SMT-LIB: ( get-value ( <term> ) )
+   * @param term the term for which the value is queried
+   * @return the value of the given term
+   */
+  Term getValue(const Term& term) const;
+  /**
+   * Get the values of the given terms.
+   * SMT-LIB: ( get-value ( <term>+ ) )
+   * @param terms the terms for which the value is queried
+   * @return the values of the given terms
+   */
+  std::vector<Term> getValue(const std::vector<Term>& terms) const;
+
+  /**
+   * Do quantifier elimination.
+   * SMT-LIB: ( get-qe <q> )
+   * Requires a logic that supports quantifier elimination. Currently, the only
+   * logics supported by quantifier elimination is LRA and LIA.
+   * @param q a quantified formula of the form:
+   *   Q x1...xn. P( x1...xn, y1...yn )
+   * where P( x1...xn, y1...yn ) is a quantifier-free formula
+   * @return a formula ret such that, given the current set of formulas A
+   * asserted to this solver:
+   *   - ( A ^ q ) and ( A ^ ret ) are equivalent
+   *   - ret is quantifier-free formula containing only free variables in
+   *     y1...yn.
+   */
+  Term getQuantifierElimination(const Term& q) const;
+
+  /**
+   * Do partial quantifier elimination, which can be used for incrementally
+   * computing the result of a quantifier elimination.
+   * SMT-LIB: ( get-qe-disjunct <q> )
+   * Requires a logic that supports quantifier elimination. Currently, the only
+   * logics supported by quantifier elimination is LRA and LIA.
+   * @param q a quantified formula of the form:
+   *   Q x1...xn. P( x1...xn, y1...yn )
+   * where P( x1...xn, y1...yn ) is a quantifier-free formula
+   * @return a formula ret such that, given the current set of formulas A
+   * asserted to this solver:
+   *   - (A ^ q) => (A ^ ret) if Q is forall or (A ^ ret) => (A ^ q) if Q is
+   *     exists,
+   *   - ret is quantifier-free formula containing only free variables in
+   *     y1...yn,
+   *   - If Q is exists, let A^Q_n be the formula
+   *       A ^ ~ret^Q_1 ^ ... ^ ~ret^Q_n
+   *     where for each i=1,...n, formula ret^Q_i is the result of calling
+   *     getQuantifierEliminationDisjunct for q with the set of assertions
+   *     A^Q_{i-1}. Similarly, if Q is forall, then let A^Q_n be
+   *       A ^ ret^Q_1 ^ ... ^ ret^Q_n
+   *     where ret^Q_i is the same as above. In either case, we have
+   *     that ret^Q_j will eventually be true or false, for some finite j.
+   */
+  Term getQuantifierEliminationDisjunct(const Term& q) const;
+
+  /**
+   * When using separation logic, this sets the location sort and the
+   * datatype sort to the given ones. This method should be invoked exactly
+   * once, before any separation logic constraints are provided.
+   * @param locSort The location sort of the heap
+   * @param dataSort The data sort of the heap
+   */
+  void declareSeparationHeap(const Sort& locSort, const Sort& dataSort) const;
+
+  /**
+   * When using separation logic, obtain the term for the heap.
+   * @return The term for the heap
+   */
+  Term getSeparationHeap() const;
+
+  /**
+   * When using separation logic, obtain the term for nil.
+   * @return The term for nil
+   */
+  Term getSeparationNilTerm() const;
+
+  /**
+   * Pop (a) level(s) from the assertion stack.
+   * SMT-LIB: ( pop <numeral> )
+   * @param nscopes the number of levels to pop
+   */
+  void pop(uint32_t nscopes = 1) const;
+
+  /**
+   * Get an interpolant
+   * SMT-LIB: ( get-interpol <conj> )
+   * Requires to enable option 'produce-interpols'.
+   * @param conj the conjecture term
+   * @param output a Term I such that A->I and I->B are valid, where A is the
+   *        current set of assertions and B is given in the input by conj.
+   * @return true if it gets I successfully, false otherwise.
+   */
+  bool getInterpolant(const Term& conj, Term& output) const;
+
+  /**
+   * Get an interpolant
+   * SMT-LIB: ( get-interpol <conj> <g> )
+   * Requires to enable option 'produce-interpols'.
+   * @param conj the conjecture term
+   * @param grammar the grammar for the interpolant I
+   * @param output a Term I such that A->I and I->B are valid, where A is the
+   *        current set of assertions and B is given in the input by conj.
+   * @return true if it gets I successfully, false otherwise.
+   */
+  bool getInterpolant(const Term& conj, Grammar& grammar, Term& output) const;
+
+  /**
+   * Get an abduct.
+   * SMT-LIB: ( get-abduct <conj> )
+   * Requires enabling option 'produce-abducts'
+   * @param conj the conjecture term
+   * @param output a term C such that A^C is satisfiable, and A^~B^C is
+   *        unsatisfiable, where A is the current set of assertions and B is
+   *        given in the input by conj
+   * @return true if it gets C successfully, false otherwise
+   */
+  bool getAbduct(const Term& conj, Term& output) const;
+
+  /**
+   * Get an abduct.
+   * SMT-LIB: ( get-abduct <conj> <g> )
+   * Requires enabling option 'produce-abducts'
+   * @param conj the conjecture term
+   * @param grammar the grammar for the abduct C
+   * @param output a term C such that A^C is satisfiable, and A^~B^C is
+   *        unsatisfiable, where A is the current set of assertions and B is
+   *        given in the input by conj
+   * @return true if it gets C successfully, false otherwise
+   */
+  bool getAbduct(const Term& conj, Grammar& grammar, Term& output) const;
+
+  /**
+   * Block the current model. Can be called only if immediately preceded by a
+   * SAT or INVALID query.
+   * SMT-LIB: ( block-model )
+   * Requires enabling 'produce-models' option and setting 'block-models' option
+   * to a mode other than "none".
+   */
+  void blockModel() const;
+
+  /**
+   * Block the current model values of (at least) the values in terms. Can be
+   * called only if immediately preceded by a SAT or NOT_ENTAILED query.
+   * SMT-LIB: ( block-model-values ( <terms>+ ) )
+   * Requires enabling 'produce-models' option and setting 'block-models' option
+   * to a mode other than "none".
+   */
+  void blockModelValues(const std::vector<Term>& terms) const;
+
+  /**
+   * Print all instantiations made by the quantifiers module.
+   * @param out the output stream
+   */
+  void printInstantiations(std::ostream& out) const;
+
+  /**
+   * Push (a) level(s) to the assertion stack.
+   * SMT-LIB: ( push <numeral> )
+   * @param nscopes the number of levels to push
+   */
+  void push(uint32_t nscopes = 1) const;
+
+  /**
+   * Remove all assertions.
+   * SMT-LIB: ( reset-assertions )
+   */
+  void resetAssertions() const;
+
+  /**
+   * Set info.
+   * SMT-LIB: ( set-info <attribute> )
+   * @param keyword the info flag
+   * @param value the value of the info flag
+   */
+  void setInfo(const std::string& keyword, const std::string& value) const;
+
+  /**
+   * Set logic.
+   * SMT-LIB: ( set-logic <symbol> )
+   * @param logic the logic to set
+   */
+  void setLogic(const std::string& logic) const;
+
+  /**
+   * Set option.
+   * SMT-LIB: ( set-option <option> )
+   * @param option the option name
+   * @param value the option value
+   */
+  void setOption(const std::string& option, const std::string& value) const;
+
+  /**
+   * If needed, convert this term to a given sort. Note that the sort of the
+   * term must be convertible into the target sort. Currently only Int to Real
+   * conversions are supported.
+   * @param s the target sort
+   * @return the term wrapped into a sort conversion if needed
+   */
+  Term ensureTermSort(const Term& t, const Sort& s) const;
+
+  /**
+   * Append <symbol> to the current list of universal variables.
+   * SyGuS v2: ( declare-var <symbol> <sort> )
+   * @param sort the sort of the universal variable
+   * @param symbol the name of the universal variable
+   * @return the universal variable
+   */
+  Term mkSygusVar(const Sort& sort,
+                  const std::string& symbol = std::string()) const;
+
+  /**
+   * Create a Sygus grammar. The first non-terminal is treated as the starting
+   * non-terminal, so the order of non-terminals matters.
+   *
+   * @param boundVars the parameters to corresponding synth-fun/synth-inv
+   * @param ntSymbols the pre-declaration of the non-terminal symbols
+   * @return the grammar
+   */
+  Grammar mkSygusGrammar(const std::vector<Term>& boundVars,
+                         const std::vector<Term>& ntSymbols) const;
+
+  /**
+   * Synthesize n-ary function.
+   * SyGuS v2: ( synth-fun <symbol> ( <boundVars>* ) <sort> )
+   * @param symbol the name of the function
+   * @param boundVars the parameters to this function
+   * @param sort the sort of the return value of this function
+   * @return the function
+   */
+  Term synthFun(const std::string& symbol,
+                const std::vector<Term>& boundVars,
+                const Sort& sort) const;
+
+  /**
+   * Synthesize n-ary function following specified syntactic constraints.
+   * SyGuS v2: ( synth-fun <symbol> ( <boundVars>* ) <sort> <g> )
+   * @param symbol the name of the function
+   * @param boundVars the parameters to this function
+   * @param sort the sort of the return value of this function
+   * @param grammar the syntactic constraints
+   * @return the function
+   */
+  Term synthFun(const std::string& symbol,
+                const std::vector<Term>& boundVars,
+                Sort sort,
+                Grammar& grammar) const;
+
+  /**
+   * Synthesize invariant.
+   * SyGuS v2: ( synth-inv <symbol> ( <boundVars>* ) )
+   * @param symbol the name of the invariant
+   * @param boundVars the parameters to this invariant
+   * @param sort the sort of the return value of this invariant
+   * @return the invariant
+   */
+  Term synthInv(const std::string& symbol,
+                const std::vector<Term>& boundVars) const;
+
+  /**
+   * Synthesize invariant following specified syntactic constraints.
+   * SyGuS v2: ( synth-inv <symbol> ( <boundVars>* ) <g> )
+   * @param symbol the name of the invariant
+   * @param boundVars the parameters to this invariant
+   * @param sort the sort of the return value of this invariant
+   * @param grammar the syntactic constraints
+   * @return the invariant
+   */
+  Term synthInv(const std::string& symbol,
+                const std::vector<Term>& boundVars,
+                Grammar& grammar) const;
+
+  /**
+   * Add a forumla to the set of Sygus constraints.
+   * SyGuS v2: ( constraint <term> )
+   * @param term the formula to add as a constraint
+   */
+  void addSygusConstraint(const Term& term) const;
+
+  /**
+   * Add a set of Sygus constraints to the current state that correspond to an
+   * invariant synthesis problem.
+   * SyGuS v2: ( inv-constraint <inv> <pre> <trans> <post> )
+   * @param inv the function-to-synthesize
+   * @param pre the pre-condition
+   * @param trans the transition relation
+   * @param post the post-condition
+   */
+  void addSygusInvConstraint(Term inv, Term pre, Term trans, Term post) const;
+
+  /**
+   * Try to find a solution for the synthesis conjecture corresponding to the
+   * current list of functions-to-synthesize, universal variables and
+   * constraints.
+   * SyGuS v2: ( check-synth )
+   * @return the result of the synthesis conjecture.
+   */
+  Result checkSynth() const;
+
+  /**
+   * Get the synthesis solution of the given term. This method should be called
+   * immediately after the solver answers unsat for sygus input.
+   * @param term the term for which the synthesis solution is queried
+   * @return the synthesis solution of the given term
+   */
+  Term getSynthSolution(Term term) const;
+
+  /**
+   * Get the synthesis solutions of the given terms. This method should be
+   * called immediately after the solver answers unsat for sygus input.
+   * @param terms the terms for which the synthesis solutions is queried
+   * @return the synthesis solutions of the given terms
+   */
+  std::vector<Term> getSynthSolutions(const std::vector<Term>& terms) const;
+
+  /**
+   * Print solution for synthesis conjecture to the given output stream.
+   * @param out the output stream
+   */
+  void printSynthSolution(std::ostream& out) const;
+
+  // !!! This is only temporarily available until the parser is fully migrated
+  // to the new API. !!!
+  SmtEngine* getSmtEngine(void) const;
+
+  // !!! This is only temporarily available until options are refactored at
+  // the driver level. !!!
+  Options& getOptions(void);
+
+ private:
+  /** @return the node manager of this solver */
+  NodeManager* getNodeManager(void) const;
+
+  /** Helper to check for API misuse in mkOp functions. */
+  void checkMkTerm(Kind kind, uint32_t nchildren) const;
+  /** Helper for mk-functions that call d_nodeMgr->mkConst(). */
+  template <typename T>
+  Term mkValHelper(T t) const;
+  /** Helper for mkReal functions that take a string as argument. */
+  Term mkRealFromStrHelper(const std::string& s) const;
+  /** Helper for mkBitVector functions that take a string as argument. */
+  Term mkBVFromStrHelper(const std::string& s, uint32_t base) const;
+  /**
+   * Helper for mkBitVector functions that take a string and a size as
+   * arguments.
+   */
+  Term mkBVFromStrHelper(uint32_t size,
+                         const std::string& s,
+                         uint32_t base) const;
+  /** Helper for mkBitVector functions that take an integer as argument. */
+  Term mkBVFromIntHelper(uint32_t size, uint64_t val) const;
+  /** Helper for functions that create tuple sorts. */
+  Sort mkTupleSortHelper(const std::vector<Sort>& sorts) const;
+  /** Helper for mkTerm functions that create Term from a Kind */
+  Term mkTermFromKind(Kind kind) const;
+  /** Helper for mkChar functions that take a string as argument. */
+  Term mkCharFromStrHelper(const std::string& s) const;
+  /** Get value helper, which accounts for subtyping */
+  Term getValueHelper(const Term& term) const;
+
+  /**
+   * Helper function that ensures that a given term is of sort real (as opposed
+   * to being of sort integer).
+   * @param t a term of sort integer or real
+   * @return a term of sort real
+   */
+  Term ensureRealSort(const Term& t) const;
+
+  /**
+   * Create n-ary term of given kind. This handles the cases of left/right
+   * associative operators, chainable operators, and cases when the number of
+   * children exceeds the maximum arity for the kind.
+   * @param kind the kind of the term
+   * @param children the children of the term
+   * @return the Term
+   */
+  Term mkTermHelper(Kind kind, const std::vector<Term>& children) const;
+
+  /**
+   * Create n-ary term of given kind from a given operator.
+   * @param op the operator
+   * @param children the children of the term
+   * @return the Term
+   */
+  Term mkTermHelper(const Op& op, const std::vector<Term>& children) const;
+
+  /**
+   * Create a vector of datatype sorts, using unresolved sorts.
+   * @param dtypedecls the datatype declarations from which the sort is created
+   * @param unresolvedSorts the list of unresolved sorts
+   * @return the datatype sorts
+   */
+  std::vector<Sort> mkDatatypeSortsInternal(
+      const std::vector<DatatypeDecl>& dtypedecls,
+      const std::set<Sort>& unresolvedSorts) const;
+
+  /**
+   * Synthesize n-ary function following specified syntactic constraints.
+   * SMT-LIB: ( synth-fun <symbol> ( <boundVars>* ) <sort> <g>? )
+   * @param symbol the name of the function
+   * @param boundVars the parameters to this function
+   * @param sort the sort of the return value of this function
+   * @param isInv determines whether this is synth-fun or synth-inv
+   * @param g the syntactic constraints
+   * @return the function
+   */
+  Term synthFunHelper(const std::string& symbol,
+                      const std::vector<Term>& boundVars,
+                      const Sort& sort,
+                      bool isInv = false,
+                      Grammar* grammar = nullptr) const;
+
+  /** Check whether string s is a valid decimal integer. */
+  bool isValidInteger(const std::string& s) const;
+
+  /** Increment the term stats counter. */
+  void increment_term_stats(Kind kind) const;
+  /** Increment the vars stats (if 'is_var') or consts stats counter. */
+  void increment_vars_consts_stats(const Sort& sort, bool is_var) const;
+
+  /** Keep a copy of the original option settings (for resets). */
+  std::unique_ptr<Options> d_originalOptions;
+  /** The node manager of this solver. */
+  std::unique_ptr<NodeManager> d_nodeMgr;
+  /** The statistics collected on the Api level. */
+  std::unique_ptr<Statistics> d_stats;
+  /** The SMT engine of this solver. */
+  std::unique_ptr<SmtEngine> d_smtEngine;
+  /** The random number generator of this solver. */
+  std::unique_ptr<Random> d_rng;
+};
+
+}  // namespace api
+}  // namespace cvc5
+#endif
diff --git a/src/api/cpp/cvc5_kind.h b/src/api/cpp/cvc5_kind.h
new file mode 100644 (file)
index 0000000..188c8d0
--- /dev/null
@@ -0,0 +1,2873 @@
+/*********************                                                        */
+/*! \file cvc5_kind.h
+ ** \verbatim
+ ** Top contributors (to current version):
+ **   Aina Niemetz, Andrew Reynolds, Makai Mann
+ ** This file is part of the CVC4 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.\endverbatim
+ **
+ ** \brief The term kinds of the CVC4 C++ API.
+ **
+ ** The term kinds of the CVC4 C++ API.
+ **/
+
+#include "cvc4_export.h"
+
+#ifndef CVC5__API__CVC5_KIND_H
+#define CVC5__API__CVC5_KIND_H
+
+#include <ostream>
+
+namespace cvc5 {
+namespace api {
+
+/* -------------------------------------------------------------------------- */
+/* Kind                                                                       */
+/* -------------------------------------------------------------------------- */
+
+/**
+ * The kind of a CVC4 term.
+ *
+ * Note that the underlying type of Kind must be signed (to enable range
+ * checks for validity). The size of this type depends on the size of
+ * cvc5::Kind (NodeValue::NBITS_KIND, currently 10 bits, see expr/node_value.h).
+ */
+enum CVC4_EXPORT Kind : int32_t
+{
+  /**
+   * Internal kind.
+   * Should never be exposed or created via the API.
+   */
+  INTERNAL_KIND = -2,
+  /**
+   * Undefined kind.
+   * Should never be exposed or created via the API.
+   */
+  UNDEFINED_KIND = -1,
+  /**
+   * Null kind (kind of null term Term()).
+   * Do not explicitly create via API functions other than Term().
+   */
+  NULL_EXPR,
+
+  /* Builtin --------------------------------------------------------------- */
+
+  /**
+   * Uninterpreted constant.
+   * Parameters: 2
+   *   -[1]: Sort of the constant
+   *   -[2]: Index of the constant
+   * Create with:
+   *   mkUninterpretedConst(Sort sort, int32_t index)
+   */
+  UNINTERPRETED_CONSTANT,
+  /**
+   * Abstract value (other than uninterpreted sort constants).
+   * Parameters: 1
+   *   -[1]: Index of the abstract value
+   * Create with:
+   *   mkAbstractValue(const std::string& index);
+   *   mkAbstractValue(uint64_t index);
+   */
+  ABSTRACT_VALUE,
+#if 0
+  /* Built-in operator */
+  BUILTIN,
+#endif
+  /**
+   * Equality, chainable.
+   * Parameters: n > 1
+   *   -[1]..[n]: Terms with same sorts
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  EQUAL,
+  /**
+   * Disequality.
+   * Parameters: n > 1
+   *   -[1]..[n]: Terms with same sorts
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  DISTINCT,
+  /**
+   * First-order constant.
+   * Not permitted in bindings (forall, exists, ...).
+   * Parameters:
+   *   See mkConst().
+   * Create with:
+   *   mkConst(const std::string& symbol, Sort sort)
+   *   mkConst(Sort sort)
+   */
+  CONSTANT,
+  /**
+   * (Bound) variable.
+   * Permitted in bindings and in the lambda and quantifier bodies only.
+   * Parameters:
+   *   See mkVar().
+   * Create with:
+   *   mkVar(const std::string& symbol, Sort sort)
+   *   mkVar(Sort sort)
+   */
+  VARIABLE,
+#if 0
+  /* Skolem variable (internal only) */
+  SKOLEM,
+#endif
+  /*
+   * Symbolic expression.
+   * Parameters: n > 0
+   *   -[1]..[n]: terms
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  SEXPR,
+  /**
+   * Lambda expression.
+   * Parameters: 2
+   *   -[1]: BOUND_VAR_LIST
+   *   -[2]: Lambda body
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  LAMBDA,
+  /**
+   * The syntax of a witness term is similar to a quantified formula except that
+   * only one bound variable is allowed.
+   * The term (witness ((x T)) F) returns an element x of type T
+   * and asserts F.
+   *
+   * The witness operator behaves like the description operator
+   * (see https://planetmath.org/hilbertsvarepsilonoperator) if there is no x
+   * that satisfies F. But if such x exists, the witness operator does not
+   * enforce the axiom that ensures uniqueness up to logical equivalence:
+   * forall x. F \equiv G => witness x. F =  witness x. G
+   *
+   * For example if there are 2 elements of type T that satisfy F, then the
+   * following formula is satisfiable:
+   * (distinct
+   *    (witness ((x Int)) F)
+   *    (witness ((x Int)) F))
+   *
+   * This kind is primarily used internally, but may be returned in models
+   * (e.g. for arithmetic terms in non-linear queries). However, it is not
+   * supported by the parser. Moreover, the user of the API should be cautious
+   * when using this operator. In general, all witness terms
+   * (witness ((x Int)) F) should be such that (exists ((x Int)) F) is a valid
+   * formula. If this is not the case, then the semantics in formulas that use
+   * witness terms may be unintuitive. For example, the following formula is
+   * unsatisfiable:
+   * (or (= (witness ((x Int)) false) 0) (not (= (witness ((x Int)) false) 0))
+   * whereas notice that (or (= z 0) (not (= z 0))) is true for any z.
+   *
+   * Parameters: 2
+   *   -[1]: BOUND_VAR_LIST
+   *   -[2]: Witness body
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  WITNESS,
+
+  /* Boolean --------------------------------------------------------------- */
+
+  /**
+   * Boolean constant.
+   * Parameters: 1
+   *   -[1]: Boolean value of the constant
+   * Create with:
+   *   mkTrue()
+   *   mkFalse()
+   *   mkBoolean(bool val)
+   */
+  CONST_BOOLEAN,
+  /* Logical not.
+   * Parameters: 1
+   *   -[1]: Boolean Term to negate
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  NOT,
+  /* Logical and.
+   * Parameters: n > 1
+   *   -[1]..[n]: Boolean Term of the conjunction
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  AND,
+  /**
+   * Logical implication.
+   * Parameters: n > 1
+   *   -[1]..[n]: Boolean Terms, right associative
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  IMPLIES,
+  /* Logical or.
+   * Parameters: n > 1
+   *   -[1]..[n]: Boolean Term of the disjunction
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  OR,
+  /* Logical exclusive or, left associative.
+   * Parameters: n > 1
+   *   -[1]..[n]: Boolean Terms, [1] xor ... xor [n]
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  XOR,
+  /* If-then-else.
+   * Parameters: 3
+   *   -[1] is a Boolean condition Term
+   *   -[2] the 'then' Term
+   *   -[3] the 'else' Term
+   * 'then' and 'else' term must have same base sort.
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  ITE,
+
+  /* UF -------------------------------------------------------------------- */
+
+  /* Application of an uninterpreted function.
+   * Parameters: n > 1
+   *   -[1]: Function Term
+   *   -[2]..[n]: Function argument instantiation Terms
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  APPLY_UF,
+#if 0
+  /* Boolean term variable */
+  BOOLEAN_TERM_VARIABLE,
+#endif
+  /**
+   * Cardinality constraint on uninterpreted sort S.
+   * Interpreted as a predicate that is true when the cardinality of S
+   * is less than or equal to the value of the second argument.
+   * Parameters: 2
+   *   -[1]: Term of sort S
+   *   -[2]: Positive integer constant that bounds the cardinality of sort S
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  CARDINALITY_CONSTRAINT,
+  /*
+   * Cardinality value for uninterpreted sort S.
+   * An operator that returns an integer indicating the value of the cardinality
+   * of sort S.
+   * Parameters: 1
+   *   -[1]: Term of sort S
+   * Create with:
+   *   mkTerm(Kind kind, Term child1)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  CARDINALITY_VALUE,
+#if 0
+  /* Combined cardinality constraint.  */
+  COMBINED_CARDINALITY_CONSTRAINT,
+  /* Partial uninterpreted function application.  */
+  PARTIAL_APPLY_UF,
+#endif
+  /**
+   * Higher-order applicative encoding of function application, left
+   * associative.
+   * Parameters: n > 1
+   *   -[1]: Function to apply
+   *   -[2] ... [n]: Arguments of the function
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  HO_APPLY,
+
+  /* Arithmetic ------------------------------------------------------------ */
+
+  /**
+   * Arithmetic addition.
+   * Parameters: n > 1
+   *   -[1]..[n]: Terms of sort Integer, Real (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  PLUS,
+  /**
+   * Arithmetic multiplication.
+   * Parameters: n > 1
+   *   -[1]..[n]: Terms of sort Integer, Real (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  MULT,
+  /**
+   * Operator for Integer AND
+   * Parameter: 1
+   *   -[1]: Size of the bit-vector that determines the semantics of the IAND
+   * Create with:
+   *   mkOp(Kind kind, uint32_t param).
+   *
+   * Apply integer conversion to bit-vector.
+   * Parameters: 2
+   *   -[1]: Op of kind IAND
+   *   -[2]: Integer term
+   *   -[3]: Integer term
+   * Create with:
+   *   mkTerm(Op op, Term child1, Term child2)
+   *   mkTerm(Op op, const std::vector<Term>& children)
+   */
+  IAND,
+#if 0
+  /* Synonym for MULT.  */
+  NONLINEAR_MULT,
+#endif
+  /**
+   * Arithmetic subtraction, left associative.
+   * Parameters: n
+   *   -[1]..[n]: Terms of sort Integer, Real (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  MINUS,
+  /**
+   * Arithmetic negation.
+   * Parameters: 1
+   *   -[1]: Term of sort Integer, Real
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  UMINUS,
+  /**
+   * Real division, division by 0 undefined, left associative.
+   * Parameters: n > 1
+   *   -[1]..[n]: Terms of sort Integer, Real
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  DIVISION,
+  /**
+   * Integer division, division by 0 undefined, left associative.
+   * Parameters: n > 1
+   *   -[1]..[n]: Terms of sort Integer
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  INTS_DIVISION,
+  /**
+   * Integer modulus, division by 0 undefined.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of sort Integer
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  INTS_MODULUS,
+  /**
+   * Absolute value.
+   * Parameters: 1
+   *   -[1]: Term of sort Integer
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  ABS,
+  /**
+   * Arithmetic power.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of sort Integer, Real
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  POW,
+  /**
+   * Exponential.
+   * Parameters: 1
+   *   -[1]: Term of sort Integer, Real
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  EXPONENTIAL,
+  /**
+   * Sine.
+   * Parameters: 1
+   *   -[1]: Term of sort Integer, Real
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  SINE,
+  /**
+   * Cosine.
+   * Parameters: 1
+   *   -[1]: Term of sort Integer, Real
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  COSINE,
+  /**
+   * Tangent.
+   * Parameters: 1
+   *   -[1]: Term of sort Integer, Real
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  TANGENT,
+  /**
+   * Cosecant.
+   * Parameters: 1
+   *   -[1]: Term of sort Integer, Real
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  COSECANT,
+  /**
+   * Secant.
+   * Parameters: 1
+   *   -[1]: Term of sort Integer, Real
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  SECANT,
+  /**
+   * Cotangent.
+   * Parameters: 1
+   *   -[1]: Term of sort Integer, Real
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  COTANGENT,
+  /**
+   * Arc sine.
+   * Parameters: 1
+   *   -[1]: Term of sort Integer, Real
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  ARCSINE,
+  /**
+   * Arc cosine.
+   * Parameters: 1
+   *   -[1]: Term of sort Integer, Real
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  ARCCOSINE,
+  /**
+   * Arc tangent.
+   * Parameters: 1
+   *   -[1]: Term of sort Integer, Real
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  ARCTANGENT,
+  /**
+   * Arc cosecant.
+   * Parameters: 1
+   *   -[1]: Term of sort Integer, Real
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  ARCCOSECANT,
+  /**
+   * Arc secant.
+   * Parameters: 1
+   *   -[1]: Term of sort Integer, Real
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  ARCSECANT,
+  /**
+   * Arc cotangent.
+   * Parameters: 1
+   *   -[1]: Term of sort Integer, Real
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  ARCCOTANGENT,
+  /**
+   * Square root.
+   * Parameters: 1
+   *   -[1]: Term of sort Integer, Real
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  SQRT,
+  /**
+   * Operator for the divisibility-by-k predicate.
+   * Parameter: 1
+   *   -[1]: The k to divide by (sort Integer)
+   * Create with:
+   *   mkOp(Kind kind, uint32_t param)
+   *
+   * Apply divisibility-by-k predicate.
+   * Parameters: 2
+   *   -[1]: Op of kind DIVISIBLE
+   *   -[2]: Integer Term
+   * Create with:
+   *   mkTerm(Op op, Term child1, Term child2)
+   *   mkTerm(Op op, const std::vector<Term>& children)
+   */
+  DIVISIBLE,
+  /**
+   * Multiple-precision rational constant.
+   * Parameters:
+   *   See mkInteger(), mkReal(), mkRational()
+   * Create with:
+   *   mkInteger(const char* s, uint32_t base = 10)
+   *   mkInteger(const std::string& s, uint32_t base = 10)
+   *   mkInteger(int32_t val)
+   *   mkInteger(uint32_t val)
+   *   mkInteger(int64_t val)
+   *   mkInteger(uint64_t val)
+   *   mkReal(const char* s, uint32_t base = 10)
+   *   mkReal(const std::string& s, uint32_t base = 10)
+   *   mkReal(int32_t val)
+   *   mkReal(int64_t val)
+   *   mkReal(uint32_t val)
+   *   mkReal(uint64_t val)
+   *   mkReal(int32_t num, int32_t den)
+   *   mkReal(int64_t num, int64_t den)
+   *   mkReal(uint32_t num, uint32_t den)
+   *   mkReal(uint64_t num, uint64_t den)
+   */
+  CONST_RATIONAL,
+  /**
+   * Less than, chainable.
+   * Parameters: n
+   *   -[1]..[n]: Terms of sort Integer, Real; [1] < ... < [n]
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  LT,
+  /**
+   * Less than or equal, chainable.
+   * Parameters: n > 1
+   *   -[1]..[n]: Terms of sort Integer, Real; [1] <= ... <= [n]
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  LEQ,
+  /**
+   * Greater than, chainable.
+   * Parameters: n > 1
+   *   -[1]..[n]: Terms of sort Integer, Real, [1] > ... > [n]
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  GT,
+  /**
+   * Greater than or equal, chainable.
+   * Parameters: n > 1
+   *   -[1]..[n]: Terms of sort Integer, Real; [1] >= ... >= [n]
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  GEQ,
+  /**
+   * Is-integer predicate.
+   * Parameters: 1
+   *   -[1]: Term of sort Integer, Real
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  IS_INTEGER,
+  /**
+   * Convert Term to Integer by the floor function.
+   * Parameters: 1
+   *   -[1]: Term of sort Integer, Real
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  TO_INTEGER,
+  /**
+   * Convert Term to Real.
+   * Parameters: 1
+   *   -[1]: Term of sort Integer, Real
+   * This is a no-op in CVC4, as Integer is a subtype of Real.
+   */
+  TO_REAL,
+  /**
+   * Pi constant.
+   * Create with:
+   *   mkPi()
+   *   mkTerm(Kind kind)
+   */
+  PI,
+
+  /* BV -------------------------------------------------------------------- */
+
+  /**
+   * Fixed-size bit-vector constant.
+   * Parameters:
+   *   See mkBitVector().
+   * Create with:
+   *   mkBitVector(uint32_t size, uint64_t val)
+   *   mkBitVector(const char* s, uint32_t base = 2)
+   *   mkBitVector(std::string& s, uint32_t base = 2)
+   */
+  CONST_BITVECTOR,
+  /**
+   * Concatenation of two or more bit-vectors.
+   * Parameters: n > 1
+   *   -[1]..[n]: Terms of bit-vector sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_CONCAT,
+  /**
+   * Bit-wise and.
+   * Parameters: n > 1
+   *   -[1]..[n]: Terms of bit-vector sort (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_AND,
+  /**
+   * Bit-wise or.
+   * Parameters: n > 1
+   *   -[1]..[n]: Terms of bit-vector sort (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_OR,
+  /**
+   * Bit-wise xor.
+   * Parameters: n > 1
+   *   -[1]..[n]: Terms of bit-vector sort (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_XOR,
+  /**
+   * Bit-wise negation.
+   * Parameters: 1
+   *   -[1]: Term of bit-vector sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  BITVECTOR_NOT,
+  /**
+   * Bit-wise nand.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_NAND,
+  /**
+   * Bit-wise nor.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_NOR,
+  /**
+   * Bit-wise xnor, left associative.
+   * Parameters: n > 1
+   *   -[1]..[n]: Terms of bit-vector sort (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_XNOR,
+  /**
+   * Equality comparison (returns bit-vector of size 1).
+   * Parameters: 2
+   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_COMP,
+  /**
+   * Multiplication of two or more bit-vectors.
+   * Parameters: n > 1
+   *   -[1]..[n]: Terms of bit-vector sort (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_MULT,
+  /**
+   * Addition of two or more bit-vectors.
+   * Parameters: n > 1
+   *   -[1]..[n]: Terms of bit-vector sort (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_PLUS,
+  /**
+   * Subtraction of two bit-vectors.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_SUB,
+  /**
+   * Negation of a bit-vector (two's complement).
+   * Parameters: 1
+   *   -[1]: Term of bit-vector sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  BITVECTOR_NEG,
+  /**
+   * Unsigned division of two bit-vectors, truncating towards 0.
+   *
+   * Note: The semantics of this operator depends on `bv-div-zero-const`
+   * (default is true).  Depending on the setting, a division by zero is
+   * treated as all ones (default, corresponds to SMT-LIB >=2.6) or an
+   * uninterpreted value (corresponds to SMT-LIB <2.6).
+   *
+   * Parameters: 2
+   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_UDIV,
+  /**
+   * Unsigned remainder from truncating division of two bit-vectors.
+   *
+   * Note: The semantics of this operator depends on `bv-div-zero-const`
+   * (default is true). Depending on the setting, if the modulus is zero, the
+   * result is either the dividend (default, corresponds to SMT-LIB >=2.6) or
+   * an uninterpreted value (corresponds to SMT-LIB <2.6).
+   *
+   * Parameters: 2
+   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_UREM,
+  /**
+   * Two's complement signed division of two bit-vectors.
+   *
+   * Note: The semantics of this operator depends on `bv-div-zero-const`
+   * (default is true). By default, the function returns all ones if the
+   * dividend is positive and one if the dividend is negative (corresponds to
+   * SMT-LIB >=2.6). If the option is disabled, a division by zero is treated
+   * as an uninterpreted value (corresponds to SMT-LIB <2.6).
+   *
+   * Parameters: 2
+   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_SDIV,
+  /**
+   * Two's complement signed remainder of two bit-vectors
+   * (sign follows dividend).
+   *
+   * Note: The semantics of this operator depends on `bv-div-zero-const`
+   * (default is true, corresponds to SMT-LIB >=2.6). Depending on the setting,
+   * if the modulus is zero, the result is either the dividend (default) or an
+   * uninterpreted value (corresponds to SMT-LIB <2.6).
+   *
+   * Parameters: 2
+   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_SREM,
+  /**
+   * Two's complement signed remainder
+   * (sign follows divisor).
+   *
+   * Note: The semantics of this operator depends on `bv-div-zero-const`
+   * (default is on). Depending on the setting, if the modulus is zero, the
+   * result is either the dividend (default, corresponds to SMT-LIB >=2.6) or
+   * an uninterpreted value (corresponds to SMT-LIB <2.6).
+   *
+   * Parameters: 2
+   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_SMOD,
+  /**
+   * Bit-vector shift left.
+   * The two bit-vector parameters must have same width.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_SHL,
+  /**
+   * Bit-vector logical shift right.
+   * The two bit-vector parameters must have same width.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_LSHR,
+  /**
+   * Bit-vector arithmetic shift right.
+   * The two bit-vector parameters must have same width.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_ASHR,
+  /**
+   * Bit-vector unsigned less than.
+   * The two bit-vector parameters must have same width.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_ULT,
+  /**
+   * Bit-vector unsigned less than or equal.
+   * The two bit-vector parameters must have same width.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_ULE,
+  /**
+   * Bit-vector unsigned greater than.
+   * The two bit-vector parameters must have same width.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_UGT,
+  /**
+   * Bit-vector unsigned greater than or equal.
+   * The two bit-vector parameters must have same width.
+   * Parameters: 2
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_UGE,
+  /* Bit-vector signed less than.
+   * The two bit-vector parameters must have same width.
+   * Parameters: 2
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_SLT,
+  /**
+   * Bit-vector signed less than or equal.
+   * The two bit-vector parameters must have same width.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_SLE,
+  /**
+   * Bit-vector signed greater than.
+   * The two bit-vector parameters must have same width.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_SGT,
+  /**
+   * Bit-vector signed greater than or equal.
+   * The two bit-vector parameters must have same width.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_SGE,
+  /**
+   * Bit-vector unsigned less than, returns bit-vector of size 1.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_ULTBV,
+  /**
+   * Bit-vector signed less than. returns bit-vector of size 1.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_SLTBV,
+  /**
+   * Same semantics as regular ITE, but condition is bit-vector of size 1.
+   * Parameters: 3
+   *   -[1]: Term of bit-vector sort of size 1, representing the condition
+   *   -[2]: Term reprsenting the 'then' branch
+   *   -[3]: Term representing the 'else' branch
+   * 'then' and 'else' term must have same base sort.
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BITVECTOR_ITE,
+  /**
+   * Bit-vector redor.
+   * Parameters: 1
+   *   -[1]: Term of bit-vector sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  BITVECTOR_REDOR,
+  /**
+   * Bit-vector redand.
+   * Parameters: 1
+   *   -[1]: Term of bit-vector sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  BITVECTOR_REDAND,
+#if 0
+  /* formula to be treated as a bv atom via eager bit-blasting
+   * (internal-only symbol) */
+  BITVECTOR_EAGER_ATOM,
+  /* term to be treated as a variable. used for eager bit-blasting Ackermann
+   * expansion of bvudiv (internal-only symbol) */
+  BITVECTOR_ACKERMANIZE_UDIV,
+  /* term to be treated as a variable. used for eager bit-blasting Ackermann
+   * expansion of bvurem (internal-only symbol) */
+  BITVECTOR_ACKERMANIZE_UREM,
+#endif
+  /**
+   * Operator for bit-vector extract (from index 'high' to 'low').
+   * Parameters: 2
+   *   -[1]: The 'high' index
+   *   -[2]: The 'low' index
+   * Create with:
+   *   mkOp(Kind kind, uint32_t param, uint32_t param)
+   *
+   * Apply bit-vector extract.
+   * Parameters: 2
+   *   -[1]: Op of kind BITVECTOR_EXTRACT
+   *   -[2]: Term of bit-vector sort
+   * Create with:
+   *   mkTerm(Op op, Term child)
+   *   mkTerm(Op op, const std::vector<Term>& children)
+   */
+  BITVECTOR_EXTRACT,
+  /**
+   * Operator for bit-vector repeat.
+   * Parameter 1:
+   *   -[1]: Number of times to repeat a given bit-vector
+   * Create with:
+   *   mkOp(Kind kind, uint32_t param).
+   *
+   * Apply bit-vector repeat.
+   * Parameters: 2
+   *   -[1]: Op of kind BITVECTOR_REPEAT
+   *   -[2]: Term of bit-vector sort
+   * Create with:
+   *   mkTerm(Op op, Term child)
+   *   mkTerm(Op op, const std::vector<Term>& children)
+   */
+  BITVECTOR_REPEAT,
+  /**
+   * Operator for bit-vector zero-extend.
+   * Parameter 1:
+   *   -[1]: Number of bits by which a given bit-vector is to be extended
+   * Create with:
+   *   mkOp(Kind kind, uint32_t param).
+   *
+   * Apply bit-vector zero-extend.
+   * Parameters: 2
+   *   -[1]: Op of kind BITVECTOR_ZERO_EXTEND
+   *   -[2]: Term of bit-vector sort
+   * Create with:
+   *   mkTerm(Op op, Term child)
+   *   mkTerm(Op op, const std::vector<Term>& children)
+   */
+  BITVECTOR_ZERO_EXTEND,
+  /**
+   * Operator for bit-vector sign-extend.
+   * Parameter 1:
+   *   -[1]: Number of bits by which a given bit-vector is to be extended
+   * Create with:
+   *   mkOp(Kind kind, uint32_t param).
+   *
+   * Apply bit-vector sign-extend.
+   * Parameters: 2
+   *   -[1]: Op of kind BITVECTOR_SIGN_EXTEND
+   *   -[2]: Term of bit-vector sort
+   * Create with:
+   *   mkTerm(Op op, Term child)
+   *   mkTerm(Op op, const std::vector<Term>& children)
+   */
+  BITVECTOR_SIGN_EXTEND,
+  /**
+   * Operator for bit-vector rotate left.
+   * Parameter 1:
+   *   -[1]: Number of bits by which a given bit-vector is to be rotated
+   * Create with:
+   *   mkOp(Kind kind, uint32_t param).
+   *
+   * Apply bit-vector rotate left.
+   * Parameters: 2
+   *   -[1]: Op of kind BITVECTOR_ROTATE_LEFT
+   *   -[2]: Term of bit-vector sort
+   * Create with:
+   *   mkTerm(Op op, Term child)
+   *   mkTerm(Op op, const std::vector<Term>& children)
+   */
+  BITVECTOR_ROTATE_LEFT,
+  /**
+   * Operator for bit-vector rotate right.
+   * Parameter 1:
+   *   -[1]: Number of bits by which a given bit-vector is to be rotated
+   * Create with:
+   *   mkOp(Kind kind, uint32_t param).
+   *
+   * Apply bit-vector rotate right.
+   * Parameters: 2
+   *   -[1]: Op of kind BITVECTOR_ROTATE_RIGHT
+   *   -[2]: Term of bit-vector sort
+   * Create with:
+   *   mkTerm(Op op, Term child)
+   *   mkTerm(Op op, const std::vector<Term>& children)
+   */
+  BITVECTOR_ROTATE_RIGHT,
+#if 0
+  /* bit-vector boolean bit extract. */
+  BITVECTOR_BITOF,
+#endif
+  /**
+   * Operator for the conversion from Integer to bit-vector.
+   * Parameter: 1
+   *   -[1]: Size of the bit-vector to convert to
+   * Create with:
+   *   mkOp(Kind kind, uint32_t param).
+   *
+   * Apply integer conversion to bit-vector.
+   * Parameters: 2
+   *   -[1]: Op of kind INT_TO_BITVECTOR
+   *   -[2]: Integer term
+   * Create with:
+   *   mkTerm(Op op, Term child)
+   *   mkTerm(Op op, const std::vector<Term>& children)
+   */
+  INT_TO_BITVECTOR,
+  /**
+   * Bit-vector conversion to (nonnegative) integer.
+   * Parameter: 1
+   *   -[1]: Term of bit-vector sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  BITVECTOR_TO_NAT,
+
+  /* FP -------------------------------------------------------------------- */
+
+  /**
+   * Floating-point constant, constructed from a double or string.
+   * Parameters: 3
+   *   -[1]: Size of the exponent
+   *   -[2]: Size of the significand
+   *   -[3]: Value of the floating-point constant as a bit-vector term
+   * Create with:
+   *   mkFloatingPoint(uint32_t sig, uint32_t exp, Term val)
+   */
+  CONST_FLOATINGPOINT,
+  /**
+   * Floating-point rounding mode term.
+   * Create with:
+   *   mkRoundingMode(RoundingMode rm)
+   */
+  CONST_ROUNDINGMODE,
+  /**
+   * Create floating-point literal from bit-vector triple.
+   * Parameters: 3
+   *   -[1]: Sign bit as a bit-vector term
+   *   -[2]: Exponent bits as a bit-vector term
+   *   -[3]: Significand bits as a bit-vector term (without hidden bit)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  FLOATINGPOINT_FP,
+  /**
+   * Floating-point equality.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of floating point sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  FLOATINGPOINT_EQ,
+  /**
+   * Floating-point absolute value.
+   * Parameters: 1
+   *   -[1]: Term of floating point sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  FLOATINGPOINT_ABS,
+  /**
+   * Floating-point negation.
+   * Parameters: 1
+   *   -[1]: Term of floating point sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  FLOATINGPOINT_NEG,
+  /**
+   * Floating-point addition.
+   * Parameters: 3
+   *   -[1]: CONST_ROUNDINGMODE
+   *   -[2]: Term of sort FloatingPoint
+   *   -[3]: Term of sort FloatingPoint
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2, child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  FLOATINGPOINT_PLUS,
+  /**
+   * Floating-point sutraction.
+   * Parameters: 3
+   *   -[1]: CONST_ROUNDINGMODE
+   *   -[2]: Term of sort FloatingPoint
+   *   -[3]: Term of sort FloatingPoint
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  FLOATINGPOINT_SUB,
+  /**
+   * Floating-point multiply.
+   * Parameters: 3
+   *   -[1]: CONST_ROUNDINGMODE
+   *   -[2]: Term of sort FloatingPoint
+   *   -[3]: Term of sort FloatingPoint
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  FLOATINGPOINT_MULT,
+  /**
+   * Floating-point division.
+   * Parameters: 3
+   *   -[1]: CONST_ROUNDINGMODE
+   *   -[2]: Term of sort FloatingPoint
+   *   -[3]: Term of sort FloatingPoint
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  FLOATINGPOINT_DIV,
+  /**
+   * Floating-point fused multiply and add.
+   * Parameters: 4
+   *   -[1]: CONST_ROUNDINGMODE
+   *   -[2]: Term of sort FloatingPoint
+   *   -[3]: Term of sort FloatingPoint
+   *   -[4]: Term of sort FloatingPoint
+   * Create with:
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  FLOATINGPOINT_FMA,
+  /**
+   * Floating-point square root.
+   * Parameters: 2
+   *   -[1]: CONST_ROUNDINGMODE
+   *   -[2]: Term of sort FloatingPoint
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  FLOATINGPOINT_SQRT,
+  /**
+   * Floating-point remainder.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of floating point sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  FLOATINGPOINT_REM,
+  /**
+   * Floating-point round to integral.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of floating point sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  FLOATINGPOINT_RTI,
+  /**
+   * Floating-point minimum.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of floating point sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  FLOATINGPOINT_MIN,
+  /**
+   * Floating-point maximum.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of floating point sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  FLOATINGPOINT_MAX,
+  /**
+   * Floating-point less than or equal.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of floating point sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  FLOATINGPOINT_LEQ,
+  /**
+   * Floating-point less than.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of floating point sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  FLOATINGPOINT_LT,
+  /**
+   * Floating-point greater than or equal.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of floating point sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  FLOATINGPOINT_GEQ,
+  /**
+   * Floating-point greater than.
+   * Parameters: 2
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  FLOATINGPOINT_GT,
+  /**
+   * Floating-point is normal.
+   * Parameters: 1
+   *   -[1]: Term of floating point sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  FLOATINGPOINT_ISN,
+  /**
+   * Floating-point is sub-normal.
+   * Parameters: 1
+   *   -[1]: Term of floating point sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  FLOATINGPOINT_ISSN,
+  /**
+   * Floating-point is zero.
+   * Parameters: 1
+   *   -[1]: Term of floating point sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  FLOATINGPOINT_ISZ,
+  /**
+   * Floating-point is infinite.
+   * Parameters: 1
+   *   -[1]: Term of floating point sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  FLOATINGPOINT_ISINF,
+  /**
+   * Floating-point is NaN.
+   * Parameters: 1
+   *   -[1]: Term of floating point sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  FLOATINGPOINT_ISNAN,
+  /**
+   * Floating-point is negative.
+   * Parameters: 1
+   *   -[1]: Term of floating point sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  FLOATINGPOINT_ISNEG,
+  /**
+   * Floating-point is positive.
+   * Parameters: 1
+   *   -[1]: Term of floating point sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  FLOATINGPOINT_ISPOS,
+  /**
+   * Operator for to_fp from bit vector.
+   * Parameters: 2
+   *   -[1]: Exponent size
+   *   -[2]: Significand size
+   * Create with:
+   *   mkOp(Kind kind, uint32_t param1, uint32_t param2)
+   *
+   * Conversion from an IEEE-754 bit vector to floating-point.
+   * Parameters: 2
+   *   -[1]: Op of kind FLOATINGPOINT_TO_FP_IEEE_BITVECTOR
+   *   -[2]: Term of sort FloatingPoint
+   * Create with:
+   *   mkTerm(Op op, Term child)
+   *   mkTerm(Op op, const std::vector<Term>& children)
+   */
+  FLOATINGPOINT_TO_FP_IEEE_BITVECTOR,
+  /**
+   * Operator for to_fp from floating point.
+   * Parameters: 2
+   *   -[1]: Exponent size
+   *   -[2]: Significand size
+   * Create with:
+   *   mkOp(Kind kind, uint32_t param1, uint32_t param2)
+   *
+   * Conversion between floating-point sorts.
+   * Parameters: 2
+   *   -[1]: Op of kind FLOATINGPOINT_TO_FP_FLOATINGPOINT
+   *   -[2]: Term of sort FloatingPoint
+   * Create with:
+   *   mkTerm(Op op, Term child)
+   *   mkTerm(Op op, const std::vector<Term>& children)
+   */
+  FLOATINGPOINT_TO_FP_FLOATINGPOINT,
+  /**
+   * Operator for to_fp from real.
+   * Parameters: 2
+   *   -[1]: Exponent size
+   *   -[2]: Significand size
+   * Create with:
+   *   mkOp(Kind kind, uint32_t param1, uint32_t param2)
+   *
+   * Conversion from a real to floating-point.
+   * Parameters: 2
+   *   -[1]: Op of kind FLOATINGPOINT_TO_FP_REAL
+   *   -[2]: Term of sort FloatingPoint
+   * Create with:
+   *   mkTerm(Op op, Term child)
+   *   mkTerm(Op op, const std::vector<Term>& children)
+   */
+  FLOATINGPOINT_TO_FP_REAL,
+  /*
+   * Operator for to_fp from signed bit vector.
+   * Parameters: 2
+   *   -[1]: Exponent size
+   *   -[2]: Significand size
+   * Create with:
+   *   mkOp(Kind kind, uint32_t param1, uint32_t param2)
+   *
+   * Conversion from a signed bit vector to floating-point.
+   * Parameters: 2
+   *   -[1]: Op of kind FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR
+   *   -[2]: Term of sort FloatingPoint
+   * Create with:
+   *   mkTerm(Op op, Term child)
+   *   mkTerm(Op op, const std::vector<Term>& children)
+   */
+  FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR,
+  /**
+   * Operator for to_fp from unsigned bit vector.
+   * Parameters: 2
+   *   -[1]: Exponent size
+   *   -[2]: Significand size
+   * Create with:
+   *   mkOp(Kind kind, uint32_t param1, uint32_t param2)
+   *
+   * Converting an unsigned bit vector to floating-point.
+   * Parameters: 2
+   *   -[1]: Op of kind FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR
+   *   -[2]: Term of sort FloatingPoint
+   * Create with:
+   *   mkTerm(Op op, Term child)
+   *   mkTerm(Op op, const std::vector<Term>& children)
+   */
+  FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR,
+  /**
+   * Operator for a generic to_fp.
+   * Parameters: 2
+   *   -[1]: exponent size
+   *   -[2]: Significand size
+   * Create with:
+   *   mkOp(Kind kind, uint32_t param1, uint32_t param2)
+   *
+   * Generic conversion to floating-point, used in parsing only.
+   * Parameters: 2
+   *   -[1]: Op of kind FLOATINGPOINT_TO_FP_GENERIC
+   *   -[2]: Term of sort FloatingPoint
+   * Create with:
+   *   mkTerm(Op op, Term child)
+   *   mkTerm(Op op, const std::vector<Term>& children)
+   */
+  FLOATINGPOINT_TO_FP_GENERIC,
+  /**
+   * Operator for to_ubv.
+   * Parameters: 1
+   *   -[1]: Size of the bit-vector to convert to
+   * Create with:
+   *   mkOp(Kind kind, uint32_t param)
+   *
+   * Conversion from a floating-point value to an unsigned bit vector.
+   * Parameters: 2
+   *   -[1]: Op of kind FLOATINGPOINT_TO_FP_TO_UBV
+   *   -[2]: Term of sort FloatingPoint
+   * Create with:
+   *   mkTerm(Op op, Term child)
+   *   mkTerm(Op op, const std::vector<Term>& children)
+   */
+  FLOATINGPOINT_TO_UBV,
+  /**
+   * Operator for to_sbv.
+   * Parameters: 1
+   *   -[1]: Size of the bit-vector to convert to
+   * Create with:
+   *   mkOp(Kind kind, uint32_t param)
+   *
+   * Conversion from a floating-point value to a signed bit vector.
+   * Parameters: 2
+   *   -[1]: Op of kind FLOATINGPOINT_TO_FP_TO_SBV
+   *   -[2]: Term of sort FloatingPoint
+   * Create with:
+   *   mkTerm(Op op, Term child)
+   *   mkTerm(Op op, const std::vector<Term>& children)
+   */
+  FLOATINGPOINT_TO_SBV,
+  /**
+   * Floating-point to real.
+   * Parameters: 1
+   *   -[1]: Term of sort FloatingPoint
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  FLOATINGPOINT_TO_REAL,
+
+  /* Arrays ---------------------------------------------------------------- */
+
+  /**
+   * Aarray select.
+   * Parameters: 2
+   *   -[1]: Term of array sort
+   *   -[2]: Selection index
+   * Create with:
+   *   mkTerm(Op op, Term child1, Term child2)
+   *   mkTerm(Op op, const std::vector<Term>& children)
+   */
+  SELECT,
+  /**
+   * Array store.
+   * Parameters: 3
+   *   -[1]: Term of array sort
+   *   -[2]: Store index
+   *   -[3]: Term to store at the index
+   * Create with:
+   *   mkTerm(Op op, Term child1, Term child2, Term child3)
+   *   mkTerm(Op op, const std::vector<Term>& children)
+   */
+  STORE,
+  /**
+   * Constant array.
+   * Parameters: 2
+   *   -[1]: Array sort
+   *   -[2]: Term representing a constant
+   * Create with:
+   *   mkTerm(Op op, Term child1, Term child2)
+   *   mkTerm(Op op, const std::vector<Term>& children)
+   *
+   * Note: We currently support the creation of constant arrays, but under some
+   * conditions when there is a chain of equalities connecting two constant
+   * arrays, the solver doesn't know what to do and aborts (Issue #1667).
+   */
+  CONST_ARRAY,
+  /**
+   * Equality over arrays a and b over a given range [i,j], i.e.,
+   * \forall k . i <= k <= j --> a[k] = b[k]
+   *
+   * Parameters: 4
+   *   -[1]: First array
+   *   -[2]: Second array
+   *   -[3]: Lower bound of range (inclusive)
+   *   -[4]: Uppper bound of range (inclusive)
+   * Create with:
+   *   mkTerm(Op op, const std::vector<Term>& children)
+   *
+   * Note: We currently support the creation of array equalities over index
+   * types bit-vector, floating-point, integer and real. Option --arrays-exp is
+   * required to support this operator.
+   */
+  EQ_RANGE,
+#if 0
+  /* array table function (internal-only symbol) */
+  ARR_TABLE_FUN,
+  /* array lambda (internal-only symbol) */
+  ARRAY_LAMBDA,
+  /* partial array select, for internal use only */
+  PARTIAL_SELECT_0,
+  /* partial array select, for internal use only */
+  PARTIAL_SELECT_1,
+#endif
+
+  /* Datatypes ------------------------------------------------------------- */
+
+  /**
+   * Constructor application.
+   * Paramters: n > 0
+   *   -[1]: Constructor (operator)
+   *   -[2]..[n]: Parameters to the constructor
+   * Create with:
+   *   mkTerm(Kind kind, Op op)
+   *   mkTerm(Kind kind, Op op, Term child)
+   *   mkTerm(Kind kind, Op op, Term child1, Term child2)
+   *   mkTerm(Kind kind, Op op, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, Op op, const std::vector<Term>& children)
+   */
+  APPLY_CONSTRUCTOR,
+  /**
+   * Datatype selector application.
+   * Parameters: 1
+   *   -[1]: Selector (operator)
+   *   -[2]: Datatype term (undefined if mis-applied)
+   * Create with:
+   *   mkTerm(Kind kind, Op op, Term child)
+   */
+  APPLY_SELECTOR,
+  /**
+   * Datatype tester application.
+   * Parameters: 2
+   *   -[1]: Tester term
+   *   -[2]: Datatype term
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  APPLY_TESTER,
+#if 0
+  /* Parametric datatype term.  */
+  PARAMETRIC_DATATYPE,
+  /* type ascription, for datatype constructor applications;
+   * first parameter is an ASCRIPTION_TYPE, second is the datatype constructor
+   * application being ascribed */
+  APPLY_TYPE_ASCRIPTION,
+#endif
+  /**
+   * Operator for a tuple update.
+   * Parameters: 1
+   *   -[1]: Index of the tuple to be updated
+   * Create with:
+   *   mkOp(Kind kind, uint32_t param)
+   *
+   * Apply tuple update.
+   * Parameters: 3
+   *   -[1]: Op of kind TUPLE_UPDATE (which references an index)
+   *   -[2]: Tuple
+   *   -[3]: Element to store in the tuple at the given index
+   * Create with:
+   *   mkTerm(Op op, Term child1, Term child2)
+   *   mkTerm(Op op, const std::vector<Term>& children)
+   */
+  TUPLE_UPDATE,
+  /**
+   * Operator for a record update.
+   * Parameters: 1
+   *   -[1]: Name of the field to be updated
+   * Create with:
+   *   mkOp(Kind kind, const std::string& param)
+   *
+   * Record update.
+   * Parameters: 3
+   *   -[1]: Op of kind RECORD_UPDATE (which references a field)
+   *   -[2]: Record term to update
+   *   -[3]: Element to store in the record in the given field
+   * Create with:
+   *   mkTerm(Op op, Term child1, Term child2)
+   *   mkTerm(Op op,, const std::vector<Term>& children)
+   */
+  RECORD_UPDATE,
+  /* Match expressions.
+   * For example, the smt2 syntax match term
+   *   (match l (((cons h t) h) (nil 0)))
+   * is represented by the AST
+   * (MATCH l
+   *   (MATCH_BIND_CASE (BOUND_VAR_LIST h t) (cons h t) h)
+   *   (MATCH_CASE nil 0))
+   * The type of the last argument of each case term could be equal.
+   * Parameters: n > 1
+   *   -[1]..[n]: Terms of kind MATCH_CASE or MATCH_BIND_CASE
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   *
+   */
+  MATCH,
+  /* Match case
+   * A (constant) case expression to be used within a match expression.
+   * Parameters: 2
+   *   -[1] Term denoting the pattern expression
+   *   -[2] Term denoting the return value
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  MATCH_CASE,
+  /* Match bind case
+   * A (non-constant) case expression to be used within a match expression.
+   * Parameters: 3
+   *   -[1] a BOUND_VAR_LIST Term containing the free variables of the case
+   *   -[2] Term denoting the pattern expression
+   *   -[3] Term denoting the return value
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  MATCH_BIND_CASE,
+  /*
+   * Datatypes size
+   * An operator mapping datatypes to an integer denoting the number of
+   * non-nullary applications of constructors they contain.
+   * Parameters: 1
+   *   -[1]: Datatype term
+   * Create with:
+   *   mkTerm(Kind kind, Term child1)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  DT_SIZE,
+  /**
+   * Operator for tuple projection indices
+   * Parameters: 1
+   *   -[1]: The tuple projection indices
+   * Create with:
+   *   mkOp(Kind TUPLE_PROJECT, std::vector<uint32_t> param)
+   *
+   * constructs a new tuple from an existing one using the elements at the
+   * given indices
+   * Parameters: 1
+   *   -[1]: a term of tuple sort
+   * Create with:
+   *   mkTerm(Op op, Term child)
+   *   mkTerm(Op op, const std::vector<Term>& children)
+   */
+  TUPLE_PROJECT,
+#if 0
+  /* datatypes height bound */
+  DT_HEIGHT_BOUND,
+  /* datatypes height bound */
+  DT_SIZE_BOUND,
+  /* datatypes sygus bound */
+  DT_SYGUS_BOUND,
+  /* datatypes sygus term order */
+  DT_SYGUS_TERM_ORDER,
+  /* datatypes sygus is constant */
+  DT_SYGUS_IS_CONST,
+#endif
+
+  /* Separation Logic ------------------------------------------------------ */
+
+  /**
+   * Separation logic nil term.
+   * Parameters: 0
+   * Create with:
+   *   mkSepNil(Sort sort)
+   */
+  SEP_NIL,
+  /**
+   * Separation logic empty heap.
+   * Parameters: 2
+   *   -[1]: Term of the same sort as the sort of the location of the heap
+   *         that is constrained to be empty
+   *   -[2]: Term of the same sort as the data sort of the heap that is
+   *         that is constrained to be empty
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  SEP_EMP,
+  /**
+   * Separation logic points-to relation.
+   * Parameters: 2
+   *   -[1]: Location of the points-to constraint
+   *   -[2]: Data of the points-to constraint
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  SEP_PTO,
+  /**
+   * Separation logic star.
+   * Parameters: n >= 2
+   *   -[1]..[n]: Child constraints that hold in disjoint (separated) heaps
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  SEP_STAR,
+  /**
+   * Separation logic magic wand.
+   * Parameters: 2
+   *   -[1]: Antecendant of the magic wand constraint
+   *   -[2]: Conclusion of the magic wand constraint, which is asserted to
+   *         hold in all heaps that are disjoint extensions of the antecedent.
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  SEP_WAND,
+#if 0
+  /* separation label (internal use only) */
+  SEP_LABEL,
+#endif
+
+  /* Sets ------------------------------------------------------------------ */
+
+  /**
+   * Empty set constant.
+   * Parameters: 1
+   *   -[1]: Sort of the set elements
+   * Create with:
+   *   mkEmptySet(Sort sort)
+   */
+  EMPTYSET,
+  /**
+   * Set union.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of set sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  UNION,
+  /**
+   * Set intersection.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of set sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  INTERSECTION,
+  /**
+   * Set subtraction.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of set sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  SETMINUS,
+  /**
+   * Subset predicate.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of set sort, [1] a subset of set [2]?
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  SUBSET,
+  /**
+   * Set membership predicate.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of set sort, [1] a member of set [2]?
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  MEMBER,
+  /**
+   * Construct a singleton set from an element given as a parameter.
+   * The returned set has same type of the element.
+   * Parameters: 1
+   *   -[1]: Single element
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  SINGLETON,
+  /**
+   * The set obtained by inserting elements;
+   * Parameters: n > 0
+   *   -[1]..[n-1]: Elements inserted into set [n]
+   *   -[n]: Set Term
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  INSERT,
+  /**
+   * Set cardinality.
+   * Parameters: 1
+   *   -[1]: Set to determine the cardinality of
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  CARD,
+  /**
+   * Set complement with respect to finite universe.
+   * Parameters: 1
+   *   -[1]: Set to complement
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  COMPLEMENT,
+  /**
+   * Finite universe set.
+   * All set variables must be interpreted as subsets of it.
+   * Create with:
+   *   mkUniverseSet(Sort sort)
+   */
+  UNIVERSE_SET,
+  /**
+   * Set join.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of set sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  JOIN,
+  /**
+   * Set cartesian product.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of set sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  PRODUCT,
+  /**
+   * Set transpose.
+   * Parameters: 1
+   *   -[1]: Term of set sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  TRANSPOSE,
+  /**
+   * Set transitive closure.
+   * Parameters: 1
+   *   -[1]: Term of set sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  TCLOSURE,
+  /**
+   * Set join image.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of set sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  JOIN_IMAGE,
+  /**
+   * Set identity.
+   * Parameters: 1
+   *   -[1]: Term of set sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  IDEN,
+  /**
+   * Set comprehension
+   * A set comprehension is specified by a bound variable list x1 ... xn,
+   * a predicate P[x1...xn], and a term t[x1...xn]. A comprehension C with the
+   * above form has members given by the following semantics:
+   * forall y. ( exists x1...xn. P[x1...xn] ^ t[x1...xn] = y ) <=> (member y C)
+   * where y ranges over the element type of the (set) type of the
+   * comprehension. If t[x1..xn] is not provided, it is equivalent to y in the
+   * above formula.
+   * Parameters: 2 (3)
+   *   -[1]: Term BOUND_VAR_LIST
+   *   -[2]: Term denoting the predicate of the comprehension
+   *   -[3]: (optional) a Term denoting the generator for the comprehension
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  COMPREHENSION,
+  /**
+   * Returns an element from a given set.
+   * If a set A = {x}, then the term (choose A) is equivalent to the term x.
+   * If the set is empty, then (choose A) is an arbitrary value.
+   * If the set has cardinality > 1, then (choose A) will deterministically
+   * return an element in A.
+   * Parameters: 1
+   *   -[1]: Term of set sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  CHOOSE,
+  /**
+   * Set is_singleton predicate.
+   * Parameters: 1
+   *   -[1]: Term of set sort, is [1] a singleton set?
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  IS_SINGLETON,
+  /* Bags ------------------------------------------------------------------ */
+  /**
+   * Empty bag constant.
+   * Parameters: 1
+   *   -[1]: Sort of the bag elements
+   * Create with:
+   *   mkEmptyBag(Sort sort)
+   */
+  EMPTYBAG,
+  /**
+   * Bag max union.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of bag sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  UNION_MAX,
+  /**
+   * Bag disjoint union (sum).
+   * Parameters: 2
+   *   -[1]..[2]: Terms of bag sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  UNION_DISJOINT,
+  /**
+   * Bag intersection (min).
+   * Parameters: 2
+   *   -[1]..[2]: Terms of bag sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  INTERSECTION_MIN,
+  /**
+   * Bag difference subtract (subtracts multiplicities of the second from the
+   * first).
+   * Parameters: 2
+   *   -[1]..[2]: Terms of bag sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  DIFFERENCE_SUBTRACT,
+  /**
+   * Bag difference 2 (removes shared elements in the two bags).
+   * Parameters: 2
+   *   -[1]..[2]: Terms of bag sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  DIFFERENCE_REMOVE,
+  /**
+   * Inclusion predicate for bags
+   * (multiplicities of the first bag <= multiplicities of the second bag).
+   * Parameters: 2
+   *   -[1]..[2]: Terms of bag sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  SUBBAG,
+  /**
+   * Element multiplicity in a bag
+   * Parameters: 2
+   *   -[1]..[2]: Terms of bag sort (Bag E), [1] an element of sort E
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BAG_COUNT,
+  /**
+   * Eliminate duplicates in a given bag. The returned bag contains exactly the
+   * same elements in the given bag, but with multiplicity one.
+   * Parameters: 1
+   *   -[1]: a term of bag sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  DUPLICATE_REMOVAL,
+  /**
+   * The bag of the single element given as a parameter.
+   * Parameters: 1
+   *   -[1]: Single element
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  MK_BAG,
+  /**
+   * Bag cardinality.
+   * Parameters: 1
+   *   -[1]: Bag to determine the cardinality of
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  BAG_CARD,
+  /**
+   * Returns an element from a given bag.
+   * If a bag A = {(x,n)} where n is the multiplicity, then the term (choose A)
+   * is equivalent to the term x.
+   * If the bag is empty, then (choose A) is an arbitrary value.
+   * If the bag contains distinct elements, then (choose A) will
+   * deterministically return an element in A.
+   * Parameters: 1
+   *   -[1]: Term of bag sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  BAG_CHOOSE,
+  /**
+   * Bag is_singleton predicate (single element with multiplicity exactly one).
+   * Parameters: 1
+   *   -[1]: Term of bag sort, is [1] a singleton bag?
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  BAG_IS_SINGLETON,
+  /**
+   * Bag.from_set converts a set to a bag.
+   * Parameters: 1
+   *   -[1]: Term of set sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  BAG_FROM_SET,
+  /**
+   * Bag.to_set converts a bag to a set.
+   * Parameters: 1
+   *   -[1]: Term of bag sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  BAG_TO_SET,
+
+  /* Strings --------------------------------------------------------------- */
+
+  /**
+   * String concat.
+   * Parameters: n > 1
+   *   -[1]..[n]: Terms of String sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  STRING_CONCAT,
+  /**
+   * String membership.
+   * Parameters: 2
+   *   -[1]: Term of String sort
+   *   -[2]: Term of RegExp sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  STRING_IN_REGEXP,
+  /**
+   * String length.
+   * Parameters: 1
+   *   -[1]: Term of String sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  STRING_LENGTH,
+  /**
+   * String substring.
+   * Extracts a substring, starting at index i and of length l, from a string
+   * s.  If the start index is negative, the start index is greater than the
+   * length of the string, or the length is negative, the result is the empty
+   * string.
+   * Parameters: 3
+   *   -[1]: Term of sort String
+   *   -[2]: Term of sort Integer (index i)
+   *   -[3]: Term of sort Integer (length l)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  STRING_SUBSTR,
+  /**
+   * String update.
+   * Updates a string s by replacing its context starting at an index with t.
+   * If the start index is negative, the start index is greater than the
+   * length of the string, the result is s. Otherwise, the length of the
+   * original string is preserved.
+   * Parameters: 3
+   *   -[1]: Term of sort String
+   *   -[2]: Term of sort Integer (index i)
+   *   -[3]: Term of sort String (replacement string t)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  STRING_UPDATE,
+  /**
+   * String character at.
+   * Returns the character at index i from a string s. If the index is negative
+   * or the index is greater than the length of the string, the result is the
+   * empty string. Otherwise the result is a string of length 1.
+   * Parameters: 2
+   *   -[1]: Term of sort String (string s)
+   *   -[2]: Term of sort Integer (index i)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  STRING_CHARAT,
+  /**
+   * String contains.
+   * Checks whether a string s1 contains another string s2. If s2 is empty, the
+   * result is always true.
+   * Parameters: 2
+   *   -[1]: Term of sort String (the string s1)
+   *   -[2]: Term of sort String (the string s2)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  STRING_CONTAINS,
+  /**
+   * String index-of.
+   * Returns the index of a substring s2 in a string s1 starting at index i. If
+   * the index is negative or greater than the length of string s1 or the
+   * substring s2 does not appear in string s1 after index i, the result is -1.
+   * Parameters: 3
+   *   -[1]: Term of sort String (substring s1)
+   *   -[2]: Term of sort String (substring s2)
+   *   -[3]: Term of sort Integer (index i)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  STRING_INDEXOF,
+  /**
+   * String replace.
+   * Replaces a string s2 in a string s1 with string s3. If s2 does not appear
+   * in s1, s1 is returned unmodified.
+   * Parameters: 3
+   *   -[1]: Term of sort String (string s1)
+   *   -[2]: Term of sort String (string s2)
+   *   -[3]: Term of sort String (string s3)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  STRING_REPLACE,
+  /**
+   * String replace all.
+   * Replaces all occurrences of a string s2 in a string s1 with string s3.
+   * If s2 does not appear in s1, s1 is returned unmodified.
+   * Parameters: 3
+   *   -[1]: Term of sort String (string s1)
+   *   -[2]: Term of sort String (string s2)
+   *   -[3]: Term of sort String (string s3)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  STRING_REPLACE_ALL,
+  /**
+   * String replace regular expression match.
+   * Replaces the first match of a regular expression r in string s1 with
+   * string s2. If r does not match a substring of s1, s1 is returned
+   * unmodified.
+   * Parameters: 3
+   *   -[1]: Term of sort String (string s1)
+   *   -[2]: Term of sort Regexp (regexp r)
+   *   -[3]: Term of sort String (string s2)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  STRING_REPLACE_RE,
+  /**
+   * String replace all regular expression matches.
+   * Replaces all matches of a regular expression r in string s1 with string
+   * s2. If r does not match a substring of s1, s1 is returned unmodified.
+   * Parameters: 3
+   *   -[1]: Term of sort String (string s1)
+   *   -[2]: Term of sort Regexp (regexp r)
+   *   -[3]: Term of sort String (string s2)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  STRING_REPLACE_RE_ALL,
+  /**
+   * String to lower case.
+   * Parameters: 1
+   *   -[1]: Term of String sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  STRING_TOLOWER,
+  /**
+   * String to upper case.
+   * Parameters: 1
+   *   -[1]: Term of String sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  STRING_TOUPPER,
+  /**
+   * String reverse.
+   * Parameters: 1
+   *   -[1]: Term of String sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  STRING_REV,
+  /**
+   * String to code.
+   * Returns the code point of a string if it has length one, or returns -1
+   * otherwise.
+   * Parameters: 1
+   *   -[1]: Term of String sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  STRING_TO_CODE,
+  /**
+   * String from code.
+   * Returns a string containing a single character whose code point matches
+   * the argument to this function, or the empty string if the argument is
+   * out-of-bounds.
+   * Parameters: 1
+   *   -[1]: Term of Integer sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  STRING_FROM_CODE,
+  /**
+   * String less than.
+   * Returns true if string s1 is (strictly) less than s2 based on a
+   * lexiographic ordering over code points.
+   * Parameters: 2
+   *   -[1]: Term of sort String (the string s1)
+   *   -[2]: Term of sort String (the string s2)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  STRING_LT,
+  /**
+   * String less than or equal.
+   * Returns true if string s1 is less than or equal to s2 based on a
+   * lexiographic ordering over code points.
+   * Parameters: 2
+   *   -[1]: Term of sort String (the string s1)
+   *   -[2]: Term of sort String (the string s2)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  STRING_LEQ,
+  /**
+   * String prefix-of.
+   * Checks whether a string s1 is a prefix of string s2. If string s1 is
+   * empty, this operator returns true.
+   * Parameters: 2
+   *   -[1]: Term of sort String (string s1)
+   *   -[2]: Term of sort String (string s2)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  STRING_PREFIX,
+  /**
+   * String suffix-of.
+   * Checks whether a string s1 is a suffix of string 2. If string s1 is empty,
+   * this operator returns true.
+   * Parameters: 2
+   *   -[1]: Term of sort String (string s1)
+   *   -[2]: Term of sort String (string s2)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  STRING_SUFFIX,
+  /**
+   * String is-digit.
+   * Returns true if string s is digit (it is one of "0", ..., "9").
+   * Parameters: 1
+   *   -[1]: Term of sort String
+   * Create with:
+   *   mkTerm(Kind kind, Term child1)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  STRING_IS_DIGIT,
+  /**
+   * Integer to string.
+   * If the integer is negative this operator returns the empty string.
+   * Parameters: 1
+   *   -[1]: Term of sort Integer
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  STRING_FROM_INT,
+  /**
+   * String to integer (total function).
+   * If the string does not contain an integer or the integer is negative, the
+   * operator returns -1.
+   * Parameters: 1
+   *   -[1]: Term of sort String
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  STRING_TO_INT,
+  /**
+   * Constant string.
+   * Parameters:
+   *   See mkString()
+   * Create with:
+   *   mkString(const char* s)
+   *   mkString(const std::string& s)
+   *   mkString(const unsigned char c)
+   *   mkString(const std::vector<unsigned>& s)
+   */
+  CONST_STRING,
+  /**
+   * Conversion from string to regexp.
+   * Parameters: 1
+   *   -[1]: Term of sort String
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  STRING_TO_REGEXP,
+  /**
+   * Regexp Concatenation .
+   * Parameters: 2
+   *   -[1]..[2]: Terms of Regexp sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  REGEXP_CONCAT,
+  /**
+   * Regexp union.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of Regexp sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  REGEXP_UNION,
+  /**
+   * Regexp intersection.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of Regexp sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  REGEXP_INTER,
+  /**
+   * Regexp difference.
+   * Parameters: 2
+   *   -[1]..[2]: Terms of Regexp sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  REGEXP_DIFF,
+  /**
+   * Regexp *.
+   * Parameters: 1
+   *   -[1]: Term of sort Regexp
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  REGEXP_STAR,
+  /**
+   * Regexp +.
+   * Parameters: 1
+   *   -[1]: Term of sort Regexp
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  REGEXP_PLUS,
+  /**
+   * Regexp ?.
+   * Parameters: 1
+   *   -[1]: Term of sort Regexp
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  REGEXP_OPT,
+  /**
+   * Regexp range.
+   * Parameters: 2
+   *   -[1]: Lower bound character for the range
+   *   -[2]: Upper bound character for the range
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  REGEXP_RANGE,
+  /**
+   * Operator for regular expression repeat.
+   * Parameters: 1
+   *   -[1]: The number of repetitions
+   * Create with:
+   *   mkOp(Kind kind, uint32_t param)
+   *
+   * Apply regular expression loop.
+   * Parameters: 2
+   *   -[1]: Op of kind REGEXP_REPEAT
+   *   -[2]: Term of regular expression sort
+   * Create with:
+   *   mkTerm(Op op, Term child)
+   *   mkTerm(Op op, const std::vector<Term>& children)
+   */
+  REGEXP_REPEAT,
+  /**
+   * Operator for regular expression loop, from lower bound to upper bound
+   * number of repetitions.
+   * Parameters: 2
+   *   -[1]: The lower bound
+   *   -[2]: The upper bound
+   * Create with:
+   *   mkOp(Kind kind, uint32_t param, uint32_t param)
+   *
+   * Apply regular expression loop.
+   * Parameters: 2
+   *   -[1]: Op of kind REGEXP_LOOP
+   *   -[2]: Term of regular expression sort
+   * Create with:
+   *   mkTerm(Op op, Term child)
+   *   mkTerm(Op op, const std::vector<Term>& children)
+   */
+  REGEXP_LOOP,
+  /**
+   * Regexp empty.
+   * Parameters: 0
+   * Create with:
+   *   mkRegexpEmpty()
+   *   mkTerm(Kind kind)
+   */
+  REGEXP_EMPTY,
+  /**
+   * Regexp all characters.
+   * Parameters: 0
+   * Create with:
+   *   mkRegexpSigma()
+   *   mkTerm(Kind kind)
+   */
+  REGEXP_SIGMA,
+  /**
+   * Regexp complement.
+   * Parameters: 1
+   *   -[1]: Term of sort RegExp
+   * Create with:
+   *   mkTerm(Kind kind, Term child1)
+   */
+  REGEXP_COMPLEMENT,
+
+  /**
+   * Sequence concat.
+   * Parameters: n > 1
+   *   -[1]..[n]: Terms of Sequence sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  SEQ_CONCAT,
+  /**
+   * Sequence length.
+   * Parameters: 1
+   *   -[1]: Term of Sequence sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  SEQ_LENGTH,
+  /**
+   * Sequence extract.
+   * Extracts a subsequence, starting at index i and of length l, from a
+   * sequence s.  If the start index is negative, the start index is greater
+   * than the length of the sequence, or the length is negative, the result is
+   * the empty sequence. Parameters: 3
+   *   -[1]: Term of sort Sequence
+   *   -[2]: Term of sort Integer (index i)
+   *   -[3]: Term of sort Integer (length l)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  SEQ_EXTRACT,
+  /**
+   * Sequence update.
+   * Updates a sequence s by replacing its context starting at an index with t.
+   * If the start index is negative, the start index is greater than the
+   * length of the sequence, the result is s. Otherwise, the length of the
+   * original sequence is preserved.
+   * Parameters: 3
+   *   -[1]: Term of sort Sequence
+   *   -[2]: Term of sort Integer (index i)
+   *   -[3]: Term of sort Sequence (replacement sequence t)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  SEQ_UPDATE,
+  /**
+   * Sequence element at.
+   * Returns the element at index i from a sequence s. If the index is negative
+   * or the index is greater or equal to the length of the sequence, the result
+   * is the empty sequence. Otherwise the result is a sequence of length 1.
+   * Parameters: 2
+   *   -[1]: Term of sequence sort (string s)
+   *   -[2]: Term of sort Integer (index i)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  SEQ_AT,
+  /**
+   * Sequence contains.
+   * Checks whether a sequence s1 contains another sequence s2. If s2 is empty,
+   * the result is always true. Parameters: 2
+   *   -[1]: Term of sort Sequence (the sequence s1)
+   *   -[2]: Term of sort Sequence (the sequence s2)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  SEQ_CONTAINS,
+  /**
+   * Sequence index-of.
+   * Returns the index of a subsequence s2 in a sequence s1 starting at index i.
+   * If the index is negative or greater than the length of sequence s1 or the
+   * subsequence s2 does not appear in sequence s1 after index i, the result is
+   * -1. Parameters: 3
+   *   -[1]: Term of sort Sequence (subsequence s1)
+   *   -[2]: Term of sort Sequence (subsequence s2)
+   *   -[3]: Term of sort Integer (index i)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  SEQ_INDEXOF,
+  /**
+   * Sequence replace.
+   * Replaces the first occurrence of a sequence s2 in a sequence s1 with
+   * sequence s3. If s2 does not appear in s1, s1 is returned unmodified.
+   * Parameters: 3
+   *   -[1]: Term of sort Sequence (sequence s1)
+   *   -[2]: Term of sort Sequence (sequence s2)
+   *   -[3]: Term of sort Sequence (sequence s3)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  SEQ_REPLACE,
+  /**
+   * Sequence replace all.
+   * Replaces all occurrences of a sequence s2 in a sequence s1 with sequence
+   * s3. If s2 does not appear in s1, s1 is returned unmodified. Parameters: 3
+   *   -[1]: Term of sort Sequence (sequence s1)
+   *   -[2]: Term of sort Sequence (sequence s2)
+   *   -[3]: Term of sort Sequence (sequence s3)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  SEQ_REPLACE_ALL,
+  /**
+   * Sequence reverse.
+   * Parameters: 1
+   *   -[1]: Term of Sequence sort
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  SEQ_REV,
+  /**
+   * Sequence prefix-of.
+   * Checks whether a sequence s1 is a prefix of sequence s2. If sequence s1 is
+   * empty, this operator returns true.
+   * Parameters: 2
+   *   -[1]: Term of sort Sequence (sequence s1)
+   *   -[2]: Term of sort Sequence (sequence s2)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  SEQ_PREFIX,
+  /**
+   * Sequence suffix-of.
+   * Checks whether a sequence s1 is a suffix of sequence s2. If sequence s1 is
+   * empty, this operator returns true. Parameters: 2
+   *   -[1]: Term of sort Sequence (sequence s1)
+   *   -[2]: Term of sort Sequence (sequence s2)
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  SEQ_SUFFIX,
+  /**
+   * Constant sequence.
+   * Parameters:
+   *   See mkEmptySequence()
+   * Create with:
+   *   mkEmptySequence(Sort sort)
+   * Note that a constant sequence is a term that is equivalent to:
+   *   (seq.++ (seq.unit c1) ... (seq.unit cn))
+   * where n>=0 and c1, ..., cn are constants of some sort. The elements
+   * can be extracted by Term::getConstSequenceElements().
+   */
+  CONST_SEQUENCE,
+  /**
+   * Sequence unit, corresponding to a sequence of length one with the given
+   * term.
+   * Parameters: 1
+   *   -[1] Element term.
+   * Create with:
+   *   mkTerm(Kind kind, Term child1)
+   */
+  SEQ_UNIT,
+  /**
+   * Sequence nth, corresponding to the nth element of a sequence.
+   * Parameters: 2
+   *   -[1] Sequence term.
+   *   -[2] Integer term.
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   */
+  SEQ_NTH,
+
+  /* Quantifiers ----------------------------------------------------------- */
+
+  /**
+   * Universally quantified formula.
+   * Parameters: 2 (3)
+   *   -[1]: BOUND_VAR_LIST Term
+   *   -[2]: Quantifier body
+   *   -[3]: (optional) INST_PATTERN_LIST Term
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  FORALL,
+  /**
+   * Existentially quantified formula.
+   * Parameters: 2 (3)
+   *   -[1]: BOUND_VAR_LIST Term
+   *   -[2]: Quantifier body
+   *   -[3]: (optional) INST_PATTERN_LIST Term
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  EXISTS,
+  /*
+   * A list of bound variables (used to bind variables under a quantifier)
+   * Parameters: n > 1
+   *   -[1]..[n]: Terms with kind BOUND_VARIABLE
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  BOUND_VAR_LIST,
+  /*
+   * An instantiation pattern.
+   * Specifies a (list of) terms to be used as a pattern for quantifier
+   * instantiation.
+   * Parameters: n > 1
+   *   -[1]..[n]: Terms with kind BOUND_VARIABLE
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  INST_PATTERN,
+  /*
+   * An instantiation no-pattern.
+   * Specifies a (list of) terms that should not be used as a pattern for
+   * quantifier instantiation.
+   * Parameters: n > 1
+   *   -[1]..[n]: Terms with kind BOUND_VARIABLE
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  INST_NO_PATTERN,
+  /*
+   * An instantiation attribute
+   * Specifies a custom property for a quantified formula given by a
+   * term that is ascribed a user attribute.
+   * Parameters: 1
+   *   -[1]: Term with a user attribute.
+   * Create with:
+   *   mkTerm(Kind kind, Term child)
+   */
+  INST_ATTRIBUTE,
+  /*
+   * A list of instantiation patterns and/or attributes.
+   * Parameters: n > 1
+   *   -[1]..[n]: Terms with kind INST_PATTERN, INST_NO_PATTERN, or
+   * INST_ATTRIBUTE.
+   * Create with:
+   *   mkTerm(Kind kind, Term child1, Term child2)
+   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
+   *   mkTerm(Kind kind, const std::vector<Term>& children)
+   */
+  INST_PATTERN_LIST,
+#if 0
+
+  /* Sort Kinds ------------------------------------------------------------ */
+
+  /* array type */
+   ARRAY_TYPE,
+  /* a type parameter for type ascription */
+  ASCRIPTION_TYPE,
+  /* constructor */
+  CONSTRUCTOR_TYPE,
+  /* a datatype type index */
+  DATATYPE_TYPE,
+  /* selector */
+  SELECTOR_TYPE,
+  /* set type, takes as parameter the type of the elements */
+  SET_TYPE,
+  /* bag type, takes as parameter the type of the elements */
+  BAG_TYPE,
+  /* sort tag */
+  SORT_TAG,
+  /* specifies types of user-declared 'uninterpreted' sorts */
+  SORT_TYPE,
+  /* tester */
+  TESTER_TYPE,
+  /* a representation for basic types */
+  TYPE_CONSTANT,
+  /* a function type */
+  FUNCTION_TYPE,
+  /* the type of a symbolic expression */
+  SEXPR_TYPE,
+  /* bit-vector type */
+  BITVECTOR_TYPE,
+  /* floating-point type */
+  FLOATINGPOINT_TYPE,
+#endif
+
+  /* ----------------------------------------------------------------------- */
+  /* marks the upper-bound of this enumeration */
+  LAST_KIND
+};
+
+/**
+ * Get the string representation of a given kind.
+ * @param k the kind
+ * @return the string representation of kind k
+ */
+std::string kindToString(Kind k) CVC4_EXPORT;
+
+/**
+ * Serialize a kind to given stream.
+ * @param out the output stream
+ * @param k the kind to be serialized to the given output stream
+ * @return the output stream
+ */
+std::ostream& operator<<(std::ostream& out, Kind k) CVC4_EXPORT;
+
+/**
+ * Hash function for Kinds.
+ */
+struct CVC4_EXPORT KindHashFunction
+{
+  size_t operator()(Kind k) const;
+};
+
+}  // namespace api
+}  // namespace cvc5
+
+#endif
diff --git a/src/api/cvc4cpp.cpp b/src/api/cvc4cpp.cpp
deleted file mode 100644 (file)
index 463fe74..0000000
+++ /dev/null
@@ -1,6901 +0,0 @@
-/*********************                                                        */
-/*! \file cvc4cpp.cpp
- ** \verbatim
- ** Top contributors (to current version):
- **   Aina Niemetz, Andrew Reynolds, Andres Noetzli
- ** This file is part of the CVC4 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.\endverbatim
- **
- ** \brief The CVC4 C++ API.
- **
- ** The CVC4 C++ API.
- **
- ** A brief note on how to guard API functions:
- **
- ** In general, we think of API guards as a fence -- they are supposed to make
- ** sure that no invalid arguments get passed into internal realms of CVC4.
- ** Thus we always want to catch such cases on the API level (and can then
- ** assert internally that no invalid argument is passed in).
- **
- ** The only special case is when we use 3rd party back-ends we have no control
- ** over, and which throw (invalid_argument) exceptions anyways. In this case,
- ** we do not replicate argument checks but delegate them to the back-end,
- ** catch thrown exceptions, and raise a CVC4ApiException.
- **
- ** Our Integer implementation, e.g., is such a special case since we support
- ** two different back end implementations (GMP, CLN). Be aware that they do
- ** not fully agree on what is (in)valid input, which requires extra checks for
- ** consistent behavior (see Solver::mkRealFromStrHelper for an example).
- **/
-
-#include "api/cvc4cpp.h"
-
-#include <cstring>
-#include <sstream>
-
-#include "api/checks.h"
-#include "base/check.h"
-#include "base/configuration.h"
-#include "expr/dtype.h"
-#include "expr/dtype_cons.h"
-#include "expr/dtype_selector.h"
-#include "expr/kind.h"
-#include "expr/metakind.h"
-#include "expr/node.h"
-#include "expr/node_algorithm.h"
-#include "expr/node_manager.h"
-#include "expr/sequence.h"
-#include "expr/type_node.h"
-#include "options/main_options.h"
-#include "options/options.h"
-#include "options/smt_options.h"
-#include "proof/unsat_core.h"
-#include "smt/model.h"
-#include "smt/smt_engine.h"
-#include "smt/smt_mode.h"
-#include "theory/logic_info.h"
-#include "theory/theory_model.h"
-#include "util/random.h"
-#include "util/result.h"
-#include "util/statistics_registry.h"
-#include "util/stats_histogram.h"
-#include "util/utility.h"
-
-namespace cvc5 {
-namespace api {
-
-/* -------------------------------------------------------------------------- */
-/* Statistics                                                                 */
-/* -------------------------------------------------------------------------- */
-
-struct Statistics
-{
-  Statistics()
-      : d_consts("api::CONSTANT"), d_vars("api::VARIABLE"), d_terms("api::TERM")
-  {
-  }
-  IntegralHistogramStat<TypeConstant> d_consts;
-  IntegralHistogramStat<TypeConstant> d_vars;
-  IntegralHistogramStat<Kind> d_terms;
-};
-
-/* -------------------------------------------------------------------------- */
-/* Kind                                                                       */
-/* -------------------------------------------------------------------------- */
-
-/* Mapping from external (API) kind to internal kind. */
-const static std::unordered_map<Kind, cvc5::Kind, KindHashFunction> s_kinds{
-    {INTERNAL_KIND, cvc5::Kind::UNDEFINED_KIND},
-    {UNDEFINED_KIND, cvc5::Kind::UNDEFINED_KIND},
-    {NULL_EXPR, cvc5::Kind::NULL_EXPR},
-    /* Builtin ------------------------------------------------------------- */
-    {UNINTERPRETED_CONSTANT, cvc5::Kind::UNINTERPRETED_CONSTANT},
-    {ABSTRACT_VALUE, cvc5::Kind::ABSTRACT_VALUE},
-    {EQUAL, cvc5::Kind::EQUAL},
-    {DISTINCT, cvc5::Kind::DISTINCT},
-    {CONSTANT, cvc5::Kind::VARIABLE},
-    {VARIABLE, cvc5::Kind::BOUND_VARIABLE},
-    {SEXPR, cvc5::Kind::SEXPR},
-    {LAMBDA, cvc5::Kind::LAMBDA},
-    {WITNESS, cvc5::Kind::WITNESS},
-    /* Boolean ------------------------------------------------------------- */
-    {CONST_BOOLEAN, cvc5::Kind::CONST_BOOLEAN},
-    {NOT, cvc5::Kind::NOT},
-    {AND, cvc5::Kind::AND},
-    {IMPLIES, cvc5::Kind::IMPLIES},
-    {OR, cvc5::Kind::OR},
-    {XOR, cvc5::Kind::XOR},
-    {ITE, cvc5::Kind::ITE},
-    {MATCH, cvc5::Kind::MATCH},
-    {MATCH_CASE, cvc5::Kind::MATCH_CASE},
-    {MATCH_BIND_CASE, cvc5::Kind::MATCH_BIND_CASE},
-    /* UF ------------------------------------------------------------------ */
-    {APPLY_UF, cvc5::Kind::APPLY_UF},
-    {CARDINALITY_CONSTRAINT, cvc5::Kind::CARDINALITY_CONSTRAINT},
-    {CARDINALITY_VALUE, cvc5::Kind::CARDINALITY_VALUE},
-    {HO_APPLY, cvc5::Kind::HO_APPLY},
-    /* Arithmetic ---------------------------------------------------------- */
-    {PLUS, cvc5::Kind::PLUS},
-    {MULT, cvc5::Kind::MULT},
-    {IAND, cvc5::Kind::IAND},
-    {MINUS, cvc5::Kind::MINUS},
-    {UMINUS, cvc5::Kind::UMINUS},
-    {DIVISION, cvc5::Kind::DIVISION},
-    {INTS_DIVISION, cvc5::Kind::INTS_DIVISION},
-    {INTS_MODULUS, cvc5::Kind::INTS_MODULUS},
-    {ABS, cvc5::Kind::ABS},
-    {DIVISIBLE, cvc5::Kind::DIVISIBLE},
-    {POW, cvc5::Kind::POW},
-    {EXPONENTIAL, cvc5::Kind::EXPONENTIAL},
-    {SINE, cvc5::Kind::SINE},
-    {COSINE, cvc5::Kind::COSINE},
-    {TANGENT, cvc5::Kind::TANGENT},
-    {COSECANT, cvc5::Kind::COSECANT},
-    {SECANT, cvc5::Kind::SECANT},
-    {COTANGENT, cvc5::Kind::COTANGENT},
-    {ARCSINE, cvc5::Kind::ARCSINE},
-    {ARCCOSINE, cvc5::Kind::ARCCOSINE},
-    {ARCTANGENT, cvc5::Kind::ARCTANGENT},
-    {ARCCOSECANT, cvc5::Kind::ARCCOSECANT},
-    {ARCSECANT, cvc5::Kind::ARCSECANT},
-    {ARCCOTANGENT, cvc5::Kind::ARCCOTANGENT},
-    {SQRT, cvc5::Kind::SQRT},
-    {CONST_RATIONAL, cvc5::Kind::CONST_RATIONAL},
-    {LT, cvc5::Kind::LT},
-    {LEQ, cvc5::Kind::LEQ},
-    {GT, cvc5::Kind::GT},
-    {GEQ, cvc5::Kind::GEQ},
-    {IS_INTEGER, cvc5::Kind::IS_INTEGER},
-    {TO_INTEGER, cvc5::Kind::TO_INTEGER},
-    {TO_REAL, cvc5::Kind::TO_REAL},
-    {PI, cvc5::Kind::PI},
-    /* BV ------------------------------------------------------------------ */
-    {CONST_BITVECTOR, cvc5::Kind::CONST_BITVECTOR},
-    {BITVECTOR_CONCAT, cvc5::Kind::BITVECTOR_CONCAT},
-    {BITVECTOR_AND, cvc5::Kind::BITVECTOR_AND},
-    {BITVECTOR_OR, cvc5::Kind::BITVECTOR_OR},
-    {BITVECTOR_XOR, cvc5::Kind::BITVECTOR_XOR},
-    {BITVECTOR_NOT, cvc5::Kind::BITVECTOR_NOT},
-    {BITVECTOR_NAND, cvc5::Kind::BITVECTOR_NAND},
-    {BITVECTOR_NOR, cvc5::Kind::BITVECTOR_NOR},
-    {BITVECTOR_XNOR, cvc5::Kind::BITVECTOR_XNOR},
-    {BITVECTOR_COMP, cvc5::Kind::BITVECTOR_COMP},
-    {BITVECTOR_MULT, cvc5::Kind::BITVECTOR_MULT},
-    {BITVECTOR_PLUS, cvc5::Kind::BITVECTOR_PLUS},
-    {BITVECTOR_SUB, cvc5::Kind::BITVECTOR_SUB},
-    {BITVECTOR_NEG, cvc5::Kind::BITVECTOR_NEG},
-    {BITVECTOR_UDIV, cvc5::Kind::BITVECTOR_UDIV},
-    {BITVECTOR_UREM, cvc5::Kind::BITVECTOR_UREM},
-    {BITVECTOR_SDIV, cvc5::Kind::BITVECTOR_SDIV},
-    {BITVECTOR_SREM, cvc5::Kind::BITVECTOR_SREM},
-    {BITVECTOR_SMOD, cvc5::Kind::BITVECTOR_SMOD},
-    {BITVECTOR_SHL, cvc5::Kind::BITVECTOR_SHL},
-    {BITVECTOR_LSHR, cvc5::Kind::BITVECTOR_LSHR},
-    {BITVECTOR_ASHR, cvc5::Kind::BITVECTOR_ASHR},
-    {BITVECTOR_ULT, cvc5::Kind::BITVECTOR_ULT},
-    {BITVECTOR_ULE, cvc5::Kind::BITVECTOR_ULE},
-    {BITVECTOR_UGT, cvc5::Kind::BITVECTOR_UGT},
-    {BITVECTOR_UGE, cvc5::Kind::BITVECTOR_UGE},
-    {BITVECTOR_SLT, cvc5::Kind::BITVECTOR_SLT},
-    {BITVECTOR_SLE, cvc5::Kind::BITVECTOR_SLE},
-    {BITVECTOR_SGT, cvc5::Kind::BITVECTOR_SGT},
-    {BITVECTOR_SGE, cvc5::Kind::BITVECTOR_SGE},
-    {BITVECTOR_ULTBV, cvc5::Kind::BITVECTOR_ULTBV},
-    {BITVECTOR_SLTBV, cvc5::Kind::BITVECTOR_SLTBV},
-    {BITVECTOR_ITE, cvc5::Kind::BITVECTOR_ITE},
-    {BITVECTOR_REDOR, cvc5::Kind::BITVECTOR_REDOR},
-    {BITVECTOR_REDAND, cvc5::Kind::BITVECTOR_REDAND},
-    {BITVECTOR_EXTRACT, cvc5::Kind::BITVECTOR_EXTRACT},
-    {BITVECTOR_REPEAT, cvc5::Kind::BITVECTOR_REPEAT},
-    {BITVECTOR_ZERO_EXTEND, cvc5::Kind::BITVECTOR_ZERO_EXTEND},
-    {BITVECTOR_SIGN_EXTEND, cvc5::Kind::BITVECTOR_SIGN_EXTEND},
-    {BITVECTOR_ROTATE_LEFT, cvc5::Kind::BITVECTOR_ROTATE_LEFT},
-    {BITVECTOR_ROTATE_RIGHT, cvc5::Kind::BITVECTOR_ROTATE_RIGHT},
-    {INT_TO_BITVECTOR, cvc5::Kind::INT_TO_BITVECTOR},
-    {BITVECTOR_TO_NAT, cvc5::Kind::BITVECTOR_TO_NAT},
-    /* FP ------------------------------------------------------------------ */
-    {CONST_FLOATINGPOINT, cvc5::Kind::CONST_FLOATINGPOINT},
-    {CONST_ROUNDINGMODE, cvc5::Kind::CONST_ROUNDINGMODE},
-    {FLOATINGPOINT_FP, cvc5::Kind::FLOATINGPOINT_FP},
-    {FLOATINGPOINT_EQ, cvc5::Kind::FLOATINGPOINT_EQ},
-    {FLOATINGPOINT_ABS, cvc5::Kind::FLOATINGPOINT_ABS},
-    {FLOATINGPOINT_NEG, cvc5::Kind::FLOATINGPOINT_NEG},
-    {FLOATINGPOINT_PLUS, cvc5::Kind::FLOATINGPOINT_PLUS},
-    {FLOATINGPOINT_SUB, cvc5::Kind::FLOATINGPOINT_SUB},
-    {FLOATINGPOINT_MULT, cvc5::Kind::FLOATINGPOINT_MULT},
-    {FLOATINGPOINT_DIV, cvc5::Kind::FLOATINGPOINT_DIV},
-    {FLOATINGPOINT_FMA, cvc5::Kind::FLOATINGPOINT_FMA},
-    {FLOATINGPOINT_SQRT, cvc5::Kind::FLOATINGPOINT_SQRT},
-    {FLOATINGPOINT_REM, cvc5::Kind::FLOATINGPOINT_REM},
-    {FLOATINGPOINT_RTI, cvc5::Kind::FLOATINGPOINT_RTI},
-    {FLOATINGPOINT_MIN, cvc5::Kind::FLOATINGPOINT_MIN},
-    {FLOATINGPOINT_MAX, cvc5::Kind::FLOATINGPOINT_MAX},
-    {FLOATINGPOINT_LEQ, cvc5::Kind::FLOATINGPOINT_LEQ},
-    {FLOATINGPOINT_LT, cvc5::Kind::FLOATINGPOINT_LT},
-    {FLOATINGPOINT_GEQ, cvc5::Kind::FLOATINGPOINT_GEQ},
-    {FLOATINGPOINT_GT, cvc5::Kind::FLOATINGPOINT_GT},
-    {FLOATINGPOINT_ISN, cvc5::Kind::FLOATINGPOINT_ISN},
-    {FLOATINGPOINT_ISSN, cvc5::Kind::FLOATINGPOINT_ISSN},
-    {FLOATINGPOINT_ISZ, cvc5::Kind::FLOATINGPOINT_ISZ},
-    {FLOATINGPOINT_ISINF, cvc5::Kind::FLOATINGPOINT_ISINF},
-    {FLOATINGPOINT_ISNAN, cvc5::Kind::FLOATINGPOINT_ISNAN},
-    {FLOATINGPOINT_ISNEG, cvc5::Kind::FLOATINGPOINT_ISNEG},
-    {FLOATINGPOINT_ISPOS, cvc5::Kind::FLOATINGPOINT_ISPOS},
-    {FLOATINGPOINT_TO_FP_FLOATINGPOINT,
-     cvc5::Kind::FLOATINGPOINT_TO_FP_FLOATINGPOINT},
-    {FLOATINGPOINT_TO_FP_REAL, cvc5::Kind::FLOATINGPOINT_TO_FP_REAL},
-    {FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR,
-     cvc5::Kind::FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR},
-    {FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR,
-     cvc5::Kind::FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR},
-    {FLOATINGPOINT_TO_FP_GENERIC, cvc5::Kind::FLOATINGPOINT_TO_FP_GENERIC},
-    {FLOATINGPOINT_TO_UBV, cvc5::Kind::FLOATINGPOINT_TO_UBV},
-    {FLOATINGPOINT_TO_SBV, cvc5::Kind::FLOATINGPOINT_TO_SBV},
-    {FLOATINGPOINT_TO_REAL, cvc5::Kind::FLOATINGPOINT_TO_REAL},
-    /* Arrays -------------------------------------------------------------- */
-    {SELECT, cvc5::Kind::SELECT},
-    {STORE, cvc5::Kind::STORE},
-    {CONST_ARRAY, cvc5::Kind::STORE_ALL},
-    {EQ_RANGE, cvc5::Kind::EQ_RANGE},
-    /* Datatypes ----------------------------------------------------------- */
-    {APPLY_SELECTOR, cvc5::Kind::APPLY_SELECTOR},
-    {APPLY_CONSTRUCTOR, cvc5::Kind::APPLY_CONSTRUCTOR},
-    {APPLY_TESTER, cvc5::Kind::APPLY_TESTER},
-    {TUPLE_UPDATE, cvc5::Kind::TUPLE_UPDATE},
-    {RECORD_UPDATE, cvc5::Kind::RECORD_UPDATE},
-    {DT_SIZE, cvc5::Kind::DT_SIZE},
-    {TUPLE_PROJECT, cvc5::Kind::TUPLE_PROJECT},
-    /* Separation Logic ---------------------------------------------------- */
-    {SEP_NIL, cvc5::Kind::SEP_NIL},
-    {SEP_EMP, cvc5::Kind::SEP_EMP},
-    {SEP_PTO, cvc5::Kind::SEP_PTO},
-    {SEP_STAR, cvc5::Kind::SEP_STAR},
-    {SEP_WAND, cvc5::Kind::SEP_WAND},
-    /* Sets ---------------------------------------------------------------- */
-    {EMPTYSET, cvc5::Kind::EMPTYSET},
-    {UNION, cvc5::Kind::UNION},
-    {INTERSECTION, cvc5::Kind::INTERSECTION},
-    {SETMINUS, cvc5::Kind::SETMINUS},
-    {SUBSET, cvc5::Kind::SUBSET},
-    {MEMBER, cvc5::Kind::MEMBER},
-    {SINGLETON, cvc5::Kind::SINGLETON},
-    {INSERT, cvc5::Kind::INSERT},
-    {CARD, cvc5::Kind::CARD},
-    {COMPLEMENT, cvc5::Kind::COMPLEMENT},
-    {UNIVERSE_SET, cvc5::Kind::UNIVERSE_SET},
-    {JOIN, cvc5::Kind::JOIN},
-    {PRODUCT, cvc5::Kind::PRODUCT},
-    {TRANSPOSE, cvc5::Kind::TRANSPOSE},
-    {TCLOSURE, cvc5::Kind::TCLOSURE},
-    {JOIN_IMAGE, cvc5::Kind::JOIN_IMAGE},
-    {IDEN, cvc5::Kind::IDEN},
-    {COMPREHENSION, cvc5::Kind::COMPREHENSION},
-    {CHOOSE, cvc5::Kind::CHOOSE},
-    {IS_SINGLETON, cvc5::Kind::IS_SINGLETON},
-    /* Bags ---------------------------------------------------------------- */
-    {UNION_MAX, cvc5::Kind::UNION_MAX},
-    {UNION_DISJOINT, cvc5::Kind::UNION_DISJOINT},
-    {INTERSECTION_MIN, cvc5::Kind::INTERSECTION_MIN},
-    {DIFFERENCE_SUBTRACT, cvc5::Kind::DIFFERENCE_SUBTRACT},
-    {DIFFERENCE_REMOVE, cvc5::Kind::DIFFERENCE_REMOVE},
-    {SUBBAG, cvc5::Kind::SUBBAG},
-    {BAG_COUNT, cvc5::Kind::BAG_COUNT},
-    {DUPLICATE_REMOVAL, cvc5::Kind::DUPLICATE_REMOVAL},
-    {MK_BAG, cvc5::Kind::MK_BAG},
-    {EMPTYBAG, cvc5::Kind::EMPTYBAG},
-    {BAG_CARD, cvc5::Kind::BAG_CARD},
-    {BAG_CHOOSE, cvc5::Kind::BAG_CHOOSE},
-    {BAG_IS_SINGLETON, cvc5::Kind::BAG_IS_SINGLETON},
-    {BAG_FROM_SET, cvc5::Kind::BAG_FROM_SET},
-    {BAG_TO_SET, cvc5::Kind::BAG_TO_SET},
-    /* Strings ------------------------------------------------------------- */
-    {STRING_CONCAT, cvc5::Kind::STRING_CONCAT},
-    {STRING_IN_REGEXP, cvc5::Kind::STRING_IN_REGEXP},
-    {STRING_LENGTH, cvc5::Kind::STRING_LENGTH},
-    {STRING_SUBSTR, cvc5::Kind::STRING_SUBSTR},
-    {STRING_UPDATE, cvc5::Kind::STRING_UPDATE},
-    {STRING_CHARAT, cvc5::Kind::STRING_CHARAT},
-    {STRING_CONTAINS, cvc5::Kind::STRING_STRCTN},
-    {STRING_INDEXOF, cvc5::Kind::STRING_STRIDOF},
-    {STRING_REPLACE, cvc5::Kind::STRING_STRREPL},
-    {STRING_REPLACE_ALL, cvc5::Kind::STRING_STRREPLALL},
-    {STRING_REPLACE_RE, cvc5::Kind::STRING_REPLACE_RE},
-    {STRING_REPLACE_RE_ALL, cvc5::Kind::STRING_REPLACE_RE_ALL},
-    {STRING_TOLOWER, cvc5::Kind::STRING_TOLOWER},
-    {STRING_TOUPPER, cvc5::Kind::STRING_TOUPPER},
-    {STRING_REV, cvc5::Kind::STRING_REV},
-    {STRING_FROM_CODE, cvc5::Kind::STRING_FROM_CODE},
-    {STRING_TO_CODE, cvc5::Kind::STRING_TO_CODE},
-    {STRING_LT, cvc5::Kind::STRING_LT},
-    {STRING_LEQ, cvc5::Kind::STRING_LEQ},
-    {STRING_PREFIX, cvc5::Kind::STRING_PREFIX},
-    {STRING_SUFFIX, cvc5::Kind::STRING_SUFFIX},
-    {STRING_IS_DIGIT, cvc5::Kind::STRING_IS_DIGIT},
-    {STRING_FROM_INT, cvc5::Kind::STRING_ITOS},
-    {STRING_TO_INT, cvc5::Kind::STRING_STOI},
-    {CONST_STRING, cvc5::Kind::CONST_STRING},
-    {STRING_TO_REGEXP, cvc5::Kind::STRING_TO_REGEXP},
-    {REGEXP_CONCAT, cvc5::Kind::REGEXP_CONCAT},
-    {REGEXP_UNION, cvc5::Kind::REGEXP_UNION},
-    {REGEXP_INTER, cvc5::Kind::REGEXP_INTER},
-    {REGEXP_DIFF, cvc5::Kind::REGEXP_DIFF},
-    {REGEXP_STAR, cvc5::Kind::REGEXP_STAR},
-    {REGEXP_PLUS, cvc5::Kind::REGEXP_PLUS},
-    {REGEXP_OPT, cvc5::Kind::REGEXP_OPT},
-    {REGEXP_RANGE, cvc5::Kind::REGEXP_RANGE},
-    {REGEXP_REPEAT, cvc5::Kind::REGEXP_REPEAT},
-    {REGEXP_LOOP, cvc5::Kind::REGEXP_LOOP},
-    {REGEXP_EMPTY, cvc5::Kind::REGEXP_EMPTY},
-    {REGEXP_SIGMA, cvc5::Kind::REGEXP_SIGMA},
-    {REGEXP_COMPLEMENT, cvc5::Kind::REGEXP_COMPLEMENT},
-    // maps to the same kind as the string versions
-    {SEQ_CONCAT, cvc5::Kind::STRING_CONCAT},
-    {SEQ_LENGTH, cvc5::Kind::STRING_LENGTH},
-    {SEQ_EXTRACT, cvc5::Kind::STRING_SUBSTR},
-    {SEQ_UPDATE, cvc5::Kind::STRING_UPDATE},
-    {SEQ_AT, cvc5::Kind::STRING_CHARAT},
-    {SEQ_CONTAINS, cvc5::Kind::STRING_STRCTN},
-    {SEQ_INDEXOF, cvc5::Kind::STRING_STRIDOF},
-    {SEQ_REPLACE, cvc5::Kind::STRING_STRREPL},
-    {SEQ_REPLACE_ALL, cvc5::Kind::STRING_STRREPLALL},
-    {SEQ_REV, cvc5::Kind::STRING_REV},
-    {SEQ_PREFIX, cvc5::Kind::STRING_PREFIX},
-    {SEQ_SUFFIX, cvc5::Kind::STRING_SUFFIX},
-    {CONST_SEQUENCE, cvc5::Kind::CONST_SEQUENCE},
-    {SEQ_UNIT, cvc5::Kind::SEQ_UNIT},
-    {SEQ_NTH, cvc5::Kind::SEQ_NTH},
-    /* Quantifiers --------------------------------------------------------- */
-    {FORALL, cvc5::Kind::FORALL},
-    {EXISTS, cvc5::Kind::EXISTS},
-    {BOUND_VAR_LIST, cvc5::Kind::BOUND_VAR_LIST},
-    {INST_PATTERN, cvc5::Kind::INST_PATTERN},
-    {INST_NO_PATTERN, cvc5::Kind::INST_NO_PATTERN},
-    {INST_ATTRIBUTE, cvc5::Kind::INST_ATTRIBUTE},
-    {INST_PATTERN_LIST, cvc5::Kind::INST_PATTERN_LIST},
-    {LAST_KIND, cvc5::Kind::LAST_KIND},
-};
-
-/* Mapping from internal kind to external (API) kind. */
-const static std::unordered_map<cvc5::Kind, Kind, cvc5::kind::KindHashFunction>
-    s_kinds_internal{
-        {cvc5::Kind::UNDEFINED_KIND, UNDEFINED_KIND},
-        {cvc5::Kind::NULL_EXPR, NULL_EXPR},
-        /* Builtin --------------------------------------------------------- */
-        {cvc5::Kind::UNINTERPRETED_CONSTANT, UNINTERPRETED_CONSTANT},
-        {cvc5::Kind::ABSTRACT_VALUE, ABSTRACT_VALUE},
-        {cvc5::Kind::EQUAL, EQUAL},
-        {cvc5::Kind::DISTINCT, DISTINCT},
-        {cvc5::Kind::VARIABLE, CONSTANT},
-        {cvc5::Kind::BOUND_VARIABLE, VARIABLE},
-        {cvc5::Kind::SEXPR, SEXPR},
-        {cvc5::Kind::LAMBDA, LAMBDA},
-        {cvc5::Kind::WITNESS, WITNESS},
-        /* Boolean --------------------------------------------------------- */
-        {cvc5::Kind::CONST_BOOLEAN, CONST_BOOLEAN},
-        {cvc5::Kind::NOT, NOT},
-        {cvc5::Kind::AND, AND},
-        {cvc5::Kind::IMPLIES, IMPLIES},
-        {cvc5::Kind::OR, OR},
-        {cvc5::Kind::XOR, XOR},
-        {cvc5::Kind::ITE, ITE},
-        {cvc5::Kind::MATCH, MATCH},
-        {cvc5::Kind::MATCH_CASE, MATCH_CASE},
-        {cvc5::Kind::MATCH_BIND_CASE, MATCH_BIND_CASE},
-        /* UF -------------------------------------------------------------- */
-        {cvc5::Kind::APPLY_UF, APPLY_UF},
-        {cvc5::Kind::CARDINALITY_CONSTRAINT, CARDINALITY_CONSTRAINT},
-        {cvc5::Kind::CARDINALITY_VALUE, CARDINALITY_VALUE},
-        {cvc5::Kind::HO_APPLY, HO_APPLY},
-        /* Arithmetic ------------------------------------------------------ */
-        {cvc5::Kind::PLUS, PLUS},
-        {cvc5::Kind::MULT, MULT},
-        {cvc5::Kind::IAND, IAND},
-        {cvc5::Kind::MINUS, MINUS},
-        {cvc5::Kind::UMINUS, UMINUS},
-        {cvc5::Kind::DIVISION, DIVISION},
-        {cvc5::Kind::DIVISION_TOTAL, INTERNAL_KIND},
-        {cvc5::Kind::INTS_DIVISION, INTS_DIVISION},
-        {cvc5::Kind::INTS_DIVISION_TOTAL, INTERNAL_KIND},
-        {cvc5::Kind::INTS_MODULUS, INTS_MODULUS},
-        {cvc5::Kind::INTS_MODULUS_TOTAL, INTERNAL_KIND},
-        {cvc5::Kind::ABS, ABS},
-        {cvc5::Kind::DIVISIBLE, DIVISIBLE},
-        {cvc5::Kind::POW, POW},
-        {cvc5::Kind::EXPONENTIAL, EXPONENTIAL},
-        {cvc5::Kind::SINE, SINE},
-        {cvc5::Kind::COSINE, COSINE},
-        {cvc5::Kind::TANGENT, TANGENT},
-        {cvc5::Kind::COSECANT, COSECANT},
-        {cvc5::Kind::SECANT, SECANT},
-        {cvc5::Kind::COTANGENT, COTANGENT},
-        {cvc5::Kind::ARCSINE, ARCSINE},
-        {cvc5::Kind::ARCCOSINE, ARCCOSINE},
-        {cvc5::Kind::ARCTANGENT, ARCTANGENT},
-        {cvc5::Kind::ARCCOSECANT, ARCCOSECANT},
-        {cvc5::Kind::ARCSECANT, ARCSECANT},
-        {cvc5::Kind::ARCCOTANGENT, ARCCOTANGENT},
-        {cvc5::Kind::SQRT, SQRT},
-        {cvc5::Kind::DIVISIBLE_OP, DIVISIBLE},
-        {cvc5::Kind::CONST_RATIONAL, CONST_RATIONAL},
-        {cvc5::Kind::LT, LT},
-        {cvc5::Kind::LEQ, LEQ},
-        {cvc5::Kind::GT, GT},
-        {cvc5::Kind::GEQ, GEQ},
-        {cvc5::Kind::IS_INTEGER, IS_INTEGER},
-        {cvc5::Kind::TO_INTEGER, TO_INTEGER},
-        {cvc5::Kind::TO_REAL, TO_REAL},
-        {cvc5::Kind::PI, PI},
-        /* BV -------------------------------------------------------------- */
-        {cvc5::Kind::CONST_BITVECTOR, CONST_BITVECTOR},
-        {cvc5::Kind::BITVECTOR_CONCAT, BITVECTOR_CONCAT},
-        {cvc5::Kind::BITVECTOR_AND, BITVECTOR_AND},
-        {cvc5::Kind::BITVECTOR_OR, BITVECTOR_OR},
-        {cvc5::Kind::BITVECTOR_XOR, BITVECTOR_XOR},
-        {cvc5::Kind::BITVECTOR_NOT, BITVECTOR_NOT},
-        {cvc5::Kind::BITVECTOR_NAND, BITVECTOR_NAND},
-        {cvc5::Kind::BITVECTOR_NOR, BITVECTOR_NOR},
-        {cvc5::Kind::BITVECTOR_XNOR, BITVECTOR_XNOR},
-        {cvc5::Kind::BITVECTOR_COMP, BITVECTOR_COMP},
-        {cvc5::Kind::BITVECTOR_MULT, BITVECTOR_MULT},
-        {cvc5::Kind::BITVECTOR_PLUS, BITVECTOR_PLUS},
-        {cvc5::Kind::BITVECTOR_SUB, BITVECTOR_SUB},
-        {cvc5::Kind::BITVECTOR_NEG, BITVECTOR_NEG},
-        {cvc5::Kind::BITVECTOR_UDIV, BITVECTOR_UDIV},
-        {cvc5::Kind::BITVECTOR_UREM, BITVECTOR_UREM},
-        {cvc5::Kind::BITVECTOR_SDIV, BITVECTOR_SDIV},
-        {cvc5::Kind::BITVECTOR_SREM, BITVECTOR_SREM},
-        {cvc5::Kind::BITVECTOR_SMOD, BITVECTOR_SMOD},
-        {cvc5::Kind::BITVECTOR_SHL, BITVECTOR_SHL},
-        {cvc5::Kind::BITVECTOR_LSHR, BITVECTOR_LSHR},
-        {cvc5::Kind::BITVECTOR_ASHR, BITVECTOR_ASHR},
-        {cvc5::Kind::BITVECTOR_ULT, BITVECTOR_ULT},
-        {cvc5::Kind::BITVECTOR_ULE, BITVECTOR_ULE},
-        {cvc5::Kind::BITVECTOR_UGT, BITVECTOR_UGT},
-        {cvc5::Kind::BITVECTOR_UGE, BITVECTOR_UGE},
-        {cvc5::Kind::BITVECTOR_SLT, BITVECTOR_SLT},
-        {cvc5::Kind::BITVECTOR_SLE, BITVECTOR_SLE},
-        {cvc5::Kind::BITVECTOR_SGT, BITVECTOR_SGT},
-        {cvc5::Kind::BITVECTOR_SGE, BITVECTOR_SGE},
-        {cvc5::Kind::BITVECTOR_ULTBV, BITVECTOR_ULTBV},
-        {cvc5::Kind::BITVECTOR_SLTBV, BITVECTOR_SLTBV},
-        {cvc5::Kind::BITVECTOR_ITE, BITVECTOR_ITE},
-        {cvc5::Kind::BITVECTOR_REDOR, BITVECTOR_REDOR},
-        {cvc5::Kind::BITVECTOR_REDAND, BITVECTOR_REDAND},
-        {cvc5::Kind::BITVECTOR_EXTRACT_OP, BITVECTOR_EXTRACT},
-        {cvc5::Kind::BITVECTOR_REPEAT_OP, BITVECTOR_REPEAT},
-        {cvc5::Kind::BITVECTOR_ZERO_EXTEND_OP, BITVECTOR_ZERO_EXTEND},
-        {cvc5::Kind::BITVECTOR_SIGN_EXTEND_OP, BITVECTOR_SIGN_EXTEND},
-        {cvc5::Kind::BITVECTOR_ROTATE_LEFT_OP, BITVECTOR_ROTATE_LEFT},
-        {cvc5::Kind::BITVECTOR_ROTATE_RIGHT_OP, BITVECTOR_ROTATE_RIGHT},
-        {cvc5::Kind::BITVECTOR_EXTRACT, BITVECTOR_EXTRACT},
-        {cvc5::Kind::BITVECTOR_REPEAT, BITVECTOR_REPEAT},
-        {cvc5::Kind::BITVECTOR_ZERO_EXTEND, BITVECTOR_ZERO_EXTEND},
-        {cvc5::Kind::BITVECTOR_SIGN_EXTEND, BITVECTOR_SIGN_EXTEND},
-        {cvc5::Kind::BITVECTOR_ROTATE_LEFT, BITVECTOR_ROTATE_LEFT},
-        {cvc5::Kind::BITVECTOR_ROTATE_RIGHT, BITVECTOR_ROTATE_RIGHT},
-        {cvc5::Kind::INT_TO_BITVECTOR_OP, INT_TO_BITVECTOR},
-        {cvc5::Kind::INT_TO_BITVECTOR, INT_TO_BITVECTOR},
-        {cvc5::Kind::BITVECTOR_TO_NAT, BITVECTOR_TO_NAT},
-        /* FP -------------------------------------------------------------- */
-        {cvc5::Kind::CONST_FLOATINGPOINT, CONST_FLOATINGPOINT},
-        {cvc5::Kind::CONST_ROUNDINGMODE, CONST_ROUNDINGMODE},
-        {cvc5::Kind::FLOATINGPOINT_FP, FLOATINGPOINT_FP},
-        {cvc5::Kind::FLOATINGPOINT_EQ, FLOATINGPOINT_EQ},
-        {cvc5::Kind::FLOATINGPOINT_ABS, FLOATINGPOINT_ABS},
-        {cvc5::Kind::FLOATINGPOINT_NEG, FLOATINGPOINT_NEG},
-        {cvc5::Kind::FLOATINGPOINT_PLUS, FLOATINGPOINT_PLUS},
-        {cvc5::Kind::FLOATINGPOINT_SUB, FLOATINGPOINT_SUB},
-        {cvc5::Kind::FLOATINGPOINT_MULT, FLOATINGPOINT_MULT},
-        {cvc5::Kind::FLOATINGPOINT_DIV, FLOATINGPOINT_DIV},
-        {cvc5::Kind::FLOATINGPOINT_FMA, FLOATINGPOINT_FMA},
-        {cvc5::Kind::FLOATINGPOINT_SQRT, FLOATINGPOINT_SQRT},
-        {cvc5::Kind::FLOATINGPOINT_REM, FLOATINGPOINT_REM},
-        {cvc5::Kind::FLOATINGPOINT_RTI, FLOATINGPOINT_RTI},
-        {cvc5::Kind::FLOATINGPOINT_MIN, FLOATINGPOINT_MIN},
-        {cvc5::Kind::FLOATINGPOINT_MAX, FLOATINGPOINT_MAX},
-        {cvc5::Kind::FLOATINGPOINT_LEQ, FLOATINGPOINT_LEQ},
-        {cvc5::Kind::FLOATINGPOINT_LT, FLOATINGPOINT_LT},
-        {cvc5::Kind::FLOATINGPOINT_GEQ, FLOATINGPOINT_GEQ},
-        {cvc5::Kind::FLOATINGPOINT_GT, FLOATINGPOINT_GT},
-        {cvc5::Kind::FLOATINGPOINT_ISN, FLOATINGPOINT_ISN},
-        {cvc5::Kind::FLOATINGPOINT_ISSN, FLOATINGPOINT_ISSN},
-        {cvc5::Kind::FLOATINGPOINT_ISZ, FLOATINGPOINT_ISZ},
-        {cvc5::Kind::FLOATINGPOINT_ISINF, FLOATINGPOINT_ISINF},
-        {cvc5::Kind::FLOATINGPOINT_ISNAN, FLOATINGPOINT_ISNAN},
-        {cvc5::Kind::FLOATINGPOINT_ISNEG, FLOATINGPOINT_ISNEG},
-        {cvc5::Kind::FLOATINGPOINT_ISPOS, FLOATINGPOINT_ISPOS},
-        {cvc5::Kind::FLOATINGPOINT_TO_FP_IEEE_BITVECTOR_OP,
-         FLOATINGPOINT_TO_FP_IEEE_BITVECTOR},
-        {cvc5::Kind::FLOATINGPOINT_TO_FP_IEEE_BITVECTOR,
-         FLOATINGPOINT_TO_FP_IEEE_BITVECTOR},
-        {cvc5::Kind::FLOATINGPOINT_TO_FP_FLOATINGPOINT_OP,
-         FLOATINGPOINT_TO_FP_FLOATINGPOINT},
-        {cvc5::Kind::FLOATINGPOINT_TO_FP_FLOATINGPOINT,
-         FLOATINGPOINT_TO_FP_FLOATINGPOINT},
-        {cvc5::Kind::FLOATINGPOINT_TO_FP_REAL_OP, FLOATINGPOINT_TO_FP_REAL},
-        {cvc5::Kind::FLOATINGPOINT_TO_FP_REAL, FLOATINGPOINT_TO_FP_REAL},
-        {cvc5::Kind::FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR_OP,
-         FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR},
-        {cvc5::Kind::FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR,
-         FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR},
-        {cvc5::Kind::FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR_OP,
-         FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR},
-        {cvc5::Kind::FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR,
-         FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR},
-        {cvc5::Kind::FLOATINGPOINT_TO_FP_GENERIC_OP,
-         FLOATINGPOINT_TO_FP_GENERIC},
-        {cvc5::Kind::FLOATINGPOINT_TO_FP_GENERIC, FLOATINGPOINT_TO_FP_GENERIC},
-        {cvc5::Kind::FLOATINGPOINT_TO_UBV_OP, FLOATINGPOINT_TO_UBV},
-        {cvc5::Kind::FLOATINGPOINT_TO_UBV, FLOATINGPOINT_TO_UBV},
-        {cvc5::Kind::FLOATINGPOINT_TO_UBV_TOTAL_OP, INTERNAL_KIND},
-        {cvc5::Kind::FLOATINGPOINT_TO_UBV_TOTAL, INTERNAL_KIND},
-        {cvc5::Kind::FLOATINGPOINT_TO_SBV_OP, FLOATINGPOINT_TO_SBV},
-        {cvc5::Kind::FLOATINGPOINT_TO_SBV, FLOATINGPOINT_TO_SBV},
-        {cvc5::Kind::FLOATINGPOINT_TO_SBV_TOTAL_OP, INTERNAL_KIND},
-        {cvc5::Kind::FLOATINGPOINT_TO_SBV_TOTAL, INTERNAL_KIND},
-        {cvc5::Kind::FLOATINGPOINT_TO_REAL, FLOATINGPOINT_TO_REAL},
-        {cvc5::Kind::FLOATINGPOINT_TO_REAL_TOTAL, INTERNAL_KIND},
-        /* Arrays ---------------------------------------------------------- */
-        {cvc5::Kind::SELECT, SELECT},
-        {cvc5::Kind::STORE, STORE},
-        {cvc5::Kind::STORE_ALL, CONST_ARRAY},
-        /* Datatypes ------------------------------------------------------- */
-        {cvc5::Kind::APPLY_SELECTOR, APPLY_SELECTOR},
-        {cvc5::Kind::APPLY_CONSTRUCTOR, APPLY_CONSTRUCTOR},
-        {cvc5::Kind::APPLY_SELECTOR_TOTAL, INTERNAL_KIND},
-        {cvc5::Kind::APPLY_TESTER, APPLY_TESTER},
-        {cvc5::Kind::TUPLE_UPDATE_OP, TUPLE_UPDATE},
-        {cvc5::Kind::TUPLE_UPDATE, TUPLE_UPDATE},
-        {cvc5::Kind::RECORD_UPDATE_OP, RECORD_UPDATE},
-        {cvc5::Kind::RECORD_UPDATE, RECORD_UPDATE},
-        {cvc5::Kind::DT_SIZE, DT_SIZE},
-        {cvc5::Kind::TUPLE_PROJECT, TUPLE_PROJECT},
-        /* Separation Logic ------------------------------------------------ */
-        {cvc5::Kind::SEP_NIL, SEP_NIL},
-        {cvc5::Kind::SEP_EMP, SEP_EMP},
-        {cvc5::Kind::SEP_PTO, SEP_PTO},
-        {cvc5::Kind::SEP_STAR, SEP_STAR},
-        {cvc5::Kind::SEP_WAND, SEP_WAND},
-        /* Sets ------------------------------------------------------------ */
-        {cvc5::Kind::EMPTYSET, EMPTYSET},
-        {cvc5::Kind::UNION, UNION},
-        {cvc5::Kind::INTERSECTION, INTERSECTION},
-        {cvc5::Kind::SETMINUS, SETMINUS},
-        {cvc5::Kind::SUBSET, SUBSET},
-        {cvc5::Kind::MEMBER, MEMBER},
-        {cvc5::Kind::SINGLETON, SINGLETON},
-        {cvc5::Kind::INSERT, INSERT},
-        {cvc5::Kind::CARD, CARD},
-        {cvc5::Kind::COMPLEMENT, COMPLEMENT},
-        {cvc5::Kind::UNIVERSE_SET, UNIVERSE_SET},
-        {cvc5::Kind::JOIN, JOIN},
-        {cvc5::Kind::PRODUCT, PRODUCT},
-        {cvc5::Kind::TRANSPOSE, TRANSPOSE},
-        {cvc5::Kind::TCLOSURE, TCLOSURE},
-        {cvc5::Kind::JOIN_IMAGE, JOIN_IMAGE},
-        {cvc5::Kind::IDEN, IDEN},
-        {cvc5::Kind::COMPREHENSION, COMPREHENSION},
-        {cvc5::Kind::CHOOSE, CHOOSE},
-        {cvc5::Kind::IS_SINGLETON, IS_SINGLETON},
-        /* Bags ------------------------------------------------------------ */
-        {cvc5::Kind::UNION_MAX, UNION_MAX},
-        {cvc5::Kind::UNION_DISJOINT, UNION_DISJOINT},
-        {cvc5::Kind::INTERSECTION_MIN, INTERSECTION_MIN},
-        {cvc5::Kind::DIFFERENCE_SUBTRACT, DIFFERENCE_SUBTRACT},
-        {cvc5::Kind::DIFFERENCE_REMOVE, DIFFERENCE_REMOVE},
-        {cvc5::Kind::SUBBAG, SUBBAG},
-        {cvc5::Kind::BAG_COUNT, BAG_COUNT},
-        {cvc5::Kind::DUPLICATE_REMOVAL, DUPLICATE_REMOVAL},
-        {cvc5::Kind::MK_BAG, MK_BAG},
-        {cvc5::Kind::EMPTYBAG, EMPTYBAG},
-        {cvc5::Kind::BAG_CARD, BAG_CARD},
-        {cvc5::Kind::BAG_CHOOSE, BAG_CHOOSE},
-        {cvc5::Kind::BAG_IS_SINGLETON, BAG_IS_SINGLETON},
-        {cvc5::Kind::BAG_FROM_SET, BAG_FROM_SET},
-        {cvc5::Kind::BAG_TO_SET, BAG_TO_SET},
-        /* Strings --------------------------------------------------------- */
-        {cvc5::Kind::STRING_CONCAT, STRING_CONCAT},
-        {cvc5::Kind::STRING_IN_REGEXP, STRING_IN_REGEXP},
-        {cvc5::Kind::STRING_LENGTH, STRING_LENGTH},
-        {cvc5::Kind::STRING_SUBSTR, STRING_SUBSTR},
-        {cvc5::Kind::STRING_UPDATE, STRING_UPDATE},
-        {cvc5::Kind::STRING_CHARAT, STRING_CHARAT},
-        {cvc5::Kind::STRING_STRCTN, STRING_CONTAINS},
-        {cvc5::Kind::STRING_STRIDOF, STRING_INDEXOF},
-        {cvc5::Kind::STRING_STRREPL, STRING_REPLACE},
-        {cvc5::Kind::STRING_STRREPLALL, STRING_REPLACE_ALL},
-        {cvc5::Kind::STRING_REPLACE_RE, STRING_REPLACE_RE},
-        {cvc5::Kind::STRING_REPLACE_RE_ALL, STRING_REPLACE_RE_ALL},
-        {cvc5::Kind::STRING_TOLOWER, STRING_TOLOWER},
-        {cvc5::Kind::STRING_TOUPPER, STRING_TOUPPER},
-        {cvc5::Kind::STRING_REV, STRING_REV},
-        {cvc5::Kind::STRING_FROM_CODE, STRING_FROM_CODE},
-        {cvc5::Kind::STRING_TO_CODE, STRING_TO_CODE},
-        {cvc5::Kind::STRING_LT, STRING_LT},
-        {cvc5::Kind::STRING_LEQ, STRING_LEQ},
-        {cvc5::Kind::STRING_PREFIX, STRING_PREFIX},
-        {cvc5::Kind::STRING_SUFFIX, STRING_SUFFIX},
-        {cvc5::Kind::STRING_IS_DIGIT, STRING_IS_DIGIT},
-        {cvc5::Kind::STRING_ITOS, STRING_FROM_INT},
-        {cvc5::Kind::STRING_STOI, STRING_TO_INT},
-        {cvc5::Kind::CONST_STRING, CONST_STRING},
-        {cvc5::Kind::STRING_TO_REGEXP, STRING_TO_REGEXP},
-        {cvc5::Kind::REGEXP_CONCAT, REGEXP_CONCAT},
-        {cvc5::Kind::REGEXP_UNION, REGEXP_UNION},
-        {cvc5::Kind::REGEXP_INTER, REGEXP_INTER},
-        {cvc5::Kind::REGEXP_DIFF, REGEXP_DIFF},
-        {cvc5::Kind::REGEXP_STAR, REGEXP_STAR},
-        {cvc5::Kind::REGEXP_PLUS, REGEXP_PLUS},
-        {cvc5::Kind::REGEXP_OPT, REGEXP_OPT},
-        {cvc5::Kind::REGEXP_RANGE, REGEXP_RANGE},
-        {cvc5::Kind::REGEXP_REPEAT, REGEXP_REPEAT},
-        {cvc5::Kind::REGEXP_REPEAT_OP, REGEXP_REPEAT},
-        {cvc5::Kind::REGEXP_LOOP, REGEXP_LOOP},
-        {cvc5::Kind::REGEXP_LOOP_OP, REGEXP_LOOP},
-        {cvc5::Kind::REGEXP_EMPTY, REGEXP_EMPTY},
-        {cvc5::Kind::REGEXP_SIGMA, REGEXP_SIGMA},
-        {cvc5::Kind::REGEXP_COMPLEMENT, REGEXP_COMPLEMENT},
-        {cvc5::Kind::CONST_SEQUENCE, CONST_SEQUENCE},
-        {cvc5::Kind::SEQ_UNIT, SEQ_UNIT},
-        {cvc5::Kind::SEQ_NTH, SEQ_NTH},
-        /* Quantifiers ----------------------------------------------------- */
-        {cvc5::Kind::FORALL, FORALL},
-        {cvc5::Kind::EXISTS, EXISTS},
-        {cvc5::Kind::BOUND_VAR_LIST, BOUND_VAR_LIST},
-        {cvc5::Kind::INST_PATTERN, INST_PATTERN},
-        {cvc5::Kind::INST_NO_PATTERN, INST_NO_PATTERN},
-        {cvc5::Kind::INST_ATTRIBUTE, INST_ATTRIBUTE},
-        {cvc5::Kind::INST_PATTERN_LIST, INST_PATTERN_LIST},
-        /* ----------------------------------------------------------------- */
-        {cvc5::Kind::LAST_KIND, LAST_KIND},
-    };
-
-/* Set of kinds for indexed operators */
-const static std::unordered_set<Kind, KindHashFunction> s_indexed_kinds(
-    {RECORD_UPDATE,
-     DIVISIBLE,
-     IAND,
-     BITVECTOR_REPEAT,
-     BITVECTOR_ZERO_EXTEND,
-     BITVECTOR_SIGN_EXTEND,
-     BITVECTOR_ROTATE_LEFT,
-     BITVECTOR_ROTATE_RIGHT,
-     INT_TO_BITVECTOR,
-     FLOATINGPOINT_TO_UBV,
-     FLOATINGPOINT_TO_SBV,
-     TUPLE_UPDATE,
-     BITVECTOR_EXTRACT,
-     FLOATINGPOINT_TO_FP_IEEE_BITVECTOR,
-     FLOATINGPOINT_TO_FP_FLOATINGPOINT,
-     FLOATINGPOINT_TO_FP_REAL,
-     FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR,
-     FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR,
-     FLOATINGPOINT_TO_FP_GENERIC});
-
-namespace {
-
-/** Convert a cvc5::Kind (internal) to a cvc5::api::Kind (external). */
-cvc5::api::Kind intToExtKind(cvc5::Kind k)
-{
-  auto it = api::s_kinds_internal.find(k);
-  if (it == api::s_kinds_internal.end())
-  {
-    return api::INTERNAL_KIND;
-  }
-  return it->second;
-}
-
-/** Convert a cvc5::api::Kind (external) to a cvc5::Kind (internal). */
-cvc5::Kind extToIntKind(cvc5::api::Kind k)
-{
-  auto it = api::s_kinds.find(k);
-  if (it == api::s_kinds.end())
-  {
-    return cvc5::Kind::UNDEFINED_KIND;
-  }
-  return it->second;
-}
-
-/** Return true if given kind is a defined external kind. */
-bool isDefinedKind(Kind k) { return k > UNDEFINED_KIND && k < LAST_KIND; }
-
-/**
- * Return true if the internal kind is one where the API term structure
- * differs from internal structure. This happens for APPLY_* kinds.
- * The API takes a "higher-order" perspective and treats functions as well
- * as datatype constructors/selectors/testers as terms
- * but interally they are not
- */
-bool isApplyKind(cvc5::Kind k)
-{
-  return (k == cvc5::Kind::APPLY_UF || k == cvc5::Kind::APPLY_CONSTRUCTOR
-          || k == cvc5::Kind::APPLY_SELECTOR || k == cvc5::Kind::APPLY_TESTER);
-}
-
-#ifdef CVC4_ASSERTIONS
-/** Return true if given kind is a defined internal kind. */
-bool isDefinedIntKind(cvc5::Kind k)
-{
-  return k != cvc5::Kind::UNDEFINED_KIND && k != cvc5::Kind::LAST_KIND;
-}
-#endif
-
-/** Return the minimum arity of given kind. */
-uint32_t minArity(Kind k)
-{
-  Assert(isDefinedKind(k));
-  Assert(isDefinedIntKind(extToIntKind(k)));
-  uint32_t min = cvc5::kind::metakind::getMinArityForKind(extToIntKind(k));
-
-  // At the API level, we treat functions/constructors/selectors/testers as
-  // normal terms instead of making them part of the operator
-  if (isApplyKind(extToIntKind(k)))
-  {
-    min++;
-  }
-  return min;
-}
-
-/** Return the maximum arity of given kind. */
-uint32_t maxArity(Kind k)
-{
-  Assert(isDefinedKind(k));
-  Assert(isDefinedIntKind(extToIntKind(k)));
-  uint32_t max = cvc5::kind::metakind::getMaxArityForKind(extToIntKind(k));
-
-  // At the API level, we treat functions/constructors/selectors/testers as
-  // normal terms instead of making them part of the operator
-  if (isApplyKind(extToIntKind(k))
-      && max != std::numeric_limits<uint32_t>::max())  // be careful not to
-                                                       // overflow
-  {
-    max++;
-  }
-  return max;
-}
-
-}  // namespace
-
-std::string kindToString(Kind k)
-{
-  return k == INTERNAL_KIND ? "INTERNAL_KIND"
-                            : cvc5::kind::kindToString(extToIntKind(k));
-}
-
-std::ostream& operator<<(std::ostream& out, Kind k)
-{
-  switch (k)
-  {
-    case INTERNAL_KIND: out << "INTERNAL_KIND"; break;
-    default: out << extToIntKind(k);
-  }
-  return out;
-}
-
-size_t KindHashFunction::operator()(Kind k) const { return k; }
-
-/* -------------------------------------------------------------------------- */
-/* API guard helpers                                                          */
-/* -------------------------------------------------------------------------- */
-
-namespace {
-
-class CVC4ApiExceptionStream
-{
- public:
-  CVC4ApiExceptionStream() {}
-  /* Note: This needs to be explicitly set to 'noexcept(false)' since it is
-   * a destructor that throws an exception and in C++11 all destructors
-   * default to noexcept(true) (else this triggers a call to std::terminate). */
-  ~CVC4ApiExceptionStream() noexcept(false)
-  {
-    if (std::uncaught_exceptions() == 0)
-    {
-      throw CVC4ApiException(d_stream.str());
-    }
-  }
-
-  std::ostream& ostream() { return d_stream; }
-
- private:
-  std::stringstream d_stream;
-};
-
-class CVC4ApiRecoverableExceptionStream
-{
- public:
-  CVC4ApiRecoverableExceptionStream() {}
-  /* Note: This needs to be explicitly set to 'noexcept(false)' since it is
-   * a destructor that throws an exception and in C++11 all destructors
-   * default to noexcept(true) (else this triggers a call to std::terminate). */
-  ~CVC4ApiRecoverableExceptionStream() noexcept(false)
-  {
-    if (std::uncaught_exceptions() == 0)
-    {
-      throw CVC4ApiRecoverableException(d_stream.str());
-    }
-  }
-
-  std::ostream& ostream() { return d_stream; }
-
- private:
-  std::stringstream d_stream;
-};
-
-#define CVC4_API_TRY_CATCH_BEGIN \
-  try                            \
-  {
-#define CVC4_API_TRY_CATCH_END                                                 \
-  }                                                                            \
-  catch (const UnrecognizedOptionException& e)                                 \
-  {                                                                            \
-    throw CVC4ApiRecoverableException(e.getMessage());                         \
-  }                                                                            \
-  catch (const cvc5::RecoverableModalException& e)                             \
-  {                                                                            \
-    throw CVC4ApiRecoverableException(e.getMessage());                         \
-  }                                                                            \
-  catch (const cvc5::Exception& e) { throw CVC4ApiException(e.getMessage()); } \
-  catch (const std::invalid_argument& e) { throw CVC4ApiException(e.what()); }
-
-}  // namespace
-
-/* -------------------------------------------------------------------------- */
-/* Result                                                                     */
-/* -------------------------------------------------------------------------- */
-
-Result::Result(const cvc5::Result& r) : d_result(new cvc5::Result(r)) {}
-
-Result::Result() : d_result(new cvc5::Result()) {}
-
-bool Result::isNull() const
-{
-  return d_result->getType() == cvc5::Result::TYPE_NONE;
-}
-
-bool Result::isSat(void) const
-{
-  return d_result->getType() == cvc5::Result::TYPE_SAT
-         && d_result->isSat() == cvc5::Result::SAT;
-}
-
-bool Result::isUnsat(void) const
-{
-  return d_result->getType() == cvc5::Result::TYPE_SAT
-         && d_result->isSat() == cvc5::Result::UNSAT;
-}
-
-bool Result::isSatUnknown(void) const
-{
-  return d_result->getType() == cvc5::Result::TYPE_SAT
-         && d_result->isSat() == cvc5::Result::SAT_UNKNOWN;
-}
-
-bool Result::isEntailed(void) const
-{
-  return d_result->getType() == cvc5::Result::TYPE_ENTAILMENT
-         && d_result->isEntailed() == cvc5::Result::ENTAILED;
-}
-
-bool Result::isNotEntailed(void) const
-{
-  return d_result->getType() == cvc5::Result::TYPE_ENTAILMENT
-         && d_result->isEntailed() == cvc5::Result::NOT_ENTAILED;
-}
-
-bool Result::isEntailmentUnknown(void) const
-{
-  return d_result->getType() == cvc5::Result::TYPE_ENTAILMENT
-         && d_result->isEntailed() == cvc5::Result::ENTAILMENT_UNKNOWN;
-}
-
-bool Result::operator==(const Result& r) const
-{
-  return *d_result == *r.d_result;
-}
-
-bool Result::operator!=(const Result& r) const
-{
-  return *d_result != *r.d_result;
-}
-
-Result::UnknownExplanation Result::getUnknownExplanation(void) const
-{
-  cvc5::Result::UnknownExplanation expl = d_result->whyUnknown();
-  switch (expl)
-  {
-    case cvc5::Result::REQUIRES_FULL_CHECK: return REQUIRES_FULL_CHECK;
-    case cvc5::Result::INCOMPLETE: return INCOMPLETE;
-    case cvc5::Result::TIMEOUT: return TIMEOUT;
-    case cvc5::Result::RESOURCEOUT: return RESOURCEOUT;
-    case cvc5::Result::MEMOUT: return MEMOUT;
-    case cvc5::Result::INTERRUPTED: return INTERRUPTED;
-    case cvc5::Result::NO_STATUS: return NO_STATUS;
-    case cvc5::Result::UNSUPPORTED: return UNSUPPORTED;
-    case cvc5::Result::OTHER: return OTHER;
-    default: return UNKNOWN_REASON;
-  }
-  return UNKNOWN_REASON;
-}
-
-std::string Result::toString(void) const { return d_result->toString(); }
-
-std::ostream& operator<<(std::ostream& out, const Result& r)
-{
-  out << r.toString();
-  return out;
-}
-
-std::ostream& operator<<(std::ostream& out, enum Result::UnknownExplanation e)
-{
-  switch (e)
-  {
-    case Result::REQUIRES_FULL_CHECK: out << "REQUIRES_FULL_CHECK"; break;
-    case Result::INCOMPLETE: out << "INCOMPLETE"; break;
-    case Result::TIMEOUT: out << "TIMEOUT"; break;
-    case Result::RESOURCEOUT: out << "RESOURCEOUT"; break;
-    case Result::MEMOUT: out << "MEMOUT"; break;
-    case Result::INTERRUPTED: out << "INTERRUPTED"; break;
-    case Result::NO_STATUS: out << "NO_STATUS"; break;
-    case Result::UNSUPPORTED: out << "UNSUPPORTED"; break;
-    case Result::OTHER: out << "OTHER"; break;
-    case Result::UNKNOWN_REASON: out << "UNKNOWN_REASON"; break;
-    default: Unhandled() << e;
-  }
-  return out;
-}
-
-/* -------------------------------------------------------------------------- */
-/* Sort                                                                       */
-/* -------------------------------------------------------------------------- */
-
-Sort::Sort(const Solver* slv, const cvc5::TypeNode& t)
-    : d_solver(slv), d_type(new cvc5::TypeNode(t))
-{
-}
-
-Sort::Sort() : d_solver(nullptr), d_type(new cvc5::TypeNode()) {}
-
-Sort::~Sort()
-{
-  if (d_solver != nullptr)
-  {
-    // Ensure that the correct node manager is in scope when the node is
-    // destroyed.
-    NodeManagerScope scope(d_solver->getNodeManager());
-    d_type.reset();
-  }
-}
-
-std::set<TypeNode> Sort::sortSetToTypeNodes(const std::set<Sort>& sorts)
-{
-  std::set<TypeNode> types;
-  for (const Sort& s : sorts)
-  {
-    types.insert(s.getTypeNode());
-  }
-  return types;
-}
-
-std::vector<TypeNode> Sort::sortVectorToTypeNodes(
-    const std::vector<Sort>& sorts)
-{
-  std::vector<TypeNode> typeNodes;
-  for (const Sort& sort : sorts)
-  {
-    typeNodes.push_back(sort.getTypeNode());
-  }
-  return typeNodes;
-}
-
-std::vector<Sort> Sort::typeNodeVectorToSorts(
-    const Solver* slv, const std::vector<TypeNode>& types)
-{
-  std::vector<Sort> sorts;
-  for (size_t i = 0, tsize = types.size(); i < tsize; i++)
-  {
-    sorts.push_back(Sort(slv, types[i]));
-  }
-  return sorts;
-}
-
-bool Sort::operator==(const Sort& s) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return *d_type == *s.d_type;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::operator!=(const Sort& s) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return *d_type != *s.d_type;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::operator<(const Sort& s) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return *d_type < *s.d_type;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::operator>(const Sort& s) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return *d_type > *s.d_type;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::operator<=(const Sort& s) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return *d_type <= *s.d_type;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::operator>=(const Sort& s) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return *d_type >= *s.d_type;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isNull() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return isNullHelper();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isBoolean() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return d_type->isBoolean();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isInteger() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return d_type->isInteger();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isReal() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  // notice that we do not expose internal subtyping to the user
-  return d_type->isReal() && !d_type->isInteger();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isString() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return d_type->isString();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isRegExp() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return d_type->isRegExp();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isRoundingMode() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return d_type->isRoundingMode();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isBitVector() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return d_type->isBitVector();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isFloatingPoint() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return d_type->isFloatingPoint();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isDatatype() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return d_type->isDatatype();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isParametricDatatype() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  if (!d_type->isDatatype()) return false;
-  return d_type->isParametricDatatype();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isConstructor() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return d_type->isConstructor();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isSelector() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return d_type->isSelector();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isTester() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return d_type->isTester();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isFunction() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return d_type->isFunction();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isPredicate() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return d_type->isPredicate();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isTuple() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return d_type->isTuple();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isRecord() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return d_type->isRecord();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isArray() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return d_type->isArray();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isSet() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return d_type->isSet();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isBag() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return d_type->isBag();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isSequence() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return d_type->isSequence();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isUninterpretedSort() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return d_type->isSort();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isSortConstructor() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return d_type->isSortConstructor();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isFirstClass() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return d_type->isFirstClass();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isFunctionLike() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return d_type->isFunctionLike();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isSubsortOf(const Sort& s) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_ARG_CHECK_SOLVER("sort", s);
-  //////// all checks before this line
-  return d_type->isSubtypeOf(*s.d_type);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isComparableTo(const Sort& s) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_ARG_CHECK_SOLVER("sort", s);
-  //////// all checks before this line
-  return d_type->isComparableTo(*s.d_type);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Datatype Sort::getDatatype() const
-{
-  NodeManagerScope scope(d_solver->getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isDatatype()) << "Expected datatype sort.";
-  //////// all checks before this line
-  return Datatype(d_solver, d_type->getDType());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Sort::instantiate(const std::vector<Sort>& params) const
-{
-  NodeManagerScope scope(d_solver->getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK_SORTS(params);
-  CVC4_API_CHECK(isParametricDatatype() || isSortConstructor())
-      << "Expected parametric datatype or sort constructor sort.";
-  //////// all checks before this line
-  std::vector<cvc5::TypeNode> tparams = sortVectorToTypeNodes(params);
-  if (d_type->isDatatype())
-  {
-    return Sort(d_solver, d_type->instantiateParametricDatatype(tparams));
-  }
-  Assert(d_type->isSortConstructor());
-  return Sort(d_solver, d_solver->getNodeManager()->mkSort(*d_type, tparams));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Sort::substitute(const Sort& sort, const Sort& replacement) const
-{
-  NodeManagerScope scope(d_solver->getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK_SORT(sort);
-  CVC4_API_CHECK_SORT(replacement);
-  //////// all checks before this line
-  return Sort(
-      d_solver,
-      d_type->substitute(sort.getTypeNode(), replacement.getTypeNode()));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Sort::substitute(const std::vector<Sort>& sorts,
-                      const std::vector<Sort>& replacements) const
-{
-  NodeManagerScope scope(d_solver->getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK_SORTS(sorts);
-  CVC4_API_CHECK_SORTS(replacements);
-  //////// all checks before this line
-
-  std::vector<cvc5::TypeNode> tSorts = sortVectorToTypeNodes(sorts),
-                              tReplacements =
-                                  sortVectorToTypeNodes(replacements);
-  return Sort(d_solver,
-              d_type->substitute(tSorts.begin(),
-                                 tSorts.end(),
-                                 tReplacements.begin(),
-                                 tReplacements.end()));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-std::string Sort::toString() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  if (d_solver != nullptr)
-  {
-    NodeManagerScope scope(d_solver->getNodeManager());
-    return d_type->toString();
-  }
-  return d_type->toString();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-const cvc5::TypeNode& Sort::getTypeNode(void) const { return *d_type; }
-
-/* Constructor sort ------------------------------------------------------- */
-
-size_t Sort::getConstructorArity() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isConstructor()) << "Not a constructor sort: " << (*this);
-  //////// all checks before this line
-  return d_type->getNumChildren() - 1;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-std::vector<Sort> Sort::getConstructorDomainSorts() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isConstructor()) << "Not a constructor sort: " << (*this);
-  //////// all checks before this line
-  return typeNodeVectorToSorts(d_solver, d_type->getArgTypes());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Sort::getConstructorCodomainSort() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isConstructor()) << "Not a constructor sort: " << (*this);
-  //////// all checks before this line
-  return Sort(d_solver, d_type->getConstructorRangeType());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/* Selector sort ------------------------------------------------------- */
-
-Sort Sort::getSelectorDomainSort() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isSelector()) << "Not a selector sort: " << (*this);
-  //////// all checks before this line
-  return Sort(d_solver, d_type->getSelectorDomainType());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Sort::getSelectorCodomainSort() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isSelector()) << "Not a selector sort: " << (*this);
-  //////// all checks before this line
-  return Sort(d_solver, d_type->getSelectorRangeType());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/* Tester sort ------------------------------------------------------- */
-
-Sort Sort::getTesterDomainSort() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isTester()) << "Not a tester sort: " << (*this);
-  //////// all checks before this line
-  return Sort(d_solver, d_type->getTesterDomainType());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Sort::getTesterCodomainSort() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isTester()) << "Not a tester sort: " << (*this);
-  //////// all checks before this line
-  return d_solver->getBooleanSort();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/* Function sort ------------------------------------------------------- */
-
-size_t Sort::getFunctionArity() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isFunction()) << "Not a function sort: " << (*this);
-  //////// all checks before this line
-  return d_type->getNumChildren() - 1;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-std::vector<Sort> Sort::getFunctionDomainSorts() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isFunction()) << "Not a function sort: " << (*this);
-  //////// all checks before this line
-  return typeNodeVectorToSorts(d_solver, d_type->getArgTypes());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Sort::getFunctionCodomainSort() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isFunction()) << "Not a function sort" << (*this);
-  //////// all checks before this line
-  return Sort(d_solver, d_type->getRangeType());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/* Array sort ---------------------------------------------------------- */
-
-Sort Sort::getArrayIndexSort() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isArray()) << "Not an array sort.";
-  //////// all checks before this line
-  return Sort(d_solver, d_type->getArrayIndexType());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Sort::getArrayElementSort() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isArray()) << "Not an array sort.";
-  //////// all checks before this line
-  return Sort(d_solver, d_type->getArrayConstituentType());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/* Set sort ------------------------------------------------------------ */
-
-Sort Sort::getSetElementSort() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isSet()) << "Not a set sort.";
-  //////// all checks before this line
-  return Sort(d_solver, d_type->getSetElementType());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/* Bag sort ------------------------------------------------------------ */
-
-Sort Sort::getBagElementSort() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isBag()) << "Not a bag sort.";
-  //////// all checks before this line
-  return Sort(d_solver, d_type->getBagElementType());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/* Sequence sort ------------------------------------------------------- */
-
-Sort Sort::getSequenceElementSort() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isSequence()) << "Not a sequence sort.";
-  //////// all checks before this line
-  return Sort(d_solver, d_type->getSequenceElementType());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/* Uninterpreted sort -------------------------------------------------- */
-
-std::string Sort::getUninterpretedSortName() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isUninterpretedSort()) << "Not an uninterpreted sort.";
-  //////// all checks before this line
-  return d_type->getName();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Sort::isUninterpretedSortParameterized() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isUninterpretedSort()) << "Not an uninterpreted sort.";
-  //////// all checks before this line
-
-  /* This method is not implemented in the NodeManager, since whether a
-   * uninterpreted sort is parameterized is irrelevant for solving. */
-  return d_type->getNumChildren() > 0;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-std::vector<Sort> Sort::getUninterpretedSortParamSorts() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isUninterpretedSort()) << "Not an uninterpreted sort.";
-  //////// all checks before this line
-
-  /* This method is not implemented in the NodeManager, since whether a
-   * uninterpreted sort is parameterized is irrelevant for solving. */
-  std::vector<TypeNode> params;
-  for (size_t i = 0, nchildren = d_type->getNumChildren(); i < nchildren; i++)
-  {
-    params.push_back((*d_type)[i]);
-  }
-  return typeNodeVectorToSorts(d_solver, params);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/* Sort constructor sort ----------------------------------------------- */
-
-std::string Sort::getSortConstructorName() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isSortConstructor()) << "Not a sort constructor sort.";
-  //////// all checks before this line
-  return d_type->getName();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-size_t Sort::getSortConstructorArity() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isSortConstructor()) << "Not a sort constructor sort.";
-  //////// all checks before this line
-  return d_type->getSortConstructorArity();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/* Bit-vector sort ----------------------------------------------------- */
-
-uint32_t Sort::getBVSize() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isBitVector()) << "Not a bit-vector sort.";
-  //////// all checks before this line
-  return d_type->getBitVectorSize();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/* Floating-point sort ------------------------------------------------- */
-
-uint32_t Sort::getFPExponentSize() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isFloatingPoint()) << "Not a floating-point sort.";
-  //////// all checks before this line
-  return d_type->getFloatingPointExponentSize();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-uint32_t Sort::getFPSignificandSize() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isFloatingPoint()) << "Not a floating-point sort.";
-  //////// all checks before this line
-  return d_type->getFloatingPointSignificandSize();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/* Datatype sort ------------------------------------------------------- */
-
-std::vector<Sort> Sort::getDatatypeParamSorts() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isParametricDatatype()) << "Not a parametric datatype sort.";
-  //////// all checks before this line
-  return typeNodeVectorToSorts(d_solver, d_type->getParamTypes());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-size_t Sort::getDatatypeArity() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isDatatype()) << "Not a datatype sort.";
-  //////// all checks before this line
-  return d_type->getNumChildren() - 1;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/* Tuple sort ---------------------------------------------------------- */
-
-size_t Sort::getTupleLength() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isTuple()) << "Not a tuple sort.";
-  //////// all checks before this line
-  return d_type->getTupleLength();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-std::vector<Sort> Sort::getTupleSorts() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(isTuple()) << "Not a tuple sort.";
-  //////// all checks before this line
-  return typeNodeVectorToSorts(d_solver, d_type->getTupleTypes());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/* --------------------------------------------------------------------- */
-
-std::ostream& operator<<(std::ostream& out, const Sort& s)
-{
-  out << s.toString();
-  return out;
-}
-
-size_t SortHashFunction::operator()(const Sort& s) const
-{
-  return TypeNodeHashFunction()(*s.d_type);
-}
-
-/* Helpers                                                                    */
-/* -------------------------------------------------------------------------- */
-
-/* Split out to avoid nested API calls (problematic with API tracing).        */
-/* .......................................................................... */
-
-bool Sort::isNullHelper() const { return d_type->isNull(); }
-
-/* -------------------------------------------------------------------------- */
-/* Op                                                                     */
-/* -------------------------------------------------------------------------- */
-
-Op::Op() : d_solver(nullptr), d_kind(NULL_EXPR), d_node(new cvc5::Node()) {}
-
-Op::Op(const Solver* slv, const Kind k)
-    : d_solver(slv), d_kind(k), d_node(new cvc5::Node())
-{
-}
-
-Op::Op(const Solver* slv, const Kind k, const cvc5::Node& n)
-    : d_solver(slv), d_kind(k), d_node(new cvc5::Node(n))
-{
-}
-
-Op::~Op()
-{
-  if (d_solver != nullptr)
-  {
-    // Ensure that the correct node manager is in scope when the type node is
-    // destroyed.
-    NodeManagerScope scope(d_solver->getNodeManager());
-    d_node.reset();
-  }
-}
-
-/* Public methods                                                             */
-bool Op::operator==(const Op& t) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  if (d_node->isNull() && t.d_node->isNull())
-  {
-    return (d_kind == t.d_kind);
-  }
-  else if (d_node->isNull() || t.d_node->isNull())
-  {
-    return false;
-  }
-  return (d_kind == t.d_kind) && (*d_node == *t.d_node);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Op::operator!=(const Op& t) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return !(*this == t);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Kind Op::getKind() const
-{
-  CVC4_API_CHECK(d_kind != NULL_EXPR) << "Expecting a non-null Kind";
-  //////// all checks before this line
-  return d_kind;
-}
-
-bool Op::isNull() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return isNullHelper();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Op::isIndexed() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return isIndexedHelper();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-template <>
-std::string Op::getIndices() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(!d_node->isNull())
-      << "Expecting a non-null internal expression. This Op is not indexed.";
-  Kind k = intToExtKind(d_node->getKind());
-  CVC4_API_CHECK(k == DIVISIBLE || k == RECORD_UPDATE)
-      << "Can't get string index from"
-      << " kind " << kindToString(k);
-  //////// all checks before this line
-  return k == DIVISIBLE ? d_node->getConst<Divisible>().k.toString()
-                        : d_node->getConst<RecordUpdate>().getField();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-template <>
-uint32_t Op::getIndices() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(!d_node->isNull())
-      << "Expecting a non-null internal expression. This Op is not indexed.";
-  //////// all checks before this line
-
-  uint32_t i = 0;
-  Kind k = intToExtKind(d_node->getKind());
-  switch (k)
-  {
-    case BITVECTOR_REPEAT:
-      i = d_node->getConst<BitVectorRepeat>().d_repeatAmount;
-      break;
-    case BITVECTOR_ZERO_EXTEND:
-      i = d_node->getConst<BitVectorZeroExtend>().d_zeroExtendAmount;
-      break;
-    case BITVECTOR_SIGN_EXTEND:
-      i = d_node->getConst<BitVectorSignExtend>().d_signExtendAmount;
-      break;
-    case BITVECTOR_ROTATE_LEFT:
-      i = d_node->getConst<BitVectorRotateLeft>().d_rotateLeftAmount;
-      break;
-    case BITVECTOR_ROTATE_RIGHT:
-      i = d_node->getConst<BitVectorRotateRight>().d_rotateRightAmount;
-      break;
-    case INT_TO_BITVECTOR: i = d_node->getConst<IntToBitVector>().d_size; break;
-    case IAND: i = d_node->getConst<IntAnd>().d_size; break;
-    case FLOATINGPOINT_TO_UBV:
-      i = d_node->getConst<FloatingPointToUBV>().d_bv_size.d_size;
-      break;
-    case FLOATINGPOINT_TO_SBV:
-      i = d_node->getConst<FloatingPointToSBV>().d_bv_size.d_size;
-      break;
-    case TUPLE_UPDATE: i = d_node->getConst<TupleUpdate>().getIndex(); break;
-    case REGEXP_REPEAT:
-      i = d_node->getConst<RegExpRepeat>().d_repeatAmount;
-      break;
-    default:
-      CVC4_API_CHECK(false) << "Can't get uint32_t index from"
-                            << " kind " << kindToString(k);
-  }
-  return i;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-template <>
-std::pair<uint32_t, uint32_t> Op::getIndices() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(!d_node->isNull())
-      << "Expecting a non-null internal expression. This Op is not indexed.";
-  //////// all checks before this line
-
-  std::pair<uint32_t, uint32_t> indices;
-  Kind k = intToExtKind(d_node->getKind());
-
-  // using if/else instead of case statement because want local variables
-  if (k == BITVECTOR_EXTRACT)
-  {
-    cvc5::BitVectorExtract ext = d_node->getConst<BitVectorExtract>();
-    indices = std::make_pair(ext.d_high, ext.d_low);
-  }
-  else if (k == FLOATINGPOINT_TO_FP_IEEE_BITVECTOR)
-  {
-    cvc5::FloatingPointToFPIEEEBitVector ext =
-        d_node->getConst<FloatingPointToFPIEEEBitVector>();
-    indices = std::make_pair(ext.getSize().exponentWidth(),
-                             ext.getSize().significandWidth());
-  }
-  else if (k == FLOATINGPOINT_TO_FP_FLOATINGPOINT)
-  {
-    cvc5::FloatingPointToFPFloatingPoint ext =
-        d_node->getConst<FloatingPointToFPFloatingPoint>();
-    indices = std::make_pair(ext.getSize().exponentWidth(),
-                             ext.getSize().significandWidth());
-  }
-  else if (k == FLOATINGPOINT_TO_FP_REAL)
-  {
-    cvc5::FloatingPointToFPReal ext = d_node->getConst<FloatingPointToFPReal>();
-    indices = std::make_pair(ext.getSize().exponentWidth(),
-                             ext.getSize().significandWidth());
-  }
-  else if (k == FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR)
-  {
-    cvc5::FloatingPointToFPSignedBitVector ext =
-        d_node->getConst<FloatingPointToFPSignedBitVector>();
-    indices = std::make_pair(ext.getSize().exponentWidth(),
-                             ext.getSize().significandWidth());
-  }
-  else if (k == FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR)
-  {
-    cvc5::FloatingPointToFPUnsignedBitVector ext =
-        d_node->getConst<FloatingPointToFPUnsignedBitVector>();
-    indices = std::make_pair(ext.getSize().exponentWidth(),
-                             ext.getSize().significandWidth());
-  }
-  else if (k == FLOATINGPOINT_TO_FP_GENERIC)
-  {
-    cvc5::FloatingPointToFPGeneric ext =
-        d_node->getConst<FloatingPointToFPGeneric>();
-    indices = std::make_pair(ext.getSize().exponentWidth(),
-                             ext.getSize().significandWidth());
-  }
-  else if (k == REGEXP_LOOP)
-  {
-    cvc5::RegExpLoop ext = d_node->getConst<RegExpLoop>();
-    indices = std::make_pair(ext.d_loopMinOcc, ext.d_loopMaxOcc);
-  }
-  else
-  {
-    CVC4_API_CHECK(false) << "Can't get pair<uint32_t, uint32_t> indices from"
-                          << " kind " << kindToString(k);
-  }
-  return indices;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-std::string Op::toString() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  if (d_node->isNull())
-  {
-    return kindToString(d_kind);
-  }
-  else
-  {
-    CVC4_API_CHECK(!d_node->isNull())
-        << "Expecting a non-null internal expression";
-    if (d_solver != nullptr)
-    {
-      NodeManagerScope scope(d_solver->getNodeManager());
-      return d_node->toString();
-    }
-    return d_node->toString();
-  }
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-std::ostream& operator<<(std::ostream& out, const Op& t)
-{
-  out << t.toString();
-  return out;
-}
-
-size_t OpHashFunction::operator()(const Op& t) const
-{
-  if (t.isIndexedHelper())
-  {
-    return NodeHashFunction()(*t.d_node);
-  }
-  else
-  {
-    return KindHashFunction()(t.d_kind);
-  }
-}
-
-/* Helpers                                                                    */
-/* -------------------------------------------------------------------------- */
-
-/* Split out to avoid nested API calls (problematic with API tracing).        */
-/* .......................................................................... */
-
-bool Op::isNullHelper() const
-{
-  return (d_node->isNull() && (d_kind == NULL_EXPR));
-}
-
-bool Op::isIndexedHelper() const { return !d_node->isNull(); }
-
-/* -------------------------------------------------------------------------- */
-/* Term                                                                       */
-/* -------------------------------------------------------------------------- */
-
-Term::Term() : d_solver(nullptr), d_node(new cvc5::Node()) {}
-
-Term::Term(const Solver* slv, const cvc5::Node& n) : d_solver(slv)
-{
-  // Ensure that we create the node in the correct node manager.
-  NodeManagerScope scope(d_solver->getNodeManager());
-  d_node.reset(new cvc5::Node(n));
-}
-
-Term::~Term()
-{
-  if (d_solver != nullptr)
-  {
-    // Ensure that the correct node manager is in scope when the node is
-    // destroyed.
-    NodeManagerScope scope(d_solver->getNodeManager());
-    d_node.reset();
-  }
-}
-
-bool Term::operator==(const Term& t) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return *d_node == *t.d_node;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Term::operator!=(const Term& t) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return *d_node != *t.d_node;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Term::operator<(const Term& t) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return *d_node < *t.d_node;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Term::operator>(const Term& t) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return *d_node > *t.d_node;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Term::operator<=(const Term& t) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return *d_node <= *t.d_node;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Term::operator>=(const Term& t) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return *d_node >= *t.d_node;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-size_t Term::getNumChildren() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-
-  // special case for apply kinds
-  if (isApplyKind(d_node->getKind()))
-  {
-    return d_node->getNumChildren() + 1;
-  }
-  if(isCastedReal())
-  {
-    return 0;
-  }
-  return d_node->getNumChildren();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Term::operator[](size_t index) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(index < getNumChildren()) << "index out of bound";
-  CVC4_API_CHECK(!isApplyKind(d_node->getKind()) || d_node->hasOperator())
-      << "Expected apply kind to have operator when accessing child of Term";
-  //////// all checks before this line
-
-  // special cases for apply kinds
-  if (isApplyKind(d_node->getKind()))
-  {
-    if (index == 0)
-    {
-      // return the operator
-      return Term(d_solver, d_node->getOperator());
-    }
-    else
-    {
-      index -= 1;
-    }
-  }
-  // otherwise we are looking up child at (index-1)
-  return Term(d_solver, (*d_node)[index]);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-uint64_t Term::getId() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return d_node->getId();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Kind Term::getKind() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return getKindHelper();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Term::getSort() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  NodeManagerScope scope(d_solver->getNodeManager());
-  //////// all checks before this line
-  return Sort(d_solver, d_node->getType());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Term::substitute(const Term& term, const Term& replacement) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK_TERM(term);
-  CVC4_API_CHECK_TERM(replacement);
-  CVC4_API_CHECK(term.getSort().isComparableTo(replacement.getSort()))
-      << "Expecting terms of comparable sort in substitute";
-  //////// all checks before this line
-  return Term(
-      d_solver,
-      d_node->substitute(TNode(*term.d_node), TNode(*replacement.d_node)));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Term::substitute(const std::vector<Term>& terms,
-                      const std::vector<Term>& replacements) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(terms.size() == replacements.size())
-      << "Expecting vectors of the same arity in substitute";
-  CVC4_API_TERM_CHECK_TERMS_WITH_TERMS_COMPARABLE_TO(terms, replacements);
-  //////// all checks before this line
-  std::vector<Node> nodes = Term::termVectorToNodes(terms);
-  std::vector<Node> nodeReplacements = Term::termVectorToNodes(replacements);
-  return Term(d_solver,
-              d_node->substitute(nodes.begin(),
-                                 nodes.end(),
-                                 nodeReplacements.begin(),
-                                 nodeReplacements.end()));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Term::hasOp() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return d_node->hasOperator();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Op Term::getOp() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(d_node->hasOperator())
-      << "Expecting Term to have an Op when calling getOp()";
-  //////// all checks before this line
-
-  // special cases for parameterized operators that are not indexed operators
-  // the API level differs from the internal structure
-  // indexed operators are stored in Ops
-  // whereas functions and datatype operators are terms, and the Op
-  // is one of the APPLY_* kinds
-  if (isApplyKind(d_node->getKind()))
-  {
-    return Op(d_solver, intToExtKind(d_node->getKind()));
-  }
-  else if (d_node->getMetaKind() == kind::metakind::PARAMETERIZED)
-  {
-    // it's an indexed operator
-    // so we should return the indexed op
-    cvc5::Node op = d_node->getOperator();
-    return Op(d_solver, intToExtKind(d_node->getKind()), op);
-  }
-  // Notice this is the only case where getKindHelper is used, since the
-  // cases above do not have special cases for intToExtKind.
-  return Op(d_solver, getKindHelper());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Term::isNull() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return isNullHelper();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Term::getConstArrayBase() const
-{
-  NodeManagerScope scope(d_solver->getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  // CONST_ARRAY kind maps to STORE_ALL internal kind
-  CVC4_API_CHECK(d_node->getKind() == cvc5::Kind::STORE_ALL)
-      << "Expecting a CONST_ARRAY Term when calling getConstArrayBase()";
-  //////// all checks before this line
-  return Term(d_solver, d_node->getConst<ArrayStoreAll>().getValue());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-std::vector<Term> Term::getConstSequenceElements() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(d_node->getKind() == cvc5::Kind::CONST_SEQUENCE)
-      << "Expecting a CONST_SEQUENCE Term when calling "
-         "getConstSequenceElements()";
-  //////// all checks before this line
-  const std::vector<Node>& elems = d_node->getConst<Sequence>().getVec();
-  std::vector<Term> terms;
-  for (const Node& t : elems)
-  {
-    terms.push_back(Term(d_solver, t));
-  }
-  return terms;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Term::notTerm() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  Node res = d_node->notNode();
-  (void)res.getType(true); /* kick off type checking */
-  return Term(d_solver, res);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Term::andTerm(const Term& t) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK_TERM(t);
-  //////// all checks before this line
-  Node res = d_node->andNode(*t.d_node);
-  (void)res.getType(true); /* kick off type checking */
-  return Term(d_solver, res);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Term::orTerm(const Term& t) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK_TERM(t);
-  //////// all checks before this line
-  Node res = d_node->orNode(*t.d_node);
-  (void)res.getType(true); /* kick off type checking */
-  return Term(d_solver, res);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Term::xorTerm(const Term& t) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK_TERM(t);
-  //////// all checks before this line
-  Node res = d_node->xorNode(*t.d_node);
-  (void)res.getType(true); /* kick off type checking */
-  return Term(d_solver, res);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Term::eqTerm(const Term& t) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK_TERM(t);
-  //////// all checks before this line
-  Node res = d_node->eqNode(*t.d_node);
-  (void)res.getType(true); /* kick off type checking */
-  return Term(d_solver, res);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Term::impTerm(const Term& t) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK_TERM(t);
-  //////// all checks before this line
-  Node res = d_node->impNode(*t.d_node);
-  (void)res.getType(true); /* kick off type checking */
-  return Term(d_solver, res);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Term::iteTerm(const Term& then_t, const Term& else_t) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK_TERM(then_t);
-  CVC4_API_CHECK_TERM(else_t);
-  //////// all checks before this line
-  Node res = d_node->iteNode(*then_t.d_node, *else_t.d_node);
-  (void)res.getType(true); /* kick off type checking */
-  return Term(d_solver, res);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-std::string Term::toString() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  if (d_solver != nullptr)
-  {
-    NodeManagerScope scope(d_solver->getNodeManager());
-    return d_node->toString();
-  }
-  return d_node->toString();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term::const_iterator::const_iterator()
-    : d_solver(nullptr), d_origNode(nullptr), d_pos(0)
-{
-}
-
-Term::const_iterator::const_iterator(const Solver* slv,
-                                     const std::shared_ptr<cvc5::Node>& n,
-                                     uint32_t p)
-    : d_solver(slv), d_origNode(n), d_pos(p)
-{
-}
-
-Term::const_iterator::const_iterator(const const_iterator& it)
-    : d_solver(nullptr), d_origNode(nullptr)
-{
-  if (it.d_origNode != nullptr)
-  {
-    d_solver = it.d_solver;
-    d_origNode = it.d_origNode;
-    d_pos = it.d_pos;
-  }
-}
-
-Term::const_iterator& Term::const_iterator::operator=(const const_iterator& it)
-{
-  d_solver = it.d_solver;
-  d_origNode = it.d_origNode;
-  d_pos = it.d_pos;
-  return *this;
-}
-
-bool Term::const_iterator::operator==(const const_iterator& it) const
-{
-  if (d_origNode == nullptr || it.d_origNode == nullptr)
-  {
-    return false;
-  }
-  return (d_solver == it.d_solver && *d_origNode == *it.d_origNode)
-         && (d_pos == it.d_pos);
-}
-
-bool Term::const_iterator::operator!=(const const_iterator& it) const
-{
-  return !(*this == it);
-}
-
-Term::const_iterator& Term::const_iterator::operator++()
-{
-  Assert(d_origNode != nullptr);
-  ++d_pos;
-  return *this;
-}
-
-Term::const_iterator Term::const_iterator::operator++(int)
-{
-  Assert(d_origNode != nullptr);
-  const_iterator it = *this;
-  ++d_pos;
-  return it;
-}
-
-Term Term::const_iterator::operator*() const
-{
-  Assert(d_origNode != nullptr);
-  // this term has an extra child (mismatch between API and internal structure)
-  // the extra child will be the first child
-  bool extra_child = isApplyKind(d_origNode->getKind());
-
-  if (!d_pos && extra_child)
-  {
-    return Term(d_solver, d_origNode->getOperator());
-  }
-  else
-  {
-    uint32_t idx = d_pos;
-    if (extra_child)
-    {
-      Assert(idx > 0);
-      --idx;
-    }
-    Assert(idx >= 0);
-    return Term(d_solver, (*d_origNode)[idx]);
-  }
-}
-
-Term::const_iterator Term::begin() const
-{
-  return Term::const_iterator(d_solver, d_node, 0);
-}
-
-Term::const_iterator Term::end() const
-{
-  int endpos = d_node->getNumChildren();
-  // special cases for APPLY_*
-  // the API differs from the internal structure
-  // the API takes a "higher-order" perspective and the applied
-  //   function or datatype constructor/selector/tester is a Term
-  // which means it needs to be one of the children, even though
-  //   internally it is not
-  if (isApplyKind(d_node->getKind()))
-  {
-    // one more child if this is a UF application (count the UF as a child)
-    ++endpos;
-  }
-  return Term::const_iterator(d_solver, d_node, endpos);
-}
-
-const cvc5::Node& Term::getNode(void) const { return *d_node; }
-
-namespace detail {
-const Rational& getRational(const cvc5::Node& node)
-{
-  return node.getConst<Rational>();
-}
-Integer getInteger(const cvc5::Node& node)
-{
-  return node.getConst<Rational>().getNumerator();
-}
-template <typename T>
-bool checkIntegerBounds(const Integer& i)
-{
-  return i >= std::numeric_limits<T>::min()
-         && i <= std::numeric_limits<T>::max();
-}
-bool checkReal32Bounds(const Rational& r)
-{
-  return checkIntegerBounds<std::int32_t>(r.getNumerator())
-         && checkIntegerBounds<std::uint32_t>(r.getDenominator());
-}
-bool checkReal64Bounds(const Rational& r)
-{
-  return checkIntegerBounds<std::int64_t>(r.getNumerator())
-         && checkIntegerBounds<std::uint64_t>(r.getDenominator());
-}
-
-bool isInteger(const Node& node)
-{
-  return node.getKind() == cvc5::Kind::CONST_RATIONAL
-         && node.getConst<Rational>().isIntegral();
-}
-bool isInt32(const Node& node)
-{
-  return isInteger(node)
-         && checkIntegerBounds<std::int32_t>(getInteger(node));
-}
-bool isUInt32(const Node& node)
-{
-  return isInteger(node)
-         && checkIntegerBounds<std::uint32_t>(getInteger(node));
-}
-bool isInt64(const Node& node)
-{
-  return isInteger(node)
-         && checkIntegerBounds<std::int64_t>(getInteger(node));
-}
-bool isUInt64(const Node& node)
-{
-  return isInteger(node)
-         && checkIntegerBounds<std::uint64_t>(getInteger(node));
-}
-}  // namespace detail
-
-bool Term::isInt32() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return detail::isInt32(*d_node);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-std::int32_t Term::getInt32() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(detail::isInt32(*d_node))
-      << "Term should be a Int32 when calling getInt32()";
-  //////// all checks before this line
-  return detail::getInteger(*d_node).getSignedInt();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Term::isUInt32() const { return detail::isUInt32(*d_node); }
-std::uint32_t Term::getUInt32() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(detail::isUInt32(*d_node))
-      << "Term should be a UInt32 when calling getUInt32()";
-  //////// all checks before this line
-  return detail::getInteger(*d_node).getUnsignedInt();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Term::isInt64() const { return detail::isInt64(*d_node); }
-std::int64_t Term::getInt64() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(detail::isInt64(*d_node))
-      << "Term should be a Int64 when calling getInt64()";
-  //////// all checks before this line
-  return detail::getInteger(*d_node).getLong();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Term::isUInt64() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return detail::isUInt64(*d_node);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-std::uint64_t Term::getUInt64() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(detail::isUInt64(*d_node))
-      << "Term should be a UInt64 when calling getUInt64()";
-  //////// all checks before this line
-  return detail::getInteger(*d_node).getUnsignedLong();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Term::isInteger() const { return detail::isInteger(*d_node); }
-std::string Term::getInteger() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(detail::isInteger(*d_node))
-      << "Term should be an Int when calling getIntString()";
-  //////// all checks before this line
-  return detail::getInteger(*d_node).toString();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Term::isString() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return d_node->getKind() == cvc5::Kind::CONST_STRING;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-std::wstring Term::getString() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(d_node->getKind() == cvc5::Kind::CONST_STRING)
-      << "Term should be a String when calling getString()";
-  //////// all checks before this line
-  return d_node->getConst<cvc5::String>().toWString();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-std::vector<Node> Term::termVectorToNodes(const std::vector<Term>& terms)
-{
-  std::vector<Node> res;
-  for (const Term& t : terms)
-  {
-    res.push_back(t.getNode());
-  }
-  return res;
-}
-
-std::ostream& operator<<(std::ostream& out, const Term& t)
-{
-  out << t.toString();
-  return out;
-}
-
-std::ostream& operator<<(std::ostream& out, const std::vector<Term>& vector)
-{
-  container_to_stream(out, vector);
-  return out;
-}
-
-std::ostream& operator<<(std::ostream& out, const std::set<Term>& set)
-{
-  container_to_stream(out, set);
-  return out;
-}
-
-std::ostream& operator<<(
-    std::ostream& out,
-    const std::unordered_set<Term, TermHashFunction>& unordered_set)
-{
-  container_to_stream(out, unordered_set);
-  return out;
-}
-
-template <typename V>
-std::ostream& operator<<(std::ostream& out, const std::map<Term, V>& map)
-{
-  container_to_stream(out, map);
-  return out;
-}
-
-template <typename V>
-std::ostream& operator<<(
-    std::ostream& out,
-    const std::unordered_map<Term, V, TermHashFunction>& unordered_map)
-{
-  container_to_stream(out, unordered_map);
-  return out;
-}
-
-size_t TermHashFunction::operator()(const Term& t) const
-{
-  return NodeHashFunction()(*t.d_node);
-}
-
-/* Helpers                                                                    */
-/* -------------------------------------------------------------------------- */
-
-/* Split out to avoid nested API calls (problematic with API tracing).        */
-/* .......................................................................... */
-
-bool Term::isNullHelper() const
-{
-  /* Split out to avoid nested API calls (problematic with API tracing). */
-  return d_node->isNull();
-}
-
-Kind Term::getKindHelper() const
-{
-  /* Sequence kinds do not exist internally, so we must convert their internal
-   * (string) versions back to sequence. All operators where this is
-   * necessary are such that their first child is of sequence type, which
-   * we check here. */
-  if (d_node->getNumChildren() > 0 && (*d_node)[0].getType().isSequence())
-  {
-    switch (d_node->getKind())
-    {
-      case cvc5::Kind::STRING_CONCAT: return SEQ_CONCAT;
-      case cvc5::Kind::STRING_LENGTH: return SEQ_LENGTH;
-      case cvc5::Kind::STRING_SUBSTR: return SEQ_EXTRACT;
-      case cvc5::Kind::STRING_UPDATE: return SEQ_UPDATE;
-      case cvc5::Kind::STRING_CHARAT: return SEQ_AT;
-      case cvc5::Kind::STRING_STRCTN: return SEQ_CONTAINS;
-      case cvc5::Kind::STRING_STRIDOF: return SEQ_INDEXOF;
-      case cvc5::Kind::STRING_STRREPL: return SEQ_REPLACE;
-      case cvc5::Kind::STRING_STRREPLALL: return SEQ_REPLACE_ALL;
-      case cvc5::Kind::STRING_REV: return SEQ_REV;
-      case cvc5::Kind::STRING_PREFIX: return SEQ_PREFIX;
-      case cvc5::Kind::STRING_SUFFIX: return SEQ_SUFFIX;
-      default:
-        // fall through to conversion below
-        break;
-    }
-  }
-  // Notice that kinds like APPLY_TYPE_ASCRIPTION will be converted to
-  // INTERNAL_KIND.
-  if (isCastedReal())
-  {
-    return CONST_RATIONAL;
-  }
-  return intToExtKind(d_node->getKind());
-}
-
-bool Term::isCastedReal() const
-{
-  if (d_node->getKind() == kind::CAST_TO_REAL)
-  {
-    return (*d_node)[0].isConst() && (*d_node)[0].getType().isInteger();
-  }
-  return false;
-}
-
-/* -------------------------------------------------------------------------- */
-/* Datatypes                                                                  */
-/* -------------------------------------------------------------------------- */
-
-/* DatatypeConstructorDecl -------------------------------------------------- */
-
-DatatypeConstructorDecl::DatatypeConstructorDecl()
-    : d_solver(nullptr), d_ctor(nullptr)
-{
-}
-
-DatatypeConstructorDecl::DatatypeConstructorDecl(const Solver* slv,
-                                                 const std::string& name)
-    : d_solver(slv), d_ctor(new cvc5::DTypeConstructor(name))
-{
-}
-DatatypeConstructorDecl::~DatatypeConstructorDecl()
-{
-  if (d_ctor != nullptr)
-  {
-    // ensure proper node manager is in scope
-    NodeManagerScope scope(d_solver->getNodeManager());
-    d_ctor.reset();
-  }
-}
-
-void DatatypeConstructorDecl::addSelector(const std::string& name,
-                                          const Sort& sort)
-{
-  NodeManagerScope scope(d_solver->getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK_SORT(sort);
-  CVC4_API_ARG_CHECK_EXPECTED(!sort.isNull(), sort)
-      << "non-null range sort for selector";
-  //////// all checks before this line
-  d_ctor->addArg(name, *sort.d_type);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-void DatatypeConstructorDecl::addSelectorSelf(const std::string& name)
-{
-  NodeManagerScope scope(d_solver->getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  d_ctor->addArgSelf(name);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool DatatypeConstructorDecl::isNull() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return isNullHelper();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-std::string DatatypeConstructorDecl::toString() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  std::stringstream ss;
-  ss << *d_ctor;
-  return ss.str();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-std::ostream& operator<<(std::ostream& out,
-                         const DatatypeConstructorDecl& ctordecl)
-{
-  out << ctordecl.toString();
-  return out;
-}
-
-std::ostream& operator<<(std::ostream& out,
-                         const std::vector<DatatypeConstructorDecl>& vector)
-{
-  container_to_stream(out, vector);
-  return out;
-}
-
-bool DatatypeConstructorDecl::isNullHelper() const { return d_ctor == nullptr; }
-
-/* DatatypeDecl ------------------------------------------------------------- */
-
-DatatypeDecl::DatatypeDecl() : d_solver(nullptr), d_dtype(nullptr) {}
-
-DatatypeDecl::DatatypeDecl(const Solver* slv,
-                           const std::string& name,
-                           bool isCoDatatype)
-    : d_solver(slv), d_dtype(new cvc5::DType(name, isCoDatatype))
-{
-}
-
-DatatypeDecl::DatatypeDecl(const Solver* slv,
-                           const std::string& name,
-                           const Sort& param,
-                           bool isCoDatatype)
-    : d_solver(slv),
-      d_dtype(new cvc5::DType(
-          name, std::vector<TypeNode>{*param.d_type}, isCoDatatype))
-{
-}
-
-DatatypeDecl::DatatypeDecl(const Solver* slv,
-                           const std::string& name,
-                           const std::vector<Sort>& params,
-                           bool isCoDatatype)
-    : d_solver(slv)
-{
-  std::vector<TypeNode> tparams = Sort::sortVectorToTypeNodes(params);
-  d_dtype = std::shared_ptr<cvc5::DType>(
-      new cvc5::DType(name, tparams, isCoDatatype));
-}
-
-bool DatatypeDecl::isNullHelper() const { return !d_dtype; }
-
-DatatypeDecl::~DatatypeDecl()
-{
-  if (d_dtype != nullptr)
-  {
-    // ensure proper node manager is in scope
-    NodeManagerScope scope(d_solver->getNodeManager());
-    d_dtype.reset();
-  }
-}
-
-void DatatypeDecl::addConstructor(const DatatypeConstructorDecl& ctor)
-{
-  NodeManagerScope scope(d_solver->getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_ARG_CHECK_NOT_NULL(ctor);
-  CVC4_API_ARG_CHECK_SOLVER("datatype constructor declaration", ctor);
-  //////// all checks before this line
-  d_dtype->addConstructor(ctor.d_ctor);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-size_t DatatypeDecl::getNumConstructors() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return d_dtype->getNumConstructors();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool DatatypeDecl::isParametric() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return d_dtype->isParametric();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-std::string DatatypeDecl::toString() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  std::stringstream ss;
-  ss << *d_dtype;
-  return ss.str();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-std::string DatatypeDecl::getName() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return d_dtype->getName();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool DatatypeDecl::isNull() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return isNullHelper();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-std::ostream& operator<<(std::ostream& out, const DatatypeDecl& dtdecl)
-{
-  out << dtdecl.toString();
-  return out;
-}
-
-cvc5::DType& DatatypeDecl::getDatatype(void) const { return *d_dtype; }
-
-/* DatatypeSelector --------------------------------------------------------- */
-
-DatatypeSelector::DatatypeSelector() : d_solver(nullptr), d_stor(nullptr) {}
-
-DatatypeSelector::DatatypeSelector(const Solver* slv,
-                                   const cvc5::DTypeSelector& stor)
-    : d_solver(slv), d_stor(new cvc5::DTypeSelector(stor))
-{
-  CVC4_API_CHECK(d_stor->isResolved()) << "Expected resolved datatype selector";
-}
-
-DatatypeSelector::~DatatypeSelector()
-{
-  if (d_stor != nullptr)
-  {
-    // ensure proper node manager is in scope
-    NodeManagerScope scope(d_solver->getNodeManager());
-    d_stor.reset();
-  }
-}
-
-std::string DatatypeSelector::getName() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return d_stor->getName();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term DatatypeSelector::getSelectorTerm() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return Term(d_solver, d_stor->getSelector());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort DatatypeSelector::getRangeSort() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return Sort(d_solver, d_stor->getRangeType());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool DatatypeSelector::isNull() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return isNullHelper();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-std::string DatatypeSelector::toString() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  std::stringstream ss;
-  ss << *d_stor;
-  return ss.str();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-std::ostream& operator<<(std::ostream& out, const DatatypeSelector& stor)
-{
-  out << stor.toString();
-  return out;
-}
-
-bool DatatypeSelector::isNullHelper() const { return d_stor == nullptr; }
-
-/* DatatypeConstructor ------------------------------------------------------ */
-
-DatatypeConstructor::DatatypeConstructor() : d_solver(nullptr), d_ctor(nullptr)
-{
-}
-
-DatatypeConstructor::DatatypeConstructor(const Solver* slv,
-                                         const cvc5::DTypeConstructor& ctor)
-    : d_solver(slv), d_ctor(new cvc5::DTypeConstructor(ctor))
-{
-  CVC4_API_CHECK(d_ctor->isResolved())
-      << "Expected resolved datatype constructor";
-}
-
-DatatypeConstructor::~DatatypeConstructor()
-{
-  if (d_ctor != nullptr)
-  {
-    // ensure proper node manager is in scope
-    NodeManagerScope scope(d_solver->getNodeManager());
-    d_ctor.reset();
-  }
-}
-
-std::string DatatypeConstructor::getName() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return d_ctor->getName();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term DatatypeConstructor::getConstructorTerm() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return Term(d_solver, d_ctor->getConstructor());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term DatatypeConstructor::getSpecializedConstructorTerm(
-    const Sort& retSort) const
-{
-  NodeManagerScope scope(d_solver->getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(d_ctor->isResolved())
-      << "Expected resolved datatype constructor";
-  CVC4_API_CHECK(retSort.isDatatype())
-      << "Cannot get specialized constructor type for non-datatype type "
-      << retSort;
-  //////// all checks before this line
-
-  NodeManager* nm = d_solver->getNodeManager();
-  Node ret =
-      nm->mkNode(kind::APPLY_TYPE_ASCRIPTION,
-                 nm->mkConst(AscriptionType(
-                     d_ctor->getSpecializedConstructorType(*retSort.d_type))),
-                 d_ctor->getConstructor());
-  (void)ret.getType(true); /* kick off type checking */
-  // apply type ascription to the operator
-  Term sctor = api::Term(d_solver, ret);
-  return sctor;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term DatatypeConstructor::getTesterTerm() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return Term(d_solver, d_ctor->getTester());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-size_t DatatypeConstructor::getNumSelectors() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return d_ctor->getNumArgs();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-DatatypeSelector DatatypeConstructor::operator[](size_t index) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return DatatypeSelector(d_solver, (*d_ctor)[index]);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-DatatypeSelector DatatypeConstructor::operator[](const std::string& name) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return getSelectorForName(name);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-DatatypeSelector DatatypeConstructor::getSelector(const std::string& name) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return getSelectorForName(name);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term DatatypeConstructor::getSelectorTerm(const std::string& name) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return getSelector(name).getSelectorTerm();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-DatatypeConstructor::const_iterator DatatypeConstructor::begin() const
-{
-  return DatatypeConstructor::const_iterator(d_solver, *d_ctor, true);
-}
-
-DatatypeConstructor::const_iterator DatatypeConstructor::end() const
-{
-  return DatatypeConstructor::const_iterator(d_solver, *d_ctor, false);
-}
-
-DatatypeConstructor::const_iterator::const_iterator(
-    const Solver* slv, const cvc5::DTypeConstructor& ctor, bool begin)
-{
-  d_solver = slv;
-  d_int_stors = &ctor.getArgs();
-
-  const std::vector<std::shared_ptr<cvc5::DTypeSelector>>& sels =
-      ctor.getArgs();
-  for (const std::shared_ptr<cvc5::DTypeSelector>& s : sels)
-  {
-    /* Can not use emplace_back here since constructor is private. */
-    d_stors.push_back(DatatypeSelector(d_solver, *s.get()));
-  }
-  d_idx = begin ? 0 : sels.size();
-}
-
-DatatypeConstructor::const_iterator::const_iterator()
-    : d_solver(nullptr), d_int_stors(nullptr), d_idx(0)
-{
-}
-
-DatatypeConstructor::const_iterator&
-DatatypeConstructor::const_iterator::operator=(
-    const DatatypeConstructor::const_iterator& it)
-{
-  d_solver = it.d_solver;
-  d_int_stors = it.d_int_stors;
-  d_stors = it.d_stors;
-  d_idx = it.d_idx;
-  return *this;
-}
-
-const DatatypeSelector& DatatypeConstructor::const_iterator::operator*() const
-{
-  return d_stors[d_idx];
-}
-
-const DatatypeSelector* DatatypeConstructor::const_iterator::operator->() const
-{
-  return &d_stors[d_idx];
-}
-
-DatatypeConstructor::const_iterator&
-DatatypeConstructor::const_iterator::operator++()
-{
-  ++d_idx;
-  return *this;
-}
-
-DatatypeConstructor::const_iterator
-DatatypeConstructor::const_iterator::operator++(int)
-{
-  DatatypeConstructor::const_iterator it(*this);
-  ++d_idx;
-  return it;
-}
-
-bool DatatypeConstructor::const_iterator::operator==(
-    const DatatypeConstructor::const_iterator& other) const
-{
-  return d_int_stors == other.d_int_stors && d_idx == other.d_idx;
-}
-
-bool DatatypeConstructor::const_iterator::operator!=(
-    const DatatypeConstructor::const_iterator& other) const
-{
-  return d_int_stors != other.d_int_stors || d_idx != other.d_idx;
-}
-
-bool DatatypeConstructor::isNull() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return isNullHelper();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-std::string DatatypeConstructor::toString() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  std::stringstream ss;
-  ss << *d_ctor;
-  return ss.str();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool DatatypeConstructor::isNullHelper() const { return d_ctor == nullptr; }
-
-DatatypeSelector DatatypeConstructor::getSelectorForName(
-    const std::string& name) const
-{
-  bool foundSel = false;
-  size_t index = 0;
-  for (size_t i = 0, nsels = getNumSelectors(); i < nsels; i++)
-  {
-    if ((*d_ctor)[i].getName() == name)
-    {
-      index = i;
-      foundSel = true;
-      break;
-    }
-  }
-  if (!foundSel)
-  {
-    std::stringstream snames;
-    snames << "{ ";
-    for (size_t i = 0, ncons = getNumSelectors(); i < ncons; i++)
-    {
-      snames << (*d_ctor)[i].getName() << " ";
-    }
-    snames << "} ";
-    CVC4_API_CHECK(foundSel) << "No selector " << name << " for constructor "
-                             << getName() << " exists among " << snames.str();
-  }
-  return DatatypeSelector(d_solver, (*d_ctor)[index]);
-}
-
-std::ostream& operator<<(std::ostream& out, const DatatypeConstructor& ctor)
-{
-  out << ctor.toString();
-  return out;
-}
-
-/* Datatype ----------------------------------------------------------------- */
-
-Datatype::Datatype(const Solver* slv, const cvc5::DType& dtype)
-    : d_solver(slv), d_dtype(new cvc5::DType(dtype))
-{
-  CVC4_API_CHECK(d_dtype->isResolved()) << "Expected resolved datatype";
-}
-
-Datatype::Datatype() : d_solver(nullptr), d_dtype(nullptr) {}
-
-Datatype::~Datatype()
-{
-  if (d_dtype != nullptr)
-  {
-    // ensure proper node manager is in scope
-    NodeManagerScope scope(d_solver->getNodeManager());
-    d_dtype.reset();
-  }
-}
-
-DatatypeConstructor Datatype::operator[](size_t idx) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  CVC4_API_CHECK(idx < getNumConstructors()) << "Index out of bounds.";
-  //////// all checks before this line
-  return DatatypeConstructor(d_solver, (*d_dtype)[idx]);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-DatatypeConstructor Datatype::operator[](const std::string& name) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return getConstructorForName(name);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-DatatypeConstructor Datatype::getConstructor(const std::string& name) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return getConstructorForName(name);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Datatype::getConstructorTerm(const std::string& name) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return getConstructor(name).getConstructorTerm();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-std::string Datatype::getName() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return d_dtype->getName();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-size_t Datatype::getNumConstructors() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return d_dtype->getNumConstructors();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Datatype::isParametric() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return d_dtype->isParametric();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Datatype::isCodatatype() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return d_dtype->isCodatatype();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Datatype::isTuple() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return d_dtype->isTuple();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Datatype::isRecord() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return d_dtype->isRecord();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Datatype::isFinite() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return d_dtype->isFinite();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Datatype::isWellFounded() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return d_dtype->isWellFounded();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-bool Datatype::hasNestedRecursion() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return d_dtype->hasNestedRecursion();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Datatype::isNull() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return isNullHelper();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-std::string Datatype::toString() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_NOT_NULL;
-  //////// all checks before this line
-  return d_dtype->getName();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Datatype::const_iterator Datatype::begin() const
-{
-  return Datatype::const_iterator(d_solver, *d_dtype, true);
-}
-
-Datatype::const_iterator Datatype::end() const
-{
-  return Datatype::const_iterator(d_solver, *d_dtype, false);
-}
-
-DatatypeConstructor Datatype::getConstructorForName(
-    const std::string& name) const
-{
-  bool foundCons = false;
-  size_t index = 0;
-  for (size_t i = 0, ncons = getNumConstructors(); i < ncons; i++)
-  {
-    if ((*d_dtype)[i].getName() == name)
-    {
-      index = i;
-      foundCons = true;
-      break;
-    }
-  }
-  if (!foundCons)
-  {
-    std::stringstream snames;
-    snames << "{ ";
-    for (size_t i = 0, ncons = getNumConstructors(); i < ncons; i++)
-    {
-      snames << (*d_dtype)[i].getName() << " ";
-    }
-    snames << "}";
-    CVC4_API_CHECK(foundCons) << "No constructor " << name << " for datatype "
-                              << getName() << " exists, among " << snames.str();
-  }
-  return DatatypeConstructor(d_solver, (*d_dtype)[index]);
-}
-
-Datatype::const_iterator::const_iterator(const Solver* slv,
-                                         const cvc5::DType& dtype,
-                                         bool begin)
-    : d_solver(slv), d_int_ctors(&dtype.getConstructors())
-{
-  const std::vector<std::shared_ptr<DTypeConstructor>>& cons =
-      dtype.getConstructors();
-  for (const std::shared_ptr<DTypeConstructor>& c : cons)
-  {
-    /* Can not use emplace_back here since constructor is private. */
-    d_ctors.push_back(DatatypeConstructor(d_solver, *c.get()));
-  }
-  d_idx = begin ? 0 : cons.size();
-}
-
-Datatype::const_iterator::const_iterator()
-    : d_solver(nullptr), d_int_ctors(nullptr), d_idx(0)
-{
-}
-
-Datatype::const_iterator& Datatype::const_iterator::operator=(
-    const Datatype::const_iterator& it)
-{
-  d_solver = it.d_solver;
-  d_int_ctors = it.d_int_ctors;
-  d_ctors = it.d_ctors;
-  d_idx = it.d_idx;
-  return *this;
-}
-
-const DatatypeConstructor& Datatype::const_iterator::operator*() const
-{
-  return d_ctors[d_idx];
-}
-
-const DatatypeConstructor* Datatype::const_iterator::operator->() const
-{
-  return &d_ctors[d_idx];
-}
-
-Datatype::const_iterator& Datatype::const_iterator::operator++()
-{
-  ++d_idx;
-  return *this;
-}
-
-Datatype::const_iterator Datatype::const_iterator::operator++(int)
-{
-  Datatype::const_iterator it(*this);
-  ++d_idx;
-  return it;
-}
-
-bool Datatype::const_iterator::operator==(
-    const Datatype::const_iterator& other) const
-{
-  return d_int_ctors == other.d_int_ctors && d_idx == other.d_idx;
-}
-
-bool Datatype::const_iterator::operator!=(
-    const Datatype::const_iterator& other) const
-{
-  return d_int_ctors != other.d_int_ctors || d_idx != other.d_idx;
-}
-
-bool Datatype::isNullHelper() const { return d_dtype == nullptr; }
-
-/* -------------------------------------------------------------------------- */
-/* Grammar                                                                    */
-/* -------------------------------------------------------------------------- */
-
-Grammar::Grammar()
-    : d_solver(nullptr),
-      d_sygusVars(),
-      d_ntSyms(),
-      d_ntsToTerms(0),
-      d_allowConst(),
-      d_allowVars(),
-      d_isResolved(false)
-{
-}
-
-Grammar::Grammar(const Solver* slv,
-                 const std::vector<Term>& sygusVars,
-                 const std::vector<Term>& ntSymbols)
-    : d_solver(slv),
-      d_sygusVars(sygusVars),
-      d_ntSyms(ntSymbols),
-      d_ntsToTerms(ntSymbols.size()),
-      d_allowConst(),
-      d_allowVars(),
-      d_isResolved(false)
-{
-  for (Term ntsymbol : d_ntSyms)
-  {
-    d_ntsToTerms.emplace(ntsymbol, std::vector<Term>());
-  }
-}
-
-void Grammar::addRule(const Term& ntSymbol, const Term& rule)
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK(!d_isResolved) << "Grammar cannot be modified after passing "
-                                   "it as an argument to synthFun/synthInv";
-  CVC4_API_CHECK_TERM(ntSymbol);
-  CVC4_API_CHECK_TERM(rule);
-  CVC4_API_ARG_CHECK_EXPECTED(
-      d_ntsToTerms.find(ntSymbol) != d_ntsToTerms.cend(), ntSymbol)
-      << "ntSymbol to be one of the non-terminal symbols given in the "
-         "predeclaration";
-  CVC4_API_CHECK(ntSymbol.d_node->getType() == rule.d_node->getType())
-      << "Expected ntSymbol and rule to have the same sort";
-  CVC4_API_ARG_CHECK_EXPECTED(!containsFreeVariables(rule), rule)
-      << "a term whose free variables are limited to synthFun/synthInv "
-         "parameters and non-terminal symbols of the grammar";
-  //////// all checks before this line
-  d_ntsToTerms[ntSymbol].push_back(rule);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-void Grammar::addRules(const Term& ntSymbol, const std::vector<Term>& rules)
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK(!d_isResolved) << "Grammar cannot be modified after passing "
-                                   "it as an argument to synthFun/synthInv";
-  CVC4_API_CHECK_TERM(ntSymbol);
-  CVC4_API_CHECK_TERMS_WITH_SORT(rules, ntSymbol.getSort());
-  CVC4_API_ARG_CHECK_EXPECTED(
-      d_ntsToTerms.find(ntSymbol) != d_ntsToTerms.cend(), ntSymbol)
-      << "ntSymbol to be one of the non-terminal symbols given in the "
-         "predeclaration";
-  for (size_t i = 0, n = rules.size(); i < n; ++i)
-  {
-    CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
-        !containsFreeVariables(rules[i]), rules[i], rules, i)
-        << "a term whose free variables are limited to synthFun/synthInv "
-           "parameters and non-terminal symbols of the grammar";
-  }
-  //////// all checks before this line
-  d_ntsToTerms[ntSymbol].insert(
-      d_ntsToTerms[ntSymbol].cend(), rules.cbegin(), rules.cend());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-void Grammar::addAnyConstant(const Term& ntSymbol)
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK(!d_isResolved) << "Grammar cannot be modified after passing "
-                                   "it as an argument to synthFun/synthInv";
-  CVC4_API_CHECK_TERM(ntSymbol);
-  CVC4_API_ARG_CHECK_EXPECTED(
-      d_ntsToTerms.find(ntSymbol) != d_ntsToTerms.cend(), ntSymbol)
-      << "ntSymbol to be one of the non-terminal symbols given in the "
-         "predeclaration";
-  //////// all checks before this line
-  d_allowConst.insert(ntSymbol);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-void Grammar::addAnyVariable(const Term& ntSymbol)
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK(!d_isResolved) << "Grammar cannot be modified after passing "
-                                   "it as an argument to synthFun/synthInv";
-  CVC4_API_CHECK_TERM(ntSymbol);
-  CVC4_API_ARG_CHECK_EXPECTED(
-      d_ntsToTerms.find(ntSymbol) != d_ntsToTerms.cend(), ntSymbol)
-      << "ntSymbol to be one of the non-terminal symbols given in the "
-         "predeclaration";
-  //////// all checks before this line
-  d_allowVars.insert(ntSymbol);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/**
- * this function concatinates the outputs of calling f on each element between
- * first and last, seperated by sep.
- * @param first the beginning of the range
- * @param last the end of the range
- * @param f the function to call on each element in the range, its output must
- *          be overloaded for operator<<
- * @param sep the string to add between successive calls to f
- */
-template <typename Iterator, typename Function>
-std::string join(Iterator first, Iterator last, Function f, std::string sep)
-{
-  std::stringstream ss;
-  Iterator i = first;
-
-  if (i != last)
-  {
-    ss << f(*i);
-    ++i;
-  }
-
-  while (i != last)
-  {
-    ss << sep << f(*i);
-    ++i;
-  }
-
-  return ss.str();
-}
-
-std::string Grammar::toString() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  std::stringstream ss;
-  ss << "  ("  // pre-declaration
-     << join(
-            d_ntSyms.cbegin(),
-            d_ntSyms.cend(),
-            [](const Term& t) {
-              std::stringstream s;
-              s << '(' << t << ' ' << t.getSort() << ')';
-              return s.str();
-            },
-            " ")
-     << ")\n  ("  // grouped rule listing
-     << join(
-            d_ntSyms.cbegin(),
-            d_ntSyms.cend(),
-            [this](const Term& t) {
-              bool allowConst = d_allowConst.find(t) != d_allowConst.cend(),
-                   allowVars = d_allowVars.find(t) != d_allowVars.cend();
-              const std::vector<Term>& rules = d_ntsToTerms.at(t);
-              std::stringstream s;
-              s << '(' << t << ' ' << t.getSort() << " ("
-                << (allowConst ? "(Constant " + t.getSort().toString() + ")"
-                               : "")
-                << (allowConst && allowVars ? " " : "")
-                << (allowVars ? "(Var " + t.getSort().toString() + ")" : "")
-                << ((allowConst || allowVars) && !rules.empty() ? " " : "")
-                << join(
-                       rules.cbegin(),
-                       rules.cend(),
-                       [](const Term& rule) { return rule.toString(); },
-                       " ")
-                << "))";
-              return s.str();
-            },
-            "\n   ")
-     << ')';
-
-  return ss.str();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Grammar::resolve()
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-
-  d_isResolved = true;
-
-  Term bvl;
-
-  if (!d_sygusVars.empty())
-  {
-    bvl = Term(
-        d_solver,
-        d_solver->getNodeManager()->mkNode(
-            cvc5::kind::BOUND_VAR_LIST, Term::termVectorToNodes(d_sygusVars)));
-  }
-
-  std::unordered_map<Term, Sort, TermHashFunction> ntsToUnres(d_ntSyms.size());
-
-  for (Term ntsymbol : d_ntSyms)
-  {
-    // make the unresolved type, used for referencing the final version of
-    // the ntsymbol's datatype
-    ntsToUnres[ntsymbol] =
-        Sort(d_solver, d_solver->getNodeManager()->mkSort(ntsymbol.toString()));
-  }
-
-  std::vector<cvc5::DType> datatypes;
-  std::set<TypeNode> unresTypes;
-
-  datatypes.reserve(d_ntSyms.size());
-
-  for (const Term& ntSym : d_ntSyms)
-  {
-    // make the datatype, which encodes terms generated by this non-terminal
-    DatatypeDecl dtDecl(d_solver, ntSym.toString());
-
-    for (const Term& consTerm : d_ntsToTerms[ntSym])
-    {
-      addSygusConstructorTerm(dtDecl, consTerm, ntsToUnres);
-    }
-
-    if (d_allowVars.find(ntSym) != d_allowVars.cend())
-    {
-      addSygusConstructorVariables(dtDecl,
-                                   Sort(d_solver, ntSym.d_node->getType()));
-    }
-
-    bool aci = d_allowConst.find(ntSym) != d_allowConst.end();
-    TypeNode btt = ntSym.d_node->getType();
-    dtDecl.d_dtype->setSygus(btt, *bvl.d_node, aci, false);
-
-    // We can be in a case where the only rule specified was (Variable T)
-    // and there are no variables of type T, in which case this is a bogus
-    // grammar. This results in the error below.
-    CVC4_API_CHECK(dtDecl.d_dtype->getNumConstructors() != 0)
-        << "Grouped rule listing for " << *dtDecl.d_dtype
-        << " produced an empty rule list";
-
-    datatypes.push_back(*dtDecl.d_dtype);
-    unresTypes.insert(*ntsToUnres[ntSym].d_type);
-  }
-
-  std::vector<TypeNode> datatypeTypes =
-      d_solver->getNodeManager()->mkMutualDatatypeTypes(
-          datatypes, unresTypes, NodeManager::DATATYPE_FLAG_PLACEHOLDER);
-
-  // return is the first datatype
-  return Sort(d_solver, datatypeTypes[0]);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-void Grammar::addSygusConstructorTerm(
-    DatatypeDecl& dt,
-    const Term& term,
-    const std::unordered_map<Term, Sort, TermHashFunction>& ntsToUnres) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_DTDECL(dt);
-  CVC4_API_CHECK_TERM(term);
-  CVC4_API_CHECK_TERMS_MAP(ntsToUnres);
-  //////// all checks before this line
-
-  // At this point, we should know that dt is well founded, and that its
-  // builtin sygus operators are well-typed.
-  // Now, purify each occurrence of a non-terminal symbol in term, replace by
-  // free variables. These become arguments to constructors. Notice we must do
-  // a tree traversal in this function, since unique paths to the same term
-  // should be treated as distinct terms.
-  // Notice that let expressions are forbidden in the input syntax of term, so
-  // this does not lead to exponential behavior with respect to input size.
-  std::vector<Term> args;
-  std::vector<Sort> cargs;
-  Term op = purifySygusGTerm(term, args, cargs, ntsToUnres);
-  std::stringstream ssCName;
-  ssCName << op.getKind();
-  if (!args.empty())
-  {
-    Term lbvl =
-        Term(d_solver,
-             d_solver->getNodeManager()->mkNode(cvc5::kind::BOUND_VAR_LIST,
-                                                Term::termVectorToNodes(args)));
-    // its operator is a lambda
-    op = Term(d_solver,
-              d_solver->getNodeManager()->mkNode(
-                  cvc5::kind::LAMBDA, *lbvl.d_node, *op.d_node));
-  }
-  std::vector<TypeNode> cargst = Sort::sortVectorToTypeNodes(cargs);
-  dt.d_dtype->addSygusConstructor(*op.d_node, ssCName.str(), cargst);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Grammar::purifySygusGTerm(
-    const Term& term,
-    std::vector<Term>& args,
-    std::vector<Sort>& cargs,
-    const std::unordered_map<Term, Sort, TermHashFunction>& ntsToUnres) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_TERM(term);
-  CVC4_API_CHECK_TERMS(args);
-  CVC4_API_CHECK_SORTS(cargs);
-  CVC4_API_CHECK_TERMS_MAP(ntsToUnres);
-  //////// all checks before this line
-
-  std::unordered_map<Term, Sort, TermHashFunction>::const_iterator itn =
-      ntsToUnres.find(term);
-  if (itn != ntsToUnres.cend())
-  {
-    Term ret =
-        Term(d_solver,
-             d_solver->getNodeManager()->mkBoundVar(term.d_node->getType()));
-    args.push_back(ret);
-    cargs.push_back(itn->second);
-    return ret;
-  }
-  std::vector<Term> pchildren;
-  bool childChanged = false;
-  for (unsigned i = 0, nchild = term.d_node->getNumChildren(); i < nchild; i++)
-  {
-    Term ptermc = purifySygusGTerm(
-        Term(d_solver, (*term.d_node)[i]), args, cargs, ntsToUnres);
-    pchildren.push_back(ptermc);
-    childChanged = childChanged || *ptermc.d_node != (*term.d_node)[i];
-  }
-  if (!childChanged)
-  {
-    return term;
-  }
-
-  Node nret;
-
-  if (term.d_node->getMetaKind() == kind::metakind::PARAMETERIZED)
-  {
-    // it's an indexed operator so we should provide the op
-    NodeBuilder<> nb(term.d_node->getKind());
-    nb << term.d_node->getOperator();
-    nb.append(Term::termVectorToNodes(pchildren));
-    nret = nb.constructNode();
-  }
-  else
-  {
-    nret = d_solver->getNodeManager()->mkNode(
-        term.d_node->getKind(), Term::termVectorToNodes(pchildren));
-  }
-
-  return Term(d_solver, nret);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-void Grammar::addSygusConstructorVariables(DatatypeDecl& dt,
-                                           const Sort& sort) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK_DTDECL(dt);
-  CVC4_API_CHECK_SORT(sort);
-  //////// all checks before this line
-
-  // each variable of appropriate type becomes a sygus constructor in dt.
-  for (unsigned i = 0, size = d_sygusVars.size(); i < size; i++)
-  {
-    Term v = d_sygusVars[i];
-    if (v.d_node->getType() == *sort.d_type)
-    {
-      std::stringstream ss;
-      ss << v;
-      std::vector<TypeNode> cargs;
-      dt.d_dtype->addSygusConstructor(*v.d_node, ss.str(), cargs);
-    }
-  }
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Grammar::containsFreeVariables(const Term& rule) const
-{
-  std::unordered_set<TNode, TNodeHashFunction> scope;
-
-  for (const Term& sygusVar : d_sygusVars)
-  {
-    scope.emplace(*sygusVar.d_node);
-  }
-
-  for (const Term& ntsymbol : d_ntSyms)
-  {
-    scope.emplace(*ntsymbol.d_node);
-  }
-
-  std::unordered_set<Node, NodeHashFunction> fvs;
-  return expr::getFreeVariablesScope(*rule.d_node, fvs, scope, false);
-}
-
-std::ostream& operator<<(std::ostream& out, const Grammar& grammar)
-{
-  return out << grammar.toString();
-}
-
-/* -------------------------------------------------------------------------- */
-/* Rounding Mode for Floating Points                                          */
-/* -------------------------------------------------------------------------- */
-
-const static std::
-    unordered_map<RoundingMode, cvc5::RoundingMode, RoundingModeHashFunction>
-        s_rmodes{
-            {ROUND_NEAREST_TIES_TO_EVEN,
-             cvc5::RoundingMode::ROUND_NEAREST_TIES_TO_EVEN},
-            {ROUND_TOWARD_POSITIVE, cvc5::RoundingMode::ROUND_TOWARD_POSITIVE},
-            {ROUND_TOWARD_NEGATIVE, cvc5::RoundingMode::ROUND_TOWARD_NEGATIVE},
-            {ROUND_TOWARD_ZERO, cvc5::RoundingMode::ROUND_TOWARD_ZERO},
-            {ROUND_NEAREST_TIES_TO_AWAY,
-             cvc5::RoundingMode::ROUND_NEAREST_TIES_TO_AWAY},
-        };
-
-const static std::unordered_map<cvc5::RoundingMode,
-                                RoundingMode,
-                                cvc5::RoundingModeHashFunction>
-    s_rmodes_internal{
-        {cvc5::RoundingMode::ROUND_NEAREST_TIES_TO_EVEN,
-         ROUND_NEAREST_TIES_TO_EVEN},
-        {cvc5::RoundingMode::ROUND_TOWARD_POSITIVE, ROUND_TOWARD_POSITIVE},
-        {cvc5::RoundingMode::ROUND_TOWARD_POSITIVE, ROUND_TOWARD_NEGATIVE},
-        {cvc5::RoundingMode::ROUND_TOWARD_ZERO, ROUND_TOWARD_ZERO},
-        {cvc5::RoundingMode::ROUND_NEAREST_TIES_TO_AWAY,
-         ROUND_NEAREST_TIES_TO_AWAY},
-    };
-
-size_t RoundingModeHashFunction::operator()(const RoundingMode& rm) const
-{
-  return size_t(rm);
-}
-
-/* -------------------------------------------------------------------------- */
-/* Solver                                                                     */
-/* -------------------------------------------------------------------------- */
-
-Solver::Solver(Options* opts)
-{
-  d_nodeMgr.reset(new NodeManager());
-  d_originalOptions.reset(new Options());
-  if (opts != nullptr)
-  {
-    d_originalOptions->copyValues(*opts);
-  }
-  d_smtEngine.reset(new SmtEngine(d_nodeMgr.get(), d_originalOptions.get()));
-  d_smtEngine->setSolver(this);
-  d_rng.reset(new Random(d_smtEngine->getOptions()[options::seed]));
-#if CVC4_STATISTICS_ON
-  d_stats.reset(new Statistics());
-  d_smtEngine->getStatisticsRegistry().registerStat(&d_stats->d_consts);
-  d_smtEngine->getStatisticsRegistry().registerStat(&d_stats->d_vars);
-  d_smtEngine->getStatisticsRegistry().registerStat(&d_stats->d_terms);
-#endif
-}
-
-Solver::~Solver() {}
-
-/* Helpers and private functions                                              */
-/* -------------------------------------------------------------------------- */
-
-NodeManager* Solver::getNodeManager(void) const { return d_nodeMgr.get(); }
-
-void Solver::increment_term_stats(Kind kind) const
-{
-#ifdef CVC4_STATISTICS_ON
-  d_stats->d_terms << kind;
-#endif
-}
-
-void Solver::increment_vars_consts_stats(const Sort& sort, bool is_var) const
-{
-#ifdef CVC4_STATISTICS_ON
-  const TypeNode tn = sort.getTypeNode();
-  TypeConstant tc = tn.getKind() == cvc5::kind::TYPE_CONSTANT
-                        ? tn.getConst<TypeConstant>()
-                        : LAST_TYPE;
-  if (is_var)
-  {
-    d_stats->d_vars << tc;
-  }
-  else
-  {
-    d_stats->d_consts << tc;
-  }
-#endif
-}
-
-/* Split out to avoid nested API calls (problematic with API tracing).        */
-/* .......................................................................... */
-
-template <typename T>
-Term Solver::mkValHelper(T t) const
-{
-  //////// all checks before this line
-  Node res = getNodeManager()->mkConst(t);
-  (void)res.getType(true); /* kick off type checking */
-  return Term(this, res);
-}
-
-Term Solver::mkRealFromStrHelper(const std::string& s) const
-{
-  //////// all checks before this line
-  try
-  {
-    cvc5::Rational r = s.find('/') != std::string::npos
-                           ? cvc5::Rational(s)
-                           : cvc5::Rational::fromDecimal(s);
-    return mkValHelper<cvc5::Rational>(r);
-  }
-  catch (const std::invalid_argument& e)
-  {
-    /* Catch to throw with a more meaningful error message. To be caught in
-     * enclosing CVC4_API_TRY_CATCH_* block to throw CVC4ApiException. */
-    std::stringstream message;
-    message << "Cannot construct Real or Int from string argument '" << s << "'"
-            << std::endl;
-    throw std::invalid_argument(message.str());
-  }
-}
-
-Term Solver::mkBVFromIntHelper(uint32_t size, uint64_t val) const
-{
-  CVC4_API_ARG_CHECK_EXPECTED(size > 0, size) << "a bit-width > 0";
-  //////// all checks before this line
-  return mkValHelper<cvc5::BitVector>(cvc5::BitVector(size, val));
-}
-
-Term Solver::mkBVFromStrHelper(const std::string& s, uint32_t base) const
-{
-  CVC4_API_ARG_CHECK_EXPECTED(!s.empty(), s) << "a non-empty string";
-  CVC4_API_ARG_CHECK_EXPECTED(base == 2 || base == 10 || base == 16, base)
-      << "base 2, 10, or 16";
-  //////// all checks before this line
-  return mkValHelper<cvc5::BitVector>(cvc5::BitVector(s, base));
-}
-
-Term Solver::mkBVFromStrHelper(uint32_t size,
-                               const std::string& s,
-                               uint32_t base) const
-{
-  CVC4_API_ARG_CHECK_EXPECTED(!s.empty(), s) << "a non-empty string";
-  CVC4_API_ARG_CHECK_EXPECTED(base == 2 || base == 10 || base == 16, base)
-      << "base 2, 10, or 16";
-  //////// all checks before this line
-
-  Integer val(s, base);
-
-  if (val.strictlyNegative())
-  {
-    CVC4_API_CHECK(val >= -Integer("2", 10).pow(size - 1))
-        << "Overflow in bitvector construction (specified bitvector size "
-        << size << " too small to hold value " << s << ")";
-  }
-  else
-  {
-    CVC4_API_CHECK(val.modByPow2(size) == val)
-        << "Overflow in bitvector construction (specified bitvector size "
-        << size << " too small to hold value " << s << ")";
-  }
-
-  return mkValHelper<cvc5::BitVector>(cvc5::BitVector(size, val));
-}
-
-Term Solver::mkCharFromStrHelper(const std::string& s) const
-{
-  CVC4_API_CHECK(s.find_first_not_of("0123456789abcdefABCDEF", 0)
-                     == std::string::npos
-                 && s.size() <= 5 && s.size() > 0)
-      << "Unexpected string for hexadecimal character " << s;
-  uint32_t val = static_cast<uint32_t>(std::stoul(s, 0, 16));
-  CVC4_API_CHECK(val < String::num_codes())
-      << "Not a valid code point for hexadecimal character " << s;
-  //////// all checks before this line
-  std::vector<unsigned> cpts;
-  cpts.push_back(val);
-  return mkValHelper<cvc5::String>(cvc5::String(cpts));
-}
-
-Term Solver::getValueHelper(const Term& term) const
-{
-  // Note: Term is checked in the caller to avoid double checks
-  //////// all checks before this line
-  Node value = d_smtEngine->getValue(*term.d_node);
-  Term res = Term(this, value);
-  // May need to wrap in real cast so that user know this is a real.
-  TypeNode tn = (*term.d_node).getType();
-  if (!tn.isInteger() && value.getType().isInteger())
-  {
-    return ensureRealSort(res);
-  }
-  return res;
-}
-
-Sort Solver::mkTupleSortHelper(const std::vector<Sort>& sorts) const
-{
-  // Note: Sorts are checked in the caller to avoid double checks
-  //////// all checks before this line
-  std::vector<TypeNode> typeNodes = Sort::sortVectorToTypeNodes(sorts);
-  return Sort(this, getNodeManager()->mkTupleType(typeNodes));
-}
-
-Term Solver::mkTermFromKind(Kind kind) const
-{
-  CVC4_API_KIND_CHECK_EXPECTED(
-      kind == PI || kind == REGEXP_EMPTY || kind == REGEXP_SIGMA, kind)
-      << "PI or REGEXP_EMPTY or REGEXP_SIGMA";
-  //////// all checks before this line
-  Node res;
-  if (kind == REGEXP_EMPTY || kind == REGEXP_SIGMA)
-  {
-    cvc5::Kind k = extToIntKind(kind);
-    Assert(isDefinedIntKind(k));
-    res = d_nodeMgr->mkNode(k, std::vector<Node>());
-  }
-  else
-  {
-    Assert(kind == PI);
-    res = d_nodeMgr->mkNullaryOperator(d_nodeMgr->realType(), cvc5::kind::PI);
-  }
-  (void)res.getType(true); /* kick off type checking */
-  increment_term_stats(kind);
-  return Term(this, res);
-}
-
-Term Solver::mkTermHelper(Kind kind, const std::vector<Term>& children) const
-{
-  // Note: Kind and children are checked in the caller to avoid double checks
-  //////// all checks before this line
-
-  std::vector<Node> echildren = Term::termVectorToNodes(children);
-  cvc5::Kind k = extToIntKind(kind);
-  Node res;
-  if (echildren.size() > 2)
-  {
-    if (kind == INTS_DIVISION || kind == XOR || kind == MINUS
-        || kind == DIVISION || kind == HO_APPLY || kind == REGEXP_DIFF)
-    {
-      // left-associative, but CVC4 internally only supports 2 args
-      res = d_nodeMgr->mkLeftAssociative(k, echildren);
-    }
-    else if (kind == IMPLIES)
-    {
-      // right-associative, but CVC4 internally only supports 2 args
-      res = d_nodeMgr->mkRightAssociative(k, echildren);
-    }
-    else if (kind == EQUAL || kind == LT || kind == GT || kind == LEQ
-             || kind == GEQ)
-    {
-      // "chainable", but CVC4 internally only supports 2 args
-      res = d_nodeMgr->mkChain(k, echildren);
-    }
-    else if (kind::isAssociative(k))
-    {
-      // mkAssociative has special treatment for associative operators with lots
-      // of children
-      res = d_nodeMgr->mkAssociative(k, echildren);
-    }
-    else
-    {
-      // default case, must check kind
-      checkMkTerm(kind, children.size());
-      res = d_nodeMgr->mkNode(k, echildren);
-    }
-  }
-  else if (kind::isAssociative(k))
-  {
-    // associative case, same as above
-    res = d_nodeMgr->mkAssociative(k, echildren);
-  }
-  else
-  {
-    // default case, same as above
-    checkMkTerm(kind, children.size());
-    if (kind == api::SINGLETON)
-    {
-      // the type of the term is the same as the type of the internal node
-      // see Term::getSort()
-      TypeNode type = children[0].d_node->getType();
-      // Internally NodeManager::mkSingleton needs a type argument
-      // to construct a singleton, since there is no difference between
-      // integers and reals (both are Rationals).
-      // At the API, mkReal and mkInteger are different and therefore the
-      // element type can be used safely here.
-      res = getNodeManager()->mkSingleton(type, *children[0].d_node);
-    }
-    else if (kind == api::MK_BAG)
-    {
-      // the type of the term is the same as the type of the internal node
-      // see Term::getSort()
-      TypeNode type = children[0].d_node->getType();
-      // Internally NodeManager::mkBag needs a type argument
-      // to construct a bag, since there is no difference between
-      // integers and reals (both are Rationals).
-      // At the API, mkReal and mkInteger are different and therefore the
-      // element type can be used safely here.
-      res = getNodeManager()->mkBag(
-          type, *children[0].d_node, *children[1].d_node);
-    }
-    else
-    {
-      res = d_nodeMgr->mkNode(k, echildren);
-    }
-  }
-
-  (void)res.getType(true); /* kick off type checking */
-  increment_term_stats(kind);
-  return Term(this, res);
-}
-
-Term Solver::mkTermHelper(const Op& op, const std::vector<Term>& children) const
-{
-  // Note: Op and children are checked in the caller to avoid double checks
-  checkMkTerm(op.d_kind, children.size());
-  //////// all checks before this line
-
-  if (!op.isIndexedHelper())
-  {
-    return mkTermHelper(op.d_kind, children);
-  }
-
-  const cvc5::Kind int_kind = extToIntKind(op.d_kind);
-  std::vector<Node> echildren = Term::termVectorToNodes(children);
-
-  NodeBuilder<> nb(int_kind);
-  nb << *op.d_node;
-  nb.append(echildren);
-  Node res = nb.constructNode();
-
-  (void)res.getType(true); /* kick off type checking */
-  return Term(this, res);
-}
-
-std::vector<Sort> Solver::mkDatatypeSortsInternal(
-    const std::vector<DatatypeDecl>& dtypedecls,
-    const std::set<Sort>& unresolvedSorts) const
-{
-  // Note: dtypedecls and unresolvedSorts are checked in the caller to avoid
-  //       double checks
-  //////// all checks before this line
-
-  std::vector<cvc5::DType> datatypes;
-  for (size_t i = 0, ndts = dtypedecls.size(); i < ndts; ++i)
-  {
-    datatypes.push_back(dtypedecls[i].getDatatype());
-  }
-
-  std::set<TypeNode> utypes = Sort::sortSetToTypeNodes(unresolvedSorts);
-  std::vector<cvc5::TypeNode> dtypes =
-      getNodeManager()->mkMutualDatatypeTypes(datatypes, utypes);
-  std::vector<Sort> retTypes = Sort::typeNodeVectorToSorts(this, dtypes);
-  return retTypes;
-}
-
-Term Solver::synthFunHelper(const std::string& symbol,
-                            const std::vector<Term>& boundVars,
-                            const Sort& sort,
-                            bool isInv,
-                            Grammar* grammar) const
-{
-  // Note: boundVars, sort and grammar are checked in the caller to avoid
-  //       double checks.
-  std::vector<TypeNode> varTypes;
-  for (const auto& bv : boundVars)
-  {
-    if (grammar)
-    {
-      CVC4_API_CHECK(grammar->d_ntSyms[0].d_node->getType() == *sort.d_type)
-          << "Invalid Start symbol for grammar, Expected Start's sort to be "
-          << *sort.d_type << " but found "
-          << grammar->d_ntSyms[0].d_node->getType();
-    }
-    varTypes.push_back(bv.d_node->getType());
-  }
-  //////// all checks before this line
-
-  TypeNode funType = varTypes.empty() ? *sort.d_type
-                                      : getNodeManager()->mkFunctionType(
-                                          varTypes, *sort.d_type);
-
-  Node fun = getNodeManager()->mkBoundVar(symbol, funType);
-  (void)fun.getType(true); /* kick off type checking */
-
-  std::vector<Node> bvns = Term::termVectorToNodes(boundVars);
-
-  d_smtEngine->declareSynthFun(
-      fun,
-      grammar == nullptr ? funType : *grammar->resolve().d_type,
-      isInv,
-      bvns);
-
-  return Term(this, fun);
-}
-
-Term Solver::ensureTermSort(const Term& term, const Sort& sort) const
-{
-  // Note: Term and sort are checked in the caller to avoid double checks
-  CVC4_API_CHECK(term.getSort() == sort
-                 || (term.getSort().isInteger() && sort.isReal()))
-      << "Expected conversion from Int to Real";
-  //////// all checks before this line
-
-  Sort t = term.getSort();
-  if (term.getSort() == sort)
-  {
-    return term;
-  }
-
-  // Integers are reals, too
-  Assert(t.d_type->isReal());
-  Term res = term;
-  if (t.isInteger())
-  {
-    // Must cast to Real to ensure correct type is passed to parametric type
-    // constructors. We do this cast using division with 1. This has the
-    // advantage wrt using TO_REAL since (constant) division is always included
-    // in the theory.
-    res = Term(this,
-               d_nodeMgr->mkNode(extToIntKind(DIVISION),
-                                 *res.d_node,
-                                 d_nodeMgr->mkConst(cvc5::Rational(1))));
-  }
-  Assert(res.getSort() == sort);
-  return res;
-}
-
-Term Solver::ensureRealSort(const Term& t) const
-{
-  Assert(this == t.d_solver);
-  CVC4_API_ARG_CHECK_EXPECTED(
-      t.getSort() == getIntegerSort() || t.getSort() == getRealSort(),
-      " an integer or real term");
-  // Note: Term is checked in the caller to avoid double checks
-  //////// all checks before this line
-  if (t.getSort() == getIntegerSort())
-  {
-    Node n = getNodeManager()->mkNode(kind::CAST_TO_REAL, *t.d_node);
-    return Term(this, n);
-  }
-  return t;
-}
-
-bool Solver::isValidInteger(const std::string& s) const
-{
-  //////// all checks before this line
-  if (s.length() == 0)
-  {
-    // string should not be empty
-    return false;
-  }
-
-  size_t index = 0;
-  if (s[index] == '-')
-  {
-    if (s.length() == 1)
-    {
-      // negative integers should contain at least one digit
-      return false;
-    }
-    index = 1;
-  }
-
-  if (s[index] == '0' && s.length() > (index + 1))
-  {
-    // From SMT-Lib 2.6: A <numeral> is the digit 0 or a non-empty sequence of
-    // digits not starting with 0. So integers like 001, 000 are not allowed
-    return false;
-  }
-
-  // all remaining characters should be decimal digits
-  for (; index < s.length(); ++index)
-  {
-    if (!std::isdigit(s[index]))
-    {
-      return false;
-    }
-  }
-
-  return true;
-}
-
-/* Helpers for mkTerm checks.                                                 */
-/* .......................................................................... */
-
-void Solver::checkMkTerm(Kind kind, uint32_t nchildren) const
-{
-  CVC4_API_KIND_CHECK(kind);
-  Assert(isDefinedIntKind(extToIntKind(kind)));
-  const cvc5::kind::MetaKind mk = kind::metaKindOf(extToIntKind(kind));
-  CVC4_API_KIND_CHECK_EXPECTED(
-      mk == kind::metakind::PARAMETERIZED || mk == kind::metakind::OPERATOR,
-      kind)
-      << "Only operator-style terms are created with mkTerm(), "
-         "to create variables, constants and values see mkVar(), mkConst() "
-         "and the respective theory-specific functions to create values, "
-         "e.g., mkBitVector().";
-  CVC4_API_KIND_CHECK_EXPECTED(
-      nchildren >= minArity(kind) && nchildren <= maxArity(kind), kind)
-      << "Terms with kind " << kindToString(kind) << " must have at least "
-      << minArity(kind) << " children and at most " << maxArity(kind)
-      << " children (the one under construction has " << nchildren << ")";
-}
-
-/* Solver Configuration                                                       */
-/* -------------------------------------------------------------------------- */
-
-bool Solver::supportsFloatingPoint() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return Configuration::isBuiltWithSymFPU();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/* Sorts Handling                                                             */
-/* -------------------------------------------------------------------------- */
-
-Sort Solver::getNullSort(void) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return Sort(this, TypeNode());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Solver::getBooleanSort(void) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return Sort(this, getNodeManager()->booleanType());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Solver::getIntegerSort(void) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return Sort(this, getNodeManager()->integerType());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Solver::getRealSort(void) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return Sort(this, getNodeManager()->realType());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Solver::getRegExpSort(void) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return Sort(this, getNodeManager()->regExpType());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Solver::getStringSort(void) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return Sort(this, getNodeManager()->stringType());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Solver::getRoundingModeSort(void) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK(Configuration::isBuiltWithSymFPU())
-      << "Expected CVC4 to be compiled with SymFPU support";
-  //////// all checks before this line
-  return Sort(this, getNodeManager()->roundingModeType());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/* Create sorts ------------------------------------------------------- */
-
-Sort Solver::mkArraySort(const Sort& indexSort, const Sort& elemSort) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_SORT(indexSort);
-  CVC4_API_SOLVER_CHECK_SORT(elemSort);
-  //////// all checks before this line
-  return Sort(
-      this, getNodeManager()->mkArrayType(*indexSort.d_type, *elemSort.d_type));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Solver::mkBitVectorSort(uint32_t size) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_ARG_CHECK_EXPECTED(size > 0, size) << "size > 0";
-  //////// all checks before this line
-  return Sort(this, getNodeManager()->mkBitVectorType(size));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Solver::mkFloatingPointSort(uint32_t exp, uint32_t sig) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK(Configuration::isBuiltWithSymFPU())
-      << "Expected CVC4 to be compiled with SymFPU support";
-  CVC4_API_ARG_CHECK_EXPECTED(exp > 0, exp) << "exponent size > 0";
-  CVC4_API_ARG_CHECK_EXPECTED(sig > 0, sig) << "significand size > 0";
-  //////// all checks before this line
-  return Sort(this, getNodeManager()->mkFloatingPointType(exp, sig));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Solver::mkDatatypeSort(const DatatypeDecl& dtypedecl) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_DTDECL(dtypedecl);
-  //////// all checks before this line
-  return Sort(this, getNodeManager()->mkDatatypeType(*dtypedecl.d_dtype));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-std::vector<Sort> Solver::mkDatatypeSorts(
-    const std::vector<DatatypeDecl>& dtypedecls) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_SOLVER_CHECK_DTDECLS(dtypedecls);
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return mkDatatypeSortsInternal(dtypedecls, {});
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-std::vector<Sort> Solver::mkDatatypeSorts(
-    const std::vector<DatatypeDecl>& dtypedecls,
-    const std::set<Sort>& unresolvedSorts) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_DTDECLS(dtypedecls);
-  CVC4_API_SOLVER_CHECK_SORTS(unresolvedSorts);
-  //////// all checks before this line
-  return mkDatatypeSortsInternal(dtypedecls, unresolvedSorts);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Solver::mkFunctionSort(const Sort& domain, const Sort& codomain) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_DOMAIN_SORT(domain);
-  CVC4_API_SOLVER_CHECK_CODOMAIN_SORT(codomain);
-  //////// all checks before this line
-  return Sort(
-      this, getNodeManager()->mkFunctionType(*domain.d_type, *codomain.d_type));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Solver::mkFunctionSort(const std::vector<Sort>& sorts,
-                            const Sort& codomain) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_ARG_SIZE_CHECK_EXPECTED(sorts.size() >= 1, sorts)
-      << "at least one parameter sort for function sort";
-  CVC4_API_SOLVER_CHECK_DOMAIN_SORTS(sorts);
-  CVC4_API_SOLVER_CHECK_CODOMAIN_SORT(codomain);
-  //////// all checks before this line
-  std::vector<TypeNode> argTypes = Sort::sortVectorToTypeNodes(sorts);
-  return Sort(this,
-              getNodeManager()->mkFunctionType(argTypes, *codomain.d_type));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Solver::mkParamSort(const std::string& symbol) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return Sort(
-      this,
-      getNodeManager()->mkSort(symbol, NodeManager::SORT_FLAG_PLACEHOLDER));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Solver::mkPredicateSort(const std::vector<Sort>& sorts) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_ARG_SIZE_CHECK_EXPECTED(sorts.size() >= 1, sorts)
-      << "at least one parameter sort for predicate sort";
-  CVC4_API_SOLVER_CHECK_DOMAIN_SORTS(sorts);
-  //////// all checks before this line
-  return Sort(
-      this,
-      getNodeManager()->mkPredicateType(Sort::sortVectorToTypeNodes(sorts)));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Solver::mkRecordSort(
-    const std::vector<std::pair<std::string, Sort>>& fields) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  std::vector<std::pair<std::string, TypeNode>> f;
-  for (size_t i = 0, size = fields.size(); i < size; ++i)
-  {
-    const auto& p = fields[i];
-    CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(!p.second.isNull(), "sort", fields, i)
-        << "non-null sort";
-    CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
-        this == p.second.d_solver, "sort", fields, i)
-        << "sort associated with this solver object";
-    f.emplace_back(p.first, *p.second.d_type);
-  }
-  //////// all checks before this line
-  return Sort(this, getNodeManager()->mkRecordType(f));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Solver::mkSetSort(const Sort& elemSort) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_SORT(elemSort);
-  //////// all checks before this line
-  return Sort(this, getNodeManager()->mkSetType(*elemSort.d_type));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Solver::mkBagSort(const Sort& elemSort) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_SORT(elemSort);
-  //////// all checks before this line
-  return Sort(this, getNodeManager()->mkBagType(*elemSort.d_type));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Solver::mkSequenceSort(const Sort& elemSort) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_SORT(elemSort);
-  //////// all checks before this line
-  return Sort(this, getNodeManager()->mkSequenceType(*elemSort.d_type));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Solver::mkUninterpretedSort(const std::string& symbol) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return Sort(this, getNodeManager()->mkSort(symbol));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Solver::mkSortConstructorSort(const std::string& symbol,
-                                   size_t arity) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_ARG_CHECK_EXPECTED(arity > 0, arity) << "an arity > 0";
-  //////// all checks before this line
-  return Sort(this, getNodeManager()->mkSortConstructor(symbol, arity));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Sort Solver::mkTupleSort(const std::vector<Sort>& sorts) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_SORTS_NOT_FUNCTION_LIKE(sorts);
-  //////// all checks before this line
-  return mkTupleSortHelper(sorts);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/* Create consts                                                              */
-/* -------------------------------------------------------------------------- */
-
-Term Solver::mkTrue(void) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return Term(this, d_nodeMgr->mkConst<bool>(true));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkFalse(void) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return Term(this, d_nodeMgr->mkConst<bool>(false));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkBoolean(bool val) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return Term(this, d_nodeMgr->mkConst<bool>(val));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkPi() const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  Node res =
-      d_nodeMgr->mkNullaryOperator(d_nodeMgr->realType(), cvc5::kind::PI);
-  (void)res.getType(true); /* kick off type checking */
-  return Term(this, res);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkInteger(const std::string& s) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_ARG_CHECK_EXPECTED(isValidInteger(s), s) << " an integer ";
-  Term integer = mkRealFromStrHelper(s);
-  CVC4_API_ARG_CHECK_EXPECTED(integer.getSort() == getIntegerSort(), s)
-      << " a string representing an integer";
-  //////// all checks before this line
-  return integer;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkInteger(int64_t val) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  Term integer = mkValHelper<cvc5::Rational>(cvc5::Rational(val));
-  Assert(integer.getSort() == getIntegerSort());
-  return integer;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkReal(const std::string& s) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  /* CLN and GMP handle this case differently, CLN interprets it as 0, GMP
-   * throws an std::invalid_argument exception. For consistency, we treat it
-   * as invalid. */
-  CVC4_API_ARG_CHECK_EXPECTED(s != ".", s)
-      << "a string representing a real or rational value.";
-  //////// all checks before this line
-  Term rational = mkRealFromStrHelper(s);
-  return ensureRealSort(rational);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkReal(int64_t val) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  Term rational = mkValHelper<cvc5::Rational>(cvc5::Rational(val));
-  return ensureRealSort(rational);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkReal(int64_t num, int64_t den) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  Term rational = mkValHelper<cvc5::Rational>(cvc5::Rational(num, den));
-  return ensureRealSort(rational);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkRegexpEmpty() const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  Node res =
-      d_nodeMgr->mkNode(cvc5::kind::REGEXP_EMPTY, std::vector<cvc5::Node>());
-  (void)res.getType(true); /* kick off type checking */
-  return Term(this, res);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkRegexpSigma() const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  Node res =
-      d_nodeMgr->mkNode(cvc5::kind::REGEXP_SIGMA, std::vector<cvc5::Node>());
-  (void)res.getType(true); /* kick off type checking */
-  return Term(this, res);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkEmptySet(const Sort& sort) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_ARG_CHECK_EXPECTED(sort.isNull() || sort.isSet(), sort)
-      << "null sort or set sort";
-  CVC4_API_ARG_CHECK_EXPECTED(sort.isNull() || this == sort.d_solver, sort)
-      << "set sort associated with this solver object";
-  //////// all checks before this line
-  return mkValHelper<cvc5::EmptySet>(cvc5::EmptySet(*sort.d_type));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkEmptyBag(const Sort& sort) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_ARG_CHECK_EXPECTED(sort.isNull() || sort.isBag(), sort)
-      << "null sort or bag sort";
-  CVC4_API_ARG_CHECK_EXPECTED(sort.isNull() || this == sort.d_solver, sort)
-      << "bag sort associated with this solver object";
-  //////// all checks before this line
-  return mkValHelper<cvc5::EmptyBag>(cvc5::EmptyBag(*sort.d_type));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkSepNil(const Sort& sort) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_SORT(sort);
-  //////// all checks before this line
-  Node res =
-      getNodeManager()->mkNullaryOperator(*sort.d_type, cvc5::kind::SEP_NIL);
-  (void)res.getType(true); /* kick off type checking */
-  return Term(this, res);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkString(const std::string& s, bool useEscSequences) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return mkValHelper<cvc5::String>(cvc5::String(s, useEscSequences));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkString(const unsigned char c) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return mkValHelper<cvc5::String>(cvc5::String(std::string(1, c)));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkString(const std::vector<uint32_t>& s) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return mkValHelper<cvc5::String>(cvc5::String(s));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkChar(const std::string& s) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return mkCharFromStrHelper(s);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkEmptySequence(const Sort& sort) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_SORT(sort);
-  //////// all checks before this line
-  std::vector<Node> seq;
-  Node res = d_nodeMgr->mkConst(Sequence(*sort.d_type, seq));
-  return Term(this, res);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkUniverseSet(const Sort& sort) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_SORT(sort);
-  //////// all checks before this line
-
-  Node res = getNodeManager()->mkNullaryOperator(*sort.d_type,
-                                                 cvc5::kind::UNIVERSE_SET);
-  // TODO(#2771): Reenable?
-  // (void)res->getType(true); /* kick off type checking */
-  return Term(this, res);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkBitVector(uint32_t size, uint64_t val) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return mkBVFromIntHelper(size, val);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkBitVector(const std::string& s, uint32_t base) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return mkBVFromStrHelper(s, base);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkBitVector(uint32_t size,
-                         const std::string& s,
-                         uint32_t base) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return mkBVFromStrHelper(size, s, base);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkConstArray(const Sort& sort, const Term& val) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_SORT(sort);
-  CVC4_API_SOLVER_CHECK_TERM(val);
-  CVC4_API_ARG_CHECK_EXPECTED(sort.isArray(), sort) << "an array sort";
-  CVC4_API_CHECK(val.getSort().isSubsortOf(sort.getArrayElementSort()))
-      << "Value does not match element sort";
-  //////// all checks before this line
-
-  // handle the special case of (CAST_TO_REAL n) where n is an integer
-  Node n = *val.d_node;
-  if (val.isCastedReal())
-  {
-    // this is safe because the constant array stores its type
-    n = n[0];
-  }
-  Term res =
-      mkValHelper<cvc5::ArrayStoreAll>(cvc5::ArrayStoreAll(*sort.d_type, n));
-  return res;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkPosInf(uint32_t exp, uint32_t sig) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK(Configuration::isBuiltWithSymFPU())
-      << "Expected CVC4 to be compiled with SymFPU support";
-  //////// all checks before this line
-  return mkValHelper<cvc5::FloatingPoint>(
-      FloatingPoint::makeInf(FloatingPointSize(exp, sig), false));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkNegInf(uint32_t exp, uint32_t sig) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK(Configuration::isBuiltWithSymFPU())
-      << "Expected CVC4 to be compiled with SymFPU support";
-  //////// all checks before this line
-  return mkValHelper<cvc5::FloatingPoint>(
-      FloatingPoint::makeInf(FloatingPointSize(exp, sig), true));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkNaN(uint32_t exp, uint32_t sig) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK(Configuration::isBuiltWithSymFPU())
-      << "Expected CVC4 to be compiled with SymFPU support";
-  //////// all checks before this line
-  return mkValHelper<cvc5::FloatingPoint>(
-      FloatingPoint::makeNaN(FloatingPointSize(exp, sig)));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkPosZero(uint32_t exp, uint32_t sig) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK(Configuration::isBuiltWithSymFPU())
-      << "Expected CVC4 to be compiled with SymFPU support";
-  //////// all checks before this line
-  return mkValHelper<cvc5::FloatingPoint>(
-      FloatingPoint::makeZero(FloatingPointSize(exp, sig), false));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkNegZero(uint32_t exp, uint32_t sig) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK(Configuration::isBuiltWithSymFPU())
-      << "Expected CVC4 to be compiled with SymFPU support";
-  //////// all checks before this line
-  return mkValHelper<cvc5::FloatingPoint>(
-      FloatingPoint::makeZero(FloatingPointSize(exp, sig), true));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkRoundingMode(RoundingMode rm) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK(Configuration::isBuiltWithSymFPU())
-      << "Expected CVC4 to be compiled with SymFPU support";
-  //////// all checks before this line
-  return mkValHelper<cvc5::RoundingMode>(s_rmodes.at(rm));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkUninterpretedConst(const Sort& sort, int32_t index) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_SORT(sort);
-  //////// all checks before this line
-  return mkValHelper<cvc5::UninterpretedConstant>(
-      cvc5::UninterpretedConstant(*sort.d_type, index));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkAbstractValue(const std::string& index) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_ARG_CHECK_EXPECTED(!index.empty(), index) << "a non-empty string";
-
-  cvc5::Integer idx(index, 10);
-  CVC4_API_ARG_CHECK_EXPECTED(idx > 0, index)
-      << "a string representing an integer > 0";
-  //////// all checks before this line
-  return Term(this, getNodeManager()->mkConst(cvc5::AbstractValue(idx)));
-  // do not call getType(), for abstract values, type can not be computed
-  // until it is substituted away
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkAbstractValue(uint64_t index) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_ARG_CHECK_EXPECTED(index > 0, index) << "an integer > 0";
-  //////// all checks before this line
-  return Term(this,
-              getNodeManager()->mkConst(cvc5::AbstractValue(Integer(index))));
-  // do not call getType(), for abstract values, type can not be computed
-  // until it is substituted away
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkFloatingPoint(uint32_t exp, uint32_t sig, Term val) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK(Configuration::isBuiltWithSymFPU())
-      << "Expected CVC4 to be compiled with SymFPU support";
-  CVC4_API_SOLVER_CHECK_TERM(val);
-  CVC4_API_ARG_CHECK_EXPECTED(exp > 0, exp) << "a value > 0";
-  CVC4_API_ARG_CHECK_EXPECTED(sig > 0, sig) << "a value > 0";
-  uint32_t bw = exp + sig;
-  CVC4_API_ARG_CHECK_EXPECTED(bw == val.getSort().getBVSize(), val)
-      << "a bit-vector constant with bit-width '" << bw << "'";
-  CVC4_API_ARG_CHECK_EXPECTED(
-      val.getSort().isBitVector() && val.d_node->isConst(), val)
-      << "bit-vector constant";
-  //////// all checks before this line
-  return mkValHelper<cvc5::FloatingPoint>(
-      cvc5::FloatingPoint(exp, sig, val.d_node->getConst<BitVector>()));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/* Create constants                                                           */
-/* -------------------------------------------------------------------------- */
-
-Term Solver::mkConst(const Sort& sort, const std::string& symbol) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_SORT(sort);
-  //////// all checks before this line
-  Node res = d_nodeMgr->mkVar(symbol, *sort.d_type);
-  (void)res.getType(true); /* kick off type checking */
-  increment_vars_consts_stats(sort, false);
-  return Term(this, res);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkConst(const Sort& sort) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_SORT(sort);
-  //////// all checks before this line
-  Node res = d_nodeMgr->mkVar(*sort.d_type);
-  (void)res.getType(true); /* kick off type checking */
-  increment_vars_consts_stats(sort, false);
-  return Term(this, res);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/* Create variables                                                           */
-/* -------------------------------------------------------------------------- */
-
-Term Solver::mkVar(const Sort& sort, const std::string& symbol) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_SORT(sort);
-  //////// all checks before this line
-  Node res = symbol.empty() ? d_nodeMgr->mkBoundVar(*sort.d_type)
-                            : d_nodeMgr->mkBoundVar(symbol, *sort.d_type);
-  (void)res.getType(true); /* kick off type checking */
-  increment_vars_consts_stats(sort, true);
-  return Term(this, res);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/* Create datatype constructor declarations                                   */
-/* -------------------------------------------------------------------------- */
-
-DatatypeConstructorDecl Solver::mkDatatypeConstructorDecl(
-    const std::string& name)
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return DatatypeConstructorDecl(this, name);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/* Create datatype declarations                                               */
-/* -------------------------------------------------------------------------- */
-
-DatatypeDecl Solver::mkDatatypeDecl(const std::string& name, bool isCoDatatype)
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return DatatypeDecl(this, name, isCoDatatype);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-DatatypeDecl Solver::mkDatatypeDecl(const std::string& name,
-                                    Sort param,
-                                    bool isCoDatatype)
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_SORT(param);
-  //////// all checks before this line
-  return DatatypeDecl(this, name, param, isCoDatatype);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-DatatypeDecl Solver::mkDatatypeDecl(const std::string& name,
-                                    const std::vector<Sort>& params,
-                                    bool isCoDatatype)
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_SORTS(params);
-  //////// all checks before this line
-  return DatatypeDecl(this, name, params, isCoDatatype);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/* Create terms                                                               */
-/* -------------------------------------------------------------------------- */
-
-Term Solver::mkTerm(Kind kind) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_KIND_CHECK(kind);
-  //////// all checks before this line
-  return mkTermFromKind(kind);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkTerm(Kind kind, const Term& child) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_KIND_CHECK(kind);
-  CVC4_API_SOLVER_CHECK_TERM(child);
-  //////// all checks before this line
-  return mkTermHelper(kind, std::vector<Term>{child});
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkTerm(Kind kind, const Term& child1, const Term& child2) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_KIND_CHECK(kind);
-  CVC4_API_SOLVER_CHECK_TERM(child1);
-  CVC4_API_SOLVER_CHECK_TERM(child2);
-  //////// all checks before this line
-  return mkTermHelper(kind, std::vector<Term>{child1, child2});
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkTerm(Kind kind,
-                    const Term& child1,
-                    const Term& child2,
-                    const Term& child3) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_KIND_CHECK(kind);
-  CVC4_API_SOLVER_CHECK_TERM(child1);
-  CVC4_API_SOLVER_CHECK_TERM(child2);
-  CVC4_API_SOLVER_CHECK_TERM(child3);
-  //////// all checks before this line
-  // need to use internal term call to check e.g. associative construction
-  return mkTermHelper(kind, std::vector<Term>{child1, child2, child3});
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkTerm(Kind kind, const std::vector<Term>& children) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_KIND_CHECK(kind);
-  CVC4_API_SOLVER_CHECK_TERMS(children);
-  //////// all checks before this line
-  return mkTermHelper(kind, children);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkTerm(const Op& op) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_OP(op);
-  checkMkTerm(op.d_kind, 0);
-  //////// all checks before this line
-
-  if (!op.isIndexedHelper())
-  {
-    return mkTermFromKind(op.d_kind);
-  }
-
-  const cvc5::Kind int_kind = extToIntKind(op.d_kind);
-  Term res = Term(this, getNodeManager()->mkNode(int_kind, *op.d_node));
-
-  (void)res.d_node->getType(true); /* kick off type checking */
-  return res;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkTerm(const Op& op, const Term& child) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_OP(op);
-  CVC4_API_SOLVER_CHECK_TERM(child);
-  //////// all checks before this line
-  return mkTermHelper(op, std::vector<Term>{child});
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkTerm(const Op& op, const Term& child1, const Term& child2) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_OP(op);
-  CVC4_API_SOLVER_CHECK_TERM(child1);
-  CVC4_API_SOLVER_CHECK_TERM(child2);
-  //////// all checks before this line
-  return mkTermHelper(op, std::vector<Term>{child1, child2});
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkTerm(const Op& op,
-                    const Term& child1,
-                    const Term& child2,
-                    const Term& child3) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_OP(op);
-  CVC4_API_SOLVER_CHECK_TERM(child1);
-  CVC4_API_SOLVER_CHECK_TERM(child2);
-  CVC4_API_SOLVER_CHECK_TERM(child3);
-  //////// all checks before this line
-  return mkTermHelper(op, std::vector<Term>{child1, child2, child3});
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkTerm(const Op& op, const std::vector<Term>& children) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_OP(op);
-  CVC4_API_SOLVER_CHECK_TERMS(children);
-  //////// all checks before this line
-  return mkTermHelper(op, children);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkTuple(const std::vector<Sort>& sorts,
-                     const std::vector<Term>& terms) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK(sorts.size() == terms.size())
-      << "Expected the same number of sorts and elements";
-  CVC4_API_SOLVER_CHECK_SORTS(sorts);
-  CVC4_API_SOLVER_CHECK_TERMS(terms);
-  //////// all checks before this line
-  std::vector<cvc5::Node> args;
-  for (size_t i = 0, size = sorts.size(); i < size; i++)
-  {
-    args.push_back(*(ensureTermSort(terms[i], sorts[i])).d_node);
-  }
-
-  Sort s = mkTupleSortHelper(sorts);
-  Datatype dt = s.getDatatype();
-  NodeBuilder<> nb(extToIntKind(APPLY_CONSTRUCTOR));
-  nb << *dt[0].getConstructorTerm().d_node;
-  nb.append(args);
-  Node res = nb.constructNode();
-  (void)res.getType(true); /* kick off type checking */
-  return Term(this, res);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/* Create operators                                                           */
-/* -------------------------------------------------------------------------- */
-
-Op Solver::mkOp(Kind kind) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_KIND_CHECK(kind);
-  CVC4_API_CHECK(s_indexed_kinds.find(kind) == s_indexed_kinds.end())
-      << "Expected a kind for a non-indexed operator.";
-  //////// all checks before this line
-  return Op(this, kind);
-  ////////
-  CVC4_API_TRY_CATCH_END
-}
-
-Op Solver::mkOp(Kind kind, const std::string& arg) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_KIND_CHECK(kind);
-  CVC4_API_KIND_CHECK_EXPECTED((kind == RECORD_UPDATE) || (kind == DIVISIBLE),
-                               kind)
-      << "RECORD_UPDATE or DIVISIBLE";
-  //////// all checks before this line
-  Op res;
-  if (kind == RECORD_UPDATE)
-  {
-    res = Op(this,
-             kind,
-             *mkValHelper<cvc5::RecordUpdate>(cvc5::RecordUpdate(arg)).d_node);
-  }
-  else
-  {
-    /* CLN and GMP handle this case differently, CLN interprets it as 0, GMP
-     * throws an std::invalid_argument exception. For consistency, we treat it
-     * as invalid. */
-    CVC4_API_ARG_CHECK_EXPECTED(arg != ".", arg)
-        << "a string representing an integer, real or rational value.";
-    res = Op(this,
-             kind,
-             *mkValHelper<cvc5::Divisible>(cvc5::Divisible(cvc5::Integer(arg)))
-                  .d_node);
-  }
-  return res;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Op Solver::mkOp(Kind kind, uint32_t arg) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_KIND_CHECK(kind);
-  //////// all checks before this line
-  Op res;
-  switch (kind)
-  {
-    case DIVISIBLE:
-      res = Op(this,
-               kind,
-               *mkValHelper<cvc5::Divisible>(cvc5::Divisible(arg)).d_node);
-      break;
-    case BITVECTOR_REPEAT:
-      res = Op(this,
-               kind,
-               *mkValHelper<cvc5::BitVectorRepeat>(cvc5::BitVectorRepeat(arg))
-                    .d_node);
-      break;
-    case BITVECTOR_ZERO_EXTEND:
-      res = Op(this,
-               kind,
-               *mkValHelper<cvc5::BitVectorZeroExtend>(
-                    cvc5::BitVectorZeroExtend(arg))
-                    .d_node);
-      break;
-    case BITVECTOR_SIGN_EXTEND:
-      res = Op(this,
-               kind,
-               *mkValHelper<cvc5::BitVectorSignExtend>(
-                    cvc5::BitVectorSignExtend(arg))
-                    .d_node);
-      break;
-    case BITVECTOR_ROTATE_LEFT:
-      res = Op(this,
-               kind,
-               *mkValHelper<cvc5::BitVectorRotateLeft>(
-                    cvc5::BitVectorRotateLeft(arg))
-                    .d_node);
-      break;
-    case BITVECTOR_ROTATE_RIGHT:
-      res = Op(this,
-               kind,
-               *mkValHelper<cvc5::BitVectorRotateRight>(
-                    cvc5::BitVectorRotateRight(arg))
-                    .d_node);
-      break;
-    case INT_TO_BITVECTOR:
-      res = Op(
-          this,
-          kind,
-          *mkValHelper<cvc5::IntToBitVector>(cvc5::IntToBitVector(arg)).d_node);
-      break;
-    case IAND:
-      res =
-          Op(this, kind, *mkValHelper<cvc5::IntAnd>(cvc5::IntAnd(arg)).d_node);
-      break;
-    case FLOATINGPOINT_TO_UBV:
-      res = Op(
-          this,
-          kind,
-          *mkValHelper<cvc5::FloatingPointToUBV>(cvc5::FloatingPointToUBV(arg))
-               .d_node);
-      break;
-    case FLOATINGPOINT_TO_SBV:
-      res = Op(
-          this,
-          kind,
-          *mkValHelper<cvc5::FloatingPointToSBV>(cvc5::FloatingPointToSBV(arg))
-               .d_node);
-      break;
-    case TUPLE_UPDATE:
-      res = Op(this,
-               kind,
-               *mkValHelper<cvc5::TupleUpdate>(cvc5::TupleUpdate(arg)).d_node);
-      break;
-    case REGEXP_REPEAT:
-      res =
-          Op(this,
-             kind,
-             *mkValHelper<cvc5::RegExpRepeat>(cvc5::RegExpRepeat(arg)).d_node);
-      break;
-    default:
-      CVC4_API_KIND_CHECK_EXPECTED(false, kind)
-          << "operator kind with uint32_t argument";
-  }
-  Assert(!res.isNull());
-  return res;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Op Solver::mkOp(Kind kind, uint32_t arg1, uint32_t arg2) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_KIND_CHECK(kind);
-  //////// all checks before this line
-
-  Op res;
-  switch (kind)
-  {
-    case BITVECTOR_EXTRACT:
-      res = Op(this,
-               kind,
-               *mkValHelper<cvc5::BitVectorExtract>(
-                    cvc5::BitVectorExtract(arg1, arg2))
-                    .d_node);
-      break;
-    case FLOATINGPOINT_TO_FP_IEEE_BITVECTOR:
-      res = Op(this,
-               kind,
-               *mkValHelper<cvc5::FloatingPointToFPIEEEBitVector>(
-                    cvc5::FloatingPointToFPIEEEBitVector(arg1, arg2))
-                    .d_node);
-      break;
-    case FLOATINGPOINT_TO_FP_FLOATINGPOINT:
-      res = Op(this,
-               kind,
-               *mkValHelper<cvc5::FloatingPointToFPFloatingPoint>(
-                    cvc5::FloatingPointToFPFloatingPoint(arg1, arg2))
-                    .d_node);
-      break;
-    case FLOATINGPOINT_TO_FP_REAL:
-      res = Op(this,
-               kind,
-               *mkValHelper<cvc5::FloatingPointToFPReal>(
-                    cvc5::FloatingPointToFPReal(arg1, arg2))
-                    .d_node);
-      break;
-    case FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR:
-      res = Op(this,
-               kind,
-               *mkValHelper<cvc5::FloatingPointToFPSignedBitVector>(
-                    cvc5::FloatingPointToFPSignedBitVector(arg1, arg2))
-                    .d_node);
-      break;
-    case FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR:
-      res = Op(this,
-               kind,
-               *mkValHelper<cvc5::FloatingPointToFPUnsignedBitVector>(
-                    cvc5::FloatingPointToFPUnsignedBitVector(arg1, arg2))
-                    .d_node);
-      break;
-    case FLOATINGPOINT_TO_FP_GENERIC:
-      res = Op(this,
-               kind,
-               *mkValHelper<cvc5::FloatingPointToFPGeneric>(
-                    cvc5::FloatingPointToFPGeneric(arg1, arg2))
-                    .d_node);
-      break;
-    case REGEXP_LOOP:
-      res = Op(
-          this,
-          kind,
-          *mkValHelper<cvc5::RegExpLoop>(cvc5::RegExpLoop(arg1, arg2)).d_node);
-      break;
-    default:
-      CVC4_API_KIND_CHECK_EXPECTED(false, kind)
-          << "operator kind with two uint32_t arguments";
-  }
-  Assert(!res.isNull());
-  return res;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Op Solver::mkOp(Kind kind, const std::vector<uint32_t>& args) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_KIND_CHECK(kind);
-  //////// all checks before this line
-
-  Op res;
-  switch (kind)
-  {
-    case TUPLE_PROJECT:
-    {
-      res = Op(this,
-               kind,
-               *mkValHelper<cvc5::TupleProjectOp>(cvc5::TupleProjectOp(args))
-                    .d_node);
-    }
-    break;
-    default:
-    {
-      std::string message = "operator kind with " + std::to_string(args.size())
-                            + " uint32_t arguments";
-      CVC4_API_KIND_CHECK_EXPECTED(false, kind) << message;
-    }
-  }
-  Assert(!res.isNull());
-  return res;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/* Non-SMT-LIB commands                                                       */
-/* -------------------------------------------------------------------------- */
-
-Term Solver::simplify(const Term& term)
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_TERM(term);
-  //////// all checks before this line
-  return Term(this, d_smtEngine->simplify(*term.d_node));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Result Solver::checkEntailed(const Term& term) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK(!d_smtEngine->isQueryMade()
-                 || d_smtEngine->getOptions()[options::incrementalSolving])
-      << "Cannot make multiple queries unless incremental solving is enabled "
-         "(try --incremental)";
-  CVC4_API_SOLVER_CHECK_TERM(term);
-  //////// all checks before this line
-  cvc5::Result r = d_smtEngine->checkEntailed(*term.d_node);
-  return Result(r);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Result Solver::checkEntailed(const std::vector<Term>& terms) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_CHECK(!d_smtEngine->isQueryMade()
-                 || d_smtEngine->getOptions()[options::incrementalSolving])
-      << "Cannot make multiple queries unless incremental solving is enabled "
-         "(try --incremental)";
-  CVC4_API_SOLVER_CHECK_TERMS(terms);
-  //////// all checks before this line
-  return d_smtEngine->checkEntailed(Term::termVectorToNodes(terms));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/* SMT-LIB commands                                                           */
-/* -------------------------------------------------------------------------- */
-
-/**
- *  ( assert <term> )
- */
-void Solver::assertFormula(const Term& term) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_TERM(term);
-  CVC4_API_SOLVER_CHECK_TERM_WITH_SORT(term, getBooleanSort());
-  //////// all checks before this line
-  d_smtEngine->assertFormula(*term.d_node);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/**
- *  ( check-sat )
- */
-Result Solver::checkSat(void) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_CHECK(!d_smtEngine->isQueryMade()
-                 || d_smtEngine->getOptions()[options::incrementalSolving])
-      << "Cannot make multiple queries unless incremental solving is enabled "
-         "(try --incremental)";
-  //////// all checks before this line
-  cvc5::Result r = d_smtEngine->checkSat();
-  return Result(r);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/**
- *  ( check-sat-assuming ( <prop_literal> ) )
- */
-Result Solver::checkSatAssuming(const Term& assumption) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_CHECK(!d_smtEngine->isQueryMade()
-                 || d_smtEngine->getOptions()[options::incrementalSolving])
-      << "Cannot make multiple queries unless incremental solving is enabled "
-         "(try --incremental)";
-  CVC4_API_SOLVER_CHECK_TERM_WITH_SORT(assumption, getBooleanSort());
-  //////// all checks before this line
-  cvc5::Result r = d_smtEngine->checkSat(*assumption.d_node);
-  return Result(r);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/**
- *  ( check-sat-assuming ( <prop_literal>* ) )
- */
-Result Solver::checkSatAssuming(const std::vector<Term>& assumptions) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_CHECK(!d_smtEngine->isQueryMade() || assumptions.size() == 0
-                 || d_smtEngine->getOptions()[options::incrementalSolving])
-      << "Cannot make multiple queries unless incremental solving is enabled "
-         "(try --incremental)";
-  CVC4_API_SOLVER_CHECK_TERMS_WITH_SORT(assumptions, getBooleanSort());
-  //////// all checks before this line
-  for (const Term& term : assumptions)
-  {
-    CVC4_API_SOLVER_CHECK_TERM(term);
-  }
-  std::vector<Node> eassumptions = Term::termVectorToNodes(assumptions);
-  cvc5::Result r = d_smtEngine->checkSat(eassumptions);
-  return Result(r);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/**
- *  ( declare-datatype <symbol> <datatype_decl> )
- */
-Sort Solver::declareDatatype(
-    const std::string& symbol,
-    const std::vector<DatatypeConstructorDecl>& ctors) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_ARG_CHECK_EXPECTED(ctors.size() > 0, ctors)
-      << "a datatype declaration with at least one constructor";
-  CVC4_API_SOLVER_CHECK_DTCTORDECLS(ctors);
-  //////// all checks before this line
-  DatatypeDecl dtdecl(this, symbol);
-  for (size_t i = 0, size = ctors.size(); i < size; i++)
-  {
-    dtdecl.addConstructor(ctors[i]);
-  }
-  return Sort(this, getNodeManager()->mkDatatypeType(*dtdecl.d_dtype));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/**
- *  ( declare-fun <symbol> ( <sort>* ) <sort> )
- */
-Term Solver::declareFun(const std::string& symbol,
-                        const std::vector<Sort>& sorts,
-                        const Sort& sort) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_DOMAIN_SORTS(sorts);
-  CVC4_API_SOLVER_CHECK_CODOMAIN_SORT(sort);
-  //////// all checks before this line
-
-  TypeNode type = *sort.d_type;
-  if (!sorts.empty())
-  {
-    std::vector<TypeNode> types = Sort::sortVectorToTypeNodes(sorts);
-    type = getNodeManager()->mkFunctionType(types, type);
-  }
-  return Term(this, d_nodeMgr->mkVar(symbol, type));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/**
- *  ( declare-sort <symbol> <numeral> )
- */
-Sort Solver::declareSort(const std::string& symbol, uint32_t arity) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  if (arity == 0)
-  {
-    return Sort(this, getNodeManager()->mkSort(symbol));
-  }
-  return Sort(this, getNodeManager()->mkSortConstructor(symbol, arity));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/**
- *  ( define-fun <function_def> )
- */
-Term Solver::defineFun(const std::string& symbol,
-                       const std::vector<Term>& bound_vars,
-                       const Sort& sort,
-                       const Term& term,
-                       bool global) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_CODOMAIN_SORT(sort);
-  CVC4_API_SOLVER_CHECK_TERM(term);
-  CVC4_API_CHECK(sort == term.getSort())
-      << "Invalid sort of function body '" << term << "', expected '" << sort
-      << "'";
-
-  std::vector<Sort> domain_sorts;
-  for (const auto& bv : bound_vars)
-  {
-    domain_sorts.push_back(bv.getSort());
-  }
-  Sort fun_sort =
-      domain_sorts.empty()
-          ? sort
-          : Sort(this,
-                 getNodeManager()->mkFunctionType(
-                     Sort::sortVectorToTypeNodes(domain_sorts), *sort.d_type));
-  Term fun = mkConst(fun_sort, symbol);
-
-  CVC4_API_SOLVER_CHECK_BOUND_VARS_DEF_FUN(fun, bound_vars, domain_sorts);
-  //////// all checks before this line
-
-  d_smtEngine->defineFunction(
-      *fun.d_node, Term::termVectorToNodes(bound_vars), *term.d_node, global);
-  return fun;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::defineFun(const Term& fun,
-                       const std::vector<Term>& bound_vars,
-                       const Term& term,
-                       bool global) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_TERM(fun);
-  CVC4_API_SOLVER_CHECK_TERM(term);
-  if (fun.getSort().isFunction())
-  {
-    std::vector<Sort> domain_sorts = fun.getSort().getFunctionDomainSorts();
-    CVC4_API_SOLVER_CHECK_BOUND_VARS_DEF_FUN(fun, bound_vars, domain_sorts);
-    Sort codomain = fun.getSort().getFunctionCodomainSort();
-    CVC4_API_CHECK(codomain == term.getSort())
-        << "Invalid sort of function body '" << term << "', expected '"
-        << codomain << "'";
-  }
-  else
-  {
-    CVC4_API_SOLVER_CHECK_BOUND_VARS(bound_vars);
-    CVC4_API_ARG_CHECK_EXPECTED(bound_vars.size() == 0, fun)
-        << "function or nullary symbol";
-  }
-  //////// all checks before this line
-  std::vector<Node> ebound_vars = Term::termVectorToNodes(bound_vars);
-  d_smtEngine->defineFunction(*fun.d_node, ebound_vars, *term.d_node, global);
-  return fun;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/**
- *  ( define-fun-rec <function_def> )
- */
-Term Solver::defineFunRec(const std::string& symbol,
-                          const std::vector<Term>& bound_vars,
-                          const Sort& sort,
-                          const Term& term,
-                          bool global) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-
-  CVC4_API_CHECK(d_smtEngine->getUserLogicInfo().isQuantified())
-      << "recursive function definitions require a logic with quantifiers";
-  CVC4_API_CHECK(
-      d_smtEngine->getUserLogicInfo().isTheoryEnabled(theory::THEORY_UF))
-      << "recursive function definitions require a logic with uninterpreted "
-         "functions";
-
-  CVC4_API_SOLVER_CHECK_TERM(term);
-  CVC4_API_SOLVER_CHECK_CODOMAIN_SORT(sort);
-  CVC4_API_CHECK(sort == term.getSort())
-      << "Invalid sort of function body '" << term << "', expected '" << sort
-      << "'";
-
-  std::vector<Sort> domain_sorts;
-  for (const auto& bv : bound_vars)
-  {
-    domain_sorts.push_back(bv.getSort());
-  }
-  Sort fun_sort =
-      domain_sorts.empty()
-          ? sort
-          : Sort(this,
-                 getNodeManager()->mkFunctionType(
-                     Sort::sortVectorToTypeNodes(domain_sorts), *sort.d_type));
-  Term fun = mkConst(fun_sort, symbol);
-
-  CVC4_API_SOLVER_CHECK_BOUND_VARS_DEF_FUN(fun, bound_vars, domain_sorts);
-  //////// all checks before this line
-
-  d_smtEngine->defineFunctionRec(
-      *fun.d_node, Term::termVectorToNodes(bound_vars), *term.d_node, global);
-
-  return fun;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::defineFunRec(const Term& fun,
-                          const std::vector<Term>& bound_vars,
-                          const Term& term,
-                          bool global) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-
-  CVC4_API_CHECK(d_smtEngine->getUserLogicInfo().isQuantified())
-      << "recursive function definitions require a logic with quantifiers";
-  CVC4_API_CHECK(
-      d_smtEngine->getUserLogicInfo().isTheoryEnabled(theory::THEORY_UF))
-      << "recursive function definitions require a logic with uninterpreted "
-         "functions";
-
-  CVC4_API_SOLVER_CHECK_TERM(fun);
-  CVC4_API_SOLVER_CHECK_TERM(term);
-  if (fun.getSort().isFunction())
-  {
-    std::vector<Sort> domain_sorts = fun.getSort().getFunctionDomainSorts();
-    CVC4_API_SOLVER_CHECK_BOUND_VARS_DEF_FUN(fun, bound_vars, domain_sorts);
-    Sort codomain = fun.getSort().getFunctionCodomainSort();
-    CVC4_API_CHECK(codomain == term.getSort())
-        << "Invalid sort of function body '" << term << "', expected '"
-        << codomain << "'";
-  }
-  else
-  {
-    CVC4_API_SOLVER_CHECK_BOUND_VARS(bound_vars);
-    CVC4_API_ARG_CHECK_EXPECTED(bound_vars.size() == 0, fun)
-        << "function or nullary symbol";
-  }
-  //////// all checks before this line
-
-  std::vector<Node> ebound_vars = Term::termVectorToNodes(bound_vars);
-  d_smtEngine->defineFunctionRec(
-      *fun.d_node, ebound_vars, *term.d_node, global);
-  return fun;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/**
- *  ( define-funs-rec ( <function_decl>^{n+1} ) ( <term>^{n+1} ) )
- */
-void Solver::defineFunsRec(const std::vector<Term>& funs,
-                           const std::vector<std::vector<Term>>& bound_vars,
-                           const std::vector<Term>& terms,
-                           bool global) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-
-  CVC4_API_CHECK(d_smtEngine->getUserLogicInfo().isQuantified())
-      << "recursive function definitions require a logic with quantifiers";
-  CVC4_API_CHECK(
-      d_smtEngine->getUserLogicInfo().isTheoryEnabled(theory::THEORY_UF))
-      << "recursive function definitions require a logic with uninterpreted "
-         "functions";
-  CVC4_API_SOLVER_CHECK_TERMS(funs);
-  CVC4_API_SOLVER_CHECK_TERMS(terms);
-
-  size_t funs_size = funs.size();
-  CVC4_API_ARG_SIZE_CHECK_EXPECTED(funs_size == bound_vars.size(), bound_vars)
-      << "'" << funs_size << "'";
-  CVC4_API_ARG_SIZE_CHECK_EXPECTED(funs_size == terms.size(), terms)
-      << "'" << funs_size << "'";
-
-  for (size_t j = 0; j < funs_size; ++j)
-  {
-    const Term& fun = funs[j];
-    const std::vector<Term>& bvars = bound_vars[j];
-    const Term& term = terms[j];
-
-    CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
-        this == fun.d_solver, "function", funs, j)
-        << "function associated with this solver object";
-    CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
-        this == term.d_solver, "term", terms, j)
-        << "term associated with this solver object";
-
-    if (fun.getSort().isFunction())
-    {
-      std::vector<Sort> domain_sorts = fun.getSort().getFunctionDomainSorts();
-      CVC4_API_SOLVER_CHECK_BOUND_VARS_DEF_FUN(fun, bvars, domain_sorts);
-      Sort codomain = fun.getSort().getFunctionCodomainSort();
-      CVC4_API_ARG_AT_INDEX_CHECK_EXPECTED(
-          codomain == term.getSort(), "sort of function body", terms, j)
-          << "'" << codomain << "'";
-    }
-    else
-    {
-      CVC4_API_SOLVER_CHECK_BOUND_VARS(bvars);
-      CVC4_API_ARG_CHECK_EXPECTED(bvars.size() == 0, fun)
-          << "function or nullary symbol";
-    }
-  }
-  //////// all checks before this line
-  std::vector<Node> efuns = Term::termVectorToNodes(funs);
-  std::vector<std::vector<Node>> ebound_vars;
-  for (const auto& v : bound_vars)
-  {
-    ebound_vars.push_back(Term::termVectorToNodes(v));
-  }
-  std::vector<Node> nodes = Term::termVectorToNodes(terms);
-  d_smtEngine->defineFunctionsRec(efuns, ebound_vars, nodes, global);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/**
- *  ( echo <std::string> )
- */
-void Solver::echo(std::ostream& out, const std::string& str) const
-{
-  out << str;
-}
-
-/**
- *  ( get-assertions )
- */
-std::vector<Term> Solver::getAssertions(void) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  std::vector<Node> assertions = d_smtEngine->getAssertions();
-  /* Can not use
-   *   return std::vector<Term>(assertions.begin(), assertions.end());
-   * here since constructor is private */
-  std::vector<Term> res;
-  for (const Node& e : assertions)
-  {
-    res.push_back(Term(this, e));
-  }
-  return res;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/**
- *  ( get-info <info_flag> )
- */
-std::string Solver::getInfo(const std::string& flag) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_RECOVERABLE_CHECK(d_smtEngine->isValidGetInfoFlag(flag))
-      << "Unrecognized flag for getInfo.";
-  //////// all checks before this line
-  return d_smtEngine->getInfo(flag).toString();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/**
- *  ( get-option <keyword> )
- */
-std::string Solver::getOption(const std::string& option) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  Node res = d_smtEngine->getOption(option);
-  return res.toString();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/**
- *  ( get-unsat-assumptions )
- */
-std::vector<Term> Solver::getUnsatAssumptions(void) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_CHECK(d_smtEngine->getOptions()[options::incrementalSolving])
-      << "Cannot get unsat assumptions unless incremental solving is enabled "
-         "(try --incremental)";
-  CVC4_API_CHECK(d_smtEngine->getOptions()[options::unsatAssumptions])
-      << "Cannot get unsat assumptions unless explicitly enabled "
-         "(try --produce-unsat-assumptions)";
-  CVC4_API_CHECK(d_smtEngine->getSmtMode() == SmtMode::UNSAT)
-      << "Cannot get unsat assumptions unless in unsat mode.";
-  //////// all checks before this line
-
-  std::vector<Node> uassumptions = d_smtEngine->getUnsatAssumptions();
-  /* Can not use
-   *   return std::vector<Term>(uassumptions.begin(), uassumptions.end());
-   * here since constructor is private */
-  std::vector<Term> res;
-  for (const Node& n : uassumptions)
-  {
-    res.push_back(Term(this, n));
-  }
-  return res;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/**
- *  ( get-unsat-core )
- */
-std::vector<Term> Solver::getUnsatCore(void) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_CHECK(d_smtEngine->getOptions()[options::unsatCores])
-      << "Cannot get unsat core unless explicitly enabled "
-         "(try --produce-unsat-cores)";
-  CVC4_API_RECOVERABLE_CHECK(d_smtEngine->getSmtMode() == SmtMode::UNSAT)
-      << "Cannot get unsat core unless in unsat mode.";
-  //////// all checks before this line
-  UnsatCore core = d_smtEngine->getUnsatCore();
-  /* Can not use
-   *   return std::vector<Term>(core.begin(), core.end());
-   * here since constructor is private */
-  std::vector<Term> res;
-  for (const Node& e : core)
-  {
-    res.push_back(Term(this, e));
-  }
-  return res;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/**
- *  ( get-value ( <term> ) )
- */
-Term Solver::getValue(const Term& term) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_TERM(term);
-  //////// all checks before this line
-  return getValueHelper(term);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/**
- *  ( get-value ( <term>+ ) )
- */
-std::vector<Term> Solver::getValue(const std::vector<Term>& terms) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_RECOVERABLE_CHECK(d_smtEngine->getOptions()[options::produceModels])
-      << "Cannot get value unless model generation is enabled "
-         "(try --produce-models)";
-  CVC4_API_RECOVERABLE_CHECK(d_smtEngine->isSmtModeSat())
-      << "Cannot get value unless after a SAT or unknown response.";
-  CVC4_API_SOLVER_CHECK_TERMS(terms);
-  //////// all checks before this line
-
-  std::vector<Term> res;
-  for (size_t i = 0, n = terms.size(); i < n; ++i)
-  {
-    /* Can not use emplace_back here since constructor is private. */
-    res.push_back(getValueHelper(terms[i]));
-  }
-  return res;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::getQuantifierElimination(const Term& q) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_TERM(q);
-  //////// all checks before this line
-  return Term(this,
-              d_smtEngine->getQuantifierElimination(q.getNode(), true, true));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::getQuantifierEliminationDisjunct(const Term& q) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_TERM(q);
-  //////// all checks before this line
-  return Term(
-      this, d_smtEngine->getQuantifierElimination(q.getNode(), false, true));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-void Solver::declareSeparationHeap(const Sort& locSort,
-                                   const Sort& dataSort) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_SORT(locSort);
-  CVC4_API_SOLVER_CHECK_SORT(dataSort);
-  CVC4_API_CHECK(
-      d_smtEngine->getLogicInfo().isTheoryEnabled(theory::THEORY_SEP))
-      << "Cannot obtain separation logic expressions if not using the "
-         "separation logic theory.";
-  //////// all checks before this line
-  d_smtEngine->declareSepHeap(locSort.getTypeNode(), dataSort.getTypeNode());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::getSeparationHeap() const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK(
-      d_smtEngine->getLogicInfo().isTheoryEnabled(theory::THEORY_SEP))
-      << "Cannot obtain separation logic expressions if not using the "
-         "separation logic theory.";
-  CVC4_API_CHECK(d_smtEngine->getOptions()[options::produceModels])
-      << "Cannot get separation heap term unless model generation is enabled "
-         "(try --produce-models)";
-  CVC4_API_RECOVERABLE_CHECK(d_smtEngine->isSmtModeSat())
-      << "Can only get separtion heap term after sat or unknown response.";
-  //////// all checks before this line
-  return Term(this, d_smtEngine->getSepHeapExpr());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::getSeparationNilTerm() const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK(
-      d_smtEngine->getLogicInfo().isTheoryEnabled(theory::THEORY_SEP))
-      << "Cannot obtain separation logic expressions if not using the "
-         "separation logic theory.";
-  CVC4_API_CHECK(d_smtEngine->getOptions()[options::produceModels])
-      << "Cannot get separation nil term unless model generation is enabled "
-         "(try --produce-models)";
-  CVC4_API_RECOVERABLE_CHECK(d_smtEngine->isSmtModeSat())
-      << "Can only get separtion nil term after sat or unknown response.";
-  //////// all checks before this line
-  return Term(this, d_smtEngine->getSepNilExpr());
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/**
- *  ( pop <numeral> )
- */
-void Solver::pop(uint32_t nscopes) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK(d_smtEngine->getOptions()[options::incrementalSolving])
-      << "Cannot pop when not solving incrementally (use --incremental)";
-  CVC4_API_CHECK(nscopes <= d_smtEngine->getNumUserLevels())
-      << "Cannot pop beyond first pushed context";
-  //////// all checks before this line
-  for (uint32_t n = 0; n < nscopes; ++n)
-  {
-    d_smtEngine->pop();
-  }
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Solver::getInterpolant(const Term& conj, Term& output) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_TERM(conj);
-  //////// all checks before this line
-  Node result;
-  bool success = d_smtEngine->getInterpol(*conj.d_node, result);
-  if (success)
-  {
-    output = Term(this, result);
-  }
-  return success;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Solver::getInterpolant(const Term& conj,
-                            Grammar& grammar,
-                            Term& output) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_TERM(conj);
-  //////// all checks before this line
-  Node result;
-  bool success =
-      d_smtEngine->getInterpol(*conj.d_node, *grammar.resolve().d_type, result);
-  if (success)
-  {
-    output = Term(this, result);
-  }
-  return success;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Solver::getAbduct(const Term& conj, Term& output) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_TERM(conj);
-  //////// all checks before this line
-  Node result;
-  bool success = d_smtEngine->getAbduct(*conj.d_node, result);
-  if (success)
-  {
-    output = Term(this, result);
-  }
-  return success;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-bool Solver::getAbduct(const Term& conj, Grammar& grammar, Term& output) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_TERM(conj);
-  //////// all checks before this line
-  Node result;
-  bool success =
-      d_smtEngine->getAbduct(*conj.d_node, *grammar.resolve().d_type, result);
-  if (success)
-  {
-    output = Term(this, result);
-  }
-  return success;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-void Solver::blockModel() const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK(d_smtEngine->getOptions()[options::produceModels])
-      << "Cannot get value unless model generation is enabled "
-         "(try --produce-models)";
-  CVC4_API_RECOVERABLE_CHECK(d_smtEngine->isSmtModeSat())
-      << "Can only block model after sat or unknown response.";
-  //////// all checks before this line
-  d_smtEngine->blockModel();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-void Solver::blockModelValues(const std::vector<Term>& terms) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK(d_smtEngine->getOptions()[options::produceModels])
-      << "Cannot get value unless model generation is enabled "
-         "(try --produce-models)";
-  CVC4_API_RECOVERABLE_CHECK(d_smtEngine->isSmtModeSat())
-      << "Can only block model values after sat or unknown response.";
-  CVC4_API_ARG_SIZE_CHECK_EXPECTED(!terms.empty(), terms)
-      << "a non-empty set of terms";
-  CVC4_API_SOLVER_CHECK_TERMS(terms);
-  //////// all checks before this line
-  d_smtEngine->blockModelValues(Term::termVectorToNodes(terms));
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-void Solver::printInstantiations(std::ostream& out) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  d_smtEngine->printInstantiations(out);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/**
- *  ( push <numeral> )
- */
-void Solver::push(uint32_t nscopes) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK(d_smtEngine->getOptions()[options::incrementalSolving])
-      << "Cannot push when not solving incrementally (use --incremental)";
-  //////// all checks before this line
-  for (uint32_t n = 0; n < nscopes; ++n)
-  {
-    d_smtEngine->push();
-  }
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/**
- *  ( reset-assertions )
- */
-void Solver::resetAssertions(void) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  d_smtEngine->resetAssertions();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/**
- *  ( set-info <attribute> )
- */
-void Solver::setInfo(const std::string& keyword, const std::string& value) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_RECOVERABLE_ARG_CHECK_EXPECTED(
-      keyword == "source" || keyword == "category" || keyword == "difficulty"
-          || keyword == "filename" || keyword == "license" || keyword == "name"
-          || keyword == "notes" || keyword == "smt-lib-version"
-          || keyword == "status",
-      keyword)
-      << "'source', 'category', 'difficulty', 'filename', 'license', 'name', "
-         "'notes', 'smt-lib-version' or 'status'";
-  CVC4_API_RECOVERABLE_ARG_CHECK_EXPECTED(
-      keyword != "smt-lib-version" || value == "2" || value == "2.0"
-          || value == "2.5" || value == "2.6",
-      value)
-      << "'2.0', '2.5', '2.6'";
-  CVC4_API_ARG_CHECK_EXPECTED(keyword != "status" || value == "sat"
-                                  || value == "unsat" || value == "unknown",
-                              value)
-      << "'sat', 'unsat' or 'unknown'";
-  //////// all checks before this line
-  d_smtEngine->setInfo(keyword, value);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/**
- *  ( set-logic <symbol> )
- */
-void Solver::setLogic(const std::string& logic) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK(!d_smtEngine->isFullyInited())
-      << "Invalid call to 'setLogic', solver is already fully initialized";
-  cvc5::LogicInfo logic_info(logic);
-  //////// all checks before this line
-  d_smtEngine->setLogic(logic_info);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/**
- *  ( set-option <option> )
- */
-void Solver::setOption(const std::string& option,
-                       const std::string& value) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_CHECK(!d_smtEngine->isFullyInited())
-      << "Invalid call to 'setOption', solver is already fully initialized";
-  //////// all checks before this line
-  d_smtEngine->setOption(option, value);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::mkSygusVar(const Sort& sort, const std::string& symbol) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_SORT(sort);
-  //////// all checks before this line
-  Node res = getNodeManager()->mkBoundVar(symbol, *sort.d_type);
-  (void)res.getType(true); /* kick off type checking */
-
-  d_smtEngine->declareSygusVar(res);
-
-  return Term(this, res);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Grammar Solver::mkSygusGrammar(const std::vector<Term>& boundVars,
-                               const std::vector<Term>& ntSymbols) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_ARG_SIZE_CHECK_EXPECTED(!ntSymbols.empty(), ntSymbols)
-      << "a non-empty vector";
-  CVC4_API_SOLVER_CHECK_BOUND_VARS(boundVars);
-  CVC4_API_SOLVER_CHECK_BOUND_VARS(ntSymbols);
-  //////// all checks before this line
-  return Grammar(this, boundVars, ntSymbols);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::synthFun(const std::string& symbol,
-                      const std::vector<Term>& boundVars,
-                      const Sort& sort) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_BOUND_VARS(boundVars);
-  CVC4_API_SOLVER_CHECK_SORT(sort);
-  //////// all checks before this line
-  return synthFunHelper(symbol, boundVars, sort);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::synthFun(const std::string& symbol,
-                      const std::vector<Term>& boundVars,
-                      Sort sort,
-                      Grammar& grammar) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_BOUND_VARS(boundVars);
-  CVC4_API_SOLVER_CHECK_SORT(sort);
-  //////// all checks before this line
-  return synthFunHelper(symbol, boundVars, sort, false, &grammar);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::synthInv(const std::string& symbol,
-                      const std::vector<Term>& boundVars) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_BOUND_VARS(boundVars);
-  //////// all checks before this line
-  return synthFunHelper(
-      symbol, boundVars, Sort(this, getNodeManager()->booleanType()), true);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::synthInv(const std::string& symbol,
-                      const std::vector<Term>& boundVars,
-                      Grammar& grammar) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_BOUND_VARS(boundVars);
-  //////// all checks before this line
-  return synthFunHelper(symbol,
-                        boundVars,
-                        Sort(this, getNodeManager()->booleanType()),
-                        true,
-                        &grammar);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-void Solver::addSygusConstraint(const Term& term) const
-{
-  NodeManagerScope scope(getNodeManager());
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_TERM(term);
-  CVC4_API_ARG_CHECK_EXPECTED(
-      term.d_node->getType() == getNodeManager()->booleanType(), term)
-      << "boolean term";
-  //////// all checks before this line
-  d_smtEngine->assertSygusConstraint(*term.d_node);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-void Solver::addSygusInvConstraint(Term inv,
-                                   Term pre,
-                                   Term trans,
-                                   Term post) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_TERM(inv);
-  CVC4_API_SOLVER_CHECK_TERM(pre);
-  CVC4_API_SOLVER_CHECK_TERM(trans);
-  CVC4_API_SOLVER_CHECK_TERM(post);
-
-  CVC4_API_ARG_CHECK_EXPECTED(inv.d_node->getType().isFunction(), inv)
-      << "a function";
-
-  TypeNode invType = inv.d_node->getType();
-
-  CVC4_API_ARG_CHECK_EXPECTED(invType.getRangeType().isBoolean(), inv)
-      << "boolean range";
-
-  CVC4_API_CHECK(pre.d_node->getType() == invType)
-      << "Expected inv and pre to have the same sort";
-
-  CVC4_API_CHECK(post.d_node->getType() == invType)
-      << "Expected inv and post to have the same sort";
-  //////// all checks before this line
-
-  const std::vector<TypeNode>& invArgTypes = invType.getArgTypes();
-
-  std::vector<TypeNode> expectedTypes;
-  expectedTypes.reserve(2 * invArgTypes.size() + 1);
-
-  for (size_t i = 0, n = invArgTypes.size(); i < 2 * n; i += 2)
-  {
-    expectedTypes.push_back(invArgTypes[i % n]);
-    expectedTypes.push_back(invArgTypes[(i + 1) % n]);
-  }
-
-  expectedTypes.push_back(invType.getRangeType());
-  TypeNode expectedTransType = getNodeManager()->mkFunctionType(expectedTypes);
-
-  CVC4_API_CHECK(trans.d_node->getType() == expectedTransType)
-      << "Expected trans's sort to be " << invType;
-
-  d_smtEngine->assertSygusInvConstraint(
-      *inv.d_node, *pre.d_node, *trans.d_node, *post.d_node);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Result Solver::checkSynth() const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  return d_smtEngine->checkSynth();
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-Term Solver::getSynthSolution(Term term) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_SOLVER_CHECK_TERM(term);
-
-  std::map<cvc5::Node, cvc5::Node> map;
-  CVC4_API_CHECK(d_smtEngine->getSynthSolutions(map))
-      << "The solver is not in a state immediately preceded by a "
-         "successful call to checkSynth";
-
-  std::map<cvc5::Node, cvc5::Node>::const_iterator it = map.find(*term.d_node);
-
-  CVC4_API_CHECK(it != map.cend()) << "Synth solution not found for given term";
-  //////// all checks before this line
-  return Term(this, it->second);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-std::vector<Term> Solver::getSynthSolutions(
-    const std::vector<Term>& terms) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  CVC4_API_ARG_SIZE_CHECK_EXPECTED(!terms.empty(), terms) << "non-empty vector";
-  CVC4_API_SOLVER_CHECK_TERMS(terms);
-
-  std::map<cvc5::Node, cvc5::Node> map;
-  CVC4_API_CHECK(d_smtEngine->getSynthSolutions(map))
-      << "The solver is not in a state immediately preceded by a "
-         "successful call to checkSynth";
-  //////// all checks before this line
-
-  std::vector<Term> synthSolution;
-  synthSolution.reserve(terms.size());
-
-  for (size_t i = 0, n = terms.size(); i < n; ++i)
-  {
-    std::map<cvc5::Node, cvc5::Node>::const_iterator it =
-        map.find(*terms[i].d_node);
-
-    CVC4_API_CHECK(it != map.cend())
-        << "Synth solution not found for term at index " << i;
-
-    synthSolution.push_back(Term(this, it->second));
-  }
-
-  return synthSolution;
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-void Solver::printSynthSolution(std::ostream& out) const
-{
-  CVC4_API_TRY_CATCH_BEGIN;
-  //////// all checks before this line
-  d_smtEngine->printSynthSolution(out);
-  ////////
-  CVC4_API_TRY_CATCH_END;
-}
-
-/**
- * !!! This is only temporarily available until the parser is fully migrated to
- * the new API. !!!
- */
-SmtEngine* Solver::getSmtEngine(void) const { return d_smtEngine.get(); }
-
-/**
- * !!! This is only temporarily available until the parser is fully migrated to
- * the new API. !!!
- */
-Options& Solver::getOptions(void) { return d_smtEngine->getOptions(); }
-
-}  // namespace api
-
-}  // namespace cvc5
diff --git a/src/api/cvc4cpp.h b/src/api/cvc4cpp.h
deleted file mode 100644 (file)
index 8f4977b..0000000
+++ /dev/null
@@ -1,3659 +0,0 @@
-/*********************                                                        */
-/*! \file cvc4cpp.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Aina Niemetz, Andrew Reynolds, Abdalrhman Mohamed
- ** This file is part of the CVC4 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.\endverbatim
- **
- ** \brief The CVC4 C++ API.
- **
- ** The CVC4 C++ API.
- **/
-
-#include "cvc4_export.h"
-
-#ifndef CVC4__API__CVC4CPP_H
-#define CVC4__API__CVC4CPP_H
-
-#include "api/cvc4cppkind.h"
-
-#include <map>
-#include <memory>
-#include <set>
-#include <sstream>
-#include <string>
-#include <unordered_map>
-#include <unordered_set>
-#include <vector>
-
-namespace cvc5 {
-
-template <bool ref_count>
-class NodeTemplate;
-typedef NodeTemplate<true> Node;
-
-class Command;
-class DType;
-class DTypeConstructor;
-class DTypeSelector;
-class NodeManager;
-class SmtEngine;
-class TypeNode;
-class Options;
-class Random;
-class Result;
-
-namespace api {
-
-class Solver;
-struct Statistics;
-
-/* -------------------------------------------------------------------------- */
-/* Exception                                                                  */
-/* -------------------------------------------------------------------------- */
-
-class CVC4_EXPORT CVC4ApiException : public std::exception
-{
- public:
-  CVC4ApiException(const std::string& str) : d_msg(str) {}
-  CVC4ApiException(const std::stringstream& stream) : d_msg(stream.str()) {}
-  std::string getMessage() const { return d_msg; }
-  const char* what() const noexcept override { return d_msg.c_str(); }
-
- private:
-  std::string d_msg;
-};
-
-class CVC4_EXPORT CVC4ApiRecoverableException : public CVC4ApiException
-{
- public:
-  CVC4ApiRecoverableException(const std::string& str) : CVC4ApiException(str) {}
-  CVC4ApiRecoverableException(const std::stringstream& stream)
-      : CVC4ApiException(stream.str())
-  {
-  }
-};
-
-/* -------------------------------------------------------------------------- */
-/* Result                                                                     */
-/* -------------------------------------------------------------------------- */
-
-/**
- * Encapsulation of a three-valued solver result, with explanations.
- */
-class CVC4_EXPORT Result
-{
-  friend class Solver;
-
- public:
-  enum UnknownExplanation
-  {
-    REQUIRES_FULL_CHECK,
-    INCOMPLETE,
-    TIMEOUT,
-    RESOURCEOUT,
-    MEMOUT,
-    INTERRUPTED,
-    NO_STATUS,
-    UNSUPPORTED,
-    OTHER,
-    UNKNOWN_REASON
-  };
-
-  /** Constructor. */
-  Result();
-
-  /**
-   * Return true if Result is empty, i.e., a nullary Result, and not an actual
-   * result returned from a checkSat() (and friends) query.
-   */
-  bool isNull() const;
-
-  /**
-   * Return true if query was a satisfiable checkSat() or checkSatAssuming()
-   * query.
-   */
-  bool isSat() const;
-
-  /**
-   * Return true if query was an unsatisfiable checkSat() or
-   * checkSatAssuming() query.
-   */
-  bool isUnsat() const;
-
-  /**
-   * Return true if query was a checkSat() or checkSatAssuming() query and
-   * CVC4 was not able to determine (un)satisfiability.
-   */
-  bool isSatUnknown() const;
-
-  /**
-   * Return true if corresponding query was an entailed checkEntailed() query.
-   */
-  bool isEntailed() const;
-
-  /**
-   * Return true if corresponding query was a checkEntailed() query that is
-   * not entailed.
-   */
-  bool isNotEntailed() const;
-
-  /**
-   * Return true if query was a checkEntailed() () query and CVC4 was not able
-   * to determine if it is entailed.
-   */
-  bool isEntailmentUnknown() const;
-
-  /**
-   * Operator overloading for equality of two results.
-   * @param r the result to compare to for equality
-   * @return true if the results are equal
-   */
-  bool operator==(const Result& r) const;
-
-  /**
-   * Operator overloading for disequality of two results.
-   * @param r the result to compare to for disequality
-   * @return true if the results are disequal
-   */
-  bool operator!=(const Result& r) const;
-
-  /**
-   * @return an explanation for an unknown query result.
-   */
-  UnknownExplanation getUnknownExplanation() const;
-
-  /**
-   * @return a string representation of this result.
-   */
-  std::string toString() const;
-
- private:
-  /**
-   * Constructor.
-   * @param r the internal result that is to be wrapped by this result
-   * @return the Result
-   */
-  Result(const cvc5::Result& r);
-
-  /**
-   * The interal result wrapped by this result.
-   * Note: This is a shared_ptr rather than a unique_ptr since cvc5::Result is
-   *       not ref counted.
-   */
-  std::shared_ptr<cvc5::Result> d_result;
-};
-
-/**
- * Serialize a Result to given stream.
- * @param out the output stream
- * @param r the result to be serialized to the given output stream
- * @return the output stream
- */
-std::ostream& operator<<(std::ostream& out, const Result& r) CVC4_EXPORT;
-
-/**
- * Serialize an UnknownExplanation to given stream.
- * @param out the output stream
- * @param r the explanation to be serialized to the given output stream
- * @return the output stream
- */
-std::ostream& operator<<(std::ostream& out,
-                         enum Result::UnknownExplanation e) CVC4_EXPORT;
-
-/* -------------------------------------------------------------------------- */
-/* Sort                                                                       */
-/* -------------------------------------------------------------------------- */
-
-class Datatype;
-
-/**
- * The sort of a CVC4 term.
- */
-class CVC4_EXPORT Sort
-{
-  friend class cvc5::Command;
-  friend class DatatypeConstructor;
-  friend class DatatypeConstructorDecl;
-  friend class DatatypeSelector;
-  friend class DatatypeDecl;
-  friend class Op;
-  friend class Solver;
-  friend class Grammar;
-  friend struct SortHashFunction;
-  friend class Term;
-
- public:
-  /**
-   * Constructor.
-   */
-  Sort();
-
-  /**
-   * Destructor.
-   */
-  ~Sort();
-
-  /**
-   * Comparison for structural equality.
-   * @param s the sort to compare to
-   * @return true if the sorts are equal
-   */
-  bool operator==(const Sort& s) const;
-
-  /**
-   * Comparison for structural disequality.
-   * @param s the sort to compare to
-   * @return true if the sorts are not equal
-   */
-  bool operator!=(const Sort& s) const;
-
-  /**
-   * Comparison for ordering on sorts.
-   * @param s the sort to compare to
-   * @return true if this sort is less than s
-   */
-  bool operator<(const Sort& s) const;
-
-  /**
-   * Comparison for ordering on sorts.
-   * @param s the sort to compare to
-   * @return true if this sort is greater than s
-   */
-  bool operator>(const Sort& s) const;
-
-  /**
-   * Comparison for ordering on sorts.
-   * @param s the sort to compare to
-   * @return true if this sort is less than or equal to s
-   */
-  bool operator<=(const Sort& s) const;
-
-  /**
-   * Comparison for ordering on sorts.
-   * @param s the sort to compare to
-   * @return true if this sort is greater than or equal to s
-   */
-  bool operator>=(const Sort& s) const;
-
-  /**
-   * @return true if this Sort is a null sort.
-   */
-  bool isNull() const;
-
-  /**
-   * Is this a Boolean sort?
-   * @return true if the sort is a Boolean sort
-   */
-  bool isBoolean() const;
-
-  /**
-   * Is this a integer sort?
-   * @return true if the sort is a integer sort
-   */
-  bool isInteger() const;
-
-  /**
-   * Is this a real sort?
-   * @return true if the sort is a real sort
-   */
-  bool isReal() const;
-
-  /**
-   * Is this a string sort?
-   * @return true if the sort is the string sort
-   */
-  bool isString() const;
-
-  /**
-   * Is this a regexp sort?
-   * @return true if the sort is the regexp sort
-   */
-  bool isRegExp() const;
-
-  /**
-   * Is this a rounding mode sort?
-   * @return true if the sort is the rounding mode sort
-   */
-  bool isRoundingMode() const;
-
-  /**
-   * Is this a bit-vector sort?
-   * @return true if the sort is a bit-vector sort
-   */
-  bool isBitVector() const;
-
-  /**
-   * Is this a floating-point sort?
-   * @return true if the sort is a floating-point sort
-   */
-  bool isFloatingPoint() const;
-
-  /**
-   * Is this a datatype sort?
-   * @return true if the sort is a datatype sort
-   */
-  bool isDatatype() const;
-
-  /**
-   * Is this a parametric datatype sort?
-   * @return true if the sort is a parametric datatype sort
-   */
-  bool isParametricDatatype() const;
-
-  /**
-   * Is this a constructor sort?
-   * @return true if the sort is a constructor sort
-   */
-  bool isConstructor() const;
-
-  /**
-   * Is this a selector sort?
-   * @return true if the sort is a selector sort
-   */
-  bool isSelector() const;
-
-  /**
-   * Is this a tester sort?
-   * @return true if the sort is a tester sort
-   */
-  bool isTester() const;
-  /**
-   * Is this a function sort?
-   * @return true if the sort is a function sort
-   */
-  bool isFunction() const;
-
-  /**
-   * Is this a predicate sort?
-   * That is, is this a function sort mapping to Boolean? All predicate
-   * sorts are also function sorts.
-   * @return true if the sort is a predicate sort
-   */
-  bool isPredicate() const;
-
-  /**
-   * Is this a tuple sort?
-   * @return true if the sort is a tuple sort
-   */
-  bool isTuple() const;
-
-  /**
-   * Is this a record sort?
-   * @return true if the sort is a record sort
-   */
-  bool isRecord() const;
-
-  /**
-   * Is this an array sort?
-   * @return true if the sort is a array sort
-   */
-  bool isArray() const;
-
-  /**
-   * Is this a Set sort?
-   * @return true if the sort is a Set sort
-   */
-  bool isSet() const;
-
-  /**
-   * Is this a Bag sort?
-   * @return true if the sort is a Bag sort
-   */
-  bool isBag() const;
-
-  /**
-   * Is this a Sequence sort?
-   * @return true if the sort is a Sequence sort
-   */
-  bool isSequence() const;
-
-  /**
-   * Is this a sort kind?
-   * @return true if this is a sort kind
-   */
-  bool isUninterpretedSort() const;
-
-  /**
-   * Is this a sort constructor kind?
-   * @return true if this is a sort constructor kind
-   */
-  bool isSortConstructor() const;
-
-  /**
-   * Is this a first-class sort?
-   * First-class sorts are sorts for which:
-   * (1) we handle equalities between terms of that type, and
-   * (2) they are allowed to be parameters of parametric sorts (e.g. index or
-   *     element sorts of arrays).
-   *
-   * Examples of sorts that are not first-class include sort constructor sorts
-   * and regular expression sorts.
-   *
-   * @return true if this is a first-class sort
-   */
-  bool isFirstClass() const;
-
-  /**
-   * Is this a function-LIKE sort?
-   *
-   * Anything function-like except arrays (e.g., datatype selectors) is
-   * considered a function here. Function-like terms can not be the argument
-   * or return value for any term that is function-like.
-   * This is mainly to avoid higher order.
-   *
-   * Note that arrays are explicitly not considered function-like here.
-   *
-   * @return true if this is a function-like sort
-   */
-  bool isFunctionLike() const;
-
-  /**
-   * Is this sort a subsort of the given sort?
-   * @return true if this sort is a subsort of s
-   */
-  bool isSubsortOf(const Sort& s) const;
-
-  /**
-   * Is this sort comparable to the given sort (i.e., do they share
-   * a common ancestor in the subsort tree)?
-   * @return true if this sort is comparable to s
-   */
-  bool isComparableTo(const Sort& s) const;
-
-  /**
-   * @return the underlying datatype of a datatype sort
-   */
-  Datatype getDatatype() const;
-
-  /**
-   * Instantiate a parameterized datatype/sort sort.
-   * Create sorts parameter with Solver::mkParamSort().
-   * @param params the list of sort parameters to instantiate with
-   */
-  Sort instantiate(const std::vector<Sort>& params) const;
-
-  /**
-   * Substitution of Sorts.
-   * @param sort the subsort to be substituted within this sort.
-   * @param replacement the sort replacing the substituted subsort.
-   */
-  Sort substitute(const Sort& sort, const Sort& replacement) const;
-
-  /**
-   * Simultaneous substitution of Sorts.
-   * @param sorts the subsorts to be substituted within this sort.
-   * @param replacements the sort replacing the substituted subsorts.
-   */
-  Sort substitute(const std::vector<Sort>& sorts,
-                  const std::vector<Sort>& replacements) const;
-
-  /**
-   * Output a string representation of this sort to a given stream.
-   * @param out the output stream
-   */
-  void toStream(std::ostream& out) const;
-
-  /**
-   * @return a string representation of this sort
-   */
-  std::string toString() const;
-
-  /* Constructor sort ------------------------------------------------------- */
-
-  /**
-   * @return the arity of a constructor sort
-   */
-  size_t getConstructorArity() const;
-
-  /**
-   * @return the domain sorts of a constructor sort
-   */
-  std::vector<Sort> getConstructorDomainSorts() const;
-
-  /**
-   * @return the codomain sort of a constructor sort
-   */
-  Sort getConstructorCodomainSort() const;
-
-  /* Selector sort ------------------------------------------------------- */
-
-  /**
-   * @return the domain sort of a selector sort
-   */
-  Sort getSelectorDomainSort() const;
-
-  /**
-   * @return the codomain sort of a selector sort
-   */
-  Sort getSelectorCodomainSort() const;
-
-  /* Tester sort ------------------------------------------------------- */
-
-  /**
-   * @return the domain sort of a tester sort
-   */
-  Sort getTesterDomainSort() const;
-
-  /**
-   * @return the codomain sort of a tester sort, which is the Boolean sort
-   */
-  Sort getTesterCodomainSort() const;
-
-  /* Function sort ------------------------------------------------------- */
-
-  /**
-   * @return the arity of a function sort
-   */
-  size_t getFunctionArity() const;
-
-  /**
-   * @return the domain sorts of a function sort
-   */
-  std::vector<Sort> getFunctionDomainSorts() const;
-
-  /**
-   * @return the codomain sort of a function sort
-   */
-  Sort getFunctionCodomainSort() const;
-
-  /* Array sort ---------------------------------------------------------- */
-
-  /**
-   * @return the array index sort of an array sort
-   */
-  Sort getArrayIndexSort() const;
-
-  /**
-   * @return the array element sort of an array element sort
-   */
-  Sort getArrayElementSort() const;
-
-  /* Set sort ------------------------------------------------------------ */
-
-  /**
-   * @return the element sort of a set sort
-   */
-  Sort getSetElementSort() const;
-
-  /* Bag sort ------------------------------------------------------------ */
-
-  /**
-   * @return the element sort of a bag sort
-   */
-  Sort getBagElementSort() const;
-
-  /* Sequence sort ------------------------------------------------------- */
-
-  /**
-   * @return the element sort of a sequence sort
-   */
-  Sort getSequenceElementSort() const;
-
-  /* Uninterpreted sort -------------------------------------------------- */
-
-  /**
-   * @return the name of an uninterpreted sort
-   */
-  std::string getUninterpretedSortName() const;
-
-  /**
-   * @return true if an uninterpreted sort is parameterezied
-   */
-  bool isUninterpretedSortParameterized() const;
-
-  /**
-   * @return the parameter sorts of an uninterpreted sort
-   */
-  std::vector<Sort> getUninterpretedSortParamSorts() const;
-
-  /* Sort constructor sort ----------------------------------------------- */
-
-  /**
-   * @return the name of a sort constructor sort
-   */
-  std::string getSortConstructorName() const;
-
-  /**
-   * @return the arity of a sort constructor sort
-   */
-  size_t getSortConstructorArity() const;
-
-  /* Bit-vector sort ----------------------------------------------------- */
-
-  /**
-   * @return the bit-width of the bit-vector sort
-   */
-  uint32_t getBVSize() const;
-
-  /* Floating-point sort ------------------------------------------------- */
-
-  /**
-   * @return the bit-width of the exponent of the floating-point sort
-   */
-  uint32_t getFPExponentSize() const;
-
-  /**
-   * @return the width of the significand of the floating-point sort
-   */
-  uint32_t getFPSignificandSize() const;
-
-  /* Datatype sort ------------------------------------------------------- */
-
-  /**
-   * @return the parameter sorts of a datatype sort
-   */
-  std::vector<Sort> getDatatypeParamSorts() const;
-
-  /**
-   * @return the arity of a datatype sort
-   */
-  size_t getDatatypeArity() const;
-
-  /* Tuple sort ---------------------------------------------------------- */
-
-  /**
-   * @return the length of a tuple sort
-   */
-  size_t getTupleLength() const;
-
-  /**
-   * @return the element sorts of a tuple sort
-   */
-  std::vector<Sort> getTupleSorts() const;
-
- private:
-  /** @return the internal wrapped TypeNode of this sort. */
-  const cvc5::TypeNode& getTypeNode(void) const;
-
-  /** Helper to convert a set of Sorts to internal TypeNodes. */
-  std::set<TypeNode> static sortSetToTypeNodes(const std::set<Sort>& sorts);
-  /** Helper to convert a vector of Sorts to internal TypeNodes. */
-  std::vector<TypeNode> static sortVectorToTypeNodes(
-      const std::vector<Sort>& sorts);
-  /** Helper to convert a vector of internal TypeNodes to Sorts. */
-  std::vector<Sort> static typeNodeVectorToSorts(
-      const Solver* slv, const std::vector<TypeNode>& types);
-
-  /**
-   * Constructor.
-   * @param slv the associated solver object
-   * @param t the internal type that is to be wrapped by this sort
-   * @return the Sort
-   */
-  Sort(const Solver* slv, const cvc5::TypeNode& t);
-
-  /**
-   * Helper for isNull checks. This prevents calling an API function with
-   * CVC4_API_CHECK_NOT_NULL
-   */
-  bool isNullHelper() const;
-
-  /**
-   * The associated solver object.
-   */
-  const Solver* d_solver;
-
-  /**
-   * The interal type wrapped by this sort.
-   * Note: This is a shared_ptr rather than a unique_ptr to avoid overhead due
-   *       to memory allocation (cvc5::Type is already ref counted, so this
-   *       could be a unique_ptr instead).
-   */
-  std::shared_ptr<cvc5::TypeNode> d_type;
-};
-
-/**
- * Serialize a sort to given stream.
- * @param out the output stream
- * @param s the sort to be serialized to the given output stream
- * @return the output stream
- */
-std::ostream& operator<<(std::ostream& out, const Sort& s) CVC4_EXPORT;
-
-/**
- * Hash function for Sorts.
- */
-struct CVC4_EXPORT SortHashFunction
-{
-  size_t operator()(const Sort& s) const;
-};
-
-/* -------------------------------------------------------------------------- */
-/* Op                                                                     */
-/* -------------------------------------------------------------------------- */
-
-/**
- * A CVC4 operator.
- * An operator is a term that represents certain operators, instantiated
- * with its required parameters, e.g., a term of kind BITVECTOR_EXTRACT.
- */
-class CVC4_EXPORT Op
-{
-  friend class Solver;
-  friend class Term;
-  friend struct OpHashFunction;
-
- public:
-  /**
-   * Constructor.
-   */
-  Op();
-
-  /**
-   * Destructor.
-   */
-  ~Op();
-
-  /**
-   * Syntactic equality operator.
-   * Return true if both operators are syntactically identical.
-   * Both operators must belong to the same solver object.
-   * @param t the operator to compare to for equality
-   * @return true if the operators are equal
-   */
-  bool operator==(const Op& t) const;
-
-  /**
-   * Syntactic disequality operator.
-   * Return true if both operators differ syntactically.
-   * Both terms must belong to the same solver object.
-   * @param t the operator to compare to for disequality
-   * @return true if operators are disequal
-   */
-  bool operator!=(const Op& t) const;
-
-  /**
-   * @return the kind of this operator
-   */
-  Kind getKind() const;
-
-  /**
-   * @return true if this operator is a null term
-   */
-  bool isNull() const;
-
-  /**
-   * @return true iff this operator is indexed
-   */
-  bool isIndexed() const;
-
-  /**
-   * Get the indices used to create this Op.
-   * Supports the following template arguments:
-   *   - string
-   *   - Kind
-   *   - uint32_t
-   *   - pair<uint32_t, uint32_t>
-   * Check the Op Kind with getKind() to determine which argument to use.
-   * @return the indices used to create this Op
-   */
-  template <typename T>
-  T getIndices() const;
-
-  /**
-   * @return a string representation of this operator
-   */
-  std::string toString() const;
-
- private:
-  /**
-   * Constructor for a single kind (non-indexed operator).
-   * @param slv the associated solver object
-   * @param k the kind of this Op
-   */
-  Op(const Solver* slv, const Kind k);
-
-  /**
-   * Constructor.
-   * @param slv the associated solver object
-   * @param k the kind of this Op
-   * @param n the internal node that is to be wrapped by this term
-   * @return the Term
-   */
-  Op(const Solver* slv, const Kind k, const cvc5::Node& n);
-
-  /**
-   * Helper for isNull checks. This prevents calling an API function with
-   * CVC4_API_CHECK_NOT_NULL
-   */
-  bool isNullHelper() const;
-
-  /**
-   * Note: An indexed operator has a non-null internal node, d_node
-   * Note 2: We use a helper method to avoid having API functions call
-   *         other API functions (we need to call this internally)
-   * @return true iff this Op is indexed
-   */
-  bool isIndexedHelper() const;
-
-  /**
-   * The associated solver object.
-   */
-  const Solver* d_solver;
-
-  /** The kind of this operator. */
-  Kind d_kind;
-
-  /**
-   * The internal node wrapped by this operator.
-   * Note: This is a shared_ptr rather than a unique_ptr to avoid overhead due
-   *       to memory allocation (cvc5::Node is already ref counted, so this
-   *       could be a unique_ptr instead).
-   */
-  std::shared_ptr<cvc5::Node> d_node;
-};
-
-/* -------------------------------------------------------------------------- */
-/* Term                                                                       */
-/* -------------------------------------------------------------------------- */
-
-/**
- * A CVC4 Term.
- */
-class CVC4_EXPORT Term
-{
-  friend class cvc5::Command;
-  friend class Datatype;
-  friend class DatatypeConstructor;
-  friend class DatatypeSelector;
-  friend class Solver;
-  friend class Grammar;
-  friend struct TermHashFunction;
-
- public:
-  /**
-   * Constructor.
-   */
-  Term();
-
-  /**
-   * Destructor.
-   */
-  ~Term();
-
-  /**
-   * Syntactic equality operator.
-   * Return true if both terms are syntactically identical.
-   * Both terms must belong to the same solver object.
-   * @param t the term to compare to for equality
-   * @return true if the terms are equal
-   */
-  bool operator==(const Term& t) const;
-
-  /**
-   * Syntactic disequality operator.
-   * Return true if both terms differ syntactically.
-   * Both terms must belong to the same solver object.
-   * @param t the term to compare to for disequality
-   * @return true if terms are disequal
-   */
-  bool operator!=(const Term& t) const;
-
-  /**
-   * Comparison for ordering on terms.
-   * @param t the term to compare to
-   * @return true if this term is less than t
-   */
-  bool operator<(const Term& t) const;
-
-  /**
-   * Comparison for ordering on terms.
-   * @param t the term to compare to
-   * @return true if this term is greater than t
-   */
-  bool operator>(const Term& t) const;
-
-  /**
-   * Comparison for ordering on terms.
-   * @param t the term to compare to
-   * @return true if this term is less than or equal to t
-   */
-  bool operator<=(const Term& t) const;
-
-  /**
-   * Comparison for ordering on terms.
-   * @param t the term to compare to
-   * @return true if this term is greater than or equal to t
-   */
-  bool operator>=(const Term& t) const;
-
-  /** @return the number of children of this term  */
-  size_t getNumChildren() const;
-
-  /**
-   * Get the child term at a given index.
-   * @param index the index of the child term to return
-   * @return the child term with the given index
-   */
-  Term operator[](size_t index) const;
-
-  /**
-   * @return the id of this term
-   */
-  uint64_t getId() const;
-
-  /**
-   * @return the kind of this term
-   */
-  Kind getKind() const;
-
-  /**
-   * @return the sort of this term
-   */
-  Sort getSort() const;
-
-  /**
-   * @return the result of replacing 'term' by 'replacement' in this term
-   */
-  Term substitute(const Term& term, const Term& replacement) const;
-
-  /**
-   * @return the result of simulatenously replacing 'terms' by 'replacements'
-   * in this term
-   */
-  Term substitute(const std::vector<Term>& terms,
-                  const std::vector<Term>& replacements) const;
-
-  /**
-   * @return true iff this term has an operator
-   */
-  bool hasOp() const;
-
-  /**
-   * @return the Op used to create this term
-   * Note: This is safe to call when hasOp() returns true.
-   */
-  Op getOp() const;
-
-  /**
-   * @return true if this Term is a null term
-   */
-  bool isNull() const;
-
-  /**
-   *  Return the base (element stored at all indices) of a constant array
-   *  throws an exception if the kind is not CONST_ARRAY
-   *  @return the base value
-   */
-  Term getConstArrayBase() const;
-
-  /**
-   *  Return the elements of a constant sequence
-   *  throws an exception if the kind is not CONST_SEQUENCE
-   *  @return the elements of the constant sequence.
-   */
-  std::vector<Term> getConstSequenceElements() const;
-
-  /**
-   * Boolean negation.
-   * @return the Boolean negation of this term
-   */
-  Term notTerm() const;
-
-  /**
-   * Boolean and.
-   * @param t a Boolean term
-   * @return the conjunction of this term and the given term
-   */
-  Term andTerm(const Term& t) const;
-
-  /**
-   * Boolean or.
-   * @param t a Boolean term
-   * @return the disjunction of this term and the given term
-   */
-  Term orTerm(const Term& t) const;
-
-  /**
-   * Boolean exclusive or.
-   * @param t a Boolean term
-   * @return the exclusive disjunction of this term and the given term
-   */
-  Term xorTerm(const Term& t) const;
-
-  /**
-   * Equality.
-   * @param t a Boolean term
-   * @return the Boolean equivalence of this term and the given term
-   */
-  Term eqTerm(const Term& t) const;
-
-  /**
-   * Boolean implication.
-   * @param t a Boolean term
-   * @return the implication of this term and the given term
-   */
-  Term impTerm(const Term& t) const;
-
-  /**
-   * If-then-else with this term as the Boolean condition.
-   * @param then_t the 'then' term
-   * @param else_t the 'else' term
-   * @return the if-then-else term with this term as the Boolean condition
-   */
-  Term iteTerm(const Term& then_t, const Term& else_t) const;
-
-  /**
-   * @return a string representation of this term
-   */
-  std::string toString() const;
-
-  /**
-   * Iterator for the children of a Term.
-   * Note: This treats uninterpreted functions as Term just like any other term
-   *       for example, the term f(x, y) will have Kind APPLY_UF and three
-   *       children: f, x, and y
-   */
-  class const_iterator : public std::iterator<std::input_iterator_tag, Term>
-  {
-    friend class Term;
-
-   public:
-    /**
-     * Null Constructor.
-     */
-    const_iterator();
-
-    /**
-     * Constructor
-     * @param slv the associated solver object
-     * @param e a shared pointer to the node that we're iterating over
-     * @param p the position of the iterator (e.g. which child it's on)
-     */
-    const_iterator(const Solver* slv,
-                   const std::shared_ptr<cvc5::Node>& e,
-                   uint32_t p);
-
-    /**
-     * Copy constructor.
-     */
-    const_iterator(const const_iterator& it);
-
-    /**
-     * Assignment operator.
-     * @param it the iterator to assign to
-     * @return the reference to the iterator after assignment
-     */
-    const_iterator& operator=(const const_iterator& it);
-
-    /**
-     * Equality operator.
-     * @param it the iterator to compare to for equality
-     * @return true if the iterators are equal
-     */
-    bool operator==(const const_iterator& it) const;
-
-    /**
-     * Disequality operator.
-     * @param it the iterator to compare to for disequality
-     * @return true if the iterators are disequal
-     */
-    bool operator!=(const const_iterator& it) const;
-
-    /**
-     * Increment operator (prefix).
-     * @return a reference to the iterator after incrementing by one
-     */
-    const_iterator& operator++();
-
-    /**
-     * Increment operator (postfix).
-     * @return a reference to the iterator after incrementing by one
-     */
-    const_iterator operator++(int);
-
-    /**
-     * Dereference operator.
-     * @return the term this iterator points to
-     */
-    Term operator*() const;
-
-   private:
-    /**
-     * The associated solver object.
-     */
-    const Solver* d_solver;
-    /** The original node to be iterated over. */
-    std::shared_ptr<cvc5::Node> d_origNode;
-    /** Keeps track of the iteration position. */
-    uint32_t d_pos;
-  };
-
-  /**
-   * @return an iterator to the first child of this Term
-   */
-  const_iterator begin() const;
-
-  /**
-   * @return an iterator to one-off-the-last child of this Term
-   */
-  const_iterator end() const;
-
-  /**
-   * @return true if the term is an integer that fits within std::int32_t.
-   */
-  bool isInt32() const;
-  /**
-   * @return the stored integer as a std::int32_t.
-   * Note: Asserts isInt32().
-   */
-  std::int32_t getInt32() const;
-  /**
-   * @return true if the term is an integer that fits within std::uint32_t.
-   */
-  bool isUInt32() const;
-  /**
-   * @return the stored integer as a std::uint32_t.
-   * Note: Asserts isUInt32().
-   */
-  std::uint32_t getUInt32() const;
-  /**
-   * @return true if the term is an integer that fits within std::int64_t.
-   */
-  bool isInt64() const;
-  /**
-   * @return the stored integer as a std::int64_t.
-   * Note: Asserts isInt64().
-   */
-  std::int64_t getInt64() const;
-  /**
-   * @return true if the term is an integer that fits within std::uint64_t.
-   */
-  bool isUInt64() const;
-  /**
-   * @return the stored integer as a std::uint64_t.
-   * Note: Asserts isUInt64().
-   */
-  std::uint64_t getUInt64() const;
-  /**
-   * @return true if the term is an integer.
-   */
-  bool isInteger() const;
-  /**
-   * @return the stored integer in (decimal) string representation.
-   * Note: Asserts isInteger().
-   */
-  std::string getInteger() const;
-
-  /**
-   * @return true if the term is a string constant.
-   */
-  bool isString() const;
-  /**
-   * @return the stored string constant.
-   *
-   * Note: This method is not to be confused with toString() which returns the
-   *       term in some string representation, whatever data it may hold.
-   *       Asserts isString().
-   */
-  std::wstring getString() const;
-
- protected:
-  /**
-   * The associated solver object.
-   */
-  const Solver* d_solver;
-
- private:
-  /** Helper to convert a vector of Terms to internal Nodes. */
-  std::vector<Node> static termVectorToNodes(const std::vector<Term>& terms);
-
-  /**
-   * Constructor.
-   * @param slv the associated solver object
-   * @param n the internal node that is to be wrapped by this term
-   * @return the Term
-   */
-  Term(const Solver* slv, const cvc5::Node& n);
-
-  /** @return the internal wrapped Node of this term. */
-  const cvc5::Node& getNode(void) const;
-
-  /**
-   * Helper for isNull checks. This prevents calling an API function with
-   * CVC4_API_CHECK_NOT_NULL
-   */
-  bool isNullHelper() const;
-
-  /**
-   * Helper function that returns the kind of the term, which takes into
-   * account special cases of the conversion for internal to external kinds.
-   * @return the kind of this term
-   */
-  Kind getKindHelper() const;
-
-  /**
-   * @return true if the current term is a constant integer that is casted into
-   * real using the operator CAST_TO_REAL, and returns false otherwise
-   */
-  bool isCastedReal() const;
-  /**
-   * The internal node wrapped by this term.
-   * Note: This is a shared_ptr rather than a unique_ptr to avoid overhead due
-   *       to memory allocation (cvc5::Node is already ref counted, so this
-   *       could be a unique_ptr instead).
-   */
-  std::shared_ptr<cvc5::Node> d_node;
-};
-
-/**
- * Hash function for Terms.
- */
-struct CVC4_EXPORT TermHashFunction
-{
-  size_t operator()(const Term& t) const;
-};
-
-/**
- * Serialize a term to given stream.
- * @param out the output stream
- * @param t the term to be serialized to the given output stream
- * @return the output stream
- */
-std::ostream& operator<<(std::ostream& out, const Term& t) CVC4_EXPORT;
-
-/**
- * Serialize a vector of terms to given stream.
- * @param out the output stream
- * @param vector the vector of terms to be serialized to the given stream
- * @return the output stream
- */
-std::ostream& operator<<(std::ostream& out,
-                         const std::vector<Term>& vector) CVC4_EXPORT;
-
-/**
- * Serialize a set of terms to the given stream.
- * @param out the output stream
- * @param set the set of terms to be serialized to the given stream
- * @return the output stream
- */
-std::ostream& operator<<(std::ostream& out,
-                         const std::set<Term>& set) CVC4_EXPORT;
-
-/**
- * Serialize an unordered_set of terms to the given stream.
- *
- * @param out the output stream
- * @param unordered_set the set of terms to be serialized to the given stream
- * @return the output stream
- */
-std::ostream& operator<<(std::ostream& out,
-                         const std::unordered_set<Term, TermHashFunction>&
-                             unordered_set) CVC4_EXPORT;
-
-/**
- * Serialize a map of terms to the given stream.
- *
- * @param out the output stream
- * @param map the map of terms to be serialized to the given stream
- * @return the output stream
- */
-template <typename V>
-std::ostream& operator<<(std::ostream& out,
-                         const std::map<Term, V>& map) CVC4_EXPORT;
-
-/**
- * Serialize an unordered_map of terms to the given stream.
- *
- * @param out the output stream
- * @param unordered_map the map of terms to be serialized to the given stream
- * @return the output stream
- */
-template <typename V>
-std::ostream& operator<<(std::ostream& out,
-                         const std::unordered_map<Term, V, TermHashFunction>&
-                             unordered_map) CVC4_EXPORT;
-
-/**
- * Serialize an operator to given stream.
- * @param out the output stream
- * @param t the operator to be serialized to the given output stream
- * @return the output stream
- */
-std::ostream& operator<<(std::ostream& out, const Op& t) CVC4_EXPORT;
-
-/**
- * Hash function for Ops.
- */
-struct CVC4_EXPORT OpHashFunction
-{
-  size_t operator()(const Op& t) const;
-};
-
-/* -------------------------------------------------------------------------- */
-/* Datatypes                                                                  */
-/* -------------------------------------------------------------------------- */
-
-class DatatypeConstructorIterator;
-class DatatypeIterator;
-
-/**
- * A CVC4 datatype constructor declaration.
- */
-class CVC4_EXPORT DatatypeConstructorDecl
-{
-  friend class DatatypeDecl;
-  friend class Solver;
-
- public:
-  /** Constructor.  */
-  DatatypeConstructorDecl();
-
-  /**
-   * Destructor.
-   */
-  ~DatatypeConstructorDecl();
-
-  /**
-   * Add datatype selector declaration.
-   * @param name the name of the datatype selector declaration to add
-   * @param sort the range sort of the datatype selector declaration to add
-   */
-  void addSelector(const std::string& name, const Sort& sort);
-  /**
-   * Add datatype selector declaration whose range type is the datatype itself.
-   * @param name the name of the datatype selector declaration to add
-   */
-  void addSelectorSelf(const std::string& name);
-
-  /**
-   * @return true if this DatatypeConstructorDecl is a null declaration.
-   */
-  bool isNull() const;
-
-  /**
-   * @return a string representation of this datatype constructor declaration
-   */
-  std::string toString() const;
-
- private:
-  /**
-   * Constructor.
-   * @param slv the associated solver object
-   * @param name the name of the datatype constructor
-   * @return the DatatypeConstructorDecl
-   */
-  DatatypeConstructorDecl(const Solver* slv, const std::string& name);
-
-  /**
-   * Helper for isNull checks. This prevents calling an API function with
-   * CVC4_API_CHECK_NOT_NULL
-   */
-  bool isNullHelper() const;
-
-  /**
-   * The associated solver object.
-   */
-  const Solver* d_solver;
-
-  /**
-   * The internal (intermediate) datatype constructor wrapped by this
-   * datatype constructor declaration.
-   * Note: This is a shared_ptr rather than a unique_ptr since
-   *       cvc5::DTypeConstructor is not ref counted.
-   */
-  std::shared_ptr<cvc5::DTypeConstructor> d_ctor;
-};
-
-class Solver;
-
-/**
- * A CVC4 datatype declaration.
- */
-class CVC4_EXPORT DatatypeDecl
-{
-  friend class DatatypeConstructorArg;
-  friend class Solver;
-  friend class Grammar;
-
- public:
-  /** Constructor.  */
-  DatatypeDecl();
-
-  /**
-   * Destructor.
-   */
-  ~DatatypeDecl();
-
-  /**
-   * Add datatype constructor declaration.
-   * @param ctor the datatype constructor declaration to add
-   */
-  void addConstructor(const DatatypeConstructorDecl& ctor);
-
-  /** Get the number of constructors (so far) for this Datatype declaration. */
-  size_t getNumConstructors() const;
-
-  /** Is this Datatype declaration parametric? */
-  bool isParametric() const;
-
-  /**
-   * @return true if this DatatypeDecl is a null object
-   */
-  bool isNull() const;
-
-  /**
-   * @return a string representation of this datatype declaration
-   */
-  std::string toString() const;
-
-  /** @return the name of this datatype declaration. */
-  std::string getName() const;
-
- private:
-  /**
-   * Constructor.
-   * @param slv the associated solver object
-   * @param name the name of the datatype
-   * @param isCoDatatype true if a codatatype is to be constructed
-   * @return the DatatypeDecl
-   */
-  DatatypeDecl(const Solver* slv,
-               const std::string& name,
-               bool isCoDatatype = false);
-
-  /**
-   * Constructor for parameterized datatype declaration.
-   * Create sorts parameter with Solver::mkParamSort().
-   * @param slv the associated solver object
-   * @param name the name of the datatype
-   * @param param the sort parameter
-   * @param isCoDatatype true if a codatatype is to be constructed
-   */
-  DatatypeDecl(const Solver* slv,
-               const std::string& name,
-               const Sort& param,
-               bool isCoDatatype = false);
-
-  /**
-   * Constructor for parameterized datatype declaration.
-   * Create sorts parameter with Solver::mkParamSort().
-   * @param slv the associated solver object
-   * @param name the name of the datatype
-   * @param params a list of sort parameters
-   * @param isCoDatatype true if a codatatype is to be constructed
-   */
-  DatatypeDecl(const Solver* slv,
-               const std::string& name,
-               const std::vector<Sort>& params,
-               bool isCoDatatype = false);
-
-  /** @return the internal wrapped Dtype of this datatype declaration. */
-  cvc5::DType& getDatatype(void) const;
-
-  /**
-   * Helper for isNull checks. This prevents calling an API function with
-   * CVC4_API_CHECK_NOT_NULL
-   */
-  bool isNullHelper() const;
-
-  /**
-   * The associated solver object.
-   */
-  const Solver* d_solver;
-
-  /**
-   * The internal (intermediate) datatype wrapped by this datatype
-   * declaration.
-   * Note: This is a shared_ptr rather than a unique_ptr since cvc5::DType is
-   *       not ref counted.
-   */
-  std::shared_ptr<cvc5::DType> d_dtype;
-};
-
-/**
- * A CVC4 datatype selector.
- */
-class CVC4_EXPORT DatatypeSelector
-{
-  friend class DatatypeConstructor;
-  friend class Solver;
-
- public:
-  /**
-   * Constructor.
-   */
-  DatatypeSelector();
-
-  /**
-   * Destructor.
-   */
-  ~DatatypeSelector();
-
-  /** @return the name of this Datatype selector. */
-  std::string getName() const;
-
-  /**
-   * Get the selector operator of this datatype selector.
-   * @return the selector term
-   */
-  Term getSelectorTerm() const;
-
-  /** @return the range sort of this argument. */
-  Sort getRangeSort() const;
-
-  /**
-   * @return true if this DatatypeSelector is a null object
-   */
-  bool isNull() const;
-
-  /**
-   * @return a string representation of this datatype selector
-   */
-  std::string toString() const;
-
- private:
-  /**
-   * Constructor.
-   * @param slv the associated solver object
-   * @param stor the internal datatype selector to be wrapped
-   * @return the DatatypeSelector
-   */
-  DatatypeSelector(const Solver* slv, const cvc5::DTypeSelector& stor);
-
-  /**
-   * Helper for isNull checks. This prevents calling an API function with
-   * CVC4_API_CHECK_NOT_NULL
-   */
-  bool isNullHelper() const;
-
-  /**
-   * The associated solver object.
-   */
-  const Solver* d_solver;
-
-  /**
-   * The internal datatype selector wrapped by this datatype selector.
-   * Note: This is a shared_ptr rather than a unique_ptr since cvc5::DType is
-   *       not ref counted.
-   */
-  std::shared_ptr<cvc5::DTypeSelector> d_stor;
-};
-
-/**
- * A CVC4 datatype constructor.
- */
-class CVC4_EXPORT DatatypeConstructor
-{
-  friend class Datatype;
-  friend class Solver;
-
- public:
-  /**
-   * Constructor.
-   */
-  DatatypeConstructor();
-
-  /**
-   * Destructor.
-   */
-  ~DatatypeConstructor();
-
-  /** @return the name of this Datatype constructor. */
-  std::string getName() const;
-
-  /**
-   * Get the constructor operator of this datatype constructor.
-   * @return the constructor term
-   */
-  Term getConstructorTerm() const;
-
-  /**
-   * Get the constructor operator of this datatype constructor whose return
-   * type is retSort. This method is intended to be used on constructors of
-   * parametric datatypes and can be seen as returning the constructor
-   * term that has been explicitly cast to the given sort.
-   *
-   * This method is required for constructors of parametric datatypes whose
-   * return type cannot be determined by type inference. For example, given:
-   *   (declare-datatype List (par (T) ((nil) (cons (head T) (tail (List T))))))
-   * The type of nil terms need to be provided by the user. In SMT version 2.6,
-   * this is done via the syntax for qualified identifiers:
-   *   (as nil (List Int))
-   * This method is equivalent of applying the above, where this
-   * DatatypeConstructor is the one corresponding to nil, and retSort is
-   * (List Int).
-   *
-   * Furthermore note that the returned constructor term t is an operator,
-   * while Solver::mkTerm(APPLY_CONSTRUCTOR, t) is used to construct the above
-   * (nullary) application of nil.
-   *
-   * @param retSort the desired return sort of the constructor
-   * @return the constructor term
-   */
-  Term getSpecializedConstructorTerm(const Sort& retSort) const;
-
-  /**
-   * Get the tester operator of this datatype constructor.
-   * @return the tester operator
-   */
-  Term getTesterTerm() const;
-
-  /**
-   * @return the number of selectors (so far) of this Datatype constructor.
-   */
-  size_t getNumSelectors() const;
-
-  /** @return the i^th DatatypeSelector. */
-  DatatypeSelector operator[](size_t index) const;
-  /**
-   * Get the datatype selector with the given name.
-   * This is a linear search through the selectors, so in case of
-   * multiple, similarly-named selectors, the first is returned.
-   * @param name the name of the datatype selector
-   * @return the first datatype selector with the given name
-   */
-  DatatypeSelector operator[](const std::string& name) const;
-  DatatypeSelector getSelector(const std::string& name) const;
-
-  /**
-   * Get the term representation of the datatype selector with the given name.
-   * This is a linear search through the arguments, so in case of multiple,
-   * similarly-named arguments, the selector for the first is returned.
-   * @param name the name of the datatype selector
-   * @return a term representing the datatype selector with the given name
-   */
-  Term getSelectorTerm(const std::string& name) const;
-
-  /**
-   * @return true if this DatatypeConstructor is a null object
-   */
-  bool isNull() const;
-
-  /**
-   * @return a string representation of this datatype constructor
-   */
-  std::string toString() const;
-
-  /**
-   * Iterator for the selectors of a datatype constructor.
-   */
-  class const_iterator
-      : public std::iterator<std::input_iterator_tag, DatatypeConstructor>
-  {
-    friend class DatatypeConstructor;  // to access constructor
-
-   public:
-    /** Nullary constructor (required for Cython). */
-    const_iterator();
-
-    /**
-     * Assignment operator.
-     * @param it the iterator to assign to
-     * @return the reference to the iterator after assignment
-     */
-    const_iterator& operator=(const const_iterator& it);
-
-    /**
-     * Equality operator.
-     * @param it the iterator to compare to for equality
-     * @return true if the iterators are equal
-     */
-    bool operator==(const const_iterator& it) const;
-
-    /**
-     * Disequality operator.
-     * @param it the iterator to compare to for disequality
-     * @return true if the iterators are disequal
-     */
-    bool operator!=(const const_iterator& it) const;
-
-    /**
-     * Increment operator (prefix).
-     * @return a reference to the iterator after incrementing by one
-     */
-    const_iterator& operator++();
-
-    /**
-     * Increment operator (postfix).
-     * @return a reference to the iterator after incrementing by one
-     */
-    const_iterator operator++(int);
-
-    /**
-     * Dereference operator.
-     * @return a reference to the selector this iterator points to
-     */
-    const DatatypeSelector& operator*() const;
-
-    /**
-     * Dereference operator.
-     * @return a pointer to the selector this iterator points to
-     */
-    const DatatypeSelector* operator->() const;
-
-   private:
-    /**
-     * Constructor.
-     * @param slv the associated Solver object
-     * @param ctor the internal datatype constructor to iterate over
-     * @param true if this is a begin() iterator
-     */
-    const_iterator(const Solver* slv,
-                   const cvc5::DTypeConstructor& ctor,
-                   bool begin);
-
-    /**
-     * The associated solver object.
-     */
-    const Solver* d_solver;
-
-    /**
-     * A pointer to the list of selectors of the internal datatype
-     * constructor to iterate over.
-     * This pointer is maintained for operators == and != only.
-     */
-    const void* d_int_stors;
-
-    /** The list of datatype selector (wrappers) to iterate over. */
-    std::vector<DatatypeSelector> d_stors;
-
-    /** The current index of the iterator. */
-    size_t d_idx;
-  };
-
-  /**
-   * @return an iterator to the first selector of this constructor
-   */
-  const_iterator begin() const;
-
-  /**
-   * @return an iterator to one-off-the-last selector of this constructor
-   */
-  const_iterator end() const;
-
- private:
-  /**
-   * Constructor.
-   * @param ctor the internal datatype constructor to be wrapped
-   * @return the DatatypeConstructor
-   */
-  DatatypeConstructor(const Solver* slv, const cvc5::DTypeConstructor& ctor);
-
-  /**
-   * Return selector for name.
-   * @param name The name of selector to find
-   * @return the selector object for the name
-   */
-  DatatypeSelector getSelectorForName(const std::string& name) const;
-
-  /**
-   * Helper for isNull checks. This prevents calling an API function with
-   * CVC4_API_CHECK_NOT_NULL
-   */
-  bool isNullHelper() const;
-
-  /**
-   * The associated solver object.
-   */
-  const Solver* d_solver;
-
-  /**
-   * The internal datatype constructor wrapped by this datatype constructor.
-   * Note: This is a shared_ptr rather than a unique_ptr since cvc5::DType is
-   *       not ref counted.
-   */
-  std::shared_ptr<cvc5::DTypeConstructor> d_ctor;
-};
-
-/*
- * A CVC4 datatype.
- */
-class CVC4_EXPORT Datatype
-{
-  friend class Solver;
-  friend class Sort;
-
- public:
-  /** Constructor. */
-  Datatype();
-
-  /**
-   * Destructor.
-   */
-  ~Datatype();
-
-  /**
-   * Get the datatype constructor at a given index.
-   * @param idx the index of the datatype constructor to return
-   * @return the datatype constructor with the given index
-   */
-  DatatypeConstructor operator[](size_t idx) const;
-
-  /**
-   * Get the datatype constructor with the given name.
-   * This is a linear search through the constructors, so in case of multiple,
-   * similarly-named constructors, the first is returned.
-   * @param name the name of the datatype constructor
-   * @return the datatype constructor with the given name
-   */
-  DatatypeConstructor operator[](const std::string& name) const;
-  DatatypeConstructor getConstructor(const std::string& name) const;
-
-  /**
-   * Get a term representing the datatype constructor with the given name.
-   * This is a linear search through the constructors, so in case of multiple,
-   * similarly-named constructors, the
-   * first is returned.
-   */
-  Term getConstructorTerm(const std::string& name) const;
-
-  /** @return the name of this Datatype. */
-  std::string getName() const;
-
-  /** @return the number of constructors for this Datatype. */
-  size_t getNumConstructors() const;
-
-  /** @return true if this datatype is parametric */
-  bool isParametric() const;
-
-  /** @return true if this datatype corresponds to a co-datatype */
-  bool isCodatatype() const;
-
-  /** @return true if this datatype corresponds to a tuple */
-  bool isTuple() const;
-
-  /** @return true if this datatype corresponds to a record */
-  bool isRecord() const;
-
-  /** @return true if this datatype is finite */
-  bool isFinite() const;
-
-  /**
-   * Is this datatype well-founded? If this datatype is not a codatatype,
-   * this returns false if there are no values of this datatype that are of
-   * finite size.
-   *
-   * @return true if this datatype is well-founded
-   */
-  bool isWellFounded() const;
-
-  /**
-   * Does this datatype have nested recursion? This method returns false if a
-   * value of this datatype includes a subterm of its type that is nested
-   * beneath a non-datatype type constructor. For example, a datatype
-   * T containing a constructor having a selector with range type (Set T) has
-   * nested recursion.
-   *
-   * @return true if this datatype has nested recursion
-   */
-  bool hasNestedRecursion() const;
-
-  /**
-   * @return true if this Datatype is a null object
-   */
-  bool isNull() const;
-
-  /**
-   * @return a string representation of this datatype
-   */
-  std::string toString() const;
-
-  /**
-   * Iterator for the constructors of a datatype.
-   */
-  class const_iterator : public std::iterator<std::input_iterator_tag, Datatype>
-  {
-    friend class Datatype;  // to access constructor
-
-   public:
-    /** Nullary constructor (required for Cython). */
-    const_iterator();
-
-    /**
-     * Assignment operator.
-     * @param it the iterator to assign to
-     * @return the reference to the iterator after assignment
-     */
-    const_iterator& operator=(const const_iterator& it);
-
-    /**
-     * Equality operator.
-     * @param it the iterator to compare to for equality
-     * @return true if the iterators are equal
-     */
-    bool operator==(const const_iterator& it) const;
-
-    /**
-     * Disequality operator.
-     * @param it the iterator to compare to for disequality
-     * @return true if the iterators are disequal
-     */
-    bool operator!=(const const_iterator& it) const;
-
-    /**
-     * Increment operator (prefix).
-     * @return a reference to the iterator after incrementing by one
-     */
-    const_iterator& operator++();
-
-    /**
-     * Increment operator (postfix).
-     * @return a reference to the iterator after incrementing by one
-     */
-    const_iterator operator++(int);
-
-    /**
-     * Dereference operator.
-     * @return a reference to the constructor this iterator points to
-     */
-    const DatatypeConstructor& operator*() const;
-
-    /**
-     * Dereference operator.
-     * @return a pointer to the constructor this iterator points to
-     */
-    const DatatypeConstructor* operator->() const;
-
-   private:
-    /**
-     * Constructor.
-     * @param slv the associated Solver object
-     * @param dtype the internal datatype to iterate over
-     * @param true if this is a begin() iterator
-     */
-    const_iterator(const Solver* slv, const cvc5::DType& dtype, bool begin);
-
-    /**
-     * The associated solver object.
-     */
-    const Solver* d_solver;
-
-    /**
-     * A pointer to the list of constructors of the internal datatype
-     * to iterate over.
-     * This pointer is maintained for operators == and != only.
-     */
-    const void* d_int_ctors;
-
-    /** The list of datatype constructor (wrappers) to iterate over. */
-    std::vector<DatatypeConstructor> d_ctors;
-
-    /** The current index of the iterator. */
-    size_t d_idx;
-  };
-
-  /**
-   * @return an iterator to the first constructor of this datatype
-   */
-  const_iterator begin() const;
-
-  /**
-   * @return an iterator to one-off-the-last constructor of this datatype
-   */
-  const_iterator end() const;
-
- private:
-  /**
-   * Constructor.
-   * @param dtype the internal datatype to be wrapped
-   * @return the Datatype
-   */
-  Datatype(const Solver* slv, const cvc5::DType& dtype);
-
-  /**
-   * Return constructor for name.
-   * @param name The name of constructor to find
-   * @return the constructor object for the name
-   */
-  DatatypeConstructor getConstructorForName(const std::string& name) const;
-
-  /**
-   * Helper for isNull checks. This prevents calling an API function with
-   * CVC4_API_CHECK_NOT_NULL
-   */
-  bool isNullHelper() const;
-
-  /**
-   * The associated solver object.
-   */
-  const Solver* d_solver;
-
-  /**
-   * The internal datatype wrapped by this datatype.
-   * Note: This is a shared_ptr rather than a unique_ptr since cvc5::DType is
-   *       not ref counted.
-   */
-  std::shared_ptr<cvc5::DType> d_dtype;
-};
-
-/**
- * Serialize a datatype declaration to given stream.
- * @param out the output stream
- * @param dtdecl the datatype declaration to be serialized to the given stream
- * @return the output stream
- */
-std::ostream& operator<<(std::ostream& out,
-                         const DatatypeDecl& dtdecl) CVC4_EXPORT;
-
-/**
- * Serialize a datatype constructor declaration to given stream.
- * @param out the output stream
- * @param ctordecl the datatype constructor declaration to be serialized
- * @return the output stream
- */
-std::ostream& operator<<(std::ostream& out,
-                         const DatatypeConstructorDecl& ctordecl) CVC4_EXPORT;
-
-/**
- * Serialize a vector of datatype constructor declarations to given stream.
- * @param out the output stream
- * @param vector the vector of datatype constructor declarations to be
- * serialized to the given stream
- * @return the output stream
- */
-std::ostream& operator<<(std::ostream& out,
-                         const std::vector<DatatypeConstructorDecl>& vector);
-
-/**
- * Serialize a datatype to given stream.
- * @param out the output stream
- * @param dtdecl the datatype to be serialized to given stream
- * @return the output stream
- */
-std::ostream& operator<<(std::ostream& out, const Datatype& dtype) CVC4_EXPORT;
-
-/**
- * Serialize a datatype constructor to given stream.
- * @param out the output stream
- * @param ctor the datatype constructor to be serialized to given stream
- * @return the output stream
- */
-std::ostream& operator<<(std::ostream& out,
-                         const DatatypeConstructor& ctor) CVC4_EXPORT;
-
-/**
- * Serialize a datatype selector to given stream.
- * @param out the output stream
- * @param ctor the datatype selector to be serialized to given stream
- * @return the output stream
- */
-std::ostream& operator<<(std::ostream& out,
-                         const DatatypeSelector& stor) CVC4_EXPORT;
-
-/* -------------------------------------------------------------------------- */
-/* Grammar                                                                    */
-/* -------------------------------------------------------------------------- */
-
-/**
- * A Sygus Grammar.
- */
-class CVC4_EXPORT Grammar
-{
-  friend class cvc5::Command;
-  friend class Solver;
-
- public:
-  /**
-   * Add <rule> to the set of rules corresponding to <ntSymbol>.
-   * @param ntSymbol the non-terminal to which the rule is added
-   * @param rule the rule to add
-   */
-  void addRule(const Term& ntSymbol, const Term& rule);
-
-  /**
-   * Add <rules> to the set of rules corresponding to <ntSymbol>.
-   * @param ntSymbol the non-terminal to which the rules are added
-   * @param rule the rules to add
-   */
-  void addRules(const Term& ntSymbol, const std::vector<Term>& rules);
-
-  /**
-   * Allow <ntSymbol> to be an arbitrary constant.
-   * @param ntSymbol the non-terminal allowed to be any constant
-   */
-  void addAnyConstant(const Term& ntSymbol);
-
-  /**
-   * Allow <ntSymbol> to be any input variable to corresponding
-   * synth-fun/synth-inv with the same sort as <ntSymbol>.
-   * @param ntSymbol the non-terminal allowed to be any input constant
-   */
-  void addAnyVariable(const Term& ntSymbol);
-
-  /**
-   * @return a string representation of this grammar.
-   */
-  std::string toString() const;
-
-  /**
-   * Nullary constructor. Needed for the Cython API.
-   */
-  Grammar();
-
- private:
-  /**
-   * Constructor.
-   * @param slv the solver that created this grammar
-   * @param sygusVars the input variables to synth-fun/synth-var
-   * @param ntSymbols the non-terminals of this grammar
-   */
-  Grammar(const Solver* slv,
-          const std::vector<Term>& sygusVars,
-          const std::vector<Term>& ntSymbols);
-
-  /**
-   * @return the resolved datatype of the Start symbol of the grammar
-   */
-  Sort resolve();
-
-  /**
-   * Adds a constructor to sygus datatype <dt> whose sygus operator is <term>.
-   *
-   * <ntsToUnres> contains a mapping from non-terminal symbols to the
-   * unresolved sorts they correspond to. This map indicates how the argument
-   * <term> should be interpreted (instances of symbols from the domain of
-   * <ntsToUnres> correspond to constructor arguments).
-   *
-   * The sygus operator that is actually added to <dt> corresponds to replacing
-   * each occurrence of non-terminal symbols from the domain of <ntsToUnres>
-   * with bound variables via purifySygusGTerm, and binding these variables
-   * via a lambda.
-   *
-   * @param dt the non-terminal's datatype to which a constructor is added
-   * @param term the sygus operator of the constructor
-   * @param ntsToUnres mapping from non-terminals to their unresolved sorts
-   */
-  void addSygusConstructorTerm(
-      DatatypeDecl& dt,
-      const Term& term,
-      const std::unordered_map<Term, Sort, TermHashFunction>& ntsToUnres) const;
-
-  /**
-   * Purify SyGuS grammar term.
-   *
-   * This returns a term where all occurrences of non-terminal symbols (those
-   * in the domain of <ntsToUnres>) are replaced by fresh variables. For
-   * each variable replaced in this way, we add the fresh variable it is
-   * replaced with to <args>, and the unresolved sorts corresponding to the
-   * non-terminal symbol to <cargs> (constructor args). In other words, <args>
-   * contains the free variables in the term returned by this method (which
-   * should be bound by a lambda), and <cargs> contains the sorts of the
-   * arguments of the sygus constructor.
-   *
-   * @param term the term to purify
-   * @param args the free variables in the term returned by this method
-   * @param cargs the sorts of the arguments of the sygus constructor
-   * @param ntsToUnres mapping from non-terminals to their unresolved sorts
-   * @return the purfied term
-   */
-  Term purifySygusGTerm(
-      const Term& term,
-      std::vector<Term>& args,
-      std::vector<Sort>& cargs,
-      const std::unordered_map<Term, Sort, TermHashFunction>& ntsToUnres) const;
-
-  /**
-   * This adds constructors to <dt> for sygus variables in <d_sygusVars> whose
-   * sort is argument <sort>. This method should be called when the sygus
-   * grammar term (Variable sort) is encountered.
-   *
-   * @param dt the non-terminal's datatype to which the constructors are added
-   * @param sort the sort of the sygus variables to add
-   */
-  void addSygusConstructorVariables(DatatypeDecl& dt, const Sort& sort) const;
-
-  /**
-   * Check if <rule> contains variables that are neither parameters of
-   * the corresponding synthFun/synthInv nor non-terminals.
-   * @param rule the non-terminal allowed to be any constant
-   * @return <true> if <rule> contains free variables and <false> otherwise
-   */
-  bool containsFreeVariables(const Term& rule) const;
-
-  /** The solver that created this grammar. */
-  const Solver* d_solver;
-  /** Input variables to the corresponding function/invariant to synthesize.*/
-  std::vector<Term> d_sygusVars;
-  /** The non-terminal symbols of this grammar. */
-  std::vector<Term> d_ntSyms;
-  /** The mapping from non-terminal symbols to their production terms. */
-  std::unordered_map<Term, std::vector<Term>, TermHashFunction> d_ntsToTerms;
-  /** The set of non-terminals that can be arbitrary constants. */
-  std::unordered_set<Term, TermHashFunction> d_allowConst;
-  /** The set of non-terminals that can be sygus variables. */
-  std::unordered_set<Term, TermHashFunction> d_allowVars;
-  /** Did we call resolve() before? */
-  bool d_isResolved;
-};
-
-/**
- * Serialize a grammar to given stream.
- * @param out the output stream
- * @param g the grammar to be serialized to the given output stream
- * @return the output stream
- */
-std::ostream& operator<<(std::ostream& out, const Grammar& g) CVC4_EXPORT;
-
-/* -------------------------------------------------------------------------- */
-/* Rounding Mode for Floating Points                                          */
-/* -------------------------------------------------------------------------- */
-
-/**
- * A CVC4 floating point rounding mode.
- */
-enum CVC4_EXPORT RoundingMode
-{
-  ROUND_NEAREST_TIES_TO_EVEN,
-  ROUND_TOWARD_POSITIVE,
-  ROUND_TOWARD_NEGATIVE,
-  ROUND_TOWARD_ZERO,
-  ROUND_NEAREST_TIES_TO_AWAY,
-};
-
-/**
- * Hash function for RoundingModes.
- */
-struct CVC4_EXPORT RoundingModeHashFunction
-{
-  inline size_t operator()(const RoundingMode& rm) const;
-};
-
-/* -------------------------------------------------------------------------- */
-/* Solver                                                                     */
-/* -------------------------------------------------------------------------- */
-
-/*
- * A CVC4 solver.
- */
-class CVC4_EXPORT Solver
-{
-  friend class Datatype;
-  friend class DatatypeDecl;
-  friend class DatatypeConstructor;
-  friend class DatatypeConstructorDecl;
-  friend class DatatypeSelector;
-  friend class Grammar;
-  friend class Op;
-  friend class cvc5::Command;
-  friend class Sort;
-  friend class Term;
-
- public:
-  /* .................................................................... */
-  /* Constructors/Destructors                                             */
-  /* .................................................................... */
-
-  /**
-   * Constructor.
-   * @param opts an optional pointer to a solver options object
-   * @return the Solver
-   */
-  Solver(Options* opts = nullptr);
-
-  /**
-   * Destructor.
-   */
-  ~Solver();
-
-  /**
-   * Disallow copy/assignment.
-   */
-  Solver(const Solver&) = delete;
-  Solver& operator=(const Solver&) = delete;
-
-  /* .................................................................... */
-  /* Solver Configuration                                                 */
-  /* .................................................................... */
-
-  bool supportsFloatingPoint() const;
-
-  /* .................................................................... */
-  /* Sorts Handling                                                       */
-  /* .................................................................... */
-
-  /**
-   * @return sort null
-   */
-  Sort getNullSort() const;
-
-  /**
-   * @return sort Boolean
-   */
-  Sort getBooleanSort() const;
-
-  /**
-   * @return sort Integer (in CVC4, Integer is a subtype of Real)
-   */
-  Sort getIntegerSort() const;
-
-  /**
-   * @return sort Real
-   */
-  Sort getRealSort() const;
-
-  /**
-   * @return sort RegExp
-   */
-  Sort getRegExpSort() const;
-
-  /**
-   * @return sort RoundingMode
-   */
-  Sort getRoundingModeSort() const;
-
-  /**
-   * @return sort String
-   */
-  Sort getStringSort() const;
-
-  /**
-   * Create an array sort.
-   * @param indexSort the array index sort
-   * @param elemSort the array element sort
-   * @return the array sort
-   */
-  Sort mkArraySort(const Sort& indexSort, const Sort& elemSort) const;
-
-  /**
-   * Create a bit-vector sort.
-   * @param size the bit-width of the bit-vector sort
-   * @return the bit-vector sort
-   */
-  Sort mkBitVectorSort(uint32_t size) const;
-
-  /**
-   * Create a floating-point sort.
-   * @param exp the bit-width of the exponent of the floating-point sort.
-   * @param sig the bit-width of the significand of the floating-point sort.
-   */
-  Sort mkFloatingPointSort(uint32_t exp, uint32_t sig) const;
-
-  /**
-   * Create a datatype sort.
-   * @param dtypedecl the datatype declaration from which the sort is created
-   * @return the datatype sort
-   */
-  Sort mkDatatypeSort(const DatatypeDecl& dtypedecl) const;
-
-  /**
-   * Create a vector of datatype sorts. The names of the datatype declarations
-   * must be distinct.
-   *
-   * @param dtypedecls the datatype declarations from which the sort is created
-   * @return the datatype sorts
-   */
-  std::vector<Sort> mkDatatypeSorts(
-      const std::vector<DatatypeDecl>& dtypedecls) const;
-
-  /**
-   * Create a vector of datatype sorts using unresolved sorts. The names of
-   * the datatype declarations in dtypedecls must be distinct.
-   *
-   * This method is called when the DatatypeDecl objects dtypedecls have been
-   * built using "unresolved" sorts.
-   *
-   * We associate each sort in unresolvedSorts with exacly one datatype from
-   * dtypedecls. In particular, it must have the same name as exactly one
-   * datatype declaration in dtypedecls.
-   *
-   * When constructing datatypes, unresolved sorts are replaced by the datatype
-   * sort constructed for the datatype declaration it is associated with.
-   *
-   * @param dtypedecls the datatype declarations from which the sort is created
-   * @param unresolvedSorts the list of unresolved sorts
-   * @return the datatype sorts
-   */
-  std::vector<Sort> mkDatatypeSorts(
-      const std::vector<DatatypeDecl>& dtypedecls,
-      const std::set<Sort>& unresolvedSorts) const;
-
-  /**
-   * Create function sort.
-   * @param domain the sort of the fuction argument
-   * @param codomain the sort of the function return value
-   * @return the function sort
-   */
-  Sort mkFunctionSort(const Sort& domain, const Sort& codomain) const;
-
-  /**
-   * Create function sort.
-   * @param sorts the sort of the function arguments
-   * @param codomain the sort of the function return value
-   * @return the function sort
-   */
-  Sort mkFunctionSort(const std::vector<Sort>& sorts,
-                      const Sort& codomain) const;
-
-  /**
-   * Create a sort parameter.
-   * @param symbol the name of the sort
-   * @return the sort parameter
-   */
-  Sort mkParamSort(const std::string& symbol) const;
-
-  /**
-   * Create a predicate sort.
-   * @param sorts the list of sorts of the predicate
-   * @return the predicate sort
-   */
-  Sort mkPredicateSort(const std::vector<Sort>& sorts) const;
-
-  /**
-   * Create a record sort
-   * @param fields the list of fields of the record
-   * @return the record sort
-   */
-  Sort mkRecordSort(
-      const std::vector<std::pair<std::string, Sort>>& fields) const;
-
-  /**
-   * Create a set sort.
-   * @param elemSort the sort of the set elements
-   * @return the set sort
-   */
-  Sort mkSetSort(const Sort& elemSort) const;
-
-  /**
-   * Create a bag sort.
-   * @param elemSort the sort of the bag elements
-   * @return the bag sort
-   */
-  Sort mkBagSort(const Sort& elemSort) const;
-
-  /**
-   * Create a sequence sort.
-   * @param elemSort the sort of the sequence elements
-   * @return the sequence sort
-   */
-  Sort mkSequenceSort(const Sort& elemSort) const;
-
-  /**
-   * Create an uninterpreted sort.
-   * @param symbol the name of the sort
-   * @return the uninterpreted sort
-   */
-  Sort mkUninterpretedSort(const std::string& symbol) const;
-
-  /**
-   * Create a sort constructor sort.
-   * @param symbol the symbol of the sort
-   * @param arity the arity of the sort
-   * @return the sort constructor sort
-   */
-  Sort mkSortConstructorSort(const std::string& symbol, size_t arity) const;
-
-  /**
-   * Create a tuple sort.
-   * @param sorts of the elements of the tuple
-   * @return the tuple sort
-   */
-  Sort mkTupleSort(const std::vector<Sort>& sorts) const;
-
-  /* .................................................................... */
-  /* Create Terms                                                         */
-  /* .................................................................... */
-
-  /**
-   * Create 0-ary term of given kind.
-   * @param kind the kind of the term
-   * @return the Term
-   */
-  Term mkTerm(Kind kind) const;
-
-  /**
-   * Create a unary term of given kind.
-   * @param kind the kind of the term
-   * @param child the child of the term
-   * @return the Term
-   */
-  Term mkTerm(Kind kind, const Term& child) const;
-
-  /**
-   * Create binary term of given kind.
-   * @param kind the kind of the term
-   * @param child1 the first child of the term
-   * @param child2 the second child of the term
-   * @return the Term
-   */
-  Term mkTerm(Kind kind, const Term& child1, const Term& child2) const;
-
-  /**
-   * Create ternary term of given kind.
-   * @param kind the kind of the term
-   * @param child1 the first child of the term
-   * @param child2 the second child of the term
-   * @param child3 the third child of the term
-   * @return the Term
-   */
-  Term mkTerm(Kind kind,
-              const Term& child1,
-              const Term& child2,
-              const Term& child3) const;
-
-  /**
-   * Create n-ary term of given kind.
-   * @param kind the kind of the term
-   * @param children the children of the term
-   * @return the Term
-   */
-  Term mkTerm(Kind kind, const std::vector<Term>& children) const;
-
-  /**
-   * Create nullary term of given kind from a given operator.
-   * Create operators with mkOp().
-   * @param the operator
-   * @return the Term
-   */
-  Term mkTerm(const Op& op) const;
-
-  /**
-   * Create unary term of given kind from a given operator.
-   * Create operators with mkOp().
-   * @param the operator
-   * @child the child of the term
-   * @return the Term
-   */
-  Term mkTerm(const Op& op, const Term& child) const;
-
-  /**
-   * Create binary term of given kind from a given operator.
-   * Create operators with mkOp().
-   * @param the operator
-   * @child1 the first child of the term
-   * @child2 the second child of the term
-   * @return the Term
-   */
-  Term mkTerm(const Op& op, const Term& child1, const Term& child2) const;
-
-  /**
-   * Create ternary term of given kind from a given operator.
-   * Create operators with mkOp().
-   * @param the operator
-   * @child1 the first child of the term
-   * @child2 the second child of the term
-   * @child3 the third child of the term
-   * @return the Term
-   */
-  Term mkTerm(const Op& op,
-              const Term& child1,
-              const Term& child2,
-              const Term& child3) const;
-
-  /**
-   * Create n-ary term of given kind from a given operator.
-   * Create operators with mkOp().
-   * @param op the operator
-   * @children the children of the term
-   * @return the Term
-   */
-  Term mkTerm(const Op& op, const std::vector<Term>& children) const;
-
-  /**
-   * Create a tuple term. Terms are automatically converted if sorts are
-   * compatible.
-   * @param sorts The sorts of the elements in the tuple
-   * @param terms The elements in the tuple
-   * @return the tuple Term
-   */
-  Term mkTuple(const std::vector<Sort>& sorts,
-               const std::vector<Term>& terms) const;
-
-  /* .................................................................... */
-  /* Create Operators                                                     */
-  /* .................................................................... */
-
-  /**
-   * Create an operator for a builtin Kind
-   * The Kind may not be the Kind for an indexed operator
-   *   (e.g. BITVECTOR_EXTRACT)
-   * Note: in this case, the Op simply wraps the Kind.
-   * The Kind can be used in mkTerm directly without
-   *   creating an op first.
-   * @param kind the kind to wrap
-   */
-  Op mkOp(Kind kind) const;
-
-  /**
-   * Create operator of kind:
-   *   - RECORD_UPDATE
-   *   - DIVISIBLE (to support arbitrary precision integers)
-   * See enum Kind for a description of the parameters.
-   * @param kind the kind of the operator
-   * @param arg the string argument to this operator
-   */
-  Op mkOp(Kind kind, const std::string& arg) const;
-
-  /**
-   * Create operator of kind:
-   *   - DIVISIBLE
-   *   - BITVECTOR_REPEAT
-   *   - BITVECTOR_ZERO_EXTEND
-   *   - BITVECTOR_SIGN_EXTEND
-   *   - BITVECTOR_ROTATE_LEFT
-   *   - BITVECTOR_ROTATE_RIGHT
-   *   - INT_TO_BITVECTOR
-   *   - FLOATINGPOINT_TO_UBV
-   *   - FLOATINGPOINT_TO_UBV_TOTAL
-   *   - FLOATINGPOINT_TO_SBV
-   *   - FLOATINGPOINT_TO_SBV_TOTAL
-   *   - TUPLE_UPDATE
-   * See enum Kind for a description of the parameters.
-   * @param kind the kind of the operator
-   * @param arg the uint32_t argument to this operator
-   */
-  Op mkOp(Kind kind, uint32_t arg) const;
-
-  /**
-   * Create operator of Kind:
-   *   - BITVECTOR_EXTRACT
-   *   - FLOATINGPOINT_TO_FP_IEEE_BITVECTOR
-   *   - FLOATINGPOINT_TO_FP_FLOATINGPOINT
-   *   - FLOATINGPOINT_TO_FP_REAL
-   *   - FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR
-   *   - FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR
-   *   - FLOATINGPOINT_TO_FP_GENERIC
-   * See enum Kind for a description of the parameters.
-   * @param kind the kind of the operator
-   * @param arg1 the first uint32_t argument to this operator
-   * @param arg2 the second uint32_t argument to this operator
-   */
-  Op mkOp(Kind kind, uint32_t arg1, uint32_t arg2) const;
-
-  /**
-   * Create operator of Kind:
-   *   - TUPLE_PROJECT
-   * See enum Kind for a description of the parameters.
-   * @param kind the kind of the operator
-   */
-  Op mkOp(Kind kind, const std::vector<uint32_t>& args) const;
-
-  /* .................................................................... */
-  /* Create Constants                                                     */
-  /* .................................................................... */
-
-  /**
-   * Create a Boolean true constant.
-   * @return the true constant
-   */
-  Term mkTrue() const;
-
-  /**
-   * Create a Boolean false constant.
-   * @return the false constant
-   */
-  Term mkFalse() const;
-
-  /**
-   * Create a Boolean constant.
-   * @return the Boolean constant
-   * @param val the value of the constant
-   */
-  Term mkBoolean(bool val) const;
-
-  /**
-   * Create a constant representing the number Pi.
-   * @return a constant representing Pi
-   */
-  Term mkPi() const;
-  /**
-   * Create an integer constant from a string.
-   * @param s the string representation of the constant, may represent an
-   *          integer (e.g., "123").
-   * @return a constant of sort Integer assuming 's' represents an integer)
-   */
-  Term mkInteger(const std::string& s) const;
-
-  /**
-   * Create an integer constant from a c++ int.
-   * @param val the value of the constant
-   * @return a constant of sort Integer
-   */
-  Term mkInteger(int64_t val) const;
-
-  /**
-   * Create a real constant from a string.
-   * @param s the string representation of the constant, may represent an
-   *          integer (e.g., "123") or real constant (e.g., "12.34" or "12/34").
-   * @return a constant of sort Real
-   */
-  Term mkReal(const std::string& s) const;
-
-  /**
-   * Create a real constant from an integer.
-   * @param val the value of the constant
-   * @return a constant of sort Integer
-   */
-  Term mkReal(int64_t val) const;
-
-  /**
-   * Create a real constant from a rational.
-   * @param num the value of the numerator
-   * @param den the value of the denominator
-   * @return a constant of sort Real
-   */
-  Term mkReal(int64_t num, int64_t den) const;
-
-  /**
-   * Create a regular expression empty term.
-   * @return the empty term
-   */
-  Term mkRegexpEmpty() const;
-
-  /**
-   * Create a regular expression sigma term.
-   * @return the sigma term
-   */
-  Term mkRegexpSigma() const;
-
-  /**
-   * Create a constant representing an empty set of the given sort.
-   * @param sort the sort of the set elements.
-   * @return the empty set constant
-   */
-  Term mkEmptySet(const Sort& sort) const;
-
-  /**
-   * Create a constant representing an empty bag of the given sort.
-   * @param sort the sort of the bag elements.
-   * @return the empty bag constant
-   */
-  Term mkEmptyBag(const Sort& sort) const;
-
-  /**
-   * Create a separation logic nil term.
-   * @param sort the sort of the nil term
-   * @return the separation logic nil term
-   */
-  Term mkSepNil(const Sort& sort) const;
-
-  /**
-   * Create a String constant.
-   * @param s the string this constant represents
-   * @param useEscSequences determines whether escape sequences in \p s should
-   * be converted to the corresponding character
-   * @return the String constant
-   */
-  Term mkString(const std::string& s, bool useEscSequences = false) const;
-
-  /**
-   * Create a String constant.
-   * @param c the character this constant represents
-   * @return the String constant
-   */
-  Term mkString(const unsigned char c) const;
-
-  /**
-   * Create a String constant.
-   * @param s a list of unsigned (unicode) values this constant represents as
-   * string
-   * @return the String constant
-   */
-  Term mkString(const std::vector<uint32_t>& s) const;
-
-  /**
-   * Create a character constant from a given string.
-   * @param s the string denoting the code point of the character (in base 16)
-   * @return the character constant
-   */
-  Term mkChar(const std::string& s) const;
-
-  /**
-   * Create an empty sequence of the given element sort.
-   * @param sort The element sort of the sequence.
-   * @return the empty sequence with given element sort.
-   */
-  Term mkEmptySequence(const Sort& sort) const;
-
-  /**
-   * Create a universe set of the given sort.
-   * @param sort the sort of the set elements
-   * @return the universe set constant
-   */
-  Term mkUniverseSet(const Sort& sort) const;
-
-  /**
-   * Create a bit-vector constant of given size and value.
-   * @param size the bit-width of the bit-vector sort
-   * @param val the value of the constant
-   * @return the bit-vector constant
-   */
-  Term mkBitVector(uint32_t size, uint64_t val = 0) const;
-
-  /**
-   * Create a bit-vector constant from a given string of base 2, 10 or 16.
-   *
-   * The size of resulting bit-vector is
-   * - base  2: the size of the binary string
-   * - base 10: the min. size required to represent the decimal as a bit-vector
-   * - base 16: the max. size required to represent the hexadecimal as a
-   *            bit-vector (4 * size of the given value string)
-   *
-   * @param s the string representation of the constant
-   * @param base the base of the string representation (2, 10, or 16)
-   * @return the bit-vector constant
-   */
-  Term mkBitVector(const std::string& s, uint32_t base = 2) const;
-
-  /**
-   * Create a bit-vector constant of a given bit-width from a given string of
-   * base 2, 10 or 16.
-   * @param size the bit-width of the constant
-   * @param s the string representation of the constant
-   * @param base the base of the string representation (2, 10, or 16)
-   * @return the bit-vector constant
-   */
-  Term mkBitVector(uint32_t size, const std::string& s, uint32_t base) const;
-
-  /**
-   * Create a constant array with the provided constant value stored at every
-   * index
-   * @param sort the sort of the constant array (must be an array sort)
-   * @param val the constant value to store (must match the sort's element sort)
-   * @return the constant array term
-   */
-  Term mkConstArray(const Sort& sort, const Term& val) const;
-
-  /**
-   * Create a positive infinity floating-point constant. Requires CVC4 to be
-   * compiled with SymFPU support.
-   * @param exp Number of bits in the exponent
-   * @param sig Number of bits in the significand
-   * @return the floating-point constant
-   */
-  Term mkPosInf(uint32_t exp, uint32_t sig) const;
-
-  /**
-   * Create a negative infinity floating-point constant. Requires CVC4 to be
-   * compiled with SymFPU support.
-   * @param exp Number of bits in the exponent
-   * @param sig Number of bits in the significand
-   * @return the floating-point constant
-   */
-  Term mkNegInf(uint32_t exp, uint32_t sig) const;
-
-  /**
-   * Create a not-a-number (NaN) floating-point constant. Requires CVC4 to be
-   * compiled with SymFPU support.
-   * @param exp Number of bits in the exponent
-   * @param sig Number of bits in the significand
-   * @return the floating-point constant
-   */
-  Term mkNaN(uint32_t exp, uint32_t sig) const;
-
-  /**
-   * Create a positive zero (+0.0) floating-point constant. Requires CVC4 to be
-   * compiled with SymFPU support.
-   * @param exp Number of bits in the exponent
-   * @param sig Number of bits in the significand
-   * @return the floating-point constant
-   */
-  Term mkPosZero(uint32_t exp, uint32_t sig) const;
-
-  /**
-   * Create a negative zero (-0.0) floating-point constant. Requires CVC4 to be
-   * compiled with SymFPU support.
-   * @param exp Number of bits in the exponent
-   * @param sig Number of bits in the significand
-   * @return the floating-point constant
-   */
-  Term mkNegZero(uint32_t exp, uint32_t sig) const;
-
-  /**
-   * Create a roundingmode constant.
-   * @param rm the floating point rounding mode this constant represents
-   */
-  Term mkRoundingMode(RoundingMode rm) const;
-
-  /**
-   * Create uninterpreted constant.
-   * @param arg1 Sort of the constant
-   * @param arg2 Index of the constant
-   */
-  Term mkUninterpretedConst(const Sort& sort, int32_t index) const;
-
-  /**
-   * Create an abstract value constant.
-   * @param index Index of the abstract value
-   */
-  Term mkAbstractValue(const std::string& index) const;
-
-  /**
-   * Create an abstract value constant.
-   * @param index Index of the abstract value
-   */
-  Term mkAbstractValue(uint64_t index) const;
-
-  /**
-   * Create a floating-point constant (requires CVC4 to be compiled with symFPU
-   * support).
-   * @param exp Size of the exponent
-   * @param sig Size of the significand
-   * @param val Value of the floating-point constant as a bit-vector term
-   */
-  Term mkFloatingPoint(uint32_t exp, uint32_t sig, Term val) const;
-
-  /* .................................................................... */
-  /* Create Variables                                                     */
-  /* .................................................................... */
-
-  /**
-   * Create (first-order) constant (0-arity function symbol).
-   * SMT-LIB: ( declare-const <symbol> <sort> )
-   * SMT-LIB: ( declare-fun <symbol> ( ) <sort> )
-   *
-   * @param sort the sort of the constant
-   * @param symbol the name of the constant
-   * @return the first-order constant
-   */
-  Term mkConst(const Sort& sort, const std::string& symbol) const;
-  /**
-   * Create (first-order) constant (0-arity function symbol), with a default
-   * symbol name.
-   *
-   * @param sort the sort of the constant
-   * @return the first-order constant
-   */
-  Term mkConst(const Sort& sort) const;
-
-  /**
-   * Create a bound variable to be used in a binder (i.e. a quantifier, a
-   * lambda, or a witness binder).
-   * @param sort the sort of the variable
-   * @param symbol the name of the variable
-   * @return the variable
-   */
-  Term mkVar(const Sort& sort, const std::string& symbol = std::string()) const;
-
-  /* .................................................................... */
-  /* Create datatype constructor declarations                             */
-  /* .................................................................... */
-
-  DatatypeConstructorDecl mkDatatypeConstructorDecl(const std::string& name);
-
-  /* .................................................................... */
-  /* Create datatype declarations                                         */
-  /* .................................................................... */
-
-  /**
-   * Create a datatype declaration.
-   * @param name the name of the datatype
-   * @param isCoDatatype true if a codatatype is to be constructed
-   * @return the DatatypeDecl
-   */
-  DatatypeDecl mkDatatypeDecl(const std::string& name,
-                              bool isCoDatatype = false);
-
-  /**
-   * Create a datatype declaration.
-   * Create sorts parameter with Solver::mkParamSort().
-   * @param name the name of the datatype
-   * @param param the sort parameter
-   * @param isCoDatatype true if a codatatype is to be constructed
-   * @return the DatatypeDecl
-   */
-  DatatypeDecl mkDatatypeDecl(const std::string& name,
-                              Sort param,
-                              bool isCoDatatype = false);
-
-  /**
-   * Create a datatype declaration.
-   * Create sorts parameter with Solver::mkParamSort().
-   * @param name the name of the datatype
-   * @param params a list of sort parameters
-   * @param isCoDatatype true if a codatatype is to be constructed
-   * @return the DatatypeDecl
-   */
-  DatatypeDecl mkDatatypeDecl(const std::string& name,
-                              const std::vector<Sort>& params,
-                              bool isCoDatatype = false);
-
-  /* .................................................................... */
-  /* Formula Handling                                                     */
-  /* .................................................................... */
-
-  /**
-   * Simplify a formula without doing "much" work.  Does not involve
-   * the SAT Engine in the simplification, but uses the current
-   * definitions, assertions, and the current partial model, if one
-   * has been constructed.  It also involves theory normalization.
-   * @param t the formula to simplify
-   * @return the simplified formula
-   */
-  Term simplify(const Term& t);
-
-  /**
-   * Assert a formula.
-   * SMT-LIB: ( assert <term> )
-   * @param term the formula to assert
-   */
-  void assertFormula(const Term& term) const;
-
-  /**
-   * Check satisfiability.
-   * SMT-LIB: ( check-sat )
-   * @return the result of the satisfiability check.
-   */
-  Result checkSat() const;
-
-  /**
-   * Check satisfiability assuming the given formula.
-   * SMT-LIB: ( check-sat-assuming ( <prop_literal> ) )
-   * @param assumption the formula to assume
-   * @return the result of the satisfiability check.
-   */
-  Result checkSatAssuming(const Term& assumption) const;
-
-  /**
-   * Check satisfiability assuming the given formulas.
-   * SMT-LIB: ( check-sat-assuming ( <prop_literal>+ ) )
-   * @param assumptions the formulas to assume
-   * @return the result of the satisfiability check.
-   */
-  Result checkSatAssuming(const std::vector<Term>& assumptions) const;
-
-  /**
-   * Check entailment of the given formula w.r.t. the current set of assertions.
-   * @param term the formula to check entailment for
-   * @return the result of the entailment check.
-   */
-  Result checkEntailed(const Term& term) const;
-
-  /**
-   * Check entailment of the given set of given formulas w.r.t. the current
-   * set of assertions.
-   * @param terms the terms to check entailment for
-   * @return the result of the entailmentcheck.
-   */
-  Result checkEntailed(const std::vector<Term>& terms) const;
-
-  /**
-   * Create datatype sort.
-   * SMT-LIB: ( declare-datatype <symbol> <datatype_decl> )
-   * @param symbol the name of the datatype sort
-   * @param ctors the constructor declarations of the datatype sort
-   * @return the datatype sort
-   */
-  Sort declareDatatype(const std::string& symbol,
-                       const std::vector<DatatypeConstructorDecl>& ctors) const;
-
-  /**
-   * Declare n-ary function symbol.
-   * SMT-LIB: ( declare-fun <symbol> ( <sort>* ) <sort> )
-   * @param symbol the name of the function
-   * @param sorts the sorts of the parameters to this function
-   * @param sort the sort of the return value of this function
-   * @return the function
-   */
-  Term declareFun(const std::string& symbol,
-                  const std::vector<Sort>& sorts,
-                  const Sort& sort) const;
-
-  /**
-   * Declare uninterpreted sort.
-   * SMT-LIB: ( declare-sort <symbol> <numeral> )
-   * @param symbol the name of the sort
-   * @param arity the arity of the sort
-   * @return the sort
-   */
-  Sort declareSort(const std::string& symbol, uint32_t arity) const;
-
-  /**
-   * Define n-ary function.
-   * SMT-LIB: ( define-fun <function_def> )
-   * @param symbol the name of the function
-   * @param bound_vars the parameters to this function
-   * @param sort the sort of the return value of this function
-   * @param term the function body
-   * @param global determines whether this definition is global (i.e. persists
-   *               when popping the context)
-   * @return the function
-   */
-  Term defineFun(const std::string& symbol,
-                 const std::vector<Term>& bound_vars,
-                 const Sort& sort,
-                 const Term& term,
-                 bool global = false) const;
-  /**
-   * Define n-ary function.
-   * SMT-LIB: ( define-fun <function_def> )
-   * Create parameter 'fun' with mkConst().
-   * @param fun the sorted function
-   * @param bound_vars the parameters to this function
-   * @param term the function body
-   * @param global determines whether this definition is global (i.e. persists
-   *               when popping the context)
-   * @return the function
-   */
-  Term defineFun(const Term& fun,
-                 const std::vector<Term>& bound_vars,
-                 const Term& term,
-                 bool global = false) const;
-
-  /**
-   * Define recursive function.
-   * SMT-LIB: ( define-fun-rec <function_def> )
-   * @param symbol the name of the function
-   * @param bound_vars the parameters to this function
-   * @param sort the sort of the return value of this function
-   * @param term the function body
-   * @param global determines whether this definition is global (i.e. persists
-   *               when popping the context)
-   * @return the function
-   */
-  Term defineFunRec(const std::string& symbol,
-                    const std::vector<Term>& bound_vars,
-                    const Sort& sort,
-                    const Term& term,
-                    bool global = false) const;
-
-  /**
-   * Define recursive function.
-   * SMT-LIB: ( define-fun-rec <function_def> )
-   * Create parameter 'fun' with mkConst().
-   * @param fun the sorted function
-   * @param bound_vars the parameters to this function
-   * @param term the function body
-   * @param global determines whether this definition is global (i.e. persists
-   *               when popping the context)
-   * @return the function
-   */
-  Term defineFunRec(const Term& fun,
-                    const std::vector<Term>& bound_vars,
-                    const Term& term,
-                    bool global = false) const;
-
-  /**
-   * Define recursive functions.
-   * SMT-LIB: ( define-funs-rec ( <function_decl>^{n+1} ) ( <term>^{n+1} ) )
-   * Create elements of parameter 'funs' with mkConst().
-   * @param funs the sorted functions
-   * @param bound_vars the list of parameters to the functions
-   * @param term the list of function bodies of the functions
-   * @param global determines whether this definition is global (i.e. persists
-   *               when popping the context)
-   * @return the function
-   */
-  void defineFunsRec(const std::vector<Term>& funs,
-                     const std::vector<std::vector<Term>>& bound_vars,
-                     const std::vector<Term>& terms,
-                     bool global = false) const;
-
-  /**
-   * Echo a given string to the given output stream.
-   * SMT-LIB: ( echo <std::string> )
-   * @param out the output stream
-   * @param str the string to echo
-   */
-  void echo(std::ostream& out, const std::string& str) const;
-
-  /**
-   * Get the list of asserted formulas.
-   * SMT-LIB: ( get-assertions )
-   * @return the list of asserted formulas
-   */
-  std::vector<Term> getAssertions() const;
-
-  /**
-   * Get info from the solver.
-   * SMT-LIB: ( get-info <info_flag> )
-   * @return the info
-   */
-  std::string getInfo(const std::string& flag) const;
-
-  /**
-   * Get the value of a given option.
-   * SMT-LIB: ( get-option <keyword> )
-   * @param option the option for which the value is queried
-   * @return a string representation of the option value
-   */
-  std::string getOption(const std::string& option) const;
-
-  /**
-   * Get the set of unsat ("failed") assumptions.
-   * SMT-LIB: ( get-unsat-assumptions )
-   * Requires to enable option 'produce-unsat-assumptions'.
-   * @return the set of unsat assumptions.
-   */
-  std::vector<Term> getUnsatAssumptions() const;
-
-  /**
-   * Get the unsatisfiable core.
-   * SMT-LIB: ( get-unsat-core )
-   * Requires to enable option 'produce-unsat-cores'.
-   * @return a set of terms representing the unsatisfiable core
-   */
-  std::vector<Term> getUnsatCore() const;
-
-  /**
-   * Get the value of the given term.
-   * SMT-LIB: ( get-value ( <term> ) )
-   * @param term the term for which the value is queried
-   * @return the value of the given term
-   */
-  Term getValue(const Term& term) const;
-  /**
-   * Get the values of the given terms.
-   * SMT-LIB: ( get-value ( <term>+ ) )
-   * @param terms the terms for which the value is queried
-   * @return the values of the given terms
-   */
-  std::vector<Term> getValue(const std::vector<Term>& terms) const;
-
-  /**
-   * Do quantifier elimination.
-   * SMT-LIB: ( get-qe <q> )
-   * Requires a logic that supports quantifier elimination. Currently, the only
-   * logics supported by quantifier elimination is LRA and LIA.
-   * @param q a quantified formula of the form:
-   *   Q x1...xn. P( x1...xn, y1...yn )
-   * where P( x1...xn, y1...yn ) is a quantifier-free formula
-   * @return a formula ret such that, given the current set of formulas A
-   * asserted to this solver:
-   *   - ( A ^ q ) and ( A ^ ret ) are equivalent
-   *   - ret is quantifier-free formula containing only free variables in
-   *     y1...yn.
-   */
-  Term getQuantifierElimination(const Term& q) const;
-
-  /**
-   * Do partial quantifier elimination, which can be used for incrementally
-   * computing the result of a quantifier elimination.
-   * SMT-LIB: ( get-qe-disjunct <q> )
-   * Requires a logic that supports quantifier elimination. Currently, the only
-   * logics supported by quantifier elimination is LRA and LIA.
-   * @param q a quantified formula of the form:
-   *   Q x1...xn. P( x1...xn, y1...yn )
-   * where P( x1...xn, y1...yn ) is a quantifier-free formula
-   * @return a formula ret such that, given the current set of formulas A
-   * asserted to this solver:
-   *   - (A ^ q) => (A ^ ret) if Q is forall or (A ^ ret) => (A ^ q) if Q is
-   *     exists,
-   *   - ret is quantifier-free formula containing only free variables in
-   *     y1...yn,
-   *   - If Q is exists, let A^Q_n be the formula
-   *       A ^ ~ret^Q_1 ^ ... ^ ~ret^Q_n
-   *     where for each i=1,...n, formula ret^Q_i is the result of calling
-   *     getQuantifierEliminationDisjunct for q with the set of assertions
-   *     A^Q_{i-1}. Similarly, if Q is forall, then let A^Q_n be
-   *       A ^ ret^Q_1 ^ ... ^ ret^Q_n
-   *     where ret^Q_i is the same as above. In either case, we have
-   *     that ret^Q_j will eventually be true or false, for some finite j.
-   */
-  Term getQuantifierEliminationDisjunct(const Term& q) const;
-
-  /**
-   * When using separation logic, this sets the location sort and the
-   * datatype sort to the given ones. This method should be invoked exactly
-   * once, before any separation logic constraints are provided.
-   * @param locSort The location sort of the heap
-   * @param dataSort The data sort of the heap
-   */
-  void declareSeparationHeap(const Sort& locSort, const Sort& dataSort) const;
-
-  /**
-   * When using separation logic, obtain the term for the heap.
-   * @return The term for the heap
-   */
-  Term getSeparationHeap() const;
-
-  /**
-   * When using separation logic, obtain the term for nil.
-   * @return The term for nil
-   */
-  Term getSeparationNilTerm() const;
-
-  /**
-   * Pop (a) level(s) from the assertion stack.
-   * SMT-LIB: ( pop <numeral> )
-   * @param nscopes the number of levels to pop
-   */
-  void pop(uint32_t nscopes = 1) const;
-
-  /**
-   * Get an interpolant
-   * SMT-LIB: ( get-interpol <conj> )
-   * Requires to enable option 'produce-interpols'.
-   * @param conj the conjecture term
-   * @param output a Term I such that A->I and I->B are valid, where A is the
-   *        current set of assertions and B is given in the input by conj.
-   * @return true if it gets I successfully, false otherwise.
-   */
-  bool getInterpolant(const Term& conj, Term& output) const;
-
-  /**
-   * Get an interpolant
-   * SMT-LIB: ( get-interpol <conj> <g> )
-   * Requires to enable option 'produce-interpols'.
-   * @param conj the conjecture term
-   * @param grammar the grammar for the interpolant I
-   * @param output a Term I such that A->I and I->B are valid, where A is the
-   *        current set of assertions and B is given in the input by conj.
-   * @return true if it gets I successfully, false otherwise.
-   */
-  bool getInterpolant(const Term& conj, Grammar& grammar, Term& output) const;
-
-  /**
-   * Get an abduct.
-   * SMT-LIB: ( get-abduct <conj> )
-   * Requires enabling option 'produce-abducts'
-   * @param conj the conjecture term
-   * @param output a term C such that A^C is satisfiable, and A^~B^C is
-   *        unsatisfiable, where A is the current set of assertions and B is
-   *        given in the input by conj
-   * @return true if it gets C successfully, false otherwise
-   */
-  bool getAbduct(const Term& conj, Term& output) const;
-
-  /**
-   * Get an abduct.
-   * SMT-LIB: ( get-abduct <conj> <g> )
-   * Requires enabling option 'produce-abducts'
-   * @param conj the conjecture term
-   * @param grammar the grammar for the abduct C
-   * @param output a term C such that A^C is satisfiable, and A^~B^C is
-   *        unsatisfiable, where A is the current set of assertions and B is
-   *        given in the input by conj
-   * @return true if it gets C successfully, false otherwise
-   */
-  bool getAbduct(const Term& conj, Grammar& grammar, Term& output) const;
-
-  /**
-   * Block the current model. Can be called only if immediately preceded by a
-   * SAT or INVALID query.
-   * SMT-LIB: ( block-model )
-   * Requires enabling 'produce-models' option and setting 'block-models' option
-   * to a mode other than "none".
-   */
-  void blockModel() const;
-
-  /**
-   * Block the current model values of (at least) the values in terms. Can be
-   * called only if immediately preceded by a SAT or NOT_ENTAILED query.
-   * SMT-LIB: ( block-model-values ( <terms>+ ) )
-   * Requires enabling 'produce-models' option and setting 'block-models' option
-   * to a mode other than "none".
-   */
-  void blockModelValues(const std::vector<Term>& terms) const;
-
-  /**
-   * Print all instantiations made by the quantifiers module.
-   * @param out the output stream
-   */
-  void printInstantiations(std::ostream& out) const;
-
-  /**
-   * Push (a) level(s) to the assertion stack.
-   * SMT-LIB: ( push <numeral> )
-   * @param nscopes the number of levels to push
-   */
-  void push(uint32_t nscopes = 1) const;
-
-  /**
-   * Remove all assertions.
-   * SMT-LIB: ( reset-assertions )
-   */
-  void resetAssertions() const;
-
-  /**
-   * Set info.
-   * SMT-LIB: ( set-info <attribute> )
-   * @param keyword the info flag
-   * @param value the value of the info flag
-   */
-  void setInfo(const std::string& keyword, const std::string& value) const;
-
-  /**
-   * Set logic.
-   * SMT-LIB: ( set-logic <symbol> )
-   * @param logic the logic to set
-   */
-  void setLogic(const std::string& logic) const;
-
-  /**
-   * Set option.
-   * SMT-LIB: ( set-option <option> )
-   * @param option the option name
-   * @param value the option value
-   */
-  void setOption(const std::string& option, const std::string& value) const;
-
-  /**
-   * If needed, convert this term to a given sort. Note that the sort of the
-   * term must be convertible into the target sort. Currently only Int to Real
-   * conversions are supported.
-   * @param s the target sort
-   * @return the term wrapped into a sort conversion if needed
-   */
-  Term ensureTermSort(const Term& t, const Sort& s) const;
-
-  /**
-   * Append <symbol> to the current list of universal variables.
-   * SyGuS v2: ( declare-var <symbol> <sort> )
-   * @param sort the sort of the universal variable
-   * @param symbol the name of the universal variable
-   * @return the universal variable
-   */
-  Term mkSygusVar(const Sort& sort,
-                  const std::string& symbol = std::string()) const;
-
-  /**
-   * Create a Sygus grammar. The first non-terminal is treated as the starting
-   * non-terminal, so the order of non-terminals matters.
-   *
-   * @param boundVars the parameters to corresponding synth-fun/synth-inv
-   * @param ntSymbols the pre-declaration of the non-terminal symbols
-   * @return the grammar
-   */
-  Grammar mkSygusGrammar(const std::vector<Term>& boundVars,
-                         const std::vector<Term>& ntSymbols) const;
-
-  /**
-   * Synthesize n-ary function.
-   * SyGuS v2: ( synth-fun <symbol> ( <boundVars>* ) <sort> )
-   * @param symbol the name of the function
-   * @param boundVars the parameters to this function
-   * @param sort the sort of the return value of this function
-   * @return the function
-   */
-  Term synthFun(const std::string& symbol,
-                const std::vector<Term>& boundVars,
-                const Sort& sort) const;
-
-  /**
-   * Synthesize n-ary function following specified syntactic constraints.
-   * SyGuS v2: ( synth-fun <symbol> ( <boundVars>* ) <sort> <g> )
-   * @param symbol the name of the function
-   * @param boundVars the parameters to this function
-   * @param sort the sort of the return value of this function
-   * @param grammar the syntactic constraints
-   * @return the function
-   */
-  Term synthFun(const std::string& symbol,
-                const std::vector<Term>& boundVars,
-                Sort sort,
-                Grammar& grammar) const;
-
-  /**
-   * Synthesize invariant.
-   * SyGuS v2: ( synth-inv <symbol> ( <boundVars>* ) )
-   * @param symbol the name of the invariant
-   * @param boundVars the parameters to this invariant
-   * @param sort the sort of the return value of this invariant
-   * @return the invariant
-   */
-  Term synthInv(const std::string& symbol,
-                const std::vector<Term>& boundVars) const;
-
-  /**
-   * Synthesize invariant following specified syntactic constraints.
-   * SyGuS v2: ( synth-inv <symbol> ( <boundVars>* ) <g> )
-   * @param symbol the name of the invariant
-   * @param boundVars the parameters to this invariant
-   * @param sort the sort of the return value of this invariant
-   * @param grammar the syntactic constraints
-   * @return the invariant
-   */
-  Term synthInv(const std::string& symbol,
-                const std::vector<Term>& boundVars,
-                Grammar& grammar) const;
-
-  /**
-   * Add a forumla to the set of Sygus constraints.
-   * SyGuS v2: ( constraint <term> )
-   * @param term the formula to add as a constraint
-   */
-  void addSygusConstraint(const Term& term) const;
-
-  /**
-   * Add a set of Sygus constraints to the current state that correspond to an
-   * invariant synthesis problem.
-   * SyGuS v2: ( inv-constraint <inv> <pre> <trans> <post> )
-   * @param inv the function-to-synthesize
-   * @param pre the pre-condition
-   * @param trans the transition relation
-   * @param post the post-condition
-   */
-  void addSygusInvConstraint(Term inv, Term pre, Term trans, Term post) const;
-
-  /**
-   * Try to find a solution for the synthesis conjecture corresponding to the
-   * current list of functions-to-synthesize, universal variables and
-   * constraints.
-   * SyGuS v2: ( check-synth )
-   * @return the result of the synthesis conjecture.
-   */
-  Result checkSynth() const;
-
-  /**
-   * Get the synthesis solution of the given term. This method should be called
-   * immediately after the solver answers unsat for sygus input.
-   * @param term the term for which the synthesis solution is queried
-   * @return the synthesis solution of the given term
-   */
-  Term getSynthSolution(Term term) const;
-
-  /**
-   * Get the synthesis solutions of the given terms. This method should be
-   * called immediately after the solver answers unsat for sygus input.
-   * @param terms the terms for which the synthesis solutions is queried
-   * @return the synthesis solutions of the given terms
-   */
-  std::vector<Term> getSynthSolutions(const std::vector<Term>& terms) const;
-
-  /**
-   * Print solution for synthesis conjecture to the given output stream.
-   * @param out the output stream
-   */
-  void printSynthSolution(std::ostream& out) const;
-
-
-  // !!! This is only temporarily available until the parser is fully migrated
-  // to the new API. !!!
-  SmtEngine* getSmtEngine(void) const;
-
-  // !!! This is only temporarily available until options are refactored at
-  // the driver level. !!!
-  Options& getOptions(void);
-
- private:
-  /** @return the node manager of this solver */
-  NodeManager* getNodeManager(void) const;
-
-  /** Helper to check for API misuse in mkOp functions. */
-  void checkMkTerm(Kind kind, uint32_t nchildren) const;
-  /** Helper for mk-functions that call d_nodeMgr->mkConst(). */
-  template <typename T>
-  Term mkValHelper(T t) const;
-  /** Helper for mkReal functions that take a string as argument. */
-  Term mkRealFromStrHelper(const std::string& s) const;
-  /** Helper for mkBitVector functions that take a string as argument. */
-  Term mkBVFromStrHelper(const std::string& s, uint32_t base) const;
-  /**
-   * Helper for mkBitVector functions that take a string and a size as
-   * arguments.
-   */
-  Term mkBVFromStrHelper(uint32_t size,
-                         const std::string& s,
-                         uint32_t base) const;
-  /** Helper for mkBitVector functions that take an integer as argument. */
-  Term mkBVFromIntHelper(uint32_t size, uint64_t val) const;
-  /** Helper for functions that create tuple sorts. */
-  Sort mkTupleSortHelper(const std::vector<Sort>& sorts) const;
-  /** Helper for mkTerm functions that create Term from a Kind */
-  Term mkTermFromKind(Kind kind) const;
-  /** Helper for mkChar functions that take a string as argument. */
-  Term mkCharFromStrHelper(const std::string& s) const;
-  /** Get value helper, which accounts for subtyping */
-  Term getValueHelper(const Term& term) const;
-
-  /**
-   * Helper function that ensures that a given term is of sort real (as opposed
-   * to being of sort integer).
-   * @param t a term of sort integer or real
-   * @return a term of sort real
-   */
-  Term ensureRealSort(const Term& t) const;
-
-  /**
-   * Create n-ary term of given kind. This handles the cases of left/right
-   * associative operators, chainable operators, and cases when the number of
-   * children exceeds the maximum arity for the kind.
-   * @param kind the kind of the term
-   * @param children the children of the term
-   * @return the Term
-   */
-  Term mkTermHelper(Kind kind, const std::vector<Term>& children) const;
-
-  /**
-   * Create n-ary term of given kind from a given operator.
-   * @param op the operator
-   * @param children the children of the term
-   * @return the Term
-   */
-  Term mkTermHelper(const Op& op, const std::vector<Term>& children) const;
-
-  /**
-   * Create a vector of datatype sorts, using unresolved sorts.
-   * @param dtypedecls the datatype declarations from which the sort is created
-   * @param unresolvedSorts the list of unresolved sorts
-   * @return the datatype sorts
-   */
-  std::vector<Sort> mkDatatypeSortsInternal(
-      const std::vector<DatatypeDecl>& dtypedecls,
-      const std::set<Sort>& unresolvedSorts) const;
-
-  /**
-   * Synthesize n-ary function following specified syntactic constraints.
-   * SMT-LIB: ( synth-fun <symbol> ( <boundVars>* ) <sort> <g>? )
-   * @param symbol the name of the function
-   * @param boundVars the parameters to this function
-   * @param sort the sort of the return value of this function
-   * @param isInv determines whether this is synth-fun or synth-inv
-   * @param g the syntactic constraints
-   * @return the function
-   */
-  Term synthFunHelper(const std::string& symbol,
-                      const std::vector<Term>& boundVars,
-                      const Sort& sort,
-                      bool isInv = false,
-                      Grammar* grammar = nullptr) const;
-
-  /** Check whether string s is a valid decimal integer. */
-  bool isValidInteger(const std::string& s) const;
-
-  /** Increment the term stats counter. */
-  void increment_term_stats(Kind kind) const;
-  /** Increment the vars stats (if 'is_var') or consts stats counter. */
-  void increment_vars_consts_stats(const Sort& sort, bool is_var) const;
-
-  /** Keep a copy of the original option settings (for resets). */
-  std::unique_ptr<Options> d_originalOptions;
-  /** The node manager of this solver. */
-  std::unique_ptr<NodeManager> d_nodeMgr;
-  /** The statistics collected on the Api level. */
-  std::unique_ptr<Statistics> d_stats;
-  /** The SMT engine of this solver. */
-  std::unique_ptr<SmtEngine> d_smtEngine;
-  /** The random number generator of this solver. */
-  std::unique_ptr<Random> d_rng;
-};
-
-}  // namespace api
-}  // namespace cvc5
-#endif
diff --git a/src/api/cvc4cppkind.h b/src/api/cvc4cppkind.h
deleted file mode 100644 (file)
index eec9014..0000000
+++ /dev/null
@@ -1,2873 +0,0 @@
-/*********************                                                        */
-/*! \file cvc4cppkind.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Aina Niemetz, Andrew Reynolds, Makai Mann
- ** This file is part of the CVC4 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.\endverbatim
- **
- ** \brief The term kinds of the CVC4 C++ API.
- **
- ** The term kinds of the CVC4 C++ API.
- **/
-
-#include "cvc4_export.h"
-
-#ifndef CVC4__API__CVC4CPPKIND_H
-#define CVC4__API__CVC4CPPKIND_H
-
-#include <ostream>
-
-namespace cvc5 {
-namespace api {
-
-/* -------------------------------------------------------------------------- */
-/* Kind                                                                       */
-/* -------------------------------------------------------------------------- */
-
-/**
- * The kind of a CVC4 term.
- *
- * Note that the underlying type of Kind must be signed (to enable range
- * checks for validity). The size of this type depends on the size of
- * cvc5::Kind (NodeValue::NBITS_KIND, currently 10 bits, see expr/node_value.h).
- */
-enum CVC4_EXPORT Kind : int32_t
-{
-  /**
-   * Internal kind.
-   * Should never be exposed or created via the API.
-   */
-  INTERNAL_KIND = -2,
-  /**
-   * Undefined kind.
-   * Should never be exposed or created via the API.
-   */
-  UNDEFINED_KIND = -1,
-  /**
-   * Null kind (kind of null term Term()).
-   * Do not explicitly create via API functions other than Term().
-   */
-  NULL_EXPR,
-
-  /* Builtin --------------------------------------------------------------- */
-
-  /**
-   * Uninterpreted constant.
-   * Parameters: 2
-   *   -[1]: Sort of the constant
-   *   -[2]: Index of the constant
-   * Create with:
-   *   mkUninterpretedConst(Sort sort, int32_t index)
-   */
-  UNINTERPRETED_CONSTANT,
-  /**
-   * Abstract value (other than uninterpreted sort constants).
-   * Parameters: 1
-   *   -[1]: Index of the abstract value
-   * Create with:
-   *   mkAbstractValue(const std::string& index);
-   *   mkAbstractValue(uint64_t index);
-   */
-  ABSTRACT_VALUE,
-#if 0
-  /* Built-in operator */
-  BUILTIN,
-#endif
-  /**
-   * Equality, chainable.
-   * Parameters: n > 1
-   *   -[1]..[n]: Terms with same sorts
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  EQUAL,
-  /**
-   * Disequality.
-   * Parameters: n > 1
-   *   -[1]..[n]: Terms with same sorts
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  DISTINCT,
-  /**
-   * First-order constant.
-   * Not permitted in bindings (forall, exists, ...).
-   * Parameters:
-   *   See mkConst().
-   * Create with:
-   *   mkConst(const std::string& symbol, Sort sort)
-   *   mkConst(Sort sort)
-   */
-  CONSTANT,
-  /**
-   * (Bound) variable.
-   * Permitted in bindings and in the lambda and quantifier bodies only.
-   * Parameters:
-   *   See mkVar().
-   * Create with:
-   *   mkVar(const std::string& symbol, Sort sort)
-   *   mkVar(Sort sort)
-   */
-  VARIABLE,
-#if 0
-  /* Skolem variable (internal only) */
-  SKOLEM,
-#endif
-  /*
-   * Symbolic expression.
-   * Parameters: n > 0
-   *   -[1]..[n]: terms
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  SEXPR,
-  /**
-   * Lambda expression.
-   * Parameters: 2
-   *   -[1]: BOUND_VAR_LIST
-   *   -[2]: Lambda body
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  LAMBDA,
-  /**
-   * The syntax of a witness term is similar to a quantified formula except that
-   * only one bound variable is allowed.
-   * The term (witness ((x T)) F) returns an element x of type T
-   * and asserts F.
-   *
-   * The witness operator behaves like the description operator
-   * (see https://planetmath.org/hilbertsvarepsilonoperator) if there is no x
-   * that satisfies F. But if such x exists, the witness operator does not
-   * enforce the axiom that ensures uniqueness up to logical equivalence:
-   * forall x. F \equiv G => witness x. F =  witness x. G
-   *
-   * For example if there are 2 elements of type T that satisfy F, then the
-   * following formula is satisfiable:
-   * (distinct
-   *    (witness ((x Int)) F)
-   *    (witness ((x Int)) F))
-   *
-   * This kind is primarily used internally, but may be returned in models
-   * (e.g. for arithmetic terms in non-linear queries). However, it is not
-   * supported by the parser. Moreover, the user of the API should be cautious
-   * when using this operator. In general, all witness terms
-   * (witness ((x Int)) F) should be such that (exists ((x Int)) F) is a valid
-   * formula. If this is not the case, then the semantics in formulas that use
-   * witness terms may be unintuitive. For example, the following formula is
-   * unsatisfiable:
-   * (or (= (witness ((x Int)) false) 0) (not (= (witness ((x Int)) false) 0))
-   * whereas notice that (or (= z 0) (not (= z 0))) is true for any z.
-   *
-   * Parameters: 2
-   *   -[1]: BOUND_VAR_LIST
-   *   -[2]: Witness body
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  WITNESS,
-
-  /* Boolean --------------------------------------------------------------- */
-
-  /**
-   * Boolean constant.
-   * Parameters: 1
-   *   -[1]: Boolean value of the constant
-   * Create with:
-   *   mkTrue()
-   *   mkFalse()
-   *   mkBoolean(bool val)
-   */
-  CONST_BOOLEAN,
-  /* Logical not.
-   * Parameters: 1
-   *   -[1]: Boolean Term to negate
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  NOT,
-  /* Logical and.
-   * Parameters: n > 1
-   *   -[1]..[n]: Boolean Term of the conjunction
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  AND,
-  /**
-   * Logical implication.
-   * Parameters: n > 1
-   *   -[1]..[n]: Boolean Terms, right associative
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  IMPLIES,
-  /* Logical or.
-   * Parameters: n > 1
-   *   -[1]..[n]: Boolean Term of the disjunction
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  OR,
-  /* Logical exclusive or, left associative.
-   * Parameters: n > 1
-   *   -[1]..[n]: Boolean Terms, [1] xor ... xor [n]
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  XOR,
-  /* If-then-else.
-   * Parameters: 3
-   *   -[1] is a Boolean condition Term
-   *   -[2] the 'then' Term
-   *   -[3] the 'else' Term
-   * 'then' and 'else' term must have same base sort.
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  ITE,
-
-  /* UF -------------------------------------------------------------------- */
-
-  /* Application of an uninterpreted function.
-   * Parameters: n > 1
-   *   -[1]: Function Term
-   *   -[2]..[n]: Function argument instantiation Terms
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  APPLY_UF,
-#if 0
-  /* Boolean term variable */
-  BOOLEAN_TERM_VARIABLE,
-#endif
-  /**
-   * Cardinality constraint on uninterpreted sort S.
-   * Interpreted as a predicate that is true when the cardinality of S
-   * is less than or equal to the value of the second argument.
-   * Parameters: 2
-   *   -[1]: Term of sort S
-   *   -[2]: Positive integer constant that bounds the cardinality of sort S
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  CARDINALITY_CONSTRAINT,
-  /*
-   * Cardinality value for uninterpreted sort S.
-   * An operator that returns an integer indicating the value of the cardinality
-   * of sort S.
-   * Parameters: 1
-   *   -[1]: Term of sort S
-   * Create with:
-   *   mkTerm(Kind kind, Term child1)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  CARDINALITY_VALUE,
-#if 0
-  /* Combined cardinality constraint.  */
-  COMBINED_CARDINALITY_CONSTRAINT,
-  /* Partial uninterpreted function application.  */
-  PARTIAL_APPLY_UF,
-#endif
-  /**
-   * Higher-order applicative encoding of function application, left
-   * associative.
-   * Parameters: n > 1
-   *   -[1]: Function to apply
-   *   -[2] ... [n]: Arguments of the function
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  HO_APPLY,
-
-  /* Arithmetic ------------------------------------------------------------ */
-
-  /**
-   * Arithmetic addition.
-   * Parameters: n > 1
-   *   -[1]..[n]: Terms of sort Integer, Real (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  PLUS,
-  /**
-   * Arithmetic multiplication.
-   * Parameters: n > 1
-   *   -[1]..[n]: Terms of sort Integer, Real (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  MULT,
-  /**
-   * Operator for Integer AND
-   * Parameter: 1
-   *   -[1]: Size of the bit-vector that determines the semantics of the IAND
-   * Create with:
-   *   mkOp(Kind kind, uint32_t param).
-   *
-   * Apply integer conversion to bit-vector.
-   * Parameters: 2
-   *   -[1]: Op of kind IAND
-   *   -[2]: Integer term
-   *   -[3]: Integer term
-   * Create with:
-   *   mkTerm(Op op, Term child1, Term child2)
-   *   mkTerm(Op op, const std::vector<Term>& children)
-   */
-  IAND,
-#if 0
-  /* Synonym for MULT.  */
-  NONLINEAR_MULT,
-#endif
-  /**
-   * Arithmetic subtraction, left associative.
-   * Parameters: n
-   *   -[1]..[n]: Terms of sort Integer, Real (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  MINUS,
-  /**
-   * Arithmetic negation.
-   * Parameters: 1
-   *   -[1]: Term of sort Integer, Real
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  UMINUS,
-  /**
-   * Real division, division by 0 undefined, left associative.
-   * Parameters: n > 1
-   *   -[1]..[n]: Terms of sort Integer, Real
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  DIVISION,
-  /**
-   * Integer division, division by 0 undefined, left associative.
-   * Parameters: n > 1
-   *   -[1]..[n]: Terms of sort Integer
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  INTS_DIVISION,
-  /**
-   * Integer modulus, division by 0 undefined.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of sort Integer
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  INTS_MODULUS,
-  /**
-   * Absolute value.
-   * Parameters: 1
-   *   -[1]: Term of sort Integer
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  ABS,
-  /**
-   * Arithmetic power.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of sort Integer, Real
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  POW,
-  /**
-   * Exponential.
-   * Parameters: 1
-   *   -[1]: Term of sort Integer, Real
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  EXPONENTIAL,
-  /**
-   * Sine.
-   * Parameters: 1
-   *   -[1]: Term of sort Integer, Real
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  SINE,
-  /**
-   * Cosine.
-   * Parameters: 1
-   *   -[1]: Term of sort Integer, Real
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  COSINE,
-  /**
-   * Tangent.
-   * Parameters: 1
-   *   -[1]: Term of sort Integer, Real
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  TANGENT,
-  /**
-   * Cosecant.
-   * Parameters: 1
-   *   -[1]: Term of sort Integer, Real
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  COSECANT,
-  /**
-   * Secant.
-   * Parameters: 1
-   *   -[1]: Term of sort Integer, Real
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  SECANT,
-  /**
-   * Cotangent.
-   * Parameters: 1
-   *   -[1]: Term of sort Integer, Real
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  COTANGENT,
-  /**
-   * Arc sine.
-   * Parameters: 1
-   *   -[1]: Term of sort Integer, Real
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  ARCSINE,
-  /**
-   * Arc cosine.
-   * Parameters: 1
-   *   -[1]: Term of sort Integer, Real
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  ARCCOSINE,
-  /**
-   * Arc tangent.
-   * Parameters: 1
-   *   -[1]: Term of sort Integer, Real
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  ARCTANGENT,
-  /**
-   * Arc cosecant.
-   * Parameters: 1
-   *   -[1]: Term of sort Integer, Real
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  ARCCOSECANT,
-  /**
-   * Arc secant.
-   * Parameters: 1
-   *   -[1]: Term of sort Integer, Real
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  ARCSECANT,
-  /**
-   * Arc cotangent.
-   * Parameters: 1
-   *   -[1]: Term of sort Integer, Real
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  ARCCOTANGENT,
-  /**
-   * Square root.
-   * Parameters: 1
-   *   -[1]: Term of sort Integer, Real
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  SQRT,
-  /**
-   * Operator for the divisibility-by-k predicate.
-   * Parameter: 1
-   *   -[1]: The k to divide by (sort Integer)
-   * Create with:
-   *   mkOp(Kind kind, uint32_t param)
-   *
-   * Apply divisibility-by-k predicate.
-   * Parameters: 2
-   *   -[1]: Op of kind DIVISIBLE
-   *   -[2]: Integer Term
-   * Create with:
-   *   mkTerm(Op op, Term child1, Term child2)
-   *   mkTerm(Op op, const std::vector<Term>& children)
-   */
-  DIVISIBLE,
-  /**
-   * Multiple-precision rational constant.
-   * Parameters:
-   *   See mkInteger(), mkReal(), mkRational()
-   * Create with:
-   *   mkInteger(const char* s, uint32_t base = 10)
-   *   mkInteger(const std::string& s, uint32_t base = 10)
-   *   mkInteger(int32_t val)
-   *   mkInteger(uint32_t val)
-   *   mkInteger(int64_t val)
-   *   mkInteger(uint64_t val)
-   *   mkReal(const char* s, uint32_t base = 10)
-   *   mkReal(const std::string& s, uint32_t base = 10)
-   *   mkReal(int32_t val)
-   *   mkReal(int64_t val)
-   *   mkReal(uint32_t val)
-   *   mkReal(uint64_t val)
-   *   mkReal(int32_t num, int32_t den)
-   *   mkReal(int64_t num, int64_t den)
-   *   mkReal(uint32_t num, uint32_t den)
-   *   mkReal(uint64_t num, uint64_t den)
-   */
-  CONST_RATIONAL,
-  /**
-   * Less than, chainable.
-   * Parameters: n
-   *   -[1]..[n]: Terms of sort Integer, Real; [1] < ... < [n]
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  LT,
-  /**
-   * Less than or equal, chainable.
-   * Parameters: n > 1
-   *   -[1]..[n]: Terms of sort Integer, Real; [1] <= ... <= [n]
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  LEQ,
-  /**
-   * Greater than, chainable.
-   * Parameters: n > 1
-   *   -[1]..[n]: Terms of sort Integer, Real, [1] > ... > [n]
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  GT,
-  /**
-   * Greater than or equal, chainable.
-   * Parameters: n > 1
-   *   -[1]..[n]: Terms of sort Integer, Real; [1] >= ... >= [n]
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  GEQ,
-  /**
-   * Is-integer predicate.
-   * Parameters: 1
-   *   -[1]: Term of sort Integer, Real
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  IS_INTEGER,
-  /**
-   * Convert Term to Integer by the floor function.
-   * Parameters: 1
-   *   -[1]: Term of sort Integer, Real
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  TO_INTEGER,
-  /**
-   * Convert Term to Real.
-   * Parameters: 1
-   *   -[1]: Term of sort Integer, Real
-   * This is a no-op in CVC4, as Integer is a subtype of Real.
-   */
-  TO_REAL,
-  /**
-   * Pi constant.
-   * Create with:
-   *   mkPi()
-   *   mkTerm(Kind kind)
-   */
-  PI,
-
-  /* BV -------------------------------------------------------------------- */
-
-  /**
-   * Fixed-size bit-vector constant.
-   * Parameters:
-   *   See mkBitVector().
-   * Create with:
-   *   mkBitVector(uint32_t size, uint64_t val)
-   *   mkBitVector(const char* s, uint32_t base = 2)
-   *   mkBitVector(std::string& s, uint32_t base = 2)
-   */
-  CONST_BITVECTOR,
-  /**
-   * Concatenation of two or more bit-vectors.
-   * Parameters: n > 1
-   *   -[1]..[n]: Terms of bit-vector sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_CONCAT,
-  /**
-   * Bit-wise and.
-   * Parameters: n > 1
-   *   -[1]..[n]: Terms of bit-vector sort (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_AND,
-  /**
-   * Bit-wise or.
-   * Parameters: n > 1
-   *   -[1]..[n]: Terms of bit-vector sort (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_OR,
-  /**
-   * Bit-wise xor.
-   * Parameters: n > 1
-   *   -[1]..[n]: Terms of bit-vector sort (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_XOR,
-  /**
-   * Bit-wise negation.
-   * Parameters: 1
-   *   -[1]: Term of bit-vector sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  BITVECTOR_NOT,
-  /**
-   * Bit-wise nand.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_NAND,
-  /**
-   * Bit-wise nor.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_NOR,
-  /**
-   * Bit-wise xnor, left associative.
-   * Parameters: n > 1
-   *   -[1]..[n]: Terms of bit-vector sort (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_XNOR,
-  /**
-   * Equality comparison (returns bit-vector of size 1).
-   * Parameters: 2
-   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_COMP,
-  /**
-   * Multiplication of two or more bit-vectors.
-   * Parameters: n > 1
-   *   -[1]..[n]: Terms of bit-vector sort (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_MULT,
-  /**
-   * Addition of two or more bit-vectors.
-   * Parameters: n > 1
-   *   -[1]..[n]: Terms of bit-vector sort (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_PLUS,
-  /**
-   * Subtraction of two bit-vectors.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_SUB,
-  /**
-   * Negation of a bit-vector (two's complement).
-   * Parameters: 1
-   *   -[1]: Term of bit-vector sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  BITVECTOR_NEG,
-  /**
-   * Unsigned division of two bit-vectors, truncating towards 0.
-   *
-   * Note: The semantics of this operator depends on `bv-div-zero-const`
-   * (default is true).  Depending on the setting, a division by zero is
-   * treated as all ones (default, corresponds to SMT-LIB >=2.6) or an
-   * uninterpreted value (corresponds to SMT-LIB <2.6).
-   *
-   * Parameters: 2
-   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_UDIV,
-  /**
-   * Unsigned remainder from truncating division of two bit-vectors.
-   *
-   * Note: The semantics of this operator depends on `bv-div-zero-const`
-   * (default is true). Depending on the setting, if the modulus is zero, the
-   * result is either the dividend (default, corresponds to SMT-LIB >=2.6) or
-   * an uninterpreted value (corresponds to SMT-LIB <2.6).
-   *
-   * Parameters: 2
-   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_UREM,
-  /**
-   * Two's complement signed division of two bit-vectors.
-   *
-   * Note: The semantics of this operator depends on `bv-div-zero-const`
-   * (default is true). By default, the function returns all ones if the
-   * dividend is positive and one if the dividend is negative (corresponds to
-   * SMT-LIB >=2.6). If the option is disabled, a division by zero is treated
-   * as an uninterpreted value (corresponds to SMT-LIB <2.6).
-   *
-   * Parameters: 2
-   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_SDIV,
-  /**
-   * Two's complement signed remainder of two bit-vectors
-   * (sign follows dividend).
-   *
-   * Note: The semantics of this operator depends on `bv-div-zero-const`
-   * (default is true, corresponds to SMT-LIB >=2.6). Depending on the setting,
-   * if the modulus is zero, the result is either the dividend (default) or an
-   * uninterpreted value (corresponds to SMT-LIB <2.6).
-   *
-   * Parameters: 2
-   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_SREM,
-  /**
-   * Two's complement signed remainder
-   * (sign follows divisor).
-   *
-   * Note: The semantics of this operator depends on `bv-div-zero-const`
-   * (default is on). Depending on the setting, if the modulus is zero, the
-   * result is either the dividend (default, corresponds to SMT-LIB >=2.6) or
-   * an uninterpreted value (corresponds to SMT-LIB <2.6).
-   *
-   * Parameters: 2
-   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_SMOD,
-  /**
-   * Bit-vector shift left.
-   * The two bit-vector parameters must have same width.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_SHL,
-  /**
-   * Bit-vector logical shift right.
-   * The two bit-vector parameters must have same width.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_LSHR,
-  /**
-   * Bit-vector arithmetic shift right.
-   * The two bit-vector parameters must have same width.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_ASHR,
-  /**
-   * Bit-vector unsigned less than.
-   * The two bit-vector parameters must have same width.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_ULT,
-  /**
-   * Bit-vector unsigned less than or equal.
-   * The two bit-vector parameters must have same width.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_ULE,
-  /**
-   * Bit-vector unsigned greater than.
-   * The two bit-vector parameters must have same width.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_UGT,
-  /**
-   * Bit-vector unsigned greater than or equal.
-   * The two bit-vector parameters must have same width.
-   * Parameters: 2
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_UGE,
-  /* Bit-vector signed less than.
-   * The two bit-vector parameters must have same width.
-   * Parameters: 2
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_SLT,
-  /**
-   * Bit-vector signed less than or equal.
-   * The two bit-vector parameters must have same width.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_SLE,
-  /**
-   * Bit-vector signed greater than.
-   * The two bit-vector parameters must have same width.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_SGT,
-  /**
-   * Bit-vector signed greater than or equal.
-   * The two bit-vector parameters must have same width.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_SGE,
-  /**
-   * Bit-vector unsigned less than, returns bit-vector of size 1.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_ULTBV,
-  /**
-   * Bit-vector signed less than. returns bit-vector of size 1.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of bit-vector sort (sorts must match)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_SLTBV,
-  /**
-   * Same semantics as regular ITE, but condition is bit-vector of size 1.
-   * Parameters: 3
-   *   -[1]: Term of bit-vector sort of size 1, representing the condition
-   *   -[2]: Term reprsenting the 'then' branch
-   *   -[3]: Term representing the 'else' branch
-   * 'then' and 'else' term must have same base sort.
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BITVECTOR_ITE,
-  /**
-   * Bit-vector redor.
-   * Parameters: 1
-   *   -[1]: Term of bit-vector sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  BITVECTOR_REDOR,
-  /**
-   * Bit-vector redand.
-   * Parameters: 1
-   *   -[1]: Term of bit-vector sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  BITVECTOR_REDAND,
-#if 0
-  /* formula to be treated as a bv atom via eager bit-blasting
-   * (internal-only symbol) */
-  BITVECTOR_EAGER_ATOM,
-  /* term to be treated as a variable. used for eager bit-blasting Ackermann
-   * expansion of bvudiv (internal-only symbol) */
-  BITVECTOR_ACKERMANIZE_UDIV,
-  /* term to be treated as a variable. used for eager bit-blasting Ackermann
-   * expansion of bvurem (internal-only symbol) */
-  BITVECTOR_ACKERMANIZE_UREM,
-#endif
-  /**
-   * Operator for bit-vector extract (from index 'high' to 'low').
-   * Parameters: 2
-   *   -[1]: The 'high' index
-   *   -[2]: The 'low' index
-   * Create with:
-   *   mkOp(Kind kind, uint32_t param, uint32_t param)
-   *
-   * Apply bit-vector extract.
-   * Parameters: 2
-   *   -[1]: Op of kind BITVECTOR_EXTRACT
-   *   -[2]: Term of bit-vector sort
-   * Create with:
-   *   mkTerm(Op op, Term child)
-   *   mkTerm(Op op, const std::vector<Term>& children)
-   */
-  BITVECTOR_EXTRACT,
-  /**
-   * Operator for bit-vector repeat.
-   * Parameter 1:
-   *   -[1]: Number of times to repeat a given bit-vector
-   * Create with:
-   *   mkOp(Kind kind, uint32_t param).
-   *
-   * Apply bit-vector repeat.
-   * Parameters: 2
-   *   -[1]: Op of kind BITVECTOR_REPEAT
-   *   -[2]: Term of bit-vector sort
-   * Create with:
-   *   mkTerm(Op op, Term child)
-   *   mkTerm(Op op, const std::vector<Term>& children)
-   */
-  BITVECTOR_REPEAT,
-  /**
-   * Operator for bit-vector zero-extend.
-   * Parameter 1:
-   *   -[1]: Number of bits by which a given bit-vector is to be extended
-   * Create with:
-   *   mkOp(Kind kind, uint32_t param).
-   *
-   * Apply bit-vector zero-extend.
-   * Parameters: 2
-   *   -[1]: Op of kind BITVECTOR_ZERO_EXTEND
-   *   -[2]: Term of bit-vector sort
-   * Create with:
-   *   mkTerm(Op op, Term child)
-   *   mkTerm(Op op, const std::vector<Term>& children)
-   */
-  BITVECTOR_ZERO_EXTEND,
-  /**
-   * Operator for bit-vector sign-extend.
-   * Parameter 1:
-   *   -[1]: Number of bits by which a given bit-vector is to be extended
-   * Create with:
-   *   mkOp(Kind kind, uint32_t param).
-   *
-   * Apply bit-vector sign-extend.
-   * Parameters: 2
-   *   -[1]: Op of kind BITVECTOR_SIGN_EXTEND
-   *   -[2]: Term of bit-vector sort
-   * Create with:
-   *   mkTerm(Op op, Term child)
-   *   mkTerm(Op op, const std::vector<Term>& children)
-   */
-  BITVECTOR_SIGN_EXTEND,
-  /**
-   * Operator for bit-vector rotate left.
-   * Parameter 1:
-   *   -[1]: Number of bits by which a given bit-vector is to be rotated
-   * Create with:
-   *   mkOp(Kind kind, uint32_t param).
-   *
-   * Apply bit-vector rotate left.
-   * Parameters: 2
-   *   -[1]: Op of kind BITVECTOR_ROTATE_LEFT
-   *   -[2]: Term of bit-vector sort
-   * Create with:
-   *   mkTerm(Op op, Term child)
-   *   mkTerm(Op op, const std::vector<Term>& children)
-   */
-  BITVECTOR_ROTATE_LEFT,
-  /**
-   * Operator for bit-vector rotate right.
-   * Parameter 1:
-   *   -[1]: Number of bits by which a given bit-vector is to be rotated
-   * Create with:
-   *   mkOp(Kind kind, uint32_t param).
-   *
-   * Apply bit-vector rotate right.
-   * Parameters: 2
-   *   -[1]: Op of kind BITVECTOR_ROTATE_RIGHT
-   *   -[2]: Term of bit-vector sort
-   * Create with:
-   *   mkTerm(Op op, Term child)
-   *   mkTerm(Op op, const std::vector<Term>& children)
-   */
-  BITVECTOR_ROTATE_RIGHT,
-#if 0
-  /* bit-vector boolean bit extract. */
-  BITVECTOR_BITOF,
-#endif
-  /**
-   * Operator for the conversion from Integer to bit-vector.
-   * Parameter: 1
-   *   -[1]: Size of the bit-vector to convert to
-   * Create with:
-   *   mkOp(Kind kind, uint32_t param).
-   *
-   * Apply integer conversion to bit-vector.
-   * Parameters: 2
-   *   -[1]: Op of kind INT_TO_BITVECTOR
-   *   -[2]: Integer term
-   * Create with:
-   *   mkTerm(Op op, Term child)
-   *   mkTerm(Op op, const std::vector<Term>& children)
-   */
-  INT_TO_BITVECTOR,
-  /**
-   * Bit-vector conversion to (nonnegative) integer.
-   * Parameter: 1
-   *   -[1]: Term of bit-vector sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  BITVECTOR_TO_NAT,
-
-  /* FP -------------------------------------------------------------------- */
-
-  /**
-   * Floating-point constant, constructed from a double or string.
-   * Parameters: 3
-   *   -[1]: Size of the exponent
-   *   -[2]: Size of the significand
-   *   -[3]: Value of the floating-point constant as a bit-vector term
-   * Create with:
-   *   mkFloatingPoint(uint32_t sig, uint32_t exp, Term val)
-   */
-  CONST_FLOATINGPOINT,
-  /**
-   * Floating-point rounding mode term.
-   * Create with:
-   *   mkRoundingMode(RoundingMode rm)
-   */
-  CONST_ROUNDINGMODE,
-  /**
-   * Create floating-point literal from bit-vector triple.
-   * Parameters: 3
-   *   -[1]: Sign bit as a bit-vector term
-   *   -[2]: Exponent bits as a bit-vector term
-   *   -[3]: Significand bits as a bit-vector term (without hidden bit)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  FLOATINGPOINT_FP,
-  /**
-   * Floating-point equality.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of floating point sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  FLOATINGPOINT_EQ,
-  /**
-   * Floating-point absolute value.
-   * Parameters: 1
-   *   -[1]: Term of floating point sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  FLOATINGPOINT_ABS,
-  /**
-   * Floating-point negation.
-   * Parameters: 1
-   *   -[1]: Term of floating point sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  FLOATINGPOINT_NEG,
-  /**
-   * Floating-point addition.
-   * Parameters: 3
-   *   -[1]: CONST_ROUNDINGMODE
-   *   -[2]: Term of sort FloatingPoint
-   *   -[3]: Term of sort FloatingPoint
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2, child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  FLOATINGPOINT_PLUS,
-  /**
-   * Floating-point sutraction.
-   * Parameters: 3
-   *   -[1]: CONST_ROUNDINGMODE
-   *   -[2]: Term of sort FloatingPoint
-   *   -[3]: Term of sort FloatingPoint
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  FLOATINGPOINT_SUB,
-  /**
-   * Floating-point multiply.
-   * Parameters: 3
-   *   -[1]: CONST_ROUNDINGMODE
-   *   -[2]: Term of sort FloatingPoint
-   *   -[3]: Term of sort FloatingPoint
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  FLOATINGPOINT_MULT,
-  /**
-   * Floating-point division.
-   * Parameters: 3
-   *   -[1]: CONST_ROUNDINGMODE
-   *   -[2]: Term of sort FloatingPoint
-   *   -[3]: Term of sort FloatingPoint
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  FLOATINGPOINT_DIV,
-  /**
-   * Floating-point fused multiply and add.
-   * Parameters: 4
-   *   -[1]: CONST_ROUNDINGMODE
-   *   -[2]: Term of sort FloatingPoint
-   *   -[3]: Term of sort FloatingPoint
-   *   -[4]: Term of sort FloatingPoint
-   * Create with:
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  FLOATINGPOINT_FMA,
-  /**
-   * Floating-point square root.
-   * Parameters: 2
-   *   -[1]: CONST_ROUNDINGMODE
-   *   -[2]: Term of sort FloatingPoint
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  FLOATINGPOINT_SQRT,
-  /**
-   * Floating-point remainder.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of floating point sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  FLOATINGPOINT_REM,
-  /**
-   * Floating-point round to integral.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of floating point sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  FLOATINGPOINT_RTI,
-  /**
-   * Floating-point minimum.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of floating point sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  FLOATINGPOINT_MIN,
-  /**
-   * Floating-point maximum.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of floating point sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  FLOATINGPOINT_MAX,
-  /**
-   * Floating-point less than or equal.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of floating point sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  FLOATINGPOINT_LEQ,
-  /**
-   * Floating-point less than.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of floating point sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  FLOATINGPOINT_LT,
-  /**
-   * Floating-point greater than or equal.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of floating point sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  FLOATINGPOINT_GEQ,
-  /**
-   * Floating-point greater than.
-   * Parameters: 2
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  FLOATINGPOINT_GT,
-  /**
-   * Floating-point is normal.
-   * Parameters: 1
-   *   -[1]: Term of floating point sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  FLOATINGPOINT_ISN,
-  /**
-   * Floating-point is sub-normal.
-   * Parameters: 1
-   *   -[1]: Term of floating point sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  FLOATINGPOINT_ISSN,
-  /**
-   * Floating-point is zero.
-   * Parameters: 1
-   *   -[1]: Term of floating point sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  FLOATINGPOINT_ISZ,
-  /**
-   * Floating-point is infinite.
-   * Parameters: 1
-   *   -[1]: Term of floating point sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  FLOATINGPOINT_ISINF,
-  /**
-   * Floating-point is NaN.
-   * Parameters: 1
-   *   -[1]: Term of floating point sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  FLOATINGPOINT_ISNAN,
-  /**
-   * Floating-point is negative.
-   * Parameters: 1
-   *   -[1]: Term of floating point sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  FLOATINGPOINT_ISNEG,
-  /**
-   * Floating-point is positive.
-   * Parameters: 1
-   *   -[1]: Term of floating point sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  FLOATINGPOINT_ISPOS,
-  /**
-   * Operator for to_fp from bit vector.
-   * Parameters: 2
-   *   -[1]: Exponent size
-   *   -[2]: Significand size
-   * Create with:
-   *   mkOp(Kind kind, uint32_t param1, uint32_t param2)
-   *
-   * Conversion from an IEEE-754 bit vector to floating-point.
-   * Parameters: 2
-   *   -[1]: Op of kind FLOATINGPOINT_TO_FP_IEEE_BITVECTOR
-   *   -[2]: Term of sort FloatingPoint
-   * Create with:
-   *   mkTerm(Op op, Term child)
-   *   mkTerm(Op op, const std::vector<Term>& children)
-   */
-  FLOATINGPOINT_TO_FP_IEEE_BITVECTOR,
-  /**
-   * Operator for to_fp from floating point.
-   * Parameters: 2
-   *   -[1]: Exponent size
-   *   -[2]: Significand size
-   * Create with:
-   *   mkOp(Kind kind, uint32_t param1, uint32_t param2)
-   *
-   * Conversion between floating-point sorts.
-   * Parameters: 2
-   *   -[1]: Op of kind FLOATINGPOINT_TO_FP_FLOATINGPOINT
-   *   -[2]: Term of sort FloatingPoint
-   * Create with:
-   *   mkTerm(Op op, Term child)
-   *   mkTerm(Op op, const std::vector<Term>& children)
-   */
-  FLOATINGPOINT_TO_FP_FLOATINGPOINT,
-  /**
-   * Operator for to_fp from real.
-   * Parameters: 2
-   *   -[1]: Exponent size
-   *   -[2]: Significand size
-   * Create with:
-   *   mkOp(Kind kind, uint32_t param1, uint32_t param2)
-   *
-   * Conversion from a real to floating-point.
-   * Parameters: 2
-   *   -[1]: Op of kind FLOATINGPOINT_TO_FP_REAL
-   *   -[2]: Term of sort FloatingPoint
-   * Create with:
-   *   mkTerm(Op op, Term child)
-   *   mkTerm(Op op, const std::vector<Term>& children)
-   */
-  FLOATINGPOINT_TO_FP_REAL,
-  /*
-   * Operator for to_fp from signed bit vector.
-   * Parameters: 2
-   *   -[1]: Exponent size
-   *   -[2]: Significand size
-   * Create with:
-   *   mkOp(Kind kind, uint32_t param1, uint32_t param2)
-   *
-   * Conversion from a signed bit vector to floating-point.
-   * Parameters: 2
-   *   -[1]: Op of kind FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR
-   *   -[2]: Term of sort FloatingPoint
-   * Create with:
-   *   mkTerm(Op op, Term child)
-   *   mkTerm(Op op, const std::vector<Term>& children)
-   */
-  FLOATINGPOINT_TO_FP_SIGNED_BITVECTOR,
-  /**
-   * Operator for to_fp from unsigned bit vector.
-   * Parameters: 2
-   *   -[1]: Exponent size
-   *   -[2]: Significand size
-   * Create with:
-   *   mkOp(Kind kind, uint32_t param1, uint32_t param2)
-   *
-   * Converting an unsigned bit vector to floating-point.
-   * Parameters: 2
-   *   -[1]: Op of kind FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR
-   *   -[2]: Term of sort FloatingPoint
-   * Create with:
-   *   mkTerm(Op op, Term child)
-   *   mkTerm(Op op, const std::vector<Term>& children)
-   */
-  FLOATINGPOINT_TO_FP_UNSIGNED_BITVECTOR,
-  /**
-   * Operator for a generic to_fp.
-   * Parameters: 2
-   *   -[1]: exponent size
-   *   -[2]: Significand size
-   * Create with:
-   *   mkOp(Kind kind, uint32_t param1, uint32_t param2)
-   *
-   * Generic conversion to floating-point, used in parsing only.
-   * Parameters: 2
-   *   -[1]: Op of kind FLOATINGPOINT_TO_FP_GENERIC
-   *   -[2]: Term of sort FloatingPoint
-   * Create with:
-   *   mkTerm(Op op, Term child)
-   *   mkTerm(Op op, const std::vector<Term>& children)
-   */
-  FLOATINGPOINT_TO_FP_GENERIC,
-  /**
-   * Operator for to_ubv.
-   * Parameters: 1
-   *   -[1]: Size of the bit-vector to convert to
-   * Create with:
-   *   mkOp(Kind kind, uint32_t param)
-   *
-   * Conversion from a floating-point value to an unsigned bit vector.
-   * Parameters: 2
-   *   -[1]: Op of kind FLOATINGPOINT_TO_FP_TO_UBV
-   *   -[2]: Term of sort FloatingPoint
-   * Create with:
-   *   mkTerm(Op op, Term child)
-   *   mkTerm(Op op, const std::vector<Term>& children)
-   */
-  FLOATINGPOINT_TO_UBV,
-  /**
-   * Operator for to_sbv.
-   * Parameters: 1
-   *   -[1]: Size of the bit-vector to convert to
-   * Create with:
-   *   mkOp(Kind kind, uint32_t param)
-   *
-   * Conversion from a floating-point value to a signed bit vector.
-   * Parameters: 2
-   *   -[1]: Op of kind FLOATINGPOINT_TO_FP_TO_SBV
-   *   -[2]: Term of sort FloatingPoint
-   * Create with:
-   *   mkTerm(Op op, Term child)
-   *   mkTerm(Op op, const std::vector<Term>& children)
-   */
-  FLOATINGPOINT_TO_SBV,
-  /**
-   * Floating-point to real.
-   * Parameters: 1
-   *   -[1]: Term of sort FloatingPoint
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  FLOATINGPOINT_TO_REAL,
-
-  /* Arrays ---------------------------------------------------------------- */
-
-  /**
-   * Aarray select.
-   * Parameters: 2
-   *   -[1]: Term of array sort
-   *   -[2]: Selection index
-   * Create with:
-   *   mkTerm(Op op, Term child1, Term child2)
-   *   mkTerm(Op op, const std::vector<Term>& children)
-   */
-  SELECT,
-  /**
-   * Array store.
-   * Parameters: 3
-   *   -[1]: Term of array sort
-   *   -[2]: Store index
-   *   -[3]: Term to store at the index
-   * Create with:
-   *   mkTerm(Op op, Term child1, Term child2, Term child3)
-   *   mkTerm(Op op, const std::vector<Term>& children)
-   */
-  STORE,
-  /**
-   * Constant array.
-   * Parameters: 2
-   *   -[1]: Array sort
-   *   -[2]: Term representing a constant
-   * Create with:
-   *   mkTerm(Op op, Term child1, Term child2)
-   *   mkTerm(Op op, const std::vector<Term>& children)
-   *
-   * Note: We currently support the creation of constant arrays, but under some
-   * conditions when there is a chain of equalities connecting two constant
-   * arrays, the solver doesn't know what to do and aborts (Issue #1667).
-   */
-  CONST_ARRAY,
-  /**
-   * Equality over arrays a and b over a given range [i,j], i.e.,
-   * \forall k . i <= k <= j --> a[k] = b[k]
-   *
-   * Parameters: 4
-   *   -[1]: First array
-   *   -[2]: Second array
-   *   -[3]: Lower bound of range (inclusive)
-   *   -[4]: Uppper bound of range (inclusive)
-   * Create with:
-   *   mkTerm(Op op, const std::vector<Term>& children)
-   *
-   * Note: We currently support the creation of array equalities over index
-   * types bit-vector, floating-point, integer and real. Option --arrays-exp is
-   * required to support this operator.
-   */
-  EQ_RANGE,
-#if 0
-  /* array table function (internal-only symbol) */
-  ARR_TABLE_FUN,
-  /* array lambda (internal-only symbol) */
-  ARRAY_LAMBDA,
-  /* partial array select, for internal use only */
-  PARTIAL_SELECT_0,
-  /* partial array select, for internal use only */
-  PARTIAL_SELECT_1,
-#endif
-
-  /* Datatypes ------------------------------------------------------------- */
-
-  /**
-   * Constructor application.
-   * Paramters: n > 0
-   *   -[1]: Constructor (operator)
-   *   -[2]..[n]: Parameters to the constructor
-   * Create with:
-   *   mkTerm(Kind kind, Op op)
-   *   mkTerm(Kind kind, Op op, Term child)
-   *   mkTerm(Kind kind, Op op, Term child1, Term child2)
-   *   mkTerm(Kind kind, Op op, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, Op op, const std::vector<Term>& children)
-   */
-  APPLY_CONSTRUCTOR,
-  /**
-   * Datatype selector application.
-   * Parameters: 1
-   *   -[1]: Selector (operator)
-   *   -[2]: Datatype term (undefined if mis-applied)
-   * Create with:
-   *   mkTerm(Kind kind, Op op, Term child)
-   */
-  APPLY_SELECTOR,
-  /**
-   * Datatype tester application.
-   * Parameters: 2
-   *   -[1]: Tester term
-   *   -[2]: Datatype term
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  APPLY_TESTER,
-#if 0
-  /* Parametric datatype term.  */
-  PARAMETRIC_DATATYPE,
-  /* type ascription, for datatype constructor applications;
-   * first parameter is an ASCRIPTION_TYPE, second is the datatype constructor
-   * application being ascribed */
-  APPLY_TYPE_ASCRIPTION,
-#endif
-  /**
-   * Operator for a tuple update.
-   * Parameters: 1
-   *   -[1]: Index of the tuple to be updated
-   * Create with:
-   *   mkOp(Kind kind, uint32_t param)
-   *
-   * Apply tuple update.
-   * Parameters: 3
-   *   -[1]: Op of kind TUPLE_UPDATE (which references an index)
-   *   -[2]: Tuple
-   *   -[3]: Element to store in the tuple at the given index
-   * Create with:
-   *   mkTerm(Op op, Term child1, Term child2)
-   *   mkTerm(Op op, const std::vector<Term>& children)
-   */
-  TUPLE_UPDATE,
-  /**
-   * Operator for a record update.
-   * Parameters: 1
-   *   -[1]: Name of the field to be updated
-   * Create with:
-   *   mkOp(Kind kind, const std::string& param)
-   *
-   * Record update.
-   * Parameters: 3
-   *   -[1]: Op of kind RECORD_UPDATE (which references a field)
-   *   -[2]: Record term to update
-   *   -[3]: Element to store in the record in the given field
-   * Create with:
-   *   mkTerm(Op op, Term child1, Term child2)
-   *   mkTerm(Op op,, const std::vector<Term>& children)
-   */
-  RECORD_UPDATE,
-  /* Match expressions.
-   * For example, the smt2 syntax match term
-   *   (match l (((cons h t) h) (nil 0)))
-   * is represented by the AST
-   * (MATCH l
-   *   (MATCH_BIND_CASE (BOUND_VAR_LIST h t) (cons h t) h)
-   *   (MATCH_CASE nil 0))
-   * The type of the last argument of each case term could be equal.
-   * Parameters: n > 1
-   *   -[1]..[n]: Terms of kind MATCH_CASE or MATCH_BIND_CASE
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   *
-   */
-  MATCH,
-  /* Match case
-   * A (constant) case expression to be used within a match expression.
-   * Parameters: 2
-   *   -[1] Term denoting the pattern expression
-   *   -[2] Term denoting the return value
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  MATCH_CASE,
-  /* Match bind case
-   * A (non-constant) case expression to be used within a match expression.
-   * Parameters: 3
-   *   -[1] a BOUND_VAR_LIST Term containing the free variables of the case
-   *   -[2] Term denoting the pattern expression
-   *   -[3] Term denoting the return value
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  MATCH_BIND_CASE,
-  /*
-   * Datatypes size
-   * An operator mapping datatypes to an integer denoting the number of
-   * non-nullary applications of constructors they contain.
-   * Parameters: 1
-   *   -[1]: Datatype term
-   * Create with:
-   *   mkTerm(Kind kind, Term child1)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  DT_SIZE,
-  /**
-   * Operator for tuple projection indices
-   * Parameters: 1
-   *   -[1]: The tuple projection indices
-   * Create with:
-   *   mkOp(Kind TUPLE_PROJECT, std::vector<uint32_t> param)
-   *
-   * constructs a new tuple from an existing one using the elements at the
-   * given indices
-   * Parameters: 1
-   *   -[1]: a term of tuple sort
-   * Create with:
-   *   mkTerm(Op op, Term child)
-   *   mkTerm(Op op, const std::vector<Term>& children)
-   */
-  TUPLE_PROJECT,
-#if 0
-  /* datatypes height bound */
-  DT_HEIGHT_BOUND,
-  /* datatypes height bound */
-  DT_SIZE_BOUND,
-  /* datatypes sygus bound */
-  DT_SYGUS_BOUND,
-  /* datatypes sygus term order */
-  DT_SYGUS_TERM_ORDER,
-  /* datatypes sygus is constant */
-  DT_SYGUS_IS_CONST,
-#endif
-
-  /* Separation Logic ------------------------------------------------------ */
-
-  /**
-   * Separation logic nil term.
-   * Parameters: 0
-   * Create with:
-   *   mkSepNil(Sort sort)
-   */
-  SEP_NIL,
-  /**
-   * Separation logic empty heap.
-   * Parameters: 2
-   *   -[1]: Term of the same sort as the sort of the location of the heap
-   *         that is constrained to be empty
-   *   -[2]: Term of the same sort as the data sort of the heap that is
-   *         that is constrained to be empty
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  SEP_EMP,
-  /**
-   * Separation logic points-to relation.
-   * Parameters: 2
-   *   -[1]: Location of the points-to constraint
-   *   -[2]: Data of the points-to constraint
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  SEP_PTO,
-  /**
-   * Separation logic star.
-   * Parameters: n >= 2
-   *   -[1]..[n]: Child constraints that hold in disjoint (separated) heaps
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  SEP_STAR,
-  /**
-   * Separation logic magic wand.
-   * Parameters: 2
-   *   -[1]: Antecendant of the magic wand constraint
-   *   -[2]: Conclusion of the magic wand constraint, which is asserted to
-   *         hold in all heaps that are disjoint extensions of the antecedent.
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  SEP_WAND,
-#if 0
-  /* separation label (internal use only) */
-  SEP_LABEL,
-#endif
-
-  /* Sets ------------------------------------------------------------------ */
-
-  /**
-   * Empty set constant.
-   * Parameters: 1
-   *   -[1]: Sort of the set elements
-   * Create with:
-   *   mkEmptySet(Sort sort)
-   */
-  EMPTYSET,
-  /**
-   * Set union.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of set sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  UNION,
-  /**
-   * Set intersection.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of set sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  INTERSECTION,
-  /**
-   * Set subtraction.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of set sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  SETMINUS,
-  /**
-   * Subset predicate.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of set sort, [1] a subset of set [2]?
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  SUBSET,
-  /**
-   * Set membership predicate.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of set sort, [1] a member of set [2]?
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  MEMBER,
-  /**
-   * Construct a singleton set from an element given as a parameter.
-   * The returned set has same type of the element.
-   * Parameters: 1
-   *   -[1]: Single element
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  SINGLETON,
-  /**
-   * The set obtained by inserting elements;
-   * Parameters: n > 0
-   *   -[1]..[n-1]: Elements inserted into set [n]
-   *   -[n]: Set Term
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  INSERT,
-  /**
-   * Set cardinality.
-   * Parameters: 1
-   *   -[1]: Set to determine the cardinality of
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  CARD,
-  /**
-   * Set complement with respect to finite universe.
-   * Parameters: 1
-   *   -[1]: Set to complement
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  COMPLEMENT,
-  /**
-   * Finite universe set.
-   * All set variables must be interpreted as subsets of it.
-   * Create with:
-   *   mkUniverseSet(Sort sort)
-   */
-  UNIVERSE_SET,
-  /**
-   * Set join.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of set sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  JOIN,
-  /**
-   * Set cartesian product.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of set sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  PRODUCT,
-  /**
-   * Set transpose.
-   * Parameters: 1
-   *   -[1]: Term of set sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  TRANSPOSE,
-  /**
-   * Set transitive closure.
-   * Parameters: 1
-   *   -[1]: Term of set sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  TCLOSURE,
-  /**
-   * Set join image.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of set sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  JOIN_IMAGE,
-  /**
-   * Set identity.
-   * Parameters: 1
-   *   -[1]: Term of set sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  IDEN,
-  /**
-   * Set comprehension
-   * A set comprehension is specified by a bound variable list x1 ... xn,
-   * a predicate P[x1...xn], and a term t[x1...xn]. A comprehension C with the
-   * above form has members given by the following semantics:
-   * forall y. ( exists x1...xn. P[x1...xn] ^ t[x1...xn] = y ) <=> (member y C)
-   * where y ranges over the element type of the (set) type of the
-   * comprehension. If t[x1..xn] is not provided, it is equivalent to y in the
-   * above formula.
-   * Parameters: 2 (3)
-   *   -[1]: Term BOUND_VAR_LIST
-   *   -[2]: Term denoting the predicate of the comprehension
-   *   -[3]: (optional) a Term denoting the generator for the comprehension
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  COMPREHENSION,
-  /**
-   * Returns an element from a given set.
-   * If a set A = {x}, then the term (choose A) is equivalent to the term x.
-   * If the set is empty, then (choose A) is an arbitrary value.
-   * If the set has cardinality > 1, then (choose A) will deterministically
-   * return an element in A.
-   * Parameters: 1
-   *   -[1]: Term of set sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  CHOOSE,
-  /**
-   * Set is_singleton predicate.
-   * Parameters: 1
-   *   -[1]: Term of set sort, is [1] a singleton set?
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  IS_SINGLETON,
-  /* Bags ------------------------------------------------------------------ */
-  /**
-   * Empty bag constant.
-   * Parameters: 1
-   *   -[1]: Sort of the bag elements
-   * Create with:
-   *   mkEmptyBag(Sort sort)
-   */
-  EMPTYBAG,
-  /**
-   * Bag max union.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of bag sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  UNION_MAX,
-  /**
-   * Bag disjoint union (sum).
-   * Parameters: 2
-   *   -[1]..[2]: Terms of bag sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  UNION_DISJOINT,
-  /**
-   * Bag intersection (min).
-   * Parameters: 2
-   *   -[1]..[2]: Terms of bag sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  INTERSECTION_MIN,
-  /**
-   * Bag difference subtract (subtracts multiplicities of the second from the
-   * first).
-   * Parameters: 2
-   *   -[1]..[2]: Terms of bag sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  DIFFERENCE_SUBTRACT,
-  /**
-   * Bag difference 2 (removes shared elements in the two bags).
-   * Parameters: 2
-   *   -[1]..[2]: Terms of bag sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  DIFFERENCE_REMOVE,
-  /**
-   * Inclusion predicate for bags
-   * (multiplicities of the first bag <= multiplicities of the second bag).
-   * Parameters: 2
-   *   -[1]..[2]: Terms of bag sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  SUBBAG,
-  /**
-   * Element multiplicity in a bag
-   * Parameters: 2
-   *   -[1]..[2]: Terms of bag sort (Bag E), [1] an element of sort E
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BAG_COUNT,
-  /**
-   * Eliminate duplicates in a given bag. The returned bag contains exactly the
-   * same elements in the given bag, but with multiplicity one.
-   * Parameters: 1
-   *   -[1]: a term of bag sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  DUPLICATE_REMOVAL,
-  /**
-   * The bag of the single element given as a parameter.
-   * Parameters: 1
-   *   -[1]: Single element
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  MK_BAG,
-  /**
-   * Bag cardinality.
-   * Parameters: 1
-   *   -[1]: Bag to determine the cardinality of
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  BAG_CARD,
-  /**
-   * Returns an element from a given bag.
-   * If a bag A = {(x,n)} where n is the multiplicity, then the term (choose A)
-   * is equivalent to the term x.
-   * If the bag is empty, then (choose A) is an arbitrary value.
-   * If the bag contains distinct elements, then (choose A) will
-   * deterministically return an element in A.
-   * Parameters: 1
-   *   -[1]: Term of bag sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  BAG_CHOOSE,
-  /**
-   * Bag is_singleton predicate (single element with multiplicity exactly one).
-   * Parameters: 1
-   *   -[1]: Term of bag sort, is [1] a singleton bag?
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  BAG_IS_SINGLETON,
-  /**
-   * Bag.from_set converts a set to a bag.
-   * Parameters: 1
-   *   -[1]: Term of set sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  BAG_FROM_SET,
-  /**
-   * Bag.to_set converts a bag to a set.
-   * Parameters: 1
-   *   -[1]: Term of bag sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  BAG_TO_SET,
-
-  /* Strings --------------------------------------------------------------- */
-
-  /**
-   * String concat.
-   * Parameters: n > 1
-   *   -[1]..[n]: Terms of String sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  STRING_CONCAT,
-  /**
-   * String membership.
-   * Parameters: 2
-   *   -[1]: Term of String sort
-   *   -[2]: Term of RegExp sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  STRING_IN_REGEXP,
-  /**
-   * String length.
-   * Parameters: 1
-   *   -[1]: Term of String sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  STRING_LENGTH,
-  /**
-   * String substring.
-   * Extracts a substring, starting at index i and of length l, from a string
-   * s.  If the start index is negative, the start index is greater than the
-   * length of the string, or the length is negative, the result is the empty
-   * string.
-   * Parameters: 3
-   *   -[1]: Term of sort String
-   *   -[2]: Term of sort Integer (index i)
-   *   -[3]: Term of sort Integer (length l)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  STRING_SUBSTR,
-  /**
-   * String update.
-   * Updates a string s by replacing its context starting at an index with t.
-   * If the start index is negative, the start index is greater than the
-   * length of the string, the result is s. Otherwise, the length of the
-   * original string is preserved.
-   * Parameters: 3
-   *   -[1]: Term of sort String
-   *   -[2]: Term of sort Integer (index i)
-   *   -[3]: Term of sort String (replacement string t)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  STRING_UPDATE,
-  /**
-   * String character at.
-   * Returns the character at index i from a string s. If the index is negative
-   * or the index is greater than the length of the string, the result is the
-   * empty string. Otherwise the result is a string of length 1.
-   * Parameters: 2
-   *   -[1]: Term of sort String (string s)
-   *   -[2]: Term of sort Integer (index i)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  STRING_CHARAT,
-  /**
-   * String contains.
-   * Checks whether a string s1 contains another string s2. If s2 is empty, the
-   * result is always true.
-   * Parameters: 2
-   *   -[1]: Term of sort String (the string s1)
-   *   -[2]: Term of sort String (the string s2)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  STRING_CONTAINS,
-  /**
-   * String index-of.
-   * Returns the index of a substring s2 in a string s1 starting at index i. If
-   * the index is negative or greater than the length of string s1 or the
-   * substring s2 does not appear in string s1 after index i, the result is -1.
-   * Parameters: 3
-   *   -[1]: Term of sort String (substring s1)
-   *   -[2]: Term of sort String (substring s2)
-   *   -[3]: Term of sort Integer (index i)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  STRING_INDEXOF,
-  /**
-   * String replace.
-   * Replaces a string s2 in a string s1 with string s3. If s2 does not appear
-   * in s1, s1 is returned unmodified.
-   * Parameters: 3
-   *   -[1]: Term of sort String (string s1)
-   *   -[2]: Term of sort String (string s2)
-   *   -[3]: Term of sort String (string s3)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  STRING_REPLACE,
-  /**
-   * String replace all.
-   * Replaces all occurrences of a string s2 in a string s1 with string s3.
-   * If s2 does not appear in s1, s1 is returned unmodified.
-   * Parameters: 3
-   *   -[1]: Term of sort String (string s1)
-   *   -[2]: Term of sort String (string s2)
-   *   -[3]: Term of sort String (string s3)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  STRING_REPLACE_ALL,
-  /**
-   * String replace regular expression match.
-   * Replaces the first match of a regular expression r in string s1 with
-   * string s2. If r does not match a substring of s1, s1 is returned
-   * unmodified.
-   * Parameters: 3
-   *   -[1]: Term of sort String (string s1)
-   *   -[2]: Term of sort Regexp (regexp r)
-   *   -[3]: Term of sort String (string s2)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  STRING_REPLACE_RE,
-  /**
-   * String replace all regular expression matches.
-   * Replaces all matches of a regular expression r in string s1 with string
-   * s2. If r does not match a substring of s1, s1 is returned unmodified.
-   * Parameters: 3
-   *   -[1]: Term of sort String (string s1)
-   *   -[2]: Term of sort Regexp (regexp r)
-   *   -[3]: Term of sort String (string s2)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  STRING_REPLACE_RE_ALL,
-  /**
-   * String to lower case.
-   * Parameters: 1
-   *   -[1]: Term of String sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  STRING_TOLOWER,
-  /**
-   * String to upper case.
-   * Parameters: 1
-   *   -[1]: Term of String sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  STRING_TOUPPER,
-  /**
-   * String reverse.
-   * Parameters: 1
-   *   -[1]: Term of String sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  STRING_REV,
-  /**
-   * String to code.
-   * Returns the code point of a string if it has length one, or returns -1
-   * otherwise.
-   * Parameters: 1
-   *   -[1]: Term of String sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  STRING_TO_CODE,
-  /**
-   * String from code.
-   * Returns a string containing a single character whose code point matches
-   * the argument to this function, or the empty string if the argument is
-   * out-of-bounds.
-   * Parameters: 1
-   *   -[1]: Term of Integer sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  STRING_FROM_CODE,
-  /**
-   * String less than.
-   * Returns true if string s1 is (strictly) less than s2 based on a
-   * lexiographic ordering over code points.
-   * Parameters: 2
-   *   -[1]: Term of sort String (the string s1)
-   *   -[2]: Term of sort String (the string s2)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  STRING_LT,
-  /**
-   * String less than or equal.
-   * Returns true if string s1 is less than or equal to s2 based on a
-   * lexiographic ordering over code points.
-   * Parameters: 2
-   *   -[1]: Term of sort String (the string s1)
-   *   -[2]: Term of sort String (the string s2)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  STRING_LEQ,
-  /**
-   * String prefix-of.
-   * Checks whether a string s1 is a prefix of string s2. If string s1 is
-   * empty, this operator returns true.
-   * Parameters: 2
-   *   -[1]: Term of sort String (string s1)
-   *   -[2]: Term of sort String (string s2)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  STRING_PREFIX,
-  /**
-   * String suffix-of.
-   * Checks whether a string s1 is a suffix of string 2. If string s1 is empty,
-   * this operator returns true.
-   * Parameters: 2
-   *   -[1]: Term of sort String (string s1)
-   *   -[2]: Term of sort String (string s2)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  STRING_SUFFIX,
-  /**
-   * String is-digit.
-   * Returns true if string s is digit (it is one of "0", ..., "9").
-   * Parameters: 1
-   *   -[1]: Term of sort String
-   * Create with:
-   *   mkTerm(Kind kind, Term child1)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  STRING_IS_DIGIT,
-  /**
-   * Integer to string.
-   * If the integer is negative this operator returns the empty string.
-   * Parameters: 1
-   *   -[1]: Term of sort Integer
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  STRING_FROM_INT,
-  /**
-   * String to integer (total function).
-   * If the string does not contain an integer or the integer is negative, the
-   * operator returns -1.
-   * Parameters: 1
-   *   -[1]: Term of sort String
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  STRING_TO_INT,
-  /**
-   * Constant string.
-   * Parameters:
-   *   See mkString()
-   * Create with:
-   *   mkString(const char* s)
-   *   mkString(const std::string& s)
-   *   mkString(const unsigned char c)
-   *   mkString(const std::vector<unsigned>& s)
-   */
-  CONST_STRING,
-  /**
-   * Conversion from string to regexp.
-   * Parameters: 1
-   *   -[1]: Term of sort String
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  STRING_TO_REGEXP,
-  /**
-   * Regexp Concatenation .
-   * Parameters: 2
-   *   -[1]..[2]: Terms of Regexp sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  REGEXP_CONCAT,
-  /**
-   * Regexp union.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of Regexp sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  REGEXP_UNION,
-  /**
-   * Regexp intersection.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of Regexp sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  REGEXP_INTER,
-  /**
-   * Regexp difference.
-   * Parameters: 2
-   *   -[1]..[2]: Terms of Regexp sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  REGEXP_DIFF,
-  /**
-   * Regexp *.
-   * Parameters: 1
-   *   -[1]: Term of sort Regexp
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  REGEXP_STAR,
-  /**
-   * Regexp +.
-   * Parameters: 1
-   *   -[1]: Term of sort Regexp
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  REGEXP_PLUS,
-  /**
-   * Regexp ?.
-   * Parameters: 1
-   *   -[1]: Term of sort Regexp
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  REGEXP_OPT,
-  /**
-   * Regexp range.
-   * Parameters: 2
-   *   -[1]: Lower bound character for the range
-   *   -[2]: Upper bound character for the range
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  REGEXP_RANGE,
-  /**
-   * Operator for regular expression repeat.
-   * Parameters: 1
-   *   -[1]: The number of repetitions
-   * Create with:
-   *   mkOp(Kind kind, uint32_t param)
-   *
-   * Apply regular expression loop.
-   * Parameters: 2
-   *   -[1]: Op of kind REGEXP_REPEAT
-   *   -[2]: Term of regular expression sort
-   * Create with:
-   *   mkTerm(Op op, Term child)
-   *   mkTerm(Op op, const std::vector<Term>& children)
-   */
-  REGEXP_REPEAT,
-  /**
-   * Operator for regular expression loop, from lower bound to upper bound
-   * number of repetitions.
-   * Parameters: 2
-   *   -[1]: The lower bound
-   *   -[2]: The upper bound
-   * Create with:
-   *   mkOp(Kind kind, uint32_t param, uint32_t param)
-   *
-   * Apply regular expression loop.
-   * Parameters: 2
-   *   -[1]: Op of kind REGEXP_LOOP
-   *   -[2]: Term of regular expression sort
-   * Create with:
-   *   mkTerm(Op op, Term child)
-   *   mkTerm(Op op, const std::vector<Term>& children)
-   */
-  REGEXP_LOOP,
-  /**
-   * Regexp empty.
-   * Parameters: 0
-   * Create with:
-   *   mkRegexpEmpty()
-   *   mkTerm(Kind kind)
-   */
-  REGEXP_EMPTY,
-  /**
-   * Regexp all characters.
-   * Parameters: 0
-   * Create with:
-   *   mkRegexpSigma()
-   *   mkTerm(Kind kind)
-   */
-  REGEXP_SIGMA,
-  /**
-   * Regexp complement.
-   * Parameters: 1
-   *   -[1]: Term of sort RegExp
-   * Create with:
-   *   mkTerm(Kind kind, Term child1)
-   */
-  REGEXP_COMPLEMENT,
-
-  /**
-   * Sequence concat.
-   * Parameters: n > 1
-   *   -[1]..[n]: Terms of Sequence sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  SEQ_CONCAT,
-  /**
-   * Sequence length.
-   * Parameters: 1
-   *   -[1]: Term of Sequence sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  SEQ_LENGTH,
-  /**
-   * Sequence extract.
-   * Extracts a subsequence, starting at index i and of length l, from a
-   * sequence s.  If the start index is negative, the start index is greater
-   * than the length of the sequence, or the length is negative, the result is
-   * the empty sequence. Parameters: 3
-   *   -[1]: Term of sort Sequence
-   *   -[2]: Term of sort Integer (index i)
-   *   -[3]: Term of sort Integer (length l)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  SEQ_EXTRACT,
-  /**
-   * Sequence update.
-   * Updates a sequence s by replacing its context starting at an index with t.
-   * If the start index is negative, the start index is greater than the
-   * length of the sequence, the result is s. Otherwise, the length of the
-   * original sequence is preserved.
-   * Parameters: 3
-   *   -[1]: Term of sort Sequence
-   *   -[2]: Term of sort Integer (index i)
-   *   -[3]: Term of sort Sequence (replacement sequence t)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  SEQ_UPDATE,
-  /**
-   * Sequence element at.
-   * Returns the element at index i from a sequence s. If the index is negative
-   * or the index is greater or equal to the length of the sequence, the result
-   * is the empty sequence. Otherwise the result is a sequence of length 1.
-   * Parameters: 2
-   *   -[1]: Term of sequence sort (string s)
-   *   -[2]: Term of sort Integer (index i)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  SEQ_AT,
-  /**
-   * Sequence contains.
-   * Checks whether a sequence s1 contains another sequence s2. If s2 is empty,
-   * the result is always true. Parameters: 2
-   *   -[1]: Term of sort Sequence (the sequence s1)
-   *   -[2]: Term of sort Sequence (the sequence s2)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  SEQ_CONTAINS,
-  /**
-   * Sequence index-of.
-   * Returns the index of a subsequence s2 in a sequence s1 starting at index i.
-   * If the index is negative or greater than the length of sequence s1 or the
-   * subsequence s2 does not appear in sequence s1 after index i, the result is
-   * -1. Parameters: 3
-   *   -[1]: Term of sort Sequence (subsequence s1)
-   *   -[2]: Term of sort Sequence (subsequence s2)
-   *   -[3]: Term of sort Integer (index i)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  SEQ_INDEXOF,
-  /**
-   * Sequence replace.
-   * Replaces the first occurrence of a sequence s2 in a sequence s1 with
-   * sequence s3. If s2 does not appear in s1, s1 is returned unmodified.
-   * Parameters: 3
-   *   -[1]: Term of sort Sequence (sequence s1)
-   *   -[2]: Term of sort Sequence (sequence s2)
-   *   -[3]: Term of sort Sequence (sequence s3)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  SEQ_REPLACE,
-  /**
-   * Sequence replace all.
-   * Replaces all occurrences of a sequence s2 in a sequence s1 with sequence
-   * s3. If s2 does not appear in s1, s1 is returned unmodified. Parameters: 3
-   *   -[1]: Term of sort Sequence (sequence s1)
-   *   -[2]: Term of sort Sequence (sequence s2)
-   *   -[3]: Term of sort Sequence (sequence s3)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  SEQ_REPLACE_ALL,
-  /**
-   * Sequence reverse.
-   * Parameters: 1
-   *   -[1]: Term of Sequence sort
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  SEQ_REV,
-  /**
-   * Sequence prefix-of.
-   * Checks whether a sequence s1 is a prefix of sequence s2. If sequence s1 is
-   * empty, this operator returns true.
-   * Parameters: 2
-   *   -[1]: Term of sort Sequence (sequence s1)
-   *   -[2]: Term of sort Sequence (sequence s2)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  SEQ_PREFIX,
-  /**
-   * Sequence suffix-of.
-   * Checks whether a sequence s1 is a suffix of sequence s2. If sequence s1 is
-   * empty, this operator returns true. Parameters: 2
-   *   -[1]: Term of sort Sequence (sequence s1)
-   *   -[2]: Term of sort Sequence (sequence s2)
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  SEQ_SUFFIX,
-  /**
-   * Constant sequence.
-   * Parameters:
-   *   See mkEmptySequence()
-   * Create with:
-   *   mkEmptySequence(Sort sort)
-   * Note that a constant sequence is a term that is equivalent to:
-   *   (seq.++ (seq.unit c1) ... (seq.unit cn))
-   * where n>=0 and c1, ..., cn are constants of some sort. The elements
-   * can be extracted by Term::getConstSequenceElements().
-   */
-  CONST_SEQUENCE,
-  /**
-   * Sequence unit, corresponding to a sequence of length one with the given
-   * term.
-   * Parameters: 1
-   *   -[1] Element term.
-   * Create with:
-   *   mkTerm(Kind kind, Term child1)
-   */
-  SEQ_UNIT,
-  /**
-   * Sequence nth, corresponding to the nth element of a sequence.
-   * Parameters: 2
-   *   -[1] Sequence term.
-   *   -[2] Integer term.
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   */
-  SEQ_NTH,
-
-  /* Quantifiers ----------------------------------------------------------- */
-
-  /**
-   * Universally quantified formula.
-   * Parameters: 2 (3)
-   *   -[1]: BOUND_VAR_LIST Term
-   *   -[2]: Quantifier body
-   *   -[3]: (optional) INST_PATTERN_LIST Term
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  FORALL,
-  /**
-   * Existentially quantified formula.
-   * Parameters: 2 (3)
-   *   -[1]: BOUND_VAR_LIST Term
-   *   -[2]: Quantifier body
-   *   -[3]: (optional) INST_PATTERN_LIST Term
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  EXISTS,
-  /*
-   * A list of bound variables (used to bind variables under a quantifier)
-   * Parameters: n > 1
-   *   -[1]..[n]: Terms with kind BOUND_VARIABLE
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  BOUND_VAR_LIST,
-  /*
-   * An instantiation pattern.
-   * Specifies a (list of) terms to be used as a pattern for quantifier
-   * instantiation.
-   * Parameters: n > 1
-   *   -[1]..[n]: Terms with kind BOUND_VARIABLE
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  INST_PATTERN,
-  /*
-   * An instantiation no-pattern.
-   * Specifies a (list of) terms that should not be used as a pattern for
-   * quantifier instantiation.
-   * Parameters: n > 1
-   *   -[1]..[n]: Terms with kind BOUND_VARIABLE
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  INST_NO_PATTERN,
-  /*
-   * An instantiation attribute
-   * Specifies a custom property for a quantified formula given by a
-   * term that is ascribed a user attribute.
-   * Parameters: 1
-   *   -[1]: Term with a user attribute.
-   * Create with:
-   *   mkTerm(Kind kind, Term child)
-   */
-  INST_ATTRIBUTE,
-  /*
-   * A list of instantiation patterns and/or attributes.
-   * Parameters: n > 1
-   *   -[1]..[n]: Terms with kind INST_PATTERN, INST_NO_PATTERN, or
-   * INST_ATTRIBUTE.
-   * Create with:
-   *   mkTerm(Kind kind, Term child1, Term child2)
-   *   mkTerm(Kind kind, Term child1, Term child2, Term child3)
-   *   mkTerm(Kind kind, const std::vector<Term>& children)
-   */
-  INST_PATTERN_LIST,
-#if 0
-
-  /* Sort Kinds ------------------------------------------------------------ */
-
-  /* array type */
-   ARRAY_TYPE,
-  /* a type parameter for type ascription */
-  ASCRIPTION_TYPE,
-  /* constructor */
-  CONSTRUCTOR_TYPE,
-  /* a datatype type index */
-  DATATYPE_TYPE,
-  /* selector */
-  SELECTOR_TYPE,
-  /* set type, takes as parameter the type of the elements */
-  SET_TYPE,
-  /* bag type, takes as parameter the type of the elements */
-  BAG_TYPE,
-  /* sort tag */
-  SORT_TAG,
-  /* specifies types of user-declared 'uninterpreted' sorts */
-  SORT_TYPE,
-  /* tester */
-  TESTER_TYPE,
-  /* a representation for basic types */
-  TYPE_CONSTANT,
-  /* a function type */
-  FUNCTION_TYPE,
-  /* the type of a symbolic expression */
-  SEXPR_TYPE,
-  /* bit-vector type */
-  BITVECTOR_TYPE,
-  /* floating-point type */
-  FLOATINGPOINT_TYPE,
-#endif
-
-  /* ----------------------------------------------------------------------- */
-  /* marks the upper-bound of this enumeration */
-  LAST_KIND
-};
-
-/**
- * Get the string representation of a given kind.
- * @param k the kind
- * @return the string representation of kind k
- */
-std::string kindToString(Kind k) CVC4_EXPORT;
-
-/**
- * Serialize a kind to given stream.
- * @param out the output stream
- * @param k the kind to be serialized to the given output stream
- * @return the output stream
- */
-std::ostream& operator<<(std::ostream& out, Kind k) CVC4_EXPORT;
-
-/**
- * Hash function for Kinds.
- */
-struct CVC4_EXPORT KindHashFunction
-{
-  size_t operator()(Kind k) const;
-};
-
-}  // namespace api
-}  // namespace cvc5
-
-#endif
index 9c25e73934e7a739d5f7d7708491fedc394907fe..38c12aa5cb566f5912918c4df1db37d12c8d7a48 100644 (file)
@@ -19,7 +19,7 @@ add_custom_target(
   COMMAND
     "${PYTHON_EXECUTABLE}"
     "${CMAKE_CURRENT_LIST_DIR}/genkinds.py"
-    --kinds-header "${PROJECT_SOURCE_DIR}/src/api/cvc4cppkind.h"
+    --kinds-header "${PROJECT_SOURCE_DIR}/src/api/cpp/cvc5_kind.h"
     --kinds-file-prefix "${CMAKE_CURRENT_BINARY_DIR}/cvc/Kind"
   DEPENDS
     genkinds.py
index 6b2e0a5af2b23e20ed62442043706374525f319f..8dc3c84d88a79f0272b8755c5cdc97ec63531f2f 100644 (file)
@@ -11,7 +11,7 @@
 #
 
 """
-This script reads CVC4/src/api/cvc4cppkind.h and generates
+This script reads CVC4/src/api/cpp/cvc5_kind.h and generates
 cvc/Kind.java file which declare all the CVC4 kinds.
 """
 
index 89116ff0e15b0bccd846c81de720eb63e6bbfe6a..1ae697a80ef9e1312014b41a614695054269c5ec 100644 (file)
@@ -12,7 +12,7 @@
 
 """
 This script implements KindsParser which
-parses the header file CVC4/src/api/cvc4cppkind.h
+parses the header file CVC4/src/api/cpp/cvc5_kind.h
 
 The script is aware of the '#if 0' pattern and will ignore
 kinds declared between '#if 0' and '#endif'. It can also
@@ -21,6 +21,7 @@ handle nested '#if 0' pairs.
 
 from collections import OrderedDict
 
+
 ##################### Useful Constants ################
 OCB = '{'
 CCB = '}'
index ec156e50e4e4b17217e7eb058c8e9957a0ec0d5a..2311b63f43e8398362526111d48ebcda7f00bf43 100644 (file)
@@ -33,7 +33,7 @@ add_custom_target(
   COMMAND
     "${PYTHON_EXECUTABLE}"
     "${CMAKE_CURRENT_BINARY_DIR}/genkinds.py"
-    --kinds-header "${PROJECT_SOURCE_DIR}/src/api/cvc4cppkind.h"
+    --kinds-header "${PROJECT_SOURCE_DIR}/src/api/cpp/cvc5_kind.h"
     --kinds-file-prefix "${CMAKE_CURRENT_BINARY_DIR}/cvc4kinds"
   DEPENDS
     "${CMAKE_CURRENT_BINARY_DIR}/genkinds.py"
index 8bcd618cfe526a20bc417523a61310a27b128a09..8072dbfa7c67f087d2fbb6988c3a25ec6401e348 100644 (file)
@@ -14,12 +14,12 @@ cdef extern from "<iostream>" namespace "std":
     ostream cout
 
 
-cdef extern from "api/cvc4cpp.h" namespace "CVC4":
+cdef extern from "api/cpp/cvc5.h" namespace "CVC4":
     cdef cppclass Options:
         pass
 
 
-cdef extern from "api/cvc4cpp.h" namespace "cvc5::api":
+cdef extern from "api/cpp/cvc5.h" namespace "cvc5::api":
     cdef cppclass Datatype:
         Datatype() except +
         DatatypeConstructor operator[](size_t idx) except +
@@ -199,7 +199,7 @@ cdef extern from "api/cvc4cpp.h" namespace "cvc5::api":
         Term mkAbstractValue(const string& index) except +
         Term mkFloatingPoint(uint32_t exp, uint32_t sig, Term val) except +
         Term mkConst(Sort sort, const string& symbol) except +
-        # default value for symbol defined in cvc4cpp.h
+        # default value for symbol defined in cpp/cvc5.h
         Term mkConst(Sort sort) except +
         Term mkVar(Sort sort, const string& symbol) except +
         DatatypeConstructorDecl mkDatatypeConstructorDecl(const string& name) except +
@@ -209,7 +209,7 @@ cdef extern from "api/cvc4cpp.h" namespace "cvc5::api":
         DatatypeDecl mkDatatypeDecl(const string& name, Sort param, bint isCoDatatype) except +
         DatatypeDecl mkDatatypeDecl(const string& name, vector[Sort]& params) except +
         DatatypeDecl mkDatatypeDecl(const string& name, vector[Sort]& params, bint isCoDatatype) except +
-        # default value for symbol defined in cvc4cpp.h
+        # default value for symbol defined in cpp/cvc5.h
         Term mkVar(Sort sort) except +
         Term simplify(const Term& t) except +
         void assertFormula(Term term) except +
@@ -354,7 +354,7 @@ cdef extern from "api/cvc4cpp.h" namespace "cvc5::api":
         size_t operator()(const Term & t) except +
 
 
-cdef extern from "api/cvc4cpp.h" namespace "cvc5::api::RoundingMode":
+cdef extern from "api/cpp/cvc5.h" namespace "cvc5::api::RoundingMode":
     cdef RoundingMode ROUND_NEAREST_TIES_TO_EVEN,
     cdef RoundingMode ROUND_TOWARD_POSITIVE,
     cdef RoundingMode ROUND_TOWARD_NEGATIVE,
index 7fb84b43c35aa30b36399d755b3cac5bc32a8de9..4c5fc818a392bc220fb71f4e011ac7c97e41519c 100644 (file)
@@ -10,7 +10,7 @@
 ## directory for licensing information.
 ##
 """
-This script reads CVC4/src/api/cvc4cppkind.h and generates
+This script reads CVC4/src/api/cpp/cvc5_kind.h and generates
 .pxd and .pxi files which declare all the CVC4 kinds and
 implement a Python wrapper for kinds, respectively. The
 default names are kinds.pxd / kinds.pxi, but the name is
@@ -40,13 +40,13 @@ PYCOMMENT           = '#'
 CDEF_KIND = "    cdef Kind "
 
 KINDS_PXD_TOP = \
-r"""cdef extern from "api/cvc4cppkind.h" namespace "cvc5::api":
+r"""cdef extern from "api/cpp/cvc5_kind.h" namespace "cvc5::api":
     cdef cppclass Kind:
         pass
 
 
-# Kind declarations: See cvc4cppkind.h for additional information
-cdef extern from "api/cvc4cppkind.h" namespace "cvc5::api::Kind":
+# Kind declarations: See cpp/cvc5_kind.h for additional information
+cdef extern from "api/cpp/cvc5_kind.h" namespace "cvc5::api::Kind":
 """
 
 KINDS_PXI_TOP = \
index 0a9248f782cb0d75b61492f5a2f16349029673ba..4ff307bc2bab9f3948152ead337b095db8ce8535 100644 (file)
@@ -21,7 +21,7 @@
 #include <memory>
 #include <string>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 #include "cvc4_export.h"
 #include "expr/symbol_table.h"
 
index 1c513fea4d7fcd6b51151ea27e5295a19bbf1381..9e60680c7a5422b5dbd787b45913ceeebf41f6a2 100644 (file)
@@ -23,7 +23,7 @@
 #include <unordered_map>
 #include <utility>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 #include "context/cdhashmap.h"
 #include "context/cdhashset.h"
 #include "context/context.h"
index 7f9fa5d5bc20b28b2626b7daa1ad43afaa89a6df..49bade416edeff65dc3c5905fa848cf0b8363770 100755 (executable)
@@ -4,5 +4,8 @@ set -e -o pipefail
 
 dir="$DESTDIR$1"
 
-find "$dir/include/cvc4/" -type f \
-  -exec sed -i'' -e 's/include.*"\(.*\)"/include <cvc4\/\1>/' {} +
+find "$dir/include/cvc5/" -type f \
+  -exec sed -i'' -e 's/include.*"api\/cpp\/\(.*\)"/include <cvc5\/\1>/' {} +
+
+find "$dir/include/cvc5/" -type f \
+  -exec sed -i'' -e 's/"cvc4_export.h"/<cvc5\/cvc4_export.h>/' {} +
index d2117e109d6e60a6287f58785c5c00db620ffddc..1b68e01e67b2652de0c90e7b2222d44a26a7d1b2 100644 (file)
@@ -18,7 +18,7 @@
 #include <iosfwd>
 #include <string>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 #include "expr/symbol_manager.h"
 #include "options/options.h"
 
index 6f9377a33c4bbd5929fb5c1ea76f588ed31c7e0c..ec141d13aae5dbc8580be20ee64b322a4643a4ae 100644 (file)
@@ -23,7 +23,7 @@
 #include <memory>
 #include <new>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 #include "base/configuration.h"
 #include "base/output.h"
 #include "cvc4autoconfig.h"
index 44fee3eb5c02e7a3491dd0df6a25271421dd0a7d..0ddd8707a19c00d567e6d10537dfcfe5cfaca36c 100644 (file)
@@ -35,7 +35,7 @@
 #  endif /* HAVE_EXT_STDIO_FILEBUF_H */
 #endif   /* HAVE_LIBEDITLINE */
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 #include "base/check.h"
 #include "base/output.h"
 #include "expr/symbol_manager.h"
index acfcc1d17facf5cd1e9fcf867811884ae92a2854..ad3642e203eba31a5485ca7e60cc822831f2fc05 100644 (file)
@@ -19,7 +19,7 @@
 #ifndef CVC4__PARSER__CVC_H
 #define CVC4__PARSER__CVC_H
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 #include "parser/parser.h"
 
 namespace cvc5 {
index fcaa369322bb091801461a5afafa1953432e9964..d54cb95ab8665f1eaa43bc9f791dcab44eb603e8 100644 (file)
@@ -25,7 +25,7 @@
 #include <string>
 #include <vector>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 #include "cvc4_export.h"
 #include "options/language.h"
 #include "parser/parser_exception.h"
index 1163ab6be79f6363c119d731355052ae3bf250b9..592fce4f7a8dd3fc9dbc6265449c7401a3d81069 100644 (file)
@@ -19,7 +19,7 @@
 
 #include <string>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 
 namespace cvc5 {
 
index 6725b5ec727f13f43ed568d152fb47e5844b6e36..b4e4639bad21c0e888bb23ce187206d2da5fa02e 100644 (file)
@@ -23,7 +23,7 @@
 #include <sstream>
 #include <unordered_set>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 #include "base/check.h"
 #include "base/output.h"
 #include "expr/kind.h"
index 173b98a9c0a8c20b492250bb51ddd315a3f3d303..79b975fc4997c111517239938e01cb7095c4323e 100644 (file)
@@ -23,7 +23,7 @@
 #include <set>
 #include <string>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 #include "cvc4_export.h"
 #include "expr/kind.h"
 #include "expr/symbol_manager.h"
index b0b6a03e74fea441d71305bf7c86e792cae4eb1d..933be7a5187b676a281f106115636bd2e0ea9d96 100644 (file)
@@ -19,7 +19,7 @@
 
 #include <string>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 #include "base/check.h"
 #include "cvc/cvc.h"
 #include "options/options.h"
index 6adc6275acd8f8551e96f99fd226310038e78b7e..3302533e653550bc9ca17b801f918534dadf6675 100644 (file)
@@ -102,7 +102,7 @@ namespace cvc5 {
 #include <unordered_set>
 #include <vector>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 #include "base/output.h"
 #include "options/set_language.h"
 #include "parser/antlr_input.h"
index 5ad5088689167dfbe95626f15ee7eb0db81e4487..645209c61f0c454d4745e56964da8d929565614b 100644 (file)
@@ -25,7 +25,7 @@
 #include <unordered_map>
 #include <utility>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 #include "parser/parse_op.h"
 #include "parser/parser.h"
 #include "theory/logic_info.h"
index 030330748b5ea4c32aab5f248d514c272e57c38c..f6b8452120f95c391f2891e574938cde32f43813 100644 (file)
@@ -100,7 +100,7 @@ using namespace cvc5::parser;
 #include <iterator>
 #include <vector>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 #include "base/output.h"
 #include "parser/antlr_input.h"
 #include "parser/parser.h"
index 7a3a47ec9823795f0188e4396fac903982edb253..2f770a58da30b2caaf2408cab82ce7cc61ad88e3 100644 (file)
@@ -18,7 +18,7 @@
 #include <algorithm>
 #include <set>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 #include "base/check.h"
 #include "options/options.h"
 #include "parser/parser.h"
index b91418bd026f8bb77eaaea43a22f013992a1fa7d..ab2e0db518756f8766046eb3006434b14e65bbbf 100644 (file)
@@ -22,7 +22,7 @@
 #include <unordered_map>
 #include <unordered_set>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 #include "parser/parse_op.h"
 #include "parser/parser.h"
 #include "util/hash.h"
index a2a45de8185e6b164fa1bbb5ed62358c9e991e18..b0019d272db0b37355db4357ea60516cd611de10 100644 (file)
@@ -22,7 +22,7 @@
 #include <typeinfo>
 #include <vector>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 #include "expr/dtype.h"
 #include "expr/dtype_cons.h"
 #include "expr/node_manager_attributes.h"
index 4a6efe7136f6002509e27e1d681ee34607ccf91e..a8d9afdfa1660d44a4966a52ff6ba7b63bef3ab5 100644 (file)
@@ -23,7 +23,7 @@
 #include <utility>
 #include <vector>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 #include "base/check.h"
 #include "base/output.h"
 #include "expr/expr_iomanip.h"
index 6c3b4f0e47ca5483a7698c3c0d73245d3dac9114..e925947365f0767238f4481d3b1d1c7e013acfbe 100644 (file)
@@ -27,7 +27,7 @@
 #include <string>
 #include <vector>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 #include "cvc4_export.h"
 #include "options/language.h"
 
index cc71a48ae0136c9bb552d2785e1493551eb613c1..73abb3e19e256f7f3fd0aed1ef27b84962407f70 100644 (file)
@@ -19,7 +19,7 @@
 #include <iostream>
 #include <sstream>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 
 using namespace cvc5::api;
 using namespace std;
index 2b57781b6116d0c5937057abf79c6ebaf0e40e34..ed2340c185c718ccf9b0745053a4a84c85c5eb44 100644 (file)
@@ -12,7 +12,7 @@
  ** \brief Test for issue #4889
  **/
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 
 using namespace cvc5::api;
 
index ab58797eec2b009264c9ba92fa99fbe8b86f2127..d0000c710e010a7d2c5c35a0ee77e5026c49e9b5 100644 (file)
@@ -12,7 +12,7 @@
  ** \brief Test for issue #5074
  **/
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 
 using namespace cvc5::api;
 
index 8686cbeb1212eb77bfdd7214e6dd9d1c045d214a..96698b4d2339ea3f8cc6367c90050a0ac65862d2 100644 (file)
@@ -28,7 +28,7 @@
 #include <iostream>
 #include <string>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 #include "options/set_language.h"
 #include "parser/parser.h"
 #include "parser/parser_builder.h"
index 46941e36d574d1634b44185a502375769917d641..5e31b0b5e296d42cbbf8f7bc81111d2bf04114fb 100644 (file)
@@ -20,7 +20,7 @@
 #include <iostream>
 #include <sstream>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 
 using namespace cvc5::api;
 
index 8599a36e1d70aa03dc7b07cd3719892cc308d310..1ce8e9c7099a3fd659f0d3cc58a10f35f2b502aa 100644 (file)
@@ -22,7 +22,7 @@
 #include <iostream>
 #include <sstream>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 
 using namespace cvc5::api;
 using namespace std;
index 0510e59dbb66fa0204114976794b2f4865521710..a3ae59eda5a7f9b782fd485ed9558adcfcce9750 100644 (file)
@@ -18,7 +18,7 @@
 #include <iostream>
 #include <sstream>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 #include "options/options.h"
 #include "options/set_language.h"
 #include "parser/parser.h"
index d28f0ceb50fdb7fe3f0775d65efc2811b76fc95c..b55678b1a88973a4f4d810b9fc97216ec879d22d 100644 (file)
@@ -17,7 +17,7 @@
 #include <iostream>
 #include <sstream>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 
 using namespace cvc5::api;
 using namespace std;
index 7ab337c0910bdbab7d137577fbc47a078c2c28d7..52f07a2f23358419b2b094d163b0c46282c28ffa 100644 (file)
@@ -17,7 +17,7 @@
 #include <sstream>
 #include <vector>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 #include "expr/symbol_manager.h"
 #include "main/interactive_shell.h"
 #include "options/base_options.h"
index 5177ff453dab99fd27b4b5f8bbc2cdcfe330d02c..be393039be68127fb1f94a8944a6bc31a42649dd 100644 (file)
@@ -19,7 +19,7 @@
 #include <string>
 #include <vector>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 #include "expr/dtype.h"
 #include "expr/dtype_cons.h"
 #include "expr/node.h"
index 3c6d8b82061edf3f3a23e85e00d58d75ae12ce63..5b695030ed2a2f7f61b1c547cae8ab9d76cc9a35 100644 (file)
@@ -17,7 +17,7 @@
 
 #include <sstream>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 #include "base/output.h"
 #include "expr/symbol_manager.h"
 #include "options/base_options.h"
index a83932b2fd2a147ff432f3ae9da1bb818982584c..113a5abd5adfdc01825b26a2b811638443267086 100644 (file)
@@ -22,7 +22,7 @@
 #include <fstream>
 #include <iostream>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 #include "expr/symbol_manager.h"
 #include "options/language.h"
 #include "parser/parser.h"
index 03ab950836f1019b1586f5529acf27c3921bc99b..d89930033471b5c0cc06c1002c577488e3d0b9b8 100644 (file)
@@ -16,7 +16,7 @@
 
 #include <iostream>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 #include "expr/node.h"
 #include "expr/node_manager.h"
 #include "options/language.h"
index 7ad2e1e5cceb214af6e05af6e670e5c48a4e60ad..b66dd58bc5712678ef626b4fb8ddaea188723e6c 100644 (file)
@@ -15,7 +15,7 @@
 #ifndef CVC4__TEST__UNIT__TEST_API_H
 #define CVC4__TEST__UNIT__TEST_API_H
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 #include "gtest/gtest.h"
 
 namespace cvc5 {
index ed432ca2f49ddcc0cc934553717ca7d2c3445878..608eeb649f04bf2313d5808a3741b16d871f2d12 100644 (file)
@@ -18,7 +18,7 @@
 #include <memory>
 #include <vector>
 
-#include "api/cvc4cpp.h"
+#include "api/cpp/cvc5.h"
 #include "expr/node.h"
 #include "expr/node_manager.h"
 #include "smt/smt_engine_scope.h"