2014-07-03 03:45:10 +00:00
|
|
|
/*
|
|
|
|
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
|
|
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
|
|
|
|
Author: Leonardo de Moura
|
|
|
|
*/
|
|
|
|
#include <string>
|
|
|
|
#include "kernel/type_checker.h"
|
|
|
|
#include "library/scoped_ext.h"
|
|
|
|
#include "library/kernel_serializer.h"
|
|
|
|
#include "library/tactic/expr_to_tactic.h"
|
|
|
|
#include "frontends/lean/parser.h"
|
2014-07-08 21:28:33 +00:00
|
|
|
#include "frontends/lean/tactic_hint.h"
|
2014-07-03 03:45:10 +00:00
|
|
|
|
|
|
|
namespace lean {
|
|
|
|
// This (scoped) environment extension allows us to set a tactic to be applied before every element
|
2014-08-21 17:36:44 +00:00
|
|
|
// in a <tt>begin ... end</tt> block
|
|
|
|
struct be_entry {
|
2014-07-03 03:45:10 +00:00
|
|
|
bool m_accumulate; // if true, then accumulate the new tactic, if false replace
|
|
|
|
expr m_tac;
|
2014-08-21 17:36:44 +00:00
|
|
|
be_entry():m_accumulate(false) {}
|
|
|
|
be_entry(bool a, expr const & t):m_accumulate(a), m_tac(t) {}
|
2014-07-03 03:45:10 +00:00
|
|
|
};
|
|
|
|
|
2014-08-21 17:36:44 +00:00
|
|
|
struct be_state {
|
2014-07-03 03:45:10 +00:00
|
|
|
optional<expr> m_pre_tac;
|
|
|
|
optional<expr> m_pre_tac_body;
|
|
|
|
};
|
|
|
|
|
2014-09-23 00:30:29 +00:00
|
|
|
static name * g_class_name = nullptr;
|
|
|
|
static std::string * g_key = nullptr;
|
|
|
|
|
2014-08-21 17:36:44 +00:00
|
|
|
struct be_config {
|
|
|
|
typedef be_state state;
|
|
|
|
typedef be_entry entry;
|
2014-07-03 03:45:10 +00:00
|
|
|
static void add_entry(environment const &, io_state const &, state & s, entry const & e) {
|
|
|
|
if (e.m_accumulate) {
|
|
|
|
if (s.m_pre_tac_body)
|
|
|
|
s.m_pre_tac_body = mk_app(get_or_else_tac_fn(), *s.m_pre_tac_body, e.m_tac);
|
|
|
|
else
|
|
|
|
s.m_pre_tac_body = e.m_tac;
|
|
|
|
s.m_pre_tac = mk_app(get_repeat_tac_fn(), *s.m_pre_tac_body);
|
|
|
|
} else {
|
|
|
|
// reset
|
|
|
|
s.m_pre_tac = e.m_tac;
|
|
|
|
s.m_pre_tac_body = e.m_tac;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
static name const & get_class_name() {
|
2014-09-23 00:30:29 +00:00
|
|
|
return *g_class_name;
|
2014-07-03 03:45:10 +00:00
|
|
|
}
|
|
|
|
static std::string const & get_serialization_key() {
|
2014-09-23 00:30:29 +00:00
|
|
|
return *g_key;
|
2014-07-03 03:45:10 +00:00
|
|
|
}
|
|
|
|
static void write_entry(serializer & s, entry const & e) {
|
|
|
|
s << e.m_accumulate << e.m_tac;
|
|
|
|
}
|
|
|
|
static entry read_entry(deserializer & d) {
|
|
|
|
entry e;
|
|
|
|
d >> e.m_accumulate >> e.m_tac;
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
};
|
|
|
|
|
2014-08-21 17:36:44 +00:00
|
|
|
template class scoped_ext<be_config>;
|
|
|
|
typedef scoped_ext<be_config> begin_end_ext;
|
2014-07-03 03:45:10 +00:00
|
|
|
|
2014-09-23 00:30:29 +00:00
|
|
|
void initialize_begin_end_ext() {
|
|
|
|
g_class_name = new name("begin_end");
|
|
|
|
g_key = new std::string("be_pre_tac");
|
|
|
|
begin_end_ext::initialize();
|
|
|
|
}
|
|
|
|
|
|
|
|
void finalize_begin_end_ext() {
|
|
|
|
begin_end_ext::finalize();
|
|
|
|
delete g_key;
|
|
|
|
delete g_class_name;
|
|
|
|
}
|
|
|
|
|
2014-07-03 03:45:10 +00:00
|
|
|
static void check_valid_tactic(environment const & env, expr const & pre_tac) {
|
|
|
|
type_checker tc(env);
|
2014-08-20 05:31:26 +00:00
|
|
|
if (!tc.is_def_eq(tc.infer(pre_tac).first, get_tactic_type()).first)
|
2014-08-21 17:36:44 +00:00
|
|
|
throw exception("invalid begin-end pre-tactic update, argument is not a tactic");
|
2014-07-03 03:45:10 +00:00
|
|
|
}
|
|
|
|
|
2014-08-21 17:36:44 +00:00
|
|
|
environment add_begin_end_pre_tactic(environment const & env, expr const & pre_tac) {
|
2014-07-03 03:45:10 +00:00
|
|
|
check_valid_tactic(env, pre_tac);
|
2014-08-21 17:36:44 +00:00
|
|
|
return begin_end_ext::add_entry(env, get_dummy_ios(), be_entry(true, pre_tac));
|
2014-07-03 03:45:10 +00:00
|
|
|
}
|
|
|
|
|
2014-08-21 17:36:44 +00:00
|
|
|
environment set_begin_end_pre_tactic(environment const & env, expr const & pre_tac) {
|
2014-07-03 03:45:10 +00:00
|
|
|
check_valid_tactic(env, pre_tac);
|
2014-08-21 17:36:44 +00:00
|
|
|
return begin_end_ext::add_entry(env, get_dummy_ios(), be_entry(false, pre_tac));
|
2014-07-03 03:45:10 +00:00
|
|
|
}
|
|
|
|
|
2014-08-21 17:36:44 +00:00
|
|
|
optional<expr> get_begin_end_pre_tactic(environment const & env) {
|
|
|
|
be_state const & s = begin_end_ext::get_state(env);
|
2014-07-03 03:45:10 +00:00
|
|
|
return s.m_pre_tac;
|
|
|
|
}
|
|
|
|
|
2014-08-21 17:36:44 +00:00
|
|
|
environment add_begin_end_cmd(parser & p) {
|
|
|
|
return add_begin_end_pre_tactic(p.env(), parse_tactic_name(p));
|
2014-07-03 03:45:10 +00:00
|
|
|
}
|
|
|
|
|
2014-08-21 17:36:44 +00:00
|
|
|
environment set_begin_end_cmd(parser & p) {
|
|
|
|
return set_begin_end_pre_tactic(p.env(), parse_tactic_name(p));
|
2014-07-03 03:45:10 +00:00
|
|
|
}
|
|
|
|
|
2014-08-21 17:36:44 +00:00
|
|
|
void register_begin_end_cmds(cmd_table & r) {
|
|
|
|
add_cmd(r, cmd_info("add_begin_end_tactic", "add a new tactic to be automatically applied before every component in a 'begin-end' block",
|
|
|
|
add_begin_end_cmd));
|
|
|
|
add_cmd(r, cmd_info("set_begin_end_tactic", "reset the tactic that is automatically applied before every component in a 'begin-end' block",
|
|
|
|
set_begin_end_cmd));
|
2014-07-03 03:45:10 +00:00
|
|
|
}
|
|
|
|
}
|