feat(kernel): add tag to kernel expressions
Frontends can used tags to associate expressions with line number information. The update_* procedures automatically propagate tags. Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
3196cd19dc
commit
2593f65ce1
3 changed files with 39 additions and 14 deletions
|
@ -31,12 +31,13 @@ unsigned hash_levels(levels const & ls) {
|
||||||
}
|
}
|
||||||
|
|
||||||
expr_cell::expr_cell(expr_kind k, unsigned h, bool has_mv, bool has_local, bool has_param_univ):
|
expr_cell::expr_cell(expr_kind k, unsigned h, bool has_mv, bool has_local, bool has_param_univ):
|
||||||
m_kind(static_cast<unsigned>(k)),
|
|
||||||
m_flags(0),
|
m_flags(0),
|
||||||
|
m_kind(static_cast<unsigned>(k)),
|
||||||
m_has_mv(has_mv),
|
m_has_mv(has_mv),
|
||||||
m_has_local(has_local),
|
m_has_local(has_local),
|
||||||
m_has_param_univ(has_param_univ),
|
m_has_param_univ(has_param_univ),
|
||||||
m_hash(h),
|
m_hash(h),
|
||||||
|
m_tag(nulltag),
|
||||||
m_rc(0) {
|
m_rc(0) {
|
||||||
// m_hash_alloc does not need to be a unique identifier.
|
// m_hash_alloc does not need to be a unique identifier.
|
||||||
// We want diverse hash codes because given expr_cell * c1 and expr_cell * c2,
|
// We want diverse hash codes because given expr_cell * c1 and expr_cell * c2,
|
||||||
|
@ -77,6 +78,10 @@ void expr_cell::set_is_arrow(bool flag) {
|
||||||
lean_assert(is_arrow() && *is_arrow() == flag);
|
lean_assert(is_arrow() && *is_arrow() == flag);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void expr_cell::set_tag(tag t) {
|
||||||
|
m_tag = t;
|
||||||
|
}
|
||||||
|
|
||||||
bool is_meta(expr const & e) {
|
bool is_meta(expr const & e) {
|
||||||
expr const * it = &e;
|
expr const * it = &e;
|
||||||
while (is_app(*it)) {
|
while (is_app(*it)) {
|
||||||
|
@ -376,9 +381,16 @@ unsigned get_free_var_range(expr const & e) {
|
||||||
|
|
||||||
bool operator==(expr const & a, expr const & b) { return expr_eq_fn()(a, b); }
|
bool operator==(expr const & a, expr const & b) { return expr_eq_fn()(a, b); }
|
||||||
|
|
||||||
|
static expr copy_tag(expr const & e, expr && new_e) {
|
||||||
|
tag t = e.get_tag();
|
||||||
|
if (t != nulltag)
|
||||||
|
new_e.set_tag(t);
|
||||||
|
return new_e;
|
||||||
|
}
|
||||||
|
|
||||||
expr update_app(expr const & e, expr const & new_fn, expr const & new_arg) {
|
expr update_app(expr const & e, expr const & new_fn, expr const & new_arg) {
|
||||||
if (!is_eqp(app_fn(e), new_fn) || !is_eqp(app_arg(e), new_arg))
|
if (!is_eqp(app_fn(e), new_fn) || !is_eqp(app_arg(e), new_arg))
|
||||||
return mk_app(new_fn, new_arg);
|
return copy_tag(e, mk_app(new_fn, new_arg));
|
||||||
else
|
else
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
@ -387,45 +399,45 @@ expr update_rev_app(expr const & e, unsigned num, expr const * new_args) {
|
||||||
expr const * it = &e;
|
expr const * it = &e;
|
||||||
for (unsigned i = 0; i < num - 1; i++) {
|
for (unsigned i = 0; i < num - 1; i++) {
|
||||||
if (!is_app(*it) || !is_eqp(app_arg(*it), new_args[i]))
|
if (!is_app(*it) || !is_eqp(app_arg(*it), new_args[i]))
|
||||||
return mk_rev_app(num, new_args);
|
return copy_tag(e, mk_rev_app(num, new_args));
|
||||||
it = &app_fn(*it);
|
it = &app_fn(*it);
|
||||||
}
|
}
|
||||||
if (!is_eqp(*it, new_args[num - 1]))
|
if (!is_eqp(*it, new_args[num - 1]))
|
||||||
return mk_rev_app(num, new_args);
|
return copy_tag(e, mk_rev_app(num, new_args));
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
expr update_binder(expr const & e, expr const & new_domain, expr const & new_body) {
|
expr update_binder(expr const & e, expr const & new_domain, expr const & new_body) {
|
||||||
if (!is_eqp(binder_domain(e), new_domain) || !is_eqp(binder_body(e), new_body))
|
if (!is_eqp(binder_domain(e), new_domain) || !is_eqp(binder_body(e), new_body))
|
||||||
return mk_binder(e.kind(), binder_name(e), new_domain, new_body, binder_info(e));
|
return copy_tag(e, mk_binder(e.kind(), binder_name(e), new_domain, new_body, binder_info(e)));
|
||||||
else
|
else
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
expr update_let(expr const & e, expr const & new_type, expr const & new_val, expr const & new_body) {
|
expr update_let(expr const & e, expr const & new_type, expr const & new_val, expr const & new_body) {
|
||||||
if (!is_eqp(let_type(e), new_type) || !is_eqp(let_value(e), new_val) || !is_eqp(let_body(e), new_body))
|
if (!is_eqp(let_type(e), new_type) || !is_eqp(let_value(e), new_val) || !is_eqp(let_body(e), new_body))
|
||||||
return mk_let(let_name(e), new_type, new_val, new_body);
|
return copy_tag(e, mk_let(let_name(e), new_type, new_val, new_body));
|
||||||
else
|
else
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
expr update_mlocal(expr const & e, expr const & new_type) {
|
expr update_mlocal(expr const & e, expr const & new_type) {
|
||||||
if (!is_eqp(mlocal_type(e), new_type))
|
if (!is_eqp(mlocal_type(e), new_type))
|
||||||
return mk_mlocal(is_metavar(e), mlocal_name(e), new_type);
|
return copy_tag(e, mk_mlocal(is_metavar(e), mlocal_name(e), new_type));
|
||||||
else
|
else
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
expr update_sort(expr const & e, level const & new_level) {
|
expr update_sort(expr const & e, level const & new_level) {
|
||||||
if (!is_eqp(sort_level(e), new_level))
|
if (!is_eqp(sort_level(e), new_level))
|
||||||
return mk_sort(new_level);
|
return copy_tag(e, mk_sort(new_level));
|
||||||
else
|
else
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
|
||||||
expr update_constant(expr const & e, levels const & new_levels) {
|
expr update_constant(expr const & e, levels const & new_levels) {
|
||||||
if (!is_eqp(const_level_params(e), new_levels))
|
if (!is_eqp(const_level_params(e), new_levels))
|
||||||
return mk_constant(const_name(e), new_levels);
|
return copy_tag(e, mk_constant(const_name(e), new_levels));
|
||||||
else
|
else
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
|
@ -440,7 +452,7 @@ expr update_macro(expr const & e, unsigned num, expr const * args) {
|
||||||
if (i == num)
|
if (i == num)
|
||||||
return e;
|
return e;
|
||||||
}
|
}
|
||||||
return mk_macro(to_macro(e)->m_definition, num, args);
|
return copy_tag(e, mk_macro(to_macro(e)->m_definition, num, args));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool is_atomic(expr const & e) {
|
bool is_atomic(expr const & e) {
|
||||||
|
|
|
@ -25,6 +25,10 @@ Author: Leonardo de Moura
|
||||||
#include "kernel/extension_context.h"
|
#include "kernel/extension_context.h"
|
||||||
|
|
||||||
namespace lean {
|
namespace lean {
|
||||||
|
// Tags are used by frontends to mark expressions. They are automatically propagated by
|
||||||
|
// procedures such as update_app, update_binder, etc.
|
||||||
|
typedef unsigned tag;
|
||||||
|
constexpr tag nulltag = std::numeric_limits<unsigned>::max();
|
||||||
class expr;
|
class expr;
|
||||||
/* =======================================
|
/* =======================================
|
||||||
Expressions
|
Expressions
|
||||||
|
@ -43,16 +47,17 @@ class expr;
|
||||||
enum class expr_kind { Var, Sort, Constant, Meta, Local, App, Lambda, Pi, Let, Macro };
|
enum class expr_kind { Var, Sort, Constant, Meta, Local, App, Lambda, Pi, Let, Macro };
|
||||||
class expr_cell {
|
class expr_cell {
|
||||||
protected:
|
protected:
|
||||||
unsigned short m_kind;
|
|
||||||
// The bits of the following field mean:
|
// The bits of the following field mean:
|
||||||
// 0-1 - term is an arrow (0 - not initialized, 1 - is arrow, 2 - is not arrow)
|
// 0-1 - term is an arrow (0 - not initialized, 1 - is arrow, 2 - is not arrow)
|
||||||
// Remark: we use atomic_uchar because these flags are computed lazily (i.e., after the expression is created)
|
// Remark: we use atomic_uchar because these flags are computed lazily (i.e., after the expression is created)
|
||||||
atomic_uchar m_flags;
|
atomic_uchar m_flags;
|
||||||
|
unsigned m_kind:8;
|
||||||
unsigned m_has_mv:1; // term contains metavariables
|
unsigned m_has_mv:1; // term contains metavariables
|
||||||
unsigned m_has_local:1; // term contains local constants
|
unsigned m_has_local:1; // term contains local constants
|
||||||
unsigned m_has_param_univ:1; // term constains parametric universe levels
|
unsigned m_has_param_univ:1; // term constains parametric universe levels
|
||||||
unsigned m_hash; // hash based on the structure of the expression (this is a good hash for structural equality)
|
unsigned m_hash; // hash based on the structure of the expression (this is a good hash for structural equality)
|
||||||
unsigned m_hash_alloc; // hash based on 'time' of allocation (this is a good hash for pointer-based equality)
|
unsigned m_hash_alloc; // hash based on 'time' of allocation (this is a good hash for pointer-based equality)
|
||||||
|
atomic_uint m_tag;
|
||||||
MK_LEAN_RC(); // Declare m_rc counter
|
MK_LEAN_RC(); // Declare m_rc counter
|
||||||
void dealloc();
|
void dealloc();
|
||||||
|
|
||||||
|
@ -69,6 +74,8 @@ public:
|
||||||
bool has_metavar() const { return m_has_mv; }
|
bool has_metavar() const { return m_has_mv; }
|
||||||
bool has_local() const { return m_has_local; }
|
bool has_local() const { return m_has_local; }
|
||||||
bool has_param_univ() const { return m_has_param_univ; }
|
bool has_param_univ() const { return m_has_param_univ; }
|
||||||
|
void set_tag(tag t);
|
||||||
|
tag get_tag() const { return m_tag; }
|
||||||
};
|
};
|
||||||
|
|
||||||
class macro_definition;
|
class macro_definition;
|
||||||
|
@ -110,6 +117,10 @@ public:
|
||||||
bool has_local() const { return m_ptr->has_local(); }
|
bool has_local() const { return m_ptr->has_local(); }
|
||||||
bool has_param_univ() const { return m_ptr->has_param_univ(); }
|
bool has_param_univ() const { return m_ptr->has_param_univ(); }
|
||||||
|
|
||||||
|
void set_tag(tag t) { m_ptr->set_tag(t); }
|
||||||
|
tag get_tag() const { return m_ptr->get_tag(); }
|
||||||
|
|
||||||
|
|
||||||
expr_cell * raw() const { return m_ptr; }
|
expr_cell * raw() const { return m_ptr; }
|
||||||
|
|
||||||
friend expr mk_var(unsigned idx);
|
friend expr mk_var(unsigned idx);
|
||||||
|
|
|
@ -388,8 +388,10 @@ int main() {
|
||||||
tst17();
|
tst17();
|
||||||
tst18();
|
tst18();
|
||||||
std::cout << "sizeof(expr): " << sizeof(expr) << "\n";
|
std::cout << "sizeof(expr): " << sizeof(expr) << "\n";
|
||||||
std::cout << "sizeof(expr_app): " << sizeof(expr_app) << "\n";
|
|
||||||
std::cout << "sizeof(expr_cell): " << sizeof(expr_cell) << "\n";
|
std::cout << "sizeof(expr_cell): " << sizeof(expr_cell) << "\n";
|
||||||
|
std::cout << "sizeof(expr_app): " << sizeof(expr_app) << "\n";
|
||||||
|
std::cout << "sizeof(expr_var): " << sizeof(expr_var) << "\n";
|
||||||
|
std::cout << "sizeof(expr_const): " << sizeof(expr_const) << "\n";
|
||||||
std::cout << "sizeof(optional<expr>): " << sizeof(optional<expr>) << "\n";
|
std::cout << "sizeof(optional<expr>): " << sizeof(optional<expr>) << "\n";
|
||||||
std::cout << "sizeof(optional<sexpr>): " << sizeof(optional<sexpr>) << "\n";
|
std::cout << "sizeof(optional<sexpr>): " << sizeof(optional<sexpr>) << "\n";
|
||||||
std::cout << "sizeof(std::function): " << sizeof(std::function<expr(expr const &, optional<expr> const &)>) << "\n";
|
std::cout << "sizeof(std::function): " << sizeof(std::function<expr(expr const &, optional<expr> const &)>) << "\n";
|
||||||
|
|
Loading…
Reference in a new issue