refactor(*): error messages

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2014-01-13 16:54:21 -08:00
parent 55aa4cbfa3
commit ccb9faf065
39 changed files with 572 additions and 274 deletions

View file

@ -304,7 +304,7 @@ print(o2)
-- An error is raised if the option is not known. -- An error is raised if the option is not known.
local ok, ex = pcall(function() options({"pp", "foo"}, true) end) local ok, ex = pcall(function() options({"pp", "foo"}, true) end)
assert(not ok) assert(not ok)
assert(ex:what() == "unknown option 'pp::foo'") assert(ex:what():find("unknown option 'pp::foo'"))
``` ```
Options objects are non-mutable values. The method `update` returns a new Options objects are non-mutable values. The method `update` returns a new

View file

@ -223,6 +223,8 @@ add_subdirectory(library/elaborator)
set(LEAN_LIBS ${LEAN_LIBS} elaborator) set(LEAN_LIBS ${LEAN_LIBS} elaborator)
add_subdirectory(library/tactic) add_subdirectory(library/tactic)
set(LEAN_LIBS ${LEAN_LIBS} tactic) set(LEAN_LIBS ${LEAN_LIBS} tactic)
add_subdirectory(library/error_handling)
set(LEAN_LIBS ${LEAN_LIBS} error_handling)
add_subdirectory(frontends/lean) add_subdirectory(frontends/lean)
set(LEAN_LIBS ${LEAN_LIBS} lean_frontend) set(LEAN_LIBS ${LEAN_LIBS} lean_frontend)
add_subdirectory(frontends/lua) add_subdirectory(frontends/lua)

View file

