/* Copyright (c) 2013-2014 Microsoft Corporation. All rights reserved. Released under Apache 2.0 license as described in the file LICENSE. Author: Leonardo de Moura */ #include #include #include "util/buffer.h" #include "util/sstream.h" #include "util/sexpr/option_declarations.h" #include "kernel/replace_fn.h" #include "kernel/for_each_fn.h" #include "kernel/abstract.h" #include "kernel/type_checker.h" #include "kernel/metavar.h" #include "library/kernel_bindings.h" #include "library/tactic/goal.h" #ifndef LEAN_DEFAULT_PP_COMPACT_GOALS #define LEAN_DEFAULT_PP_COMPACT_GOALS false #endif namespace lean { 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); } local_context goal::to_local_context() const { buffer hyps; get_hyps(hyps); std::reverse(hyps.begin(), hyps.end()); return local_context(to_list(hyps)); } format goal::pp(formatter const & fmt) const { return pp(fmt, substitution()); } format goal::pp(formatter const & fmt, substitution const & s) const { substitution tmp_subst(s); options const & opts = fmt.get_options(); unsigned indent = get_pp_indent(opts); bool unicode = get_pp_unicode(opts); bool compact = get_pp_compact_goals(opts); format turnstile = unicode ? format("\u22A2") /* ⊢ */ : format("|-"); expr conclusion = m_type; buffer tmp; get_app_args(m_meta, tmp); format r; unsigned i = 0; while (i < tmp.size()) { if (i > 0) r += compose(comma(), line()); expr l = tmp[i]; format ids = fmt(l); expr t = tmp_subst.instantiate(mlocal_type(l)); 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++; } if (compact) r = group(r); r += line() + turnstile + space() + nest(indent, fmt(tmp_subst.instantiate(conclusion))); if (compact) r = group(r); return r; } expr goal::abstract(expr const & v) const { buffer locals; get_app_args(m_meta, locals); return Fun(locals, v); } expr goal::mk_meta(name const & n, expr const & type) const { buffer locals; 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)); } goal goal::instantiate(substitution const & s) const { substitution s1(s); return goal(s1.instantiate_all(m_meta), s1.instantiate_all(m_type)); } static bool validate_locals(expr const & r, unsigned num_locals, expr const * locals) { bool failed = false; for_each(r, [&](expr const & e, unsigned) { if (!has_local(e) || failed) return false; if (is_local(e) && !std::any_of(locals, locals + num_locals, [&](expr const & l) { return mlocal_name(l) == mlocal_name(e); })) { failed = true; return false; } return true; }); return !failed; } bool goal::validate_locals() const { buffer locals; get_app_args(m_meta, locals); if (!::lean::validate_locals(m_type, locals.size(), locals.data())) return false; unsigned i = locals.size(); while (i > 0) { --i; if (!::lean::validate_locals(mlocal_type(locals[i]), i, locals.data())) return false; } return true; } bool goal::validate(environment const & env) const { if (validate_locals()) { type_checker tc(env); return tc.is_def_eq(tc.check(m_meta).first, m_type).first; } else { return false; } } list goal::to_context() const { buffer locals; get_app_rev_args(m_meta, locals); return to_list(locals.begin(), locals.end()); } optional> goal::find_hyp(name const & uname) const { expr const * it = &m_meta; unsigned i = 0; while (is_app(*it)) { expr const & h = app_arg(*it); if (local_pp_name(h) == uname) return some(mk_pair(h, i)); i++; it = &app_fn(*it); } return optional>(); } void goal::get_hyps(buffer & r) const { get_app_args(m_meta, r); } static bool uses_name(name const & n, buffer const & locals) { for (expr const & local : locals) { if (is_local(local) && local_pp_name(local) == n) return true; } return false; } name get_unused_name(name const & prefix, unsigned & idx, buffer const & locals) { while (true) { name curr = prefix.append_after(idx); idx++; if (!uses_name(curr, locals)) return curr; } } name get_unused_name(name const & prefix, buffer const & locals) { if (!uses_name(prefix, locals)) return prefix; unsigned idx = 1; return get_unused_name(prefix, idx, locals); } name get_unused_name(name const & prefix, unsigned & idx, expr const & meta) { buffer locals; get_app_rev_args(meta, locals); return get_unused_name(prefix, idx, locals); } name get_unused_name(name const & prefix, expr const & meta) { buffer locals; 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); } name goal::get_unused_name(name const & prefix) const { return ::lean::get_unused_name(prefix, m_meta); } 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; } DECL_UDATA(goal) 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()); } static int goal_tostring(lua_State * L) { std::ostringstream out; goal & g = to_goal(L, 1); formatter fmt = mk_formatter(L); options opts = get_global_options(L); out << mk_pair(g.pp(fmt), opts); lua_pushstring(L, out.str().c_str()); return 1; } static int goal_mk_meta(lua_State * L) { return push_expr(L, to_goal(L, 1).mk_meta(to_name_ext(L, 2), to_expr(L, 3))); } static int goal_pp(lua_State * L) { int nargs = lua_gettop(L); goal & g = to_goal(L, 1); if (nargs == 1) { return push_format(L, g.pp(mk_formatter(L))); } else { return push_format(L, g.pp(to_formatter(L, 2))); } } 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()); } static const struct luaL_Reg goal_m[] = { {"__gc", goal_gc}, // never throws {"__tostring", safe_function}, {"abstract", safe_function}, {"mk_meta", safe_function}, {"pp", safe_function}, {"validate", safe_function}, {"validate_locals", safe_function}, {"meta", safe_function}, {"type", safe_function}, {"name", safe_function}, {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"); } }