chore(library/old_tactic/tactic): remove dead code

This commit is contained in:
Leonardo de Moura 2016-07-16 13:37:54 -04:00
parent a30603405c
commit e945db8306
10 changed files with 0 additions and 1107 deletions

View file

@ -1,81 +0,0 @@
/*
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#include "util/lazy_list_fn.h"
#include "util/fresh_name.h"
#include "kernel/type_checker.h"
#include "kernel/error_msgs.h"
#include "library/constants.h"
#include "library/reducible.h"
#include "library/unifier.h"
#include "library/tactic/tactic.h"
#include "library/tactic/elaborate.h"
#include "library/tactic/expr_to_tactic.h"
namespace lean {
tactic change_goal_tactic(elaborate_fn const & elab, expr const & e) {
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) {
proof_state new_s = s;
goals const & gs = new_s.get_goals();
if (!gs) {
throw_no_goal_if_enabled(s);
return proof_state_seq();
}
expr t = head(gs).get_type();
bool report_unassigned = true;
if (auto new_e = elaborate_with_respect_to(env, ios, elab, new_s, e, none_expr(), report_unassigned)) {
goals const & gs = new_s.get_goals();
goal const & g = head(gs);
substitution subst = new_s.get_subst();
auto tc = mk_type_checker(env);
constraint_seq cs;
if (tc->is_def_eq(t, *new_e, justification(), cs)) {
if (cs) {
unifier_config cfg(ios.get_options());
buffer<constraint> cs_buf;
cs.linearize(cs_buf);
to_buffer(new_s.get_postponed(), cs_buf);
unify_result_seq rseq = unify(env, cs_buf.size(), cs_buf.data(), subst, cfg);
return map2<proof_state>(rseq, [=](pair<substitution, constraints> const & p) -> proof_state {
substitution const & subst = p.first;
constraints const & postponed = p.second;
substitution new_subst = subst;
expr final_e = new_subst.instantiate_all(*new_e);
expr M = g.mk_meta(mk_fresh_name(), final_e);
goal new_g(M, final_e);
assign(new_subst, g, M);
return proof_state(new_s, cons(new_g, tail(gs)), new_subst, postponed);
});
}
expr M = g.mk_meta(mk_fresh_name(), *new_e);
goal new_g(M, *new_e);
assign(subst, g, M);
return proof_state_seq(proof_state(new_s, cons(new_g, tail(gs)), subst));
} else {
throw_tactic_exception_if_enabled(new_s, [=](formatter const & fmt) {
format r = format("invalid 'change' tactic, the given type");
r += pp_indent_expr(fmt, *new_e);
r += compose(line(), format("does not match the goal type"));
r += pp_indent_expr(fmt, t);
return r;
});
return proof_state_seq();
}
}
return proof_state_seq();
});
}
void initialize_change_tactic() {
register_tac(get_tactic_change_name(),
[](old_type_checker &, elaborate_fn const & fn, expr const & e, pos_info_provider const *) {
check_tactic_expr(app_arg(e), "invalid 'change' tactic, invalid argument");
return change_goal_tactic(fn, get_tactic_expr_expr(app_arg(e)));
});
}
void finalize_change_tactic() {
}
}

View file

@ -1,13 +0,0 @@
/*
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#pragma once
#include "library/tactic/tactic.h"
namespace lean {
void initialize_change_tactic();
void finalize_change_tactic();
}

View file

@ -1,286 +0,0 @@
/*
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#include <algorithm>
#include "util/fresh_name.h"
#include "kernel/abstract.h"
#include "kernel/instantiate.h"
#include "library/util.h"
#include "library/locals.h"
#include "library/constants.h"
#include "library/reducible.h"
#include "library/class_instance_resolution.h"
#include "library/tactic/util.h"
#include "library/tactic/intros_tactic.h"
#include "library/tactic/subst_tactic.h"
#include "library/tactic/expr_to_tactic.h"
namespace lean {
enum class congr_arg_kind { Fixed, Singleton, Eq };
optional<expr> mk_congr_subsingleton_thm(old_type_checker & tc, io_state const & ios, expr const & fn, optional<unsigned> const & expected_num_args,
buffer<congr_arg_kind> & arg_kinds, constraint_seq & cs) {
expr fn_type = tc.infer(fn, cs);
buffer<expr> hyps;
collected_locals ctx_buffer;
collect_locals(fn_type, ctx_buffer);
collect_locals(fn, ctx_buffer);
hyps.append(ctx_buffer.get_collected());
list<expr> ctx = to_list(hyps);
buffer<expr> domain;
expr codomain = to_telescope(tc, fn_type, domain, optional<binder_info>(), cs);
if (expected_num_args && *expected_num_args != domain.size()) {
if (*expected_num_args > domain.size())
return none_expr();
lean_assert(*expected_num_args < domain.size());
while (domain.size() > *expected_num_args) {
codomain = Pi(domain.back(), codomain);
domain.pop_back();
}
}
buffer<bool> prop; // pp[i] iff i-th arg is a proposition
buffer<bool> ss; // ss[i] is not none iff i-th arg is a subsingleton
buffer<bool> codomain_deps_on; // codomain_deps_on[i] iff codomain depends on i-th argument
for (expr const & d : domain) {
prop.push_back(tc.is_prop(mlocal_type(d), cs) && tc.env().prop_proof_irrel());
if (prop.back()) {
ss.push_back(true);
} else {
ss.push_back(static_cast<bool>(mk_subsingleton_instance(tc.env(), ios.get_options(), ctx, mlocal_type(d))));
}
codomain_deps_on.push_back(depends_on(codomain, d));
ctx = cons(d, ctx);
}
buffer<expr> new_domain;
buffer<expr> conclusion_lhs;
for (unsigned i = 0; i < domain.size(); i++) {
lean_assert(i == new_domain.size());
expr const & d_i = domain[i];
expr new_type = replace_locals(mlocal_type(d_i), i, domain.data(), new_domain.data());
expr new_d_i = mk_local(get_unused_name(local_pp_name(d_i), hyps), new_type);
hyps.push_back(new_d_i);
conclusion_lhs.push_back(new_d_i);
new_domain.push_back(new_d_i);
}
buffer<expr> lhss, rhss;
buffer<optional<expr>> eqs;
buffer<bool> ss_elim; // true if equality proof should be synthesized using singletion elimination
buffer<expr> conclusion_rhs;
name h("he");
unsigned eqidx = 1;
for (unsigned i = 0; i < new_domain.size(); i++) {
expr const & d_i = new_domain[i];
if (ss[i]) {
arg_kinds.push_back(congr_arg_kind::Singleton);
expr new_type = replace_locals(mlocal_type(d_i), rhss, lhss);
expr new_d_i = mk_local(get_unused_name(local_pp_name(d_i).append_after("new"), hyps), new_type);
hyps.push_back(new_d_i);
rhss.push_back(d_i);
lhss.push_back(new_d_i);
conclusion_rhs.push_back(new_d_i);
ss_elim.push_back(!prop[i]);
eqs.push_back(none_expr());
} else {
unsigned j = i+1;
for (; j < new_domain.size(); j++) {
expr t_j = mlocal_type(new_domain[j]);
if (depends_on(t_j, d_i) && !ss[j])
break;
}
if (j < new_domain.size() || codomain_deps_on[i]) {
arg_kinds.push_back(congr_arg_kind::Fixed);
conclusion_rhs.push_back(d_i);
} else {
arg_kinds.push_back(congr_arg_kind::Eq);
expr new_type = replace_locals(mlocal_type(d_i), rhss, lhss);
expr new_d_i = mk_local(get_unused_name(local_pp_name(d_i).append_after("new"), hyps), new_type);
name new_h_name = get_unused_name(name(h, eqidx), hyps);
eqidx++;
expr new_eq = mk_local(new_h_name, mk_eq(tc, new_d_i, d_i));
hyps.push_back(new_d_i);
rhss.push_back(d_i);
lhss.push_back(new_d_i);
conclusion_rhs.push_back(new_d_i);
ss_elim.push_back(false);
eqs.push_back(some_expr(new_eq));
}
}
}
for (optional<expr> const & eq : eqs) {
if (eq)
hyps.push_back(*eq);
}
expr conclusion = mk_eq(tc, mk_app(fn, conclusion_lhs), mk_app(fn, conclusion_rhs));
expr mvar_type = Pi(hyps, conclusion);
expr mvar = mk_metavar(mk_fresh_name(), mvar_type);
expr meta = mk_app(mvar, hyps);
proof_state ps = to_proof_state(meta, conclusion).update_report_failure(false);
for (unsigned i = 0; i < eqs.size(); i++) {
goal const & g = head(ps.get_goals());
optional<expr> const & eq = eqs[i];
if (eq) {
auto new_eq = g.find_hyp(local_pp_name(*eq));
if (auto new_ps = subst(tc.env(), mlocal_name(new_eq->first), false, ps)) {
ps = *new_ps;
} else {
return none_expr();
}
} else if (ss_elim[i]) {
expr lhs = lhss[i];
expr rhs = rhss[i];
expr new_lhs, new_rhs;
if (auto it = g.find_hyp(local_pp_name(lhs)))
new_lhs = it->first;
else
return none_expr();
if (auto it = g.find_hyp(local_pp_name(rhs)))
new_rhs = it->first;
else
return none_expr();
buffer<expr> hyps;
g.get_hyps(hyps);
auto spr = mk_subsingleton_instance(tc.env(), ios.get_options(), to_list(hyps), mlocal_type(new_lhs));
if (!spr)
return none_expr();
expr new_eq = mk_local(get_unused_name(name(h, eqidx), hyps), mk_eq(tc, new_rhs, new_lhs));
eqidx++;
expr new_eq_pr = mk_subsingleton_elim(tc, *spr, new_rhs, new_lhs);
expr aux_mvar = mk_metavar(mk_fresh_name(), Pi(hyps, g.get_type()));
expr aux_meta_core = mk_app(aux_mvar, hyps);
goal aux_g(mk_app(aux_meta_core, new_eq), g.get_type());
substitution new_subst = ps.get_subst();
assign(new_subst, g, mk_app(aux_meta_core, new_eq_pr));
proof_state aux_ps = proof_state(ps, goals(aux_g), new_subst);
if (auto new_ps = subst(tc.env(), mlocal_name(new_eq), false, aux_ps)) {
ps = *new_ps;
} else {
return none_expr();
}
} else {
// do nothing, it is a proposition
}
}
substitution subst = ps.get_subst();
goal const & g = head(ps.get_goals());
assign(subst, g, mk_refl(tc, app_arg(g.get_type())));
expr result = subst.instantiate_all(mvar);
try {
check_term(tc, result);
} catch (exception &) {
return none_expr();
}
for (expr const & ctx_local : ctx_buffer.get_collected()) {
result = mk_app(result, ctx_local);
mvar_type = instantiate(binding_body(mvar_type), ctx_local);
}
result = head_beta_reduce(result);
return some_expr(result);
}
tactic congruence_tactic() {
auto fn = [=](environment const & env, io_state const & ios, proof_state const & s) -> optional<proof_state> {
goals const & gs = s.get_goals();
if (empty(gs)) {
throw_no_goal_if_enabled(s);
return none_proof_state();
}
goal const & g = head(gs);
expr t = g.get_type();
substitution subst = s.get_subst();
auto tc = mk_type_checker(env);
constraint_seq cs;
t = tc->whnf(t, cs);
expr lhs, rhs;
if (!is_eq(t, lhs, rhs)) {
throw_tactic_exception_if_enabled(s, "invalid 'congruence' tactic, goal is not an equality");
return none_proof_state();
}
if (!is_app(lhs) || !is_app(rhs)) {
throw_tactic_exception_if_enabled(s, "invalid 'congruence' tactic, left and right hand side of equation must be a function application");
return none_proof_state();
}
buffer<expr> lhs_args, rhs_args;
expr lhs_fn = get_app_args(lhs, lhs_args);
expr rhs_fn = get_app_args(rhs, rhs_args);
if (lhs_args.size() != rhs_args.size()) {
throw_tactic_exception_if_enabled(s, "invalid 'congruence' tactic, left and right hand side of equation must have the same number of arguments");
return none_proof_state();
}
expr lhs_fn_type = tc->whnf(tc->infer(lhs_fn, cs), cs);
expr rhs_fn_type = tc->whnf(tc->infer(rhs_fn, cs), cs);
if (!tc->is_def_eq(lhs_fn_type, rhs_fn_type, justification(), cs)) {
throw_tactic_exception_if_enabled(s, "invalid 'congruence' tactic, functions do not have the same type");
return none_proof_state();
}
buffer<goal> new_goals;
optional<expr> fn_pr;
if (!tc->is_def_eq(lhs_fn, rhs_fn, justification(), cs)) {
expr new_type = mk_eq(*tc, lhs_fn, rhs_fn);
expr new_meta = g.mk_meta(mk_fresh_name(), new_type);
new_goals.push_back(goal(new_meta, new_type));
fn_pr = new_meta;
}
buffer<congr_arg_kind> arg_kinds;
auto cg_proof = mk_congr_subsingleton_thm(*tc, ios, lhs_fn, some(lhs_args.size()), arg_kinds, cs);
if (!cg_proof) {
throw_tactic_exception_if_enabled(s, "invalid 'congruence' tactic, tactic does not support this kind of dependent function");
return none_proof_state();
}
expr pr = mk_app(*cg_proof, lhs_args);
for (unsigned i = 0; i < arg_kinds.size(); i++) {
if (arg_kinds[i] == congr_arg_kind::Fixed) {
if (!tc->is_def_eq(lhs_args[i], rhs_args[i], justification(), cs)) {
throw_tactic_exception_if_enabled(s, sstream() << "invalid 'congruence' tactic, argument #" << (i+1)
<< " must be the same in the left and right hand sides");
return none_proof_state();
}
} else {
pr = mk_app(pr, rhs_args[i]);
}
}
for (unsigned i = 0; i < arg_kinds.size(); i++) {
if (arg_kinds[i] == congr_arg_kind::Eq) {
if (tc->is_def_eq(lhs_args[i], rhs_args[i], justification(), cs)) {
pr = mk_app(pr, mk_refl(*tc, lhs_args[i]));
} else {
expr new_type = mk_eq(*tc, lhs_args[i], rhs_args[i]);
expr new_meta = g.mk_meta(mk_fresh_name(), new_type);
new_goals.push_back(goal(new_meta, new_type));
pr = mk_app(pr, mk_symm(*tc, new_meta));
}
}
}
if (fn_pr) {
expr motive_rhs = mk_app(mk_var(0), rhs_args);
expr motive = mk_lambda("f", lhs_fn_type, mk_app(app_fn(app_fn(g.get_type())), lhs, motive_rhs));
pr = mk_subst(*tc, motive, lhs_fn, rhs_fn, *fn_pr, pr);
}
assign(subst, g, pr);
proof_state new_ps(s, to_list(new_goals.begin(), new_goals.end(), tail(gs)), subst);
if (solve_constraints(env, ios, new_ps, cs))
return some_proof_state(new_ps);
return none_proof_state();
};
return tactic01(fn);
}
void initialize_congruence_tactic() { register_simple_tac(name{"tactic", "congruence"}, congruence_tactic); }
void finalize_congruence_tactic() {}
}

View file

@ -1,16 +0,0 @@
/*
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#pragma once
#include "kernel/type_checker.h"
namespace lean {
enum class congr_arg_kind { Fixed, Singleton, Eq };
optional<expr> mk_congr_subsingleton_thm(type_checker & tc, io_state const & ios,
expr const & fn, optional<unsigned> const & expected_num_args,
buffer<congr_arg_kind> & arg_kinds, constraint_seq & cs);
void initialize_congruence_tactic();
void finalize_congruence_tactic();
}

View file

@ -1,450 +0,0 @@
/*
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 <unordered_map>
#include <string>
#include "util/sstream.h"
#include "util/optional.h"
#include "kernel/instantiate.h"
#include "library/annotation.h"
#include "library/string.h"
#include "library/explicit.h"
#include "library/placeholder.h"
#include "library/old_type_checker.h"
#include "library/num.h"
#include "library/constants.h"
#include "library/projection.h"
#include "library/kernel_serializer.h"
#include "library/tactic/expr_to_tactic.h"
namespace lean {
static expr * g_and_then_tac_fn = nullptr;
static expr * g_or_else_tac_fn = nullptr;
static expr * g_id_tac_fn = nullptr;
static expr * g_repeat_tac_fn = nullptr;
static expr * g_determ_tac_fn = nullptr;
static expr * g_tac_type = nullptr;
static expr * g_builtin_tac = nullptr;
static expr * g_fixpoint_tac = nullptr;
expr const & get_and_then_tac_fn() { return *g_and_then_tac_fn; }
expr const & get_or_else_tac_fn() { return *g_or_else_tac_fn; }
expr const & get_id_tac_fn() { return *g_id_tac_fn; }
expr const & get_determ_tac_fn() { return *g_determ_tac_fn; }
expr const & get_repeat_tac_fn() { return *g_repeat_tac_fn; }
expr const & get_tactic_type() { return *g_tac_type; }
expr const & get_builtin_tac() { return *g_builtin_tac; }
typedef std::unordered_map<name, expr_to_tactic_fn, name_hash, name_eq> expr_to_tactic_map;
static expr_to_tactic_map * g_map = nullptr;
expr_to_tactic_map & get_expr_to_tactic_map() {
return *g_map;
}
void register_tac(name const & n, expr_to_tactic_fn const & fn) {
get_expr_to_tactic_map().insert(mk_pair(n, fn));
}
bool has_tactic_decls(environment const & env) {
try {
old_type_checker tc(env);
return
tc.infer(*g_builtin_tac).first == *g_tac_type &&
tc.infer(*g_and_then_tac_fn).first == *g_tac_type >> (*g_tac_type >> *g_tac_type) &&
tc.infer(*g_or_else_tac_fn).first == *g_tac_type >> (*g_tac_type >> *g_tac_type) &&
tc.infer(*g_repeat_tac_fn).first == *g_tac_type >> *g_tac_type;
} catch (exception &) {
return false;
}
}
static expr * g_tactic_expr_type = nullptr;
static expr * g_tactic_expr_builtin = nullptr;
static expr * g_tactic_expr_list_type = nullptr;
static expr * g_tactic_identifier_type = nullptr;
static expr * g_tactic_using_expr_type = nullptr;
static expr * g_tactic_location_type = nullptr;
static expr * g_tactic_with_expr_type = nullptr;
expr const & get_tactic_expr_type() { return *g_tactic_expr_type; }
expr const & get_tactic_expr_builtin() { return *g_tactic_expr_builtin; }
expr const & get_tactic_expr_list_type() { return *g_tactic_expr_list_type; }
expr const & get_tactic_identifier_type() { return *g_tactic_identifier_type; }
expr const & get_tactic_using_expr_type() { return *g_tactic_using_expr_type; }
expr const & get_tactic_location_type() { return *g_tactic_location_type; }
expr const & get_tactic_with_expr_type() { return *g_tactic_with_expr_type; }
static std::string * g_tactic_expr_opcode = nullptr;
static std::string * g_tactic_opcode = nullptr;
std::string const & get_tactic_expr_opcode() { return *g_tactic_expr_opcode; }
std::string const & get_tactic_opcode() { return *g_tactic_opcode; }
class tactic_expr_macro_definition_cell : public macro_definition_cell {
public:
tactic_expr_macro_definition_cell() {}
virtual name get_name() const { return get_tactic_expr_name(); }
virtual expr check_type(expr const &, abstract_type_context &, bool) const {
return get_tactic_expr_type();
}
virtual optional<expr> expand(expr const &, abstract_type_context &) const {
return some_expr(get_tactic_expr_builtin());
}
virtual void write(serializer & s) const {
s.write_string(get_tactic_expr_opcode());
}
};
static macro_definition * g_tactic_expr_macro = nullptr;
expr mk_tactic_expr(expr const & e) {
return mk_macro(*g_tactic_expr_macro, 1, &e, e.get_tag());
}
bool is_tactic_expr(expr const & e) {
return is_macro(e) && macro_def(e).get_name() == get_tactic_expr_name();
}
expr const & get_tactic_expr_expr(expr const & e) {
lean_assert(is_tactic_expr(e));
expr const * it = &e;
while (is_tactic_expr(*it))
it = &macro_arg(*it, 0);
return *it;
}
void check_tactic_expr(expr const & e, char const * error_msg) {
if (!is_tactic_expr(e))
throw expr_to_tactic_exception(e, error_msg);
}
name const & tactic_expr_to_id(expr e, char const * error_msg) {
if (is_tactic_expr(e))
e = get_tactic_expr_expr(e);
if (is_constant(e)) {
return const_name(e);
} else if (is_local(e)) {
return local_pp_name(e);
} else if (is_as_atomic(e)) {
e = get_app_fn(get_as_atomic_arg(e));
if (is_explicit(e))
e = get_explicit_arg(e);
return tactic_expr_to_id(e, error_msg);
} else {
throw expr_to_tactic_exception(e, error_msg);
}
}
static expr * g_expr_list_cons = nullptr;
static expr * g_expr_list_nil = nullptr;
expr mk_expr_list(unsigned num, expr const * args) {
expr r = *g_expr_list_nil;
unsigned i = num;
while (i > 0) {
--i;
r = mk_app(*g_expr_list_cons, args[i], r);
}
return r;
}
expr ids_to_tactic_expr(buffer<name> const & args) {
buffer<expr> es;
for (name const & id : args) {
es.push_back(mk_local(id, mk_expr_placeholder()));
}
return mk_expr_list(es.size(), es.data());
}
void get_tactic_expr_list_elements(expr l, buffer<expr> & r, char const * error_msg) {
while (true) {
if (l == *g_expr_list_nil)
return;
if (!is_app(l) ||
!is_app(app_fn(l)) ||
app_fn(app_fn(l)) != *g_expr_list_cons ||
!is_tactic_expr(app_arg(app_fn(l))))
throw expr_to_tactic_exception(l, error_msg);
r.push_back(get_tactic_expr_expr(app_arg(app_fn(l))));
l = app_arg(l);
}
}
void get_tactic_id_list_elements(expr l, buffer<name> & r, char const * error_msg) {
buffer<expr> es;
get_tactic_expr_list_elements(l, es, error_msg);
for (unsigned i = 0; i < es.size(); i++) {
r.push_back(tactic_expr_to_id(es[i], error_msg));
}
}
static void throw_failed(expr const & e) {
throw expr_to_tactic_exception(e, "failed to convert expression into tactic");
}
/** \brief Return true if v is the constant tactic.builtin or the constant function that returns tactic.builtin_tactic */
static bool is_builtin_tactic(expr const & v) {
if (is_lambda(v))
return is_builtin_tactic(binding_body(v));
else if (v == *g_builtin_tac)
return true;
else
return false;
}
tactic expr_to_tactic(old_type_checker & tc, elaborate_fn const & fn, expr e, pos_info_provider const * p) {
e = copy_tag(e, tc.whnf(e).first);
expr f = get_app_fn(e);
if (!is_constant(f))
throw_failed(e);
optional<declaration> it = tc.env().find(const_name(f));
if (!it || !it->is_definition())
throw_failed(e);
expr v = it->get_value();
if (is_builtin_tactic(v)) {
auto const & map = get_expr_to_tactic_map();
auto it2 = map.find(const_name(f));
if (it2 != map.end())
return it2->second(tc, fn, e, p);
else
throw expr_to_tactic_exception(e, sstream() << "implementation for builtin tactic '" <<
const_name(f) << "' was not found");
} else {
// unfold definition
buffer<expr> locals;
get_app_rev_args(e, locals);
level_param_names const & ps = it->get_univ_params();
levels ls = const_levels(f);
unsigned num_ps = length(ps);
unsigned num_ls = length(ls);
if (num_ls > num_ps)
throw expr_to_tactic_exception(e, sstream() << "invalid number of universes");
if (num_ls < num_ps) {
buffer<level> extra_ls;
for (unsigned i = num_ls; i < num_ps; i++)
extra_ls.push_back(mk_meta_univ(mk_fresh_name()));
ls = append(ls, to_list(extra_ls.begin(), extra_ls.end()));
}
v = instantiate_univ_params(v, ps, ls);
v = apply_beta(v, locals.size(), locals.data());
return expr_to_tactic(tc, fn, v, p);
}
}
unsigned get_unsigned(old_type_checker & tc, expr const & e, expr const & ref) {
optional<mpz> k = to_num(e);
if (!k)
k = to_num(tc.whnf(e).first);
if (!k)
throw expr_to_tactic_exception(ref, "invalid tactic, second argument must be a numeral");
if (!k->is_unsigned_int())
throw expr_to_tactic_exception(ref,
"invalid tactic, second argument does not fit in "
"a machine unsigned integer");
return k->get_unsigned_int();
}
unsigned get_unsigned_arg(old_type_checker & tc, expr const & e, unsigned i) {
buffer<expr> args;
get_app_args(e, args);
if (i >= args.size())
throw expr_to_tactic_exception(e, "invalid tactic, insufficient number of arguments");
return get_unsigned(tc, args[i], e);
}
optional<unsigned> get_optional_unsigned(old_type_checker & tc, expr const & e) {
if (is_app(e) && is_constant(get_app_fn(e))) {
if (const_name(get_app_fn(e)) == get_option_some_name()) {
return optional<unsigned>(get_unsigned(tc, app_arg(e), e));
} else if (const_name(get_app_fn(e)) == get_option_none_name()) {
return optional<unsigned>();
}
}
throw expr_to_tactic_exception(e, "invalid tactic, argument is not an option num");
}
class tac_builtin_opaque_converter : public projection_converter {
public:
tac_builtin_opaque_converter(environment const & env):projection_converter(env) {}
virtual bool is_opaque(declaration const & d) const {
name n = d.get_name();
if (!is_prefix_of(get_tactic_name(), n))
return projection_converter::is_opaque(d);
expr v = d.get_value();
while (is_lambda(v))
v = binding_body(v);
if (is_constant(v) && const_name(v) == get_tactic_builtin_name())
return true;
return projection_converter::is_opaque(d);
}
};
tactic expr_to_tactic(environment const & env, elaborate_fn const & fn, expr const & e, pos_info_provider const * p) {
bool memoize = false;
old_type_checker tc(env, std::unique_ptr<old_converter>(new tac_builtin_opaque_converter(env)), memoize);
return expr_to_tactic(tc, fn, e, p);
}
tactic fixpoint(expr const & b, elaborate_fn const & fn) {
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) -> proof_state_seq {
return expr_to_tactic(env, fn, b, nullptr)(env, ios, s);
});
}
void register_simple_tac(name const & n, std::function<tactic()> f) {
register_tac(n, [=](old_type_checker &, elaborate_fn const &, expr const & e, pos_info_provider const *) {
if (!is_constant(e))
throw expr_to_tactic_exception(e, "invalid constant tactic");
return f();
});
}
void register_bin_tac(name const & n, std::function<tactic(tactic const &, tactic const &)> f) {
register_tac(n, [=](old_type_checker & tc, elaborate_fn const & fn, expr const & e, pos_info_provider const * p) {
buffer<expr> args;
get_app_args(e, args);
if (args.size() != 2)
throw expr_to_tactic_exception(e, "invalid binary tactic, it must have two arguments");
tactic t1 = expr_to_tactic(tc, fn, args[0], p);
tactic t2 = expr_to_tactic(tc, fn, args[1], p);
return f(t1, t2);
});
}
void register_unary_tac(name const & n, std::function<tactic(tactic const &)> f) {
register_tac(n, [=](old_type_checker & tc, elaborate_fn const & fn, expr const & e, pos_info_provider const * p) {
buffer<expr> args;
get_app_args(e, args);
if (args.size() != 1)
throw expr_to_tactic_exception(e, "invalid unary tactic, it must have one argument");
return f(expr_to_tactic(tc, fn, args[0], p));
});
}
void register_unary_num_tac(name const & n, std::function<tactic(tactic const &, unsigned k)> f) {
register_tac(n, [=](old_type_checker & tc, elaborate_fn const & fn, expr const & e, pos_info_provider const * p) {
buffer<expr> args;
get_app_args(e, args);
if (args.size() != 2)
throw expr_to_tactic_exception(e, "invalid tactic, it must have two arguments");
tactic t = expr_to_tactic(tc, fn, args[0], p);
return f(t, get_unsigned_arg(tc, e, 1));
});
}
void register_num_tac(name const & n, std::function<tactic(unsigned k)> f) {
register_tac(n, [=](old_type_checker & tc, elaborate_fn const &, expr const & e, pos_info_provider const *) {
buffer<expr> args;
get_app_args(e, args);
if (args.size() != 1)
throw expr_to_tactic_exception(e, "invalid tactic, it must have one argument");
return f(get_unsigned_arg(tc, e, 0));
});
}
static name * g_by_name = nullptr;
expr mk_by(expr const & e) { return mk_annotation(*g_by_name, e); }
bool is_by(expr const & e) { return is_annotation(e, *g_by_name); }
expr const & get_by_arg(expr const & e) { lean_assert(is_by(e)); return get_annotation_arg(e); }
void initialize_expr_to_tactic() {
g_by_name = new name("by");
register_annotation(*g_by_name);
g_map = new expr_to_tactic_map();
g_tactic_expr_type = new expr(mk_constant(get_tactic_expr_name()));
g_tactic_expr_builtin = new expr(mk_constant(get_tactic_expr_builtin_name()));
g_tactic_expr_list_type = new expr(mk_constant(get_tactic_expr_list_name()));
g_tactic_identifier_type = new expr(mk_constant(get_tactic_identifier_name()));
g_tactic_using_expr_type = new expr(mk_constant(get_tactic_using_expr_name()));
g_tactic_location_type = new expr(mk_constant(get_tactic_location_name()));
g_tactic_with_expr_type = new expr(mk_constant(get_tactic_with_expr_name()));
g_tactic_expr_opcode = new std::string("TACE");
g_tactic_expr_macro = new macro_definition(new tactic_expr_macro_definition_cell());
register_macro_deserializer(*g_tactic_expr_opcode,
[](deserializer &, unsigned num, expr const * args) {
if (num != 1)
throw corrupted_stream_exception();
return mk_tactic_expr(args[0]);
});
g_expr_list_cons = new expr(mk_constant(get_tactic_expr_list_cons_name()));
g_expr_list_nil = new expr(mk_constant(get_tactic_expr_list_nil_name()));
g_and_then_tac_fn = new expr(Const(get_tactic_and_then_name()));
g_or_else_tac_fn = new expr(Const(get_tactic_or_else_name()));
g_id_tac_fn = new expr(Const(get_tactic_id_name()));
g_repeat_tac_fn = new expr(Const(get_tactic_repeat_name()));
g_determ_tac_fn = new expr(Const(get_tactic_determ_name()));
g_tac_type = new expr(Const(get_tactic_name()));
g_builtin_tac = new expr(Const(get_tactic_builtin_name()));
g_fixpoint_tac = new expr(Const(get_tactic_fixpoint_name()));
register_simple_tac(get_tactic_id_name(),
[]() { return id_tactic(); });
register_simple_tac(get_tactic_now_name(),
[]() { return now_tactic(); });
register_simple_tac(get_tactic_fail_name(),
[]() { return fail_tactic(); });
register_bin_tac(get_tactic_and_then_name(),
[](tactic const & t1, tactic const & t2) { return then(t1, t2); });
register_bin_tac(get_tactic_par_name(),
[](tactic const & t1, tactic const & t2) { return par(t1, t2); });
register_bin_tac(get_tactic_or_else_name(),
[](tactic const & t1, tactic const & t2) { return orelse(t1, t2); });
register_unary_tac(get_tactic_repeat_name(),
[](tactic const & t1) { return repeat(t1); });
register_unary_tac(get_tactic_all_goals_name(),
[](tactic const & t1) { return all_goals(t1); });
register_unary_num_tac(get_tactic_at_most_name(),
[](tactic const & t, unsigned k) { return take(t, k); });
register_unary_num_tac(get_tactic_discard_name(),
[](tactic const & t, unsigned k) { return discard(t, k); });
register_unary_num_tac(get_tactic_focus_at_name(),
[](tactic const & t, unsigned k) { return focus(t, k); });
register_unary_num_tac(get_tactic_try_for_name(),
[](tactic const & t, unsigned k) { return try_for(t, k); });
register_num_tac(get_tactic_rotate_left_name(), [](unsigned k) { return rotate_left(k); });
register_num_tac(get_tactic_rotate_right_name(), [](unsigned k) { return rotate_right(k); });
register_tac(get_tactic_fixpoint_name(),
[](old_type_checker & tc, elaborate_fn const & fn, expr const & e, pos_info_provider const *) {
if (!is_constant(app_fn(e)))
throw expr_to_tactic_exception(e, "invalid fixpoint tactic, it must have one argument");
expr r = tc.whnf(mk_app(app_arg(e), e)).first;
return fixpoint(r, fn);
});
}
void finalize_expr_to_tactic() {
delete g_expr_list_cons;
delete g_expr_list_nil;
delete g_tactic_expr_type;
delete g_tactic_expr_builtin;
delete g_tactic_expr_list_type;
delete g_tactic_identifier_type;
delete g_tactic_using_expr_type;
delete g_tactic_location_type;
delete g_tactic_with_expr_type;
delete g_tactic_expr_opcode;
delete g_tactic_expr_macro;
delete g_fixpoint_tac;
delete g_builtin_tac;
delete g_tac_type;
delete g_determ_tac_fn;
delete g_repeat_tac_fn;
delete g_or_else_tac_fn;
delete g_and_then_tac_fn;
delete g_id_tac_fn;
delete g_map;
delete g_tactic_opcode;
delete g_by_name;
}
}

