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-09-13 03:04:10 +00:00
|
|
|
#include "util/hash.h"
|
2013-11-19 02:41:08 +00:00
|
|
|
#include "util/buffer.h"
|
2013-09-13 03:04:10 +00:00
|
|
|
#include "kernel/expr.h"
|
|
|
|
#include "kernel/free_vars.h"
|
|
|
|
#include "kernel/expr_eq.h"
|
2013-09-27 01:24:45 +00:00
|
|
|
#include "kernel/metavar.h"
|
2013-07-22 11:03:46 +00:00
|
|
|
|
|
|
|
namespace lean {
|
2013-09-27 01:24:45 +00:00
|
|
|
local_entry::local_entry(unsigned s, unsigned n):m_kind(local_entry_kind::Lift), m_s(s), m_n(n) {}
|
|
|
|
local_entry::local_entry(unsigned s, expr const & v):m_kind(local_entry_kind::Inst), m_s(s), m_v(v) {}
|
|
|
|
local_entry::~local_entry() {}
|
|
|
|
bool local_entry::operator==(local_entry const & e) const {
|
|
|
|
if (m_kind != e.m_kind || m_s != e.m_s)
|
|
|
|
return false;
|
|
|
|
if (is_inst())
|
|
|
|
return m_v == e.m_v;
|
|
|
|
else
|
|
|
|
return m_n == e.m_n;
|
|
|
|
}
|
2013-09-13 01:25:38 +00:00
|
|
|
|
2013-07-22 11:03:46 +00:00
|
|
|
unsigned hash_args(unsigned size, expr const * args) {
|
|
|
|
return hash(size, [&args](unsigned i){ return args[i].hash(); });
|
|
|
|
}
|
|
|
|
|
2013-08-13 22:13:54 +00:00
|
|
|
static expr g_null;
|
|
|
|
|
|
|
|
expr const & expr::null() {
|
|
|
|
lean_assert(!g_null);
|
|
|
|
return g_null;
|
|
|
|
}
|
|
|
|
|
2013-09-13 01:25:38 +00:00
|
|
|
expr_cell::expr_cell(expr_kind k, unsigned h, bool has_mv):
|
2013-07-23 15:59:39 +00:00
|
|
|
m_kind(static_cast<unsigned>(k)),
|
2013-09-13 01:25:38 +00:00
|
|
|
m_flags(has_mv ? 4 : 0),
|
2013-07-22 11:03:46 +00:00
|
|
|
m_hash(h),
|
2013-11-14 10:31:54 +00:00
|
|
|
m_rc(1) {
|
|
|
|
// m_hash_alloc does not need to be a unique identifier.
|
|
|
|
// We want diverse hash codes such that given expr_cell * c1 and expr_cell * c2,
|
|
|
|
// if c1 != c2, then there is high probability c1->m_hash_alloc != c2->m_hash_alloc.
|
|
|
|
// Remark: using pointer address as a hash code is not a good idea.
|
|
|
|
// - each execution run will behave differently.
|
|
|
|
// - the hash is not diverse enough
|
|
|
|
static thread_local unsigned g_hash_alloc_counter = 0;
|
|
|
|
m_hash_alloc = g_hash_alloc_counter;
|
|
|
|
g_hash_alloc_counter++;
|
|
|
|
}
|
2013-07-22 11:03:46 +00:00
|
|
|
|
2013-11-19 02:41:08 +00:00
|
|
|
void expr_cell::dec_ref(expr & e, buffer<expr_cell*> & todelete) {
|
|
|
|
if (e) {
|
|
|
|
expr_cell * c = e.steal_ptr();
|
|
|
|
lean_assert(!e);
|
|
|
|
if (c->dec_ref_core())
|
|
|
|
todelete.push_back(c);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-22 11:03:46 +00:00
|
|
|
expr_var::expr_var(unsigned idx):
|
2013-09-13 01:25:38 +00:00
|
|
|
expr_cell(expr_kind::Var, idx, false),
|
2013-07-22 11:03:46 +00:00
|
|
|
m_vidx(idx) {}
|
|
|
|
|
2013-11-19 19:21:45 +00:00
|
|
|
expr_const::expr_const(name const & n, expr const & t):
|
|
|
|
expr_cell(expr_kind::Constant, n.hash(), t && t.has_metavar()),
|
|
|
|
m_name(n),
|
|
|
|
m_type(t) {}
|
|
|
|
void expr_const::dealloc(buffer<expr_cell*> & todelete) {
|
|
|
|
dec_ref(m_type, todelete);
|
|
|
|
delete(this);
|
|
|
|
}
|
2013-07-22 11:03:46 +00:00
|
|
|
|
2013-09-13 01:25:38 +00:00
|
|
|
expr_app::expr_app(unsigned num_args, bool has_mv):
|
|
|
|
expr_cell(expr_kind::App, 0, has_mv),
|
2013-07-22 11:03:46 +00:00
|
|
|
m_num_args(num_args) {
|
|
|
|
}
|
2013-11-19 02:41:08 +00:00
|
|
|
expr_app::~expr_app() {}
|
|
|
|
void expr_app::dealloc(buffer<expr_cell*> & todelete) {
|
|
|
|
unsigned i = m_num_args;
|
|
|
|
while (i > 0) {
|
|
|
|
--i;
|
|
|
|
dec_ref(m_args[i], todelete);
|
|
|
|
lean_assert(!m_args[i]);
|
|
|
|
}
|
|
|
|
delete[] reinterpret_cast<char*>(this);
|
2013-07-22 11:03:46 +00:00
|
|
|
}
|
2013-08-06 18:27:14 +00:00
|
|
|
expr mk_app(unsigned n, expr const * as) {
|
2013-07-23 18:47:36 +00:00
|
|
|
lean_assert(n > 1);
|
|
|
|
unsigned new_n;
|
|
|
|
unsigned n0 = 0;
|
|
|
|
expr const & arg0 = as[0];
|
2013-09-13 01:25:38 +00:00
|
|
|
bool has_mv = std::any_of(as, as + n, [](expr const & c) { return c.has_metavar(); });
|
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-08-07 15:17:33 +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)];
|
2013-09-13 01:25:38 +00:00
|
|
|
expr r(new (mem) expr_app(new_n, has_mv));
|
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-08-04 16:37:52 +00:00
|
|
|
expr_eq::expr_eq(expr const & lhs, expr const & rhs):
|
2013-09-13 01:25:38 +00:00
|
|
|
expr_cell(expr_kind::Eq, ::lean::hash(lhs.hash(), rhs.hash()), lhs.has_metavar() || rhs.has_metavar()),
|
2013-08-04 16:37:52 +00:00
|
|
|
m_lhs(lhs),
|
|
|
|
m_rhs(rhs) {
|
|
|
|
}
|
2013-09-04 06:15:37 +00:00
|
|
|
expr_eq::~expr_eq() {}
|
2013-11-19 02:41:08 +00:00
|
|
|
void expr_eq::dealloc(buffer<expr_cell*> & todelete) {
|
|
|
|
dec_ref(m_rhs, todelete);
|
|
|
|
dec_ref(m_lhs, todelete);
|
|
|
|
delete(this);
|
|
|
|
}
|
2013-07-24 04:49:19 +00:00
|
|
|
expr_abstraction::expr_abstraction(expr_kind k, name const & n, expr const & t, expr const & b):
|
2013-09-13 01:25:38 +00:00
|
|
|
expr_cell(k, ::lean::hash(t.hash(), b.hash()), t.has_metavar() || b.has_metavar()),
|
2013-07-22 11:03:46 +00:00
|
|
|
m_name(n),
|
2013-08-03 18:31:42 +00:00
|
|
|
m_domain(t),
|
2013-07-24 04:49:19 +00:00
|
|
|
m_body(b) {
|
2013-07-22 11:03:46 +00:00
|
|
|
}
|
2013-11-19 02:41:08 +00:00
|
|
|
void expr_abstraction::dealloc(buffer<expr_cell*> & todelete) {
|
|
|
|
dec_ref(m_body, todelete);
|
|
|
|
dec_ref(m_domain, todelete);
|
|
|
|
lean_assert(!m_body);
|
|
|
|
lean_assert(!m_domain);
|
|
|
|
delete(this);
|
|
|
|
}
|
2013-09-04 06:15:37 +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):
|
2013-09-13 01:25:38 +00:00
|
|
|
expr_cell(expr_kind::Type, l.hash(), false),
|
2013-07-30 02:44:26 +00:00
|
|
|
m_level(l) {
|
2013-07-22 11:03:46 +00:00
|
|
|
}
|
2013-09-04 06:15:37 +00:00
|
|
|
expr_type::~expr_type() {}
|
2013-09-06 17:06:26 +00:00
|
|
|
expr_let::expr_let(name const & n, expr const & t, expr const & v, expr const & b):
|
2013-09-13 01:25:38 +00:00
|
|
|
expr_cell(expr_kind::Let, ::lean::hash(v.hash(), b.hash()), v.has_metavar() || b.has_metavar() || (t && t.has_metavar())),
|
2013-08-04 16:37:52 +00:00
|
|
|
m_name(n),
|
2013-09-06 17:06:26 +00:00
|
|
|
m_type(t),
|
2013-08-04 16:37:52 +00:00
|
|
|
m_value(v),
|
|
|
|
m_body(b) {
|
|
|
|
}
|
2013-11-19 02:41:08 +00:00
|
|
|
void expr_let::dealloc(buffer<expr_cell*> & todelete) {
|
|
|
|
dec_ref(m_body, todelete);
|
|
|
|
dec_ref(m_value, todelete);
|
|
|
|
dec_ref(m_type, todelete);
|
|
|
|
delete(this);
|
|
|
|
}
|
2013-09-04 06:15:37 +00:00
|
|
|
expr_let::~expr_let() {}
|
2013-09-04 15:53:00 +00:00
|
|
|
name value::get_unicode_name() const { return get_name(); }
|
2013-09-20 04:26:01 +00:00
|
|
|
bool value::normalize(unsigned, expr const *, expr &) const { return false; }
|
2013-09-04 06:15:37 +00:00
|
|
|
void value::display(std::ostream & out) const { out << get_name(); }
|
|
|
|
bool value::operator==(value const & other) const { return typeid(*this) == typeid(other); }
|
2013-09-24 19:16:32 +00:00
|
|
|
bool value::operator<(value const & other) const {
|
|
|
|
if (get_name() == other.get_name())
|
|
|
|
return lt(other);
|
|
|
|
else
|
|
|
|
return get_name() < other.get_name();
|
|
|
|
}
|
2013-09-04 06:15:37 +00:00
|
|
|
format value::pp() const { return format(get_name()); }
|
2013-10-30 18:42:23 +00:00
|
|
|
format value::pp(bool unicode, bool) const { return unicode ? format(get_unicode_name()) : pp(); }
|
2013-09-04 06:15:37 +00:00
|
|
|
unsigned value::hash() const { return get_name().hash(); }
|
2013-11-27 20:58:54 +00:00
|
|
|
int value::push_lua(lua_State *) const { return 0; } // NOLINT
|
2013-08-03 23:09:21 +00:00
|
|
|
expr_value::expr_value(value & v):
|
2013-09-13 01:25:38 +00:00
|
|
|
expr_cell(expr_kind::Value, v.hash(), false),
|
2013-08-03 23:09:21 +00:00
|
|
|
m_val(v) {
|
|
|
|
m_val.inc_ref();
|
|
|
|
}
|
|
|
|
expr_value::~expr_value() {
|
|
|
|
m_val.dec_ref();
|
|
|
|
}
|
2013-10-02 00:25:17 +00:00
|
|
|
expr_metavar::expr_metavar(name const & n, local_context const & lctx):
|
2013-09-27 01:24:45 +00:00
|
|
|
expr_cell(expr_kind::MetaVar, n.hash(), true),
|
2013-10-02 00:25:17 +00:00
|
|
|
m_name(n), m_lctx(lctx) {}
|
2013-09-13 01:25:38 +00:00
|
|
|
expr_metavar::~expr_metavar() {}
|
2013-07-22 11:03:46 +00:00
|
|
|
|
|
|
|
void expr_cell::dealloc() {
|
2013-11-19 02:41:08 +00:00
|
|
|
try {
|
|
|
|
buffer<expr_cell*> todo;
|
|
|
|
todo.push_back(this);
|
|
|
|
while (!todo.empty()) {
|
|
|
|
expr_cell * it = todo.back();
|
|
|
|
todo.pop_back();
|
|
|
|
lean_assert(it->get_rc() == 0);
|
|
|
|
switch (it->kind()) {
|
|
|
|
case expr_kind::Var: delete static_cast<expr_var*>(it); break;
|
|
|
|
case expr_kind::Value: delete static_cast<expr_value*>(it); break;
|
|
|
|
case expr_kind::MetaVar: delete static_cast<expr_metavar*>(it); break;
|
|
|
|
case expr_kind::Type: delete static_cast<expr_type*>(it); break;
|
2013-11-19 19:21:45 +00:00
|
|
|
case expr_kind::Constant: static_cast<expr_const*>(it)->dealloc(todo); break;
|
2013-11-19 02:41:08 +00:00
|
|
|
case expr_kind::Eq: static_cast<expr_eq*>(it)->dealloc(todo); break;
|
|
|
|
case expr_kind::App: static_cast<expr_app*>(it)->dealloc(todo); break;
|
|
|
|
case expr_kind::Lambda: static_cast<expr_lambda*>(it)->dealloc(todo); break;
|
|
|
|
case expr_kind::Pi: static_cast<expr_pi*>(it)->dealloc(todo); break;
|
|
|
|
case expr_kind::Let: static_cast<expr_let*>(it)->dealloc(todo); break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
} catch (std::bad_alloc&) {
|
|
|
|
// We need this catch, because push_back may fail when expanding the buffer.
|
|
|
|
// In this case, we avoid the crash, and "accept" the memory leak.
|
2013-07-22 11:03:46 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-08-06 18:27:14 +00:00
|
|
|
expr mk_type() {
|
|
|
|
static thread_local expr r = mk_type(level());
|
2013-08-04 02:57:06 +00:00
|
|
|
return r;
|
|
|
|
}
|
|
|
|
|
2013-07-22 23:40:17 +00:00
|
|
|
bool operator==(expr const & a, expr const & b) {
|
2013-08-23 16:36:40 +00:00
|
|
|
return expr_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-12-06 03:00:31 +00:00
|
|
|
bool is_eq(expr const & e, expr & lhs, expr & rhs) {
|
|
|
|
if (is_eq(e)) {
|
|
|
|
lhs = eq_lhs(e);
|
|
|
|
rhs = eq_rhs(e);
|
|
|
|
return true;
|
|
|
|
} else {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2013-07-24 17:14:22 +00:00
|
|
|
expr copy(expr const & a) {
|
|
|
|
switch (a.kind()) {
|
2013-08-06 18:27:14 +00:00
|
|
|
case expr_kind::Var: return mk_var(var_idx(a));
|
2013-11-19 19:21:45 +00:00
|
|
|
case expr_kind::Constant: return mk_constant(const_name(a), const_type(a));
|
2013-08-06 18:27:14 +00:00
|
|
|
case expr_kind::Type: return mk_type(ty_level(a));
|
|
|
|
case expr_kind::Value: return mk_value(static_cast<expr_value*>(a.raw())->m_val);
|
|
|
|
case expr_kind::App: return mk_app(num_args(a), begin_args(a));
|
|
|
|
case expr_kind::Eq: return mk_eq(eq_lhs(a), eq_rhs(a));
|
|
|
|
case expr_kind::Lambda: return mk_lambda(abst_name(a), abst_domain(a), abst_body(a));
|
|
|
|
case expr_kind::Pi: return mk_pi(abst_name(a), abst_domain(a), abst_body(a));
|
2013-09-06 17:06:26 +00:00
|
|
|
case expr_kind::Let: return mk_let(let_name(a), let_type(a), let_value(a), let_body(a));
|
2013-10-02 00:25:17 +00:00
|
|
|
case expr_kind::MetaVar: return mk_metavar(metavar_name(a), metavar_lctx(a));
|
2013-07-24 17:14:22 +00:00
|
|
|
}
|
2013-11-11 17:19:38 +00:00
|
|
|
lean_unreachable(); // LCOV_EXCL_LINE
|
2013-07-24 17:14:22 +00:00
|
|
|
}
|
2013-07-22 11:03:46 +00:00
|
|
|
}
|