Improve syntax for fmf cardinality constraints (#7556)
[cvc5.git] / src / parser / smt2 / smt2.h
index 09f7a5696503b2bfd18a0cf10a5595e020468b5e..58a20cb2790a1f974c7b926e4a4afcebd5e28eaf 100644 (file)
@@ -1,23 +1,22 @@
-/*********************                                                        */
-/*! \file smt2.h
- ** \verbatim
- ** Top contributors (to current version):
- **   Morgan Deters, Andrew Reynolds, Christopher L. Conway
- ** This file is part of the CVC4 project.
- ** Copyright (c) 2009-2017 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 Definitions of SMT2 constants.
- **
- ** Definitions of SMT2 constants.
- **/
-
-#include "cvc4parser_private.h"
-
-#ifndef __CVC4__PARSER__SMT2_H
-#define __CVC4__PARSER__SMT2_H
+/******************************************************************************
+ * Top contributors (to current version):
+ *   Andrew Reynolds, Andres Noetzli, Morgan Deters
+ *
+ * This file is part of the cvc5 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.
+ * ****************************************************************************
+ *
+ * Definitions of SMT2 constants.
+ */
+
+#include "cvc5parser_private.h"
+
+#ifndef CVC5__PARSER__SMT2_H
+#define CVC5__PARSER__SMT2_H
 
 #include <sstream>
 #include <stack>
 #include <unordered_map>
 #include <utility>
 
+#include "api/cpp/cvc5.h"
+#include "parser/parse_op.h"
 #include "parser/parser.h"
-#include "parser/smt1/smt1.h"
 #include "theory/logic_info.h"
-#include "util/abstract_value.h"
 
-namespace CVC4 {
+namespace cvc5 {
 
-class SExpr;
+class Command;
+
+namespace api {
+class Solver;
+}
 
 namespace parser {
 
-class Smt2 : public Parser {
+class Smt2 : public Parser
+{
   friend class ParserBuilder;
 
-public:
-  enum Theory {
-    THEORY_ARRAYS,
-    THEORY_BITVECTORS,
-    THEORY_CORE,
-    THEORY_DATATYPES,
-    THEORY_INTS,
-    THEORY_REALS,
-    THEORY_REALS_INTS,
-    THEORY_QUANTIFIERS,
-    THEORY_SETS,
-    THEORY_STRINGS,
-    THEORY_UF,
-    THEORY_FP,
-    THEORY_SEP
-  };
-
-private:
+ private:
+  /** Has the logic been set (either by forcing it or a set-logic command)? */
   bool d_logicSet;
+  /** Have we seen a set-logic command yet? */
+  bool d_seenSetLogic;
+
   LogicInfo d_logic;
-  std::unordered_map<std::string, Kind> operatorKindMap;
-  std::pair<Expr, std::string> d_lastNamedTerm;
-  // for sygus
-  std::vector<Expr> d_sygusVars, d_sygusConstraints, d_sygusFunSymbols;
-  std::map< Expr, bool > d_sygusVarPrimed;
+  std::unordered_map<std::string, api::Kind> d_operatorKindMap;
+  /**
+   * Maps indexed symbols to the kind of the operator (e.g. "extract" to
+   * BITVECTOR_EXTRACT).
+   */
+  std::unordered_map<std::string, api::Kind> d_indexedOpKindMap;
+  std::pair<api::Term, std::string> d_lastNamedTerm;
+  /**
+   * A list of sygus grammar objects. We keep track of them here to ensure that
+   * they don't get deleted before the commands using them get invoked.
+   */
+  std::vector<std::unique_ptr<api::Grammar>> d_allocGrammars;
 
-protected:
-  Smt2(ExprManager* exprManager, Input* input, bool strictMode = false, bool parseOnly = false);
+ protected:
+  Smt2(api::Solver* solver,
+       SymbolManager* sm,
+       bool strictMode = false,
+       bool parseOnly = false);
+
+ public:
+  ~Smt2();
 
-public:
   /**
-   * Add theory symbols to the parser state.
-   *
-   * @param theory the theory to open (e.g., Core, Ints)
+   * Add core theory symbols to the parser state.
    */
-  void addTheory(Theory theory);
+  void addCoreSymbols();
+
+  void addOperator(api::Kind k, const std::string& name);
 
-  void addOperator(Kind k, const std::string& name);
+  /**
+   * Registers an indexed function symbol.
+   *
+   * @param tKind The kind of the term that uses the operator kind (e.g.
+   *              BITVECTOR_EXTRACT). NOTE: this is an internal kind for now
+   *              because that is what we use to create expressions. Eventually
+   *              it will be an api::Kind.
+   * @param opKind The kind of the operator term (e.g. BITVECTOR_EXTRACT)
+   * @param name The name of the symbol (e.g. "extract")
+   */
+  void addIndexedOperator(api::Kind tKind,
+                          api::Kind opKind,
+                          const std::string& name);
 
-  Kind getOperatorKind(const std::string& name) const;
+  api::Kind getOperatorKind(const std::string& name) const;
 
   bool isOperatorEnabled(const std::string& name) const;
 
-  bool isTheoryEnabled(Theory theory) const;
+  bool isTheoryEnabled(theory::TheoryId theory) const;
+
+  /**
+   * Checks if higher-order support is enabled.
+   *
+   * @return true if higher-order support is enabled, false otherwise
+   */
+  bool isHoEnabled() const;
+  /**
+   * @return true if cardinality constraints are enabled, false otherwise
+   */
+  bool hasCardinalityConstraints() const;
 
   bool logicIsSet() override;
 
   /**
-   * Returns the expression that name should be interpreted as. 
+   * Creates an indexed constant, e.g. (_ +oo 8 24) (positive infinity
+   * as a 32-bit floating-point constant).
+   *
+   * @param name The name of the constant (e.g. "+oo")
+   * @param numerals The parameters for the constant (e.g. [8, 24])
+   * @return The term corresponding to the constant or a parse error if name is
+   *         not valid.
+   */
+  api::Term mkIndexedConstant(const std::string& name,
+                              const std::vector<uint64_t>& numerals);
+
+  /**
+   * Creates an indexed operator kind, e.g. BITVECTOR_EXTRACT for "extract".
+   *
+   * @param name The name of the operator (e.g. "extract")
+   * @return The kind corresponding to the indexed operator or a parse
+   *         error if the name is not valid.
    */
-  Expr getExpressionForNameAndType(const std::string& name, Type t) override;
+  api::Kind getIndexedOpKind(const std::string& name);
+
+  /**
+   * Returns the expression that name should be interpreted as.
+   */
+  api::Term getExpressionForNameAndType(const std::string& name,
+                                        api::Sort t) override;
+
+  /**
+   * If we are in a version < 2.6, this updates name to the tester name of cons,
+   * e.g. "is-cons".
+   */
+  bool getTesterName(api::Term cons, std::string& name) override;
 
   /** Make function defined by a define-fun(s)-rec command.
-  *
-  * fname : the name of the function.
-  * sortedVarNames : the list of variable arguments for the function.
-  * t : the range type of the function we are defining.
-  *
-  * This function will create a bind a new function term to name fname.
-  * The type of this function is
-  * Parser::mkFlatFunctionType(sorts,t,flattenVars),
-  * where sorts are the types in the second components of sortedVarNames.
-  * As descibed in Parser::mkFlatFunctionType, new bound variables may be
-  * added to flattenVars in this function if the function is given a function
-  * range type.
-  */
-  Expr mkDefineFunRec(
+   *
+   * fname : the name of the function.
+   * sortedVarNames : the list of variable arguments for the function.
+   * t : the range type of the function we are defining.
+   *
+   * This function will create a bind a new function term to name fname.
+   * The type of this function is
+   * Parser::mkFlatFunctionType(sorts,t,flattenVars),
+   * where sorts are the types in the second components of sortedVarNames.
+   * As descibed in Parser::mkFlatFunctionType, new bound variables may be
+   * added to flattenVars in this function if the function is given a function
+   * range type.
+   */
+  api::Term bindDefineFunRec(
       const std::string& fname,
-      const std::vector<std::pair<std::string, Type> >& sortedVarNames,
-      Type t,
-      std::vector<Expr>& flattenVars);
+      const std::vector<std::pair<std::string, api::Sort>>& sortedVarNames,
+      api::Sort t,
+      std::vector<api::Term>& flattenVars);
 
   /** Push scope for define-fun-rec
    *
-  * This calls Parser::pushScope(bindingLevel) and sets up
-  * initial information for reading a body of a function definition
-  * in the define-fun-rec and define-funs-rec command.
-  * The input parameters func/flattenVars are the result
-  * of a call to mkDefineRec above.
-  *
-  * func : the function whose body we are defining.
-  * sortedVarNames : the list of variable arguments for the function.
-  * flattenVars : the implicit variables introduced when defining func.
-  *
-  * This function:
-  * (1) Calls Parser::pushScope(bindingLevel).
-  * (2) Computes the bound variable list for the quantified formula
-  *     that defined this definition and stores it in bvs.
-  */
+   * This calls Parser::pushScope() and sets up
+   * initial information for reading a body of a function definition
+   * in the define-fun-rec and define-funs-rec command.
+   * The input parameters func/flattenVars are the result
+   * of a call to mkDefineRec above.
+   *
+   * func : the function whose body we are defining.
+   * sortedVarNames : the list of variable arguments for the function.
+   * flattenVars : the implicit variables introduced when defining func.
+   *
+   * This function:
+   * (1) Calls Parser::pushScope().
+   * (2) Computes the bound variable list for the quantified formula
+   *     that defined this definition and stores it in bvs.
+   */
   void pushDefineFunRecScope(
-      const std::vector<std::pair<std::string, Type> >& sortedVarNames,
-      Expr func,
-      const std::vector<Expr>& flattenVars,
-      std::vector<Expr>& bvs,
-      bool bindingLevel = false);
+      const std::vector<std::pair<std::string, api::Sort>>& sortedVarNames,
+      api::Term func,
+      const std::vector<api::Term>& flattenVars,
+      std::vector<api::Term>& bvs);
 
   void reset() override;
 
-  void resetAssertions();
+  /**
+   * Creates a command that adds an invariant constraint.
+   *
+   * @param names Name of four symbols corresponding to the
+   *              function-to-synthesize, precondition, postcondition,
+   *              transition relation.
+   * @return The command that adds an invariant constraint
+   */
+  std::unique_ptr<Command> invConstraint(const std::vector<std::string>& names);
 
   /**
    * Sets the logic for the current benchmark. Declares any logic and
    * theory symbols.
    *
    * @param name the name of the logic (e.g., QF_UF, AUFLIA)
+   * @param fromCommand should be set to true if the request originates from a
+   *                    set-logic command and false otherwise
+   * @return the command corresponding to setting the logic (if fromCommand
+   * is true), and nullptr otherwise.
    */
-  void setLogic(std::string name);
+  Command* setLogic(std::string name, bool fromCommand = true);
 
   /**
    * Get the logic.
    */
   const LogicInfo& getLogic() const { return d_logic; }
 
-  bool v2_0() const {
-    return getLanguage() == language::input::LANG_SMTLIB_V2_0;
-  }
   /**
-   * Are we using smtlib 2.5 or above? If exact=true, then this method returns
-   * false if the input language is not exactly SMT-LIB 2.5.
+   * Create a Sygus grammar.
+   * @param boundVars the parameters to corresponding synth-fun/synth-inv
+   * @param ntSymbols the pre-declaration of the non-terminal symbols
+   * @return a pointer to the grammar
    */
-  bool v2_5(bool exact = false) const
-  {
-    return language::isInputLang_smt2_5(getLanguage(), exact);
-  }
+  api::Grammar* mkGrammar(const std::vector<api::Term>& boundVars,
+                          const std::vector<api::Term>& ntSymbols);
+
   /**
    * Are we using smtlib 2.6 or above? If exact=true, then this method returns
    * false if the input language is not exactly SMT-LIB 2.6.
    */
   bool v2_6(bool exact = false) const
   {
-    return language::isInputLang_smt2_6(getLanguage(), exact);
+    return d_solver->getOption("input-language") == "LANG_SMTLIB_V2_6";
   }
-  bool sygus() const { return getLanguage() == language::input::LANG_SYGUS; }
+  /** Are we using a sygus language? */
+  bool sygus() const;
 
-  void setInfo(const std::string& flag, const SExpr& sexpr);
-
-  void setOption(const std::string& flag, const SExpr& sexpr);
+  /**
+   * Returns true if the language that we are parsing (SMT-LIB version >=2.5
+   * and SyGuS) treats duplicate double quotes ("") as an escape sequence
+   * denoting a single double quote (").
+   */
+  bool escapeDupDblQuote() const { return v2_6() || sygus(); }
 
   void checkThatLogicIsSet();
 
-  void checkUserSymbol(const std::string& name) {
-    if(name.length() > 0 && (name[0] == '.' || name[0] == '@')) {
+  /**
+   * Checks whether the current logic allows free sorts. If the logic does not
+   * support free sorts, the function triggers a parse error.
+   */
+  void checkLogicAllowsFreeSorts();
+
+  /**
+   * Checks whether the current logic allows functions of non-zero arity. If
+   * the logic does not support such functions, the function triggers a parse
+   * error.
+   */
+  void checkLogicAllowsFunctions();
+
+  void checkUserSymbol(const std::string& name)
+  {
+    if (name.length() > 0 && (name[0] == '.' || name[0] == '@'))
+    {
+      std::stringstream ss;
+      ss << "cannot declare or define symbol `" << name
+         << "'; symbols starting with . and @ are reserved in SMT-LIB";
+      parseError(ss.str());
+    }
+    else if (isOperatorEnabled(name))
+    {
       std::stringstream ss;
-      ss << "cannot declare or define symbol `" << name << "'; symbols starting with . and @ are reserved in SMT-LIB";
+      ss << "Symbol `" << name << "' is shadowing a theory function symbol";
       parseError(ss.str());
     }
   }
 
   void includeFile(const std::string& filename);
 
-  void setLastNamedTerm(Expr e, std::string name) {
+  void setLastNamedTerm(api::Term e, std::string name)
+  {
     d_lastNamedTerm = std::make_pair(e, name);
   }
 
-  void clearLastNamedTerm() {
-    d_lastNamedTerm = std::make_pair(Expr(), "");
-  }
-
-  std::pair<Expr, std::string> lastNamedTerm() {
-    return d_lastNamedTerm;
-  }
-
-  bool isAbstractValue(const std::string& name) {
-    return name.length() >= 2 && name[0] == '@' && name[1] != '0' &&
-      name.find_first_not_of("0123456789", 1) == std::string::npos;
-  }
-
-  Expr mkAbstractValue(const std::string& name) {
-    assert(isAbstractValue(name));
-    return getExprManager()->mkConst(AbstractValue(Integer(name.substr(1))));
-  }
-
-  Expr mkSygusVar(const std::string& name, const Type& type, bool isPrimed = false);
-
-  void mkSygusConstantsForType( const Type& type, std::vector<CVC4::Expr>& ops );
-
-  void processSygusGTerm( CVC4::SygusGTerm& sgt, int index,
-                          std::vector< CVC4::Datatype >& datatypes,
-                          std::vector< CVC4::Type>& sorts,
-                          std::vector< std::vector<CVC4::Expr> >& ops,
-                          std::vector< std::vector<std::string> >& cnames,
-                          std::vector< std::vector< std::vector< CVC4::Type > > >& cargs,
-                          std::vector< bool >& allow_const,
-                          std::vector< std::vector< std::string > >& unresolved_gterm_sym,
-                          std::vector<CVC4::Expr>& sygus_vars,
-                          std::map< CVC4::Type, CVC4::Type >& sygus_to_builtin, std::map< CVC4::Type, CVC4::Expr >& sygus_to_builtin_expr,
-                          CVC4::Type& ret, bool isNested = false );
-
-  static bool pushSygusDatatypeDef( Type t, std::string& dname,
-                                    std::vector< CVC4::Datatype >& datatypes,
-                                    std::vector< CVC4::Type>& sorts,
-                                    std::vector< std::vector<CVC4::Expr> >& ops,
-                                    std::vector< std::vector<std::string> >& cnames,
-                                    std::vector< std::vector< std::vector< CVC4::Type > > >& cargs,
-                                    std::vector< bool >& allow_const,
-                                    std::vector< std::vector< std::string > >& unresolved_gterm_sym );
-
-  static bool popSygusDatatypeDef( std::vector< CVC4::Datatype >& datatypes,
-                                   std::vector< CVC4::Type>& sorts,
-                                   std::vector< std::vector<CVC4::Expr> >& ops,
-                                   std::vector< std::vector<std::string> >& cnames,
-                                   std::vector< std::vector< std::vector< CVC4::Type > > >& cargs,
-                                   std::vector< bool >& allow_const,
-                                   std::vector< std::vector< std::string > >& unresolved_gterm_sym );
-
-  void setSygusStartIndex( std::string& fun, int startIndex,
-                           std::vector< CVC4::Datatype >& datatypes,
-                           std::vector< CVC4::Type>& sorts,
-                           std::vector< std::vector<CVC4::Expr> >& ops );
-
-  void mkSygusDatatype( CVC4::Datatype& dt, std::vector<CVC4::Expr>& ops,
-                        std::vector<std::string>& cnames, std::vector< std::vector< CVC4::Type > >& cargs,
-                        std::vector<std::string>& unresolved_gterm_sym,
-                        std::map< CVC4::Type, CVC4::Type >& sygus_to_builtin );
-
-
-  void addSygusConstraint(Expr constraint) {
-    d_sygusConstraints.push_back(constraint);
+  void clearLastNamedTerm()
+  {
+    d_lastNamedTerm = std::make_pair(api::Term(), "");
   }
 
-  Expr getSygusConstraints() {
-    switch(d_sygusConstraints.size()) {
-    case 0: return getExprManager()->mkConst(bool(true));
-    case 1: return d_sygusConstraints[0];
-    default: return getExprManager()->mkExpr(kind::AND, d_sygusConstraints);
-    }
-  }
+  std::pair<api::Term, std::string> lastNamedTerm() { return d_lastNamedTerm; }
 
-  const std::vector<Expr>& getSygusVars() {
-    return d_sygusVars;
-  }
-  const void getSygusPrimedVars( std::vector<Expr>& vars, bool isPrimed );
+  /** Does name denote an abstract value? (of the form '@n' for numeral n). */
+  bool isAbstractValue(const std::string& name);
 
-  const void addSygusFunSymbol( Type t, Expr synth_fun );
-  const std::vector<Expr>& getSygusFunSymbols() {
-    return d_sygusFunSymbols;
-  }
+  /** Make abstract value
+   *
+   * Abstract values are used for processing get-value calls. The argument
+   * name should be such that isAbstractValue(name) is true.
+   */
+  api::Term mkAbstractValue(const std::string& name);
 
   /**
    * Smt2 parser provides its own checkDeclaration, which does the
@@ -288,50 +311,22 @@ public:
   {
     // if the symbol is something like "-1", we'll give the user a helpful
     // syntax hint.  (-1 is a valid identifier in SMT-LIB, NOT unary minus.)
-    if( check != CHECK_DECLARED ||
-        name[0] != '-' ||
-        name.find_first_not_of("0123456789", 1) != std::string::npos ) {
-      this->Parser::checkDeclaration(name, check, type, notes);
+    if (name.length() > 1 && name[0] == '-'
+        && name.find_first_not_of("0123456789", 1) == std::string::npos)
+    {
+      std::stringstream ss;
+      ss << notes << "You may have intended to apply unary minus: `(- "
+         << name.substr(1) << ")'\n";
+      this->Parser::checkDeclaration(name, check, type, ss.str());
       return;
-    }else{
-      //it is allowable in sygus
-      if( sygus() && name[0]=='-' ){
-        //do not check anything
-        return;
-      }
-    }
-
-    std::stringstream ss;
-    ss << notes
-       << "You may have intended to apply unary minus: `(- "
-       << name.substr(1)
-       << ")'\n";
-    this->Parser::checkDeclaration(name, check, type, ss.str());
-  }
-
-  void checkOperator(Kind kind, unsigned numArgs)
-  {
-    Parser::checkOperator(kind, numArgs);
-    // strict SMT-LIB mode enables extra checks for some bitvector operators
-    // that CVC4 permits as N-ary but the standard requires is binary
-    if(strictModeEnabled()) {
-      switch(kind) {
-      case kind::BITVECTOR_CONCAT:
-      case kind::BITVECTOR_AND:
-      case kind::BITVECTOR_OR:
-      case kind::BITVECTOR_XOR:
-      case kind::BITVECTOR_MULT:
-      case kind::BITVECTOR_PLUS:
-        if(numArgs != 2) {
-          parseError("Operator requires exact 2 arguments in strict SMT-LIB "
-                     "compliance mode: " + kindToString(kind));
-        }
-        break;
-      default:
-        break; /* no problem */
-      }
     }
+    this->Parser::checkDeclaration(name, check, type, notes);
   }
+  /**
+   * Notify that expression expr was given name std::string via a :named
+   * attribute.
+   */
+  void notifyNamedExpression(api::Term& expr, std::string name);
 
   // Throw a ParserException with msg appended with the current logic.
   inline void parseErrorLogic(const std::string& msg)
@@ -340,63 +335,97 @@ public:
     parseError(withLogic);
   }
 
-private:
-  std::map< CVC4::Expr, CVC4::Type > d_sygus_bound_var_type;
-  std::map< CVC4::Expr, std::vector< CVC4::Expr > > d_sygus_let_func_to_vars;
-  std::map< CVC4::Expr, CVC4::Expr > d_sygus_let_func_to_body;
-  std::map< CVC4::Expr, unsigned > d_sygus_let_func_to_num_input_vars;
-  //auxiliary define-fun functions introduced for production rules
-  std::vector< CVC4::Expr > d_sygus_defined_funs;
-
-  void collectSygusLetArgs( CVC4::Expr e, std::vector< CVC4::Type >& sygusArgs, std::vector< CVC4::Expr >& builtinArgs );
-
-  Type processSygusNestedGTerm( int sub_dt_index, std::string& sub_dname, std::vector< CVC4::Datatype >& datatypes,
-                                std::vector< CVC4::Type>& sorts,
-                                std::vector< std::vector<CVC4::Expr> >& ops,
-                                std::vector< std::vector<std::string> >& cnames,
-                                std::vector< std::vector< std::vector< CVC4::Type > > >& cargs,
-                                std::vector< bool >& allow_const,
-                                std::vector< std::vector< std::string > >& unresolved_gterm_sym,
-                                std::map< CVC4::Type, CVC4::Type >& sygus_to_builtin,
-                                std::map< CVC4::Type, CVC4::Expr >& sygus_to_builtin_expr, Type sub_ret );
-
-  void processSygusLetConstructor( std::vector< CVC4::Expr >& let_vars, int index,
-                                   std::vector< CVC4::Datatype >& datatypes,
-                                   std::vector< CVC4::Type>& sorts,
-                                   std::vector< std::vector<CVC4::Expr> >& ops,
-                                   std::vector< std::vector<std::string> >& cnames,
-                                   std::vector< std::vector< std::vector< CVC4::Type > > >& cargs,
-                                   std::vector<CVC4::Expr>& sygus_vars,
-                                   std::map< CVC4::Type, CVC4::Type >& sygus_to_builtin,
-                                   std::map< CVC4::Type, CVC4::Expr >& sygus_to_builtin_expr );
-
-  /** make sygus bound var list
+  //------------------------- processing parse operators
+  /**
+   * Given a parse operator p, apply a type ascription to it. This method is run
+   * when we encounter "(as t type)" and information regarding t has been stored
+   * in p.
+   *
+   * This updates p to take into account the ascription. This may include:
+   * - Converting an (pre-ascribed) array constant specification "const" to
+   * an ascribed array constant specification (as const type) where type is
+   * (Array T1 T2) for some T1, T2.
+   * - Converting a (nullary or non-nullary) parametric datatype constructor to
+   * the specialized constructor for the given type.
+   * - Converting an empty set, universe set, or separation nil reference to
+   * the respective term of the given type.
+   * - If p's expression field is set, then we leave p unchanged, check if
+   * that expression has the given type and throw a parse error otherwise.
+   */
+  void parseOpApplyTypeAscription(ParseOp& p, api::Sort type);
+  /**
+   * This converts a ParseOp to expression, assuming it is a standalone term.
    *
-   * This is used for converting non-builtin sygus operators to lambda
-   * expressions. It takes as input a datatype and constructor index (for
-   * naming) and a vector of type ltypes.
-   * It appends a bound variable to lvars for each type in ltypes, and returns
-   * a bound variable list whose children are lvars.
+   * In particular:
+   * - If p's expression field is set, then that expression is returned.
+   * - If p's name field is set, then we look up that name in the symbol table
+   * of this class.
+   * In other cases, a parse error is thrown.
    */
-  Expr makeSygusBoundVarList(Datatype& dt,
-                             unsigned i,
-                             const std::vector<Type>& ltypes,
-                             std::vector<Expr>& lvars);
+  api::Term parseOpToExpr(ParseOp& p);
+  /**
+   * Apply parse operator to list of arguments, and return the resulting
+   * expression.
+   *
+   * This method involves two phases.
+   * (1) Processing the operator represented by p,
+   * (2) Applying that operator to the set of arguments.
+   *
+   * For (1), this involves determining the kind of the overall expression. We
+   * may be in one the following cases:
+   * - If p's expression field is set, we may choose to prepend it to args, or
+   * otherwise determine the appropriate kind of the overall expression based on
+   * this expression.
+   * - If p's name field is set, then we get the appropriate symbol for that
+   * name, which may involve disambiguating that name if it is overloaded based
+   * on the types of args. We then determine the overall kind of the return
+   * expression based on that symbol.
+   * - p's kind field may be already set.
+   *
+   * For (2), we construct the overall expression, which may involve the
+   * following:
+   * - If p is an array constant specification (as const (Array T1 T2)), then
+   * we return the appropriate array constant based on args[0].
+   * - If p represents a tuple selector, then we infer the appropriate tuple
+   * selector expression based on the type of args[0].
+   * - If the overall kind of the expression is chainable, we may convert it
+   * to a left- or right-associative chain.
+   * - If the overall kind is MINUS and args has size 1, then we return an
+   * application of UMINUS.
+   * - If the overall expression is a partial application, then we process this
+   * as a chain of HO_APPLY terms.
+   */
+  api::Term applyParseOp(ParseOp& p, std::vector<api::Term>& args);
+  //------------------------- end processing parse operators
+ private:
 
   void addArithmeticOperators();
 
+  void addTranscendentalOperators();
+
+  void addQuantifiersOperators();
+
   void addBitvectorOperators();
 
+  void addDatatypesOperators();
+
   void addStringOperators();
 
   void addFloatingPointOperators();
 
   void addSepOperators();
 
-  InputLanguage getLanguage() const;
-};/* class Smt2 */
+  /**
+   * Utility function to create a conjunction of expressions.
+   *
+   * @param es Expressions in the conjunction
+   * @return True if `es` is empty, `e` if `es` consists of a single element
+   *         `e`, the conjunction of expressions otherwise.
+   */
+  api::Term mkAnd(const std::vector<api::Term>& es);
+}; /* class Smt2 */
 
-}/* CVC4::parser namespace */
-}/* CVC4 namespace */
+}  // namespace parser
+}  // namespace cvc5
 
-#endif /* __CVC4__PARSER__SMT2_H */
+#endif /* CVC5__PARSER__SMT2_H */