/* Copyright (c) 2016 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Author: Daniel Selsam */ #include #include #include #include #include #include "util/flet.h" #include "util/name_map.h" #include "util/exception.h" #include "util/fresh_name.h" #include "util/lean_path.h" #include "kernel/environment.h" #include "kernel/kernel_exception.h" #include "kernel/abstract.h" #include "kernel/instantiate.h" #include "kernel/error_msgs.h" #include "kernel/declaration.h" #include "kernel/type_checker.h" #include "kernel/expr_maps.h" #include "kernel/pos_info_provider.h" #include "library/app_builder.h" #include "library/constants.h" #include "library/io_state.h" #include "library/io_state_stream.h" #include "library/local_context.h" #include "library/pp_options.h" #include "library/module.h" #include "library/trace.h" #include "library/mpq_macro.h" #include "library/scope_pos_info_provider.h" #include "library/tactic/tactic_state.h" #include "frontends/smt2/scanner.h" #include "frontends/smt2/elaborator.h" #include "frontends/smt2/parser.h" namespace lean { namespace smt2 { static name * g_smt2_unique_prefix; // Reserved words // (a) General // static char const * g_token_as = "as"; static char const * g_token_exists = "exists"; static char const * g_token_forall = "forall"; static char const * g_token_let = "let"; // (b) Command names static char const * g_token_assert = "assert"; static char const * g_token_check_sat = "check-sat"; static char const * g_token_check_sat_assuming = "check-sat-assuming"; static char const * g_token_declare_const = "declare-const"; static char const * g_token_declare_fun = "declare-fun"; static char const * g_token_declare_sort = "declare-sort"; static char const * g_token_define_fun = "define-fun"; static char const * g_token_define_fun_rec = "define-fun-rec"; static char const * g_token_define_funs_rec = "define-fun-rec"; static char const * g_token_define_sort = "define-sort"; static char const * g_token_echo = "echo"; static char const * g_token_exit = "exit"; static char const * g_token_get_assertions = "get-assertions"; static char const * g_token_get_assignment = "get-assignment"; static char const * g_token_get_info = "get-info"; static char const * g_token_get_model = "get-model"; static char const * g_token_get_option = "get-option"; static char const * g_token_get_proof = "get-proof"; static char const * g_token_get_unsat_assumptions = "get-unsat-assumptions"; static char const * g_token_get_unsat_core = "get-unsat-core"; static char const * g_token_get_value = "get-value"; static char const * g_token_pop = "pop"; static char const * g_token_push = "push"; static char const * g_token_reset = "reset"; static char const * g_token_reset_assertions = "reset-assertions"; static char const * g_token_set_info = "set-info"; static char const * g_token_set_logic = "set-logic"; static char const * g_token_set_option = "set-option"; // Making bindings enum class binding_type { FORALL, EXISTS, LET }; expr mk_binding(local_context const & lctx, binding_type btype, unsigned num_locals, expr const * locals, expr const & e) { buffer decls; buffer types; buffer> values; for (unsigned i = 0; i < num_locals; i++) { local_decl const & decl = *lctx.get_local_decl(locals[i]); decls.push_back(decl); types.push_back(::lean::abstract_locals(decl.get_type(), i, locals)); if (auto v = decl.get_value()) values.push_back(some_expr(::lean::abstract_locals(*v, i, locals))); else values.push_back(none_expr()); } expr new_e = ::lean::abstract_locals(e, num_locals, locals); lean_assert(types.size() == values.size()); unsigned i = types.size(); while (i > 0) { --i; switch (btype) { case binding_type::FORALL: lean_assert(!values[i]); new_e = ::lean::mk_pi(decls[i].get_pp_name(), types[i], new_e, decls[i].get_info()); break; case binding_type::EXISTS: lean_assert(!values[i]); // @Exists.{l_1} ?A (λ (x : ?A), @eq.{l_1} ?A x x) : Prop new_e = mk_app(mk_constant(get_Exists_name(), {mk_level_one()}), types[i], ::lean::mk_lambda(decls[i].get_pp_name(), types[i], new_e, decls[i].get_info())); break; case binding_type::LET: lean_assert(values[i]); new_e = mk_let(decls[i].get_pp_name(), types[i], *values[i], new_e); break; } } return new_e; } expr mk_binding(local_context const & lctx, binding_type btype, buffer const & locals, expr const & e) { return mk_binding(lctx, btype, locals.size(), locals.data(), e); } // Parser class class parser : public pos_info_provider { public: // pos_info_provider interface virtual optional get_pos_info(expr const &) const override { return optional(); } virtual char const * get_file_name() const override { return m_scanner.get_stream_name().c_str(); } virtual pos_info get_some_pos() const override { return m_scanner.get_pos_info(); } private: struct exit_exception : public exception {}; environment m_env; io_state m_ios; local_context m_lctx; scanner m_scanner; scanner::token_kind m_curr_kind{scanner::token_kind::BEGIN}; bool m_use_locals{true}; bool m_verbose{false}; type_context * m_tctx_ptr{nullptr}; // Util std::string const & get_stream_name() const { return m_scanner.get_stream_name(); } [[ noreturn ]] void throw_parser_exception(char const * msg, pos_info p) { throw parser_exception(msg, get_stream_name().c_str(), p.first, p.second); } [[ noreturn ]] void throw_parser_exception(std::string const & msg) { throw_parser_exception(msg.c_str(), m_scanner.get_pos_info()); } [[ noreturn ]] void throw_parser_exception(char const * msg) { throw_parser_exception(msg, m_scanner.get_pos_info()); } // Only named constants that are going into the global environment need to // prefixed to avoid clashes void register_hypothesis(symbol const & sym, expr const & ty) { if (m_use_locals) { m_lctx.mk_local_decl(sym, ty); } else { declaration d = mk_axiom(mk_user_name(sym), list(), ty); m_env = env().add(check(env(), d)); } } void register_hypothesis(expr const & ty) { name n = mk_tagged_fresh_name(*g_smt2_unique_prefix); if (m_use_locals) { m_lctx.mk_local_decl(n, ty); } else { declaration d = mk_axiom(n, list(), ty); m_env = env().add(check(env(), d)); } } environment & env() { return m_env; } io_state & ios() { return m_ios; } local_context const & lctx() { return m_tctx_ptr ? m_tctx_ptr->lctx() : m_lctx; } scanner::token_kind curr_kind() const { return m_curr_kind; } std::string const & curr_string() const { return m_scanner.get_str_val(); } symbol const & curr_symbol() const { return m_scanner.get_symbol_val(); } mpq const & curr_numeral() const { return m_scanner.get_num_val(); } mpq curr_numeral_next() { mpq q = m_scanner.get_num_val(); next(); return q; } void scan() { m_curr_kind = m_scanner.scan(); } void next() { if (m_curr_kind != scanner::token_kind::END) scan(); } void check_curr_kind(scanner::token_kind kind, char const * msg) { if (curr_kind() != kind) throw_parser_exception(msg); } void check_curr_kind(scanner::token_kind kind, std::string const & msg) { if (curr_kind() != kind) throw_parser_exception(msg); } // Parser helpers // Parsing sorts void parse_sorted_var_list(buffer & bindings, char const * context) { lean_assert(m_tctx_ptr); check_curr_kind(scanner::token_kind::LEFT_PAREN, std::string(context) + ": sorted-var list expected"); next(); while (curr_kind() == scanner::token_kind::LEFT_PAREN) { next(); check_curr_kind(scanner::token_kind::SYMBOL, std::string(context) + ": invalid sorted-val list"); symbol sym = curr_symbol(); next(); expr ty = parse_expr(context); expr l = m_tctx_ptr->push_local(sym, ty); bindings.push_back(l); check_curr_kind(scanner::token_kind::RIGHT_PAREN, std::string(context) + ": invalid sorted-val list"); next(); } check_curr_kind(scanner::token_kind::RIGHT_PAREN, std::string(context) + ": invalid sorted-val list"); next(); } void parse_var_binding_list(buffer & bindings, char const * context) { lean_assert(m_tctx_ptr); check_curr_kind(scanner::token_kind::LEFT_PAREN, std::string(context) + ": var-binding list expected"); next(); while (curr_kind() == scanner::token_kind::LEFT_PAREN) { next(); check_curr_kind(scanner::token_kind::SYMBOL, std::string(context) + ": invalid var-binding list"); symbol sym = curr_symbol(); next(); expr val = parse_expr(context); expr ty = m_tctx_ptr->infer(val); expr l = m_tctx_ptr->push_let(sym, ty, val); bindings.push_back(l); check_curr_kind(scanner::token_kind::RIGHT_PAREN, std::string(context) + ": invalid var-binding list"); next(); } check_curr_kind(scanner::token_kind::RIGHT_PAREN, std::string(context) + ": invalid var-binding list"); next(); } void parse_attributes(char const * context) { // TODO(dhs): currently ignores all attributes check_curr_kind(scanner::token_kind::KEYWORD, std::string(context) + ": invalid attributes"); while (curr_kind() == scanner::token_kind::KEYWORD) { next(); bool still_in_attribute = true; int num_open_paren = 0; while (still_in_attribute) { switch (curr_kind()) { case scanner::token_kind::SYMBOL: case scanner::token_kind::STRING: case scanner::token_kind::INT: case scanner::token_kind::FLOAT: case scanner::token_kind::BV: next(); break; case scanner::token_kind::LEFT_PAREN: num_open_paren++; next(); break; case scanner::token_kind::RIGHT_PAREN: if (--num_open_paren < 1) still_in_attribute = false; if (num_open_paren >= 0) next(); break; default: still_in_attribute = false; break; } } } } expr parse_expr(char const * context) { symbol sym; buffer args; optional l; switch (curr_kind()) { case scanner::token_kind::SYMBOL: sym = curr_symbol(); next(); l = lctx().get_local_decl_from_user_name(sym); if (l) return l->mk_ref(); else return elaborate_constant(sym); lean_unreachable(); break; case scanner::token_kind::STRING: // TODO(dhs): strings throw_parser_exception("string literals not accepted in expressions yet"); lean_unreachable(); break; case scanner::token_kind::INT: // TODO(dhs): Lean's bv may want a Nat instead of an Int return mk_mpq_macro(curr_numeral_next(), mk_constant(get_int_name())); case scanner::token_kind::FLOAT: return mk_mpq_macro(curr_numeral_next(), mk_constant(get_real_name())); case scanner::token_kind::BV: // TODO(dhs): bit vectors // (Already getting the value in the scanner, just don't have a good Lean target yet) throw_parser_exception("bit-vector literals not accepted in expressions yet"); lean_unreachable(); break; case scanner::token_kind::LEFT_PAREN: next(); if (curr_kind() == scanner::token_kind::SYMBOL && curr_symbol() == "_") { // dependent types next(); parse_exprs(args, context); // Note: there are no dependent applications that require elaboration on their own lean_assert(args.size() > 1); return mk_app(args); } else if (curr_kind() == scanner::token_kind::SYMBOL && curr_symbol() == "!") { // annotated terms next(); expr e = parse_expr(context); parse_attributes(context); check_curr_kind(scanner::token_kind::RIGHT_PAREN, "invalid constant declaration, ')' expected"); next(); return e; } else if (curr_kind() == scanner::token_kind::SYMBOL && curr_symbol() == g_token_forall) { lean_assert(m_tctx_ptr); next(); buffer bindings; parse_sorted_var_list(bindings, context); expr e = parse_expr(context); expr pi = mk_binding(m_tctx_ptr->lctx(), binding_type::FORALL, bindings, e); for (unsigned i = 0; i < bindings.size(); ++i) m_tctx_ptr->pop_local(); check_curr_kind(scanner::token_kind::RIGHT_PAREN, "invalid constant declaration, ')' expected"); next(); return pi; } else if (curr_kind() == scanner::token_kind::SYMBOL && curr_symbol() == g_token_exists) { lean_assert(m_tctx_ptr); next(); buffer bindings; parse_sorted_var_list(bindings, context); expr e = parse_expr(context); expr exists = mk_binding(m_tctx_ptr->lctx(), binding_type::EXISTS, bindings, e); for (unsigned i = 0; i < bindings.size(); ++i) m_tctx_ptr->pop_local(); check_curr_kind(scanner::token_kind::RIGHT_PAREN, "invalid constant declaration, ')' expected"); next(); return exists; } else if (curr_kind() == scanner::token_kind::SYMBOL && curr_symbol() == g_token_let) { lean_assert(m_tctx_ptr); next(); buffer bindings; parse_var_binding_list(bindings, context); expr e = parse_expr(context); expr let = mk_binding(m_tctx_ptr->lctx(), binding_type::LET, bindings, e); for (unsigned i = 0; i < bindings.size(); ++i) m_tctx_ptr->pop_local(); check_curr_kind(scanner::token_kind::RIGHT_PAREN, "invalid constant declaration, ')' expected"); next(); return let; } else { parse_exprs(args, context); // When parsing sorts, we don't bother elaborating applications if (m_tctx_ptr) return elaborate_app(*m_tctx_ptr, args); else return mk_app(args); } default: throw_parser_exception((std::string(context) + ", invalid sort").c_str()); lean_unreachable(); break; } lean_unreachable(); } void parse_exprs(buffer & es, char const * context) { while (curr_kind() != scanner::token_kind::RIGHT_PAREN) { es.push_back(parse_expr(context)); } next(); } void parse_expr_list(buffer & es, char const * context) { check_curr_kind(scanner::token_kind::LEFT_PAREN, context); next(); parse_exprs(es, context); } // Outer loop bool parse_commands() { scan(); // TODO(dhs): for now we will not recover from any errors while (true) { switch (curr_kind()) { case scanner::token_kind::LEFT_PAREN: parse_command(); break; case scanner::token_kind::END: return true; default: throw_parser_exception("invalid command, '(' expected"); break; } } } void parse_command() { lean_assert(curr_kind() == scanner::token_kind::LEFT_PAREN); next(); check_curr_kind(scanner::token_kind::SYMBOL, "invalid command, symbol expected"); std::string const & s = m_scanner.get_str_val(); if (s == g_token_assert) parse_assert(); else if (s == g_token_check_sat) parse_check_sat(); else if (s == g_token_check_sat_assuming) parse_check_sat_assuming(); else if (s == g_token_declare_const) parse_declare_const(); else if (s == g_token_declare_fun) parse_declare_fun(); else if (s == g_token_declare_sort) parse_declare_sort(); else if (s == g_token_define_fun) parse_define_fun(); else if (s == g_token_define_fun_rec) parse_define_fun_rec(); else if (s == g_token_define_funs_rec) parse_define_funs_rec(); else if (s == g_token_define_sort) parse_define_sort(); else if (s == g_token_echo) parse_echo(); else if (s == g_token_exit) parse_exit(); else if (s == g_token_get_assertions) parse_get_assertions(); else if (s == g_token_get_assignment) parse_get_assignment(); else if (s == g_token_get_info) parse_get_info(); else if (s == g_token_get_model) parse_get_model(); else if (s == g_token_get_option) parse_get_option(); else if (s == g_token_get_proof) parse_get_proof(); else if (s == g_token_get_unsat_assumptions) parse_get_unsat_assumptions(); else if (s == g_token_get_unsat_core) parse_get_unsat_core(); else if (s == g_token_get_value) parse_get_value(); else if (s == g_token_pop) parse_pop(); else if (s == g_token_push) parse_push(); else if (s == g_token_reset) parse_reset(); else if (s == g_token_reset_assertions) parse_reset_assertions(); else if (s == g_token_set_info) parse_set_info(); else if (s == g_token_set_logic) parse_set_logic(); else if (s == g_token_set_option) parse_set_option(); else throw_parser_exception(std::string("unknown command: ") + s); } // Individual commands void parse_assert() { lean_assert(curr_kind() == scanner::token_kind::SYMBOL); lean_assert(curr_symbol() == g_token_assert); next(); type_context aux_tctx(m_env, m_ios.get_options(), m_lctx); expr e; { flet parsing_a_term(m_tctx_ptr, &aux_tctx); e = parse_expr("invalid assert command"); } if (m_verbose) ios().get_regular_stream() << "[assert] " << e << "\n"; register_hypothesis(e); check_curr_kind(scanner::token_kind::RIGHT_PAREN, "invalid constant declaration, ')' expected"); next(); } void parse_check_sat() { lean_assert(curr_kind() == scanner::token_kind::SYMBOL); lean_assert(curr_symbol() == g_token_check_sat); next(); metavar_context mctx; expr goal_mvar = mctx.mk_metavar_decl(lctx(), mk_constant(get_false_name())); vm_obj s = to_obj(tactic_state(env(), ios().get_options(), mctx, list(goal_mvar), goal_mvar)); vm_state state(env()); scope_vm_state scope(state); vm_obj result = state.invoke(get_smt_prove_name(), s); if (optional s_new = is_tactic_success(result)) { mctx = s_new->mctx(); expr proof = mctx.instantiate_mvars(goal_mvar); if (has_expr_metavar(proof)) { ios().get_regular_stream() << "\n"; } else { ios().get_regular_stream() << "unsat\n"; } } else { ios().get_regular_stream() << "\n"; } check_curr_kind(scanner::token_kind::RIGHT_PAREN, "invalid constant declaration, ')' expected"); next(); } void parse_check_sat_assuming() { throw_parser_exception("check-sat-assuming not yet supported"); } void parse_declare_const() { lean_assert(curr_kind() == scanner::token_kind::SYMBOL); lean_assert(curr_symbol() == g_token_declare_const); next(); check_curr_kind(scanner::token_kind::SYMBOL, "invalid constant declaration, symbol expected"); symbol sym = curr_symbol(); next(); expr ty = parse_expr("invalid constant declaration"); if (m_verbose) ios().get_regular_stream() << "[declare_const] " << sym << " : " << ty << "\n"; register_hypothesis(sym, ty); check_curr_kind(scanner::token_kind::RIGHT_PAREN, "invalid constant declaration, ')' expected"); next(); } void parse_declare_fun() { lean_assert(curr_kind() == scanner::token_kind::SYMBOL); lean_assert(curr_symbol() == g_token_declare_fun); next(); check_curr_kind(scanner::token_kind::SYMBOL, "invalid function declaration, symbol expected"); symbol sym = curr_symbol(); next(); buffer parameter_sorts; parse_expr_list(parameter_sorts, "invalid function declaration"); expr ty = parse_expr("invalid function declaration"); for (int i = parameter_sorts.size() - 1; i >= 0; --i) { ty = mk_arrow(parameter_sorts[i], ty); } if (m_verbose) ios().get_regular_stream() << "[declare_fun] " << sym << " : " << ty << "\n"; register_hypothesis(sym, ty); check_curr_kind(scanner::token_kind::RIGHT_PAREN, "invalid function declaration, ')' expected"); next(); } void parse_declare_sort() { lean_assert(curr_kind() == scanner::token_kind::SYMBOL); lean_assert(curr_symbol() == g_token_declare_sort); next(); check_curr_kind(scanner::token_kind::SYMBOL, "invalid sort declaration, symbol expected"); symbol sym = curr_symbol(); next(); // Note: the official standard requires the arity, but it seems to be convention to have no arity mean 0 mpq arity; if (curr_kind() == scanner::token_kind::RIGHT_PAREN) { // no arity means 0 } else { check_curr_kind(scanner::token_kind::INT, "invalid sort declaration, arity () expected"); arity = curr_numeral(); // TODO(dhs): the standard does not put a limit on the arity, but a parametric sort that takes more than ten-thousand arguments is absurd // (arbitrary) if (arity > 10000) { throw_parser_exception("invalid sort declaration, arities greater than 10,000 not supported"); } next(); } expr ty = mk_Type(); for (unsigned i = 0; i < arity; ++i) { ty = mk_arrow(mk_Type(), ty); } if (m_verbose) ios().get_regular_stream() << "[declare_sort] " << sym << " : " << ty << "\n"; register_hypothesis(sym, ty); check_curr_kind(scanner::token_kind::RIGHT_PAREN, "invalid sort declaration, ')' expected"); next(); } void parse_define_fun() { throw_parser_exception("define-fun not yet supported"); } void parse_define_fun_rec() { throw_parser_exception("define-fun-rec not yet supported"); } void parse_define_funs_rec() { throw_parser_exception("define-funs-rec not yet supported"); } void parse_define_sort() { throw_parser_exception("define-sort not yet supported"); } void parse_echo() { throw_parser_exception("echo not yet supported"); } void parse_exit() { lean_assert(curr_kind() == scanner::token_kind::SYMBOL); lean_assert(curr_symbol() == g_token_exit); next(); check_curr_kind(scanner::token_kind::RIGHT_PAREN, "invalid exit, ')' expected"); next(); throw exit_exception(); } void parse_get_assertions() { throw_parser_exception("get-assertions not yet supported"); } void parse_get_assignment() { throw_parser_exception("get-assignment not yet supported"); } void parse_get_info() { throw_parser_exception("get-info not yet supported"); } void parse_get_model() { throw_parser_exception("get-model not yet supported"); } void parse_get_option() { throw_parser_exception("get-option not yet supported"); } void parse_get_proof() { throw_parser_exception("get-proof not yet supported"); } void parse_get_unsat_assumptions() { throw_parser_exception("get-unsat-assumptions not yet supported"); } void parse_get_unsat_core() { throw_parser_exception("get-unsat-core not yet supported"); } void parse_get_value() { throw_parser_exception("get-value not yet supported"); } void parse_pop() { throw_parser_exception("pop not yet supported"); } void parse_push() { throw_parser_exception("push not yet supported"); } void parse_reset() { throw_parser_exception("reset not yet supported"); } void parse_reset_assertions() { throw_parser_exception("reset-assertions not yet supported"); } void parse_set_info() { lean_assert(curr_kind() == scanner::token_kind::SYMBOL); lean_assert(curr_symbol() == g_token_set_info); next(); parse_attributes("set-info"); // only one attribute is okay check_curr_kind(scanner::token_kind::RIGHT_PAREN, "invalid set-info, ')' expected"); next(); } void parse_set_logic() { // Currently ignored (we deduce the logic automatically) lean_assert(curr_kind() == scanner::token_kind::SYMBOL); lean_assert(curr_symbol() == g_token_set_logic); next(); check_curr_kind(scanner::token_kind::SYMBOL, "invalid set-logic command, symbol expected"); symbol sym = curr_symbol(); next(); check_curr_kind(scanner::token_kind::RIGHT_PAREN, "invalid set-logic, ')' expected"); next(); } void parse_set_option() { lean_assert(curr_kind() == scanner::token_kind::SYMBOL); lean_assert(curr_symbol() == g_token_set_option); next(); check_curr_kind(scanner::token_kind::KEYWORD, "invalid set-option command, keyword expected"); symbol sym = curr_symbol(); next(); if (sym == ":use_locals") { m_use_locals = true; } else if (sym == ":verbose") { check_curr_kind(scanner::token_kind::SYMBOL, "invalid set-option command, option ':verbose' requires argument 'true' or 'false'"); symbol val = curr_symbol(); next(); if (val == "true") m_verbose = true; else if (val == "false") m_verbose = false; else throw_parser_exception("invalid set-option command, option ':verbose' requires argument 'true' or 'false'"); } else if (sym == ":lbool") { check_curr_kind(scanner::token_kind::SYMBOL, "invalid set-option, 'true' or 'false' expected"); symbol tf = curr_symbol(); next(); bool status; if (tf == "true") status = true; else if (tf == "false") status = false; else throw_parser_exception("invalid set-option command, option ':lbool' requires next argument 'true' or 'false'"); name n; while (curr_kind() == scanner::token_kind::SYMBOL) { symbol sym = curr_symbol(); next(); n = name(n, sym.c_str()); } lean_assert(!n.is_anonymous()); m_ios.set_option(n, status); } else if (sym == ":lnat") { check_curr_kind(scanner::token_kind::INT, "invalid set-option, option ':lnat` " "requires next argument to be a numeral"); unsigned val = curr_numeral().get_numerator().get_unsigned_int(); next(); name n; while (curr_kind() == scanner::token_kind::SYMBOL) { symbol sym = curr_symbol(); next(); n = name(n, sym.c_str()); } lean_assert(!n.is_anonymous()); m_ios.set_option(n, val); } else { // TODO(dhs): just a warning? throw_parser_exception(std::string("unsupported option: ") + sym); } check_curr_kind(scanner::token_kind::RIGHT_PAREN, "invalid set-option, ')' expected"); next(); } public: // Constructor parser(environment const & env, io_state & ios, std::istream & strm, char const * strm_name): m_env(env), m_ios(ios), m_scanner(strm, strm_name) {} // Entry point bool operator()() { scoped_expr_caching disable(false); scoped_set_distinguishing_pp_options set(get_distinguishing_pp_options()); buffer olean_files; std::string base = dirname(get_stream_name().c_str()); optional k; olean_files.push_back(module_name(k, name("init"))); olean_files.push_back(module_name(k, name("smt"))); unsigned num_threads = 0; bool keep_imported_theorems = false; m_env = import_modules(m_env, base, olean_files.size(), olean_files.data(), num_threads, keep_imported_theorems, m_ios); bool ok = true; try { parse_commands(); } catch (exit_exception const & ex) { return ok; } catch (throwable const & ex) { ok = false; ::lean::message_builder(this, std::make_shared(m_env, m_ios.get_options(), m_lctx), m_env, m_ios, get_file_name(), get_some_pos(), ERROR) .set_exception(ex).report(); } return ok; } }; // Setup and teardown void initialize_parser() { g_smt2_unique_prefix = new name(name::mk_internal_unique_name()); } void finalize_parser() { delete g_smt2_unique_prefix; } // Entry point bool parse_commands(environment & env, io_state & ios, char const * fname) { std::ifstream in(fname); if (in.bad() || in.fail()) throw exception(sstream() << "failed to open file '" << fname << "'"); parser p(env, ios, in, fname); return p(); } }}