Add pretty printer for Lean environment
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
f8e3563034
commit
2670e94398
19 changed files with 399 additions and 116 deletions
|
@ -1,4 +1,5 @@
|
|||
add_library(kernel expr.cpp max_sharing.cpp free_vars.cpp abstract.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
|
||||
pp.cpp)
|
||||
target_link_libraries(kernel ${EXTRA_LIBS})
|
||||
|
|
|
@ -127,16 +127,16 @@ public:
|
|||
return false;
|
||||
}
|
||||
}
|
||||
virtual void display(std::ostream & out) const { out << "<="; }
|
||||
virtual format pp() const { return format("<="); }
|
||||
virtual void display(std::ostream & out) const { out << "Le"; }
|
||||
virtual format pp() const { return format("Le"); }
|
||||
virtual unsigned hash() const { return 67; }
|
||||
};
|
||||
char const * int_le_value::g_kind = "<=";
|
||||
MK_BUILTIN(int_le_fn, int_le_value);
|
||||
|
||||
MK_CONSTANT(int_ge_fn, name(name("int"), "ge"));
|
||||
MK_CONSTANT(int_lt_fn, name(name("int"), "lt"));
|
||||
MK_CONSTANT(int_gt_fn, name(name("int"), "gt"));
|
||||
MK_CONSTANT(int_ge_fn, name(name("int"), "Ge"));
|
||||
MK_CONSTANT(int_lt_fn, name(name("int"), "Lt"));
|
||||
MK_CONSTANT(int_gt_fn, name(name("int"), "Gt"));
|
||||
|
||||
void add_int_theory(environment & env) {
|
||||
expr p = Int >> (Int >> Bool);
|
||||
|
|
|
@ -32,7 +32,7 @@ MK_CONSTANT(disj2_fn, name("Disj2"));
|
|||
MK_CONSTANT(disj_cases_fn, name("DisjCases"));
|
||||
MK_CONSTANT(symm_fn, name("Symm"));
|
||||
MK_CONSTANT(trans_fn, name("Trans"));
|
||||
MK_CONSTANT(xtrans_fn, name("xTrans"));
|
||||
MK_CONSTANT(trans_ext_fn, name("TransExt"));
|
||||
MK_CONSTANT(congr1_fn, name("Congr1"));
|
||||
MK_CONSTANT(congr2_fn, name("Congr2"));
|
||||
MK_CONSTANT(congr_fn, name("Congr"));
|
||||
|
@ -207,8 +207,8 @@ void add_basic_thms(environment & env) {
|
|||
Fun({{A, TypeU}, {a, A}, {b, A}, {c, A}, {H1, Eq(a,b)}, {H2, Eq(b,c)}},
|
||||
Subst(A, Fun({x, A}, Eq(a, x)), b, c, H1, H2)));
|
||||
|
||||
// xTrans: Pi (A: Type u) (B : Type u) (a : A) (b c : B) (H1 : a = b) (H2 : b = c), a = c
|
||||
env.add_theorem(xtrans_fn_name, Pi({{A, TypeU}, {B, TypeU}, {a, A}, {b, B}, {c, B}, {H1, Eq(a, b)}, {H2, Eq(b, c)}}, Eq(a, c)),
|
||||
// TransExt: Pi (A: Type u) (B : Type u) (a : A) (b c : B) (H1 : a = b) (H2 : b = c), a = c
|
||||
env.add_theorem(trans_ext_fn_name, Pi({{A, TypeU}, {B, TypeU}, {a, A}, {b, B}, {c, B}, {H1, Eq(a, b)}, {H2, Eq(b, c)}}, Eq(a, c)),
|
||||
Fun({{A, TypeU}, {B, TypeU}, {a, A}, {b, B}, {c, B}, {H1, Eq(a, b)}, {H2, Eq(b, c)}},
|
||||
Subst(B, Fun({x, B}, Eq(a, x)), b, c, H1, H2)));
|
||||
|
||||
|
@ -259,8 +259,8 @@ void add_basic_thms(environment & env) {
|
|||
// Congr : Pi (A : Type u) (B : A -> Type u) (f g : Pi (x : A) B x) (a b : A) (H1 : f = g) (H2 : a = b), f a = g b
|
||||
env.add_theorem(congr_fn_name, Pi({{A, TypeU}, {B, A_arrow_u}, {f, piABx}, {g, piABx}, {a, A}, {b, A}, {H1, Eq(f, g)}, {H2, Eq(a, b)}}, Eq(f(a), g(b))),
|
||||
Fun({{A, TypeU}, {B, A_arrow_u}, {f, piABx}, {g, piABx}, {a, A}, {b, A}, {H1, Eq(f, g)}, {H2, Eq(a, b)}},
|
||||
xTrans(B(a), B(b), f(a), f(b), g(b),
|
||||
Congr2(A, B, f, a, b, H2), Congr1(A, B, f, g, b, H1))));
|
||||
TransExt(B(a), B(b), f(a), f(b), g(b),
|
||||
Congr2(A, B, f, a, b, H2), Congr1(A, B, f, g, b, H1))));
|
||||
|
||||
|
||||
// ForallElim : Pi (A : Type u) (P : A -> bool) (H : (forall A P)) (a : A), P a
|
||||
|
|
|
@ -93,9 +93,9 @@ expr mk_trans_fn();
|
|||
/** \brief (Theorem) A : Type u, a b c : A, H1 : a = b, H2 : b = c |- Trans(A, a, b, c, H1, H2) : a = c */
|
||||
inline expr Trans(expr const & A, expr const & a, expr const & b, expr const & c, expr const & H1, expr const & H2) { return mk_app({mk_trans_fn(), A, a, b, c, H1, H2}); }
|
||||
|
||||
expr mk_xtrans_fn();
|
||||
/** \brief (Theorem) A : Type u, B : Type u, a : A, b c : B, H1 : a = b, H2 : b = c |- xTrans(A, B, a, b, c, H1, H2) : a = c */
|
||||
inline expr xTrans(expr const & A, expr const & B, expr const & a, expr const & b, expr const & c, expr const & H1, expr const & H2) { return mk_app({mk_xtrans_fn(), A, B, a, b, c, H1, H2}); }
|
||||
expr mk_trans_ext_fn();
|
||||
/** \brief (Theorem) A : Type u, B : Type u, a : A, b c : B, H1 : a = b, H2 : b = c |- TransExt(A, B, a, b, c, H1, H2) : a = c */
|
||||
inline expr TransExt(expr const & A, expr const & B, expr const & a, expr const & b, expr const & c, expr const & H1, expr const & H2) { return mk_app({mk_trans_ext_fn(), A, B, a, b, c, H1, H2}); }
|
||||
|
||||
expr mk_eqt_elim_fn();
|
||||
/** \brief (Theorem) a : Bool, H : a = True |- EqTElim(a, H) : a */
|
||||
|
|
|
@ -165,7 +165,7 @@ public:
|
|||
}
|
||||
virtual bool operator==(value const & other) const { return other.kind() == kind(); }
|
||||
virtual void display(std::ostream & out) const { out << "=>"; }
|
||||
virtual format pp() const { return format("=>"); }
|
||||
virtual format pp() const { return format("implies"); }
|
||||
virtual unsigned hash() const { return 23; }
|
||||
};
|
||||
char const * implies_fn_value::g_kind = "implies";
|
||||
|
|
|
@ -13,6 +13,7 @@ Author: Leonardo de Moura
|
|||
#include "safe_arith.h"
|
||||
#include "type_check.h"
|
||||
#include "exception.h"
|
||||
#include "pp.h"
|
||||
#include "debug.h"
|
||||
|
||||
namespace lean {
|
||||
|
@ -28,13 +29,17 @@ environment::definition::definition(name const & n, expr const & t, expr const &
|
|||
environment::definition::~definition() {
|
||||
}
|
||||
|
||||
void environment::definition::display_header(std::ostream & out) const {
|
||||
out << "Definition";
|
||||
void environment::definition::display(std::ostream & out) const {
|
||||
out << header() << " " << m_name << " : " << m_type << " := " << m_value << "\n";
|
||||
}
|
||||
|
||||
void environment::definition::display(std::ostream & out) const {
|
||||
display_header(out);
|
||||
out << " " << m_name << " : " << m_type << " := " << m_value << "\n";
|
||||
format pp_object_kind(char const * n) { return highlight(format(n), format::format_color::BLUE); }
|
||||
constexpr unsigned indentation = 2; // TODO: must be option
|
||||
|
||||
format environment::definition::pp(environment const & env) const {
|
||||
return nest(indentation,
|
||||
format{pp_object_kind(header()), format(" "), format(m_name), format(" : "), ::lean::pp(m_type, env), format(" :="),
|
||||
line(), ::lean::pp(m_value), format(".")});
|
||||
}
|
||||
|
||||
environment::fact::fact(name const & n, expr const & t):
|
||||
|
@ -45,9 +50,13 @@ environment::fact::fact(name const & n, expr const & t):
|
|||
environment::fact::~fact() {
|
||||
}
|
||||
|
||||
format environment::fact::pp(environment const & env) const {
|
||||
return nest(indentation,
|
||||
format{pp_object_kind(header()), format(" "), format(m_name), format(" : "), ::lean::pp(m_type, env), format(".")});
|
||||
}
|
||||
|
||||
void environment::fact::display(std::ostream & out) const {
|
||||
display_header(out);
|
||||
out << " " << m_name << " : " << m_type << "\n";
|
||||
out << header() << " " << m_name << " : " << m_type << "\n";
|
||||
}
|
||||
|
||||
/** \brief Implementation of the Lean environment. */
|
||||
|
@ -242,18 +251,18 @@ struct environment::imp {
|
|||
}
|
||||
}
|
||||
|
||||
void display_objects(std::ostream & out) const {
|
||||
void display_objects(std::ostream & out, environment const & env) const {
|
||||
for (object const * obj : m_objects) {
|
||||
obj->display(out);
|
||||
out << obj->pp(env) << "\n";
|
||||
}
|
||||
}
|
||||
|
||||
/** \brief Display universal variable constraints and objects stored in this environment and its parents. */
|
||||
void display(std::ostream & out) const {
|
||||
void display(std::ostream & out, environment const & env) const {
|
||||
if (has_parent())
|
||||
m_parent->display(out);
|
||||
m_parent->display(out, env);
|
||||
display_uvars(out);
|
||||
display_objects(out);
|
||||
display_objects(out, env);
|
||||
}
|
||||
|
||||
imp():
|
||||
|
@ -375,10 +384,10 @@ environment::object const * environment::get_object_ptr(name const & n) const {
|
|||
}
|
||||
|
||||
void environment::display_objects(std::ostream & out) const {
|
||||
m_imp->display_objects(out);
|
||||
m_imp->display_objects(out, *this);
|
||||
}
|
||||
|
||||
void environment::display(std::ostream & out) const {
|
||||
m_imp->display(out);
|
||||
m_imp->display(out, *this);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -77,6 +77,8 @@ public:
|
|||
It is just a place holder at this point.
|
||||
*/
|
||||
class object {
|
||||
protected:
|
||||
virtual char const * header() const = 0;
|
||||
public:
|
||||
object() {}
|
||||
object(object const & o) = delete;
|
||||
|
@ -85,6 +87,7 @@ public:
|
|||
virtual ~object() {}
|
||||
virtual object_kind kind() const = 0;
|
||||
virtual void display(std::ostream & out) const = 0;
|
||||
virtual format pp(environment const &) const = 0;
|
||||
virtual expr const & get_type() const = 0;
|
||||
};
|
||||
|
||||
|
@ -93,7 +96,7 @@ public:
|
|||
expr m_type;
|
||||
expr m_value;
|
||||
bool m_opaque;
|
||||
virtual void display_header(std::ostream & out) const;
|
||||
virtual char const * header() const { return "Definition"; }
|
||||
public:
|
||||
definition(name const & n, expr const & t, expr const & v, bool opaque);
|
||||
virtual ~definition();
|
||||
|
@ -103,10 +106,11 @@ public:
|
|||
expr const & get_value() const { return m_value; }
|
||||
bool is_opaque() const { return m_opaque; }
|
||||
virtual void display(std::ostream & out) const;
|
||||
virtual format pp(environment const & env) const;
|
||||
};
|
||||
|
||||
class theorem : public definition {
|
||||
virtual void display_header(std::ostream & out) const { out << "Theorem"; }
|
||||
virtual char const * header() const { return "Theorem"; }
|
||||
public:
|
||||
theorem(name const & n, expr const & t, expr const & v):definition(n, t, v, true) {}
|
||||
virtual object_kind kind() const { return object_kind::Theorem; }
|
||||
|
@ -116,24 +120,24 @@ public:
|
|||
protected:
|
||||
name m_name;
|
||||
expr m_type;
|
||||
virtual void display_header(std::ostream & out) const = 0;
|
||||
public:
|
||||
fact(name const & n, expr const & t);
|
||||
virtual ~fact();
|
||||
name const & get_name() const { return m_name; }
|
||||
virtual expr const & get_type() const { return m_type; }
|
||||
virtual void display(std::ostream & out) const;
|
||||
virtual format pp(environment const &) const;
|
||||
};
|
||||
|
||||
class axiom : public fact {
|
||||
virtual void display_header(std::ostream & out) const { out << "Axiom"; }
|
||||
virtual char const * header() const { return "Axiom"; }
|
||||
public:
|
||||
axiom(name const & n, expr const & t):fact(n, t) {}
|
||||
virtual object_kind kind() const { return object_kind::Axiom; }
|
||||
};
|
||||
|
||||
class variable : public fact {
|
||||
virtual void display_header(std::ostream & out) const { out << "Var"; }
|
||||
virtual char const * header() const { return "Variable"; }
|
||||
public:
|
||||
variable(name const & n, expr const & t):fact(n, t) {}
|
||||
virtual object_kind kind() const { return object_kind::Var; }
|
||||
|
|
|
@ -236,70 +236,4 @@ expr copy(expr const & a) {
|
|||
return expr();
|
||||
}
|
||||
}
|
||||
|
||||
lean::format pp_aux(lean::expr const & a) {
|
||||
using namespace lean;
|
||||
switch (a.kind()) {
|
||||
case expr_kind::Var:
|
||||
return format{format("#"), format(static_cast<int>(var_idx(a)))};
|
||||
case expr_kind::Constant:
|
||||
return format(const_name(a));
|
||||
case expr_kind::Value:
|
||||
return to_value(a).pp();
|
||||
case expr_kind::App:
|
||||
{
|
||||
format r;
|
||||
for (unsigned i = 0; i < num_args(a); i++) {
|
||||
if (i > 0) r += format(" ");
|
||||
r += pp_aux(arg(a, i));
|
||||
}
|
||||
return paren(r);
|
||||
}
|
||||
case expr_kind::Eq:
|
||||
return paren(format{pp_aux(eq_lhs(a)), format("="), pp_aux(eq_rhs(a))});
|
||||
case expr_kind::Let:
|
||||
return paren(format{
|
||||
highlight(format("let "), format::format_color::PINK), /* Use unicode lambda */
|
||||
paren(format{
|
||||
format(let_name(a)),
|
||||
format(" := "),
|
||||
pp_aux(let_value(a))}),
|
||||
format(" in "),
|
||||
pp_aux(let_body(a))});
|
||||
case expr_kind::Lambda:
|
||||
return paren(format{
|
||||
highlight(format("\u03BB "), format::format_color::PINK), /* Use unicode lambda */
|
||||
paren(format{
|
||||
format(abst_name(a)),
|
||||
format(" : "),
|
||||
pp_aux(abst_domain(a))}),
|
||||
format(" "),
|
||||
pp_aux(abst_body(a))});
|
||||
case expr_kind::Pi:
|
||||
return paren(format{
|
||||
highlight(format("\u03A0 "), format::format_color::ORANGE), /* Use unicode lambda */
|
||||
paren(format{
|
||||
format(abst_name(a)),
|
||||
format(" : "),
|
||||
pp_aux(abst_domain(a))}),
|
||||
format(" "),
|
||||
pp_aux(abst_body(a))});
|
||||
case expr_kind::Type:
|
||||
{
|
||||
std::stringstream ss;
|
||||
ss << ty_level(a);
|
||||
|
||||
return paren(format{format("Type "),
|
||||
format(ss.str())});
|
||||
}
|
||||
}
|
||||
lean_unreachable();
|
||||
return format();
|
||||
}
|
||||
|
||||
void print(lean::expr const & a) { std::cout << a << "\n"; }
|
||||
|
||||
void pp(lean::expr const & a) {
|
||||
lean::format const & f = pp_aux(a);
|
||||
std::cout << f << "\n";
|
||||
}
|
||||
|
|
|
@ -246,6 +246,7 @@ inline bool is_app(expr const & e) { return e.kind() == expr_kind::App;
|
|||
inline bool is_eq(expr const & e) { return e.kind() == expr_kind::Eq; }
|
||||
inline bool is_lambda(expr const & e) { return e.kind() == expr_kind::Lambda; }
|
||||
inline bool is_pi(expr const & e) { return e.kind() == expr_kind::Pi; }
|
||||
bool is_arrow(expr const & e);
|
||||
inline bool is_type(expr const & e) { return e.kind() == expr_kind::Type; }
|
||||
inline bool is_let(expr const & e) { return e.kind() == expr_kind::Let; }
|
||||
inline bool is_abstraction(expr const & e) { return is_lambda(e) || is_pi(e); }
|
||||
|
@ -471,5 +472,4 @@ template<typename F> expr update_eq(expr const & e, F f) {
|
|||
}
|
||||
// =======================================
|
||||
}
|
||||
void pp(lean::expr const & a);
|
||||
void print(lean::expr const & a);
|
||||
|
|
52
src/kernel/for_each.h
Normal file
52
src/kernel/for_each.h
Normal file
|
@ -0,0 +1,52 @@
|
|||
/*
|
||||
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 "expr.h"
|
||||
#include "sets.h"
|
||||
|
||||
namespace lean {
|
||||
template<typename F>
|
||||
class for_each_fn {
|
||||
expr_cell_offset_set m_visited;
|
||||
F m_f;
|
||||
|
||||
void apply(expr const & e, unsigned offset) {
|
||||
if (is_shared(e)) {
|
||||
expr_cell_offset p(e.raw(), offset);
|
||||
if (m_visited.find(p) != m_visited.end())
|
||||
return;
|
||||
m_visited.insert(p);
|
||||
}
|
||||
|
||||
m_f(e, offset);
|
||||
|
||||
switch (e.kind()) {
|
||||
case expr_kind::Constant: case expr_kind::Type: case expr_kind::Value: case expr_kind::Var:
|
||||
return;
|
||||
case expr_kind::App:
|
||||
std::for_each(begin_args(e), end_args(e), [=](expr const & arg){ return apply(arg, offset); });
|
||||
return;
|
||||
case expr_kind::Eq:
|
||||
apply(eq_lhs(e), offset);
|
||||
apply(eq_rhs(e), offset);
|
||||
return;
|
||||
case expr_kind::Lambda:
|
||||
case expr_kind::Pi:
|
||||
apply(abst_domain(e), offset);
|
||||
apply(abst_body(e), offset + 1);
|
||||
return;
|
||||
case expr_kind::Let:
|
||||
apply(let_value(e), offset);
|
||||
apply(let_body(e), offset + 1);
|
||||
return;
|
||||
}
|
||||
}
|
||||
public:
|
||||
for_each_fn(F const & f):m_f(f) {}
|
||||
void operator()(expr const & e) { apply(e, 0); }
|
||||
};
|
||||
}
|
|
@ -52,7 +52,8 @@ void level_cell::dealloc() {
|
|||
case level_kind::Max: static_cast<level_max*>(this)->~level_max(); delete[] reinterpret_cast<char*>(this); break;
|
||||
}
|
||||
}
|
||||
level::level(): m_ptr(new level_uvar(name("bot"))) { lean_assert(uvar_name(*this) == name("bot")); }
|
||||
static name g_bot_name("bot");
|
||||
level::level(): m_ptr(new level_uvar(g_bot_name)) { lean_assert(uvar_name(*this) == name("bot")); }
|
||||
level::level(name const & n): m_ptr(new level_uvar(n)) {}
|
||||
level::level(level const & l, unsigned k):m_ptr(new level_lift(l, k)) { lean_assert(is_uvar(l)); }
|
||||
level::level(level_cell * ptr): m_ptr(ptr) { lean_assert(m_ptr->get_rc() == 1); }
|
||||
|
@ -81,6 +82,10 @@ unsigned level::hash() const {
|
|||
return 0;
|
||||
}
|
||||
|
||||
bool level::is_bottom() const {
|
||||
return is_uvar(*this) && uvar_name(*this) == g_bot_name;
|
||||
}
|
||||
|
||||
level max_core(unsigned sz, level const * ls) {
|
||||
char * mem = new char[sizeof(level_max) + sz*sizeof(level)];
|
||||
return to_level(new (mem) level_max(sz, ls));
|
||||
|
@ -187,6 +192,30 @@ std::ostream & operator<<(std::ostream & out, level const & l) {
|
|||
return out;
|
||||
}
|
||||
|
||||
format pp(level const & l, char const * sep) {
|
||||
switch (kind(l)) {
|
||||
case level_kind::UVar:
|
||||
if (l.is_bottom())
|
||||
return format(0);
|
||||
else
|
||||
return format(uvar_name(l).to_string(sep));
|
||||
case level_kind::Lift:
|
||||
if (lift_of(l).is_bottom())
|
||||
return format(lift_offset(l));
|
||||
else
|
||||
return format{pp(lift_of(l), sep), format(" + "), format(lift_offset(l))};
|
||||
case level_kind::Max: {
|
||||
format r = pp(max_level(l, 0), sep);
|
||||
for (unsigned i = 1; i < max_size(l); i++) {
|
||||
r += format(" \u2293 ");
|
||||
r += pp(max_level(l, i), sep);
|
||||
}
|
||||
return r;
|
||||
}}
|
||||
lean_unreachable();
|
||||
return format();
|
||||
}
|
||||
|
||||
level max(std::initializer_list<level> const & l) {
|
||||
if (l.size() == 1)
|
||||
return *(l.begin());
|
||||
|
|
|
@ -7,6 +7,7 @@ Author: Leonardo de Moura
|
|||
#pragma once
|
||||
#include <iostream>
|
||||
#include "name.h"
|
||||
#include "format.h"
|
||||
|
||||
namespace lean {
|
||||
class environment;
|
||||
|
@ -34,6 +35,8 @@ public:
|
|||
|
||||
unsigned hash() const;
|
||||
|
||||
bool is_bottom() const;
|
||||
|
||||
friend level_kind kind (level const & l);
|
||||
friend name const & uvar_name (level const & l);
|
||||
friend level const & lift_of (level const & l);
|
||||
|
@ -61,4 +64,6 @@ inline bool is_max (level const & l) { return kind(l) == level_kind::Max; }
|
|||
|
||||
inline level const * max_begin_levels(level const & l) { return &max_level(l, 0); }
|
||||
inline level const * max_end_levels(level const & l) { return max_begin_levels(l) + max_size(l); }
|
||||
|
||||
format pp(level const & l, char const * sep = default_name_separator);
|
||||
}
|
||||
|
|
211
src/kernel/pp.cpp
Normal file
211
src/kernel/pp.cpp
Normal file
|
@ -0,0 +1,211 @@
|
|||
/*
|
||||
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 "pp.h"
|
||||
#include "environment.h"
|
||||
#include "scoped_set.h"
|
||||
#include "for_each.h"
|
||||
#include "instantiate.h"
|
||||
|
||||
namespace lean {
|
||||
struct pp_fn {
|
||||
environment const * m_env;
|
||||
|
||||
pp_fn(environment const * env):m_env(env) {}
|
||||
|
||||
unsigned indent() const { return 2; }
|
||||
char const * sep() const { return default_name_separator; }
|
||||
format pp_keyword(char const * k) { return highlight(format(k), format::format_color::ORANGE); }
|
||||
format pp_type_kwd() { return highlight(format("Type"), format::format_color::PINK); }
|
||||
format pp_eq_kwd() { return highlight(format(" = "), format::format_color::BLUE); }
|
||||
format pp_lambda_kwd() { return pp_keyword("\u03BB "); }
|
||||
format pp_lambda_arrow() { return format(" \u21D2"); }
|
||||
format pp_pi_kwd() { return pp_keyword("\u03A0 "); }
|
||||
format pp_type_arrow() { return format(" \u2192 "); }
|
||||
format pp_colon() { return format(" : "); }
|
||||
format pp_space() { return format(" "); }
|
||||
format pp_lp() { return format("("); }
|
||||
format pp_rp() { return format(")"); }
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
format pp_var(expr const & e) {
|
||||
unsigned vidx = var_idx(e);
|
||||
return compose(format("#"), format(vidx));
|
||||
}
|
||||
|
||||
format pp_constant(expr const & e) {
|
||||
return format(const_name(e).to_string(sep()));
|
||||
}
|
||||
|
||||
format pp_value(expr const & e) {
|
||||
return to_value(e).pp();
|
||||
}
|
||||
|
||||
format pp_type(expr const & e) {
|
||||
if (e == Type()) {
|
||||
return pp_type_kwd();
|
||||
} else {
|
||||
return format{pp_type_kwd(), pp_space(), ::lean::pp(ty_level(e), sep())};
|
||||
}
|
||||
}
|
||||
|
||||
format pp_child(expr const & c) {
|
||||
if (is_atomic(c))
|
||||
return pp(c);
|
||||
else
|
||||
return format{pp_lp(), pp(c), pp_rp()};
|
||||
}
|
||||
|
||||
format pp_eq(expr const & e) {
|
||||
return format{pp_child(eq_lhs(e)), pp_eq_kwd(), pp_child(eq_rhs(e))};
|
||||
}
|
||||
|
||||
format pp_app(expr const & e) {
|
||||
// TODO: infix operators, implicit arguments
|
||||
|
||||
// Prefix case
|
||||
format r = pp_child(arg(e, 0));
|
||||
for (unsigned i = 1; i < num_args(e); i++) {
|
||||
r += compose(line(), pp_child(arg(e, i)));
|
||||
}
|
||||
return group(nest(indent(), r));
|
||||
}
|
||||
|
||||
format pp_arrow_body(expr const & e) {
|
||||
if (is_atomic(e) || is_arrow(e))
|
||||
return pp(e);
|
||||
else
|
||||
return pp_child(e);
|
||||
}
|
||||
|
||||
struct is_used {};
|
||||
|
||||
/** \brief Return true iff \c n is already used in body */
|
||||
bool used(name const & n, expr const & body) {
|
||||
auto visitor = [&](expr const & e, unsigned offset) -> void {
|
||||
if (is_constant(e)) {
|
||||
if (const_name(e) == n)
|
||||
throw is_used();
|
||||
}
|
||||
};
|
||||
|
||||
try {
|
||||
for_each_fn<decltype(visitor)> f(visitor);
|
||||
f(body);
|
||||
return false;
|
||||
} catch (is_used) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
format pp_bname(expr const & binder) {
|
||||
return format(abst_name(binder).to_string(sep()));
|
||||
}
|
||||
|
||||
template<typename It>
|
||||
format pp_bnames(It const & begin, It const & end, bool use_line) {
|
||||
auto it = begin;
|
||||
format r = pp_bname(*it);
|
||||
++it;
|
||||
for (; it != end; ++it) {
|
||||
r += compose(use_line ? line() : pp_space(), pp_bname(*it));
|
||||
}
|
||||
return r;
|
||||
}
|
||||
|
||||
expr collect_nested(expr const & e, expr_kind k, buffer<expr> & r) {
|
||||
if (e.kind() == k) {
|
||||
r.push_back(e);
|
||||
name const & n = abst_name(e);
|
||||
name n1 = n;
|
||||
unsigned i = 1;
|
||||
while (used(n1, abst_body(e))) {
|
||||
n1 = name(n, i);
|
||||
i++;
|
||||
}
|
||||
expr b = instantiate_with_closed(abst_body(e), mk_constant(n1));
|
||||
return collect_nested(b, k, r);
|
||||
} else {
|
||||
return e;
|
||||
}
|
||||
}
|
||||
|
||||
format pp_abstraction(expr const & e) {
|
||||
if (is_arrow(e)) {
|
||||
return format{pp_child(abst_domain(e)), pp_type_arrow(), pp_arrow_body(abst_body(e))};
|
||||
} else {
|
||||
buffer<expr> nested;
|
||||
expr b = collect_nested(e, e.kind(), nested);
|
||||
lean_assert(b.kind() != e.kind());
|
||||
format head = is_lambda(e) ? pp_lambda_kwd() : pp_pi_kwd();
|
||||
format body_sep = is_lambda(e) ? pp_lambda_arrow() : format(",");
|
||||
|
||||
if (std::all_of(nested.begin(), nested.end(), [&](expr const & a) { return abst_domain(a) == abst_domain(e); })) {
|
||||
// Domain of all binders is the same
|
||||
format names = pp_bnames(nested.begin(), nested.end(), false);
|
||||
return group(nest(indent(), format{head, names, pp_colon(), pp(abst_domain(e)), body_sep, line(), pp(b)}));
|
||||
} else {
|
||||
auto it = nested.begin();
|
||||
auto end = nested.end();
|
||||
// PP binders in blocks (names ... : type)
|
||||
bool first = true;
|
||||
format bindings;
|
||||
while (it != end) {
|
||||
auto it2 = it;
|
||||
++it2;
|
||||
while (it2 != end && abst_domain(*it2) == abst_domain(*it)) {
|
||||
++it2;
|
||||
}
|
||||
format block = group(nest(indent(), format{pp_lp(), pp_bnames(it, it2, true), pp_colon(), pp(abst_domain(*it)), pp_rp()}));
|
||||
if (first) {
|
||||
bindings = block;
|
||||
first = false;
|
||||
} else {
|
||||
bindings += compose(line(), block);
|
||||
}
|
||||
it = it2;
|
||||
}
|
||||
return group(nest(indent(), format{head, group(bindings), body_sep, line(), pp(b)}));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
format pp_let(expr const & e) {
|
||||
return format("TODO");
|
||||
}
|
||||
|
||||
format pp(expr const & e) {
|
||||
switch (e.kind()) {
|
||||
case expr_kind::Var: return pp_var(e);
|
||||
case expr_kind::Constant: return pp_constant(e);
|
||||
case expr_kind::Value: return pp_value(e);
|
||||
case expr_kind::App: return pp_app(e);
|
||||
case expr_kind::Lambda:
|
||||
case expr_kind::Pi: return pp_abstraction(e);
|
||||
case expr_kind::Type: return pp_type(e);
|
||||
case expr_kind::Eq: return pp_eq(e);
|
||||
case expr_kind::Let: return pp_let(e);
|
||||
}
|
||||
lean_unreachable();
|
||||
return format();
|
||||
}
|
||||
|
||||
format operator()(expr const & e) {
|
||||
return pp(e);
|
||||
}
|
||||
};
|
||||
format pp(expr const & n) { return pp_fn(0)(n); }
|
||||
format pp(expr const & n, environment const & env) { return pp_fn(&env)(n); }
|
||||
}
|
15
src/kernel/pp.h
Normal file
15
src/kernel/pp.h
Normal file
|
@ -0,0 +1,15 @@
|
|||
/*
|
||||
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 "expr.h"
|
||||
#include "format.h"
|
||||
|
||||
namespace lean {
|
||||
class environment;
|
||||
format pp(expr const & n);
|
||||
format pp(expr const & n, environment const & env);
|
||||
}
|
|
@ -14,6 +14,8 @@ Author: Leonardo de Moura
|
|||
#include "abstract.h"
|
||||
#include "instantiate.h"
|
||||
#include "deep_copy.h"
|
||||
#include "arith.h"
|
||||
#include "pp.h"
|
||||
using namespace lean;
|
||||
|
||||
void tst1() {
|
||||
|
@ -45,11 +47,11 @@ void tst1_pp() {
|
|||
f = Var(0);
|
||||
expr fa = f(a);
|
||||
expr ty = Type();
|
||||
pp(fa(a)); std::cout << "\n";
|
||||
pp(fa(fa, fa)); std::cout << "\n";
|
||||
pp(mk_lambda("x", ty, Var(0))); std::cout << "\n";
|
||||
pp(mk_pi("x", ty, Var(0))); std::cout << "\n";
|
||||
pp(mk_pi("x", ty, mk_lambda("y", ty, Var(0)))); std::cout << "\n";
|
||||
std::cout << pp(fa(a)) << "\n";
|
||||
std::cout << pp(fa(fa, fa)) << "\n";
|
||||
std::cout << pp(mk_lambda("x", ty, Var(0))) << "\n";
|
||||
std::cout << pp(mk_pi("x", ty, Var(0))) << "\n";
|
||||
std::cout << pp(mk_pi("x", ty, mk_lambda("y", ty, Var(0)))) << "\n";
|
||||
std::cerr << "=============== PP =====================\n";
|
||||
}
|
||||
|
||||
|
@ -212,11 +214,9 @@ void tst5() {
|
|||
std::cout << "count(r1): " << count(r1) << "\n";
|
||||
std::cout << "count(r2): " << count(r2) << "\n";
|
||||
std::cout << "r1 = " << std::endl;
|
||||
pp(r1);
|
||||
std::cout << std::endl;
|
||||
std::cout << pp(r1) << std::endl;
|
||||
std::cout << "r2 = " << std::endl;
|
||||
pp(r2);
|
||||
std::cout << std::endl;
|
||||
std::cout << pp(r2) << std::endl;
|
||||
lean_assert(r1 == r2);
|
||||
}
|
||||
{
|
||||
|
@ -279,8 +279,8 @@ void tst8() {
|
|||
lean_assert(!closed(r));
|
||||
lean_assert(closed(mk_lambda("z", p, r)));
|
||||
|
||||
pp(mk_lambda("y", p, mk_app({mk_lambda("x", p, y), Var(0)}))); std::cout << std::endl;
|
||||
pp(mk_pi("x", p, f(f(f(a))))); std::cout << std::endl;
|
||||
std::cout << pp(mk_lambda("y", p, mk_app({mk_lambda("x", p, y), Var(0)}))) << std::endl;
|
||||
std::cout << pp(mk_pi("x", p, f(f(f(a))))) << std::endl;
|
||||
|
||||
}
|
||||
|
||||
|
@ -371,6 +371,12 @@ void tst15() {
|
|||
lean_assert(closed(l));
|
||||
}
|
||||
|
||||
void tst16() {
|
||||
std::cout << pp(Type() >> ((Int >> Int) >> (Int >> Bool))) << "\n";
|
||||
expr x = Const("x"); expr y = Const("y"); expr f = Const("f");
|
||||
std::cout << pp(Fun({{x, Int}, {y, Int}, {x, Bool}, {f, Pi({x,Bool}, x)}}, f(x, f(Eq(y,Var(3)), iVal(10))))) << "\n";
|
||||
}
|
||||
|
||||
int main() {
|
||||
continue_on_violation(true);
|
||||
std::cout << "sizeof(expr): " << sizeof(expr) << "\n";
|
||||
|
@ -392,6 +398,7 @@ int main() {
|
|||
tst13();
|
||||
tst14();
|
||||
tst15();
|
||||
tst16();
|
||||
std::cout << "done" << "\n";
|
||||
return has_violations() ? 1 : 0;
|
||||
}
|
||||
|
|
|
@ -12,10 +12,13 @@ using namespace lean;
|
|||
|
||||
static void tst1() {
|
||||
environment env;
|
||||
level l1 = env.define_uvar("l1", level());
|
||||
level l1 = env.define_uvar(name(name("l1"), "suffix"), level());
|
||||
level l2 = env.define_uvar("l2", l1 + 10);
|
||||
level l3 = env.define_uvar("l3", max(l2, l1 + 3));
|
||||
level l4 = env.define_uvar("l4", max(l1 + 8, max(l2 + 2, l3 + 20)));
|
||||
std::cout << pp(max(l1 + 8, max(l2 + 2, l3 + 20))) << "\n";
|
||||
std::cout << pp(level()) << "\n";
|
||||
std::cout << pp(level()+1) << "\n";
|
||||
env.display_uvars(std::cout);
|
||||
lean_assert(env.is_ge(l4 + 10, l3 + 30));
|
||||
lean_assert(!env.is_ge(l4 + 9, l3 + 30));
|
||||
|
|
|
@ -10,6 +10,7 @@ Author: Soonho Kong
|
|||
#include <algorithm>
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
#include "mpz.h"
|
||||
|
||||
namespace lean {
|
||||
/**
|
||||
|
@ -143,6 +144,7 @@ public:
|
|||
explicit format(std::string const & v):m_value(sexpr_text(sexpr(v))) {}
|
||||
explicit format(int v):m_value(sexpr_text(sexpr(v))) {}
|
||||
explicit format(double v):m_value(sexpr_text(sexpr(v))) {}
|
||||
explicit format(unsigned v):m_value(sexpr_text(sexpr(mpz(v)))) {}
|
||||
explicit format(name const & v):m_value(sexpr_text(sexpr(v))) {}
|
||||
explicit format(mpz const & v):m_value(sexpr_text(sexpr(v))) {}
|
||||
explicit format(mpq const & v):m_value(sexpr_text(sexpr(v))) {}
|
||||
|
|
|
@ -7,6 +7,7 @@ Author: Leonardo de Moura
|
|||
#include <cstring>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include "name.h"
|
||||
#include "debug.h"
|
||||
#include "rc.h"
|
||||
|
@ -247,7 +248,13 @@ size_t name::size(char const * sep) const {
|
|||
}
|
||||
|
||||
unsigned name::hash() const {
|
||||
return m_ptr->m_hash;
|
||||
return m_ptr ? m_ptr->m_hash : 11;
|
||||
}
|
||||
|
||||
std::string name::to_string(char const * sep) const {
|
||||
std::ostringstream s;
|
||||
imp::display(s, sep, m_ptr);
|
||||
return s.str();
|
||||
}
|
||||
|
||||
std::ostream & operator<<(std::ostream & out, name const & n) {
|
||||
|
|
|
@ -9,7 +9,7 @@ Author: Leonardo de Moura
|
|||
|
||||
namespace lean {
|
||||
|
||||
constexpr char const * default_name_separator = "::";
|
||||
constexpr char const * default_name_separator = "\u2055";
|
||||
enum class name_kind { ANONYMOUS, STRING, NUMERAL };
|
||||
|
||||
/**
|
||||
|
@ -47,6 +47,10 @@ public:
|
|||
char const * get_string() const;
|
||||
bool is_atomic() const;
|
||||
name get_prefix() const;
|
||||
/**
|
||||
\brief Convert this hierarchical name into a string using the given separator to "glue" the different limbs.
|
||||
*/
|
||||
std::string to_string(char const * sep = default_name_separator) const;
|
||||
/**
|
||||
\brief Size of the this name (in characters) when using the given separator.
|
||||
*/
|
||||
|
|
Loading…
Reference in a new issue