@ -14,6 +14,7 @@ namespace lean {
parser::parser(environment const & env, io_state const & ios, std::istream & in, char const * strm_name, script_state * S, bool use_exceptions, bool interactive) { parser::parser(environment const & env, io_state const & ios, std::istream & in, char const * strm_name, script_state * S, bool use_exceptions, bool interactive) {
parser_imp::show_prompt(interactive, ios); parser_imp::show_prompt(interactive, ios);
m_ptr.reset(new parser_imp(env, ios, in, strm_name, S, use_exceptions, interactive)); m_ptr.reset(new parser_imp(env, ios, in, strm_name, S, use_exceptions, interactive));
m_ptr->m_this = m_ptr;
} }
parser::~parser() { parser::~parser() {

View file

@ -16,7 +16,7 @@ class parser_imp;
/** \brief Functional object for parsing commands and expressions */ /** \brief Functional object for parsing commands and expressions */
class parser { class parser {
private: private:
std::unique_ptr<parser_imp> m_ptr; std::shared_ptr<parser_imp> m_ptr;
public: public:
parser(environment const & env, io_state const & st, std::istream & in, char const * strm_name, script_state * S, bool use_exceptions = true, bool interactive = false); parser(environment const & env, io_state const & st, std::istream & in, char const * strm_name, script_state * S, bool use_exceptions = true, bool interactive = false);
~parser(); ~parser();

View file

@ -83,7 +83,7 @@ void parser_imp::register_implicit_arguments(name const & n, parameter_buffer &
/** \brief Throw an exception if \c e contains a metavariable */ /** \brief Throw an exception if \c e contains a metavariable */
void parser_imp::check_no_metavar(expr const & e, metavar_env const & menv, char const * msg) { void parser_imp::check_no_metavar(expr const & e, metavar_env const &, char const * msg) {
if (has_metavar(e)) if (has_metavar(e))
throw unsolved_metavar_exception(msg, e); throw unsolved_metavar_exception(msg, e);
} }

View file

@ -5,10 +5,10 @@ Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura Author: Leonardo de Moura
*/ */
#include <utility> #include <utility>
#include "kernel/kernel_exception.h"
#include "kernel/for_each_fn.h" #include "kernel/for_each_fn.h"
#include "library/io_state_stream.h" #include "library/io_state_stream.h"
#include "library/elaborator/elaborator_justification.h" #include "library/parser_nested_exception.h"
#include "library/error_handling/error_handling.h"
#include "frontends/lean/parser_imp.h" #include "frontends/lean/parser_imp.h"
namespace lean { namespace lean {
@ -21,94 +21,21 @@ void parser_imp::display_error_pos(unsigned line, unsigned pos) {
void parser_imp::display_error_pos(pos_info const & p) { display_error_pos(p.first, p.second); } void parser_imp::display_error_pos(pos_info const & p) { display_error_pos(p.first, p.second); }
void parser_imp::display_error_pos(optional<expr> const & e) {
if (e) {
auto it = m_expr_pos_info.find(*e);
if (it == m_expr_pos_info.end())
return display_error_pos(m_last_cmd_pos);
else
return display_error_pos(it->second);
} else {
return display_error_pos(m_last_cmd_pos);
}
}
void parser_imp::display_error(char const * msg, unsigned line, unsigned pos) { void parser_imp::display_error(char const * msg, unsigned line, unsigned pos) {
display_error_pos(line, pos); display_error_pos(line, pos);
regular(m_io_state) << " " << msg << endl; regular(m_io_state) << " " << msg << endl;
} }
void parser_imp::display_error(char const * msg) {
display_error(msg, m_scanner.get_line(), m_scanner.get_pos());
}
void parser_imp::display_error(kernel_exception const & ex) {
optional<expr> main_expr = ex.get_main_expr();
if (main_expr)
display_error_pos(some_expr(m_elaborator.get_original(*main_expr)));
else
display_error_pos(main_expr);
regular(m_io_state) << " " << ex << endl;
}
void parser_imp::display_error(unsolved_metavar_exception const & ex) {
display_error_pos(some_expr(m_elaborator.get_original(ex.get_expr())));
formatter fmt = m_io_state.get_formatter();
options opts = m_io_state.get_options();
unsigned indent = get_pp_indent(opts);
format r = nest(indent, compose(line(), fmt(ex.get_expr(), opts)));
regular(m_io_state) << " " << ex.what() << mk_pair(r, opts) << endl;
name_set already_displayed;
for_each(ex.get_expr(), [&](expr const & e, unsigned) -> bool {
if (is_metavar(e)) {
name const & m = metavar_name(e);
if (already_displayed.find(m) == already_displayed.end()) {
already_displayed.insert(m);
for (unsigned i = 0; i < indent; i++) regular(m_io_state) << " ";
display_error_pos(some_expr(m_elaborator.get_original(e)));
regular(m_io_state) << " unsolved metavar " << m << endl;
}
}
return true;
});
}
std::pair<unsigned, unsigned> parser_imp::lean_pos_info_provider::get_pos_info(expr const & e) const { std::pair<unsigned, unsigned> parser_imp::lean_pos_info_provider::get_pos_info(expr const & e) const {
expr const & o = m_ref.m_elaborator.get_original(e); expr const & o = m_parser->m_elaborator.get_original(e);
auto it = m_ref.m_expr_pos_info.find(o); auto it = m_parser->m_expr_pos_info.find(o);
if (it == m_ref.m_expr_pos_info.end()) if (it == m_parser->m_expr_pos_info.end())
throw exception("position is not available"); // information is not available return m_pos;
return it->second; return it->second;
} }
char const * parser_imp::lean_pos_info_provider::get_file_name(expr const & ) const { char const * parser_imp::lean_pos_info_provider::get_file_name() const {
return m_ref.m_strm_name.c_str(); return m_parser->m_strm_name.c_str();
}
void parser_imp::display_error(elaborator_exception const & ex) {
formatter fmt = m_io_state.get_formatter();
options opts = m_io_state.get_options();
lean_pos_info_provider pos_provider(*this);
auto j = ex.get_justification();
j = remove_detail(j);
regular(m_io_state) << mk_pair(j.pp(fmt, opts, &pos_provider, true), opts) << endl;
}
void parser_imp::display_error(script_exception const & ex) {
switch (ex.get_source()) {
case script_exception::source::String:
display_error_pos(ex.get_line() + m_last_script_pos.first - 1, static_cast<unsigned>(-1));
regular(m_io_state) << " executing script," << ex.get_msg() << endl;
break;
case script_exception::source::File:
display_error_pos(m_last_script_pos);
regular(m_io_state) << " executing external script (" << ex.get_filename() << ":" << ex.get_line() << ")," << ex.get_msg() << endl;
break;
case script_exception::source::Unknown:
display_error_pos(m_last_script_pos);
regular(m_io_state) << " executing script, exact error position is not available, " << ex.what() << endl;
break;
}
} }
void parser_imp::display_error(tactic_cmd_error const & ex) { void parser_imp::display_error(tactic_cmd_error const & ex) {
@ -116,13 +43,21 @@ void parser_imp::display_error(tactic_cmd_error const & ex) {
display_proof_state(ex.m_state); display_proof_state(ex.m_state);
} }
#define CATCH_CORE(ShowError, ThrowError) \ void parser_imp::display_error(exception const & ex) {
m_found_errors = true; \ lean_pos_info_provider pos_provider(m_this.lock(), m_last_cmd_pos);
if (m_show_errors) { ShowError ; } \ ::lean::display_error(m_io_state, &pos_provider, ex);
sync(); \ }
if (m_use_exceptions) { ThrowError ; }
#define CATCH(ShowError) CATCH_CORE(ShowError, throw;) void parser_imp::display_error(script_exception const & ex) {
lean_pos_info_provider pos_provider(m_this.lock(), m_last_script_pos);
::lean::display_error(m_io_state, &pos_provider, ex);
}
#define CATCH(ShowError, ThrowError) \
m_found_errors = true; \
if (!m_use_exceptions && m_show_errors) { ShowError ; } \
sync(); \
if (m_use_exceptions) { ThrowError ; }
/** /**
\brief Execute the given function \c f, and handle exceptions occurring \brief Execute the given function \c f, and handle exceptions occurring
@ -133,21 +68,14 @@ void parser_imp::protected_call(std::function<void()> && f, std::function<void()
try { try {
f(); f();
} catch (tactic_cmd_error & ex) { } catch (tactic_cmd_error & ex) {
CATCH(display_error(ex)); CATCH(display_error(ex),
throw parser_exception(ex.what(), m_strm_name.c_str(), ex.m_pos.first, ex.m_pos.second));
} catch (parser_exception & ex) { } catch (parser_exception & ex) {
CATCH(regular(m_io_state) << ex.what() << endl;); CATCH(regular(m_io_state) << ex.what() << endl,
throw);
} catch (parser_error & ex) { } catch (parser_error & ex) {
CATCH_CORE(display_error(ex.what(), ex.m_pos.first, ex.m_pos.second), CATCH(display_error(ex.what(), ex.m_pos.first, ex.m_pos.second),
throw parser_exception(ex.what(), m_strm_name.c_str(), ex.m_pos.first, ex.m_pos.second)); throw parser_exception(ex.what(), m_strm_name.c_str(), ex.m_pos.first, ex.m_pos.second));
} catch (kernel_exception & ex) {
CATCH(display_error(ex));
} catch (elaborator_exception & ex) {
CATCH(display_error(ex));
} catch (unsolved_metavar_exception & ex) {
CATCH(display_error(ex));
} catch (script_exception & ex) {
reset_interrupt();
CATCH(display_error(ex));
} catch (interrupted & ex) { } catch (interrupted & ex) {
reset_interrupt(); reset_interrupt();
if (m_verbose) if (m_verbose)
@ -155,8 +83,16 @@ void parser_imp::protected_call(std::function<void()> && f, std::function<void()
sync(); sync();
if (m_use_exceptions) if (m_use_exceptions)
throw; throw;
} catch (script_exception & ex) {
reset_interrupt();
CATCH(display_error(ex),
throw parser_nested_exception(std::shared_ptr<exception>(ex.clone()),
std::shared_ptr<pos_info_provider>(new lean_pos_info_provider(m_this.lock(), m_last_script_pos))));
} catch (exception & ex) { } catch (exception & ex) {
CATCH(display_error(ex.what());); reset_interrupt();
CATCH(display_error(ex),
throw parser_nested_exception(std::shared_ptr<exception>(ex.clone()),
std::shared_ptr<pos_info_provider>(new lean_pos_info_provider(m_this.lock(), m_last_cmd_pos))));
} }
} }
} }

View file

@ -8,6 +8,7 @@ Author: Leonardo de Moura
#include <string> #include <string>
#include <vector> #include <vector>
#include "library/io_state_stream.h" #include "library/io_state_stream.h"
#include "library/parser_nested_exception.h"
#include "frontends/lean/parser_imp.h" #include "frontends/lean/parser_imp.h"
#include "frontends/lean/parser_macros.h" #include "frontends/lean/parser_macros.h"
#include "frontends/lean/parser_calc.h" #include "frontends/lean/parser_calc.h"
@ -217,6 +218,9 @@ expr parser_imp::parse_expr_main() {
return p.first; return p.first;
} catch (parser_error & ex) { } catch (parser_error & ex) {
throw parser_exception(ex.what(), m_strm_name.c_str(), ex.m_pos.first, ex.m_pos.second); throw parser_exception(ex.what(), m_strm_name.c_str(), ex.m_pos.first, ex.m_pos.second);
} catch (exception & ex) {
throw parser_nested_exception(std::shared_ptr<exception>(ex.clone()),
std::shared_ptr<pos_info_provider>(new lean_pos_info_provider(m_this.lock(), m_last_cmd_pos)));
} }
} }
}; };

View file

@ -34,7 +34,7 @@ bool get_parser_show_errors(options const & opts);
/** \brief Auxiliary object that stores a reference to the parser object inside the Lua State */ /** \brief Auxiliary object that stores a reference to the parser object inside the Lua State */
struct set_parser { struct set_parser {
script_state * m_state; script_state::weak_ref m_state;
parser_imp * m_prev; parser_imp * m_prev;
set_parser(script_state * S, parser_imp * ptr); set_parser(script_state * S, parser_imp * ptr);
~set_parser(); ~set_parser();
@ -57,29 +57,30 @@ class parser_imp {
typedef expr_map<pos_info> expr_pos_info; typedef expr_map<pos_info> expr_pos_info;
typedef expr_map<tactic> tactic_hints; // a mapping from placeholder to tactic typedef expr_map<tactic> tactic_hints; // a mapping from placeholder to tactic
typedef scoped_map<name, expr, name_hash, name_eq> using_decls; typedef scoped_map<name, expr, name_hash, name_eq> using_decls;
environment m_env;
io_state m_io_state;
scanner m_scanner;
std::string m_strm_name; // input stream name
frontend_elaborator m_elaborator;
macros const * m_expr_macros;
macros const * m_cmd_macros;
macros const * m_tactic_macros;
scanner::token m_curr;
bool m_use_exceptions;
bool m_interactive;
bool m_found_errors;
local_decls m_local_decls;
unsigned m_num_local_decls;
expr_pos_info m_expr_pos_info;
pos_info m_last_cmd_pos;
pos_info m_last_script_pos;
tactic_hints m_tactic_hints;
using_decls m_using_decls;
std::vector<name> m_namespace_prefixes;
enum class scope_kind { Scope, Namespace }; enum class scope_kind { Scope, Namespace };
std::vector<scope_kind> m_scope_kinds;
std::weak_ptr<parser_imp> m_this;
environment m_env;
io_state m_io_state;
scanner m_scanner;
std::string m_strm_name; // input stream name
frontend_elaborator m_elaborator;
macros const * m_expr_macros;
macros const * m_cmd_macros;
macros const * m_tactic_macros;
scanner::token m_curr;
bool m_use_exceptions;
bool m_interactive;
bool m_found_errors;
local_decls m_local_decls;
unsigned m_num_local_decls;
expr_pos_info m_expr_pos_info;
pos_info m_last_cmd_pos;
pos_info m_last_script_pos;
tactic_hints m_tactic_hints;
using_decls m_using_decls;
std::vector<name> m_namespace_prefixes;
std::vector<scope_kind> m_scope_kinds;
std::unique_ptr<calc_proof_parser> m_calc_proof_parser; std::unique_ptr<calc_proof_parser> m_calc_proof_parser;
@ -202,22 +203,20 @@ public:
private: private:
void display_error_pos(unsigned line, unsigned pos); void display_error_pos(unsigned line, unsigned pos);
void display_error_pos(pos_info const & p); void display_error_pos(pos_info const & p);
void display_error_pos(optional<expr> const & e);
void display_error(char const * msg, unsigned line, unsigned pos); void display_error(char const * msg, unsigned line, unsigned pos);
void display_error(char const * msg);
void display_error(kernel_exception const & ex);
void display_error(unsolved_metavar_exception const & ex);
struct lean_pos_info_provider : public pos_info_provider { struct lean_pos_info_provider : public pos_info_provider {
parser_imp const & m_ref; std::shared_ptr<parser_imp> m_parser;
lean_pos_info_provider(parser_imp const & r):m_ref(r) {} pos_info m_pos;
lean_pos_info_provider(std::shared_ptr<parser_imp> const & p, pos_info const & pos):m_parser(p), m_pos(pos) {}
virtual std::pair<unsigned, unsigned> get_pos_info(expr const & e) const; virtual std::pair<unsigned, unsigned> get_pos_info(expr const & e) const;
virtual char const * get_file_name(expr const & e) const; virtual std::pair<unsigned, unsigned> get_some_pos() const { return m_pos; }
virtual char const * get_file_name() const;
}; };
void display_error(elaborator_exception const & ex);
void display_error(script_exception const & ex);
void display_error(tactic_cmd_error const & ex); void display_error(tactic_cmd_error const & ex);
void display_error(script_exception const & ex);
void display_error(exception const & ex);
public: public:
void protected_call(std::function<void()> && f, std::function<void()> && sync); void protected_call(std::function<void()> && f, std::function<void()> && sync);
/*@}*/ /*@}*/

View file

@ -24,9 +24,9 @@ parser_imp * get_parser(lua_State * L) {
} }
set_parser::set_parser(script_state * S, parser_imp * ptr) { set_parser::set_parser(script_state * S, parser_imp * ptr) {
m_state = S; if (S) {
if (m_state) { m_state = S->to_weak_ref();
m_state->apply([&](lua_State * L) { S->apply([&](lua_State * L) {
m_prev = get_parser(L); m_prev = get_parser(L);
lua_pushlightuserdata(L, static_cast<void *>(&g_set_parser_key)); lua_pushlightuserdata(L, static_cast<void *>(&g_set_parser_key));
lua_pushlightuserdata(L, ptr); lua_pushlightuserdata(L, ptr);
@ -35,8 +35,9 @@ set_parser::set_parser(script_state * S, parser_imp * ptr) {
} }
} }
set_parser::~set_parser() { set_parser::~set_parser() {
if (m_state) { if (!m_state.expired()) {
m_state->apply([&](lua_State * L) { script_state S(m_state);
S.apply([&](lua_State * L) {
lua_pushlightuserdata(L, static_cast<void *>(&g_set_parser_key)); lua_pushlightuserdata(L, static_cast<void *>(&g_set_parser_key));
lua_pushlightuserdata(L, m_prev); lua_pushlightuserdata(L, m_prev);
lua_settable(L, LUA_REGISTRYINDEX); lua_settable(L, LUA_REGISTRYINDEX);

View file

@ -101,9 +101,9 @@ bool shell::operator()() {
#ifdef LEAN_USE_READLINE #ifdef LEAN_USE_READLINE
readline_streambuf buf; readline_streambuf buf;
std::istream is(&buf); std::istream is(&buf);
parser p(m_env, m_io_state, is, "stdin", m_script_state, false, true); parser p(m_env, m_io_state, is, "[stdin]", m_script_state, false, true);
#else #else
parser p(m_env, m_io_state, std::cin, "stdin", m_script_state, false, true); parser p(m_env, m_io_state, std::cin, "[stdin]", m_script_state, false, true);
#endif #endif
return p(); return p();
} }

View file

@ -7,13 +7,13 @@ Author: Leonardo de Moura
#include "kernel/pos_info_provider.h" #include "kernel/pos_info_provider.h"
namespace lean { namespace lean {
char const * pos_info_provider::get_file_name(expr const & ) const { char const * pos_info_provider::get_file_name() const {
return "unknown"; return "unknown";
} }
format pos_info_provider::pp(expr const & e) const { format pos_info_provider::pp(expr const & e) const {
try { try {
auto p = get_pos_info(e); auto p = get_pos_info(e);
return format{format(get_file_name(e)), colon(), format(p.first), colon(), format(p.second), colon()}; return format{format(get_file_name()), colon(), format(p.first), colon(), format(p.second), colon()};
} catch (exception &) { } catch (exception &) {
return format(); return format();
} }

View file

@ -4,6 +4,7 @@ Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura Author: Leonardo de Moura
*/ */
#pragma once
#include <utility> #include <utility>
#include "util/sexpr/format.h" #include "util/sexpr/format.h"
#include "kernel/expr.h" #include "kernel/expr.h"
@ -20,7 +21,9 @@ public:
Throws an exception if the given expression does not have this kind of information associated with it. Throws an exception if the given expression does not have this kind of information associated with it.
*/ */
virtual std::pair<unsigned, unsigned> get_pos_info(expr const & e) const = 0; virtual std::pair<unsigned, unsigned> get_pos_info(expr const & e) const = 0;
virtual char const * get_file_name(expr const & e) const; virtual char const * get_file_name() const;
virtual std::pair<unsigned, unsigned> get_some_pos() const = 0;
unsigned get_line(expr const & e) const { return get_pos_info(e).first; } unsigned get_line(expr const & e) const { return get_pos_info(e).first; }
unsigned get_pos(expr const & e) const { return get_pos_info(e).second; } unsigned get_pos(expr const & e) const { return get_pos_info(e).second; }
/** /**

View file

@ -0,0 +1,2 @@
add_library(error_handling error_handling.cpp)
target_link_libraries(error_handling ${LEAN_LIBS})

View file

@ -0,0 +1,183 @@
/*
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/script_exception.h"
#include "util/name_set.h"
#include "kernel/kernel_exception.h"
#include "kernel/for_each_fn.h"
#include "library/io_state_stream.h"
#include "library/elaborator/elaborator_justification.h"
#include "library/elaborator/elaborator_exception.h"
#include "library/parser_nested_exception.h"
#include "library/unsolved_metavar_exception.h"
namespace lean {
void display_error_pos(io_state const & ios, char const * strm_name, unsigned line, unsigned pos) {
regular(ios) << strm_name << ":" << line << ":";
if (pos != static_cast<unsigned>(-1))
regular(ios) << pos << ":";
regular(ios) << " error:";
}
void display_error_pos(io_state const & ios, pos_info_provider const * p, expr const & e) {
if (p) {
auto pos = p->get_pos_info(e);
display_error_pos(ios, p->get_file_name(), pos.first, pos.second);
} else {
regular(ios) << "error:";
}
}
void display_error_pos(io_state 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 {
regular(ios) << "error:";
}
}
void display_error(io_state const & ios, pos_info_provider const * p, exception const & ex);
static void display_error(io_state const & ios, pos_info_provider const * p, kernel_exception const & ex) {
display_error_pos(ios, p, ex.get_main_expr());
regular(ios) << " " << ex << endl;
}
static void display_error(io_state const & ios, pos_info_provider const * p, elaborator_exception const & ex) {
formatter fmt = ios.get_formatter();
options opts = ios.get_options();
auto j = ex.get_justification();
j = remove_detail(j);
regular(ios) << mk_pair(j.pp(fmt, opts, p, true), opts) << endl;
}
struct delta_pos_info_provider : public pos_info_provider {
unsigned m_delta;
std::string m_file_name;
pos_info_provider const & m_provider;
delta_pos_info_provider(unsigned d, char const * fname, pos_info_provider const & p):m_delta(d), m_file_name(fname), m_provider(p) {}
virtual std::pair<unsigned, unsigned> get_pos_info(expr const & e) const {
auto r = m_provider.get_pos_info(e);
return mk_pair(r.first + m_delta, r.second);
}
virtual char const * get_file_name() const { return m_file_name.c_str(); }
virtual std::pair<unsigned, unsigned> get_some_pos() const {
auto r = m_provider.get_some_pos();
return mk_pair(r.first + m_delta, r.second);
}
};
static void display_error(io_state const & ios, pos_info_provider const * p, script_exception const & ex) {
if (p) {
char const * msg = ex.get_msg();
char const * space = msg && *msg == ' ' ? "" : " ";
switch (ex.get_source()) {
case script_exception::source::String:
display_error_pos(ios, p->get_file_name(), ex.get_line() + p->get_some_pos().first - 1, static_cast<unsigned>(-1));
regular(ios) << " executing script," << space << msg << endl;
break;
case script_exception::source::File:
display_error_pos(ios, p->get_file_name(), p->get_some_pos().first, p->get_some_pos().second);
regular(ios) << " executing external script (" << ex.get_file_name() << ":" << ex.get_line() << ")," << space << msg << endl;
break;
case script_exception::source::Unknown:
display_error_pos(ios, p->get_file_name(), p->get_some_pos().first, p->get_some_pos().second);
regular(ios) << " executing script, exact error position is not available, " << ex.what() << endl;
break;
}
} else {
regular(ios) << ex.what() << endl;
}
}
static void display_error(io_state const & ios, pos_info_provider const * p, script_nested_exception const & ex) {
switch (ex.get_source()) {
case script_exception::source::String:
if (p) {
display_error_pos(ios, p->get_file_name(), ex.get_line() + p->get_some_pos().first - 1, static_cast<unsigned>(-1));
regular(ios) << " executing script" << endl;
}
display_error(ios, nullptr, ex.get_exception());
break;
case script_exception::source::File:
if (p) {
display_error_pos(ios, p->get_file_name(), p->get_some_pos().first, p->get_some_pos().second);
regular(ios) << " executing external script (" << ex.get_file_name() << ":" << ex.get_line() << ")" << endl;
} else {
display_error_pos(ios, ex.get_file_name(), ex.get_line(), -1);
regular(ios) << " executing script" << endl;
}
display_error(ios, nullptr, ex.get_exception());
break;
case script_exception::source::Unknown:
display_error(ios, nullptr, ex.get_exception());
break;
}
}
static void display_error(io_state const & ios, pos_info_provider const *, parser_nested_exception const & ex) {
display_error(ios, &(ex.get_provider()), ex.get_exception());
}
static void display_error(io_state const & ios, pos_info_provider const *, parser_exception const & ex) {
regular(ios) << ex.what() << endl;
}
static void display_error(io_state const & ios, pos_info_provider const * p, unsolved_metavar_exception const & ex) {
display_error_pos(ios, p, ex.get_expr());
formatter fmt = ios.get_formatter();
options opts = ios.get_options();
unsigned indent = get_pp_indent(opts);
format r = nest(indent, compose(line(), fmt(ex.get_expr(), opts)));
regular(ios) << " " << ex.what() << mk_pair(r, opts) << endl;
if (p) {
name_set already_displayed;
for_each(ex.get_expr(), [&](expr const & e, unsigned) -> bool {
if (is_metavar(e)) {
name const & m = metavar_name(e);
if (already_displayed.find(m) == already_displayed.end()) {
already_displayed.insert(m);
for (unsigned i = 0; i < indent; i++) regular(ios) << " ";
display_error_pos(ios, p, e);
regular(ios) << " unsolved metavar " << m << endl;
}
}
return true;
});
}
}
void display_error(io_state const & ios, pos_info_provider const * p, exception const & ex) {
if (auto k_ex = dynamic_cast<kernel_exception const *>(&ex)) {
display_error(ios, p, *k_ex);
} else if (auto e_ex = dynamic_cast<elaborator_exception const *>(&ex)) {
display_error(ios, p, *e_ex);
} else if (auto m_ex = dynamic_cast<unsolved_metavar_exception const *>(&ex)) {
display_error(ios, p, *m_ex);
} else if (auto ls_ex = dynamic_cast<script_nested_exception const *>(&ex)) {
display_error(ios, p, *ls_ex);
} else if (auto s_ex = dynamic_cast<script_exception const *>(&ex)) {
display_error(ios, p, *s_ex);
} else if (auto n_ex = dynamic_cast<parser_nested_exception const *>(&ex)) {
display_error(ios, p, *n_ex);
} else if (auto n_ex = dynamic_cast<parser_exception const *>(&ex)) {
display_error(ios, p, *n_ex);
} else if (p) {
display_error_pos(ios, p->get_file_name(), p->get_some_pos().first, p->get_some_pos().second);
regular(ios) << " " << ex.what() << endl;
} else {
regular(ios) << "error: " << ex.what() << endl;
}
}
}

View file

@ -0,0 +1,18 @@
/*
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 "kernel/io_state.h"
namespace lean {
/**
\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 const & ios, pos_info_provider const * p, exception const & ex);
}

View file

@ -1205,11 +1205,15 @@ static const struct luaL_Reg environment_m[] = {
static char g_set_environment_key; static char g_set_environment_key;
void set_global_environment(lua_State * L, environment const & env) {
lua_pushlightuserdata(L, static_cast<void *>(&g_set_environment_key));
push_environment(L, env);
lua_settable(L, LUA_REGISTRYINDEX);
}
set_environment::set_environment(lua_State * L, environment const & env) { set_environment::set_environment(lua_State * L, environment const & env) {
m_state = L; m_state = L;
lua_pushlightuserdata(m_state, static_cast<void *>(&g_set_environment_key)); set_global_environment(L, env);
push_environment(m_state, env);
lua_settable(m_state, LUA_REGISTRYINDEX);
} }
set_environment::~set_environment() { set_environment::~set_environment() {
@ -1832,6 +1836,13 @@ void open_io_state(lua_State * L) {
static char g_set_state_key; static char g_set_state_key;
void set_global_io_state(lua_State * L, io_state & ios) {
lua_pushlightuserdata(L, static_cast<void *>(&g_set_state_key));
lua_pushlightuserdata(L, &ios);
lua_settable(L, LUA_REGISTRYINDEX);
set_global_options(L, ios.get_options());
}
set_io_state::set_io_state(lua_State * L, io_state & st) { set_io_state::set_io_state(lua_State * L, io_state & st) {
m_state = L; m_state = L;
m_prev = get_io_state(L); m_prev = get_io_state(L);

View file

@ -44,8 +44,11 @@ formatter get_global_formatter(lua_State * L);
Otherwise, we update the registry of \c L. Otherwise, we update the registry of \c L.
*/ */
void set_global_formatter(lua_State * L, formatter const & fmt); void set_global_formatter(lua_State * L, formatter const & fmt);
/** \brief Set the Lua registry of a Lua state with an environment object. */
void set_global_environment(lua_State * L, environment const & env);
/** /**
\brief Auxiliary class for setting the Lua registry of a Lua state \brief Auxiliary class for temporarily setting the Lua registry of a Lua state
with an environment object. with an environment object.
*/ */
class set_environment { class set_environment {
@ -74,6 +77,9 @@ public:
rw_shared_environment(lua_State * L, int idx); rw_shared_environment(lua_State * L, int idx);
rw_shared_environment(lua_State * L); rw_shared_environment(lua_State * L);
}; };
/** \brief Set the Lua registry of a Lua state with an io_state object. */
void set_global_io_state(lua_State * L, io_state & ios);
/** /**
\brief Auxiliary class for temporarily setting the Lua registry of a Lua state \brief Auxiliary class for temporarily setting the Lua registry of a Lua state
with a Lean io_state object. with a Lean io_state object.

View file

@ -0,0 +1,25 @@
/*
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 <memory>
#include "util/exception.h"
#include "kernel/pos_info_provider.h"
namespace lean {
/** \brief Lean exception occurred when parsing file. */
class parser_nested_exception : public exception {
std::shared_ptr<exception> m_exception;
std::shared_ptr<pos_info_provider> m_provider;
public:
parser_nested_exception(std::shared_ptr<exception> const & ex, std::shared_ptr<pos_info_provider> const & pr):exception("parser exception"), m_exception(ex), m_provider(pr) {}
virtual ~parser_nested_exception() {}
virtual exception * clone() const { return new parser_nested_exception(m_exception, m_provider); }
virtual void rethrow() const { throw *this; }
virtual char const * what() const noexcept { return m_exception->what(); }
exception const & get_exception() const { return *(m_exception.get()); }
pos_info_provider const & get_provider() const { return *(m_provider.get()); }
};
}

View file

@ -23,6 +23,7 @@ Author: Leonardo de Moura
#include "library/printer.h" #include "library/printer.h"
#include "library/kernel_bindings.h" #include "library/kernel_bindings.h"
#include "library/io_state_stream.h" #include "library/io_state_stream.h"
#include "library/error_handling/error_handling.h"
#include "frontends/lean/parser.h" #include "frontends/lean/parser.h"
#include "frontends/lean/shell.h" #include "frontends/lean/shell.h"
#include "frontends/lean/frontend.h" #include "frontends/lean/frontend.h"
@ -108,67 +109,77 @@ static struct option g_long_options[] = {
}; };
int main(int argc, char ** argv) { int main(int argc, char ** argv) {
try { lean::save_stack_info();
lean::save_stack_info(); lean::register_modules();
lean::register_modules(); bool no_kernel = false;
bool no_kernel = false; bool export_objects = false;
bool export_objects = false; bool trust_imported = false;
bool trust_imported = false; bool quiet = false;
bool quiet = false; std::string output;
std::string output; input_kind default_k = input_kind::Lean; // default
input_kind default_k = input_kind::Lean; // default while (true) {
while (true) { int c = getopt_long(argc, argv, "qtnlupgvhc:012s:012o:", g_long_options, NULL);
int c = getopt_long(argc, argv, "qtnlupgvhc:012s:012o:", g_long_options, NULL); if (c == -1)
if (c == -1) break; // end of command line
break; // end of command line switch (c) {
switch (c) { case 'v':
case 'v': display_header(std::cout);
display_header(std::cout); return 0;
return 0; case 'g':
case 'g': std::cout << g_githash << "\n";
std::cout << g_githash << "\n"; return 0;
return 0; case 'h':
case 'h': display_help(std::cout);
display_help(std::cout); return 0;
return 0; case 'l':
case 'l': default_k = input_kind::Lean;
default_k = input_kind::Lean; break;
break; case 'u':
case 'u': default_k = input_kind::Lua;
default_k = input_kind::Lua; break;
break; case 'b':
case 'b': default_k = input_kind::OLean;
default_k = input_kind::OLean; break;
break; case 'c':
case 'c': script_state::set_check_interrupt_freq(atoi(optarg));
script_state::set_check_interrupt_freq(atoi(optarg)); break;
break; case 'p':
case 'p': std::cout << lean::get_lean_path() << "\n";
std::cout << lean::get_lean_path() << "\n"; return 0;
return 0; case 's':
case 's': lean::set_thread_stack_size(atoi(optarg)*1024);
lean::set_thread_stack_size(atoi(optarg)*1024); break;
break; case 'n':
case 'n': no_kernel = true;
no_kernel = true; break;
break; case 'o':
case 'o': output = optarg;
output = optarg; export_objects = true;
export_objects = true; break;
break; case 't':
case 't': trust_imported = true;
trust_imported = true; lean::set_default_trust_imported_for_lua(true);
lean::set_default_trust_imported_for_lua(true); break;
break; case 'q':
case 'q': quiet = true;
quiet = true; break;
break; default:
default: std::cerr << "Unknown command line option\n";
std::cerr << "Unknown command line option\n"; display_help(std::cerr);
display_help(std::cerr); return 1;
return 1;
}
} }
}
environment env;
env->set_trusted_imported(trust_imported);
io_state ios = init_frontend(env, no_kernel);
if (quiet)
ios.set_option("verbose", false);
script_state S;
S.apply([&](lua_State * L) {
set_global_environment(L, env);
set_global_io_state(L, ios);
});
try {
if (optind >= argc) { if (optind >= argc) {
display_header(std::cout); display_header(std::cout);
signal(SIGINT, on_ctrl_c); signal(SIGINT, on_ctrl_c);
@ -178,12 +189,6 @@ int main(int argc, char ** argv) {
#else #else
std::cout << "Type Ctrl-D or 'Exit.' to exit or 'Help.' for help."<< std::endl; std::cout << "Type Ctrl-D or 'Exit.' to exit or 'Help.' for help."<< std::endl;
#endif #endif
environment env;
env->set_trusted_imported(trust_imported);
io_state ios = init_frontend(env, no_kernel);
if (quiet)
ios.set_option("verbose", false);
script_state S;
shell sh(env, &S); shell sh(env, &S);
int status = sh() ? 0 : 1; int status = sh() ? 0 : 1;
if (export_objects) if (export_objects)
@ -191,17 +196,10 @@ int main(int argc, char ** argv) {
return status; return status;
} else { } else {
lean_assert(default_k == input_kind::Lua); lean_assert(default_k == input_kind::Lua);
script_state S;
S.import("repl"); S.import("repl");
return 0; return 0;
} }
} else { } else {
environment env;
env->set_trusted_imported(trust_imported);
io_state ios = init_frontend(env, no_kernel);
if (quiet)
ios.set_option("verbose", false);
script_state S;
bool ok = true; bool ok = true;
for (int i = optind; i < argc; i++) { for (int i = optind; i < argc; i++) {
char const * ext = get_file_extension(argv[i]); char const * ext = get_file_extension(argv[i]);
@ -227,15 +225,9 @@ int main(int argc, char ** argv) {
} }
} else if (k == input_kind::Lua) { } else if (k == input_kind::Lua) {
try { try {
S.apply([&](lua_State * L) { S.dofile(argv[i]);
lean::set_io_state set1(L, ios);
lean::set_environment set2(L, env);
S.exec_unprotected([&]() {
S.dofile(argv[i]);
});
});
} catch (lean::exception & ex) { } catch (lean::exception & ex) {
std::cerr << ex.what() << std::endl; ::lean::display_error(ios, nullptr, ex);
ok = false; ok = false;
} }
} else { } else {
@ -246,12 +238,8 @@ int main(int argc, char ** argv) {
env->export_objects(output); env->export_objects(output);
return ok ? 0 : 1; return ok ? 0 : 1;
} }
} catch (lean::kernel_exception & ex) {
std::cerr << "Error: " << ex.pp(lean::mk_simple_formatter(), lean::options()) << "\n";
} catch (lean::parser_exception & ex) {
std::cerr << ex.what() << "\n";
} catch (lean::exception & ex) { } catch (lean::exception & ex) {
std::cerr << "Error: " << ex.what() << "\n"; ::lean::display_error(ios, nullptr, ex);
} }
return 1; return 1;
} }

View file

@ -8,6 +8,7 @@ Author: Leonardo de Moura
#include "util/lua.h" #include "util/lua.h"
#include <exception> #include <exception>
#include <string> #include <string>
#include <memory>
namespace lean { namespace lean {
class sstream; class sstream;
@ -39,9 +40,12 @@ public:
virtual char const * what() const noexcept; virtual char const * what() const noexcept;
unsigned get_line() const { return m_line; } unsigned get_line() const { return m_line; }
unsigned get_pos() const { return m_pos; } unsigned get_pos() const { return m_pos; }
std::string const & get_file_name() const { return m_fname; }
virtual exception * clone() const { return new parser_exception(m_msg, m_fname.c_str(), m_line, m_pos); } virtual exception * clone() const { return new parser_exception(m_msg, m_fname.c_str(), m_line, m_pos); }
virtual void rethrow() const { throw *this; } 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); }
}; };
/** \brief Exception used to sign that a computation was interrupted */ /** \brief Exception used to sign that a computation was interrupted */
class interrupted : public exception { class interrupted : public exception {
public: public:

View file

@ -91,10 +91,11 @@ static void exec(lua_State * L) {
void check_result(lua_State * L, int result) { void check_result(lua_State * L, int result) {
if (result) { if (result) {
if (is_exception(L, -1)) if (is_exception(L, -1)) {
to_exception(L, -1).rethrow(); to_exception(L, -1).rethrow();
else } else {
throw script_exception(lua_tostring(L, -1)); throw script_exception(lua_tostring(L, -1));
}
} }
} }
@ -137,10 +138,16 @@ bool resume(lua_State * L, int nargs) {
int safe_function_wrapper(lua_State * L, lua_CFunction f) { int safe_function_wrapper(lua_State * L, lua_CFunction f) {
try { try {
return f(L); return f(L);
} catch (script_exception & e) {
lua_pushstring(L, e.what());
} catch (exception & e) { } catch (exception & e) {
push_exception(L, e); lua_Debug ar;
lua_getstack(L, 1, &ar);
lua_getinfo(L, "Sl", &ar);
if (ar.source && *(ar.source) == '@')
push_exception(L, script_nested_exception(true, ar.source+1, ar.currentline, std::shared_ptr<exception>(e.clone())));
else if (ar.source)
push_exception(L, script_nested_exception(false, ar.source, ar.currentline, std::shared_ptr<exception>(e.clone())));
else
push_exception(L, e);
} catch (std::bad_alloc &) { } catch (std::bad_alloc &) {
lua_pushstring(L, "out of memory"); lua_pushstring(L, "out of memory");
} catch (std::exception & e) { } catch (std::exception & e) {

View file

@ -55,7 +55,7 @@ script_exception::script_exception(char const * lua_error) {
script_exception::~script_exception() { script_exception::~script_exception() {
} }
char const * script_exception::get_filename() const { char const * script_exception::get_file_name() const {
lean_assert(get_source() == source::File); lean_assert(get_source() == source::File);
return m_file.c_str(); return m_file.c_str();
} }
@ -72,12 +72,30 @@ char const * script_exception::get_msg() const noexcept {
char const * script_exception::what() const noexcept { char const * script_exception::what() const noexcept {
static thread_local std::string buffer; static thread_local std::string buffer;
std::ostringstream strm; std::ostringstream strm;
char const * msg = get_msg();
char const * space = msg && *msg == ' ' ? "" : " ";
switch (get_source()) { switch (get_source()) {
case source::String: strm << "[string]:" << get_line() << ":" << get_msg() << "\n"; break; case source::String: strm << "[string]:" << get_line() << ":" << space << get_msg(); break;
case source::File: strm << get_filename() << ":" << get_line() << ":" << get_msg() << "\n"; break; case source::File: strm << get_file_name() << ":" << get_line() << ":" << space << get_msg(); break;
case source::Unknown: return get_msg(); case source::Unknown: return get_msg();
} }
buffer = strm.str(); buffer = strm.str();
return buffer.c_str(); return buffer.c_str();
} }
script_nested_exception::script_nested_exception(source s, std::string f, unsigned l, std::shared_ptr<exception> const & ex):
script_exception(s, f, l, "Lean exception"),
m_exception(ex) {
lean_assert(ex);
}
script_nested_exception::~script_nested_exception() {}
char const * script_nested_exception::what() const noexcept {
static thread_local std::string buffer;
std::ostringstream strm;
strm << script_exception::what() << "\n" << get_exception().what();
buffer = strm.str();
return buffer.c_str();
}
} }

View file

@ -6,6 +6,7 @@ Author: Leonardo de Moura
*/ */
#pragma once #pragma once
#include <string> #include <string>
#include <memory>
#include "util/exception.h" #include "util/exception.h"
namespace lean { namespace lean {
@ -15,21 +16,36 @@ namespace lean {
class script_exception : public exception { class script_exception : public exception {
public: public:
enum class source { String, File, Unknown }; enum class source { String, File, Unknown };
private: protected:
source m_source; source m_source;
std::string m_file; // if source == File, then this field contains the filename that triggered the error. std::string m_file; // if source == File, then this field contains the filename that triggered the error.
unsigned m_line; // line number unsigned m_line; // line number
script_exception(source s, std::string f, unsigned l):m_source(s), m_file(f), m_line(l) {} script_exception(source s, std::string f, unsigned l, std::string const & msg):exception(msg), m_source(s), m_file(f), m_line(l) {}
public: public:
script_exception(char const * lua_error); script_exception(char const * lua_error);
virtual ~script_exception(); virtual ~script_exception();
virtual char const * what() const noexcept; virtual char const * what() const noexcept;
virtual source get_source() const { return m_source; } virtual source get_source() const { return m_source; }
virtual char const * get_filename() const; virtual char const * get_file_name() const;
virtual unsigned get_line() const; virtual unsigned get_line() const;
/** \brief Return error message without position information */ /** \brief Return error message without position information */
virtual char const * get_msg() const noexcept; virtual char const * get_msg() const noexcept;
virtual exception * clone() const { return new script_exception(m_source, m_file, m_line); } virtual exception * clone() const { return new script_exception(m_source, m_file, m_line, m_msg); }
virtual void rethrow() const { throw *this; } virtual void rethrow() const { throw *this; }
}; };
/**
\brief Lean exception occurred inside of a script
*/
class script_nested_exception : public script_exception {
std::shared_ptr<exception> m_exception;
script_nested_exception(source s, std::string f, unsigned l, std::shared_ptr<exception> const & ex);
public:
script_nested_exception(bool file, std::string f, unsigned l, std::shared_ptr<exception> const & ex):script_nested_exception(file ? source::File : source::String, f, l, ex) {}
virtual ~script_nested_exception();
virtual char const * what() const noexcept;
virtual exception * clone() const { return new script_nested_exception(m_source, m_file, m_line, m_exception); }
virtual void rethrow() const { throw *this; }
exception const & get_exception() const { return *(m_exception.get()); }
};
} }

View file

@ -1,3 +1,3 @@
Set: pp::colors Set: pp::colors
Set: pp::unicode Set: pp::unicode
alias3.lean:2:13: error: alias 'A' was already defined alias3.lean:2:0: error: alias 'A' was already defined

View file

@ -7,12 +7,12 @@
variable f : T → R variable f : T → R
coercion f coercion f
Assumed: g Assumed: g
coercion1.lean:8:0: error: invalid coercion declaration, frontend already has a coercion for the given types coercion1.lean:7:0: error: invalid coercion declaration, frontend already has a coercion for the given types
Assumed: h Assumed: h
coercion1.lean:10:0: error: invalid coercion declaration, a coercion must have an arrow type (i.e., a non-dependent functional type) coercion1.lean:9:0: error: invalid coercion declaration, a coercion must have an arrow type (i.e., a non-dependent functional type)
Defined: T2 Defined: T2
Defined: R2 Defined: R2
Assumed: f2 Assumed: f2
coercion1.lean:14:0: error: invalid coercion declaration, frontend already has a coercion for the given types coercion1.lean:13:0: error: invalid coercion declaration, frontend already has a coercion for the given types
Assumed: id Assumed: id
coercion1.lean:16:0: error: invalid coercion declaration, 'from' and 'to' types are the same coercion1.lean:15:0: error: invalid coercion declaration, 'from' and 'to' types are the same

View file

@ -3,10 +3,14 @@
Assumed: x Assumed: x
env_errors.lean:3:0: error: set_opaque failed, 'x' is not a definition env_errors.lean:3:0: error: set_opaque failed, 'x' is not a definition
before import before import
env_errors.lean:11:0: error: file 'tstblafoo.lean' not found in the LEAN_PATH env_errors.lean:8: error: executing script
error: file 'tstblafoo.lean' not found in the LEAN_PATH
before load1 before load1
env_errors.lean:17:0: error: failed to open file 'tstblafoo.lean' env_errors.lean:14: error: executing script
error: failed to open file 'tstblafoo.lean'
before load2 before load2
env_errors.lean:23:0: error: corrupted binary file env_errors.lean:20: error: executing script
error: corrupted binary file
before load3 before load3
env_errors.lean:28:0: error: file 'fake2.olean' does not seem to be a valid object Lean file env_errors.lean:26: error: executing script
error: file 'fake2.olean' does not seem to be a valid object Lean file

View file

@ -9,4 +9,4 @@ module::@g : ∀ (A : Type), A → A → A
h::1::explicit : ∀ (A B : Type), A → B → A h::1::explicit : ∀ (A B : Type), A → B → A
Assumed: @h Assumed: @h
Assumed: h Assumed: h
explicit.lean:9:37: error: failed to mark implicit arguments for 'h', the frontend already has an object named '@h' explicit.lean:9:0: error: failed to mark implicit arguments for 'h', the frontend already has an object named '@h'

View file

@ -2,18 +2,18 @@
Set: pp::unicode Set: pp::unicode
Proof state: Proof state:
a : Bool, b : Bool, H : a, H::1 : b ⊢ a ∧ b a : Bool, b : Bool, H : a, H::1 : b ⊢ a ∧ b
## stdin:5:0: error: invalid 'done' command, proof cannot be produced from this state ## [stdin]:5:0: error: invalid 'done' command, proof cannot be produced from this state
Proof state: Proof state:
a : Bool, b : Bool, H : a, H::1 : b ⊢ a ∧ b a : Bool, b : Bool, H : a, H::1 : b ⊢ a ∧ b
## stdin:6:0: error: invalid 'done' command, proof cannot be produced from this state ## [stdin]:6:0: error: invalid 'done' command, proof cannot be produced from this state
Proof state: Proof state:
a : Bool, b : Bool, H : a, H::1 : b ⊢ a ∧ b a : Bool, b : Bool, H : a, H::1 : b ⊢ a ∧ b
## stdin:7:0: error: unknown tactic 'imp_tac2' ## [stdin]:7:0: error: unknown tactic 'imp_tac2'
## stdin:8:0: error: unknown tactic 'foo' ## [stdin]:8:0: error: unknown tactic 'foo'
## Proof state: ## Proof state:
a : Bool, b : Bool, H : a, H::1 : b ⊢ a a : Bool, b : Bool, H : a, H::1 : b ⊢ a
a : Bool, b : Bool, H : a, H::1 : b ⊢ b a : Bool, b : Bool, H : a, H::1 : b ⊢ b
## stdin:10:0: error: failed to backtrack ## [stdin]:10:0: error: failed to backtrack
Proof state: Proof state:
a : Bool, b : Bool, H : a, H::1 : b ⊢ a a : Bool, b : Bool, H : a, H::1 : b ⊢ a
a : Bool, b : Bool, H : a, H::1 : b ⊢ b a : Bool, b : Bool, H : a, H::1 : b ⊢ b

View file

@ -6,15 +6,15 @@ A : Bool, B : Bool, H : A ∧ B ⊢ A
no goals no goals
## Proof state: ## Proof state:
A : Bool, B : Bool, H : A ∧ B, H1 : A ⊢ B A : Bool, B : Bool, H : A ∧ B, H1 : A ⊢ B
## stdin:15:3: error: unknown tactic 'simple2_tac' ## [stdin]:15:3: error: unknown tactic 'simple2_tac'
## stdin:15:16: error: invalid 'done' command, proof cannot be produced from this state ## [stdin]:15:16: error: invalid 'done' command, proof cannot be produced from this state
Proof state: Proof state:
A : Bool, B : Bool, H : A ∧ B, H1 : A ⊢ B A : Bool, B : Bool, H : A ∧ B, H1 : A ⊢ B
## Proof state: ## Proof state:
no goals no goals
## Proof state: ## Proof state:
A : Bool, B : Bool, H : A ∧ B, H1 : A, H2 : B ⊢ B ∧ A A : Bool, B : Bool, H : A ∧ B, H1 : A, H2 : B ⊢ B ∧ A
## stdin:18:0: error: failed to prove theorem, proof has been aborted ## [stdin]:18:0: error: failed to prove theorem, proof has been aborted
Proof state: Proof state:
A : Bool, B : Bool, H : A ∧ B, H1 : A, H2 : B ⊢ B ∧ A A : Bool, B : Bool, H : A ∧ B, H1 : A, H2 : B ⊢ B ∧ A
# echo command after failure # echo command after failure

View file

@ -2,8 +2,8 @@
Set: pp::unicode Set: pp::unicode
Proof state: Proof state:
a : Bool, b : Bool, H : a, H::1 : b ⊢ a ∧ b a : Bool, b : Bool, H : a, H::1 : b ⊢ a ∧ b
## stdin:5:0: error: unknown tactic 'foo' ## [stdin]:5:0: error: unknown tactic 'foo'
## stdin:6:5: error: failed to prove theorem, proof has been aborted ## [stdin]:6:5: error: failed to prove theorem, proof has been aborted
Proof state: Proof state:
a : Bool, b : Bool, H : a, H::1 : b ⊢ a ∧ b a : Bool, b : Bool, H : a, H::1 : b ⊢ a ∧ b
# Assumed: a # Assumed: a

View file

@ -6,7 +6,7 @@ a : Bool, b : Bool, H : b ⊢ a b
a : Bool, b : Bool, H : b ⊢ a a : Bool, b : Bool, H : b ⊢ a
## Proof state: ## Proof state:
a : Bool, b : Bool, H : b ⊢ b a : Bool, b : Bool, H : b ⊢ b
## stdin:9:0: error: failed to backtrack ## [stdin]:9:0: error: failed to backtrack
Proof state: Proof state:
a : Bool, b : Bool, H : b ⊢ b a : Bool, b : Bool, H : b ⊢ b
## Proof state: ## Proof state:

View file

@ -1,5 +1,5 @@
# Set: pp::colors # Set: pp::colors
Set: pp::unicode Set: pp::unicode
stdin:4:8: error: invalid definition, identifier expected [stdin]:4:8: error: invalid definition, identifier expected
# done # done
# #

View file

@ -4,21 +4,23 @@
Assumed: i Assumed: i
Assumed: j Assumed: j
Assumed: p Assumed: p
[string]:5: Lean exception
elaborator exception elaborator exception
lua15.lean:9: error: executing script
Failed to solve Failed to solve
⊢ (?M::0 ≈ Nat::add) ⊕ (?M::0 ≈ Int::add) ⊢ (?M::0 ≈ Nat::add) ⊕ (?M::0 ≈ Int::add)
Overloading at [string]:1:3: Overloading at
(Int::add | Nat::add) i p (Int::add | Nat::add) i p
Failed to solve Failed to solve
Type of argument 1 must be convertible to the expected type in the application of [string]:1:3: Type of argument 1 must be convertible to the expected type in the application of
Nat::add Nat::add
with arguments: with arguments:
i i
p p
Failed to solve Failed to solve
⊢ Bool ≺ ⊢ Bool ≺
Type of argument 2 must be convertible to the expected type in the application of [string]:1:3: Type of argument 2 must be convertible to the expected type in the application of
Int::add Int::add
with arguments: with arguments:
i i

13
tests/lean/lua15b.lean Normal file
View file

@ -0,0 +1,13 @@
import Int.
variables i j : Int
variable p : Bool
(*
local env = get_environment()
parse_lean_cmds([[
print "hello"
eval i + j
check i + p
]])
*)

View file

@ -0,0 +1,27 @@
Set: pp::colors
Set: pp::unicode
Imported 'Int'
Assumed: i
Assumed: j
Assumed: p
hello
i + j
lua15b.lean:8: error: executing script
Failed to solve
⊢ (?M::0 ≈ Nat::add) ⊕ (?M::0 ≈ Int::add)
[string]:3:12: Overloading at
(Int::add | Nat::add) i p
Failed to solve
[string]:3:12: Type of argument 1 must be convertible to the expected type in the application of
Nat::add
with arguments:
i
p
Failed to solve
⊢ Bool ≺
[string]:3:12: Type of argument 2 must be convertible to the expected type in the application of
Int::add
with arguments:
i
p

20
tests/lean/parser1.lean Normal file
View file

@ -0,0 +1,20 @@
(*
foo(10)
*)
print "checkpoint"
(*
parse_lean_cmds("(" .. "*" .. [[
foo(20)
]] .. "*" .. ")")
*)

View file

@ -0,0 +1,6 @@
Set: pp::colors
Set: pp::unicode
parser1.lean:6: error: executing script, attempt to call global 'foo' (a nil value)
checkpoint
parser1.lean:14: error: executing script
[string]:2: error: executing script, attempt to call global 'foo' (a nil value)

View file

@ -8,4 +8,4 @@ T:interrupt()
local ok, msg = pcall(function() T:wait() end) local ok, msg = pcall(function() T:wait() end)
assert(not ok) assert(not ok)
assert(is_exception(msg)) assert(is_exception(msg))
assert(msg:what() == "interrupted") print(msg:what():find("interrupted"))

View file

@ -31,6 +31,8 @@ assert(not pcall(function() S:eval([[ x = ]]) end))
local T2 = thread(S, [[ local x = ...; error("failed") ]], 10) local T2 = thread(S, [[ local x = ...; error("failed") ]], 10)
local ok, msg = pcall(function() T2:wait() end) local ok, msg = pcall(function() T2:wait() end)
assert(not ok) assert(not ok)
assert(string.sub(msg, -7) == "failed\n") assert(is_exception(msg))
print(msg:what())
assert(msg:what():find("failed"))
local T3 = thread(S, [[ local x = ...; return x + 10, x - 10 ]], 10) local T3 = thread(S, [[ local x = ...; return x + 10, x - 10 ]], 10)
T3 = nil T3 = nil