2013-07-22 11:03:46 +00:00
|
|
|
/*
|
|
|
|
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
|
|
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
|
|
|
|
Author: Leonardo de Moura
|
2013-08-01 22:42:06 +00:00
|
|
|
Soonho Kong
|
2013-07-22 11:03:46 +00:00
|
|
|
*/
|
|
|
|
#include <vector>
|
2013-08-01 22:42:06 +00:00
|
|
|
#include <sstream>
|
2013-07-22 11:03:46 +00:00
|
|
|
#include "expr.h"
|
2013-07-30 08:39:29 +00:00
|
|
|
#include "free_vars.h"
|
2013-07-23 17:09:04 +00:00
|
|
|
#include "sets.h"
|
2013-07-22 11:03:46 +00:00
|
|
|
#include "hash.h"
|
2013-08-01 22:42:06 +00:00
|
|
|
#include "format.h"
|
2013-07-22 11:03:46 +00:00
|
|
|
|
|
|
|
namespace lean {
|
|
|
|
|
|
|
|
unsigned hash_args(unsigned size, expr const * args) {
|
|
|
|
return hash(size, [&args](unsigned i){ return args[i].hash(); });
|
|
|
|
}
|
|
|
|
|
|
|
|
expr_cell::expr_cell(expr_kind k, unsigned h):
|
2013-07-23 15:59:39 +00:00
|
|
|
m_kind(static_cast<unsigned>(k)),
|
2013-07-24 08:16:35 +00:00
|
|
|
m_flags(0),
|
2013-07-22 11:03:46 +00:00
|
|
|
m_hash(h),
|
|
|
|
m_rc(1) {}
|
|
|
|
|
|
|
|
expr_var::expr_var(unsigned idx):
|
|
|
|
expr_cell(expr_kind::Var, idx),
|
|
|
|
m_vidx(idx) {}
|
|
|
|
|
|
|
|
expr_const::expr_const(name const & n, unsigned pos):
|
2013-07-22 20:04:27 +00:00
|
|
|
expr_cell(expr_kind::Constant, n.hash()),
|
2013-07-22 11:03:46 +00:00
|
|
|
m_name(n),
|
|
|
|
m_pos(pos) {}
|
|
|
|
|
|
|
|
expr_app::expr_app(unsigned num_args):
|
|
|
|
expr_cell(expr_kind::App, 0),
|
|
|
|
m_num_args(num_args) {
|
|
|
|
}
|
|
|
|
expr_app::~expr_app() {
|
|
|
|
for (unsigned i = 0; i < m_num_args; i++)
|
|
|
|
(m_args+i)->~expr();
|
|
|
|
}
|
2013-07-23 18:47:36 +00:00
|
|
|
expr app(unsigned n, expr const * as) {
|
|
|
|
lean_assert(n > 1);
|
|
|
|
unsigned new_n;
|
|
|
|
unsigned n0 = 0;
|
|
|
|
expr const & arg0 = as[0];
|
2013-07-24 02:27:13 +00:00
|
|
|
// Remark: we represent ((app a b) c) as (app a b c)
|
2013-07-22 11:03:46 +00:00
|
|
|
if (is_app(arg0)) {
|
2013-07-23 18:47:36 +00:00
|
|
|
n0 = num_args(arg0);
|
|
|
|
new_n = n + n0 - 1;
|
2013-07-22 11:03:46 +00:00
|
|
|
}
|
|
|
|
else {
|
2013-07-23 18:47:36 +00:00
|
|
|
new_n = n;
|
2013-07-22 11:03:46 +00:00
|
|
|
}
|
2013-07-23 18:47:36 +00:00
|
|
|
char * mem = new char[sizeof(expr_app) + new_n*sizeof(expr)];
|
|
|
|
expr r(new (mem) expr_app(new_n));
|
2013-07-22 11:03:46 +00:00
|
|
|
expr * m_args = to_app(r)->m_args;
|
|
|
|
unsigned i = 0;
|
|
|
|
unsigned j = 0;
|
2013-07-23 18:47:36 +00:00
|
|
|
if (new_n != n) {
|
|
|
|
for (; i < n0; i++)
|
|
|
|
new (m_args+i) expr(arg(arg0, i));
|
2013-07-22 11:03:46 +00:00
|
|
|
j++;
|
|
|
|
}
|
2013-07-23 18:47:36 +00:00
|
|
|
for (; i < new_n; ++i, ++j) {
|
|
|
|
lean_assert(j < n);
|
|
|
|
new (m_args+i) expr(as[j]);
|
2013-07-22 11:03:46 +00:00
|
|
|
}
|
2013-07-23 18:47:36 +00:00
|
|
|
to_app(r)->m_hash = hash_args(new_n, m_args);
|
2013-07-22 11:03:46 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2013-07-24 04:49:19 +00:00
|
|
|
expr_abstraction::expr_abstraction(expr_kind k, name const & n, expr const & t, expr const & b):
|
|
|
|
expr_cell(k, ::lean::hash(t.hash(), b.hash())),
|
2013-07-22 11:03:46 +00:00
|
|
|
m_name(n),
|
|
|
|
m_type(t),
|
2013-07-24 04:49:19 +00:00
|
|
|
m_body(b) {
|
2013-07-22 11:03:46 +00:00
|
|
|
}
|
|
|
|
expr_lambda::expr_lambda(name const & n, expr const & t, expr const & e):
|
|
|
|
expr_abstraction(expr_kind::Lambda, n, t, e) {}
|
|
|
|
expr_pi::expr_pi(name const & n, expr const & t, expr const & e):
|
|
|
|
expr_abstraction(expr_kind::Pi, n, t, e) {}
|
|
|
|
|
2013-07-30 02:44:26 +00:00
|
|
|
expr_type::expr_type(level const & l):
|
|
|
|
expr_cell(expr_kind::Type, l.hash()),
|
|
|
|
m_level(l) {
|
2013-07-22 11:03:46 +00:00
|
|
|
}
|
|
|
|
expr_type::~expr_type() {
|
|
|
|
}
|
|
|
|
expr_numeral::expr_numeral(mpz const & n):
|
|
|
|
expr_cell(expr_kind::Numeral, n.hash()),
|
|
|
|
m_numeral(n) {}
|
|
|
|
|
|
|
|
void expr_cell::dealloc() {
|
2013-07-23 15:59:39 +00:00
|
|
|
switch (kind()) {
|
2013-07-22 11:03:46 +00:00
|
|
|
case expr_kind::Var: delete static_cast<expr_var*>(this); break;
|
|
|
|
case expr_kind::Constant: delete static_cast<expr_const*>(this); break;
|
|
|
|
case expr_kind::App: static_cast<expr_app*>(this)->~expr_app(); delete[] reinterpret_cast<char*>(this); break;
|
|
|
|
case expr_kind::Lambda: delete static_cast<expr_lambda*>(this); break;
|
|
|
|
case expr_kind::Pi: delete static_cast<expr_pi*>(this); break;
|
2013-07-30 02:44:26 +00:00
|
|
|
case expr_kind::Type: delete static_cast<expr_type*>(this); break;
|
2013-07-22 11:03:46 +00:00
|
|
|
case expr_kind::Numeral: delete static_cast<expr_numeral*>(this); break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-24 07:45:38 +00:00
|
|
|
class eq_fn {
|
2013-07-23 16:12:15 +00:00
|
|
|
expr_cell_pair_set m_eq_visited;
|
2013-07-24 07:45:38 +00:00
|
|
|
|
2013-07-23 16:12:15 +00:00
|
|
|
bool apply(expr const & a, expr const & b) {
|
|
|
|
if (eqp(a, b)) return true;
|
|
|
|
if (a.hash() != b.hash()) return false;
|
|
|
|
if (a.kind() != b.kind()) return false;
|
2013-07-23 18:47:36 +00:00
|
|
|
if (is_var(a)) return var_idx(a) == var_idx(b);
|
2013-07-23 16:12:15 +00:00
|
|
|
if (is_shared(a) && is_shared(b)) {
|
|
|
|
auto p = std::make_pair(a.raw(), b.raw());
|
|
|
|
if (m_eq_visited.find(p) != m_eq_visited.end())
|
|
|
|
return true;
|
|
|
|
m_eq_visited.insert(p);
|
|
|
|
}
|
|
|
|
switch (a.kind()) {
|
|
|
|
case expr_kind::Var: lean_unreachable(); return true;
|
2013-07-23 18:47:36 +00:00
|
|
|
case expr_kind::Constant: return const_name(a) == const_name(b);
|
2013-07-23 16:12:15 +00:00
|
|
|
case expr_kind::App:
|
2013-07-23 18:47:36 +00:00
|
|
|
if (num_args(a) != num_args(b))
|
2013-07-22 11:03:46 +00:00
|
|
|
return false;
|
2013-07-23 18:47:36 +00:00
|
|
|
for (unsigned i = 0; i < num_args(a); i++)
|
|
|
|
if (!apply(arg(a, i), arg(b, i)))
|
2013-07-23 16:12:15 +00:00
|
|
|
return false;
|
|
|
|
return true;
|
|
|
|
case expr_kind::Lambda:
|
|
|
|
case expr_kind::Pi:
|
|
|
|
// Lambda and Pi
|
|
|
|
// Remark: we ignore get_abs_name because we want alpha-equivalence
|
2013-07-24 04:49:19 +00:00
|
|
|
return apply(abst_type(a), abst_type(b)) && apply(abst_body(a), abst_body(b));
|
2013-07-30 02:44:26 +00:00
|
|
|
case expr_kind::Type: return ty_level(a) == ty_level(b);
|
2013-07-23 18:47:36 +00:00
|
|
|
case expr_kind::Numeral: return num_value(a) == num_value(b);
|
2013-07-22 11:03:46 +00:00
|
|
|
}
|
2013-07-23 16:12:15 +00:00
|
|
|
lean_unreachable();
|
|
|
|
return false;
|
2013-07-22 11:03:46 +00:00
|
|
|
}
|
2013-07-24 07:45:38 +00:00
|
|
|
public:
|
|
|
|
bool operator()(expr const & a, expr const & b) {
|
|
|
|
return apply(a, b);
|
|
|
|
}
|
2013-07-23 16:12:15 +00:00
|
|
|
};
|
|
|
|
|
2013-07-22 23:40:17 +00:00
|
|
|
bool operator==(expr const & a, expr const & b) {
|
2013-07-24 07:45:38 +00:00
|
|
|
return eq_fn()(a, b);
|
2013-07-22 11:03:46 +00:00
|
|
|
}
|
|
|
|
|
2013-08-02 04:28:26 +00:00
|
|
|
bool is_arrow(expr const & t) {
|
|
|
|
return is_pi(t) && !has_free_var(abst_body(t), 0);
|
|
|
|
}
|
|
|
|
|
2013-07-22 11:03:46 +00:00
|
|
|
// Low-level pretty printer
|
|
|
|
std::ostream & operator<<(std::ostream & out, expr const & a) {
|
|
|
|
switch (a.kind()) {
|
2013-07-23 18:47:36 +00:00
|
|
|
case expr_kind::Var: out << "#" << var_idx(a); break;
|
|
|
|
case expr_kind::Constant: out << const_name(a); break;
|
2013-07-22 11:03:46 +00:00
|
|
|
case expr_kind::App:
|
|
|
|
out << "(";
|
2013-07-23 18:47:36 +00:00
|
|
|
for (unsigned i = 0; i < num_args(a); i++) {
|
2013-07-22 11:03:46 +00:00
|
|
|
if (i > 0) out << " ";
|
2013-07-23 18:47:36 +00:00
|
|
|
out << arg(a, i);
|
2013-07-22 11:03:46 +00:00
|
|
|
}
|
|
|
|
out << ")";
|
|
|
|
break;
|
2013-07-24 04:49:19 +00:00
|
|
|
case expr_kind::Lambda: out << "(fun (" << abst_name(a) << " : " << abst_type(a) << ") " << abst_body(a) << ")"; break;
|
2013-07-30 08:39:29 +00:00
|
|
|
case expr_kind::Pi:
|
2013-08-02 04:28:26 +00:00
|
|
|
if (!is_arrow(a))
|
2013-07-30 08:39:29 +00:00
|
|
|
out << "(pi (" << abst_name(a) << " : " << abst_type(a) << ") " << abst_body(a) << ")";
|
2013-08-02 04:28:26 +00:00
|
|
|
else if (!is_arrow(abst_type(a)))
|
2013-07-30 08:39:29 +00:00
|
|
|
out << abst_type(a) << " -> " << abst_body(a);
|
2013-08-02 04:28:26 +00:00
|
|
|
else
|
|
|
|
out << "(" << abst_type(a) << ") -> " << abst_body(a);
|
2013-07-30 08:39:29 +00:00
|
|
|
break;
|
|
|
|
case expr_kind::Type: {
|
|
|
|
level const & l = ty_level(a);
|
|
|
|
if (is_uvar(l) && uvar_idx(l) == 0)
|
|
|
|
out << "Type";
|
|
|
|
else
|
|
|
|
out << "(Type " << ty_level(a) << ")";
|
|
|
|
break;
|
|
|
|
}
|
2013-07-23 18:47:36 +00:00
|
|
|
case expr_kind::Numeral: out << num_value(a); break;
|
2013-07-22 11:03:46 +00:00
|
|
|
}
|
|
|
|
return out;
|
|
|
|
}
|
|
|
|
|
2013-07-24 17:14:22 +00:00
|
|
|
expr copy(expr const & a) {
|
|
|
|
switch (a.kind()) {
|
|
|
|
case expr_kind::Var: return var(var_idx(a));
|
|
|
|
case expr_kind::Constant: return constant(const_name(a), const_pos(a));
|
2013-07-30 02:44:26 +00:00
|
|
|
case expr_kind::Type: return type(ty_level(a));
|
2013-07-24 17:14:22 +00:00
|
|
|
case expr_kind::Numeral: return numeral(num_value(a));
|
|
|
|
case expr_kind::App: return app(num_args(a), begin_args(a));
|
|
|
|
case expr_kind::Lambda: return lambda(abst_name(a), abst_type(a), abst_body(a));
|
|
|
|
case expr_kind::Pi: return pi(abst_name(a), abst_type(a), abst_body(a));
|
|
|
|
}
|
|
|
|
lean_unreachable();
|
|
|
|
return expr();
|
|
|
|
}
|
2013-07-22 11:03:46 +00:00
|
|
|
}
|
2013-07-26 02:13:45 +00:00
|
|
|
|
2013-08-01 22:42:06 +00:00
|
|
|
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::App:
|
|
|
|
{
|
2013-08-02 01:54:06 +00:00
|
|
|
format r;
|
2013-08-01 22:42:06 +00:00
|
|
|
for (unsigned i = 0; i < num_args(a); i++) {
|
|
|
|
if (i > 0) r += format(" ");
|
|
|
|
r += pp_aux(arg(a, i));
|
|
|
|
}
|
2013-08-02 01:54:06 +00:00
|
|
|
return paren(r);
|
2013-08-01 22:42:06 +00:00
|
|
|
}
|
|
|
|
case expr_kind::Lambda:
|
2013-08-02 01:54:06 +00:00
|
|
|
return paren(format{
|
|
|
|
highlight(format("\u03BB "), format::format_color::PINK), /* Use unicode lambda */
|
|
|
|
paren(format{
|
|
|
|
format(abst_name(a)),
|
|
|
|
format(" : "),
|
|
|
|
pp_aux(abst_type(a))}),
|
|
|
|
format(" "),
|
|
|
|
pp_aux(abst_body(a))});
|
2013-08-01 22:42:06 +00:00
|
|
|
case expr_kind::Pi:
|
2013-08-02 01:54:06 +00:00
|
|
|
return paren(format{
|
|
|
|
highlight(format("\u03A0 "), format::format_color::ORANGE), /* Use unicode lambda */
|
|
|
|
paren(format{
|
|
|
|
format(abst_name(a)),
|
|
|
|
format(" : "),
|
|
|
|
pp_aux(abst_type(a))}),
|
|
|
|
format(" "),
|
|
|
|
pp_aux(abst_body(a))});
|
2013-08-01 22:42:06 +00:00
|
|
|
case expr_kind::Type:
|
|
|
|
{
|
|
|
|
std::stringstream ss;
|
|
|
|
ss << ty_level(a);
|
2013-08-02 01:54:06 +00:00
|
|
|
|
|
|
|
return paren(format{format("Type "),
|
|
|
|
format(ss.str())});
|
2013-08-01 22:42:06 +00:00
|
|
|
}
|
|
|
|
case expr_kind::Numeral:
|
|
|
|
return format(num_value(a));
|
|
|
|
}
|
|
|
|
lean_unreachable();
|
|
|
|
return format();
|
|
|
|
}
|
|
|
|
|
|
|
|
void pp(lean::expr const & a) {
|
|
|
|
lean::format const & f = pp_aux(a);
|
|
|
|
std::cout << f;
|
|
|
|
}
|