Add expr_formatter and expr_locator. Add better error messages. Improve simple printer.
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
3bcbdf7c7b
commit
392b347f53
14 changed files with 410 additions and 68 deletions
|
@ -1,5 +1,5 @@
|
||||||
add_library(kernel expr.cpp max_sharing.cpp free_vars.cpp abstract.cpp
|
add_library(kernel expr.cpp max_sharing.cpp free_vars.cpp abstract.cpp
|
||||||
instantiate.cpp deep_copy.cpp normalize.cpp level.cpp environment.cpp
|
instantiate.cpp deep_copy.cpp normalize.cpp level.cpp environment.cpp
|
||||||
type_check.cpp context.cpp builtin.cpp basic_thms.cpp toplevel.cpp
|
type_check.cpp context.cpp builtin.cpp basic_thms.cpp toplevel.cpp
|
||||||
object.cpp pp.cpp)
|
object.cpp expr_formatter.cpp expr_locator.cpp pp.cpp)
|
||||||
target_link_libraries(kernel ${LEAN_LIBS})
|
target_link_libraries(kernel ${LEAN_LIBS})
|
||||||
|
|
|
@ -6,19 +6,29 @@ Author: Leonardo de Moura
|
||||||
*/
|
*/
|
||||||
#include "context.h"
|
#include "context.h"
|
||||||
#include "exception.h"
|
#include "exception.h"
|
||||||
|
#include "expr_formatter.h"
|
||||||
|
|
||||||
namespace lean {
|
namespace lean {
|
||||||
std::ostream & operator<<(std::ostream & out, context const & c) {
|
format pp(expr_formatter & fmt, context const & c) {
|
||||||
if (c) {
|
if (c) {
|
||||||
|
format r;
|
||||||
if (tail(c))
|
if (tail(c))
|
||||||
out << tail(c) << "\n";
|
r = format{pp(fmt, tail(c)), line()};
|
||||||
context_entry const & e = head(c);
|
context_entry const & e = head(c);
|
||||||
if (e.get_name().is_anonymous())
|
if (e.get_name().is_anonymous())
|
||||||
out << "_";
|
r += format("_");
|
||||||
else
|
else
|
||||||
out << e.get_name();
|
r += format(e.get_name());
|
||||||
out << " : " << e.get_type();
|
r += format{space(), colon(), space(), fmt(e.get_type(), tail(c))};
|
||||||
|
return r;
|
||||||
|
} else {
|
||||||
|
return format();
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream & operator<<(std::ostream & out, context const & c) {
|
||||||
|
auto fmt = mk_simple_expr_formatter();
|
||||||
|
out << pp(*fmt, c);
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -35,5 +35,7 @@ inline context extend(context const & c, name const & n, expr const & t) {
|
||||||
inline bool empty(context const & c) {
|
inline bool empty(context const & c) {
|
||||||
return is_nil(c);
|
return is_nil(c);
|
||||||
}
|
}
|
||||||
|
class expr_formatter;
|
||||||
|
format pp(expr_formatter & f, context const & c);
|
||||||
std::ostream & operator<<(std::ostream & out, context const & c);
|
std::ostream & operator<<(std::ostream & out, context const & c);
|
||||||
}
|
}
|
||||||
|
|
|
@ -31,6 +31,29 @@ struct environment::imp {
|
||||||
// Object management
|
// Object management
|
||||||
std::vector<object*> m_objects;
|
std::vector<object*> m_objects;
|
||||||
object_dictionary m_object_dictionary;
|
object_dictionary m_object_dictionary;
|
||||||
|
// Expression formatter && locator
|
||||||
|
std::shared_ptr<expr_formatter> m_formatter;
|
||||||
|
std::shared_ptr<expr_locator> m_locator;
|
||||||
|
|
||||||
|
expr_formatter & get_formatter() {
|
||||||
|
if (m_formatter) {
|
||||||
|
return *m_formatter;
|
||||||
|
} else {
|
||||||
|
// root environments always have a formatter.
|
||||||
|
lean_assert(has_parent());
|
||||||
|
return m_parent->get_formatter();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expr_locator & get_locator() {
|
||||||
|
if (m_locator) {
|
||||||
|
return *m_locator;
|
||||||
|
} else {
|
||||||
|
// root environments always have a locator.
|
||||||
|
lean_assert(has_parent());
|
||||||
|
return m_parent->get_locator();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Return true iff this environment has children.
|
\brief Return true iff this environment has children.
|
||||||
|
@ -316,6 +339,8 @@ struct environment::imp {
|
||||||
imp():
|
imp():
|
||||||
m_num_children(0) {
|
m_num_children(0) {
|
||||||
init_uvars();
|
init_uvars();
|
||||||
|
m_formatter = mk_simple_expr_formatter();
|
||||||
|
m_locator = mk_dummy_expr_locator();
|
||||||
}
|
}
|
||||||
|
|
||||||
explicit imp(std::shared_ptr<imp> const & parent):
|
explicit imp(std::shared_ptr<imp> const & parent):
|
||||||
|
@ -346,6 +371,24 @@ environment::environment(std::shared_ptr<imp> const & ptr):
|
||||||
environment::~environment() {
|
environment::~environment() {
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void environment::set_formatter(std::shared_ptr<expr_formatter> const & formatter) {
|
||||||
|
lean_assert(formatter);
|
||||||
|
m_imp->m_formatter = formatter;
|
||||||
|
}
|
||||||
|
|
||||||
|
expr_formatter & environment::get_formatter() const {
|
||||||
|
return m_imp->get_formatter();
|
||||||
|
}
|
||||||
|
|
||||||
|
void environment::set_locator(std::shared_ptr<expr_locator> const & locator) {
|
||||||
|
lean_assert(locator);
|
||||||
|
m_imp->m_locator = locator;
|
||||||
|
}
|
||||||
|
|
||||||
|
expr_locator & environment::get_locator() const {
|
||||||
|
return m_imp->get_locator();
|
||||||
|
}
|
||||||
|
|
||||||
environment environment::mk_child() const {
|
environment environment::mk_child() const {
|
||||||
return environment(new imp(m_imp));
|
return environment(new imp(m_imp));
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,6 +9,8 @@ Author: Leonardo de Moura
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include "object.h"
|
#include "object.h"
|
||||||
#include "level.h"
|
#include "level.h"
|
||||||
|
#include "expr_formatter.h"
|
||||||
|
#include "expr_locator.h"
|
||||||
|
|
||||||
namespace lean {
|
namespace lean {
|
||||||
/**
|
/**
|
||||||
|
@ -28,6 +30,18 @@ public:
|
||||||
environment();
|
environment();
|
||||||
~environment();
|
~environment();
|
||||||
|
|
||||||
|
/** \brief Set expression formatter. */
|
||||||
|
void set_formatter(std::shared_ptr<expr_formatter> const & formatter);
|
||||||
|
|
||||||
|
/** \brief Return expression formatter. */
|
||||||
|
expr_formatter & get_formatter() const;
|
||||||
|
|
||||||
|
/** \brief Set expression locator. */
|
||||||
|
void set_locator(std::shared_ptr<expr_locator> const & locator);
|
||||||
|
|
||||||
|
/** \brief Return expression locator. */
|
||||||
|
expr_locator & get_locator() const;
|
||||||
|
|
||||||
// =======================================
|
// =======================================
|
||||||
// Parent/Child environment management
|
// Parent/Child environment management
|
||||||
/**
|
/**
|
||||||
|
|
|
@ -188,45 +188,6 @@ bool is_arrow(expr const & t) {
|
||||||
return is_pi(t) && !has_free_var(abst_body(t), 0);
|
return is_pi(t) && !has_free_var(abst_body(t), 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Low-level pretty printer
|
|
||||||
std::ostream & operator<<(std::ostream & out, expr const & a) {
|
|
||||||
switch (a.kind()) {
|
|
||||||
case expr_kind::Var: out << "#" << var_idx(a); break;
|
|
||||||
case expr_kind::Constant: out << const_name(a); break;
|
|
||||||
case expr_kind::App:
|
|
||||||
out << "(";
|
|
||||||
for (unsigned i = 0; i < num_args(a); i++) {
|
|
||||||
if (i > 0) out << " ";
|
|
||||||
out << arg(a, i);
|
|
||||||
}
|
|
||||||
out << ")";
|
|
||||||
break;
|
|
||||||
case expr_kind::Eq: out << "(" << eq_lhs(a) << " = " << eq_rhs(a) << ")"; break;
|
|
||||||
case expr_kind::Lambda: out << "(fun " << abst_name(a) << " : " << abst_domain(a) << " => " << abst_body(a) << ")"; break;
|
|
||||||
case expr_kind::Pi:
|
|
||||||
if (!is_arrow(a)) {
|
|
||||||
out << "(pi " << abst_name(a) << " : " << abst_domain(a) << ", " << abst_body(a) << ")";
|
|
||||||
} else if (!is_arrow(abst_domain(a))) {
|
|
||||||
out << abst_domain(a) << " -> " << abst_body(a);
|
|
||||||
} else {
|
|
||||||
out << "(" << abst_domain(a) << ") -> " << abst_body(a);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
case expr_kind::Let: out << "(let " << let_name(a) << " := " << let_value(a) << " in " << let_body(a) << ")"; break;
|
|
||||||
case expr_kind::Type: {
|
|
||||||
level const & l = ty_level(a);
|
|
||||||
if (l == level()) {
|
|
||||||
out << "Type";
|
|
||||||
} else {
|
|
||||||
out << "(Type " << ty_level(a) << ")";
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case expr_kind::Value: to_value(a).display(out); break;
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
}
|
|
||||||
|
|
||||||
expr copy(expr const & a) {
|
expr copy(expr const & a) {
|
||||||
switch (a.kind()) {
|
switch (a.kind()) {
|
||||||
case expr_kind::Var: return mk_var(var_idx(a));
|
case expr_kind::Var: return mk_var(var_idx(a));
|
||||||
|
|
172
src/kernel/expr_formatter.cpp
Normal file
172
src/kernel/expr_formatter.cpp
Normal file
|
@ -0,0 +1,172 @@
|
||||||
|
/*
|
||||||
|
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 "expr_formatter.h"
|
||||||
|
#include "exception.h"
|
||||||
|
|
||||||
|
namespace lean {
|
||||||
|
void expr_formatter::pp(std::ostream & out, expr const & e, context const & c) {
|
||||||
|
out << mk_pair(operator()(e, c), get_options());
|
||||||
|
}
|
||||||
|
|
||||||
|
void expr_formatter::pp(std::ostream & out, expr const & e) {
|
||||||
|
pp(out, e, context());
|
||||||
|
}
|
||||||
|
|
||||||
|
format expr_formatter::nest(format const & f) {
|
||||||
|
return ::lean::nest(get_pp_indent(get_options()), f);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_atomic(expr const & e) {
|
||||||
|
switch (e.kind()) {
|
||||||
|
case expr_kind::Var: case expr_kind::Constant: case expr_kind::Value: case expr_kind::Type:
|
||||||
|
return true;
|
||||||
|
case expr_kind::App: case expr_kind::Lambda: case expr_kind::Pi: case expr_kind::Eq: case expr_kind::Let:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
class simple_expr_formatter : public expr_formatter {
|
||||||
|
static thread_local std::ostream * m_out;
|
||||||
|
|
||||||
|
std::ostream & out() { return *m_out; }
|
||||||
|
|
||||||
|
void print_child(expr const & a, context const & c) {
|
||||||
|
if (is_atomic(a)) {
|
||||||
|
print(a, c);
|
||||||
|
} else {
|
||||||
|
out() << "(";
|
||||||
|
print(a, c);
|
||||||
|
out() << ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_value(expr const & a) {
|
||||||
|
to_value(a).display(out());
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_type(expr const & a) {
|
||||||
|
if (a == Type()) {
|
||||||
|
out() << "Type";
|
||||||
|
} else {
|
||||||
|
out() << "Type " << ty_level(a);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_eq(expr const & a, context const & c) {
|
||||||
|
print_child(eq_lhs(a), c);
|
||||||
|
out() << " = ";
|
||||||
|
print_child(eq_rhs(a), c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_app(expr const & a, context const & c) {
|
||||||
|
print_child(arg(a, 0), c);
|
||||||
|
for (unsigned i = 1; i < num_args(a); i++) {
|
||||||
|
out() << " ";
|
||||||
|
print_child(arg(a, i), c);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void print_arrow_body(expr const & a, context const & c) {
|
||||||
|
if (is_atomic(a) || is_arrow(a))
|
||||||
|
return print(a, c);
|
||||||
|
else
|
||||||
|
return print_child(a, c);
|
||||||
|
}
|
||||||
|
|
||||||
|
void print(expr const & a, context const & c) {
|
||||||
|
switch (a.kind()) {
|
||||||
|
case expr_kind::Var:
|
||||||
|
try {
|
||||||
|
context const & c1 = lookup(c, var_idx(a));
|
||||||
|
out() << head(c1).get_name();
|
||||||
|
} catch (exception & ex) {
|
||||||
|
out() << "#" << var_idx(a);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case expr_kind::Constant:
|
||||||
|
out() << const_name(a);
|
||||||
|
break;
|
||||||
|
case expr_kind::App:
|
||||||
|
print_app(a, c);
|
||||||
|
break;
|
||||||
|
case expr_kind::Eq:
|
||||||
|
print_eq(a, c);
|
||||||
|
break;
|
||||||
|
case expr_kind::Lambda:
|
||||||
|
out() << "fun " << abst_name(a) << " : ";
|
||||||
|
print_child(abst_domain(a), c);
|
||||||
|
out() << ", ";
|
||||||
|
print_child(abst_body(a), extend(c, abst_name(a), abst_domain(a)));
|
||||||
|
break;
|
||||||
|
case expr_kind::Pi:
|
||||||
|
if (!is_arrow(a)) {
|
||||||
|
out() << "Pi " << abst_name(a) << " : ";
|
||||||
|
print_child(abst_domain(a), c);
|
||||||
|
out() << ", ";
|
||||||
|
print_child(abst_body(a), extend(c, abst_name(a), abst_domain(a)));
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
print_child(abst_domain(a), c);
|
||||||
|
out() << " -> ";
|
||||||
|
print_arrow_body(abst_body(a), extend(c, abst_name(a), abst_domain(a)));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case expr_kind::Let:
|
||||||
|
out() << "let " << let_name(a) << " := ";
|
||||||
|
print_child(let_value(a), c);
|
||||||
|
out() << " in ";
|
||||||
|
print_child(let_body(a), extend(c, let_name(a), let_value(a)));
|
||||||
|
break;
|
||||||
|
case expr_kind::Type:
|
||||||
|
print_type(a);
|
||||||
|
break;
|
||||||
|
case expr_kind::Value:
|
||||||
|
print_value(a);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public:
|
||||||
|
virtual ~simple_expr_formatter() {}
|
||||||
|
|
||||||
|
virtual format operator()(expr const & e, context const & c) {
|
||||||
|
std::ostringstream s;
|
||||||
|
m_out = &s;
|
||||||
|
print(e, c);
|
||||||
|
return format(s.str());
|
||||||
|
}
|
||||||
|
|
||||||
|
virtual bool has_location(expr const & e) const { return false; }
|
||||||
|
|
||||||
|
virtual std::pair<unsigned, unsigned> get_location(expr const & e) const { return mk_pair(0,0); }
|
||||||
|
|
||||||
|
virtual options get_options() const { return options(); }
|
||||||
|
|
||||||
|
void print(std::ostream & out, expr const & a, context const & c) {
|
||||||
|
m_out = &out;
|
||||||
|
print(a, c);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
thread_local std::ostream * simple_expr_formatter::m_out = 0;
|
||||||
|
|
||||||
|
std::shared_ptr<expr_formatter> mk_simple_expr_formatter() {
|
||||||
|
return std::shared_ptr<expr_formatter>(new simple_expr_formatter());
|
||||||
|
}
|
||||||
|
|
||||||
|
std::ostream & operator<<(std::ostream & out, std::pair<expr_formatter &, expr const &> const & p) {
|
||||||
|
p.first.pp(out, p.second);
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
static simple_expr_formatter g_simple_formatter;
|
||||||
|
|
||||||
|
std::ostream & operator<<(std::ostream & out, expr const & a) {
|
||||||
|
g_simple_formatter.print(out, a, context());
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
}
|
35
src/kernel/expr_formatter.h
Normal file
35
src/kernel/expr_formatter.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
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 <memory>
|
||||||
|
#include "context.h"
|
||||||
|
#include "options.h"
|
||||||
|
|
||||||
|
namespace lean {
|
||||||
|
/** \brief Abstract class for formatting expressions. */
|
||||||
|
class expr_formatter {
|
||||||
|
public:
|
||||||
|
virtual ~expr_formatter() {}
|
||||||
|
/** \brief Convert expression in the given context into a format object. */
|
||||||
|
virtual format operator()(expr const & e, context const & c) = 0;
|
||||||
|
/** \brief Return options for pretty printing. */
|
||||||
|
virtual options get_options() const = 0;
|
||||||
|
|
||||||
|
void pp(std::ostream & out, expr const & e, context const & c);
|
||||||
|
void pp(std::ostream & out, expr const & e);
|
||||||
|
|
||||||
|
/** \brief Nest the given format object using the setting provided by get_options. */
|
||||||
|
format nest(format const & f);
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Create simple expression formatter.
|
||||||
|
It is mainly useful for pretty printing.
|
||||||
|
*/
|
||||||
|
std::shared_ptr<expr_formatter> mk_simple_expr_formatter();
|
||||||
|
std::ostream & operator<<(std::ostream & out, std::pair<expr_formatter &, expr const &> const & p);
|
||||||
|
}
|
35
src/kernel/expr_locator.cpp
Normal file
35
src/kernel/expr_locator.cpp
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
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 "expr_locator.h"
|
||||||
|
#include "exception.h"
|
||||||
|
|
||||||
|
namespace lean {
|
||||||
|
expr_locator::~expr_locator() {}
|
||||||
|
bool expr_locator::has_location(expr const & e) const { return false; }
|
||||||
|
std::pair<unsigned, unsigned> expr_locator::get_location(expr const & e) const { lean_unreachable(); return mk_pair(0, 0); }
|
||||||
|
|
||||||
|
std::shared_ptr<expr_locator> mk_dummy_expr_locator() {
|
||||||
|
return std::shared_ptr<expr_locator>(new expr_locator());
|
||||||
|
}
|
||||||
|
|
||||||
|
void throw_exception(expr_locator const & loc, expr const & src, char const * msg) {
|
||||||
|
if (loc.has_location(src)) {
|
||||||
|
std::ostringstream s;
|
||||||
|
auto p = loc.get_location(src);
|
||||||
|
s << "(line: " << p.first << ", pos: " << p.second << ") " << msg;
|
||||||
|
throw exception(s.str());
|
||||||
|
} else {
|
||||||
|
throw exception(msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void throw_exception(expr_locator const & loc, expr const & src, format const & msg) {
|
||||||
|
std::ostringstream s;
|
||||||
|
s << msg;
|
||||||
|
throw_exception(loc, src, s.str().c_str());
|
||||||
|
}
|
||||||
|
}
|
35
src/kernel/expr_locator.h
Normal file
35
src/kernel/expr_locator.h
Normal file
|
@ -0,0 +1,35 @@
|
||||||
|
/*
|
||||||
|
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 <memory>
|
||||||
|
#include "expr.h"
|
||||||
|
|
||||||
|
namespace lean {
|
||||||
|
/**
|
||||||
|
\brief Abstract class that specifies the API to retrieve
|
||||||
|
expression location (line and position).
|
||||||
|
*/
|
||||||
|
class expr_locator {
|
||||||
|
public:
|
||||||
|
virtual ~expr_locator();
|
||||||
|
/** \brief Return true iff the expression has location information associated with it. */
|
||||||
|
virtual bool has_location(expr const & e) const;
|
||||||
|
/** \brief Return location (line, pos) associated with expression. \pre has_location() */
|
||||||
|
virtual std::pair<unsigned, unsigned> get_location(expr const & e) const;
|
||||||
|
};
|
||||||
|
/**
|
||||||
|
\brief Create a expression locator s.t. has_location always return false.
|
||||||
|
*/
|
||||||
|
std::shared_ptr<expr_locator> mk_dummy_expr_locator();
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Throw an exception with the given msg, and include location
|
||||||
|
of the given expression (if available).
|
||||||
|
*/
|
||||||
|
void throw_exception(expr_locator const & loc, expr const & src, char const * msg);
|
||||||
|
void throw_exception(expr_locator const & loc, expr const & src, format const & msg);
|
||||||
|
}
|
|
@ -4,9 +4,9 @@ Released under Apache 2.0 license as described in the file LICENSE.
|
||||||
|
|
||||||
Author: Leonardo de Moura
|
Author: Leonardo de Moura
|
||||||
*/
|
*/
|
||||||
#include <sstream>
|
|
||||||
#include "type_check.h"
|
#include "type_check.h"
|
||||||
#include "scoped_map.h"
|
#include "scoped_map.h"
|
||||||
|
#include "environment.h"
|
||||||
#include "normalize.h"
|
#include "normalize.h"
|
||||||
#include "instantiate.h"
|
#include "instantiate.h"
|
||||||
#include "builtin.h"
|
#include "builtin.h"
|
||||||
|
@ -56,6 +56,20 @@ struct infer_type_fn {
|
||||||
return lift_free_vars(head(def_c).get_type(), length(c) - (length(def_c) - 1));
|
return lift_free_vars(head(def_c).get_type(), length(c) - (length(def_c) - 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expr_formatter & fmt() { return m_env.get_formatter(); }
|
||||||
|
|
||||||
|
format nl_indent(format const & f) { return fmt().nest(format{line(), f}); }
|
||||||
|
|
||||||
|
void throw_exception(expr const & src, format const & msg) {
|
||||||
|
::lean::throw_exception(m_env.get_locator(), src, msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Include context (if not empty) in the formatted message */
|
||||||
|
void push_context(format & msg, context const & ctx) {
|
||||||
|
if (!empty(ctx))
|
||||||
|
msg += format{format("in context: "), nl_indent(pp(fmt(), ctx)), line()};
|
||||||
|
}
|
||||||
|
|
||||||
level infer_universe(expr const & t, context const & ctx) {
|
level infer_universe(expr const & t, context const & ctx) {
|
||||||
lean_trace("type_check", tout << "infer universe\n" << t << "\n";);
|
lean_trace("type_check", tout << "infer universe\n" << t << "\n";);
|
||||||
expr u = normalize(infer_type(t, ctx), m_env, ctx);
|
expr u = normalize(infer_type(t, ctx), m_env, ctx);
|
||||||
|
@ -63,30 +77,30 @@ struct infer_type_fn {
|
||||||
return ty_level(u);
|
return ty_level(u);
|
||||||
if (u == Bool)
|
if (u == Bool)
|
||||||
return level();
|
return level();
|
||||||
std::ostringstream buffer;
|
format msg = format("type expected, ");
|
||||||
buffer << "type expected, ";
|
push_context(msg, ctx);
|
||||||
if (!empty(ctx))
|
msg += format{format("got:"), nl_indent(fmt()(t, ctx))};
|
||||||
buffer << "in context:\n" << ctx << "\n";
|
throw_exception(t, msg);
|
||||||
buffer << "got:\n" << t;
|
lean_unreachable();
|
||||||
throw exception(buffer.str());
|
return level();
|
||||||
}
|
}
|
||||||
|
|
||||||
expr check_pi(expr const & e, context const & ctx) {
|
expr check_pi(expr const & e, expr const & s, context const & ctx) {
|
||||||
if (is_pi(e))
|
if (is_pi(e))
|
||||||
return e;
|
return e;
|
||||||
expr r = normalize(e, m_env, ctx);
|
expr r = normalize(e, m_env, ctx);
|
||||||
if (is_pi(r))
|
if (is_pi(r))
|
||||||
return r;
|
return r;
|
||||||
std::ostringstream buffer;
|
format msg = format("function expected, ");
|
||||||
buffer << "function expected, ";
|
push_context(msg, ctx);
|
||||||
if (!empty(ctx))
|
msg += format{format("got:"), nl_indent(fmt()(s, ctx))};
|
||||||
buffer << "in context:\n" << ctx << "\n";
|
throw_exception(s, msg);
|
||||||
buffer << "got:\n" << e;
|
lean_unreachable();
|
||||||
throw exception(buffer.str());
|
return expr();
|
||||||
}
|
}
|
||||||
|
|
||||||
expr infer_pi(expr const & e, context const & ctx) {
|
expr infer_pi(expr const & e, context const & ctx) {
|
||||||
return check_pi(infer_type(e, ctx), ctx);
|
return check_pi(infer_type(e, ctx), e, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
expr infer_type(expr const & e, context const & ctx) {
|
expr infer_type(expr const & e, context const & ctx) {
|
||||||
|
@ -120,13 +134,14 @@ struct infer_type_fn {
|
||||||
expr const & c = arg(e, i);
|
expr const & c = arg(e, i);
|
||||||
expr c_t = infer_type(c, ctx);
|
expr c_t = infer_type(c, ctx);
|
||||||
if (!is_convertible(abst_domain(f_t), c_t, m_env, ctx)) {
|
if (!is_convertible(abst_domain(f_t), c_t, m_env, ctx)) {
|
||||||
std::ostringstream buffer;
|
format msg = format{format("type mismatch at argument "), format(i), format("of"),
|
||||||
buffer << "type mismatch at argument " << i << " of\n" << e
|
nl_indent(fmt()(e, ctx)), line(),
|
||||||
<< "\nexpected type:\n" << abst_domain(f_t)
|
format("expected type:"),
|
||||||
<< "\ngiven type:\n" << c_t;
|
nl_indent(fmt()(abst_domain(f_t), ctx)), line(),
|
||||||
if (!empty(ctx))
|
format("given type:"),
|
||||||
buffer << "\nin context:\n" << ctx;
|
nl_indent(fmt()(c_t, ctx))};
|
||||||
throw exception(buffer.str());
|
push_context(msg, ctx);
|
||||||
|
throw_exception(arg(e,i), msg);
|
||||||
}
|
}
|
||||||
if (closed(abst_body(f_t)))
|
if (closed(abst_body(f_t)))
|
||||||
f_t = abst_body(f_t);
|
f_t = abst_body(f_t);
|
||||||
|
@ -139,7 +154,7 @@ struct infer_type_fn {
|
||||||
r = f_t;
|
r = f_t;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
check_pi(f_t, ctx);
|
check_pi(f_t, e, ctx);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
|
@ -101,6 +101,20 @@ static void tst5() {
|
||||||
lean_assert(Implies(P, prop) == prop2);
|
lean_assert(Implies(P, prop) == prop2);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void tst6() {
|
||||||
|
environment env = mk_toplevel();
|
||||||
|
expr A = Const("A");
|
||||||
|
expr f = Const("f");
|
||||||
|
expr x = Const("x");
|
||||||
|
expr t = Fun({A, Type()}, Fun({f, arrow(Int, A)}, Fun({x, Int}, f(x, x))));
|
||||||
|
try {
|
||||||
|
infer_type(t, env);
|
||||||
|
lean_unreachable();
|
||||||
|
} catch (exception & ex) {
|
||||||
|
std::cout << "Error: " << ex.what() << "\n";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
int main() {
|
int main() {
|
||||||
continue_on_violation(true);
|
continue_on_violation(true);
|
||||||
tst1();
|
tst1();
|
||||||
|
@ -108,5 +122,6 @@ int main() {
|
||||||
tst3();
|
tst3();
|
||||||
tst4();
|
tst4();
|
||||||
tst5();
|
tst5();
|
||||||
|
tst6();
|
||||||
return has_violations() ? 1 : 0;
|
return has_violations() ? 1 : 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -108,6 +108,7 @@ static format g_space(" ");
|
||||||
static format g_lp("(");
|
static format g_lp("(");
|
||||||
static format g_rp(")");
|
static format g_rp(")");
|
||||||
static format g_comma(",");
|
static format g_comma(",");
|
||||||
|
static format g_colon(":");
|
||||||
static format g_dot(".");
|
static format g_dot(".");
|
||||||
format const & line() {
|
format const & line() {
|
||||||
return g_line;
|
return g_line;
|
||||||
|
@ -124,6 +125,9 @@ format const & rp() {
|
||||||
format const & comma() {
|
format const & comma() {
|
||||||
return g_comma;
|
return g_comma;
|
||||||
}
|
}
|
||||||
|
format const & colon() {
|
||||||
|
return g_colon;
|
||||||
|
}
|
||||||
format const & dot() {
|
format const & dot() {
|
||||||
return g_dot;
|
return g_dot;
|
||||||
}
|
}
|
||||||
|
|
|
@ -219,6 +219,7 @@ format const & space();
|
||||||
format const & lp();
|
format const & lp();
|
||||||
format const & rp();
|
format const & rp();
|
||||||
format const & comma();
|
format const & comma();
|
||||||
|
format const & colon();
|
||||||
format const & dot();
|
format const & dot();
|
||||||
format group(format const & f);
|
format group(format const & f);
|
||||||
format above(format const & f1, format const & f2);
|
format above(format const & f1, format const & f2);
|
||||||
|
|
Loading…
Reference in a new issue