2013-11-21 01:02:41 +00:00
|
|
|
/*
|
2014-06-27 13:59:17 +00:00
|
|
|
Copyright (c) 2013-2014 Microsoft Corporation. All rights reserved.
|
2013-11-21 01:02:41 +00:00
|
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
|
|
|
|
Author: Leonardo de Moura
|
|
|
|
*/
|
|
|
|
#include <utility>
|
2015-02-07 00:09:59 +00:00
|
|
|
#include <algorithm>
|
2013-11-21 01:02:41 +00:00
|
|
|
#include "util/buffer.h"
|
2014-06-27 18:11:12 +00:00
|
|
|
#include "util/sstream.h"
|
2014-10-28 23:25:16 +00:00
|
|
|
#include "util/sexpr/option_declarations.h"
|
2014-06-27 18:11:12 +00:00
|
|
|
#include "kernel/replace_fn.h"
|
|
|
|
#include "kernel/for_each_fn.h"
|
|
|
|
#include "kernel/abstract.h"
|
2014-07-01 23:11:19 +00:00
|
|
|
#include "kernel/type_checker.h"
|
2014-10-15 00:37:20 +00:00
|
|
|
#include "kernel/metavar.h"
|
2013-11-27 03:15:49 +00:00
|
|
|
#include "library/kernel_bindings.h"
|
2013-11-21 01:02:41 +00:00
|
|
|
#include "library/tactic/goal.h"
|
|
|
|
|
2014-10-28 23:25:16 +00:00
|
|
|
#ifndef LEAN_DEFAULT_PP_COMPACT_GOALS
|
|
|
|
#define LEAN_DEFAULT_PP_COMPACT_GOALS false
|
|
|
|
#endif
|
|
|
|
|
2013-11-21 01:02:41 +00:00
|
|
|
namespace lean {
|
2014-10-28 23:25:16 +00:00
|
|
|
static name * g_pp_compact_goals = nullptr;
|
|
|
|
void initialize_goal() {
|
|
|
|
g_pp_compact_goals = new name({"pp", "compact_goals"});
|
|
|
|
register_bool_option(*g_pp_compact_goals, LEAN_DEFAULT_PP_COMPACT_GOALS,
|
|
|
|
"(pretty printer) try to display goal in a single line when possible");
|
|
|
|
}
|
|
|
|
void finalize_goal() {
|
|
|
|
delete g_pp_compact_goals;
|
|
|
|
}
|
|
|
|
bool get_pp_compact_goals(options const & o) {
|
|
|
|
return o.get_bool(*g_pp_compact_goals, LEAN_DEFAULT_PP_COMPACT_GOALS);
|
|
|
|
}
|
|
|
|
|
2015-02-07 00:09:59 +00:00
|
|
|
local_context goal::to_local_context() const {
|
|
|
|
buffer<expr> hyps;
|
|
|
|
get_hyps(hyps);
|
|
|
|
std::reverse(hyps.begin(), hyps.end());
|
|
|
|
return local_context(to_list(hyps));
|
|
|
|
}
|
|
|
|
|
2014-07-10 17:32:00 +00:00
|
|
|
format goal::pp(formatter const & fmt) const {
|
2014-10-15 00:37:20 +00:00
|
|
|
return pp(fmt, substitution());
|
|
|
|
}
|
|
|
|
|
|
|
|
format goal::pp(formatter const & fmt, substitution const & s) const {
|
|
|
|
substitution tmp_subst(s);
|
2014-07-10 17:32:00 +00:00
|
|
|
options const & opts = fmt.get_options();
|
2013-11-22 00:44:31 +00:00
|
|
|
unsigned indent = get_pp_indent(opts);
|
|
|
|
bool unicode = get_pp_unicode(opts);
|
2014-10-28 23:25:16 +00:00
|
|
|
bool compact = get_pp_compact_goals(opts);
|
2013-11-22 00:44:31 +00:00
|
|
|
format turnstile = unicode ? format("\u22A2") /* ⊢ */ : format("|-");
|
2014-07-01 23:11:19 +00:00
|
|
|
expr conclusion = m_type;
|
|
|
|
buffer<expr> tmp;
|
|
|
|
get_app_args(m_meta, tmp);
|
2013-11-22 00:44:31 +00:00
|
|
|
format r;
|
2015-01-13 19:10:28 +00:00
|
|
|
unsigned i = 0;
|
|
|
|
while (i < tmp.size()) {
|
|
|
|
if (i > 0)
|
|
|
|
r += compose(comma(), line());
|
|
|
|
expr l = tmp[i];
|
|
|
|
format ids = fmt(l);
|
2014-10-15 00:37:20 +00:00
|
|
|
expr t = tmp_subst.instantiate(mlocal_type(l));
|
2015-01-13 19:10:28 +00:00
|
|
|
lean_assert(tmp.size() > 0);
|
|
|
|
while (i < tmp.size() - 1) {
|
|
|
|
expr l2 = tmp[i+1];
|
|
|
|
expr t2 = tmp_subst.instantiate(mlocal_type(l2));
|
|
|
|
if (t2 != t)
|
|
|
|
break;
|
|
|
|
ids += space() + fmt(l2);
|
|
|
|
i++;
|
|
|
|
}
|
|
|
|
r += group(ids + space() + colon() + nest(indent, line() + fmt(t)));
|
|
|
|
i++;
|
2013-11-22 00:44:31 +00:00
|
|
|
}
|
2014-10-28 23:25:16 +00:00
|
|
|
if (compact)
|
|
|
|
r = group(r);
|
2014-10-15 00:37:20 +00:00
|
|
|
r += line() + turnstile + space() + nest(indent, fmt(tmp_subst.instantiate(conclusion)));
|
2014-10-28 23:25:16 +00:00
|
|
|
if (compact)
|
|
|
|
r = group(r);
|
|
|
|
return r;
|
2013-11-22 00:44:31 +00:00
|
|
|
}
|
|
|
|
|
2014-07-01 23:11:19 +00:00
|
|
|
expr goal::abstract(expr const & v) const {
|
|
|
|
buffer<expr> locals;
|
|
|
|
get_app_args(m_meta, locals);
|
|
|
|
return Fun(locals, v);
|
|
|
|
}
|
|
|
|
|
2014-10-24 04:22:52 +00:00
|
|
|
expr goal::mk_meta(name const & n, expr const & type) const {
|
2014-07-01 23:11:19 +00:00
|
|
|
buffer<expr> locals;
|
2014-07-02 21:47:18 +00:00
|
|
|
expr this_mvar = get_app_args(m_meta, locals);
|
|
|
|
expr mvar = copy_tag(this_mvar, mk_metavar(n, Pi(locals, type)));
|
|
|
|
return copy_tag(m_meta, mk_app(mvar, locals));
|
2014-06-27 18:11:12 +00:00
|
|
|
}
|
|
|
|
|
2014-10-28 23:39:21 +00:00
|
|
|
goal goal::instantiate(substitution const & s) const {
|
|
|
|
substitution s1(s);
|
|
|
|
return goal(s1.instantiate_all(m_meta), s1.instantiate_all(m_type));
|
|
|
|
}
|
|
|
|
|
2014-07-01 23:11:19 +00:00
|
|
|
static bool validate_locals(expr const & r, unsigned num_locals, expr const * locals) {
|
2014-06-27 18:11:12 +00:00
|
|
|
bool failed = false;
|
|
|
|
for_each(r, [&](expr const & e, unsigned) {
|
|
|
|
if (!has_local(e) || failed) return false;
|
|
|
|
if (is_local(e) &&
|
2014-07-01 23:11:19 +00:00
|
|
|
!std::any_of(locals, locals + num_locals,
|
|
|
|
[&](expr const & l) { return mlocal_name(l) == mlocal_name(e); })) {
|
2014-06-27 18:11:12 +00:00
|
|
|
failed = true;
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
});
|
|
|
|
return !failed;
|
|
|
|
}
|
|
|
|
|
2014-07-01 23:11:19 +00:00
|
|
|
bool goal::validate_locals() const {
|
|
|
|
buffer<expr> locals;
|
|
|
|
get_app_args(m_meta, locals);
|
|
|
|
if (!::lean::validate_locals(m_type, locals.size(), locals.data()))
|
2014-06-27 18:11:12 +00:00
|
|
|
return false;
|
2014-07-01 23:11:19 +00:00
|
|
|
unsigned i = locals.size();
|
|
|
|
while (i > 0) {
|
|
|
|
--i;
|
|
|
|
if (!::lean::validate_locals(mlocal_type(locals[i]), i, locals.data()))
|
2014-06-27 18:11:12 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
2014-07-01 23:11:19 +00:00
|
|
|
bool goal::validate(environment const & env) const {
|
|
|
|
if (validate_locals()) {
|
|
|
|
type_checker tc(env);
|
2014-08-20 05:31:26 +00:00
|
|
|
return tc.is_def_eq(tc.check(m_meta).first, m_type).first;
|
2013-11-27 03:15:49 +00:00
|
|
|
} else {
|
2014-07-01 23:11:19 +00:00
|
|
|
return false;
|
2013-11-27 03:15:49 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-10-15 00:12:57 +00:00
|
|
|
list<expr> goal::to_context() const {
|
|
|
|
buffer<expr> locals;
|
|
|
|
get_app_rev_args(m_meta, locals);
|
|
|
|
return to_list(locals.begin(), locals.end());
|
|
|
|
}
|
|
|
|
|
2015-03-12 03:39:41 +00:00
|
|
|
template<typename F>
|
|
|
|
static optional<pair<expr, unsigned>> find_hyp_core(expr const & meta, F && pred) {
|
|
|
|
expr const * it = &meta;
|
2014-11-27 01:08:14 +00:00
|
|
|
unsigned i = 0;
|
|
|
|
while (is_app(*it)) {
|
|
|
|
expr const & h = app_arg(*it);
|
2015-03-12 03:39:41 +00:00
|
|
|
if (pred(h))
|
2014-11-27 01:08:14 +00:00
|
|
|
return some(mk_pair(h, i));
|
|
|
|
i++;
|
|
|
|
it = &app_fn(*it);
|
|
|
|
}
|
|
|
|
return optional<pair<expr, unsigned>>();
|
|
|
|
}
|
|
|
|
|
2015-03-12 03:39:41 +00:00
|
|
|
optional<pair<expr, unsigned>> goal::find_hyp(name const & uname) const {
|
|
|
|
return find_hyp_core(m_meta, [&](expr const & h) { return local_pp_name(h) == uname; });
|
|
|
|
}
|
|
|
|
|
|
|
|
optional<pair<expr, unsigned>> goal::find_hyp_from_internal_name(name const & n) const {
|
|
|
|
return find_hyp_core(m_meta, [&](expr const & h) { return mlocal_name(h) == n; });
|
|
|
|
}
|
|
|
|
|
2014-11-27 01:08:14 +00:00
|
|
|
void goal::get_hyps(buffer<expr> & r) const {
|
|
|
|
get_app_args(m_meta, r);
|
|
|
|
}
|
|
|
|
|
2015-03-12 21:13:01 +00:00
|
|
|
void assign(substitution & s, goal const & g, expr const & v) {
|
|
|
|
buffer<expr> hyps;
|
|
|
|
expr const & mvar = get_app_args(g.get_meta(), hyps);
|
|
|
|
s.assign(mvar, hyps, v);
|
|
|
|
}
|
|
|
|
|
2014-11-29 03:39:07 +00:00
|
|
|
static bool uses_name(name const & n, buffer<expr> const & locals) {
|
|
|
|
for (expr const & local : locals) {
|
|
|
|
if (is_local(local) && local_pp_name(local) == n)
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2014-11-27 08:06:26 +00:00
|
|
|
name get_unused_name(name const & prefix, unsigned & idx, buffer<expr> const & locals) {
|
2014-11-27 02:46:08 +00:00
|
|
|
while (true) {
|
|
|
|
name curr = prefix.append_after(idx);
|
|
|
|
idx++;
|
2014-11-29 03:39:07 +00:00
|
|
|
if (!uses_name(curr, locals))
|
2014-11-27 02:46:08 +00:00
|
|
|
return curr;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-11-27 08:06:26 +00:00
|
|
|
name get_unused_name(name const & prefix, buffer<expr> const & locals) {
|
2014-11-29 03:39:07 +00:00
|
|
|
if (!uses_name(prefix, locals))
|
|
|
|
return prefix;
|
2014-11-27 08:06:26 +00:00
|
|
|
unsigned idx = 1;
|
|
|
|
return get_unused_name(prefix, idx, locals);
|
|
|
|
}
|
|
|
|
|
2014-11-29 03:39:07 +00:00
|
|
|
name get_unused_name(name const & prefix, unsigned & idx, expr const & meta) {
|
|
|
|
buffer<expr> locals;
|
|
|
|
get_app_rev_args(meta, locals);
|
|
|
|
return get_unused_name(prefix, idx, locals);
|
|
|
|
}
|
|
|
|
|
|
|
|
name get_unused_name(name const & prefix, expr const & meta) {
|
2014-11-27 08:06:26 +00:00
|
|
|
buffer<expr> locals;
|
2014-11-29 03:39:07 +00:00
|
|
|
get_app_rev_args(meta, locals);
|
|
|
|
return get_unused_name(prefix, locals);
|
|
|
|
}
|
|
|
|
|
|
|
|
name goal::get_unused_name(name const & prefix, unsigned & idx) const {
|
|
|
|
return ::lean::get_unused_name(prefix, idx, m_meta);
|
2014-11-27 08:06:26 +00:00
|
|
|
}
|
|
|
|
|
2014-11-27 02:46:08 +00:00
|
|
|
name goal::get_unused_name(name const & prefix) const {
|
2014-11-29 03:39:07 +00:00
|
|
|
return ::lean::get_unused_name(prefix, m_meta);
|
2014-11-27 02:46:08 +00:00
|
|
|
}
|
|
|
|
|
2014-10-28 23:39:21 +00:00
|
|
|
io_state_stream const & operator<<(io_state_stream const & out, goal const & g) {
|
|
|
|
options const & opts = out.get_options();
|
|
|
|
out.get_stream() << mk_pair(g.pp(out.get_formatter()), opts);
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2013-11-27 03:15:49 +00:00
|
|
|
DECL_UDATA(goal)
|
|
|
|
|
2014-07-01 23:11:19 +00:00
|
|
|
static int mk_goal(lua_State * L) { return push_goal(L, goal(to_expr(L, 1), to_expr(L, 2))); }
|
|
|
|
static int goal_meta(lua_State * L) { return push_expr(L, to_goal(L, 1).get_meta()); }
|
|
|
|
static int goal_type(lua_State * L) { return push_expr(L, to_goal(L, 1).get_type()); }
|
2013-11-27 03:15:49 +00:00
|
|
|
static int goal_tostring(lua_State * L) {
|
|
|
|
std::ostringstream out;
|
|
|
|
goal & g = to_goal(L, 1);
|
2014-07-10 17:32:00 +00:00
|
|
|
formatter fmt = mk_formatter(L);
|
2014-06-27 13:59:17 +00:00
|
|
|
options opts = get_global_options(L);
|
2014-07-10 17:32:00 +00:00
|
|
|
out << mk_pair(g.pp(fmt), opts);
|
2013-11-27 03:15:49 +00:00
|
|
|
lua_pushstring(L, out.str().c_str());
|
|
|
|
return 1;
|
|
|
|
}
|
2014-07-01 23:11:19 +00:00
|
|
|
static int goal_mk_meta(lua_State * L) {
|
2014-10-24 04:22:52 +00:00
|
|
|
return push_expr(L, to_goal(L, 1).mk_meta(to_name_ext(L, 2), to_expr(L, 3)));
|
2014-07-01 23:11:19 +00:00
|
|
|
}
|
|
|
|
|
2013-11-27 03:15:49 +00:00
|
|
|
static int goal_pp(lua_State * L) {
|
|
|
|
int nargs = lua_gettop(L);
|
|
|
|
goal & g = to_goal(L, 1);
|
2013-12-08 07:21:07 +00:00
|
|
|
if (nargs == 1) {
|
2014-07-10 17:32:00 +00:00
|
|
|
return push_format(L, g.pp(mk_formatter(L)));
|
2013-11-27 03:15:49 +00:00
|
|
|
} else {
|
2014-07-10 17:32:00 +00:00
|
|
|
return push_format(L, g.pp(to_formatter(L, 2)));
|
2013-11-27 03:15:49 +00:00
|
|
|
}
|
|
|
|
}
|
2014-07-01 23:11:19 +00:00
|
|
|
static int goal_validate_locals(lua_State * L) { return push_boolean(L, to_goal(L, 1).validate_locals()); }
|
|
|
|
static int goal_validate(lua_State * L) { return push_boolean(L, to_goal(L, 1).validate(to_environment(L, 2))); }
|
|
|
|
static int goal_abstract(lua_State * L) { return push_expr(L, to_goal(L, 1).abstract(to_expr(L, 2))); }
|
|
|
|
static int goal_name(lua_State * L) { return push_name(L, to_goal(L, 1).get_name()); }
|
2013-11-27 03:15:49 +00:00
|
|
|
|
|
|
|
static const struct luaL_Reg goal_m[] = {
|
|
|
|
{"__gc", goal_gc}, // never throws
|
|
|
|
{"__tostring", safe_function<goal_tostring>},
|
2014-07-01 23:11:19 +00:00
|
|
|
{"abstract", safe_function<goal_abstract>},
|
2014-06-27 18:11:12 +00:00
|
|
|
{"mk_meta", safe_function<goal_mk_meta>},
|
2013-11-27 03:15:49 +00:00
|
|
|
{"pp", safe_function<goal_pp>},
|
2014-06-27 18:11:12 +00:00
|
|
|
{"validate", safe_function<goal_validate>},
|
2014-07-01 23:11:19 +00:00
|
|
|
{"validate_locals", safe_function<goal_validate_locals>},
|
|
|
|
{"meta", safe_function<goal_meta>},
|
|
|
|
{"type", safe_function<goal_type>},
|
|
|
|
{"name", safe_function<goal_name>},
|
2013-11-27 03:15:49 +00:00
|
|
|
{0, 0}
|
|
|
|
};
|
|
|
|
|
|
|
|
void open_goal(lua_State * L) {
|
|
|
|
luaL_newmetatable(L, goal_mt);
|
|
|
|
lua_pushvalue(L, -1);
|
|
|
|
lua_setfield(L, -2, "__index");
|
|
|
|
setfuncs(L, goal_m, 0);
|
|
|
|
|
|
|
|
SET_GLOBAL_FUN(goal_pred, "is_goal");
|
|
|
|
SET_GLOBAL_FUN(mk_goal, "goal");
|
|
|
|
}
|
2013-11-21 01:02:41 +00:00
|
|
|
}
|