diff --git a/src/kernel/environment.h b/src/kernel/environment.h index dd05dd1ef..7ea90b9b9 100644 --- a/src/kernel/environment.h +++ b/src/kernel/environment.h @@ -35,6 +35,7 @@ public: weak_ref to_weak_ref() const { return weak_ref(m_ptr); } friend bool is_eqp(environment const & env1, environment const & env2) { return env1.m_ptr.get() == env2.m_ptr.get(); } + friend void swap(environment & env1, environment & env2) { env1.m_ptr.swap(env2.m_ptr); } // ======================================= // Parent/Child environment management /** diff --git a/src/library/tactic/CMakeLists.txt b/src/library/tactic/CMakeLists.txt index fe30ad2a0..658d481ec 100644 --- a/src/library/tactic/CMakeLists.txt +++ b/src/library/tactic/CMakeLists.txt @@ -1,2 +1,2 @@ -add_library(tactic goal.cpp tactic.cpp) +add_library(tactic goal.cpp proof_builder.cpp proof_state.cpp tactic.cpp) target_link_libraries(tactic ${LEAN_LIBS}) diff --git a/src/library/tactic/goal.cpp b/src/library/tactic/goal.cpp index bfbc32044..2f83b18f8 100644 --- a/src/library/tactic/goal.cpp +++ b/src/library/tactic/goal.cpp @@ -22,7 +22,7 @@ goal_proof_fn::goal_proof_fn(std::vector && consts): m_constants(consts) { } -expr goal_proof_fn::operator()(expr const & pr) { +expr goal_proof_fn::operator()(expr const & pr) const { return abstract(pr, m_constants.size(), m_constants.data()); } diff --git a/src/library/tactic/goal.h b/src/library/tactic/goal.h index d74838d2a..30c4094c8 100644 --- a/src/library/tactic/goal.h +++ b/src/library/tactic/goal.h @@ -36,7 +36,7 @@ class goal_proof_fn { std::vector m_constants; goal_proof_fn(std::vector && constants); public: - expr operator()(expr const & pr); + expr operator()(expr const & pr) const; }; /** diff --git a/src/library/tactic/justification_builder.h b/src/library/tactic/justification_builder.h index 33e14e300..d775161fb 100644 --- a/src/library/tactic/justification_builder.h +++ b/src/library/tactic/justification_builder.h @@ -25,6 +25,7 @@ class justification_builder { protected: justification_builder_cell * m_ptr; public: + justification_builder():m_ptr(nullptr) {} explicit justification_builder(justification_builder_cell * ptr):m_ptr(ptr) { lean_assert(m_ptr); m_ptr->inc_ref(); } justification_builder(justification_builder const & s):m_ptr(s.m_ptr) { if (m_ptr) m_ptr->inc_ref(); } justification_builder(justification_builder && s):m_ptr(s.m_ptr) { s.m_ptr = nullptr; } @@ -35,4 +36,17 @@ public: justification operator()(name const & n, justification const & j, environment const & env, assignment const & a) const { return m_ptr->operator()(n, j, env, a); } }; + +template +class simple_justification_builder : public justification_builder_cell { + F m_f; +public: + simple_justification_builder(F && f):m_f(std::forward(f)) {} + virtual justification operator()(name const & n, justification const & j, environment const & env, assignment const & a) const { return m_f(n, j, env, a); } +}; + +template +justification_builder mk_justification_builder(F && f) { + return justification_builder(new simple_justification_builder(std::forward(f))); +} } diff --git a/src/library/tactic/proof_builder.cpp b/src/library/tactic/proof_builder.cpp new file mode 100644 index 000000000..7657e9490 --- /dev/null +++ b/src/library/tactic/proof_builder.cpp @@ -0,0 +1,17 @@ +/* +Copyright (c) 2013 Microsoft Corporation. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. + +Author: Leonardo de Moura +*/ +#include "library/tactic/proof_builder.h" + +namespace lean { +expr find(proof_map const & m, name const & n) { + expr * r = const_cast(m).splay_find(n); + if (r) + return *r; + else + return expr(); +} +} diff --git a/src/library/tactic/proof_builder.h b/src/library/tactic/proof_builder.h index 74b5551c2..c9f4773d3 100644 --- a/src/library/tactic/proof_builder.h +++ b/src/library/tactic/proof_builder.h @@ -16,6 +16,8 @@ Author: Leonardo de Moura namespace lean { typedef splay_map proof_map; +expr find(proof_map const & m, name const & n); + class proof_builder_cell { void dealloc() { delete this; } MK_LEAN_RC(); @@ -28,6 +30,7 @@ class proof_builder { protected: proof_builder_cell * m_ptr; public: + proof_builder():m_ptr(nullptr) {} explicit proof_builder(proof_builder_cell * ptr):m_ptr(ptr) { lean_assert(m_ptr); m_ptr->inc_ref(); } proof_builder(proof_builder const & s):m_ptr(s.m_ptr) { if (m_ptr) m_ptr->inc_ref(); } proof_builder(proof_builder && s):m_ptr(s.m_ptr) { s.m_ptr = nullptr; } @@ -38,4 +41,17 @@ public: expr operator()(proof_map const & p, environment const & env, assignment const & a) const { return m_ptr->operator()(p, env, a); } }; + +template +class simple_proof_builder : public proof_builder_cell { + F m_f; +public: + simple_proof_builder(F && f):m_f(std::forward(f)) {} + virtual expr operator()(proof_map const & p, environment const & env, assignment const & a) const { return m_f(p, env, a); } +}; + +template +proof_builder mk_proof_builder(F && f) { + return proof_builder(new simple_proof_builder(std::forward(f))); +} } diff --git a/src/library/tactic/proof_state.cpp b/src/library/tactic/proof_state.cpp new file mode 100644 index 000000000..33a54883b --- /dev/null +++ b/src/library/tactic/proof_state.cpp @@ -0,0 +1,41 @@ +/* +Copyright (c) 2013 Microsoft Corporation. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. + +Author: Leonardo de Moura +*/ +#include "util/sstream.h" +#include "library/tactic/tactic_exception.h" +#include "library/tactic/proof_state.h" + +namespace lean { +void swap(proof_state & s1, proof_state & s2) { + swap(s1.m_env, s2.m_env); + swap(s1.m_goals, s2.m_goals); + swap(s1.m_menv, s2.m_menv); + swap(s1.m_proof_builder, s2.m_proof_builder); + swap(s1.m_justification_builder, s2.m_justification_builder); +} + +static name g_main("main"); + +proof_state to_proof_state(environment const & env, context const & ctx, expr const & t) { + auto p = to_goal(env, ctx, t); + goal g = p.first; + goal_proof_fn fn = p.second; + return proof_state(env, + goals(mk_pair(g_main, g)), + metavar_env(), + mk_proof_builder([=](proof_map const & m, environment const &, assignment const &) -> expr { + expr p = find(m, g_main); + if (!p) + throw tactic_exception(sstream() << "failed to find proof for '" << g_main << "' goal"); + return fn(p); + }), + mk_justification_builder([](name const & n, justification const & j, environment const &, assignment const &) -> justification { + if (n != g_main) + throw tactic_exception(sstream() << "unknown goal name '" << n << "'"); + return j; + })); +} +} diff --git a/src/library/tactic/proof_state.h b/src/library/tactic/proof_state.h index b6e280bf4..32d8e4947 100644 --- a/src/library/tactic/proof_state.h +++ b/src/library/tactic/proof_state.h @@ -11,19 +11,25 @@ Author: Leonardo de Moura #include "library/tactic/justification_builder.h" namespace lean { +typedef list> goals; class proof_state { - environment const m_env; - list> m_goals; + environment m_env; + goals m_goals; metavar_env m_menv; proof_builder m_proof_builder; justification_builder m_justification_builder; public: + proof_state() {} proof_state(environment const & env, list> const & gs, metavar_env const & menv, proof_builder const & p, justification_builder const & j): m_env(env), m_goals(gs), m_menv(menv), m_proof_builder(p), m_justification_builder(j) {} + friend void swap(proof_state & s1, proof_state & s2); environment const & get_environment() const { return m_env; } list> const & get_goals() const { return m_goals; } metavar_env const & get_menv() const { return m_menv; } proof_builder const & get_proof_builder() const { return m_proof_builder; } justification_builder const & get_justification_builder() const { return m_justification_builder; } }; +void swap(proof_state & s1, proof_state & s2); + +proof_state to_proof_state(environment const & env, context const & ctx, expr const & t); } diff --git a/src/library/tactic/tactic.cpp b/src/library/tactic/tactic.cpp index 86fcbb72d..23237b328 100644 --- a/src/library/tactic/tactic.cpp +++ b/src/library/tactic/tactic.cpp @@ -12,6 +12,10 @@ tactic_result::~tactic_result() { void tactic_result::interrupt() { m_result = true; } +void tactic_result::request_interrupt() { + std::lock_guard lock(m_mutex); + interrupt(); +} tactic_cell::~tactic_cell() { } @@ -23,4 +27,70 @@ tactic & tactic::operator=(tactic const & s) { tactic & tactic::operator=(tactic && s) { LEAN_MOVE_REF(tactic, s); } + +class id_tactic : public tactic_cell { +public: + class result : public tactic_result { + proof_state_ref m_r; + public: + result(proof_state const & s):m_r(new proof_state(s)) {} + + virtual proof_state_ref next() { + return proof_state_ref(std::move(m_r)); + } + }; + + virtual tactic_result_ref operator()(proof_state const & s) const { + return tactic_result_ref(new result(s)); + } +}; + +tactic idtac() { return tactic(new id_tactic()); } + +class then_tactic : public tactic_cell { + tactic m_t1; + tactic m_t2; +public: + then_tactic(tactic const & t1, tactic const & t2):m_t1(t1), m_t2(t2) {} + + class result : public tactic_result { + tactic_result_ref m_r1; + proof_state_ref m_s1; + tactic m_t2; + tactic_result_ref m_r2; + protected: + virtual void interrupt() { + tactic_result::interrupt(); + propagate_interrupt(m_r1); + propagate_interrupt(m_r2); + } + public: + result(tactic_result_ref && r1, tactic const & t2):m_r1(std::move(r1)), m_t2(t2) {} + + virtual proof_state_ref next() { + if (m_r2) { + proof_state_ref s2 = m_r2->next(); + if (s2) + return s2; + m_r2.release(); + m_s1.release(); + } + lean_assert(!m_r2); + lean_assert(!m_s1); + proof_state_ref new_s1(m_r1->next()); + if (!new_s1) + return proof_state_ref(); // done, m_r1 has no more solutions + m_s1.swap(new_s1); + tactic_result_ref r2 = m_t2(proof_state(*m_s1)); + exclusive_update([&]() { m_r2.swap(r2); }); // must protect because interrupt() may be invoked from different thread + return m_r2->next(); + } + }; + + virtual tactic_result_ref operator()(proof_state const & s) const { + return tactic_result_ref(new result(m_t1(s), m_t2)); + } +}; + +tactic then(tactic const & t1, tactic const & t2) { return tactic(new then_tactic(t1, t2)); } } diff --git a/src/library/tactic/tactic.h b/src/library/tactic/tactic.h index 9bd25490e..139b3952d 100644 --- a/src/library/tactic/tactic.h +++ b/src/library/tactic/tactic.h @@ -7,27 +7,39 @@ Author: Leonardo de Moura #pragma once #include #include +#include #include "library/tactic/proof_state.h" namespace lean { +typedef std::unique_ptr proof_state_ref; +class tactic_result; +typedef std::unique_ptr tactic_result_ref; + class tactic_result { - volatile bool m_result; + std::mutex m_mutex; + bool m_result; +protected: + template + void exclusive_update(F && f) { + std::lock_guard lock(m_mutex); + f(); + } + virtual void interrupt(); + void propagate_interrupt(tactic_result_ref & r) { if (r) r->interrupt(); } public: tactic_result():m_result(false) {} bool interrupted() const { return m_result; } + void request_interrupt(); virtual ~tactic_result(); - virtual void interrupt(); - virtual proof_state next() = 0; + virtual proof_state_ref next() = 0; }; -typedef std::unique_ptr tactic_result_ref; - class tactic_cell { void dealloc() { delete this; } MK_LEAN_RC(); public: virtual ~tactic_cell(); - virtual tactic_result_ref operator()(proof_state const & p) const = 0; + virtual tactic_result_ref operator()(proof_state const & s) const = 0; }; class tactic { @@ -42,7 +54,9 @@ public: tactic & operator=(tactic const & s); tactic & operator=(tactic && s); - tactic_result_ref operator()(proof_state const & p) const { return m_ptr->operator()(p); } + tactic_result_ref operator()(proof_state const & s) const { return m_ptr->operator()(s); } }; -} +tactic idtac(); +tactic then(tactic const & t1, tactic const & t2); +} diff --git a/src/library/tactic/tactic_exception.h b/src/library/tactic/tactic_exception.h new file mode 100644 index 000000000..49bdc529c --- /dev/null +++ b/src/library/tactic/tactic_exception.h @@ -0,0 +1,17 @@ +/* +Copyright (c) 2013 Microsoft Corporation. All rights reserved. +Released under Apache 2.0 license as described in the file LICENSE. + +Author: Leonardo de Moura +*/ +#pragma once +#include "util/exception.h" + +namespace lean { +class tactic_exception : public exception { +public: + tactic_exception(char const * msg):exception(msg) {} + tactic_exception(std::string const & msg):exception(msg) {} + tactic_exception(sstream const & strm):exception(strm) {} +}; +}