View file

@ -1,102 +0,0 @@
/*
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#pragma once
#include "kernel/pos_info_provider.h"
#include "library/old_type_checker.h"
#include "library/tactic/tactic.h"
#include "library/tactic/elaborate.h"
namespace lean {
/**
\brief Return true iff the environment \c env contains the following declarations
in the namespace 'tactic'
tactic.builtin : tactic
and_then : tactic -> tactic -> tactic
or_else : tactic -> tactic -> tactic
repeat : tactic -> tactic
*/
bool has_tactic_decls(environment const & env);
/**
\brief Creates a tactic by 'executing' \c e. Definitions are unfolded, whnf procedure is invoked,
and definitions marked as 'tactic.builtin' are handled by the code registered using
\c register_expr_to_tactic.
*/
tactic expr_to_tactic(environment const & env, elaborate_fn const & fn, expr const & e, pos_info_provider const * p);
// auxiliary procedure used to compile nested tactic in tacticals
tactic expr_to_tactic(old_type_checker & tc, elaborate_fn const & fn, expr e, pos_info_provider const * p);
name const & get_tactic_name();
unsigned get_unsigned_arg(old_type_checker & tc, expr const & e, unsigned i);
optional<unsigned> get_optional_unsigned(old_type_checker & tc, expr const & e);
expr const & get_tactic_expr_type();
expr const & get_tactic_identifier_type();
expr const & get_tactic_with_expr_type();
expr const & get_tactic_location_type();
expr const & get_tactic_with_expr_type();
expr mk_tactic_expr(expr const & e);
bool is_tactic_expr(expr const & e);
expr const & get_tactic_expr_expr(expr const & e);
void check_tactic_expr(expr const & e, char const * msg);
expr const & get_tactic_expr_list_type();
expr const & get_tactic_using_expr_type();
expr mk_expr_list(unsigned num, expr const * args);
name const & tactic_expr_to_id(expr e, char const * error_msg);
void get_tactic_expr_list_elements(expr l, buffer<expr> & r, char const * error_msg);
void get_tactic_id_list_elements(expr l, buffer<name> & r, char const * error_msg);
expr ids_to_tactic_expr(buffer<name> const & ids);
/**
\brief Create an expression `by t`, where \c t is an expression of type `tactic`.
This kind of expression only affects the elaborator, the kernel will reject
any declaration that contains it.
\post get_by_arg(mk_by(t)) == t
\post is_by(mk_by(t))
*/
expr mk_by(expr const & t);
/** \brief Return true iff \c t is an expression created using \c mk_by */
bool is_by(expr const & t);
/** \see mk_by */
expr const & get_by_arg(expr const & t);
expr const & get_tactic_type();
expr const & get_and_then_tac_fn();
expr const & get_or_else_tac_fn();
expr const & get_id_tac_fn();
expr const & get_repeat_tac_fn();
expr const & get_determ_tac_fn();
/** \brief Exception used to report a problem when an expression is being converted into a tactic. */
class expr_to_tactic_exception : public exception {
expr m_expr;
public:
expr_to_tactic_exception(expr const & e, char const * msg):exception(msg), m_expr(e) {}
expr_to_tactic_exception(expr const & e, sstream const & strm):exception(strm), m_expr(e) {}
expr const & get_expr() const { return m_expr; }
};
typedef std::function<tactic(old_type_checker &, elaborate_fn const & fn, expr const &, pos_info_provider const *)>
expr_to_tactic_fn;
/** \brief Register a new "procedural attachment" for expr_to_tactic. */
void register_tac(name const & n, expr_to_tactic_fn const & fn);
// remark: we cannot use "std::function <...> const &" in the following procedures, for some obscure reason it produces
// memory leaks when we compile using clang 3.3
void register_simple_tac(name const & n, std::function<tactic()> f);
void register_bin_tac(name const & n, std::function<tactic(tactic const &, tactic const &)> f);
void register_unary_tac(name const & n, std::function<tactic(tactic const &)> f);
void register_unary_num_tac(name const & n, std::function<tactic(tactic const &, unsigned)> f);
void register_num_tac(name const & n, std::function<tactic(unsigned k)> f);
void initialize_expr_to_tactic();
void finalize_expr_to_tactic();
}

