2013-11-21 18:44:53 +00:00
|
|
|
/*
|
2014-06-28 01:42:59 +00:00
|
|
|
Copyright (c) 2013-2014 Microsoft Corporation. All rights reserved.
|
2013-11-21 18:44:53 +00:00
|
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
|
|
|
|
Author: Leonardo de Moura
|
|
|
|
*/
|
2013-11-21 23:31:55 +00:00
|
|
|
#include <utility>
|
2013-11-22 02:39:33 +00:00
|
|
|
#include <chrono>
|
2013-11-24 01:06:00 +00:00
|
|
|
#include <string>
|
2013-11-28 01:47:29 +00:00
|
|
|
#include "util/luaref.h"
|
2013-11-23 23:33:25 +00:00
|
|
|
#include "util/sstream.h"
|
2013-11-21 23:31:55 +00:00
|
|
|
#include "util/interrupt.h"
|
2013-11-22 02:39:33 +00:00
|
|
|
#include "util/lazy_list_fn.h"
|
2014-07-01 23:11:19 +00:00
|
|
|
#include "util/list_fn.h"
|
2013-12-01 16:51:56 +00:00
|
|
|
#include "kernel/instantiate.h"
|
2014-07-03 01:32:44 +00:00
|
|
|
#include "kernel/type_checker.h"
|
|
|
|
#include "kernel/for_each_fn.h"
|
2014-06-28 01:35:59 +00:00
|
|
|
#include "kernel/replace_visitor.h"
|
2013-11-28 01:47:29 +00:00
|
|
|
#include "library/kernel_bindings.h"
|
2013-11-21 18:44:53 +00:00
|
|
|
#include "library/tactic/tactic.h"
|
2014-06-28 01:35:59 +00:00
|
|
|
#include "library/io_state_stream.h"
|
2013-11-21 18:44:53 +00:00
|
|
|
|
|
|
|
namespace lean {
|
2014-07-03 01:32:44 +00:00
|
|
|
/** \brief Throw an exception is \c v contains local constants, \c e is only used for position information. */
|
|
|
|
void check_has_no_local(expr const & v, expr const & e, char const * tac_name) {
|
|
|
|
if (has_local(v)) {
|
|
|
|
for_each(v, [&](expr const & l, unsigned) {
|
|
|
|
if (is_local(l))
|
|
|
|
throw tactic_exception(e, sstream() << "tactic '" << tac_name << "' contains reference to local '" << local_pp_name(l)
|
|
|
|
<< "' which is not visible by this tactic "
|
|
|
|
<< "possible causes: it was not marked as [fact]; it was destructued");
|
|
|
|
return has_local(l);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-02 21:09:01 +00:00
|
|
|
tactic_exception::tactic_exception(expr const & e, char const * msg):exception(msg), m_expr(e) {}
|
|
|
|
tactic_exception::tactic_exception(expr const & e, sstream const & strm):exception(strm), m_expr(e) {}
|
|
|
|
|
2014-06-29 18:07:06 +00:00
|
|
|
tactic tactic01(std::function<optional<proof_state>(environment const &, io_state const & ios, proof_state const &)> f) {
|
2014-06-28 01:35:59 +00:00
|
|
|
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) {
|
|
|
|
return mk_proof_state_seq([=]() {
|
|
|
|
auto r = f(env, ios, s);
|
|
|
|
if (r)
|
|
|
|
return some(mk_pair(*r, proof_state_seq()));
|
|
|
|
else
|
|
|
|
return proof_state_seq::maybe_pair();
|
|
|
|
});
|
|
|
|
});
|
2013-11-22 00:44:31 +00:00
|
|
|
}
|
|
|
|
|
2014-06-29 18:07:06 +00:00
|
|
|
tactic tactic1(std::function<proof_state(environment const &, io_state const & ios, proof_state const &)> f) {
|
2014-06-28 01:35:59 +00:00
|
|
|
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) {
|
|
|
|
return mk_proof_state_seq([=]() {
|
|
|
|
auto r = f(env, ios, s);
|
|
|
|
return some(mk_pair(r, proof_state_seq()));
|
|
|
|
});
|
|
|
|
});
|
2013-11-22 01:25:19 +00:00
|
|
|
}
|
|
|
|
|
2013-11-22 02:39:33 +00:00
|
|
|
tactic id_tactic() {
|
2014-06-28 01:35:59 +00:00
|
|
|
return tactic1([](environment const &, io_state const &, proof_state const & s) -> proof_state { return s; });
|
2013-11-22 02:39:33 +00:00
|
|
|
}
|
2013-11-22 01:25:19 +00:00
|
|
|
|
2013-11-22 02:39:33 +00:00
|
|
|
tactic fail_tactic() {
|
2014-06-28 01:35:59 +00:00
|
|
|
return tactic([](environment const &, io_state const &, proof_state const &) -> proof_state_seq { return proof_state_seq(); });
|
2013-11-22 02:39:33 +00:00
|
|
|
}
|
2013-11-22 01:25:19 +00:00
|
|
|
|
|
|
|
tactic now_tactic() {
|
2014-06-28 01:35:59 +00:00
|
|
|
return tactic01([](environment const &, io_state const &, proof_state const & s) -> optional<proof_state> {
|
2013-11-22 01:25:19 +00:00
|
|
|
if (!empty(s.get_goals()))
|
2013-11-25 18:39:40 +00:00
|
|
|
return none_proof_state();
|
2013-11-22 02:39:33 +00:00
|
|
|
else
|
2013-11-25 18:39:40 +00:00
|
|
|
return some(s);
|
2013-11-22 01:25:19 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2014-06-29 18:24:56 +00:00
|
|
|
tactic cond(proof_state_pred p, tactic const & t1, tactic const & t2) {
|
2014-06-28 01:35:59 +00:00
|
|
|
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) -> proof_state_seq {
|
|
|
|
return mk_proof_state_seq([=]() {
|
|
|
|
if (p(env, ios, s)) {
|
|
|
|
return t1(env, ios, s).pull();
|
|
|
|
} else {
|
|
|
|
return t2(env, ios, s).pull();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2013-11-23 23:33:25 +00:00
|
|
|
tactic trace_tactic(std::string const & msg) {
|
2014-06-28 01:35:59 +00:00
|
|
|
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();
|
2013-11-24 08:38:52 +00:00
|
|
|
return s;
|
2013-11-23 23:33:25 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
tactic trace_tactic(sstream const & msg) {
|
|
|
|
return trace_tactic(msg.str());
|
|
|
|
}
|
|
|
|
|
|
|
|
tactic trace_tactic(char const * msg) {
|
|
|
|
return trace_tactic(std::string(msg));
|
|
|
|
}
|
|
|
|
|
2014-06-30 01:26:07 +00:00
|
|
|
tactic trace_state_tactic(std::string const & fname, std::pair<unsigned, unsigned> const & pos) {
|
2014-06-28 01:35:59 +00:00
|
|
|
return tactic1([=](environment const & env, io_state const & ios, proof_state const & s) -> proof_state {
|
2014-06-30 01:26:07 +00:00
|
|
|
diagnostic(env, ios) << fname << ":" << pos.first << ":" << pos.second << ": proof state\n"
|
|
|
|
<< s << endl;
|
2014-06-28 01:35:59 +00:00
|
|
|
ios.get_diagnostic_channel().get_stream().flush();
|
2013-11-25 00:44:02 +00:00
|
|
|
return s;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2014-07-09 00:48:41 +00:00
|
|
|
tactic trace_state_tactic() {
|
|
|
|
return tactic1([=](environment const & env, io_state const & ios, proof_state const & s) -> proof_state {
|
|
|
|
diagnostic(env, ios) << "proof state\n" << s << endl;
|
|
|
|
ios.get_diagnostic_channel().get_stream().flush();
|
|
|
|
return s;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2013-11-25 00:29:04 +00:00
|
|
|
tactic suppress_trace(tactic const & t) {
|
2014-06-28 01:35:59 +00:00
|
|
|
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) -> proof_state_seq {
|
|
|
|
io_state new_ios(ios);
|
2013-12-24 19:32:09 +00:00
|
|
|
std::shared_ptr<output_channel> out(std::make_shared<string_output_channel>());
|
2014-06-28 01:35:59 +00:00
|
|
|
new_ios.set_diagnostic_channel(out);
|
|
|
|
return t(env, new_ios, s);
|
2013-12-22 22:10:42 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2013-11-24 19:22:40 +00:00
|
|
|
tactic then(tactic const & t1, tactic const & t2) {
|
2014-06-28 01:35:59 +00:00
|
|
|
return tactic([=](environment const & env, io_state const & ios, proof_state const & s1) -> proof_state_seq {
|
|
|
|
return map_append(t1(env, ios, s1), [=](proof_state const & s2) {
|
2013-11-22 02:39:33 +00:00
|
|
|
check_interrupted();
|
2014-06-28 01:35:59 +00:00
|
|
|
return t2(env, ios, s2);
|
2013-12-07 22:59:21 +00:00
|
|
|
}, "THEN tactical");
|
2013-11-22 02:39:33 +00:00
|
|
|
});
|
|
|
|
}
|
2013-11-21 20:34:37 +00:00
|
|
|
|
2013-11-24 19:22:40 +00:00
|
|
|
tactic orelse(tactic const & t1, tactic const & t2) {
|
2014-06-28 01:35:59 +00:00
|
|
|
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) -> proof_state_seq {
|
|
|
|
return orelse(t1(env, ios, s), t2(env, ios, s), "ORELSE tactical");
|
2013-11-22 02:39:33 +00:00
|
|
|
});
|
|
|
|
}
|
2013-11-21 20:34:37 +00:00
|
|
|
|
2013-11-25 00:29:04 +00:00
|
|
|
tactic using_params(tactic const & t, options const & opts) {
|
2014-06-28 01:35:59 +00:00
|
|
|
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) -> proof_state_seq {
|
|
|
|
io_state new_ios(ios);
|
|
|
|
new_ios.set_options(join(opts, ios.get_options()));
|
|
|
|
return t(env, new_ios, s);
|
2013-11-25 00:29:04 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2013-11-24 19:22:40 +00:00
|
|
|
tactic try_for(tactic const & t, unsigned ms, unsigned check_ms) {
|
2014-06-28 01:35:59 +00:00
|
|
|
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) -> proof_state_seq {
|
|
|
|
return timeout(t(env, ios, s), ms, check_ms);
|
2013-11-22 02:39:33 +00:00
|
|
|
});
|
|
|
|
}
|
2013-11-23 00:15:03 +00:00
|
|
|
|
2013-11-24 19:22:40 +00:00
|
|
|
tactic append(tactic const & t1, tactic const & t2) {
|
2014-06-28 01:35:59 +00:00
|
|
|
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) -> proof_state_seq {
|
|
|
|
return append(t1(env, ios, s), t2(env, ios, s), "APPEND tactical");
|
2013-11-23 00:15:03 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2013-11-24 19:22:40 +00:00
|
|
|
tactic interleave(tactic const & t1, tactic const & t2) {
|
2014-06-28 01:35:59 +00:00
|
|
|
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) -> proof_state_seq {
|
|
|
|
return interleave(t1(env, ios, s), t2(env, ios, s), "INTERLEAVE tactical");
|
2013-11-23 00:15:03 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2013-11-24 19:22:40 +00:00
|
|
|
tactic par(tactic const & t1, tactic const & t2, unsigned check_ms) {
|
2014-06-28 01:35:59 +00:00
|
|
|
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) -> proof_state_seq {
|
|
|
|
return par(t1(env, ios, s), t2(env, ios, s), check_ms);
|
2013-11-23 00:15:03 +00:00
|
|
|
});
|
|
|
|
}
|
2013-11-23 00:39:25 +00:00
|
|
|
|
2013-11-24 19:22:40 +00:00
|
|
|
tactic repeat(tactic const & t) {
|
2014-06-28 01:35:59 +00:00
|
|
|
return tactic([=](environment const & env, io_state const & ios, proof_state const & s1) -> proof_state_seq {
|
2013-11-24 19:18:32 +00:00
|
|
|
return repeat(s1, [=](proof_state const & s2) {
|
2014-06-28 01:35:59 +00:00
|
|
|
return t(env, ios, s2);
|
2013-12-07 22:59:21 +00:00
|
|
|
}, "REPEAT tactical");
|
2013-11-23 00:39:25 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2013-11-24 19:22:40 +00:00
|
|
|
tactic repeat_at_most(tactic const & t, unsigned k) {
|
2014-06-28 01:35:59 +00:00
|
|
|
return tactic([=](environment const & env, io_state const & ios, proof_state const & s1) -> proof_state_seq {
|
2013-11-24 19:18:32 +00:00
|
|
|
return repeat_at_most(s1, [=](proof_state const & s2) {
|
2014-06-28 01:35:59 +00:00
|
|
|
return t(env, ios, s2);
|
2013-12-07 22:59:21 +00:00
|
|
|
}, k, "REPEAT_AT_MOST tactical");
|
2013-11-23 00:39:25 +00:00
|
|
|
});
|
|
|
|
}
|
2013-11-23 01:05:18 +00:00
|
|
|
|
2013-11-24 19:22:40 +00:00
|
|
|
tactic take(tactic const & t, unsigned k) {
|
2014-06-28 01:35:59 +00:00
|
|
|
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) -> proof_state_seq {
|
|
|
|
return take(k, t(env, ios, s));
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2014-07-03 16:20:01 +00:00
|
|
|
tactic discard(tactic const & t, unsigned k) {
|
|
|
|
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) -> proof_state_seq {
|
|
|
|
auto r = t(env, ios, s);
|
|
|
|
for (unsigned i = 0; i < k; i++) {
|
|
|
|
auto m = r.pull();
|
|
|
|
if (!m)
|
|
|
|
return proof_state_seq();
|
|
|
|
r = m->second;
|
|
|
|
}
|
|
|
|
return r;
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2014-06-28 01:35:59 +00:00
|
|
|
tactic assumption_tactic() {
|
|
|
|
return tactic01([](environment const &, io_state const &, proof_state const & s) -> optional<proof_state> {
|
2014-07-01 23:11:19 +00:00
|
|
|
substitution subst = s.get_subst();
|
2014-07-02 20:14:50 +00:00
|
|
|
bool solved = false;
|
2014-07-01 23:11:19 +00:00
|
|
|
goals new_gs = map_goals(s, [&](goal const & g) -> optional<goal> {
|
|
|
|
expr const & t = g.get_type();
|
|
|
|
optional<expr> h;
|
|
|
|
buffer<expr> locals;
|
|
|
|
get_app_args(g.get_meta(), locals);
|
|
|
|
for (auto const & l : locals) {
|
|
|
|
if (mlocal_type(l) == t) {
|
|
|
|
h = l;
|
2014-06-28 01:35:59 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
2014-07-01 23:11:19 +00:00
|
|
|
if (h) {
|
2014-07-02 20:14:50 +00:00
|
|
|
subst = subst.assign(g.get_mvar(), g.abstract(*h), justification());
|
|
|
|
solved = true;
|
2014-06-28 01:35:59 +00:00
|
|
|
return optional<goal>();
|
|
|
|
} else {
|
|
|
|
return some(g);
|
|
|
|
}
|
|
|
|
});
|
2014-07-02 20:14:50 +00:00
|
|
|
if (solved)
|
|
|
|
return some(proof_state(s, new_gs, subst));
|
|
|
|
else
|
|
|
|
return none_proof_state();
|
2013-11-23 01:05:18 +00:00
|
|
|
});
|
|
|
|
}
|
2013-11-28 01:47:29 +00:00
|
|
|
|
2014-07-03 01:32:44 +00:00
|
|
|
tactic exact_tactic(expr const & _e) {
|
|
|
|
return tactic01([=](environment const & env, io_state const &, proof_state const & s) {
|
|
|
|
type_checker tc(env);
|
|
|
|
substitution subst = s.get_subst();
|
|
|
|
goals const & gs = s.get_goals();
|
|
|
|
goal const & g = head(gs);
|
|
|
|
expr e = subst.instantiate(_e);
|
|
|
|
expr e_t = subst.instantiate(tc.infer(e));
|
|
|
|
expr t = subst.instantiate(g.get_type());
|
|
|
|
if (tc.is_def_eq(e_t, t) && !tc.next_cnstr()) {
|
|
|
|
expr new_p = g.abstract(e);
|
|
|
|
check_has_no_local(new_p, _e, "exact");
|
|
|
|
substitution new_subst = subst.assign(g.get_name(), new_p);
|
|
|
|
return some(proof_state(s, tail(gs), new_subst));
|
|
|
|
} else {
|
|
|
|
return none_proof_state();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2014-06-28 01:35:59 +00:00
|
|
|
tactic beta_tactic() {
|
|
|
|
return tactic01([=](environment const &, io_state const &, proof_state const & s) -> optional<proof_state> {
|
|
|
|
bool reduced = false;
|
2014-07-01 23:11:19 +00:00
|
|
|
goals new_gs = map_goals(s, [&](goal const & g) -> optional<goal> {
|
|
|
|
expr new_meta = beta_reduce(g.get_meta());
|
|
|
|
expr new_type = beta_reduce(g.get_type());
|
|
|
|
if (new_meta != g.get_meta() || new_type != g.get_type())
|
2014-06-28 01:35:59 +00:00
|
|
|
reduced = true;
|
2014-07-01 23:11:19 +00:00
|
|
|
return some(goal(new_meta, new_type));
|
2014-06-28 01:35:59 +00:00
|
|
|
});
|
|
|
|
return reduced ? some(proof_state(s, new_gs)) : none_proof_state();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2014-07-01 23:11:19 +00:00
|
|
|
proof_state_seq focus_core(tactic const & t, unsigned i, environment const & env, io_state const & ios, proof_state const & s) {
|
|
|
|
goals gs = s.get_goals();
|
|
|
|
if (i >= length(gs))
|
|
|
|
return proof_state_seq();
|
|
|
|
goal const & g = get_ith(gs, i);
|
|
|
|
proof_state new_s(s, goals(g)); // singleton goal
|
|
|
|
return map(t(env, ios, new_s), [=](proof_state const & s2) {
|
|
|
|
// we have to put back the goals that were not selected
|
|
|
|
buffer<goal> tmp;
|
|
|
|
to_buffer(gs, tmp);
|
|
|
|
buffer<goal> new_gs;
|
|
|
|
new_gs.append(i, tmp.data());
|
|
|
|
for (auto g : s2.get_goals())
|
|
|
|
new_gs.push_back(g);
|
|
|
|
new_gs.append(tmp.size()-i-1, tmp.data()+i+1);
|
|
|
|
return proof_state(s2, to_list(new_gs.begin(), new_gs.end()));
|
2013-11-30 19:28:10 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2014-07-01 23:11:19 +00:00
|
|
|
tactic focus(tactic const & t, unsigned i) {
|
2014-06-28 01:35:59 +00:00
|
|
|
return tactic([=](environment const & env, io_state const & ios, proof_state const & s) -> proof_state_seq {
|
2014-07-01 23:11:19 +00:00
|
|
|
return focus_core(t, i, env, ios, s);
|
2013-11-30 19:28:10 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2013-12-01 18:41:05 +00:00
|
|
|
class unfold_core_fn : public replace_visitor {
|
|
|
|
protected:
|
|
|
|
bool m_unfolded;
|
|
|
|
|
2014-06-28 01:35:59 +00:00
|
|
|
virtual expr visit_app(expr const & e) {
|
|
|
|
expr const & f = get_app_fn(e);
|
2013-12-01 18:41:05 +00:00
|
|
|
if (is_constant(f)) {
|
2014-06-28 01:35:59 +00:00
|
|
|
expr new_f = visit(f);
|
|
|
|
bool modified = new_f != f;
|
2013-12-01 18:41:05 +00:00
|
|
|
buffer<expr> new_args;
|
2014-06-28 01:35:59 +00:00
|
|
|
get_app_args(e, new_args);
|
|
|
|
for (unsigned i = 0; i < new_args.size(); i++) {
|
|
|
|
expr arg = new_args[i];
|
|
|
|
new_args[i] = visit(arg);
|
|
|
|
if (!modified && new_args[i] != arg)
|
|
|
|
modified = true;
|
|
|
|
}
|
2014-06-29 19:04:58 +00:00
|
|
|
if (is_lambda(new_f)) {
|
|
|
|
std::reverse(new_args.begin(), new_args.end());
|
|
|
|
return apply_beta(new_f, new_args.size(), new_args.data());
|
|
|
|
} else if (modified) {
|
|
|
|
return mk_app(new_f, new_args);
|
|
|
|
} else {
|
2014-06-28 01:35:59 +00:00
|
|
|
return e;
|
2014-06-29 19:04:58 +00:00
|
|
|
}
|
2013-12-01 18:41:05 +00:00
|
|
|
} else {
|
2014-06-28 01:35:59 +00:00
|
|
|
return replace_visitor::visit_app(e);
|
2013-12-01 18:41:05 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
public:
|
|
|
|
unfold_core_fn():m_unfolded(false) {}
|
|
|
|
bool unfolded() const { return m_unfolded; }
|
|
|
|
};
|
|
|
|
|
|
|
|
class unfold_fn : public unfold_core_fn {
|
2013-12-01 16:51:56 +00:00
|
|
|
protected:
|
2014-06-29 19:04:58 +00:00
|
|
|
name const & m_name;
|
|
|
|
level_param_names const & m_ps;
|
|
|
|
expr const & m_def;
|
2013-12-01 16:51:56 +00:00
|
|
|
|
2014-06-28 01:35:59 +00:00
|
|
|
virtual expr visit_constant(expr const & c) {
|
2013-12-01 16:51:56 +00:00
|
|
|
if (const_name(c) == m_name) {
|
|
|
|
m_unfolded = true;
|
2014-06-29 19:09:55 +00:00
|
|
|
return instantiate_univ_params(m_def, m_ps, const_levels(c));
|
2013-12-01 16:51:56 +00:00
|
|
|
} else {
|
|
|
|
return c;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-01 18:41:05 +00:00
|
|
|
public:
|
2014-06-29 19:04:58 +00:00
|
|
|
unfold_fn(name const & n, level_param_names const & ps, expr const & d):m_name(n), m_ps(ps), m_def(d) {}
|
2013-12-01 18:41:05 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
class unfold_all_fn : public unfold_core_fn {
|
|
|
|
protected:
|
2014-06-28 01:35:59 +00:00
|
|
|
environment m_env;
|
2013-12-01 18:41:05 +00:00
|
|
|
|
2014-06-28 01:35:59 +00:00
|
|
|
virtual expr visit_constant(expr const & c) {
|
|
|
|
optional<declaration> d = m_env.find(const_name(c));
|
|
|
|
if (d && d->is_definition() && (!d->is_opaque() || d->get_module_idx() == 0)) {
|
2013-12-01 18:41:05 +00:00
|
|
|
m_unfolded = true;
|
2014-06-29 19:09:55 +00:00
|
|
|
return instantiate_univ_params(d->get_value(), d->get_univ_params(), const_levels(c));
|
2013-12-01 16:51:56 +00:00
|
|
|
} else {
|
2013-12-01 18:41:05 +00:00
|
|
|
return c;
|
2013-12-01 16:51:56 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
public:
|
2014-06-28 01:35:59 +00:00
|
|
|
unfold_all_fn(environment const & env):m_env(env) {}
|
2013-12-01 16:51:56 +00:00
|
|
|
};
|
|
|
|
|
2013-12-01 18:41:05 +00:00
|
|
|
optional<proof_state> unfold_tactic_core(unfold_core_fn & fn, proof_state const & s) {
|
2014-07-01 23:11:19 +00:00
|
|
|
bool reduced = false;
|
|
|
|
goals new_gs = map_goals(s, [&](goal const & g) -> optional<goal> {
|
|
|
|
expr new_meta = fn(g.get_meta());
|
|
|
|
expr new_type = fn(g.get_type());
|
|
|
|
if (new_meta != g.get_meta() || new_type != g.get_type())
|
|
|
|
reduced = true;
|
|
|
|
return some(goal(new_meta, new_type));
|
2013-12-01 18:41:05 +00:00
|
|
|
});
|
2014-07-01 23:11:19 +00:00
|
|
|
if (reduced) {
|
2013-12-08 07:21:07 +00:00
|
|
|
return some(proof_state(s, new_gs));
|
2013-12-01 18:41:05 +00:00
|
|
|
} else {
|
|
|
|
return none_proof_state();
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-12-01 16:51:56 +00:00
|
|
|
tactic unfold_tactic(name const & n) {
|
2014-06-28 01:35:59 +00:00
|
|
|
return tactic01([=](environment const & env, io_state const &, proof_state const & s) -> optional<proof_state> {
|
|
|
|
optional<declaration> d = env.find(n);
|
|
|
|
if (!d || !d->is_definition() || (d->is_opaque() && d->get_module_idx() != 0))
|
2013-12-01 16:51:56 +00:00
|
|
|
return none_proof_state(); // tactic failed
|
2014-06-29 19:04:58 +00:00
|
|
|
unfold_fn fn(n, d->get_univ_params(), d->get_value());
|
2013-12-01 18:41:05 +00:00
|
|
|
return unfold_tactic_core(fn, s);
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
tactic unfold_tactic() {
|
2014-06-28 01:35:59 +00:00
|
|
|
return tactic01([=](environment const & env, io_state const &, proof_state const & s) -> optional<proof_state> {
|
2013-12-01 18:41:05 +00:00
|
|
|
unfold_all_fn fn(env);
|
|
|
|
return unfold_tactic_core(fn, s);
|
2013-12-01 16:51:56 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2013-11-28 01:47:29 +00:00
|
|
|
DECL_UDATA(proof_state_seq)
|
|
|
|
static const struct luaL_Reg proof_state_seq_m[] = {
|
|
|
|
{"__gc", proof_state_seq_gc}, // never throws
|
|
|
|
{0, 0}
|
|
|
|
};
|
|
|
|
|
|
|
|
static int proof_state_seq_next(lua_State * L) {
|
|
|
|
proof_state_seq seq = to_proof_state_seq(L, lua_upvalueindex(1));
|
2014-06-28 01:35:59 +00:00
|
|
|
auto p = seq.pull();
|
2013-11-28 01:47:29 +00:00
|
|
|
if (p) {
|
|
|
|
push_proof_state_seq(L, p->second);
|
|
|
|
lua_replace(L, lua_upvalueindex(1));
|
|
|
|
push_proof_state(L, p->first);
|
|
|
|
} else {
|
|
|
|
lua_pushnil(L);
|
|
|
|
}
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
static int push_proof_state_seq_it(lua_State * L, proof_state_seq const & seq) {
|
|
|
|
push_proof_state_seq(L, seq);
|
|
|
|
lua_pushcclosure(L, &safe_function<proof_state_seq_next>, 1); // create closure with 1 upvalue
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
DECL_UDATA(tactic)
|
|
|
|
|
2013-11-29 17:39:31 +00:00
|
|
|
[[ noreturn ]] void throw_tactic_expected(int i) {
|
|
|
|
throw exception(sstream() << "arg #" << i << " must be a tactic or a function that returns a tactic");
|
|
|
|
}
|
|
|
|
|
2014-06-28 01:35:59 +00:00
|
|
|
static int tactic_call_core(lua_State * L, tactic t, environment env, io_state ios, proof_state s) {
|
|
|
|
return push_proof_state_seq_it(L, t(env, ios, s));
|
2013-11-28 01:47:29 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static int tactic_call(lua_State * L) {
|
|
|
|
int nargs = lua_gettop(L);
|
2013-12-26 23:54:53 +00:00
|
|
|
tactic t = to_tactic(L, 1);
|
2014-06-28 01:35:59 +00:00
|
|
|
environment env = to_environment(L, 2);
|
|
|
|
if (nargs == 3)
|
|
|
|
return tactic_call_core(L, t, env, get_io_state(L), to_proof_state(L, 3));
|
|
|
|
else
|
2013-11-28 01:47:29 +00:00
|
|
|
return tactic_call_core(L, t, env, to_io_state(L, 3), to_proof_state(L, 4));
|
|
|
|
}
|
|
|
|
|
2013-11-29 06:11:07 +00:00
|
|
|
typedef tactic (*binary_tactic_fn)(tactic const &, tactic const &);
|
|
|
|
|
|
|
|
template<binary_tactic_fn F>
|
|
|
|
static int nary_tactic(lua_State * L) {
|
|
|
|
int nargs = lua_gettop(L);
|
|
|
|
if (nargs < 2)
|
|
|
|
throw exception("tactical expects at least two arguments");
|
2013-12-26 23:54:53 +00:00
|
|
|
tactic r = F(to_tactic(L, 1), to_tactic(L, 2));
|
2013-11-29 06:11:07 +00:00
|
|
|
for (int i = 3; i <= nargs; i++)
|
2013-12-26 23:54:53 +00:00
|
|
|
r = F(r, to_tactic(L, i));
|
2013-11-29 06:11:07 +00:00
|
|
|
return push_tactic(L, r);
|
|
|
|
}
|
|
|
|
|
2013-12-26 23:54:53 +00:00
|
|
|
static int tactic_then(lua_State * L) { return push_tactic(L, then(to_tactic(L, 1), to_tactic(L, 2))); }
|
|
|
|
static int tactic_orelse(lua_State * L) { return push_tactic(L, orelse(to_tactic(L, 1), to_tactic(L, 2))); }
|
|
|
|
static int tactic_append(lua_State * L) { return push_tactic(L, append(to_tactic(L, 1), to_tactic(L, 2))); }
|
|
|
|
static int tactic_interleave(lua_State * L) { return push_tactic(L, interleave(to_tactic(L, 1), to_tactic(L, 2))); }
|
|
|
|
static int tactic_par(lua_State * L) { return push_tactic(L, par(to_tactic(L, 1), to_tactic(L, 2))); }
|
|
|
|
static int tactic_repeat(lua_State * L) { return push_tactic(L, repeat(to_tactic(L, 1))); }
|
|
|
|
static int tactic_repeat_at_most(lua_State * L) { return push_tactic(L, repeat_at_most(to_tactic(L, 1), luaL_checkinteger(L, 2))); }
|
|
|
|
static int tactic_take(lua_State * L) { return push_tactic(L, take(to_tactic(L, 1), luaL_checkinteger(L, 2))); }
|
|
|
|
static int tactic_suppress_trace(lua_State * L) { return push_tactic(L, suppress_trace(to_tactic(L, 1))); }
|
|
|
|
static int tactic_try_for(lua_State * L) { return push_tactic(L, try_for(to_tactic(L, 1), luaL_checkinteger(L, 2))); }
|
|
|
|
static int tactic_using_params(lua_State * L) { return push_tactic(L, using_params(to_tactic(L, 1), to_options(L, 2))); }
|
2013-11-30 19:28:10 +00:00
|
|
|
static int tactic_focus(lua_State * L) {
|
|
|
|
int nargs = lua_gettop(L);
|
|
|
|
if (nargs == 1)
|
2013-12-26 23:54:53 +00:00
|
|
|
return push_tactic(L, focus(to_tactic(L, 1)));
|
2013-11-30 19:28:10 +00:00
|
|
|
else
|
2014-07-01 23:11:19 +00:00
|
|
|
return push_tactic(L, focus(to_tactic(L, 1), lua_tointeger(L, 2)));
|
2013-11-30 19:28:10 +00:00
|
|
|
}
|
2013-11-28 01:47:29 +00:00
|
|
|
static int mk_lua_tactic01(lua_State * L) {
|
|
|
|
luaL_checktype(L, 1, LUA_TFUNCTION); // user-fun
|
|
|
|
luaref ref(L, 1);
|
2014-06-28 01:35:59 +00:00
|
|
|
tactic t = tactic01([=](environment const & env, io_state const & ios, proof_state const & s) -> optional<proof_state> {
|
|
|
|
ref.push(); // push user-fun on the stack
|
|
|
|
push_environment(L, env); // push args...
|
|
|
|
push_io_state(L, ios);
|
|
|
|
push_proof_state(L, s);
|
|
|
|
pcall(L, 3, 1, 0);
|
|
|
|
optional<proof_state> r;
|
|
|
|
if (is_proof_state(L, -1))
|
|
|
|
r = to_proof_state(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
return r;
|
|
|
|
});
|
|
|
|
return push_tactic(L, t);
|
2013-11-28 01:47:29 +00:00
|
|
|
}
|
|
|
|
|
2013-11-29 01:57:24 +00:00
|
|
|
static int mk_lua_cond_tactic(lua_State * L, tactic t1, tactic t2) {
|
|
|
|
luaL_checktype(L, 1, LUA_TFUNCTION); // user-fun
|
|
|
|
luaref ref(L, 1);
|
2014-06-28 01:35:59 +00:00
|
|
|
tactic t = tactic([=](environment const & env, io_state const & ios, proof_state const & s) -> proof_state_seq {
|
|
|
|
return mk_proof_state_seq([=]() {
|
|
|
|
ref.push(); // push user-fun on the stack
|
|
|
|
push_environment(L, env); // push args...
|
|
|
|
push_io_state(L, ios);
|
|
|
|
push_proof_state(L, s);
|
|
|
|
pcall(L, 3, 1, 0);
|
|
|
|
bool cond = lua_toboolean(L, -1);
|
|
|
|
lua_pop(L, 1);
|
|
|
|
if (cond) {
|
|
|
|
return t1(env, ios, s).pull();
|
|
|
|
} else {
|
|
|
|
return t2(env, ios, s).pull();
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
return push_tactic(L, t);
|
2013-11-29 01:57:24 +00:00
|
|
|
}
|
|
|
|
|
2014-06-28 01:35:59 +00:00
|
|
|
static int mk_lua_cond_tactic(lua_State * L) { return mk_lua_cond_tactic(L, to_tactic(L, 2), to_tactic(L, 3)); }
|
|
|
|
static int mk_lua_when_tactic(lua_State * L) { return mk_lua_cond_tactic(L, to_tactic(L, 2), id_tactic()); }
|
2013-11-29 09:33:26 +00:00
|
|
|
static int mk_id_tactic(lua_State * L) { return push_tactic(L, id_tactic()); }
|
|
|
|
static int mk_now_tactic(lua_State * L) { return push_tactic(L, now_tactic()); }
|
|
|
|
static int mk_fail_tactic(lua_State * L) { return push_tactic(L, fail_tactic()); }
|
|
|
|
static int mk_trace_tactic(lua_State * L) { return push_tactic(L, trace_tactic(luaL_checkstring(L, 1))); }
|
|
|
|
static int mk_assumption_tactic(lua_State * L) { return push_tactic(L, assumption_tactic()); }
|
2013-12-01 18:41:05 +00:00
|
|
|
static int mk_unfold_tactic(lua_State * L) {
|
|
|
|
int nargs = lua_gettop(L);
|
|
|
|
if (nargs == 0)
|
|
|
|
return push_tactic(L, unfold_tactic());
|
|
|
|
else
|
|
|
|
return push_tactic(L, unfold_tactic(to_name_ext(L, 1)));
|
|
|
|
}
|
2013-12-02 16:10:51 +00:00
|
|
|
static int mk_beta_tactic(lua_State * L) { return push_tactic(L, beta_tactic()); }
|
2013-11-28 01:47:29 +00:00
|
|
|
static const struct luaL_Reg tactic_m[] = {
|
|
|
|
{"__gc", tactic_gc}, // never throws
|
|
|
|
{"__call", safe_function<tactic_call>},
|
|
|
|
{"__concat", safe_function<tactic_then>},
|
|
|
|
{"__pow", safe_function<tactic_orelse>},
|
|
|
|
{"__add", safe_function<tactic_append>},
|
|
|
|
{"then", safe_function<tactic_then>},
|
|
|
|
{"orelse", safe_function<tactic_orelse>},
|
|
|
|
{"append", safe_function<tactic_append>},
|
2013-11-29 01:57:24 +00:00
|
|
|
{"interleave", safe_function<tactic_interleave>},
|
2013-11-28 01:47:29 +00:00
|
|
|
{"par", safe_function<tactic_par>},
|
|
|
|
{"repeat", safe_function<tactic_repeat>},
|
|
|
|
{"repeat_at_most", safe_function<tactic_repeat_at_most>},
|
|
|
|
{"take", safe_function<tactic_take>},
|
|
|
|
{"suppress_trace", safe_function<tactic_suppress_trace>},
|
|
|
|
{"try_for", safe_function<tactic_try_for>},
|
2013-11-29 01:57:24 +00:00
|
|
|
{"using_params", safe_function<tactic_using_params>},
|
|
|
|
{"using", safe_function<tactic_using_params>},
|
2013-11-30 19:28:10 +00:00
|
|
|
{"focus", safe_function<tactic_focus>},
|
2013-11-28 01:47:29 +00:00
|
|
|
{0, 0}
|
|
|
|
};
|
|
|
|
|
|
|
|
void open_tactic(lua_State * L) {
|
|
|
|
luaL_newmetatable(L, proof_state_seq_mt);
|
|
|
|
lua_pushvalue(L, -1);
|
|
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
setfuncs(L, proof_state_seq_m, 0);
|
|
|
|
SET_GLOBAL_FUN(proof_state_seq_pred, "is_proof_state_seq");
|
|
|
|
|
|
|
|
luaL_newmetatable(L, tactic_mt);
|
|
|
|
lua_pushvalue(L, -1);
|
|
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
setfuncs(L, tactic_m, 0);
|
|
|
|
|
2013-11-29 09:33:26 +00:00
|
|
|
SET_GLOBAL_FUN(tactic_pred, "is_tactic");
|
2013-12-06 04:00:20 +00:00
|
|
|
SET_GLOBAL_FUN(mk_trace_tactic, "trace_tac");
|
|
|
|
SET_GLOBAL_FUN(mk_id_tactic, "id_tac");
|
|
|
|
SET_GLOBAL_FUN(mk_now_tactic, "now_tac");
|
|
|
|
SET_GLOBAL_FUN(mk_fail_tactic, "fail_tac");
|
|
|
|
SET_GLOBAL_FUN(mk_assumption_tactic, "assumption_tac");
|
|
|
|
SET_GLOBAL_FUN(mk_unfold_tactic, "unfold_tac");
|
|
|
|
SET_GLOBAL_FUN(mk_beta_tactic, "beta_tac");
|
2014-06-28 01:35:59 +00:00
|
|
|
SET_GLOBAL_FUN(mk_lua_tactic01, "tactic01");
|
2013-11-29 09:33:26 +00:00
|
|
|
|
2013-11-29 01:57:24 +00:00
|
|
|
// HOL-like tactic names
|
2013-12-26 23:54:53 +00:00
|
|
|
SET_GLOBAL_FUN(nary_tactic<then>, "Then");
|
|
|
|
SET_GLOBAL_FUN(nary_tactic<orelse>, "OrElse");
|
|
|
|
SET_GLOBAL_FUN(nary_tactic<interleave>, "Interleave");
|
|
|
|
SET_GLOBAL_FUN(nary_tactic<append>, "Append");
|
|
|
|
SET_GLOBAL_FUN(nary_tactic<par>, "Par");
|
|
|
|
SET_GLOBAL_FUN(tactic_repeat, "Repeat");
|
|
|
|
SET_GLOBAL_FUN(tactic_repeat_at_most, "RepeatAtMost");
|
|
|
|
SET_GLOBAL_FUN(mk_lua_cond_tactic, "Cond");
|
|
|
|
SET_GLOBAL_FUN(mk_lua_when_tactic, "When");
|
|
|
|
SET_GLOBAL_FUN(tactic_try_for, "TryFor");
|
|
|
|
SET_GLOBAL_FUN(tactic_take, "Take");
|
|
|
|
SET_GLOBAL_FUN(tactic_using_params, "Using");
|
|
|
|
SET_GLOBAL_FUN(tactic_using_params, "UsingParams");
|
|
|
|
SET_GLOBAL_FUN(tactic_focus, "Focus");
|
2013-11-28 01:47:29 +00:00
|
|
|
}
|
2013-11-21 18:44:53 +00:00
|
|
|
}
|