refactor(*): structured message objects

This commit is contained in:
Gabriel Ebner 2016-10-11 17:29:01 -04:00 committed by Leonardo de Moura
parent bf7bae6eaf
commit b05b514cc2
32 changed files with 434 additions and 584 deletions

View file

@ -7,7 +7,6 @@ Author: Leonardo de Moura
#include "kernel/kernel_exception.h"
#include "kernel/type_checker.h"
#include "library/print.h"
#include "library/error_handling.h"
#include "api/exception.h"
#include "api/string.h"
using namespace lean; // NOLINT
@ -41,25 +40,6 @@ char const * lean_exception_get_message(lean_exception e) {
}
}
char const * lean_exception_get_detailed_message(lean_exception e) {
if (!e)
return 0;
try {
formatter_factory fmtf = mk_print_formatter_factory();
std::shared_ptr<output_channel> out(new string_output_channel());
io_state ios(fmtf);
ios.set_regular_channel(out);
ios.set_diagnostic_channel(out);
environment env;
type_checker tc(env);
io_state_stream ioss(env, ios, tc);
display_error(ioss, nullptr, *lean::to_exception(e));
return mk_string(static_cast<string_output_channel const *>(out.get())->str());
} catch (...) {
return 0;
}
}
lean_exception_kind lean_exception_get_kind(lean_exception e) {
lean::throwable * ex = lean::to_exception(e);
if (!ex)

View file

@ -4,7 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#include "library/error_handling.h"
#include "library/io_state_stream.h"
#include "frontends/lean/pp.h"
#include "api/string.h"
#include "api/exception.h"
@ -116,7 +116,7 @@ lean_bool lean_exception_to_pp_string(lean_env env, lean_ios ios, lean_exception
type_checker tc(to_env_ref(env));
io_state_stream ioss(to_env_ref(env), new_ios, tc);
throwable * _e = to_exception(e);
display_error(ioss, nullptr, *_e);
ioss << _e->what();
*r = mk_string(static_cast<string_output_channel const *>(aux.get())->str());
LEAN_CATCH;
}

View file

@ -165,18 +165,14 @@ environment check_cmd(parser & p) {
std::tie(e, ls) = parse_local_expr(p);
type_checker tc(p.env(), true, false);
expr type = tc.check(e, ls);
auto out = regular(p.env(), p.ios(), tc);
auto out = p.mk_message(p.cmd_pos(), INFORMATION);
formatter fmt = out.get_formatter();
unsigned indent = get_pp_indent(p.get_options());
format e_fmt = fmt(e);
format type_fmt = fmt(type);
format r = group(e_fmt + space() + colon() + nest(indent, line() + type_fmt));
flycheck_information info(p.ios());
if (info.enabled()) {
p.display_information_pos(p.cmd_pos());
out << "check result:\n";
}
out << mk_pair(r, p.get_options()) << endl;
out.set_caption("check result") << r;
out.report();
return p.env();
}
@ -197,21 +193,14 @@ environment eval_cmd(parser & p) {
bool eta = false;
r = normalize(tc, e, eta);
}
flycheck_information info(p.ios());
if (info.enabled()) {
p.display_information_pos(p.cmd_pos());
p.ios().get_regular_stream() << "eval result:\n";
}
type_context tc(p.env(), p.get_options());
auto out = regular(p.env(), p.ios(), tc);
out << r << endl;
auto out = p.mk_message(p.cmd_pos(), INFORMATION);
out.set_caption("eval result") << r;
out.report();
return p.env();
}
environment exit_cmd(parser & p) {
flycheck_warning wrn(p.ios());
p.display_warning_pos(p.cmd_pos());
p.ios().get_regular_stream() << " using 'exit' to interrupt Lean" << std::endl;
(p.mk_message(p.cmd_pos(), WARNING) << "using 'exit' to interrupt Lean").report();
throw interrupt_parser();
}
@ -337,18 +326,13 @@ static environment local_cmd(parser & p) {
}
static environment help_cmd(parser & p) {
flycheck_information info(p.ios());
if (info.enabled()) {
p.display_information_pos(p.cmd_pos());
p.ios().get_regular_stream() << "help result:\n";
}
auto rep = p.mk_message(p.cmd_pos(), INFORMATION);
if (p.curr_is_token_or_id(get_options_tk())) {
p.next();
auto decls = get_option_declarations();
decls.for_each([&](name const &, option_declaration const & opt) {
p.ios().get_regular_stream()
<< " " << opt.get_name() << " (" << opt.kind() << ") "
<< opt.get_description() << " (default: " << opt.get_default_value() << ")" << std::endl;
rep << " " << opt.get_name() << " (" << opt.kind() << ") "
<< opt.get_description() << " (default: " << opt.get_default_value() << ")\n";
});
} else if (p.curr_is_token_or_id(get_commands_tk())) {
p.next();
@ -359,14 +343,13 @@ static environment help_cmd(parser & p) {
});
std::sort(ns.begin(), ns.end());
for (name const & n : ns) {
p.ios().get_regular_stream()
<< " " << n << ": " << cmds.find(n)->get_descr() << std::endl;
rep << " " << n << ": " << cmds.find(n)->get_descr() << "\n";
};
} else {
p.ios().get_regular_stream()
<< "help options : describe available options\n"
rep << "help options : describe available options\n"
<< "help commands : describe available commands\n";
}
rep.report();
return p.env();
}
@ -409,16 +392,14 @@ static environment unify_cmd(parser & p) {
local_context lctx;
e1 = convert_metavars(mctx, e1);
e2 = convert_metavars(mctx, e2);
tout() << e1 << " =?= " << e2 << "\n";
auto rep = p.mk_message(p.cmd_pos(), INFORMATION);
rep << e1 << " =?= " << e2 << "\n";
type_context ctx(env, p.get_options(), mctx, lctx, transparency_mode::Semireducible);
bool success = ctx.is_def_eq(e1, e2);
if (success)
tout() << ctx.instantiate_mvars(e1) << " =?= " << ctx.instantiate_mvars(e2) << "\n";
flycheck_information info(p.ios());
if (info.enabled()) {
p.display_information_pos(p.cmd_pos());
}
p.ios().get_regular_stream() << (success ? "success" : "fail") << std::endl;
rep << ctx.instantiate_mvars(e1) << " =?= " << ctx.instantiate_mvars(e2) << "\n";
rep << (success ? "unification successful" : "unification failed");
rep.report();
return env;
}
@ -483,8 +464,11 @@ static environment vm_eval_cmd(parser & p) {
vm_state s(new_env);
optional<vm_obj> initial_state;
if (is_IO) initial_state = mk_vm_simple(0);
auto out = p.mk_message(INFORMATION);
out.set_caption("vm_eval result");
// TODO(gabriel): capture output
if (p.profiling()) {
timeit timer(p.ios().get_diagnostic_stream(), "vm_eval time");
timeit timer(out.get_text_stream().get_stream(), "vm_eval time");
vm_eval_core(s, main, initial_state);
} else {
vm_eval_core(s, main, initial_state);
@ -493,13 +477,13 @@ static environment vm_eval_cmd(parser & p) {
// do not print anything
} else if (is_string) {
vm_obj r = s.get(0);
p.ios().get_regular_stream() << to_string(r) << "\n";
out << to_string(r);
} else {
/* if it is not IO nor a string, then display object on top of the stack using vm_obj display method */
vm_obj r = s.get(0);
display(p.ios().get_regular_stream(), r);
p.ios().get_regular_stream() << "\n";
display(out.get_text_stream().get_stream(), r);
}
out.report();
return p.env();
}

View file

@ -6,9 +6,10 @@ Author: Leonardo de Moura
*/
#pragma once
#include "frontends/lean/cmd_table.h"
#include "library/message_builder.h"
namespace lean {
bool print_id_info(parser & p, name const & id, bool show_value, pos_info const & pos);
bool print_token_info(parser const & p, name const & tk);
bool print_id_info(parser & p, message_builder & out, name const & id, bool show_value, pos_info const & pos);
bool print_token_info(parser const & p, message_builder & out, name const & tk);
cmd_table get_builtin_cmds();
/* \brief Replay export declarations in the top-level of imported files */

View file

@ -22,8 +22,6 @@ Author: Leonardo de Moura
#include "library/locals.h"
#include "library/explicit.h"
#include "library/unfold_macros.h"
#include "library/flycheck.h"
#include "library/error_handling.h"
#include "frontends/lean/parser.h"
#include "frontends/lean/decl_util.h"
#include "frontends/lean/util.h"

View file

@ -20,7 +20,6 @@ Author: Leonardo de Moura
#include "library/noncomputable.h"
#include "library/module.h"
#include "library/flycheck.h"
#include "library/error_handling.h"
#include "library/scope_pos_info_provider.h"
#include "library/replace_visitor.h"
#include "library/equations_compiler/equations.h"
@ -218,17 +217,15 @@ static expr_pair elaborate_definition_core(elaborator & elab, def_cmd_kind kind,
}
}
static void display_pos(std::ostream & out, parser const & p, pos_info const & pos) {
display_pos(out, p.get_stream_name().c_str(), pos.first, pos.second);
}
static expr_pair elaborate_definition(parser & p, elaborator & elab, def_cmd_kind kind, expr const & fn, expr const & val, pos_info const & pos) {
if (p.profiling()) {
std::ostringstream msg;
display_pos(msg, p, pos);
msg << " elaboration time for " << local_pp_name(fn);
timeit timer(p.ios().get_diagnostic_stream(), msg.str().c_str(), LEAN_PROFILE_THRESHOLD);
return elaborate_definition_core(elab, kind, fn, val);
auto msg = p.mk_message(pos, INFORMATION);
msg << "elaboration time for " << fn;
{
timeit timer(msg.get_text_stream().get_stream(), "", LEAN_PROFILE_THRESHOLD);
return elaborate_definition_core(elab, kind, fn, val);
}
msg.report();
} else {
return elaborate_definition_core(elab, kind, fn, val);
}
@ -264,11 +261,13 @@ static pair<environment, name> mk_real_name(environment const & env, name const
static certified_declaration check(parser & p, environment const & env, name const & c_name, declaration const & d, pos_info const & pos) {
if (p.profiling()) {
std::ostringstream msg;
display_pos(msg, p, pos);
msg << " type checking time for " << c_name;
timeit timer(p.ios().get_diagnostic_stream(), msg.str().c_str(), LEAN_PROFILE_THRESHOLD);
return ::lean::check(env, d);
auto msg = p.mk_message(pos, INFORMATION);
msg << "type checking time for " << c_name;
{
timeit timer(msg.get_text_stream().get_stream(), "", LEAN_PROFILE_THRESHOLD);
return ::lean::check(env, d);
}
msg.report();
} else {
return ::lean::check(env, d);
}
@ -297,13 +296,11 @@ static environment compile_decl(parser & p, environment const & env, def_cmd_kin
} catch (exception & ex) {
if (p.found_errors())
return env;
flycheck_warning wrn(p.ios());
auto & out = p.ios().get_regular_stream();
display_pos(out, p, pos);
out << "failed to generate bytecode for '" << c_name << "'" << std::endl;
type_context ctx(p.env());
auto out2 = regular(p.env(), p.ios(), ctx);
display_warning(out2, get_pos_info_provider(), ex);
// FIXME(gabriel): use position from exception
auto out = p.mk_message(pos, WARNING);
out << "failed to generate bytecode for '" << c_name << "'\n";
out.set_exception(ex);
out.report();
return env;
}
}

View file

@ -28,7 +28,6 @@ Author: Leonardo de Moura
#include "library/pp_options.h"
#include "library/flycheck.h"
#include "library/replace_visitor.h"
#include "library/error_handling.h"
#include "library/locals.h"
#include "library/private.h"
#include "library/attribute_manager.h"
@ -2289,11 +2288,8 @@ void elaborator::show_goal(tactic_state const & s, expr const & start_ref, expr
if (curr_pos->first < line || (curr_pos->first == line && curr_pos->second < col))
return;
m_show_goal_pos = optional<pos_info>();
auto out = regular(m_env, get_global_ios(), m_ctx);
print_lean_info_header(out.get_stream());
out << "position " << curr_pos->first << ":" << curr_pos->second << "\n";
out << s.pp(get_global_ios().get_formatter_factory()) << "\n";
print_lean_info_footer(out.get_stream());
get_global_ios().report(message(provider->get_file_name(), *curr_pos, INFORMATION,
(sstream() << mk_pair(s.pp(get_global_ios().get_formatter_factory()), get_global_ios().get_options())).str()));
}
/* Apply the given tactic to the state 's'.

View file

@ -43,7 +43,6 @@ Author: Leonardo de Moura
#include "library/flycheck.h"
#include "library/pp_options.h"
#include "library/noncomputable.h"
#include "library/error_handling.h"
#include "library/scope_pos_info_provider.h"
#include "library/type_context.h"
#include "library/equations_compiler/equations.h"
@ -216,35 +215,33 @@ void parser::scan() {
if (curr_is_identifier()) {
name const & id = get_name_val();
if (p.second <= m_info_at_col && m_info_at_col < p.second + id.utf8_size()) {
print_lean_info_header(m_ios.get_regular_stream());
auto out = mk_message(INFORMATION);
bool ok = true;
try {
bool show_value = false;
ok = print_id_info(*this, id, show_value, p);
ok = print_id_info(*this, out, id, show_value, p);
} catch (exception &) {
ok = false;
}
if (!ok)
m_ios.get_regular_stream() << "unknown identifier '" << id << "'\n";
print_lean_info_footer(m_ios.get_regular_stream());
out << "unknown identifier '" << id << "'\n";
out.report();
m_info_at = false;
}
} else if (curr_is_keyword()) {
name const & tk = get_token_info().token();
if (p.second <= m_info_at_col && m_info_at_col < p.second + tk.utf8_size()) {
print_lean_info_header(m_ios.get_regular_stream());
auto out = mk_message(INFORMATION);
try {
print_token_info(*this, tk);
print_token_info(*this, out, tk);
} catch (exception &) {}
print_lean_info_footer(m_ios.get_regular_stream());
out.report();
m_info_at = false;
}
} else if (curr_is_command()) {
name const & tk = get_token_info().token();
if (p.second <= m_info_at_col && m_info_at_col < p.second + tk.utf8_size()) {
print_lean_info_header(m_ios.get_regular_stream());
m_ios.get_regular_stream() << "'" << tk << "' is a command\n";
print_lean_info_footer(m_ios.get_regular_stream());
(mk_message(INFORMATION) << "'" << tk << "' is a command").report();
m_info_at = false;
}
}
@ -284,9 +281,7 @@ expr parser::mk_sorry(pos_info const & p) {
// TODO(Leo): remove the #ifdef.
// The compilation option LEAN_IGNORE_SORRY is a temporary hack for the nightly builds
// We use it to avoid a buch of warnings on cdash.
flycheck_warning wrn(m_ios);
display_warning_pos(p.first, p.second);
m_ios.get_regular_stream() << " using 'sorry'" << std::endl;
(mk_message(p, WARNING) << "using 'sorry'").report();
#endif
}
return save_pos(::lean::mk_sorry(), p);
@ -308,38 +303,6 @@ void parser::updt_options() {
}
}
void parser::display_warning_pos(unsigned line, unsigned pos) {
type_context tc(env(), get_options());
auto out = regular(env(), ios(), tc);
::lean::display_warning_pos(out, get_stream_name().c_str(), line, pos);
}
void parser::display_warning_pos(pos_info p) { display_warning_pos(p.first, p.second); }
void parser::display_information_pos(pos_info pos) {
::lean::display_information_pos(ios().get_regular_stream(), get_options(),
get_stream_name().c_str(), pos.first, pos.second);
}
void parser::display_error_pos(unsigned line, unsigned pos) {
::lean::display_error_pos(ios().get_regular_stream(), get_options(),
get_stream_name().c_str(), line, pos);
}
void parser::display_error_pos(pos_info p) { display_error_pos(p.first, p.second); }
void parser::display_error(char const * msg, unsigned line, unsigned pos) {
flycheck_error err(ios());
display_error_pos(line, pos);
ios().get_regular_stream() << " " << msg << std::endl;
}
void parser::display_error(char const * msg, pos_info p) { display_error(msg, p.first, p.second); }
void parser::display_error(throwable const & ex) {
type_context tc(env(), get_options());
auto out = regular(env(), ios(), tc);
::lean::display_error(out, this, ex);
}
void parser::throw_parser_exception(char const * msg, pos_info p) {
throw parser_exception(msg, get_stream_name().c_str(), p.first, p.second);
}
@ -364,21 +327,21 @@ void parser::protected_call(std::function<void()> && f, std::function<void()> &&
ex.get_exception().rethrow();
}
} catch (parser_exception & ex) {
CATCH(flycheck_error err(ios()); ios().get_regular_stream() << ex.what() << std::endl,
throw);
CATCH(ios().report(ex), throw);
} catch (parser_error & ex) {
CATCH(display_error(ex.what(), ex.m_pos),
CATCH((mk_message(ex.m_pos, ERROR) << ex.get_msg()).report(),
throw_parser_exception(ex.what(), ex.m_pos));
} catch (interrupted & ex) {
reset_interrupt();
if (m_verbose)
ios().get_regular_stream() << "!!!Interrupted!!!" << std::endl;
(mk_message(m_last_cmd_pos, ERROR) << "!!!Interrupted!!!").report();
sync();
if (m_use_exceptions)
throw;
} catch (throwable & ex) {
reset_interrupt();
CATCH(display_error(ex), throw_nested_exception(ex, m_last_cmd_pos));
CATCH(mk_message(m_last_cmd_pos, ERROR).set_exception(ex).report(),
throw_nested_exception(ex, m_last_cmd_pos));
}
}
@ -2108,13 +2071,11 @@ void parser::parse_imports() {
olean_files.push_back(module_name(k, f));
} else {
m_found_errors = true;
if (!m_use_exceptions && m_show_errors) {
flycheck_error err(ios());
display_error_pos(pos());
ios().get_regular_stream() << " invalid import, unknown module '" << f << "'" << std::endl;
}
parser_error error(sstream() << "invalid import, unknown module '" << f << "'", pos());
if (!m_use_exceptions && m_show_errors)
ios().report(message(get_file_name(), error.m_pos, ERROR, error.get_msg()));
if (m_use_exceptions)
throw parser_error(sstream() << "invalid import, unknown module '" << f << "'", pos());
throw error;
}
};
if (!prelude) {
@ -2182,9 +2143,7 @@ bool parser::parse_commands() {
// TODO(Leo): remove the #ifdef.
// The compilation option LEAN_IGNORE_SORRY is a temporary hack for the nightly builds
// We use it to avoid a buch of warnings on cdash.
flycheck_warning wrn(ios());
display_warning_pos(pos());
ios().get_regular_stream() << " imported file uses 'sorry'" << std::endl;
(mk_message(WARNING) << "imported file uses 'sorry'").report();
#endif
}
while (!done) {
@ -2217,7 +2176,7 @@ bool parser::parse_commands() {
if (has_open_scopes(m_env)) {
m_found_errors = true;
if (!m_use_exceptions && m_show_errors)
display_error("invalid end of module, expecting 'end'", pos());
(mk_message(ERROR) << "invalid end of module, expecting 'end'").report();
else if (m_use_exceptions)
throw_parser_exception("invalid end of module, expecting 'end'", pos());
}
@ -2291,6 +2250,14 @@ char const * parser::get_file_name() const {
return get_stream_name().c_str();
}
message_builder parser::mk_message(pos_info const &p, message_severity severity) {
std::shared_ptr<abstract_type_context> tc = std::make_shared<type_context>(env(), get_options());
return message_builder(this, tc, env(), ios(), get_file_name(), p, severity);
}
message_builder parser::mk_message(message_severity severity) {
return mk_message(pos(), severity);
}
bool parse_commands(environment & env, io_state & ios, std::istream & in, char const * strm_name,
optional<std::string> const & base_dir, bool use_exceptions,
unsigned num_threads, definition_cache * cache) {

View file

@ -16,6 +16,7 @@ Author: Leonardo de Moura
#include "library/abstract_parser.h"
#include "library/io_state.h"
#include "library/io_state_stream.h"
#include "library/message_builder.h"
#include "library/definition_cache.h"
#include "frontends/lean/scanner.h"
#include "frontends/lean/local_decls.h"
@ -135,11 +136,6 @@ class parser : public abstract_parser {
// noncomputable definitions not tagged as noncomputable.
bool m_ignore_noncomputable;
void display_warning_pos(unsigned line, unsigned pos);
void display_error_pos(unsigned line, unsigned pos);
void display_error_pos(pos_info p);
void display_error(char const * msg, unsigned line, unsigned pos);
void display_error(char const * msg, pos_info p);
void throw_parser_exception(char const * msg, pos_info p);
void throw_nested_exception(throwable const & ex, pos_info p);
@ -213,8 +209,6 @@ public:
snapshot const * s = nullptr, snapshot_vector * sv = nullptr);
~parser();
void display_error(throwable const & ex);
bool ignore_noncomputable() const { return m_ignore_noncomputable; }
void set_ignore_noncomputable() { m_ignore_noncomputable = true; }
@ -240,6 +234,9 @@ public:
environment const & env() const { return m_env; }
io_state const & ios() const { return m_ios; }
message_builder mk_message(pos_info const & p, message_severity severity);
message_builder mk_message(message_severity severity);
local_level_decls const & get_local_level_decls() const { return m_local_level_decls; }
local_expr_decls const & get_local_expr_decls() const { return m_local_decls; }
@ -479,9 +476,6 @@ public:
expr mk_sorry(pos_info const & p);
bool used_sorry() const { return m_used_sorry; }
void display_information_pos(pos_info p);
void display_warning_pos(pos_info p);
/** return true iff profiling is enabled */
bool profiling() const { return m_profile; }

View file

@ -1731,40 +1731,4 @@ formatter_factory mk_pretty_formatter_factory() {
};
}
static options mk_options(bool detail) {
options opts;
if (detail) {
opts = opts.update(name{"pp", "implicit"}, true);
opts = opts.update(name{"pp", "notation"}, false);
}
return opts;
}
static void pp_core(environment const & env, expr const & e, bool detail) {
type_checker tc(env);
io_state ios(mk_pretty_formatter_factory(), mk_options(detail));
regular(env, ios, tc) << e << "\n";
}
/* static void pp_core(environment const & env, goal const & g, bool detail) {
type_checker tc(env);
io_state ios(mk_pretty_formatter_factory(), mk_options(detail));
regular(env, ios, tc) << g << "\n";
}
static void pp_core(environment const & env, proof_state const & s, bool detail) {
type_checker tc(env);
io_state ios(mk_pretty_formatter_factory(), mk_options(detail));
auto out = regular(env, ios, tc);
out << s.pp(out.get_formatter()) << "\n";
}
*/
}
// for debugging purposes
void pp(lean::environment const & env, lean::expr const & e) { lean::pp_core(env, e, false); }
// void pp(lean::environment const & env, lean::goal const & g) { lean::pp_core(env, g, false); }
// void pp(lean::environment const & env, lean::proof_state const & s) { lean::pp_core(env, s, false); }
void pp_detail(lean::environment const & env, lean::expr const & e) { lean::pp_core(env, e, true); }
// void pp_detail(lean::environment const & env, lean::goal const & g) { lean::pp_core(env, g, true); }
// void pp_detail(lean::environment const & env, lean::proof_state const & s) { lean::pp_core(env, s, true); }

View file

@ -6,6 +6,7 @@ Author: Leonardo de Moura
*/
#include <algorithm>
#include <string>
#include <library/trace.h>
#include "util/sstream.h"
#include "util/sexpr/option_declarations.h"
#include "kernel/for_each_fn.h"
@ -14,7 +15,6 @@ Author: Leonardo de Moura
#include "library/util.h"
#include "library/class.h"
#include "library/aliases.h"
#include "library/flycheck.h"
#include "library/pp_options.h"
#include "library/private.h"
#include "library/protected.h"
@ -69,22 +69,19 @@ struct print_axioms_deps {
}
};
static environment print_axioms(parser & p) {
static environment print_axioms(parser & p, message_builder & out) {
if (p.curr_is_identifier()) {
name c = p.check_constant_next("invalid 'print axioms', constant expected");
environment new_env = p.reveal_all_theorems();
type_context tc(new_env, p.get_options());
auto out = regular(new_env, p.ios(), tc);
print_axioms_deps(p.env(), out)(c);
auto new_out = io_state_stream(new_env, p.ios(), tc, out.get_text_stream().get_channel());
print_axioms_deps(p.env(), new_out)(c);
return new_env;
} else {
bool has_axioms = false;
environment const & env = p.env();
type_context tc(env, p.get_options());
auto out = regular(env, p.ios(), tc);
env.for_each_declaration([&](declaration const & d) {
p.env().for_each_declaration([&](declaration const & d) {
name const & n = d.get_name();
if (!d.is_definition() && !env.is_builtin(n) && d.is_trusted()) {
if (!d.is_definition() && !p.env().is_builtin(n) && d.is_trusted()) {
out << n << " : " << d.get_type() << endl;
has_axioms = true;
}
@ -95,33 +92,28 @@ static environment print_axioms(parser & p) {
}
}
static void print_prefix(parser & p) {
static void print_prefix(parser & p, message_builder & out) {
name prefix = p.check_id_next("invalid 'print prefix' command, identifier expected");
environment const & env = p.env();
buffer<declaration> to_print;
type_context tc(env, p.get_options());
auto out = regular(env, p.ios(), tc);
env.for_each_declaration([&](declaration const & d) {
p.env().for_each_declaration([&](declaration const & d) {
if (is_prefix_of(prefix, d.get_name())) {
to_print.push_back(d);
}
});
std::sort(to_print.begin(), to_print.end(), [](declaration const & d1, declaration const & d2) { return d1.get_name() < d2.get_name(); });
for (declaration const & d : to_print) {
out << d.get_name() << " : " << d.get_type() << endl;
out << d.get_name() << " : " << d.get_type() << "\n";
}
if (to_print.empty())
out << "no declaration starting with prefix '" << prefix << "'" << endl;
out << "no declaration starting with prefix '" << prefix << "'\n";
}
static void print_fields(parser const & p, name const & S, pos_info const & pos) {
static void print_fields(parser const & p, message_builder & out, name const & S, pos_info const & pos) {
environment const & env = p.env();
if (!is_structure(env, S))
throw parser_error(sstream() << "invalid 'print fields' command, '" << S << "' is not a structure", pos);
buffer<name> field_names;
get_structure_fields(env, S, field_names);
type_context tc(env, p.get_options());
auto out = regular(env, p.ios(), tc);
for (name const & field_name : field_names) {
declaration d = env.get(field_name);
out << d.get_name() << " : " << d.get_type() << endl;
@ -142,16 +134,13 @@ static bool uses_some_token(unsigned num, notation::transition const * ts, buffe
std::any_of(tokens.begin(), tokens.end(), [&](name const & token) { return uses_token(num, ts, token); });
}
static bool print_parse_table(parser const & p, parse_table const & t, bool nud, buffer<name> const & tokens, bool tactic_table = false) {
static bool print_parse_table(parser const & p, message_builder & rep, parse_table const & t, bool nud, buffer<name> const & tokens, bool tactic_table = false) {
bool found = false;
io_state ios = p.ios();
options os = ios.get_options();
options os = rep.get_text_stream().get_options();
os = os.update_if_undef(get_pp_full_names_name(), true);
os = os.update(get_pp_notation_name(), false);
os = os.update(get_pp_preterm_name(), true);
ios.set_options(os);
type_context tc(p.env(), p.get_options());
io_state_stream out = regular(p.env(), ios, tc);
auto out = rep.get_text_stream().update_options(os);
optional<token_table> tt(get_token_table(p.env()));
t.for_each([&](unsigned num, notation::transition const * ts, list<notation::accepting> const & overloads) {
if (uses_some_token(num, ts, tokens)) {
@ -164,19 +153,19 @@ static bool print_parse_table(parser const & p, parse_table const & t, bool nud,
return found;
}
static void print_notation(parser & p) {
static void print_notation(parser & p, message_builder & out) {
buffer<name> tokens;
while (p.curr_is_keyword()) {
tokens.push_back(p.get_token_info().token());
p.next();
}
bool found = false;
if (print_parse_table(p, get_nud_table(p.env()), true, tokens))
if (print_parse_table(p, out, get_nud_table(p.env()), true, tokens))
found = true;
if (print_parse_table(p, get_led_table(p.env()), false, tokens))
if (print_parse_table(p, out, get_led_table(p.env()), false, tokens))
found = true;
if (!found)
p.ios().get_regular_stream() << "no notation" << std::endl;
out << "no notation";
}
#if 0
@ -225,25 +214,21 @@ static name to_user_name(environment const & env, name const & n) {
return n;
}
static void print_definition(parser const & p, name const & n, pos_info const & pos) {
static void print_definition(parser const & p, message_builder & out, name const & n, pos_info const & pos) {
environment const & env = p.env();
declaration d = env.get(n);
options opts = p.get_options();
opts = opts.update_if_undef(get_pp_beta_name(), false);
io_state ios(p.ios(), opts);
type_context tc(env, opts);
io_state_stream out = regular(env, ios, tc);
if (d.is_axiom())
throw parser_error(sstream() << "invalid 'print definition', theorem '" << to_user_name(env, n)
<< "' is not available (suggestion: use command 'reveal " << to_user_name(env, n) << "')", pos);
if (!d.is_definition())
throw parser_error(sstream() << "invalid 'print definition', '" << to_user_name(env, n) << "' is not a definition", pos);
out << d.get_value() << endl;
options opts = out.get_text_stream().get_options();
opts = opts.update_if_undef(get_pp_beta_name(), false);
out.get_text_stream().update_options(opts) << d.get_value() << endl;
}
static void print_attributes(parser const & p, name const & n) {
static void print_attributes(parser const & p, message_builder & out, name const & n) {
environment const & env = p.env();
std::ostream & out = p.ios().get_regular_stream();
buffer<attribute const *> attrs;
get_attributes(p.env(), attrs);
std::sort(attrs.begin(), attrs.end(), [](attribute const * a1, attribute const * a2) {
@ -261,7 +246,7 @@ static void print_attributes(parser const & p, name const & n) {
out << ", ";
}
out << attr->get_name();
data->print(out);
data->print(out.get_text_stream().get_stream());
unsigned prio = attr->get_prio(env, n);
if (prio != LEAN_DEFAULT_PRIORITY)
out << ", priority " << prio;
@ -271,13 +256,11 @@ static void print_attributes(parser const & p, name const & n) {
out << "]\n";
}
static void print_inductive(parser const & p, name const & n, pos_info const & pos) {
static void print_inductive(parser const & p, message_builder & out, name const & n, pos_info const & pos) {
environment const & env = p.env();
type_checker tc(env);
io_state_stream out = regular(env, p.ios(), tc);
if (auto idecl = inductive::is_inductive_decl(env, n)) {
level_param_names ls = idecl->m_level_params;
print_attributes(p, n);
print_attributes(p, out, n);
if (is_structure(env, n))
out << "structure";
else
@ -286,7 +269,7 @@ static void print_inductive(parser const & p, name const & n, pos_info const & p
out << " : " << env.get(n).get_type() << "\n";
if (is_structure(env, n)) {
out << "fields:\n";
print_fields(p, n, pos);
print_fields(p, out, n, pos);
} else {
out << "constructors:\n";
buffer<name> constructors;
@ -300,9 +283,8 @@ static void print_inductive(parser const & p, name const & n, pos_info const & p
}
}
static void print_recursor_info(parser & p) {
static void print_recursor_info(parser & p, message_builder & out) {
name c = p.check_constant_next("invalid 'print [recursor]', constant expected");
std::ostream & out = p.ios().get_regular_stream();
recursor_info info = get_recursor_info(p.env(), c);
out << "recursor information\n"
<< " num. parameters: " << info.get_num_params() << "\n"
@ -339,28 +321,26 @@ static void print_recursor_info(parser & p) {
}
}
static bool print_constant(parser const & p, char const * kind, declaration const & d, bool is_def = false) {
static bool print_constant(parser const & p, message_builder & out, char const * kind, declaration const & d, bool is_def = false) {
type_checker tc(p.env());
auto out = regular(p.env(), p.ios(), tc);
print_attributes(p, d.get_name());
print_attributes(p, out, d.get_name());
if (is_protected(p.env(), d.get_name()))
out << "protected ";
if (d.is_definition() && is_marked_noncomputable(p.env(), d.get_name()))
out << "noncomputable ";
out << kind << " " << to_user_name(p.env(), d.get_name());
out.update_options(out.get_options().update((name {"pp", "binder_types"}), true)) << " : " << d.get_type();
out.get_text_stream().update_options(out.get_text_stream().get_options().update((name {"pp", "binder_types"}), true))
<< " : " << d.get_type();
if (is_def)
out << " :=";
out << "\n";
return true;
}
bool print_id_info(parser & p, name const & id, bool show_value, pos_info const & pos) {
bool print_id_info(parser & p, message_builder & out, name const & id, bool show_value, pos_info const & pos) {
// declarations
try {
environment const & env = p.env();
type_checker tc(env);
auto out = regular(env, p.ios(), tc);
try {
list<name> cs = p.to_constants(id, "", pos);
bool first = true;
@ -368,27 +348,27 @@ bool print_id_info(parser & p, name const & id, bool show_value, pos_info const
if (first) first = false; else out << "\n";
declaration const & d = env.get(c);
if (d.is_theorem()) {
print_constant(p, "theorem", d, show_value);
print_constant(p, out, "theorem", d, show_value);
if (show_value)
print_definition(p, c, pos);
print_definition(p, out, c, pos);
} else if (d.is_axiom() || d.is_constant_assumption()) {
if (inductive::is_inductive_decl(env, c)) {
print_inductive(p, c, pos);
print_inductive(p, out, c, pos);
} else if (inductive::is_intro_rule(env, c)) {
print_constant(p, "constructor", d);
print_constant(p, out, "constructor", d);
} else if (inductive::is_elim_rule(env, c)) {
print_constant(p, "eliminator", d);
print_constant(p, out, "eliminator", d);
} else if (is_quotient_decl(env, c)) {
print_constant(p, "builtin-quotient-type-constant", d);
print_constant(p, out, "builtin-quotient-type-constant", d);
} else if (d.is_axiom()) {
print_constant(p, "axiom", d);
print_constant(p, out, "axiom", d);
} else {
print_constant(p, "constant", d);
print_constant(p, out, "constant", d);
}
} else if (d.is_definition()) {
print_constant(p, "definition", d, show_value);
print_constant(p, out, "definition", d, show_value);
if (show_value)
print_definition(p, c, pos);
print_definition(p, out, c, pos);
}
// print_patterns(p, c);
}
@ -423,32 +403,32 @@ bool print_id_info(parser & p, name const & id, bool show_value, pos_info const
return false;
}
bool print_token_info(parser const & p, name const & tk) {
bool print_token_info(parser const & p, message_builder & out, name const & tk) {
buffer<name> tokens;
tokens.push_back(tk);
bool found = false;
if (print_parse_table(p, get_nud_table(p.env()), true, tokens)) {
if (print_parse_table(p, out, get_nud_table(p.env()), true, tokens)) {
found = true;
}
if (print_parse_table(p, get_led_table(p.env()), false, tokens)) {
if (print_parse_table(p, out, get_led_table(p.env()), false, tokens)) {
found = true;
}
return found;
}
bool print_polymorphic(parser & p) {
bool print_polymorphic(parser & p, message_builder & out) {
auto pos = p.pos();
try {
name id = p.check_id_next("");
bool show_value = true;
if (print_id_info(p, id, show_value, pos))
if (print_id_info(p, out, id, show_value, pos))
return true;
} catch (exception &) {}
// notation
if (p.curr_is_keyword()) {
name tk = p.get_token_info().token();
if (print_token_info(p, tk)) {
if (print_token_info(p, out, tk)) {
p.next();
return true;
}
@ -456,30 +436,23 @@ bool print_polymorphic(parser & p) {
return false;
}
static void print_unification_hints(parser & p) {
type_checker tc(p.env());
auto out = regular(p.env(), p.ios(), tc);
static void print_unification_hints(parser & p, message_builder & out) {
out << pp_unification_hints(get_unification_hints(p.env()), out.get_formatter());
}
static void print_simp_rules(parser & p) {
static void print_simp_rules(parser & p, message_builder & out) {
name attr = p.check_id_next("invalid 'print [simp]' command, identifier expected");
simp_lemmas slss = get_simp_lemmas(p.env(), transparency_mode::Reducible, attr);
type_checker tc(p.env());
auto out = regular(p.env(), p.ios(), tc);
out << slss.pp_simp(out.get_formatter());
}
static void print_congr_rules(parser & p) {
static void print_congr_rules(parser & p, message_builder & out) {
name attr = p.check_id_next("invalid 'print [congr]' command, identifier expected");
simp_lemmas slss = get_simp_lemmas(p.env(), transparency_mode::Reducible, attr);
type_checker tc(p.env());
auto out = regular(p.env(), p.ios(), tc);
out << slss.pp_congr(out.get_formatter());
}
static void print_aliases(parser const & p) {
std::ostream & out = p.ios().get_regular_stream();
static void print_aliases(parser const & p, message_builder & out) {
for_each_expr_alias(p.env(), [&](name const & n, list<name> const & as) {
out << n << " -> {";
bool first = true;
@ -491,8 +464,7 @@ static void print_aliases(parser const & p) {
});
}
static void print_key_equivalences(parser & p) {
std::ostream & out = p.ios().get_regular_stream();
static void print_key_equivalences(parser & p, message_builder & out) {
for_each_key_equivalence(p.env(), [&](buffer<name> const & ns) {
out << "[";
for (unsigned i = 0; i < ns.size(); i++) {
@ -503,7 +475,7 @@ static void print_key_equivalences(parser & p) {
});
}
static void print_attribute(parser & p, attribute const & attr) {
static void print_attribute(parser & p, message_builder & out, attribute const & attr) {
buffer<name> instances;
attr.get_instances(p.env(), instances);
@ -511,28 +483,23 @@ static void print_attribute(parser & p, attribute const & attr) {
unsigned i = instances.size();
while (i > 0) {
--i;
p.ios().get_regular_stream() << instances[i] << "\n";
out << instances[i] << "\n";
}
}
environment print_cmd(parser & p) {
flycheck_information info(p.ios());
environment const & env = p.env();
type_checker tc(env);
auto out = regular(env, p.ios(), tc);
if (info.enabled()) {
p.display_information_pos(p.cmd_pos());
out << "print result:\n";
}
auto out = p.mk_message(p.cmd_pos(), INFORMATION);
out.set_caption("print result");
auto env = p.env();
if (p.curr() == scanner::token_kind::String) {
out << p.get_str_val() << endl;
p.next();
} else if (p.curr_is_token_or_id(get_raw_tk())) {
p.next();
expr e = p.parse_expr();
options opts = out.get_options();
options opts = out.get_text_stream().get_options();
opts = opts.update(get_pp_notation_name(), false);
out.update_options(opts) << e << endl;
out.get_text_stream().update_options(opts) << e << endl;
} else if (p.curr_is_token_or_id(get_options_tk())) {
p.next();
out << p.ios().get_options() << endl;
@ -541,7 +508,7 @@ environment print_cmd(parser & p) {
out << "trust level: " << p.env().trust_lvl() << endl;
} else if (p.curr_is_token_or_id(get_key_equivalences_tk())) {
p.next();
print_key_equivalences(p);
print_key_equivalences(p, out);
} else if (p.curr_is_token_or_id(get_definition_tk())) {
p.next();
auto pos = p.pos();
@ -555,11 +522,11 @@ environment print_cmd(parser & p) {
out << "\n";
declaration const & d = p.env().get(c);
if (d.is_theorem()) {
print_constant(p, "theorem", d);
print_definition(p, c, pos);
print_constant(p, out, "theorem", d);
print_definition(p, out, c, pos);
} else if (d.is_definition()) {
print_constant(p, "definition", d);
print_definition(p, c, pos);
print_constant(p, out, "definition", d);
print_definition(p, out, c, pos);
} else {
throw parser_error(sstream() << "invalid 'print definition', '" << to_user_name(p.env(), c) << "' is not a definition", pos);
}
@ -590,26 +557,26 @@ environment print_cmd(parser & p) {
}
} else if (p.curr_is_token_or_id(get_prefix_tk())) {
p.next();
print_prefix(p);
print_prefix(p, out);
} else if (p.curr_is_token_or_id(get_aliases_tk())) {
p.next();
print_aliases(p);
print_aliases(p, out);
} else if (p.curr_is_token_or_id(get_axioms_tk())) {
p.next();
return print_axioms(p);
print_axioms(p, out);
} else if (p.curr_is_token_or_id(get_fields_tk())) {
p.next();
auto pos = p.pos();
name S = p.check_constant_next("invalid 'print fields' command, constant expected");
print_fields(p, S, pos);
print_fields(p, out, S, pos);
} else if (p.curr_is_token_or_id(get_notation_tk())) {
p.next();
print_notation(p);
print_notation(p, out);
} else if (p.curr_is_token_or_id(get_inductive_tk())) {
p.next();
auto pos = p.pos();
name c = p.check_constant_next("invalid 'print inductive', constant expected");
print_inductive(p, c, pos);
print_inductive(p, out, c, pos);
} else if (p.curr_is_token(get_lbracket_tk())) {
p.next();
auto pos = p.pos();
@ -617,23 +584,24 @@ environment print_cmd(parser & p) {
p.check_token_next(get_rbracket_tk(), "invalid 'print [<attr>]', ']' expected");
if (name == "recursor") {
print_recursor_info(p);
print_recursor_info(p, out);
} else if (name == "unify") {
print_unification_hints(p);
print_unification_hints(p, out);
} else if (name == "simp") {
print_simp_rules(p);
print_simp_rules(p, out);
} else if (name == "congr") {
print_congr_rules(p);
print_congr_rules(p, out);
} else {
if (!is_attribute(p.env(), name))
throw parser_error(sstream() << "unknown attribute [" << name << "]", pos);
auto const & attr = get_attribute(p.env(), name);
print_attribute(p, attr);
print_attribute(p, out, attr);
}
} else if (print_polymorphic(p)) {
} else if (print_polymorphic(p, out)) {
} else {
throw parser_error("invalid print command", p.pos());
}
out.report();
return p.env();
}
}

View file

@ -8,6 +8,7 @@ Author: Daniel Selsam
#include <stack>
#include <utility>
#include <vector>
#include <library/message_builder.h>
#include "util/flet.h"
#include "util/name_map.h"
#include "util/exception.h"
@ -27,7 +28,6 @@ Author: Daniel Selsam
#include "library/io_state.h"
#include "library/io_state_stream.h"
#include "library/local_context.h"
#include "library/error_handling.h"
#include "library/pp_options.h"
#include "library/module.h"
#include "library/trace.h"
@ -713,9 +713,9 @@ public:
return ok;
} catch (throwable const & ex) {
ok = false;
type_context aux_tctx(m_env, m_ios.get_options(), m_lctx);
auto out = regular(m_env, m_ios, aux_tctx);
::lean::display_error(out, this, ex);
::lean::message_builder(this, std::make_shared<type_context>(m_env, m_ios.get_options(), m_lctx),
m_env, m_ios, get_file_name(), get_some_pos(), ERROR)
.set_exception(ex).report();
}
return ok;
}

View file

@ -10,9 +10,10 @@ add_library(library OBJECT deep_copy.cpp expr_lt.cpp io_state.cpp
unfold_macros.cpp app_builder.cpp projection.cpp relation_manager.cpp
export.cpp user_recursors.cpp idx_metavar.cpp noncomputable.cpp
aux_recursors.cpp norm_num.cpp trace.cpp
attribute_manager.cpp error_handling.cpp unification_hint.cpp
attribute_manager.cpp unification_hint.cpp
local_context.cpp metavar_context.cpp type_context.cpp export_decl.cpp delayed_abstraction.cpp
fun_info.cpp congr_lemma.cpp defeq_canonizer.cpp scope_pos_info_provider.cpp
mpq_macro.cpp arith_instance_manager.cpp replace_visitor_with_tc.cpp
aux_definition.cpp inverse.cpp library_system.cpp pattern_attribute.cpp choice.cpp
locals.cpp normalize.cpp discr_tree.cpp)
locals.cpp normalize.cpp discr_tree.cpp
messages.cpp message_builder.cpp)

View file

@ -6,6 +6,7 @@ Author: Sebastian Ullrich
*/
#pragma once
#include "kernel/pos_info_provider.h"
#include <string>
namespace lean {
/** \brief Exception used to track parsing erros, it does not leak outside of this class. */
@ -13,6 +14,7 @@ struct parser_error : public exception {
pos_info m_pos;
parser_error(char const * msg, pos_info const & p):exception(msg), m_pos(p) {}
parser_error(sstream const & msg, pos_info const & p):exception(msg), m_pos(p) {}
std::string const & get_msg() const { return m_msg; }
virtual throwable * clone() const { return new parser_error(m_msg.c_str(), m_pos); }
virtual void rethrow() const { throw *this; }
};

View file

@ -1,157 +0,0 @@
/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#include <utility>
#include <string>
#include "util/name_set.h"
#include "kernel/ext_exception.h"
#include "kernel/for_each_fn.h"
#include "library/io_state_stream.h"
#include "library/exception.h"
#include "library/flycheck.h"
#include "library/pp_options.h"
#include "library/error_handling.h"
namespace lean {
void display_pos(std::ostream & out, options const & o, char const * strm_name, unsigned line, unsigned pos) {
out << strm_name << ":";
if (o.get_bool("flycheck", false)) {
// generate valid line and column for flycheck mode
if (line == static_cast<unsigned>(-1))
line = 1;
if (pos == static_cast<unsigned>(-1))
pos = 0;
}
if (line != static_cast<unsigned>(-1))
out << line << ":";
if (pos != static_cast<unsigned>(-1))
out << pos << ":";
}
void display_pos(std::ostream & out, char const * strm_name, unsigned line, unsigned pos) {
display_pos(out, options(), strm_name, line, pos);
}
void display_pos(io_state_stream const & ios, char const * strm_name, unsigned line, unsigned pos) {
display_pos(ios.get_stream(), ios.get_options(), strm_name, line, pos);
}
void display_error_pos(std::ostream & out, options const & o, char const * strm_name, unsigned line, unsigned pos) {
display_pos(out, o, strm_name, line, pos);
out << " error:";
}
void display_error_pos(io_state_stream const & ios, char const * strm_name, unsigned line, unsigned pos) {
display_error_pos(ios.get_stream(), ios.get_options(), strm_name, line, pos);
}
void display_warning_pos(std::ostream & out, options const & o, char const * strm_name, unsigned line, unsigned pos) {
display_pos(out, o, strm_name, line, pos);
out << " warning:";
}
void display_warning_pos(io_state_stream const & ios, char const * strm_name, unsigned line, unsigned pos) {
display_warning_pos(ios.get_stream(), ios.get_options(), strm_name, line, pos);
}
void display_warning_pos(io_state_stream const & ios, pos_info_provider const * p, expr const & e) {
if (p) {
auto pos = p->get_pos_info_or_some(e);
display_warning_pos(ios, p->get_file_name(), pos.first, pos.second);
} else {
ios << "warning:";
}
}
void display_warning_pos(io_state_stream const & ios, pos_info_provider const * p, optional<expr> const & e) {
if (e) {
display_warning_pos(ios, p, *e);
} else {
ios << "warning:";
}
}
void display_information_pos(std::ostream & out, options const & o, char const * strm_name, unsigned line, unsigned pos) {
display_pos(out, o, strm_name, line, pos);
out << " information:";
}
void display_information_pos(io_state_stream const & ios, char const * strm_name, unsigned line, unsigned pos) {
display_information_pos(ios.get_stream(), ios.get_options(), strm_name, line, pos);
}
void display_error_pos(std::ostream & out, options const & o, pos_info_provider const * p, expr const & e) {
if (p) {
auto pos = p->get_pos_info_or_some(e);
display_error_pos(out, o, p->get_file_name(), pos.first, pos.second);
} else {
out << "error:";
}
}
void display_error_pos(io_state_stream const & ios, pos_info_provider const * p, expr const & e) {
display_error_pos(ios.get_stream(), ios.get_options(), p, e);
}
void display_error_pos(io_state_stream const & ios, pos_info_provider const * p, optional<expr> const & e) {
if (e) {
display_error_pos(ios, p, *e);
} else if (p) {
auto pos = p->get_some_pos();
display_error_pos(ios, p->get_file_name(), pos.first, pos.second);
} else {
ios << "error:";
}
}
static void display_error_warning_pos(bool is_error, io_state_stream const & ios, pos_info_provider const * p, optional<expr> const & e) {
if (is_error)
display_error_pos(ios, p, e);
else
display_warning_pos(ios, p, e);
}
static void display_error_warning_pos(bool is_error, io_state_stream const & ios, char const * strm_name, unsigned line, unsigned pos) {
if (is_error)
display_error_pos(ios, strm_name, line, pos);
else
display_warning_pos(ios, strm_name, line, pos);
}
static void display_error_warning(bool is_error, io_state_stream const & ios, pos_info_provider const * p, throwable const & ex);
static void display_error_warning(bool is_error, io_state_stream const & ios, pos_info_provider const * p, ext_exception const & ex) {
display_error_warning_pos(is_error, ios, p, ex.get_main_expr());
ios << " " << ex << endl;
}
static void display_error_warning(bool is_error, io_state_stream const & ios, pos_info_provider const * p, formatted_exception const & ex) {
display_error_warning_pos(is_error, ios, p, ex.get_main_expr());
ios << " " << ex << endl;
}
static void display_error_warning(bool is_error, io_state_stream const & ios, pos_info_provider const * p, throwable const & ex) {
flycheck_error err(ios.get_stream(), ios.get_options());
if (auto k_ex = dynamic_cast<ext_exception const *>(&ex)) {
display_error_warning(is_error, ios, p, *k_ex);
} else if (auto f_ex = dynamic_cast<formatted_exception const *>(&ex)) {
display_error_warning(is_error, ios, p, *f_ex);
} else if (p) {
display_error_warning_pos(is_error, ios, p->get_file_name(), p->get_some_pos().first, p->get_some_pos().second);
ios << " " << ex.what() << endl;
} else {
ios << (is_error ? "error: " : "warning: ") << ex.what() << endl;
}
}
void display_error(io_state_stream const & ios, pos_info_provider const * p, throwable const & ex) {
display_error_warning(true, ios, p, ex);
}
void display_warning(io_state_stream const & ios, pos_info_provider const * p, throwable const & ex) {
display_error_warning(false, ios, p, ex);
}
}

View file

@ -1,36 +0,0 @@
/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#pragma once
#include "util/exception.h"
#include "kernel/pos_info_provider.h"
#include "library/io_state_stream.h"
namespace lean {
void display_pos(std::ostream & out, options const & o, char const * strm_name, unsigned line, unsigned pos);
void display_pos(std::ostream & out, char const * strm_name, unsigned line, unsigned pos);
void display_pos(io_state_stream const & ios, char const * strm_name, unsigned line, unsigned pos);
/**
\brief Display position information associated with \c e (IF avaiable).
If it is not available, it just displays "error:"
*/
void display_error_pos(std::ostream & out, options const & o, pos_info_provider const * p, expr const & e);
void display_error_pos(io_state_stream const & ios, pos_info_provider const * p, expr const & e);
/** \brief Display position information + "error:" */
void display_error_pos(std::ostream & out, options const & o, char const * strm_name, unsigned line, unsigned pos);
void display_error_pos(io_state_stream const & ios, char const * strm_name, unsigned line, unsigned pos);
/** \brief Similar to #display_error_pos, but displays a "warning:" */
void display_warning_pos(std::ostream & out, options const & o, char const * strm_name, unsigned line, unsigned pos);
void display_warning_pos(io_state_stream const & ios, char const * strm_name, unsigned line, unsigned pos);
void display_information_pos(std::ostream & out, options const & o, char const * strm_name, unsigned line, unsigned pos);
void display_information_pos(io_state_stream const & ios, char const * strm_name, unsigned line, unsigned pos);
/**
\brief Display exception in the regular stream of \c ios, using the configuration options and formatter from \c ios.
Exceptions that contain expressions use the given \c pos_info_provider (if available) to retrieve line number information.
*/
void display_error(io_state_stream const & ios, pos_info_provider const * p, throwable const & ex);
void display_warning(io_state_stream const & ios, pos_info_provider const * p, throwable const & ex);
}

View file

@ -5,7 +5,6 @@ Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#include "library/flycheck.h"
#include "library/error_handling.h"
namespace lean {
flycheck_scope::flycheck_scope(std::ostream & out, options const & o, char const * kind):
@ -18,7 +17,7 @@ flycheck_scope::~flycheck_scope() {
}
flycheck_output_scope::flycheck_output_scope(io_state const & ios, char const * stream_name, pos_info const & pos) :
m_stream_name(stream_name), m_pos(pos),
m_out(ios.get_regular_stream()),
m_ios(ios),
m_redirected_ios(ios),
m_scoped_ios(), m_buffer() {
if (ios.get_options().get_bool("flycheck", false)) {
@ -34,12 +33,8 @@ flycheck_output_scope::flycheck_output_scope(pos_info_provider const * provider,
flycheck_output_scope::~flycheck_output_scope() {
if (enabled()) {
auto redirected_output = m_buffer->str();
if (!redirected_output.empty()) {
m_out << "FLYCHECK_BEGIN INFORMATION" << std::endl;
display_pos(m_out, m_stream_name, m_pos.first, m_pos.second);
m_out << " information:" << std::endl << redirected_output;
m_out << "FLYCHECK_END" << std::endl;
}
if (!redirected_output.empty())
m_ios.report(message(m_stream_name, m_pos, INFORMATION, "trace output", redirected_output));
}
}
}

View file

@ -27,7 +27,7 @@ public:
class flycheck_output_scope {
char const * m_stream_name;
pos_info m_pos;
std::ostream & m_out;
io_state const & m_ios;
io_state m_redirected_ios;
std::unique_ptr<scope_global_ios> m_scoped_ios;
std::shared_ptr<string_output_channel> m_buffer;
@ -39,19 +39,4 @@ public:
~flycheck_output_scope();
bool enabled() const { return static_cast<bool>(m_scoped_ios); }
};
struct flycheck_error : public flycheck_scope {
flycheck_error(std::ostream & out, options const & o):flycheck_scope(out, o, "ERROR") {}
flycheck_error(io_state const & ios):flycheck_scope(ios, "ERROR") {}
};
struct flycheck_warning : public flycheck_scope {
flycheck_warning(std::ostream & out, options const & o):flycheck_scope(out, o, "WARNING") {}
flycheck_warning(io_state const & ios):flycheck_scope(ios, "WARNING") {}
};
struct flycheck_information : public flycheck_scope {
flycheck_information(std::ostream & out, options const & o):flycheck_scope(out, o, "INFORMATION") {}
flycheck_information(io_state const & ios):flycheck_scope(ios, "INFORMATION") {}
};
}

View file

@ -21,26 +21,30 @@ io_state::io_state():io_state(mk_print_formatter_factory()) {}
io_state::io_state(formatter_factory const & fmtf):
m_formatter_factory(fmtf),
m_regular_channel(std::make_shared<stdout_channel>()),
m_diagnostic_channel(std::make_shared<stderr_channel>()) {
m_diagnostic_channel(std::make_shared<stderr_channel>()),
m_message_channel(std::make_shared<output_channel_message_stream>(m_options, m_regular_channel)) {
}
io_state::io_state(options const & opts, formatter_factory const & fmtf):
m_options(opts),
m_formatter_factory(fmtf),
m_regular_channel(std::make_shared<stdout_channel>()),
m_diagnostic_channel(std::make_shared<stderr_channel>()) {
m_diagnostic_channel(std::make_shared<stderr_channel>()),
m_message_channel(std::make_shared<output_channel_message_stream>(m_options, m_regular_channel)) {
}
io_state::io_state(io_state const & ios, std::shared_ptr<output_channel> const & r, std::shared_ptr<output_channel> const & d):
m_options(ios.m_options),
m_formatter_factory(ios.m_formatter_factory),
m_regular_channel(r),
m_diagnostic_channel(d) {
m_diagnostic_channel(d),
m_message_channel(ios.m_message_channel) {
}
io_state::io_state(io_state const & ios, options const & o):
m_options(o),
m_formatter_factory(ios.m_formatter_factory),
m_regular_channel(ios.m_regular_channel),
m_diagnostic_channel(ios.m_diagnostic_channel) {
m_diagnostic_channel(ios.m_diagnostic_channel),
m_message_channel(ios.m_message_channel) {
}
io_state::~io_state() {}

View file

@ -6,6 +6,7 @@ Author: Leonardo de Moura
*/
#pragma once
#include "util/output_channel.h"
#include "library/messages.h"
#include "util/sexpr/options.h"
#include "kernel/expr.h"
@ -22,6 +23,7 @@ class io_state {
formatter_factory m_formatter_factory;
std::shared_ptr<output_channel> m_regular_channel;
std::shared_ptr<output_channel> m_diagnostic_channel;
std::shared_ptr<message_stream> m_message_channel;
public:
io_state();
io_state(formatter_factory const & fmtf);
@ -32,13 +34,18 @@ public:
options const & get_options() const { return m_options; }
formatter_factory const & get_formatter_factory() const { return m_formatter_factory; }
std::shared_ptr<message_stream> const & get_message_channel_ptr() const { return m_message_channel; }
std::shared_ptr<output_channel> const & get_regular_channel_ptr() const { return m_regular_channel; }
std::shared_ptr<output_channel> const & get_diagnostic_channel_ptr() const { return m_diagnostic_channel; }
message_stream & get_message_channel() const { return *m_message_channel; }
output_channel & get_regular_channel() const { return *m_regular_channel; }
output_channel & get_diagnostic_channel() const { return *m_diagnostic_channel; }
std::ostream & get_regular_stream() const { return m_regular_channel->get_stream(); }
std::ostream & get_diagnostic_stream() const { return m_diagnostic_channel->get_stream(); }
void report(message const & msg) const { if (m_message_channel) m_message_channel->report(msg); }
void set_message_channel(std::shared_ptr<message_stream> const & out) { m_message_channel = out; }
void set_regular_channel(std::shared_ptr<output_channel> const & out);
void set_diagnostic_channel(std::shared_ptr<output_channel> const & out);
void set_options(options const & opts);
@ -47,6 +54,7 @@ public:
set_options(get_options().update(n, v));
}
};
/** \brief Return a dummy io_state that is meant to be used in contexts that require an io_state, but it is not really used */
io_state const & get_dummy_ios();

View file

@ -19,13 +19,16 @@ protected:
environment m_env;
formatter m_formatter;
std::shared_ptr<output_channel> m_stream;
public:
io_state_stream(environment const & env, formatter const & fmt, std::shared_ptr<output_channel> const & s):
m_env(env), m_formatter(fmt), m_stream(s) {}
public:
io_state_stream(environment const & env, io_state const & ios, abstract_type_context & ctx, bool regular = true):
io_state_stream(environment const & env, io_state const & ios, abstract_type_context & ctx, std::shared_ptr<output_channel> const & stream):
m_env(env), m_formatter(ios.get_formatter_factory()(env, ios.get_options(), ctx)),
m_stream(regular ? ios.get_regular_channel_ptr() : ios.get_diagnostic_channel_ptr()) {}
m_stream(stream) {}
io_state_stream(environment const & env, io_state const & ios, abstract_type_context & ctx, bool regular = true):
io_state_stream(env, ios, ctx, regular ? ios.get_regular_channel_ptr() : ios.get_diagnostic_channel_ptr()) {}
std::ostream & get_stream() const { return m_stream->get_stream(); }
std::shared_ptr<output_channel> get_channel() const { return m_stream; }
void flush() { get_stream().flush(); }
formatter const & get_formatter() const { return m_formatter; }
options get_options() const { return m_formatter.get_options(); }

View file

@ -0,0 +1,55 @@
/*
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Gabriel Ebner
*/
#include "library/message_builder.h"
#include "library/type_context.h"
#include <string>
namespace lean {
message_builder::message_builder(pos_info_provider const * provider,
std::shared_ptr<abstract_type_context> const & tc,
environment const & env, io_state const & ios,
std::string const & file_name, const pos_info & pos,
message_severity severity) :
m_pos_info_provider(provider), m_ios(ios), m_tc(tc),
m_file_name(file_name), m_pos(pos), m_severity(severity),
m_caption(), m_text(std::make_shared<string_output_channel>()),
m_text_stream(env, ios.get_formatter_factory()(env, ios.get_options(), *tc), m_text) {}
message_builder::message_builder(environment const & env, io_state const & ios,
std::string const & file_name, pos_info const & pos,
message_severity severity) :
message_builder(nullptr, std::make_shared<type_context>(env, ios.get_options()),
env, ios, file_name, pos, severity) {}
message message_builder::build() {
auto text = m_text->str();
if (!text.empty() && *text.rbegin() == '\n')
text = text.substr(0, text.size() - 1);
return message(m_file_name, m_pos, m_severity, m_caption, text);
}
message_builder & message_builder::set_exception(throwable const & ex) {
if (auto ext_ex = dynamic_cast<ext_exception const *>(&ex)) {
if (m_pos_info_provider && ext_ex->get_main_expr()) {
if (auto main_pos = m_pos_info_provider->get_pos_info(*ext_ex->get_main_expr()))
m_pos = *main_pos;
}
*this << *ext_ex;
} else if (auto f_ex = dynamic_cast<formatted_exception const *>(&ex)) {
if (m_pos_info_provider && f_ex->get_main_expr()) {
if (auto main_pos = m_pos_info_provider->get_pos_info(*f_ex->get_main_expr()))
m_pos = *main_pos;
}
*this << f_ex->pp();
} else {
*this << ex.what();
}
return *this;
}
}

View file

@ -0,0 +1,55 @@
/*
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Gabriel Ebner
*/
#pragma once
#include <string>
#include "kernel/pos_info_provider.h"
#include "util/output_channel.h"
#include "util/exception.h"
#include "library/io_state_stream.h"
namespace lean {
/** Buider for a message object. Automatically reports the message on destruction. */
class message_builder {
pos_info_provider const * m_pos_info_provider;
io_state const & m_ios;
std::shared_ptr<abstract_type_context> m_tc;
std::string m_file_name;
pos_info m_pos;
message_severity m_severity;
std::string m_caption;
std::shared_ptr<string_output_channel> m_text;
io_state_stream m_text_stream;
public:
message_builder(pos_info_provider const * provider,
std::shared_ptr<abstract_type_context> const & tc,
environment const & env, io_state const & ios,
std::string const & file_name, pos_info const & pos,
message_severity severity);
message_builder(environment const & env, io_state const & ios,
std::string const & file_name, pos_info const & pos,
message_severity severity);
message build();
void report() { m_ios.report(build()); }
message_builder & set_file_name(std::string const & file_name) { m_file_name = file_name; return *this; }
message_builder & set_pos(pos_info const & pos) { m_pos = pos; return *this; }
message_builder & set_severity(message_severity severity) { m_severity = severity; return *this; }
message_builder & set_caption(std::string const & caption) { m_caption = caption; return *this; }
formatter const & get_formatter() const { return m_text_stream.get_formatter(); }
io_state_stream & get_text_stream() { return m_text_stream; }
template <typename T>
message_builder & operator<<(T const & t) { m_text_stream << t; return *this; }
message_builder & set_exception(throwable const & ex);
};
}

41
src/library/messages.cpp Normal file
View file

@ -0,0 +1,41 @@
/*
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Gabriel Ebner
*/
#include "library/messages.h"
#include "library/flycheck.h"
namespace lean {
message::message(parser_exception const & ex) :
message(ex.get_file_name(), pos_info(ex.get_line(), ex.get_pos()),
ERROR, ex.get_msg()) {}
static char const * flycheck_kind_of_severity(message_severity severity) {
switch (severity) {
case INFORMATION: return "INFORMATION";
case WARNING: return "WARNING";
case ERROR: return "ERROR";
default: lean_unreachable();
}
}
void output_channel_message_stream::report(message const & msg) {
flycheck_scope flycheck(m_out->get_stream(), m_options, flycheck_kind_of_severity(msg.get_severity()));
if (flycheck.enabled() || msg.get_severity() != INFORMATION) {
m_out->get_stream() << msg.get_file_name()
<< ":" << msg.get_pos().first << ":" << msg.get_pos().second << ": ";
switch (msg.get_severity()) {
case INFORMATION: break;
case WARNING: m_out->get_stream() << "warning: "; break;
case ERROR: m_out->get_stream() << "error: "; break;
}
if (!msg.get_caption().empty())
m_out->get_stream() << msg.get_caption() << ":\n";
}
m_out->get_stream() << msg.get_text() << "\n";
}
}

58
src/library/messages.h Normal file
View file

@ -0,0 +1,58 @@
/*
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Gabriel Ebner
*/
#pragma once
#include <string>
#include "kernel/pos_info_provider.h"
#include "util/output_channel.h"
#include "util/exception.h"
namespace lean {
enum message_severity { INFORMATION, WARNING, ERROR };
class message {
std::string m_file_name;
pos_info m_pos;
message_severity m_severity;
std::string m_caption, m_text;
public:
message(std::string const & file_name, pos_info const & pos,
message_severity severity, std::string const & caption, std::string const & text) :
m_file_name(file_name), m_pos(pos),
m_severity(severity), m_caption(caption), m_text(text) {}
message(std::string const & file_name, pos_info const & pos,
message_severity severity, std::string const & text) :
message(file_name, pos, severity, std::string(), text) {}
message(std::string const & file_name, pos_info const & pos,
message_severity severity) :
message(file_name, pos, severity, std::string()) {}
message(parser_exception const & ex);
std::string get_file_name() const { return m_file_name; }
pos_info get_pos() const { return m_pos; }
message_severity get_severity() const { return m_severity; }
std::string get_caption() const { return m_caption; }
std::string get_text() const { return m_text; }
};
class message_stream {
public:
virtual ~message_stream() {}
virtual void report(message const & msg) = 0;
};
class output_channel_message_stream : public message_stream {
options m_options;
std::shared_ptr<output_channel> m_out;
public:
output_channel_message_stream(options const & opts, std::shared_ptr<output_channel> const & out) :
m_options(opts), m_out(out) {}
~output_channel_message_stream() {}
void report(message const & msg) override;
};
}

View file

@ -8,7 +8,6 @@ Author: Leonardo de Moura
#include "library/module.h"
#include "library/standard_kernel.h"
#include "library/type_context.h"
#include "library/error_handling.h"
#include "frontends/lean/pp.h"
#include "frontends/lean/parser.h"
#include "init/init.h"
@ -36,10 +35,7 @@ public:
bool keep_proofs = false;
env = import_modules(env, base, 1, &mod, num_threads, keep_proofs, ios);
} catch (lean::exception & ex) {
simple_pos_info_provider pp("import_module");
type_context tc(env, ios.get_options());
auto out = diagnostic(env, ios, tc);
lean::display_error(out, &pp, ex);
lean::message_builder(env, ios, "import_module", lean::pos_info(1, 1), lean::ERROR).set_exception(ex).report();
return 1;
}
return 0;
@ -54,11 +50,8 @@ public:
ok = false;
}
} catch (lean::exception & ex) {
simple_pos_info_provider pp(input_filename.c_str());
lean::message_builder(env, ios, input_filename, lean::pos_info(1, 1), lean::ERROR).set_exception(ex).report();
ok = false;
type_context tc(env, ios.get_options());
auto out = diagnostic(env, ios, tc);
lean::display_error(out, &pp, ex);
}
return ok ? 0 : 1;
}

View file

@ -32,7 +32,7 @@ Author: Leonardo de Moura
#include "library/io_state_stream.h"
#include "library/definition_cache.h"
#include "library/export.h"
#include "library/error_handling.h"
#include "library/message_builder.h"
#include "frontends/lean/parser.h"
#include "frontends/lean/pp.h"
#include "frontends/lean/dependencies.h"
@ -360,9 +360,10 @@ int main(int argc, char ** argv) {
} catch (lean::exception & ex) {
ok = false;
type_context tc(env, ios.get_options());
auto out = diagnostic(env, ios, tc);
simple_pos_info_provider pp(argv[i]);
lean::display_error(out, &pp, ex);
lean::message_builder(&pp, std::make_shared<type_context>(env, ios.get_options()),
env, ios, argv[i], pos_info(1, 1), lean::ERROR)
.set_exception(ex).report();
}
}
return ok ? 0 : 1;
@ -381,16 +382,11 @@ int main(int argc, char ** argv) {
cache.load(in);
} catch (lean::throwable & ex) {
cache_ptr = nullptr;
// I'm using flycheck_error instead off flycheck_warning because
// the :error-patterns at lean-flycheck.el do not work after
// I add a rule for FLYCHECK_WARNING.
// Same for display_error_pos vs display_warning_pos.
lean::flycheck_error warn(ios);
if (optind < argc)
display_error_pos(ios.get_regular_stream(), ios.get_options(), argv[optind], 1, 0);
ios.get_regular_stream()
<< "failed to load cache file '" << cache_name << "', "
<< ex.what() << ". cache is going to be ignored\n";
auto out = lean::message_builder(env, ios, argv[optind], lean::pos_info(1, 1), lean::WARNING);
out << "failed to load cache file '" << cache_name << "'\n";
out.set_exception(ex);
out << "cache is going to be ignored";
out.report();
}
}
try {
@ -405,11 +401,8 @@ int main(int argc, char ** argv) {
ok = false;
}
} catch (lean::exception & ex) {
simple_pos_info_provider pp(argv[i]);
ok = false;
type_context tc(env, ios.get_options());
auto out = diagnostic(env, ios, tc);
lean::display_error(out, &pp, ex);
lean::message_builder(env, ios, argv[i], lean::pos_info(1, 1), lean::ERROR).set_exception(ex).report();
}
}
if (save_cache) {
@ -434,9 +427,7 @@ int main(int argc, char ** argv) {
}
return ok ? 0 : 1;
} catch (lean::throwable & ex) {
type_context tc(env, ios.get_options());
auto out = diagnostic(env, ios, tc);
lean::display_error(out, nullptr, ex);
lean::message_builder(env, ios, "<unknown>", lean::pos_info(1, 1), lean::ERROR).set_exception(ex).report();
} catch (std::bad_alloc & ex) {
std::cerr << "out of memory" << std::endl;
return 1;

View file

@ -54,6 +54,7 @@ public:
unsigned get_line() const { return m_line; }
unsigned get_pos() const { return m_pos; }
std::string const & get_file_name() const { return m_fname; }
std::string const & get_msg() const { return m_msg; }
virtual throwable * clone() const { return new parser_exception(m_msg, m_fname.c_str(), m_line, m_pos); }
virtual void rethrow() const { throw *this; }
parser_exception update_line(unsigned line_delta) const { return parser_exception(m_msg, m_fname.c_str(), m_line + line_delta, m_pos); }

View file

@ -4,4 +4,7 @@
'\\'
aaa\
aaa'
aaa'

View file

@ -1,8 +1,8 @@
@mul.{1} nat nat.has_mul a b : nat
@add.{1} nat nat.has_add a b : nat
concrete_instance.lean:8:9:failed to generate bytecode for 'nat.semigroup'
concrete_instance.lean:8:0: warning: code generation failed, VM does not have code for 'sorry'
concrete_instance.lean:9:9:failed to generate bytecode for 'nat.add_semigroup'
concrete_instance.lean:9:0: warning: code generation failed, VM does not have code for 'sorry'
concrete_instance.lean:8:9: warning: failed to generate bytecode for 'nat.semigroup'
code generation failed, VM does not have code for 'sorry'
concrete_instance.lean:9:9: warning: failed to generate bytecode for 'nat.add_semigroup'
code generation failed, VM does not have code for 'sorry'
@mul.{1} nat nat.has_mul a b : nat
@add.{1} nat nat.has_add a b : nat

View file

@ -18,7 +18,6 @@ but is expected to have type
?m_2 ?m_3 ?m_3
Additional information:
elab_error_msgs.lean:9:0: context: 'eliminator' elaboration is not used for 'bogus_elim' because a (reliable) way to synthesize 'a', which occurs in the resulting type, was not found
elab_error_msgs.lean:13:20: error: failed to synthesize type class instance for
a b : Prop,
h : a ∧ b ∧ b,

View file

@ -1,23 +1,23 @@
g x y =?= f z
fail
unification failed
g x y =?= f z
g x y =?= f z
success
unification successful
unification hints:
(toy.g, toy.f) g #1 #0 =?= f z {}
n + 1 =?= succ n
fail
unification failed
n + 1 =?= succ n
n + 1 =?= succ n
success
unification successful
unification hints:
(add, nat.succ) #4 + 1 =?= succ #3 {#4 =?= #3}
(toy.g, toy.f) toy.g #1 #0 =?= toy.f toy.z {}
Canonical.carrier A_canonical =?= A
fail
unification failed
Canonical.carrier A_canonical =?= A
Canonical.carrier A_canonical =?= A
success
unification successful
unification hints:
(add, nat.succ) #4 + 1 =?= succ #3 {#4 =?= #3}
(toy.g, toy.f) toy.g #1 #0 =?= toy.f toy.z {}