Handle (and pretty print) elaborator error messages in the lean default frontend

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2013-08-31 16:46:41 -07:00
parent 03a5b5dbd0
commit 71b8b6408e
8 changed files with 214 additions and 53 deletions

View file

@ -18,6 +18,7 @@ Author: Leonardo de Moura
#include "expr_maps.h" #include "expr_maps.h"
#include "sstream.h" #include "sstream.h"
#include "kernel_exception.h" #include "kernel_exception.h"
#include "elaborator_exception.h"
#include "metavar.h" #include "metavar.h"
#include "elaborator.h" #include "elaborator.h"
#include "lean_frontend.h" #include "lean_frontend.h"
@ -552,7 +553,8 @@ class parser::imp {
if (m_frontend.has_implicit_arguments(obj.get_name())) { if (m_frontend.has_implicit_arguments(obj.get_name())) {
std::vector<bool> const & imp_args = m_frontend.get_implicit_arguments(obj.get_name()); std::vector<bool> const & imp_args = m_frontend.get_implicit_arguments(obj.get_name());
buffer<expr> args; buffer<expr> args;
args.push_back(save(mk_constant(obj.get_name()), pos())); pos_info p = pos();
args.push_back(save(mk_constant(obj.get_name()), p));
// We parse all the arguments to make sure we // We parse all the arguments to make sure we
// get all explicit arguments. // get all explicit arguments.
for (unsigned i = 0; i < imp_args.size(); i++) { for (unsigned i = 0; i < imp_args.size(); i++) {
@ -906,6 +908,15 @@ class parser::imp {
} }
} }
/**
\brief Create a new application and associate position of left with the resultant expression.
*/
expr mk_app_left(expr const & left, expr const & arg) {
auto it = m_expr_pos_info.find(left);
lean_assert(it != m_expr_pos_info.end());
return save(mk_app(left, arg), it->second);
}
/** /**
\brief Auxiliary method used when processing the 'inside' of an expression. \brief Auxiliary method used when processing the 'inside' of an expression.
*/ */
@ -914,12 +925,12 @@ class parser::imp {
case scanner::token::Id: return parse_led_id(left); case scanner::token::Id: return parse_led_id(left);
case scanner::token::Eq: return parse_eq(left); case scanner::token::Eq: return parse_eq(left);
case scanner::token::Arrow: return parse_arrow(left); case scanner::token::Arrow: return parse_arrow(left);
case scanner::token::LeftParen: return mk_app(left, parse_lparen()); case scanner::token::LeftParen: return mk_app_left(left, parse_lparen());
case scanner::token::IntVal: return mk_app(left, parse_int()); case scanner::token::IntVal: return mk_app_left(left, parse_int());
case scanner::token::DecimalVal: return mk_app(left, parse_decimal()); case scanner::token::DecimalVal: return mk_app_left(left, parse_decimal());
case scanner::token::StringVal: return mk_app(left, parse_string()); case scanner::token::StringVal: return mk_app_left(left, parse_string());
case scanner::token::Placeholder: return mk_app(left, parse_placeholder()); case scanner::token::Placeholder: return mk_app_left(left, parse_placeholder());
case scanner::token::Type: return mk_app(left, parse_type()); case scanner::token::Type: return mk_app_left(left, parse_type());
default: return left; default: return left;
} }
} }
@ -961,13 +972,7 @@ class parser::imp {
/*@}*/ /*@}*/
expr elaborate(expr const & e) { expr elaborate(expr const & e) {
if (has_metavar(e)) { return m_elaborator(e);
expr r = m_elaborator(e);
m_elaborator.clear();
return r;
} else {
return e;
}
} }
/** /**
@ -1410,7 +1415,12 @@ class parser::imp {
display_error(msg, m_scanner.get_line(), m_scanner.get_pos()); display_error(msg, m_scanner.get_line(), m_scanner.get_pos());
} }
void display_error(kernel_exception const & ex) { void display_error(kernel_exception const & ex) {
display_error_pos(ex.get_main_expr()); display_error_pos(m_elaborator.get_original(ex.get_main_expr()));
regular(m_frontend) << " " << ex << endl;
sync();
}
void display_error(elaborator_exception const & ex) {
display_error_pos(m_elaborator.get_original(ex.get_expr()));
regular(m_frontend) << " " << ex << endl; regular(m_frontend) << " " << ex << endl;
sync(); sync();
} }
@ -1477,6 +1487,12 @@ public:
display_error(ex); display_error(ex);
if (m_use_exceptions) if (m_use_exceptions)
throw; throw;
} catch (elaborator_exception & ex) {
m_found_errors = true;
if (m_show_errors)
display_error(ex);
if (m_use_exceptions)
throw;
} catch (interrupted & ex) { } catch (interrupted & ex) {
if (m_verbose) if (m_verbose)
regular(m_frontend) << "\n!!!Interrupted!!!" << endl; regular(m_frontend) << "\n!!!Interrupted!!!" << endl;

View file

@ -66,6 +66,10 @@ static format g_let_fmt = highlight_keyword(format("let"));
static format g_in_fmt = highlight_keyword(format("in")); static format g_in_fmt = highlight_keyword(format("in"));
static format g_assign_fmt = highlight_keyword(format(":=")); static format g_assign_fmt = highlight_keyword(format(":="));
static format g_geq_fmt = format("\u2265"); static format g_geq_fmt = format("\u2265");
static format g_lift_fmt = highlight_keyword(format("lift"));
static format g_lower_fmt = highlight_keyword(format("lower"));
static format g_subst_fmt = highlight_keyword(format("subst"));
static name g_pp_max_depth {"lean", "pp", "max_depth"}; static name g_pp_max_depth {"lean", "pp", "max_depth"};
static name g_pp_max_steps {"lean", "pp", "max_steps"}; static name g_pp_max_steps {"lean", "pp", "max_steps"};
@ -98,18 +102,17 @@ static name g_nu("\u03BD");
/** /**
\brief Return a fresh name for the given abstraction or let. \brief Return a fresh name for the given abstraction or let.
By fresh, we mean a name that is not used for any constant in By fresh, we mean a name that is not used for any constant in
abst_body(e). If fe != nullptr, then the resultant name also does abst_body(e).
not clash with the name of any object defined in fe.
The resultant name is based on abst_name(e). The resultant name is based on abst_name(e).
*/ */
name get_unused_name(expr const & e, frontend const * fe = nullptr) { name get_unused_name(expr const & e) {
lean_assert(is_abstraction(e) || is_let(e)); lean_assert(is_abstraction(e) || is_let(e));
name const & n = is_abstraction(e) ? abst_name(e) : let_name(e); name const & n = is_abstraction(e) ? abst_name(e) : let_name(e);
name n1 = n; name n1 = n;
unsigned i = 1; unsigned i = 1;
expr const & b = is_abstraction(e) ? abst_body(e) : let_body(e); expr const & b = is_abstraction(e) ? abst_body(e) : let_body(e);
while (occurs(n1, b) || (fe != nullptr && fe->find_object(n1))) { while (occurs(n1, b)) {
n1 = name(n, i); n1 = name(n, i);
i++; i++;
} }
@ -190,7 +193,7 @@ class pp_fn {
result pp_constant(expr const & e) { result pp_constant(expr const & e) {
name const & n = const_name(e); name const & n = const_name(e);
if (is_metavar(e)) { if (is_metavar(e)) {
return mk_result(format("_"), 1); return mk_result(format{format("?M"), format(metavar_idx(e))}, 1);
} else if (has_implicit_arguments(n)) { } else if (has_implicit_arguments(n)) {
return mk_result(format(m_frontend.get_explicit_version(n)), 1); return mk_result(format(m_frontend.get_explicit_version(n)), 1);
} else { } else {
@ -852,6 +855,32 @@ class pp_fn {
return mk_result(r_format, p_arg1.second + p_arg2.second + 1); return mk_result(r_format, p_arg1.second + p_arg2.second + 1);
} }
result pp_lower(expr const & e, unsigned depth) {
expr arg; unsigned s, n;
is_lower(e, arg, s, n);
result p_arg = pp_child(arg, depth);
format r_format = format{g_lower_fmt, colon(), format(s), colon(), format(s), nest(m_indent, compose(line(), p_arg.first))};
return mk_result(r_format, p_arg.second + 1);
}
result pp_lift(expr const & e, unsigned depth) {
expr arg; unsigned s, n;
is_lift(e, arg, s, n);
result p_arg = pp_child(arg, depth);
format r_format = format{g_lift_fmt, colon(), format(s), colon(), format(s), nest(m_indent, compose(line(), p_arg.first))};
return mk_result(r_format, p_arg.second + 1);
}
result pp_subst(expr const & e, unsigned depth) {
expr arg, v; unsigned i;
is_subst(e, arg, i, v);
result p_arg = pp_child(arg, depth);
result p_v = pp_child(v, depth);
format r_format = format{g_subst_fmt, colon(), format(i),
nest(m_indent, format{line(), p_arg.first, line(), p_v.first})};
return mk_result(r_format, p_arg.second + p_v.second + 1);
}
result pp(expr const & e, unsigned depth, bool main = false) { result pp(expr const & e, unsigned depth, bool main = false) {
check_interrupted(m_interrupted); check_interrupted(m_interrupted);
if (!is_atomic(e) && (m_num_steps > m_max_steps || depth > m_max_depth)) { if (!is_atomic(e) && (m_num_steps > m_max_steps || depth > m_max_depth)) {
@ -864,16 +893,24 @@ class pp_fn {
return mk_result(format(it->second), 1); return mk_result(format(it->second), 1);
} }
result r; result r;
switch (e.kind()) { if (is_lower(e)) {
case expr_kind::Var: r = pp_var(e); break; r = pp_lower(e, depth);
case expr_kind::Constant: r = pp_constant(e); break; } else if (is_lift(e)) {
case expr_kind::Value: r = pp_value(e); break; r = pp_lift(e, depth);
case expr_kind::App: r = pp_app(e, depth); break; } else if (is_subst(e)) {
case expr_kind::Lambda: r = pp_subst(e, depth);
case expr_kind::Pi: r = pp_abstraction(e, depth); break; } else {
case expr_kind::Type: r = pp_type(e); break; switch (e.kind()) {
case expr_kind::Eq: r = pp_eq(e, depth); break; case expr_kind::Var: r = pp_var(e); break;
case expr_kind::Let: r = pp_let(e, depth); break; case expr_kind::Constant: r = pp_constant(e); break;
case expr_kind::Value: r = pp_value(e); break;
case expr_kind::App: r = pp_app(e, depth); break;
case expr_kind::Lambda:
case expr_kind::Pi: r = pp_abstraction(e, depth); break;
case expr_kind::Type: r = pp_type(e); break;
case expr_kind::Eq: r = pp_eq(e, depth); break;
case expr_kind::Let: r = pp_let(e, depth); break;
}
} }
if (!main && m_extra_lets && is_shared(e) && r.second > m_alias_min_weight) { if (!main && m_extra_lets && is_shared(e) && r.second > m_alias_min_weight) {
name new_aux = name(m_aux, m_aliases_defs.size()+1); name new_aux = name(m_aux, m_aliases_defs.size()+1);
@ -965,6 +1002,10 @@ public:
void set_interrupt(bool flag) { void set_interrupt(bool flag) {
m_interrupted = flag; m_interrupted = flag;
} }
void register_local(name const & n) {
m_local_names.insert(n);
}
}; };
class pp_formatter_cell : public formatter_cell { class pp_formatter_cell : public formatter_cell {
@ -979,17 +1020,20 @@ class pp_formatter_cell : public formatter_cell {
} }
format pp(context const & c, expr const & e, bool include_e, options const & opts) { format pp(context const & c, expr const & e, bool include_e, options const & opts) {
pp_fn fn(m_frontend, opts);
scoped_set_interruptable_ptr<pp_fn> set(m_pp_fn, &fn);
unsigned indent = get_pp_indent(opts); unsigned indent = get_pp_indent(opts);
format r; format r;
bool first = true; bool first = true;
expr c2 = context_to_lambda(c, e); expr c2 = context_to_lambda(c, e);
while (is_fake_context(c2)) { while (is_fake_context(c2)) {
check_interrupted(m_interrupted); check_interrupted(m_interrupted);
name n1 = get_unused_name(c2, &m_frontend); name n1 = get_unused_name(c2);
format entry = format{format(n1), space(), colon(), space(), pp(fake_context_domain(c2), opts)}; fn.register_local(n1);
format entry = format{format(n1), space(), colon(), space(), fn(fake_context_domain(c2))};
expr val = fake_context_value(c2); expr val = fake_context_value(c2);
if (val) if (val)
entry += format{space(), g_assign_fmt, nest(indent, format{line(), pp(val, opts)})}; entry += format{space(), g_assign_fmt, nest(indent, format{line(), fn(val)})};
if (first) { if (first) {
r = group(entry); r = group(entry);
first = false; first = false;
@ -1000,9 +1044,9 @@ class pp_formatter_cell : public formatter_cell {
} }
if (include_e) { if (include_e) {
if (first) if (first)
r += format{line(), pp(c2, opts)}; r += format{line(), fn(c2)};
else else
r = pp(c2, opts); r = fn(c2);
} else { } else {
return r; return r;
} }
@ -1090,14 +1134,17 @@ public:
if (format_ctx) { if (format_ctx) {
return pp(c, e, true, opts); return pp(c, e, true, opts);
} else { } else {
pp_fn fn(m_frontend, opts);
scoped_set_interruptable_ptr<pp_fn> set(m_pp_fn, &fn);
expr c2 = context_to_lambda(c, e); expr c2 = context_to_lambda(c, e);
while (is_fake_context(c2)) { while (is_fake_context(c2)) {
check_interrupted(m_interrupted); check_interrupted(m_interrupted);
name n1 = get_unused_name(c2, &m_frontend); name n1 = get_unused_name(c2);
fn.register_local(n1);
expr const & rest = fake_context_rest(c2); expr const & rest = fake_context_rest(c2);
c2 = instantiate_with_closed(rest, mk_constant(n1)); c2 = instantiate_with_closed(rest, mk_constant(n1));
} }
return pp(c2, opts); return fn(c2);
} }
} }

View file

@ -19,6 +19,8 @@ Author: Leonardo de Moura
namespace lean { namespace lean {
static name g_overload_name(name(name(name(0u), "library"), "overload")); static name g_overload_name(name(name(name(0u), "library"), "overload"));
static expr g_overload = mk_constant(g_overload_name); static expr g_overload = mk_constant(g_overload_name);
static format g_assignment_fmt = format(":=");
static format g_unification_fmt = format("\u2248");
bool is_overload_marker(expr const & e) { bool is_overload_marker(expr const & e) {
return e == g_overload; return e == g_overload;
@ -65,12 +67,19 @@ class elaborator::imp {
environment const & m_env; environment const & m_env;
name_set const * m_available_defs; name_set const * m_available_defs;
elaborator const * m_owner; elaborator const * m_owner;
expr m_root;
constraint_queue m_constraints; constraint_queue m_constraints;
metavars m_metavars; metavars m_metavars;
bool m_add_constraints; bool m_add_constraints;
// The following mapping is used to store the relationship
// between elaborated expressions and non-elaborated expressions.
// We need that because a frontend may associate line number information
// with the original non-elaborated expressions.
expr_map<expr> m_trace;
volatile bool m_interrupted; volatile bool m_interrupted;
expr metavar_type(expr const & m) { expr metavar_type(expr const & m) {
@ -434,7 +443,14 @@ class elaborator::imp {
} }
return n; return n;
}; };
replace_fn<decltype(proc)> replacer(proc);
auto tracer = [&](expr const & old_e, expr const & new_e) {
if (!is_eqp(new_e, old_e)) {
m_trace[new_e] = old_e;
}
};
replace_fn<decltype(proc), decltype(tracer)> replacer(proc, tracer);
return replacer(e); return replacer(e);
} }
@ -444,14 +460,14 @@ class elaborator::imp {
solve_core(); solve_core();
bool cont = false; bool cont = false;
bool progress = false; bool progress = false;
unsigned unsolved_midx = 0; // unsigned unsolved_midx = 0;
for (unsigned midx = 0; midx < num_meta; midx++) { for (unsigned midx = 0; midx < num_meta; midx++) {
if (m_metavars[midx].m_assignment) { if (m_metavars[midx].m_assignment) {
if (has_assigned_metavar(m_metavars[midx].m_assignment)) { if (has_assigned_metavar(m_metavars[midx].m_assignment)) {
m_metavars[midx].m_assignment = instantiate(m_metavars[midx].m_assignment); m_metavars[midx].m_assignment = instantiate(m_metavars[midx].m_assignment);
} }
if (has_metavar(m_metavars[midx].m_assignment)) { if (has_metavar(m_metavars[midx].m_assignment)) {
unsolved_midx = midx; // unsolved_midx = midx;
cont = true; // must continue cont = true; // must continue
} else { } else {
if (m_metavars[midx].m_type && !m_metavars[midx].m_type_cnstr) { if (m_metavars[midx].m_type && !m_metavars[midx].m_type_cnstr) {
@ -473,7 +489,7 @@ class elaborator::imp {
if (!cont) if (!cont)
return; return;
if (!progress) if (!progress)
throw unsolved_placeholder_exception(*m_owner, m_metavars[unsolved_midx].m_ctx, m_metavars[unsolved_midx].m_mvar); throw unsolved_placeholder_exception(*m_owner, context(), m_root);
} }
} }
@ -494,8 +510,7 @@ public:
} }
void clear() { void clear() {
m_constraints.clear(); m_trace.clear();
m_metavars.clear();
} }
void set_interrupt(bool flag) { void set_interrupt(bool flag) {
@ -524,23 +539,69 @@ public:
return m_env; return m_env;
} }
struct resetter {
imp & m_ref;
resetter(imp & r):m_ref(r) {}
~resetter() { m_ref.m_constraints.clear(); m_ref.m_metavars.clear(); }
};
expr operator()(expr const & e, elaborator const & elb) { expr operator()(expr const & e, elaborator const & elb) {
// std::cout << "ELABORATIMG: " << e << "\n"; if (has_metavar(e)) {
m_owner = &elb; resetter r(*this);
unsigned num_meta = m_metavars.size(); m_owner = &elb;
m_add_constraints = true; m_root = e;
infer(e, context()); unsigned num_meta = m_metavars.size();
solve(num_meta); m_add_constraints = true;
return instantiate(e); infer(e, context());
solve(num_meta);
return instantiate(e);
} else {
return e;
}
}
expr const & get_original(expr const & e) const {
expr const * r = &e;
while (true) {
auto it = m_trace.find(*r);
if (it == m_trace.end()) {
return *r;
} else {
r = &(it->second);
}
}
}
format pp(formatter & f, options const & o) const {
format r;
bool first = true;
for (unsigned i = 0; i < m_metavars.size(); i++) {
metavar_info const & info = m_metavars[i];
expr m = ::lean::mk_metavar(i);
if (first) first = false; else r += line();
format r_assignment;
if (info.m_assignment)
r_assignment = f(info.m_assignment, o);
else
r_assignment = highlight(format("[unassigned]"));
r += group(format{f(m,o), space(), g_assignment_fmt, line(), r_assignment});
}
for (auto c : m_constraints) {
if (first) first = false; else r += line();
r += group(format{f(c.m_lhs, o), space(), g_unification_fmt, line(), f(c.m_rhs, o)});
}
return r;
} }
}; };
elaborator::elaborator(environment const & env):m_ptr(new imp(env, nullptr)) {} elaborator::elaborator(environment const & env):m_ptr(new imp(env, nullptr)) {}
elaborator::~elaborator() {} elaborator::~elaborator() {}
expr elaborator::mk_metavar() { return m_ptr->mk_metavar(); } expr elaborator::mk_metavar() { return m_ptr->mk_metavar(); }
expr elaborator::operator()(expr const & e) { return (*m_ptr)(e, *this); } expr elaborator::operator()(expr const & e) { return (*m_ptr)(e, *this); }
expr const & elaborator::get_original(expr const & e) const { return m_ptr->get_original(e); }
void elaborator::set_interrupt(bool flag) { m_ptr->set_interrupt(flag); } void elaborator::set_interrupt(bool flag) { m_ptr->set_interrupt(flag); }
void elaborator::clear() { m_ptr->clear(); } void elaborator::clear() { m_ptr->clear(); }
environment const & elaborator::get_environment() const { return m_ptr->get_environment(); } environment const & elaborator::get_environment() const { return m_ptr->get_environment(); }
void elaborator::display(std::ostream & out) const { m_ptr->display(out); } void elaborator::display(std::ostream & out) const { m_ptr->display(out); }
format elaborator::pp(formatter & f, options const & o) const { return m_ptr->pp(f,o); }
void elaborator::print(imp * ptr) { ptr->display(std::cout); } void elaborator::print(imp * ptr) { ptr->display(std::cout); }
} }

View file

@ -7,6 +7,7 @@ Author: Leonardo de Moura
#pragma once #pragma once
#include <memory> #include <memory>
#include "environment.h" #include "environment.h"
#include "formatter.h"
namespace lean { namespace lean {
/** /**
@ -26,6 +27,13 @@ public:
expr operator()(expr const & e); expr operator()(expr const & e);
/**
\brief If \c e is an expression instantiated by the elaborator, then it
returns the expression (the one with "holes") used to generate \c e.
Otherwise, it just returns \c e.
*/
expr const & get_original(expr const & e) const;
void set_interrupt(bool flag); void set_interrupt(bool flag);
void interrupt() { set_interrupt(true); } void interrupt() { set_interrupt(true); }
void reset_interrupt() { set_interrupt(false); } void reset_interrupt() { set_interrupt(false); }
@ -35,6 +43,7 @@ public:
environment const & get_environment() const; environment const & get_environment() const;
void display(std::ostream & out) const; void display(std::ostream & out) const;
format pp(formatter & f, options const & o) const;
}; };
/** \brief Return true iff \c e is a special constant used to mark application of overloads. */ /** \brief Return true iff \c e is a special constant used to mark application of overloads. */
bool is_overload_marker(expr const & e); bool is_overload_marker(expr const & e);

View file

@ -37,7 +37,7 @@ public:
class unsolved_placeholder_exception : public elaborator_exception { class unsolved_placeholder_exception : public elaborator_exception {
public: public:
unsolved_placeholder_exception(elaborator const & elb, context const & ctx, expr const & e):elaborator_exception(elb, ctx, e) {} unsolved_placeholder_exception(elaborator const & elb, context const & ctx, expr const & e):elaborator_exception(elb, ctx, e) {}
virtual char const * what() const noexcept { return "unsolved placeholder, system could not fill this placeholder"; } virtual char const * what() const noexcept { return "unsolved placeholder"; }
}; };
class unification_app_mismatch_exception : public elaborator_exception { class unification_app_mismatch_exception : public elaborator_exception {
@ -45,12 +45,12 @@ class unification_app_mismatch_exception : public elaborator_exception {
public: public:
unification_app_mismatch_exception(elaborator const & elb, context const & ctx, expr const & s, unsigned pos):elaborator_exception(elb, ctx, s), m_arg_pos(pos) {} unification_app_mismatch_exception(elaborator const & elb, context const & ctx, expr const & s, unsigned pos):elaborator_exception(elb, ctx, s), m_arg_pos(pos) {}
unsigned get_arg_pos() const { return m_arg_pos; } unsigned get_arg_pos() const { return m_arg_pos; }
virtual char const * what() const noexcept { return "failed to solve unification problem during elaboration"; } virtual char const * what() const noexcept { return "application type mismatch during term elaboration"; }
}; };
class unification_type_mismatch_exception : public elaborator_exception { class unification_type_mismatch_exception : public elaborator_exception {
public: public:
unification_type_mismatch_exception(elaborator const & elb, context const & ctx, expr const & s):elaborator_exception(elb, ctx, s) {} unification_type_mismatch_exception(elaborator const & elb, context const & ctx, expr const & s):elaborator_exception(elb, ctx, s) {}
virtual char const * what() const noexcept { return "failed to solve unification problem during elaboration"; } virtual char const * what() const noexcept { return "type mismatch during term elaboration"; }
}; };
} }

View file

@ -8,6 +8,9 @@ Author: Leonardo de Moura
#include "formatter.h" #include "formatter.h"
#include "printer.h" #include "printer.h"
#include "kernel_exception.h" #include "kernel_exception.h"
#include "elaborator_exception.h"
#include "elaborator.h"
namespace lean { namespace lean {
class simple_formatter_cell : public formatter_cell { class simple_formatter_cell : public formatter_cell {
public: public:
@ -76,4 +79,14 @@ format formatter::operator()(kernel_exception const & ex, options const & opts)
return format(ex.what()); return format(ex.what());
} }
} }
format formatter::operator()(elaborator_exception const & ex, options const & opts) {
unsigned indent = get_pp_indent(opts);
format expr_f = operator()(ex.get_context(), ex.get_expr(), false, opts);
format elb_f = ex.get_elaborator().pp(*this, opts);
return format({format(ex.what()), space(), format("at term"),
nest(indent, compose(line(), expr_f)),
line(), format("Elaborator state"),
nest(indent, compose(line(), elb_f))});
}
} }

View file

@ -38,6 +38,7 @@ public:
virtual void set_interrupt(bool flag) {} virtual void set_interrupt(bool flag) {}
}; };
class kernel_exception; class kernel_exception;
class elaborator_exception;
class formatter { class formatter {
std::shared_ptr<formatter_cell> m_cell; std::shared_ptr<formatter_cell> m_cell;
public: public:
@ -50,6 +51,8 @@ public:
format operator()(environment const & env, options const & opts = options()) { return (*m_cell)(env, opts); } format operator()(environment const & env, options const & opts = options()) { return (*m_cell)(env, opts); }
/** \brief Pretty print a kernel exception using the this formatter */ /** \brief Pretty print a kernel exception using the this formatter */
format operator()(kernel_exception const & ex, options const & opts = options()); format operator()(kernel_exception const & ex, options const & opts = options());
/** \brief Pretty print a elaborator exception using the this formatter */
format operator()(elaborator_exception const & ex, options const & opts = options());
void set_interrupt(bool flag) { m_cell->set_interrupt(flag); } void set_interrupt(bool flag) { m_cell->set_interrupt(flag); }
}; };

View file

@ -102,6 +102,18 @@ inline diagnostic const & operator<<(diagnostic const & out, kernel_exception co
return out; return out;
} }
inline regular const & operator<<(regular const & out, elaborator_exception const & ex) {
options const & opts = out.m_state.get_options();
out.m_state.get_regular_channel().get_stream() << mk_pair(out.m_state.get_formatter()(ex, opts), opts);
return out;
}
inline diagnostic const & operator<<(diagnostic const & out, elaborator_exception const & ex) {
options const & opts = out.m_state.get_options();
out.m_state.get_diagnostic_channel().get_stream() << mk_pair(out.m_state.get_formatter()(ex, opts), opts);
return out;
}
template<typename T> template<typename T>
inline regular const & operator<<(regular const & out, T const & t) { inline regular const & operator<<(regular const & out, T const & t) {
out.m_state.get_regular_channel().get_stream() << t; out.m_state.get_regular_channel().get_stream() << t;