View file

@ -1,89 +0,0 @@
/*
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 "util/sstream.h"
#include "kernel/type_checker.h"
#include "library/constants.h"
#include "library/string.h"
#include "library/tactic/tactic.h"
#include "library/tactic/expr_to_tactic.h"
namespace lean {
tactic trace_tactic(std::string const & msg) {
return tactic1([=](environment const &, io_state const & ios, proof_state const & s) -> proof_state {
ios.get_diagnostic_channel() << msg << "\n";
ios.get_diagnostic_channel().get_stream().flush();
return s;
});
}
tactic trace_tactic(sstream const & msg) {
return trace_tactic(msg.str());
}
tactic trace_tactic(char const * msg) {
return trace_tactic(std::string(msg));
}
tactic trace_state_tactic(std::string const & fname, pair<unsigned, unsigned> const & pos) {
return tactic1([=](environment const & env, io_state const & ios, proof_state const & s) -> proof_state {
type_checker tc(env);
auto out = diagnostic(env, ios, tc);
out << fname << ":" << pos.first << ":" << pos.second << ": proof state\n"
<< s.pp(out.get_formatter()) << endl;
ios.get_diagnostic_channel().get_stream().flush();
return s;
});
}
tactic trace_state_tactic() {
return tactic1([=](environment const & env, io_state const & ios, proof_state const & s) -> proof_state {
type_checker tc(env);
auto out = diagnostic(env, ios, tc);
out << "proof state\n" << s.pp(out.get_formatter()) << endl;
ios.get_diagnostic_channel().get_stream().flush();
return s;
});
}
tactic suppress_trace(tactic const & t) {
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) -> proof_state_seq {
io_state new_ios(ios);
std::shared_ptr<output_channel> out(std::make_shared<string_output_channel>());
new_ios.set_diagnostic_channel(out);
return t(env, new_ios, s);
});
}
void initialize_trace_tactic() {
register_tac(get_tactic_state_name(),
[](old_type_checker &, elaborate_fn const &, expr const & e, pos_info_provider const * p) {
if (p)
if (auto it = p->get_pos_info(e))
return trace_state_tactic(std::string(p->get_file_name()), *it);
return trace_state_tactic();
});
register_tac(get_tactic_trace_name(),
[](old_type_checker & tc, elaborate_fn const &, expr const & e, pos_info_provider const *) {
buffer<expr> args;
get_app_args(e, args);
if (args.size() != 1)
throw expr_to_tactic_exception(e, "invalid trace tactic, argument expected");
if (auto str = to_string(args[0]))
return trace_tactic(*str);
else if (auto str = to_string(tc.whnf(args[0]).first))
return trace_tactic(*str);
else
throw expr_to_tactic_exception(e, "invalid trace tactic, string value expected");
});
}
void finalize_trace_tactic() {
}
}

View file

@ -1,25 +0,0 @@
/*
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#pragma once
#include <string>
#include "library/tactic/tactic.h"
namespace lean {
/** \brief Return a tactic that just returns the input state, and display the given message in the diagnostic channel. */
tactic trace_tactic(char const * msg);
class sstream;
tactic trace_tactic(sstream const & msg);
tactic trace_tactic(std::string const & msg);
/** \brief Return a tactic that just displays the input state in the diagnostic channel. */
tactic trace_state_tactic(std::string const & fname, pair<unsigned, unsigned> const & pos);
tactic trace_state_tactic();
/** \brief Create a tactic that applies \c t, but suppressing diagnostic messages. */
tactic suppress_trace(tactic const & t);
void initialize_trace_tactic();
void finalize_trace_tactic();
}

View file

@ -1,33 +0,0 @@
/*
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 "kernel/type_checker.h"
#include "library/aliases.h"
#include "library/constants.h"
#include "library/util.h"
#include "library/tactic/util.h"
#include "library/tactic/proof_state.h"
namespace lean {
bool is_tactic_namespace_open(environment const & env) {
for (name const & a : get_expr_aliases(env, "apply")) {
if (a == get_tactic_apply_name()) {
// make sure the type is the expected one
if (auto d = env.find(a)) {
expr t = d->get_type();
if (is_pi(t)) {
expr b = binding_body(t);
if (!is_constant(b) || const_name(b) != get_tactic_name())
throw exception("tactic namespace declarations have been modified, "
"function 'tactic.apply' is expected to return a 'tactic'");
}
}
return true;
}
}
return false;
}
}

View file

@ -1,12 +0,0 @@
/*
Copyright (c) 2014 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#pragma once
#include "kernel/environment.h"
namespace lean {
/** \brief Return true iff the tactic namespace is open in given environment. */
bool is_tactic_namespace_open(environment const & env);
}