feat(frontends/lean/pp): take notation declarations into account when pretty printing

TODO: support foldl/foldr and binders
This commit is contained in:
Leonardo de Moura 2014-10-19 08:40:56 -07:00
parent 8cfb3ae687
commit 555d26aa61
24 changed files with 370 additions and 120 deletions

View file

@ -59,7 +59,10 @@ environment print_cmd(parser & p) {
} else if (p.curr_is_token_or_id(get_raw_tk())) { } else if (p.curr_is_token_or_id(get_raw_tk())) {
p.next(); p.next();
expr e = p.parse_expr(); expr e = p.parse_expr();
p.regular_stream() << e << endl; io_state_stream out = p.regular_stream();
options opts = out.get_options();
opts = opts.update(get_pp_notation_option_name(), false);
out.update_options(opts) << e << endl;
} else if (p.curr_is_token_or_id(get_options_tk())) { } else if (p.curr_is_token_or_id(get_options_tk())) {
p.next(); p.next();
p.regular_stream() << p.ios().get_options() << endl; p.regular_stream() << p.ios().get_options() << endl;

View file

@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura Author: Leonardo de Moura
*/ */
#include <algorithm>
#include "util/flet.h" #include "util/flet.h"
#include "kernel/replace_fn.h" #include "kernel/replace_fn.h"
#include "kernel/free_vars.h" #include "kernel/free_vars.h"
@ -25,6 +26,7 @@ Author: Leonardo de Moura
#include "frontends/lean/pp_options.h" #include "frontends/lean/pp_options.h"
#include "frontends/lean/token_table.h" #include "frontends/lean/token_table.h"
#include "frontends/lean/builtin_exprs.h" #include "frontends/lean/builtin_exprs.h"
#include "frontends/lean/parser_config.h"
namespace lean { namespace lean {
static format * g_ellipsis_n_fmt = nullptr; static format * g_ellipsis_n_fmt = nullptr;
@ -211,11 +213,11 @@ auto pretty_fn::pp_coercion_fn(expr const & e, unsigned sz) -> result {
} else { } else {
expr const & fn = app_fn(e); expr const & fn = app_fn(e);
result res_fn = pp_coercion_fn(fn, sz-1); result res_fn = pp_coercion_fn(fn, sz-1);
format fn_fmt = res_fn.first; format fn_fmt = res_fn.fmt();
if (m_implict && sz == 2 && has_implicit_args(fn)) if (m_implict && sz == 2 && has_implicit_args(fn))
fn_fmt = compose(*g_explicit_fmt, fn_fmt); fn_fmt = compose(*g_explicit_fmt, fn_fmt);
result res_arg = pp_child(app_arg(e), max_bp()); 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); return result(max_bp()-1, group(compose(fn_fmt, nest(m_indent, compose(line(), res_arg.fmt())))));
} }
} }
@ -232,8 +234,8 @@ auto pretty_fn::pp_coercion(expr const & e, unsigned bp) -> result {
unsigned sz = args.size() - r->second; unsigned sz = args.size() - r->second;
lean_assert(sz >= 2); lean_assert(sz >= 2);
auto r = pp_coercion_fn(e, sz); auto r = pp_coercion_fn(e, sz);
if (r.second < bp) { if (r.rbp() < bp) {
return mk_result(paren(r.first)); return result(paren(r.fmt()));
} else { } else {
return r; return r;
} }
@ -242,8 +244,8 @@ auto pretty_fn::pp_coercion(expr const & e, unsigned bp) -> result {
auto pretty_fn::pp_child_core(expr const & e, unsigned bp) -> result { auto pretty_fn::pp_child_core(expr const & e, unsigned bp) -> result {
result r = pp(e); result r = pp(e);
if (r.second < bp) { if (r.rbp() < bp) {
return mk_result(paren(r.first)); return result(paren(r.fmt()));
} else { } else {
return r; return r;
} }
@ -261,16 +263,16 @@ auto pretty_fn::pp_child(expr const & e, unsigned bp) -> result {
auto pretty_fn::pp_var(expr const & e) -> result { auto pretty_fn::pp_var(expr const & e) -> result {
unsigned vidx = var_idx(e); unsigned vidx = var_idx(e);
return mk_result(compose(format("#"), format(vidx))); return result(compose(format("#"), format(vidx)));
} }
auto pretty_fn::pp_sort(expr const & e) -> result { auto pretty_fn::pp_sort(expr const & e) -> result {
if (m_env.impredicative() && e == mk_Prop()) { if (m_env.impredicative() && e == mk_Prop()) {
return mk_result(format("Prop")); return result(format("Prop"));
} else if (m_universes) { } else if (m_universes) {
return mk_result(group(format("Type.{") + nest(6, pp_level(sort_level(e))) + format("}"))); return result(group(format("Type.{") + nest(6, pp_level(sort_level(e))) + format("}")));
} else { } else {
return mk_result(format("Type")); return result(format("Type"));
} }
} }
@ -322,18 +324,18 @@ auto pretty_fn::pp_const(expr const & e) -> result {
first = false; first = false;
} }
r += format("}"); r += format("}");
return mk_result(group(r)); return result(group(r));
} else { } else {
return mk_result(format(n)); return result(format(n));
} }
} }
auto pretty_fn::pp_meta(expr const & e) -> result { auto pretty_fn::pp_meta(expr const & e) -> result {
return mk_result(compose(format("?"), format(mlocal_name(e)))); return result(compose(format("?"), format(mlocal_name(e))));
} }
auto pretty_fn::pp_local(expr const & e) -> result { auto pretty_fn::pp_local(expr const & e) -> result {
return mk_result(format(local_pp_name(e))); return result(format(local_pp_name(e)));
} }
bool pretty_fn::has_implicit_args(expr const & f) { bool pretty_fn::has_implicit_args(expr const & f) {
@ -360,11 +362,11 @@ bool pretty_fn::has_implicit_args(expr const & f) {
auto pretty_fn::pp_app(expr const & e) -> result { auto pretty_fn::pp_app(expr const & e) -> result {
expr const & fn = app_fn(e); expr const & fn = app_fn(e);
result res_fn = pp_child(fn, max_bp()-1); result res_fn = pp_child(fn, max_bp()-1);
format fn_fmt = res_fn.first; format fn_fmt = res_fn.fmt();
if (m_implict && !is_app(fn) && has_implicit_args(fn)) if (m_implict && !is_app(fn) && has_implicit_args(fn))
fn_fmt = compose(*g_explicit_fmt, fn_fmt); fn_fmt = compose(*g_explicit_fmt, fn_fmt);
result res_arg = pp_child(app_arg(e), max_bp()); 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); return result(max_bp()-1, group(compose(fn_fmt, nest(m_indent, compose(line(), res_arg.fmt())))));
} }
format pretty_fn::pp_binder_block(buffer<name> const & names, expr const & type, binder_info const & bi) { format pretty_fn::pp_binder_block(buffer<name> const & names, expr const & type, binder_info const & bi) {
@ -378,7 +380,7 @@ format pretty_fn::pp_binder_block(buffer<name> const & names, expr const & type,
r += format(n); r += format(n);
r += space(); r += space();
} }
r += compose(colon(), nest(m_indent, compose(line(), pp_child(type, 0).first))); r += compose(colon(), nest(m_indent, compose(line(), pp_child(type, 0).fmt())));
if (bi.is_implicit()) r += format("}"); if (bi.is_implicit()) r += format("}");
else if (bi.is_inst_implicit()) r += format("]"); else if (bi.is_inst_implicit()) r += format("]");
else if (bi.is_strict_implicit() && m_unicode) r += format(""); else if (bi.is_strict_implicit() && m_unicode) r += format("");
@ -421,8 +423,8 @@ auto pretty_fn::pp_lambda(expr const & e) -> result {
} }
format r = m_unicode ? *g_lambda_n_fmt : *g_lambda_fmt; format r = m_unicode ? *g_lambda_n_fmt : *g_lambda_fmt;
r += pp_binders(locals); r += pp_binders(locals);
r += compose(comma(), nest(m_indent, compose(line(), pp_child(b, 0).first))); r += compose(comma(), nest(m_indent, compose(line(), pp_child(b, 0).fmt())));
return mk_result(r, 0); return result(0, r);
} }
/** \brief Similar to #is_arrow, but only returns true if binder_info is the default one. /** \brief Similar to #is_arrow, but only returns true if binder_info is the default one.
@ -436,8 +438,8 @@ auto pretty_fn::pp_pi(expr const & e) -> result {
if (is_default_arrow(e)) { if (is_default_arrow(e)) {
result lhs = pp_child(binding_domain(e), get_arrow_prec()); 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); result rhs = pp_child(lift_free_vars(binding_body(e), 1), get_arrow_prec()-1);
format r = group(lhs.first + space() + (m_unicode ? *g_arrow_n_fmt : *g_arrow_fmt) + line() + rhs.first); format r = group(lhs.fmt() + space() + (m_unicode ? *g_arrow_n_fmt : *g_arrow_fmt) + line() + rhs.fmt());
return mk_result(r, get_arrow_prec()-1); return result(get_arrow_prec()-1, r);
} else { } else {
expr b = e; expr b = e;
buffer<expr> locals; buffer<expr> locals;
@ -452,8 +454,8 @@ auto pretty_fn::pp_pi(expr const & e) -> result {
else else
r = m_unicode ? *g_pi_n_fmt : *g_pi_fmt; r = m_unicode ? *g_pi_n_fmt : *g_pi_fmt;
r += pp_binders(locals); r += pp_binders(locals);
r += compose(comma(), nest(m_indent, compose(line(), pp_child(b, 0).first))); r += compose(comma(), nest(m_indent, compose(line(), pp_child(b, 0).fmt())));
return mk_result(r, 0); return result(0, r);
} }
} }
@ -470,9 +472,9 @@ auto pretty_fn::pp_have(expr const & e) -> result {
expr local = p.second; expr local = p.second;
expr body = p.first; expr body = p.first;
name const & n = local_pp_name(local); name const & n = local_pp_name(local);
format type_fmt = pp_child(mlocal_type(local), 0).first; format type_fmt = pp_child(mlocal_type(local), 0).fmt();
format proof_fmt = pp_child(proof, 0).first; format proof_fmt = pp_child(proof, 0).fmt();
format body_fmt = pp_child(body, 0).first; format body_fmt = pp_child(body, 0).fmt();
format r = *g_have_fmt + space() + format(n) + space(); format r = *g_have_fmt + space() + format(n) + space();
if (binding_info(binding).is_contextual()) if (binding_info(binding).is_contextual())
r += compose(*g_visible_fmt, space()); r += compose(*g_visible_fmt, space());
@ -481,7 +483,7 @@ auto pretty_fn::pp_have(expr const & e) -> result {
r += nest(m_indent, line() + proof_fmt + comma()); r += nest(m_indent, line() + proof_fmt + comma());
r = group(r); r = group(r);
r += line() + body_fmt; r += line() + body_fmt;
return mk_result(r, 0); return result(0, r);
} }
auto pretty_fn::pp_show(expr const & e) -> result { auto pretty_fn::pp_show(expr const & e) -> result {
@ -489,17 +491,17 @@ auto pretty_fn::pp_show(expr const & e) -> result {
expr s = get_annotation_arg(e); expr s = get_annotation_arg(e);
expr proof = app_arg(s); expr proof = app_arg(s);
expr type = binding_domain(app_fn(s)); expr type = binding_domain(app_fn(s));
format type_fmt = pp_child(type, 0).first; format type_fmt = pp_child(type, 0).fmt();
format proof_fmt = pp_child(proof, 0).first; format proof_fmt = pp_child(proof, 0).fmt();
format r = *g_show_fmt + space() + nest(5, type_fmt) + comma() + space() + *g_from_fmt; format r = *g_show_fmt + space() + nest(5, type_fmt) + comma() + space() + *g_from_fmt;
r = group(r); r = group(r);
r += nest(m_indent, compose(line(), proof_fmt)); r += nest(m_indent, compose(line(), proof_fmt));
return mk_result(group(r), 0); return result(0, group(r));
} }
auto pretty_fn::pp_explicit(expr const & e) -> result { auto pretty_fn::pp_explicit(expr const & e) -> result {
result res_arg = pp_child(get_explicit_arg(e), max_bp()); result res_arg = pp_child(get_explicit_arg(e), max_bp());
return mk_result(compose(*g_explicit_fmt, res_arg.first), max_bp()); return result(max_bp(), compose(*g_explicit_fmt, res_arg.fmt()));
} }
auto pretty_fn::pp_macro(expr const & e) -> result { auto pretty_fn::pp_macro(expr const & e) -> result {
@ -510,9 +512,9 @@ auto pretty_fn::pp_macro(expr const & e) -> result {
// fix macro<->pp interface // fix macro<->pp interface
format r = compose(format("["), format(macro_def(e).get_name())); format r = compose(format("["), format(macro_def(e).get_name()));
for (unsigned i = 0; i < macro_num_args(e); i++) 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 += nest(m_indent, compose(line(), pp_child(macro_arg(e, i), max_bp()).fmt()));
r += format("]"); r += format("]");
return mk_result(group(r)); return result(group(r));
} }
} }
@ -544,26 +546,221 @@ auto pretty_fn::pp_let(expr e) -> result {
format beg = i == 0 ? space() : line(); format beg = i == 0 ? space() : line();
format sep = i < sz - 1 ? comma() : format(); format sep = i < sz - 1 ? comma() : format();
format entry = format(n); format entry = format(n);
format v_fmt = pp_child(v, 0).first; format v_fmt = pp_child(v, 0).fmt();
entry += space() + *g_assign_fmt + nest(m_indent, line() + v_fmt + sep); entry += space() + *g_assign_fmt + nest(m_indent, line() + v_fmt + sep);
r += nest(3 + 1, beg + group(entry)); r += nest(3 + 1, beg + group(entry));
} }
format b = pp_child(e, 0).first; format b = pp_child(e, 0).fmt();
r += line() + *g_in_fmt + space() + nest(2 + 1, b); r += line() + *g_in_fmt + space() + nest(2 + 1, b);
return mk_result(r, 0); return result(0, r);
} }
auto pretty_fn::pp_num(mpz const & n) -> result { auto pretty_fn::pp_num(mpz const & n) -> result {
return mk_result(format(n)); return result(format(n));
}
bool pretty_fn::match(level const & p, level const & l) {
if (p == l)
return true;
if (m_universes)
return false;
if (is_placeholder(p))
return true;
if (is_succ(p) && is_succ(l))
return match(succ_of(p), succ_of(l));
return false;
}
bool pretty_fn::match(expr const & p, expr const & e, buffer<optional<expr>> & args) {
if (is_explicit(p)) {
return match(get_explicit_arg(p), e, args);
} else if (is_var(p)) {
unsigned vidx = var_idx(p);
if (vidx >= args.size()) args.resize(vidx+1);
if (args[vidx])
return *args[vidx] == e;
args[vidx] = e;
return true;
} else if (is_placeholder(p)) {
return true;
} else if (is_constant(p)) {
if (!is_constant(e))
return false;
levels p_ls = const_levels(p);
levels e_ls = const_levels(p);
while (!is_nil(p_ls)) {
if (is_nil(e_ls))
return false; // e must have at least as many arguments as p
if (!match(head(p_ls), head(e_ls)))
return false;
p_ls = tail(p_ls);
e_ls = tail(e_ls);
}
return true;
} else if (is_sort(p)) {
if (!is_sort(e))
return false;
return match(sort_level(p), sort_level(e));
} else if (is_app(e)) {
buffer<expr> p_args, e_args;
expr const & p_fn = get_app_args(p, p_args);
expr const & e_fn = get_app_args(e, e_args);
if (!match(p_fn, e_fn, args))
return false;
bool expl = is_explicit(p);
if (expl) {
if (p_args.size() != e_args.size())
return false;
for (unsigned i = 0; i < p_args.size(); i++) {
if (!match(p_args[i], e_args[i], args))
return false;
}
return true;
} else {
try {
expr fn_type = m_tc.infer(e_fn).first;
unsigned j = 0;
for (unsigned i = 0; i < e_args.size(); i++) {
fn_type = m_tc.ensure_pi(fn_type).first;
if (is_explicit(binding_info(fn_type))) {
if (j >= p_args.size())
return false;
if (!match(p_args[j], e_args[i], args))
return false;
j++;
}
fn_type = instantiate(binding_body(fn_type), e_args[i]);
}
return j == p_args.size();
} catch (exception&) {
return false;
}
}
} else {
return false;
}
}
static unsigned get_some_precedence(token_table const & t, name const & tk) {
if (tk.is_atomic() && tk.is_string()) {
if (auto p = get_precedence(t, tk.get_string()))
return *p;
} else {
if (auto p = get_precedence(t, tk.to_string().c_str()))
return *p;
}
return 0;
}
auto pretty_fn::pp_notation_child(expr const & e, unsigned lbp, unsigned rbp) -> result {
if (is_app(e) && !m_coercion && is_coercion(m_env, get_app_fn(e))) {
return pp_coercion(e, rbp);
} else {
result r = pp(e);
// std::cout << "e: " << e << "\n";
// std::cout << "lbp: " << lbp << ", rbp: " << rbp << ", r.lbp(): " << r.lbp() << ", r.rbp(): " << r.rbp() << "\n\n";
if (r.rbp() < lbp || r.lbp() <= rbp) {
return result(paren(r.fmt()));
} else {
return r;
}
}
}
auto pretty_fn::pp_notation(notation_entry const & entry, buffer<optional<expr>> & args) -> optional<result> {
std::reverse(args.begin(), args.end());
if (entry.is_numeral()) {
return some(result(format(entry.get_num())));
} else {
using notation::transition;
buffer<transition> ts;
to_buffer(entry.get_transitions(), ts);
format fmt;
unsigned i = ts.size();
unsigned last_rbp = max_bp()-1;
unsigned token_lbp = 0;
bool last = true;
while (i > 0) {
--i;
format curr;
notation::action const & a = ts[i].get_action();
name const & tk = ts[i].get_token();
switch (a.kind()) {
case notation::action_kind::Skip:
curr = format(tk);
if (last)
last_rbp = get_some_precedence(m_token_table, tk);
break;
case notation::action_kind::Expr:
if (args.empty() || !args.back()) {
return optional<result>();
} else {
expr e = *args.back();
args.pop_back();
result e_r = pp_notation_child(e, token_lbp, a.rbp());
format e_fmt = e_r.fmt();
curr = format(tk) + space() + e_fmt;
if (last)
last_rbp = a.rbp();
}
break;
case notation::action_kind::Exprs:
case notation::action_kind::Binder:
case notation::action_kind::Binders:
case notation::action_kind::ScopedExpr:
// TODO(Leo)
return optional<result>();
case notation::action_kind::Ext:
case notation::action_kind::LuaExt:
return optional<result>();
}
token_lbp = get_some_precedence(m_token_table, tk);
if (last) {
fmt = curr;
last = false;
} else {
fmt = curr + space() + fmt;
}
}
unsigned first_lbp = token_lbp;
if (!entry.is_nud()) {
lean_assert(!last);
if (args.size() != 1 || !args.back())
return optional<result>();
expr e = *args.back();
args.pop_back();
format e_fmt = pp_notation_child(e, token_lbp, 0).fmt();
fmt = e_fmt + space() + fmt;
}
return optional<result>(result(first_lbp, last_rbp, fmt));
}
}
auto pretty_fn::pp_notation(expr const & e) -> optional<result> {
if (!m_notation || is_var(e))
return optional<result>();
for (notation_entry const & entry : get_notation_entries(m_env, head_index(e))) {
if (!m_unicode && !entry.is_safe_ascii())
continue; // ignore this notation declaration since unicode support is not enabled
buffer<optional<expr>> args;
if (match(entry.get_expr(), e, args)) {
if (auto r = pp_notation(entry, args))
return r;
}
}
return optional<result>();
} }
auto pretty_fn::pp(expr const & e) -> result { auto pretty_fn::pp(expr const & e) -> result {
if (m_depth > m_max_depth || m_num_steps > m_max_steps) if (m_depth > m_max_depth || m_num_steps > m_max_steps)
return mk_result(m_unicode ? *g_ellipsis_n_fmt : *g_ellipsis_fmt); return result(m_unicode ? *g_ellipsis_n_fmt : *g_ellipsis_fmt);
flet<unsigned> let_d(m_depth, m_depth+1); flet<unsigned> let_d(m_depth, m_depth+1);
m_num_steps++; m_num_steps++;
if (is_placeholder(e)) return mk_result(*g_placeholder_fmt); if (auto r = pp_notation(e))
return *r;
if (is_placeholder(e)) return result(*g_placeholder_fmt);
if (is_show(e)) return pp_show(e); if (is_show(e)) return pp_show(e);
if (is_have(e)) return pp_have(e); if (is_have(e)) return pp_have(e);
if (is_let(e)) return pp_let(e); if (is_let(e)) return pp_let(e);
@ -588,7 +785,7 @@ auto pretty_fn::pp(expr const & e) -> result {
} }
pretty_fn::pretty_fn(environment const & env, options const & o): pretty_fn::pretty_fn(environment const & env, options const & o):
m_env(env), m_tc(env) { m_env(env), m_tc(env), m_token_table(get_token_table(env)) {
set_options_core(o); set_options_core(o);
m_meta_prefix = "M"; m_meta_prefix = "M";
m_next_meta_idx = 1; m_next_meta_idx = 1;
@ -597,9 +794,9 @@ pretty_fn::pretty_fn(environment const & env, options const & o):
format pretty_fn::operator()(expr const & e) { format pretty_fn::operator()(expr const & e) {
m_depth = 0; m_num_steps = 0; m_depth = 0; m_num_steps = 0;
if (m_beta) if (m_beta)
return pp_child(purify(beta_reduce(e)), 0).first; return pp_child(purify(beta_reduce(e)), 0).fmt();
else else
return pp_child(purify(e), 0).first; return pp_child(purify(e), 0).fmt();
} }
formatter_factory mk_pretty_formatter_factory() { formatter_factory mk_pretty_formatter_factory() {

View file

@ -14,14 +14,31 @@ Author: Leonardo de Moura
#include "util/sexpr/format.h" #include "util/sexpr/format.h"
#include "kernel/environment.h" #include "kernel/environment.h"
#include "kernel/type_checker.h" #include "kernel/type_checker.h"
#include "frontends/lean/token_table.h"
namespace lean { namespace lean {
class notation_entry;
class pretty_fn { class pretty_fn {
public: public:
typedef pair<format, unsigned> result; static unsigned max_bp() { return std::numeric_limits<unsigned>::max(); }
class result {
unsigned m_lbp;
unsigned m_rbp;
format m_fmt;
public:
result():m_lbp(max_bp()), m_rbp(max_bp()) {}
result(format const & fmt):m_lbp(max_bp()), m_rbp(max_bp()), m_fmt(fmt) {}
result(unsigned rbp, format const & fmt):m_lbp(max_bp()), m_rbp(rbp), m_fmt(fmt) {}
result(unsigned lbp, unsigned rbp, format const & fmt):m_lbp(lbp), m_rbp(rbp), m_fmt(fmt) {}
unsigned lbp() const { return m_lbp; }
unsigned rbp() const { return m_rbp; }
format const & fmt() const { return m_fmt; }
};
private: private:
environment m_env; environment m_env;
type_checker m_tc; type_checker m_tc;
token_table const & m_token_table;
unsigned m_num_steps; unsigned m_num_steps;
unsigned m_depth; unsigned m_depth;
name m_meta_prefix; name m_meta_prefix;
@ -44,13 +61,10 @@ private:
bool m_metavar_args; bool m_metavar_args;
bool m_beta; bool m_beta;
unsigned max_bp() const { return std::numeric_limits<unsigned>::max(); }
name mk_metavar_name(name const & m); name mk_metavar_name(name const & m);
name mk_local_name(name const & n, name const & suggested); name mk_local_name(name const & n, name const & suggested);
level purify(level const & l); level purify(level const & l);
expr purify(expr const & e); expr purify(expr const & e);
result mk_result(format const & e, unsigned rbp) const { return mk_pair(e, rbp); }
result mk_result(format const & e) const { return mk_result(e, max_bp()); }
bool is_implicit(expr const & f); bool is_implicit(expr const & f);
bool is_prop(expr const & e); bool is_prop(expr const & e);
bool has_implicit_args(expr const & f); bool has_implicit_args(expr const & f);
@ -60,6 +74,12 @@ private:
format pp_binders(buffer<expr> const & locals); format pp_binders(buffer<expr> const & locals);
format pp_level(level const & l); format pp_level(level const & l);
bool match(level const & p, level const & l);
bool match(expr const & p, expr const & e, buffer<optional<expr>> & args);
result pp_notation_child(expr const & e, unsigned lbp, unsigned rbp);
optional<result> pp_notation(notation_entry const & entry, buffer<optional<expr>> & args);
optional<result> pp_notation(expr const & e);
result pp_coercion_fn(expr const & e, unsigned sz); result pp_coercion_fn(expr const & e, unsigned sz);
result pp_coercion(expr const & e, unsigned bp); result pp_coercion(expr const & e, unsigned bp);
result pp_child_core(expr const & e, unsigned bp); result pp_child_core(expr const & e, unsigned bp);

View file

@ -120,6 +120,7 @@ void finalize_pp_options() {
name const & get_pp_coercions_option_name() { return *g_pp_coercions; } name const & get_pp_coercions_option_name() { return *g_pp_coercions; }
name const & get_pp_full_names_option_name() { return *g_pp_full_names; } name const & get_pp_full_names_option_name() { return *g_pp_full_names; }
name const & get_pp_universes_option_name() { return *g_pp_universes; } name const & get_pp_universes_option_name() { return *g_pp_universes; }
name const & get_pp_notation_option_name() { return *g_pp_notation; }
unsigned get_pp_max_depth(options const & opts) { return opts.get_unsigned(*g_pp_max_depth, LEAN_DEFAULT_PP_MAX_DEPTH); } unsigned get_pp_max_depth(options const & opts) { return opts.get_unsigned(*g_pp_max_depth, LEAN_DEFAULT_PP_MAX_DEPTH); }
unsigned get_pp_max_steps(options const & opts) { return opts.get_unsigned(*g_pp_max_steps, LEAN_DEFAULT_PP_MAX_STEPS); } unsigned get_pp_max_steps(options const & opts) { return opts.get_unsigned(*g_pp_max_steps, LEAN_DEFAULT_PP_MAX_STEPS); }

View file

@ -10,6 +10,7 @@ namespace lean {
name const & get_pp_coercions_option_name(); name const & get_pp_coercions_option_name();
name const & get_pp_full_names_option_name(); name const & get_pp_full_names_option_name();
name const & get_pp_universes_option_name(); name const & get_pp_universes_option_name();
name const & get_pp_notation_option_name();
unsigned get_pp_max_depth(options const & opts); unsigned get_pp_max_depth(options const & opts);
unsigned get_pp_max_steps(options const & opts); unsigned get_pp_max_steps(options const & opts);

View file

@ -9,11 +9,11 @@ bug1.lean:13:7: error: type mismatch at definition 'and_intro', has type
p → q → (∀ (c : bool), (p → q → c) → c) p → q → (∀ (c : bool), (p → q → c) → c)
but is expected to have type but is expected to have type
∀ (p q : bool), ∀ (p q : bool),
p → q → and p p p → q → p ∧ p
bug1.lean:17:7: error: type mismatch at definition 'and_intro', has type bug1.lean:17:7: error: type mismatch at definition 'and_intro', has type
∀ (p q : bool), ∀ (p q : bool),
p → q → (∀ (c : bool), (p → q → c) → c) p → q → (∀ (c : bool), (p → q → c) → c)
but is expected to have type but is expected to have type
∀ (p q : bool), ∀ (p q : bool),
p → q → and q p p → q → q ∧ p
and_intro : ∀ (p q : bool), p → q → and p q and_intro : ∀ (p q : bool), p → q → p ∧ q

View file

@ -1,4 +1,4 @@
le_eq_trans a d e (le_trans a c d (eq_le_trans a b c H1 H2) H3) H4 : le a e le_eq_trans a d e (le_trans a c d (eq_le_trans a b c H1 H2) H3) H4 : a ≤ e
calc1.lean:38:10: error: invalid 'calc' expression, transitivity rule is not defined for current step calc1.lean:38:10: error: invalid 'calc' expression, transitivity rule is not defined for current step
le_lt_trans b c d H2 H5 : lt b d le_lt_trans b c d H2 H5 : b < d
[choice (@le2_trans b d e (@le2_trans b c d H2 H3) H4) (@le_trans b d e (@le_trans b c d H2 H3) H4)] [choice (@le2_trans b d e (@le2_trans b c d H2 H3) H4) (@le_trans b d e (@le_trans b c d H2 H3) H4)]

View file

@ -1,9 +1,9 @@
crash.lean:8:12: error: type mismatch at application crash.lean:8:12: error: type mismatch at application
have H' : not P, from H, have H' : ¬ P, from H,
?M_1 ?M_1
term term
H H
has type has type
P P
but is expected to have type but is expected to have type
not P ¬ P

View file

@ -1,9 +1,8 @@
have e1 [visible] : eq a b, from H1, have e1 [visible] : a = b, from H1,
have e2 : eq a c, from trans e1 H2, have e2 : a = c, from e1 ⬝ H2,
have e3 : eq c a, from symm e2, have e3 : c = a, from e2 ⁻¹,
have e4 [visible] : eq b a, from symm e1, have e4 [visible] : b = a, from e1 ⁻¹,
have e5 : eq b c, from trans e4 e2, have e5 : b = c, from e4 ⬝ e2,
have e6 : eq a a, from have e6 : a = a, from H1 ⬝ H2 ⬝ H2 ⁻¹ ⬝ H1 ⁻¹ ⬝ H1 ⬝ H2 ⬝ H2 ⁻¹ ⬝ H1 ⁻¹,
trans H1 (trans H2 (trans (symm H2) (trans (symm H1) (trans H1 (trans H2 (trans (symm H2) (symm H1))))))), e3 ⬝ e2 :
trans e3 e2 : c = c
eq c c

View file

@ -2,7 +2,7 @@
-- ENDWAIT -- ENDWAIT
-- BEGININFO -- BEGININFO
-- TYPE|5|16 -- TYPE|5|16
decidable (eq a b) decidable (a = b)
-- ACK -- ACK
-- SYNTH|5|16 -- SYNTH|5|16
int.has_decidable_eq a b int.has_decidable_eq a b

View file

@ -4,8 +4,8 @@
false|Prop false|Prop
false.rec|∀ (C : Prop), false → C false.rec|∀ (C : Prop), false → C
false_elim|false → ?c false_elim|false → ?c
not_false_trivial|not false not_false_trivial|¬ false
true_ne_false|not (eq true false) true_ne_false|¬ true = false
p_ne_false|?p → ne ?p false p_ne_false|?p → ?p false
eq_false_elim|eq ?a false → not ?a eq_false_elim|?a = false → ¬ ?a
-- ENDFINDP -- ENDFINDP

View file

@ -2,7 +2,7 @@
-- ENDWAIT -- ENDWAIT
-- BEGININFO -- BEGININFO
-- TYPE|9|0 -- TYPE|9|0
eq (tst.foo a b) (tst.foo a b) tst.foo a b = tst.foo a b
-- ACK -- ACK
-- IDENTIFIER|9|0 -- IDENTIFIER|9|0
rfl rfl
@ -17,7 +17,7 @@ rfl
-- ENDWAIT -- ENDWAIT
-- BEGININFO -- BEGININFO
-- TYPE|9|0 -- TYPE|9|0
eq (tst.foo a b) (tst.foo a b) tst.foo a b = tst.foo a b
-- ACK -- ACK
-- IDENTIFIER|9|0 -- IDENTIFIER|9|0
rfl rfl

View file

@ -2,7 +2,7 @@
-- ENDWAIT -- ENDWAIT
-- BEGININFO -- BEGININFO
-- TYPE|4|0 -- TYPE|4|0
A → B → and A B A → B → A ∧ B
-- ACK -- ACK
-- IDENTIFIER|4|0 -- IDENTIFIER|4|0
and.intro and.intro

View file

@ -2,7 +2,7 @@
-- ENDWAIT -- ENDWAIT
-- BEGININFO -- BEGININFO
-- TYPE|6|6 -- TYPE|6|6
(nat → Prop) → nat ( → Prop) →
-- ACK -- ACK
-- IDENTIFIER|6|6 -- IDENTIFIER|6|6
epsilon epsilon
@ -17,7 +17,7 @@ epsilon
x x
-- ACK -- ACK
-- TYPE|6|21 -- TYPE|6|21
Type Type
-- ACK -- ACK
-- IDENTIFIER|6|21 -- IDENTIFIER|6|21
nat nat

18
tests/lean/notation.lean Normal file
View file

@ -0,0 +1,18 @@
import logic data.nat.basic
open num
constant b : num
check b + b + b
check true ∧ false ∧ true
check (true ∧ false) ∧ true
check 2 + (2 + 2)
check (2 + 2) + 2
check 1 = (2 + 3)*2
check 2 + 3 * 2 = 3 * 2 + 2
check (true false) = (true false) ∧ true
check true ∧ (false true)
constant A : Type₁
constant a : A
notation 1 := a
check a
open nat
check

View file

@ -0,0 +1,11 @@
b + b + b : num
true ∧ false ∧ true : Prop
(true ∧ false) ∧ true : Prop
2 + (2 + 2) : num
2 + 2 + 2 : num
1 = (2 + 3) * 2 : Prop
2 + 3 * 2 = 3 * 2 + 2 : Prop
(true false) = (true false) ∧ true : Prop
true ∧ (false true) : Prop
1 : A
: Type₁

View file

@ -1,8 +1,8 @@
show eq a c, from eq.trans H1 H2 : eq a c show a = c, from H1 ⬝ H2 : a = c
------------ ------------
have e1 [visible] : eq a b, from H1, have e1 [visible] : a = b, from H1,
have e2 : eq a c, from eq.trans e1 H2, have e2 : a = c, from e1 ⬝ H2,
have e3 : eq c a, from eq.symm e2, have e3 : c = a, from e2 ⁻¹,
have e4 [visible] : eq b a, from eq.symm e1, have e4 [visible] : b = a, from e1 ⁻¹,
show eq b c, from eq.trans (eq.symm e1) e2 : show b = c, from e1 ⁻¹ ⬝ e2 :
eq b c b = c

View file

@ -1,6 +1,6 @@
ite (and p q) (f x) y : N if p ∧ q then f x else y : N
t10.lean:14:6: error: type mismatch at application t10.lean:14:6: error: type mismatch at application
ite (and p q) q ite (p ∧ q) q
term term
q q
has type has type
@ -9,4 +9,4 @@ but is expected to have type
N N
cons x (cons y (cons z (cons x (cons y (cons y nil))))) : list cons x (cons y (cons z (cons x (cons y (cons y nil))))) : list
cons x nil : list cons x nil : list
nil : list [ ] : list

View file

@ -8,8 +8,8 @@ t14.lean:23:26: error: invalid 'open/export' command option, mixing explicit and
a : A a : A
c : A c : A
A : Type A : Type
f a c : A a * c : A
foo.f foo.a foo.c : foo.A foo.a * foo.c : foo.A
t14.lean:46:8: error: unknown identifier 'a' t14.lean:46:8: error: unknown identifier 'a'
f a c : A f a c : A
t14.lean:52:9: error: unexpected token t14.lean:52:9: error: unexpected token

View file

@ -1,3 +1,3 @@
add a (mul b a) : N a + b * a : N
t9.lean:16:7: error: invalid expression t9.lean:16:7: error: invalid expression
add a (mul b a) : N a + b * a : N

View file

@ -1 +1 @@
tuple.{l_1} : Type.{max 1 l_1} → nat → Type.{max 1 l_1} tuple.{l_1} : Type.{max 1 l_1} → → Type.{max 1 l_1}

View file

@ -1 +1 @@
f 1 0 (Rtrue (pr1 (pair 1 0)) 0) : nat f 1 0 (Rtrue (pr₁ (pair 1 0)) 0) :

View file

@ -1,13 +1,13 @@
univ.lean:5:9: error: solution computed by the elaborator forces a universe placeholder to be a fixed value, computed sort is univ.lean:5:9: error: solution computed by the elaborator forces a universe placeholder to be a fixed value, computed sort is
Type.{1} Type
univ.lean:7:9: error: solution computed by the elaborator forces a universe placeholder to be a fixed value, computed sort is univ.lean:7:9: error: solution computed by the elaborator forces a universe placeholder to be a fixed value, computed sort is
Type.{1} Type
id Type num : Type id Type num : Type
id Type num : Type id Type num : Type
univ.lean:13:9: error: solution computed by the elaborator forces a universe placeholder to be a fixed value, computed sort is univ.lean:13:9: error: solution computed by the elaborator forces a universe placeholder to be a fixed value, computed sort is
Type.{1} Type
id Type num : Type id Type num : Type
univ.lean:17:9: error: solution computed by the elaborator forces a universe placeholder to be a fixed value, computed sort is univ.lean:17:9: error: solution computed by the elaborator forces a universe placeholder to be a fixed value, computed sort is
Type.{2} Type
univ.lean:19:9: error: solution computed by the elaborator forces a universe placeholder to be a fixed value, computed sort is univ.lean:19:9: error: solution computed by the elaborator forces a universe placeholder to be a fixed value, computed sort is
Type.{2} Type

View file

@ -1 +1 @@
foo : Π (B : Type), B → (Π (A : Type), A → eq A B → Prop) foo : Π (B : Type), B → (Π (A : Type), A → A = B → Prop)