lean4-htt/src/frontends/smt2/parser.cpp
2016-10-13 18:49:10 -07:00

744 lines
31 KiB
C++

/*
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Daniel Selsam
*/
#include <string>
#include <stack>
#include <utility>
#include <vector>
#include <library/message_builder.h>
#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<local_decl> decls;
buffer<expr> types;
buffer<optional<expr>> 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<expr> 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<pos_info> get_pos_info(expr const &) const override { return optional<pos_info>(); }
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<name>(), 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<name>(), 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<expr> & 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<expr> & 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<expr> args;
optional<local_decl> 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<expr> 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<expr> 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<expr> 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<expr> & es, char const * context) {
while (curr_kind() != scanner::token_kind::RIGHT_PAREN) {
es.push_back(parse_expr(context));
}
next();
}
void parse_expr_list(buffer<expr> & 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<type_context *> 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<expr>(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<tactic_state> 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() << "<tactic succeeded but left metavars>\n";
} else {
ios().get_regular_stream() << "unsat\n";
}
} else {
ios().get_regular_stream() << "<tactic failed>\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<expr> 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 (<numeral>) 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<module_name> olean_files;
std::string base = dirname(get_stream_name().c_str());
optional<unsigned> 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<type_context>(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();
}
}}