2014-07-09 08:12:36 +00:00
|
|
|
/*
|
|
|
|
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 "util/flet.h"
|
|
|
|
#include "kernel/replace_fn.h"
|
|
|
|
#include "kernel/free_vars.h"
|
2014-08-29 01:20:58 +00:00
|
|
|
#include "kernel/abstract.h"
|
|
|
|
#include "kernel/instantiate.h"
|
2014-08-22 17:38:10 +00:00
|
|
|
#include "library/annotation.h"
|
2014-07-09 08:12:36 +00:00
|
|
|
#include "library/aliases.h"
|
|
|
|
#include "library/scoped_ext.h"
|
|
|
|
#include "library/coercion.h"
|
2014-07-10 01:47:10 +00:00
|
|
|
#include "library/expr_pair.h"
|
2014-07-25 15:46:03 +00:00
|
|
|
#include "library/placeholder.h"
|
2014-07-25 17:58:13 +00:00
|
|
|
#include "library/private.h"
|
2014-07-29 21:26:27 +00:00
|
|
|
#include "library/explicit.h"
|
2014-08-22 18:26:00 +00:00
|
|
|
#include "library/typed_expr.h"
|
2014-08-14 16:11:34 +00:00
|
|
|
#include "library/num.h"
|
2014-08-29 01:20:58 +00:00
|
|
|
#include "library/let.h"
|
2014-08-22 17:32:01 +00:00
|
|
|
#include "library/print.h"
|
2014-07-09 08:12:36 +00:00
|
|
|
#include "frontends/lean/pp.h"
|
|
|
|
#include "frontends/lean/pp_options.h"
|
|
|
|
#include "frontends/lean/token_table.h"
|
2014-07-27 04:56:35 +00:00
|
|
|
#include "frontends/lean/builtin_exprs.h"
|
2014-07-09 08:12:36 +00:00
|
|
|
|
|
|
|
namespace lean {
|
2014-09-23 17:00:36 +00:00
|
|
|
static format * g_ellipsis_n_fmt = nullptr;
|
|
|
|
static format * g_ellipsis_fmt = nullptr;
|
|
|
|
static format * g_placeholder_fmt = nullptr;
|
|
|
|
static format * g_lambda_n_fmt = nullptr;
|
|
|
|
static format * g_lambda_fmt = nullptr;
|
|
|
|
static format * g_forall_n_fmt = nullptr;
|
|
|
|
static format * g_forall_fmt = nullptr;
|
|
|
|
static format * g_pi_n_fmt = nullptr;
|
|
|
|
static format * g_pi_fmt = nullptr;
|
|
|
|
static format * g_arrow_n_fmt = nullptr;
|
|
|
|
static format * g_arrow_fmt = nullptr;
|
|
|
|
static format * g_let_fmt = nullptr;
|
|
|
|
static format * g_in_fmt = nullptr;
|
|
|
|
static format * g_assign_fmt = nullptr;
|
|
|
|
static format * g_have_fmt = nullptr;
|
|
|
|
static format * g_from_fmt = nullptr;
|
|
|
|
static format * g_visible_fmt = nullptr;
|
|
|
|
static format * g_show_fmt = nullptr;
|
|
|
|
static format * g_explicit_fmt = nullptr;
|
|
|
|
static name * g_tmp_prefix = nullptr;
|
|
|
|
|
|
|
|
void initialize_pp() {
|
|
|
|
g_ellipsis_n_fmt = new format(highlight(format("\u2026")));
|
|
|
|
g_ellipsis_fmt = new format(highlight(format("...")));
|
|
|
|
g_placeholder_fmt = new format(highlight(format("_")));
|
|
|
|
g_lambda_n_fmt = new format(highlight_keyword(format("\u03BB")));
|
|
|
|
g_lambda_fmt = new format(highlight_keyword(format("fun")));
|
|
|
|
g_forall_n_fmt = new format(highlight_keyword(format("\u2200")));
|
|
|
|
g_forall_fmt = new format(highlight_keyword(format("forall")));
|
|
|
|
g_pi_n_fmt = new format(highlight_keyword(format("Π")));
|
|
|
|
g_pi_fmt = new format(highlight_keyword(format("Pi")));
|
|
|
|
g_arrow_n_fmt = new format(highlight_keyword(format("\u2192")));
|
|
|
|
g_arrow_fmt = new format(highlight_keyword(format("->")));
|
|
|
|
g_let_fmt = new format(highlight_keyword(format("let")));
|
|
|
|
g_in_fmt = new format(highlight_keyword(format("in")));
|
|
|
|
g_assign_fmt = new format(highlight_keyword(format(":=")));
|
|
|
|
g_have_fmt = new format(highlight_keyword(format("have")));
|
|
|
|
g_from_fmt = new format(highlight_keyword(format("from")));
|
|
|
|
g_visible_fmt = new format(highlight_keyword(format("[visible]")));
|
|
|
|
g_show_fmt = new format(highlight_keyword(format("show")));
|
|
|
|
g_explicit_fmt = new format(highlight_keyword(format("@")));
|
|
|
|
g_tmp_prefix = new name(name::mk_internal_unique_name());
|
|
|
|
}
|
|
|
|
|
|
|
|
void finalize_pp() {
|
|
|
|
delete g_ellipsis_n_fmt;
|
|
|
|
delete g_ellipsis_fmt;
|
|
|
|
delete g_placeholder_fmt;
|
|
|
|
delete g_lambda_n_fmt;
|
|
|
|
delete g_lambda_fmt;
|
|
|
|
delete g_forall_n_fmt;
|
|
|
|
delete g_forall_fmt;
|
|
|
|
delete g_pi_n_fmt;
|
|
|
|
delete g_pi_fmt;
|
|
|
|
delete g_arrow_n_fmt;
|
|
|
|
delete g_arrow_fmt;
|
|
|
|
delete g_let_fmt;
|
|
|
|
delete g_in_fmt;
|
|
|
|
delete g_assign_fmt;
|
|
|
|
delete g_have_fmt;
|
|
|
|
delete g_from_fmt;
|
|
|
|
delete g_visible_fmt;
|
|
|
|
delete g_show_fmt;
|
|
|
|
delete g_explicit_fmt;
|
|
|
|
delete g_tmp_prefix;
|
|
|
|
}
|
2014-07-09 08:12:36 +00:00
|
|
|
|
|
|
|
name pretty_fn::mk_metavar_name(name const & m) {
|
|
|
|
if (auto it = m_purify_meta_table.find(m))
|
|
|
|
return *it;
|
|
|
|
name new_m = m_meta_prefix.append_after(m_next_meta_idx);
|
|
|
|
m_next_meta_idx++;
|
|
|
|
m_purify_meta_table.insert(m, new_m);
|
|
|
|
return new_m;
|
|
|
|
}
|
|
|
|
|
2014-07-10 13:13:51 +00:00
|
|
|
name pretty_fn::mk_local_name(name const & n, name const & suggested) {
|
|
|
|
if (auto it = m_purify_local_table.find(n))
|
|
|
|
return *it;
|
2014-07-09 08:12:36 +00:00
|
|
|
unsigned i = 1;
|
2014-07-10 13:13:51 +00:00
|
|
|
name r = suggested;
|
|
|
|
while (m_purify_used_locals.contains(r)) {
|
|
|
|
r = suggested.append_after(i);
|
2014-07-09 08:12:36 +00:00
|
|
|
i++;
|
|
|
|
}
|
2014-07-10 13:13:51 +00:00
|
|
|
m_purify_used_locals.insert(r);
|
|
|
|
m_purify_local_table.insert(n, r);
|
2014-07-09 08:12:36 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
level pretty_fn::purify(level const & l) {
|
|
|
|
if (!m_universes || !has_meta(l))
|
|
|
|
return l;
|
|
|
|
return replace(l, [&](level const & l) {
|
|
|
|
if (!has_meta(l))
|
|
|
|
return some_level(l);
|
|
|
|
if (is_meta(l))
|
|
|
|
return some_level(mk_meta_univ(mk_metavar_name(meta_id(l))));
|
|
|
|
return none_level();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
|
|
|
/** \brief Make sure that all metavariables have reasonable names,
|
|
|
|
and for all local constants l1 l2, local_pp_name(l1) != local_pp_name(l2).
|
|
|
|
|
|
|
|
\remark pretty_fn will create new local constants when pretty printing,
|
|
|
|
but it will make sure that the new constants will not produce collisions.
|
|
|
|
*/
|
|
|
|
expr pretty_fn::purify(expr const & e) {
|
|
|
|
if (!has_expr_metavar(e) && !has_local(e) && (!m_universes || !has_univ_metavar(e)))
|
|
|
|
return e;
|
|
|
|
return replace(e, [&](expr const & e, unsigned) {
|
|
|
|
if (!has_expr_metavar(e) && !has_local(e) && (!m_universes || !has_univ_metavar(e)))
|
|
|
|
return some_expr(e);
|
|
|
|
else if (is_metavar(e))
|
|
|
|
return some_expr(mk_metavar(mk_metavar_name(mlocal_name(e)), mlocal_type(e)));
|
|
|
|
else if (is_local(e))
|
2014-07-10 13:13:51 +00:00
|
|
|
return some_expr(mk_local(mlocal_name(e), mk_local_name(mlocal_name(e), local_pp_name(e)), mlocal_type(e), local_info(e)));
|
2014-07-09 08:12:36 +00:00
|
|
|
else if (is_constant(e))
|
|
|
|
return some_expr(update_constant(e, map(const_levels(e), [&](level const & l) { return purify(l); })));
|
|
|
|
else if (is_sort(e))
|
|
|
|
return some_expr(update_sort(e, purify(sort_level(e))));
|
|
|
|
else
|
|
|
|
return none_expr();
|
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2014-07-27 16:41:25 +00:00
|
|
|
void pretty_fn::set_options_core(options const & o) {
|
|
|
|
m_options = o;
|
2014-07-25 18:03:54 +00:00
|
|
|
m_indent = get_pp_indent(o);
|
|
|
|
m_max_depth = get_pp_max_depth(o);
|
|
|
|
m_max_steps = get_pp_max_steps(o);
|
|
|
|
m_implict = get_pp_implicit(o);
|
|
|
|
m_unicode = get_pp_unicode(o);
|
2014-09-08 15:30:08 +00:00
|
|
|
m_coercion = get_pp_coercions(o);
|
2014-07-25 18:03:54 +00:00
|
|
|
m_notation = get_pp_notation(o);
|
|
|
|
m_universes = get_pp_universes(o);
|
|
|
|
m_full_names = get_pp_full_names(o);
|
|
|
|
m_private_names = get_pp_private_names(o);
|
2014-07-31 23:44:57 +00:00
|
|
|
m_metavar_args = get_pp_metavar_args(o);
|
2014-09-09 21:10:20 +00:00
|
|
|
m_beta = get_pp_beta(o);
|
2014-07-09 08:12:36 +00:00
|
|
|
}
|
|
|
|
|
2014-07-27 16:41:25 +00:00
|
|
|
void pretty_fn::set_options(options const & o) {
|
|
|
|
if (is_eqp(o, m_options))
|
|
|
|
return;
|
|
|
|
set_options_core(o);
|
|
|
|
}
|
|
|
|
|
2014-07-09 08:12:36 +00:00
|
|
|
format pretty_fn::pp_level(level const & l) {
|
|
|
|
return ::lean::pp(l, m_unicode, m_indent);
|
|
|
|
}
|
|
|
|
|
|
|
|
bool pretty_fn::is_implicit(expr const & f) {
|
|
|
|
if (m_implict)
|
|
|
|
return false; // showing implicit arguments
|
2014-09-26 16:38:36 +00:00
|
|
|
if (!closed(f)) {
|
|
|
|
// the Lean type checker assumes expressions are closed.
|
|
|
|
return false;
|
|
|
|
}
|
2014-07-09 08:12:36 +00:00
|
|
|
try {
|
2014-08-20 05:31:26 +00:00
|
|
|
binder_info bi = binding_info(m_tc.ensure_pi(m_tc.infer(f).first).first);
|
2014-07-09 08:12:36 +00:00
|
|
|
return bi.is_implicit() || bi.is_strict_implicit();
|
2014-09-18 23:21:20 +00:00
|
|
|
} catch (exception &) {
|
2014-07-09 08:12:36 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
bool pretty_fn::is_prop(expr const & e) {
|
|
|
|
try {
|
2014-08-20 05:31:26 +00:00
|
|
|
return m_env.impredicative() && m_tc.is_prop(e).first;
|
2014-09-18 23:21:20 +00:00
|
|
|
} catch (exception &) {
|
2014-07-09 08:12:36 +00:00
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-20 16:56:46 +00:00
|
|
|
auto pretty_fn::pp_coercion_fn(expr const & e, unsigned sz) -> result {
|
|
|
|
if (sz == 1) {
|
|
|
|
return pp_child(app_arg(e), max_bp()-1);
|
|
|
|
} else if (is_app(e) && is_implicit(app_fn(e))) {
|
|
|
|
return pp_coercion_fn(app_fn(e), sz-1);
|
|
|
|
} else {
|
|
|
|
expr const & fn = app_fn(e);
|
|
|
|
result res_fn = pp_coercion_fn(fn, sz-1);
|
|
|
|
format fn_fmt = res_fn.first;
|
|
|
|
if (m_implict && sz == 2 && has_implicit_args(fn))
|
2014-09-23 17:00:36 +00:00
|
|
|
fn_fmt = compose(*g_explicit_fmt, fn_fmt);
|
2014-09-20 16:56:46 +00:00
|
|
|
result res_arg = pp_child(app_arg(e), max_bp());
|
|
|
|
return mk_result(group(compose(fn_fmt, nest(m_indent, compose(line(), res_arg.first)))), max_bp()-1);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-09-09 19:46:55 +00:00
|
|
|
auto pretty_fn::pp_coercion(expr const & e, unsigned bp) -> result {
|
|
|
|
buffer<expr> args;
|
|
|
|
expr const & f = get_app_args(e, args);
|
|
|
|
optional<pair<name, unsigned>> r = is_coercion(m_env, f);
|
|
|
|
lean_assert(r);
|
2014-09-20 16:56:46 +00:00
|
|
|
if (r->second >= args.size()) {
|
2014-09-09 19:46:55 +00:00
|
|
|
return pp_child_core(e, bp);
|
2014-09-20 16:56:46 +00:00
|
|
|
} else if (r->second == args.size() - 1) {
|
2014-09-09 19:46:55 +00:00
|
|
|
return pp_child(args.back(), bp);
|
2014-09-20 16:56:46 +00:00
|
|
|
} else {
|
|
|
|
unsigned sz = args.size() - r->second;
|
|
|
|
lean_assert(sz >= 2);
|
|
|
|
auto r = pp_coercion_fn(e, sz);
|
|
|
|
if (r.second < bp) {
|
|
|
|
return mk_result(paren(r.first));
|
|
|
|
} else {
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
2014-09-09 19:46:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
auto pretty_fn::pp_child_core(expr const & e, unsigned bp) -> result {
|
|
|
|
result r = pp(e);
|
|
|
|
if (r.second < bp) {
|
|
|
|
return mk_result(paren(r.first));
|
|
|
|
} else {
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-09 08:12:36 +00:00
|
|
|
auto pretty_fn::pp_child(expr const & e, unsigned bp) -> result {
|
|
|
|
if (is_app(e) && is_implicit(app_fn(e))) {
|
|
|
|
return pp_child(app_fn(e), bp);
|
|
|
|
} else if (is_app(e) && !m_coercion && is_coercion(m_env, get_app_fn(e))) {
|
2014-09-09 19:46:55 +00:00
|
|
|
return pp_coercion(e, bp);
|
2014-07-09 08:12:36 +00:00
|
|
|
} else {
|
2014-09-09 19:46:55 +00:00
|
|
|
return pp_child_core(e, bp);
|
2014-07-09 08:12:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto pretty_fn::pp_var(expr const & e) -> result {
|
|
|
|
unsigned vidx = var_idx(e);
|
|
|
|
return mk_result(compose(format("#"), format(vidx)));
|
|
|
|
}
|
|
|
|
|
|
|
|
auto pretty_fn::pp_sort(expr const & e) -> result {
|
2014-09-23 19:09:13 +00:00
|
|
|
if (m_env.impredicative() && e == mk_Prop()) {
|
2014-07-22 16:43:18 +00:00
|
|
|
return mk_result(format("Prop"));
|
2014-07-09 08:12:36 +00:00
|
|
|
} else if (m_universes) {
|
2014-08-24 16:35:25 +00:00
|
|
|
return mk_result(group(format("Type.{") + nest(6, pp_level(sort_level(e))) + format("}")));
|
2014-07-09 08:12:36 +00:00
|
|
|
} else {
|
|
|
|
return mk_result(format("Type"));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto pretty_fn::pp_const(expr const & e) -> result {
|
|
|
|
name n = const_name(e);
|
2014-07-10 14:55:19 +00:00
|
|
|
if (!m_full_names) {
|
2014-07-28 04:01:59 +00:00
|
|
|
if (auto it = is_expr_aliased(m_env, n)) {
|
2014-07-10 14:55:19 +00:00
|
|
|
n = *it;
|
|
|
|
} else {
|
|
|
|
for (name const & ns : get_namespaces(m_env)) {
|
2014-07-25 15:30:30 +00:00
|
|
|
if (!ns.is_anonymous()) {
|
|
|
|
name new_n = n.replace_prefix(ns, name());
|
2014-08-07 15:24:56 +00:00
|
|
|
if (new_n != n && !new_n.is_anonymous()) {
|
2014-07-25 15:30:30 +00:00
|
|
|
n = new_n;
|
|
|
|
break;
|
|
|
|
}
|
2014-07-10 14:55:19 +00:00
|
|
|
}
|
2014-07-09 08:12:36 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2014-07-25 18:03:54 +00:00
|
|
|
if (!m_private_names) {
|
|
|
|
if (auto n1 = hidden_to_user_name(m_env, n))
|
|
|
|
n = *n1;
|
|
|
|
}
|
2014-07-10 02:17:00 +00:00
|
|
|
if (m_universes && !empty(const_levels(e))) {
|
2014-07-09 08:12:36 +00:00
|
|
|
format r = compose(format(n), format(".{"));
|
2014-07-10 02:17:00 +00:00
|
|
|
bool first = true;
|
2014-07-09 08:12:36 +00:00
|
|
|
for (auto const & l : const_levels(e)) {
|
|
|
|
format l_fmt = pp_level(l);
|
|
|
|
if (is_max(l) || is_imax(l))
|
|
|
|
l_fmt = paren(l_fmt);
|
2014-07-10 02:17:00 +00:00
|
|
|
if (first)
|
|
|
|
r += nest(m_indent, l_fmt);
|
|
|
|
else
|
|
|
|
r += nest(m_indent, compose(line(), l_fmt));
|
|
|
|
first = false;
|
2014-07-09 08:12:36 +00:00
|
|
|
}
|
|
|
|
r += format("}");
|
|
|
|
return mk_result(group(r));
|
|
|
|
} else {
|
|
|
|
return mk_result(format(n));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
auto pretty_fn::pp_meta(expr const & e) -> result {
|
|
|
|
return mk_result(compose(format("?"), format(mlocal_name(e))));
|
|
|
|
}
|
|
|
|
|
|
|
|
auto pretty_fn::pp_local(expr const & e) -> result {
|
|
|
|
return mk_result(format(local_pp_name(e)));
|
|
|
|
}
|
|
|
|
|
2014-09-03 00:09:57 +00:00
|
|
|
bool pretty_fn::has_implicit_args(expr const & f) {
|
2014-09-26 16:38:36 +00:00
|
|
|
if (!closed(f)) {
|
|
|
|
// the Lean type checker assumes expressions are closed.
|
|
|
|
return false;
|
|
|
|
}
|
2014-09-23 17:00:36 +00:00
|
|
|
name_generator ngen(*g_tmp_prefix);
|
2014-09-18 23:21:20 +00:00
|
|
|
try {
|
|
|
|
expr type = m_tc.whnf(m_tc.infer(f).first).first;
|
|
|
|
while (is_pi(type)) {
|
|
|
|
binder_info bi = binding_info(type);
|
|
|
|
if (bi.is_implicit() || bi.is_strict_implicit())
|
|
|
|
return true;
|
|
|
|
expr local = mk_local(ngen.next(), binding_name(type), binding_domain(type), binding_info(type));
|
|
|
|
type = m_tc.whnf(instantiate(binding_body(type), local)).first;
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
} catch (exception &) {
|
|
|
|
return false;
|
2014-09-03 00:09:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-09 08:12:36 +00:00
|
|
|
auto pretty_fn::pp_app(expr const & e) -> result {
|
2014-09-03 00:09:57 +00:00
|
|
|
expr const & fn = app_fn(e);
|
|
|
|
result res_fn = pp_child(fn, max_bp()-1);
|
|
|
|
format fn_fmt = res_fn.first;
|
|
|
|
if (m_implict && !is_app(fn) && has_implicit_args(fn))
|
2014-09-23 17:00:36 +00:00
|
|
|
fn_fmt = compose(*g_explicit_fmt, fn_fmt);
|
2014-07-09 08:12:36 +00:00
|
|
|
result res_arg = pp_child(app_arg(e), max_bp());
|
2014-09-03 00:09:57 +00:00
|
|
|
return mk_result(group(compose(fn_fmt, nest(m_indent, compose(line(), res_arg.first)))), max_bp()-1);
|
2014-07-09 08:12:36 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
format pretty_fn::pp_binder_block(buffer<name> const & names, expr const & type, binder_info const & bi) {
|
|
|
|
format r;
|
|
|
|
if (bi.is_implicit()) r += format("{");
|
|
|
|
else if (bi.is_cast()) r += format("[");
|
|
|
|
else if (bi.is_strict_implicit() && m_unicode) r += format("⦃");
|
|
|
|
else if (bi.is_strict_implicit() && !m_unicode) r += format("{{");
|
|
|
|
else r += format("(");
|
|
|
|
for (name const & n : names) {
|
|
|
|
r += format(n);
|
|
|
|
r += space();
|
|
|
|
}
|
|
|
|
r += compose(colon(), nest(m_indent, compose(line(), pp_child(type, 0).first)));
|
|
|
|
if (bi.is_implicit()) r += format("}");
|
|
|
|
else if (bi.is_cast()) r += format("]");
|
|
|
|
else if (bi.is_strict_implicit() && m_unicode) r += format("⦄");
|
|
|
|
else if (bi.is_strict_implicit() && !m_unicode) r += format("}}");
|
|
|
|
else r += format(")");
|
|
|
|
return group(r);
|
|
|
|
}
|
|
|
|
|
|
|
|
format pretty_fn::pp_binders(buffer<expr> const & locals) {
|
|
|
|
unsigned num = locals.size();
|
|
|
|
buffer<name> names;
|
|
|
|
expr local = locals[0];
|
|
|
|
expr type = mlocal_type(local);
|
|
|
|
binder_info bi = local_info(local);
|
|
|
|
names.push_back(local_pp_name(local));
|
|
|
|
format r;
|
|
|
|
for (unsigned i = 1; i < num; i++) {
|
|
|
|
expr local = locals[i];
|
|
|
|
if (mlocal_type(local) == type && local_info(local) == bi) {
|
|
|
|
names.push_back(local_pp_name(local));
|
|
|
|
} else {
|
|
|
|
r += group(compose(line(), pp_binder_block(names, type, bi)));
|
|
|
|
names.clear();
|
|
|
|
type = mlocal_type(local);
|
|
|
|
bi = local_info(local);
|
|
|
|
names.push_back(local_pp_name(local));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
r += group(compose(line(), pp_binder_block(names, type, bi)));
|
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
|
|
|
auto pretty_fn::pp_lambda(expr const & e) -> result {
|
|
|
|
expr b = e;
|
|
|
|
buffer<expr> locals;
|
|
|
|
while (is_lambda(b)) {
|
|
|
|
auto p = binding_body_fresh(b, true);
|
|
|
|
locals.push_back(p.second);
|
|
|
|
b = p.first;
|
|
|
|
}
|
2014-09-23 17:00:36 +00:00
|
|
|
format r = m_unicode ? *g_lambda_n_fmt : *g_lambda_fmt;
|
2014-07-09 08:12:36 +00:00
|
|
|
r += pp_binders(locals);
|
|
|
|
r += compose(comma(), nest(m_indent, compose(line(), pp_child(b, 0).first)));
|
|
|
|
return mk_result(r, 0);
|
|
|
|
}
|
|
|
|
|
2014-09-02 22:54:44 +00:00
|
|
|
/** \brief Similar to #is_arrow, but only returns true if binder_info is the default one.
|
|
|
|
That is, we don't want to lose binder info when pretty printing.
|
|
|
|
*/
|
|
|
|
static bool is_default_arrow(expr const & e) {
|
|
|
|
return is_arrow(e) && binding_info(e) == binder_info();
|
|
|
|
}
|
|
|
|
|
2014-07-09 08:12:36 +00:00
|
|
|
auto pretty_fn::pp_pi(expr const & e) -> result {
|
2014-09-02 22:54:44 +00:00
|
|
|
if (is_default_arrow(e)) {
|
2014-07-09 08:12:36 +00:00
|
|
|
result lhs = pp_child(binding_domain(e), get_arrow_prec());
|
|
|
|
result rhs = pp_child(lift_free_vars(binding_body(e), 1), get_arrow_prec()-1);
|
2014-09-23 17:00:36 +00:00
|
|
|
format r = group(lhs.first + space() + (m_unicode ? *g_arrow_n_fmt : *g_arrow_fmt) + line() + rhs.first);
|
2014-07-09 08:12:36 +00:00
|
|
|
return mk_result(r, get_arrow_prec()-1);
|
|
|
|
} else {
|
|
|
|
expr b = e;
|
|
|
|
buffer<expr> locals;
|
2014-09-02 22:54:44 +00:00
|
|
|
while (is_pi(b) && !is_default_arrow(b)) {
|
2014-07-09 08:12:36 +00:00
|
|
|
auto p = binding_body_fresh(b, true);
|
|
|
|
locals.push_back(p.second);
|
|
|
|
b = p.first;
|
|
|
|
}
|
|
|
|
format r;
|
|
|
|
if (is_prop(b))
|
2014-09-23 17:00:36 +00:00
|
|
|
r = m_unicode ? *g_forall_n_fmt : *g_forall_fmt;
|
2014-07-09 08:12:36 +00:00
|
|
|
else
|
2014-09-23 17:00:36 +00:00
|
|
|
r = m_unicode ? *g_pi_n_fmt : *g_pi_fmt;
|
2014-07-09 08:12:36 +00:00
|
|
|
r += pp_binders(locals);
|
|
|
|
r += compose(comma(), nest(m_indent, compose(line(), pp_child(b, 0).first)));
|
|
|
|
return mk_result(r, 0);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-07-27 04:35:26 +00:00
|
|
|
static bool is_have(expr const & e) { return is_app(e) && is_have_annotation(app_fn(e)); }
|
2014-07-27 04:56:35 +00:00
|
|
|
static bool is_show(expr const & e) {
|
2014-08-28 23:27:52 +00:00
|
|
|
return is_show_annotation(e) && is_app(get_annotation_arg(e)) &&
|
|
|
|
is_lambda(app_fn(get_annotation_arg(e)));
|
2014-07-10 01:47:10 +00:00
|
|
|
}
|
|
|
|
|
2014-07-27 04:35:26 +00:00
|
|
|
auto pretty_fn::pp_have(expr const & e) -> result {
|
|
|
|
expr proof = app_arg(e);
|
|
|
|
expr binding = get_annotation_arg(app_fn(e));
|
|
|
|
auto p = binding_body_fresh(binding, true);
|
|
|
|
expr local = p.second;
|
|
|
|
expr body = p.first;
|
|
|
|
name const & n = local_pp_name(local);
|
|
|
|
format type_fmt = pp_child(mlocal_type(local), 0).first;
|
|
|
|
format proof_fmt = pp_child(proof, 0).first;
|
|
|
|
format body_fmt = pp_child(body, 0).first;
|
2014-09-23 17:00:36 +00:00
|
|
|
format r = *g_have_fmt + space() + format(n) + space();
|
2014-07-27 04:35:26 +00:00
|
|
|
if (binding_info(binding).is_contextual())
|
2014-09-23 17:00:36 +00:00
|
|
|
r += compose(*g_visible_fmt, space());
|
|
|
|
r += colon() + nest(m_indent, line() + type_fmt + comma() + space() + *g_from_fmt);
|
2014-07-27 04:35:26 +00:00
|
|
|
r = group(r);
|
2014-08-24 16:35:25 +00:00
|
|
|
r += nest(m_indent, line() + proof_fmt + comma());
|
2014-07-27 04:35:26 +00:00
|
|
|
r = group(r);
|
2014-08-24 16:35:25 +00:00
|
|
|
r += line() + body_fmt;
|
2014-07-27 04:35:26 +00:00
|
|
|
return mk_result(r, 0);
|
|
|
|
}
|
|
|
|
|
2014-07-27 04:56:35 +00:00
|
|
|
auto pretty_fn::pp_show(expr const & e) -> result {
|
2014-08-28 23:27:52 +00:00
|
|
|
lean_assert(is_show(e));
|
|
|
|
expr s = get_annotation_arg(e);
|
|
|
|
expr proof = app_arg(s);
|
|
|
|
expr type = binding_domain(app_fn(s));
|
|
|
|
format type_fmt = pp_child(type, 0).first;
|
2014-07-27 04:56:35 +00:00
|
|
|
format proof_fmt = pp_child(proof, 0).first;
|
2014-09-23 17:00:36 +00:00
|
|
|
format r = *g_show_fmt + space() + nest(5, type_fmt) + comma() + space() + *g_from_fmt;
|
2014-07-27 04:56:35 +00:00
|
|
|
r = group(r);
|
|
|
|
r += nest(m_indent, compose(line(), proof_fmt));
|
|
|
|
return mk_result(group(r), 0);
|
|
|
|
}
|
|
|
|
|
2014-07-29 21:26:27 +00:00
|
|
|
auto pretty_fn::pp_explicit(expr const & e) -> result {
|
|
|
|
result res_arg = pp_child(get_explicit_arg(e), max_bp());
|
2014-09-23 17:00:36 +00:00
|
|
|
return mk_result(compose(*g_explicit_fmt, res_arg.first), max_bp());
|
2014-07-29 21:26:27 +00:00
|
|
|
}
|
|
|
|
|
2014-07-09 08:12:36 +00:00
|
|
|
auto pretty_fn::pp_macro(expr const & e) -> result {
|
2014-07-29 21:26:27 +00:00
|
|
|
if (is_explicit(e)) {
|
|
|
|
return pp_explicit(e);
|
|
|
|
} else {
|
|
|
|
// TODO(Leo): have macro annotations
|
|
|
|
// fix macro<->pp interface
|
|
|
|
format r = compose(format("["), format(macro_def(e).get_name()));
|
|
|
|
for (unsigned i = 0; i < macro_num_args(e); i++)
|
|
|
|
r += nest(m_indent, compose(line(), pp_child(macro_arg(e, i), max_bp()).first));
|
|
|
|
r += format("]");
|
|
|
|
return mk_result(group(r));
|
|
|
|
}
|
2014-07-09 08:12:36 +00:00
|
|
|
}
|
|
|
|
|
2014-08-29 01:20:58 +00:00
|
|
|
auto pretty_fn::pp_let(expr e) -> result {
|
2014-08-29 01:30:33 +00:00
|
|
|
buffer<pair<name, expr>> decls;
|
2014-08-29 01:20:58 +00:00
|
|
|
while (true) {
|
|
|
|
if (!is_let(e))
|
|
|
|
break;
|
|
|
|
name n = get_let_var_name(e);
|
|
|
|
expr v = get_let_value(e);
|
|
|
|
expr b = get_let_body(e);
|
|
|
|
lean_assert(closed(b));
|
|
|
|
expr b1 = abstract(b, v);
|
|
|
|
if (closed(b1)) {
|
|
|
|
e = b1;
|
|
|
|
} else {
|
|
|
|
n = pick_unused_name(b1, n);
|
2014-08-29 01:30:33 +00:00
|
|
|
decls.emplace_back(n, v);
|
2014-08-29 01:20:58 +00:00
|
|
|
e = instantiate(b1, mk_constant(n));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (decls.empty())
|
|
|
|
return pp(e);
|
2014-09-23 17:00:36 +00:00
|
|
|
format r = *g_let_fmt;
|
2014-08-29 01:20:58 +00:00
|
|
|
unsigned sz = decls.size();
|
|
|
|
for (unsigned i = 0; i < sz; i++) {
|
2014-08-29 01:30:33 +00:00
|
|
|
name const & n = decls[i].first;
|
|
|
|
expr const & v = decls[i].second;
|
|
|
|
format beg = i == 0 ? space() : line();
|
|
|
|
format sep = i < sz - 1 ? comma() : format();
|
|
|
|
format entry = format(n);
|
|
|
|
format v_fmt = pp_child(v, 0).first;
|
2014-09-23 17:00:36 +00:00
|
|
|
entry += space() + *g_assign_fmt + nest(m_indent, line() + v_fmt + sep);
|
2014-08-29 01:20:58 +00:00
|
|
|
r += nest(3 + 1, beg + group(entry));
|
|
|
|
}
|
|
|
|
format b = pp_child(e, 0).first;
|
2014-09-23 17:00:36 +00:00
|
|
|
r += line() + *g_in_fmt + space() + nest(2 + 1, b);
|
2014-08-29 01:20:58 +00:00
|
|
|
return mk_result(r, 0);
|
|
|
|
}
|
|
|
|
|
2014-08-14 16:11:34 +00:00
|
|
|
auto pretty_fn::pp_num(mpz const & n) -> result {
|
|
|
|
return mk_result(format(n));
|
|
|
|
}
|
|
|
|
|
2014-07-09 08:12:36 +00:00
|
|
|
auto pretty_fn::pp(expr const & e) -> result {
|
|
|
|
if (m_depth > m_max_depth || m_num_steps > m_max_steps)
|
2014-09-23 17:00:36 +00:00
|
|
|
return mk_result(m_unicode ? *g_ellipsis_n_fmt : *g_ellipsis_fmt);
|
2014-07-09 08:12:36 +00:00
|
|
|
flet<unsigned> let_d(m_depth, m_depth+1);
|
|
|
|
m_num_steps++;
|
|
|
|
|
2014-09-23 17:00:36 +00:00
|
|
|
if (is_placeholder(e)) return mk_result(*g_placeholder_fmt);
|
2014-08-22 18:26:00 +00:00
|
|
|
if (is_show(e)) return pp_show(e);
|
|
|
|
if (is_have(e)) return pp_have(e);
|
2014-08-29 01:20:58 +00:00
|
|
|
if (is_let(e)) return pp_let(e);
|
2014-08-22 18:26:00 +00:00
|
|
|
if (is_typed_expr(e)) return pp(get_typed_expr_expr(e));
|
2014-08-29 16:58:11 +00:00
|
|
|
if (is_let_value(e)) return pp(get_let_value_expr(e));
|
2014-08-14 16:11:34 +00:00
|
|
|
if (auto n = to_num(e)) return pp_num(*n);
|
2014-08-22 18:26:00 +00:00
|
|
|
if (!m_metavar_args && is_meta(e))
|
|
|
|
return pp_meta(get_app_fn(e));
|
2014-07-25 15:46:03 +00:00
|
|
|
|
2014-07-09 08:12:36 +00:00
|
|
|
switch (e.kind()) {
|
|
|
|
case expr_kind::Var: return pp_var(e);
|
|
|
|
case expr_kind::Sort: return pp_sort(e);
|
|
|
|
case expr_kind::Constant: return pp_const(e);
|
|
|
|
case expr_kind::Meta: return pp_meta(e);
|
|
|
|
case expr_kind::Local: return pp_local(e);
|
|
|
|
case expr_kind::App: return pp_app(e);
|
|
|
|
case expr_kind::Lambda: return pp_lambda(e);
|
|
|
|
case expr_kind::Pi: return pp_pi(e);
|
|
|
|
case expr_kind::Macro: return pp_macro(e);
|
|
|
|
}
|
|
|
|
lean_unreachable(); // LCOV_EXCL_LINE
|
|
|
|
}
|
|
|
|
|
|
|
|
pretty_fn::pretty_fn(environment const & env, options const & o):
|
|
|
|
m_env(env), m_tc(env) {
|
2014-07-27 16:41:25 +00:00
|
|
|
set_options_core(o);
|
2014-07-09 08:12:36 +00:00
|
|
|
m_meta_prefix = "M";
|
|
|
|
m_next_meta_idx = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
format pretty_fn::operator()(expr const & e) {
|
2014-07-09 18:13:17 +00:00
|
|
|
m_depth = 0; m_num_steps = 0;
|
2014-09-09 21:10:20 +00:00
|
|
|
if (m_beta)
|
|
|
|
return pp_child(purify(beta_reduce(e)), 0).first;
|
|
|
|
else
|
|
|
|
return pp_child(purify(e), 0).first;
|
2014-07-09 08:12:36 +00:00
|
|
|
}
|
|
|
|
|
2014-07-10 17:32:00 +00:00
|
|
|
formatter_factory mk_pretty_formatter_factory() {
|
|
|
|
return [](environment const & env, options const & o) { // NOLINT
|
2014-07-10 17:59:03 +00:00
|
|
|
auto fn_ptr = std::make_shared<pretty_fn>(env, o);
|
2014-07-27 16:41:25 +00:00
|
|
|
return formatter(o, [=](expr const & e, options const & new_o) {
|
|
|
|
fn_ptr->set_options(new_o);
|
2014-07-10 17:59:03 +00:00
|
|
|
return (*fn_ptr)(e);
|
2014-07-10 17:32:00 +00:00
|
|
|
});
|
|
|
|
};
|
2014-07-09 08:12:36 +00:00
|
|
|
}
|
|
|
|
}
|