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
|
|
|
|
*/
|
|
|
|
#pragma once
|
|
|
|
#include <iostream>
|
|
|
|
#include <limits>
|
|
|
|
#include "rc.h"
|
2013-07-23 17:16:47 +00:00
|
|
|
#include "name.h"
|
2013-07-22 11:03:46 +00:00
|
|
|
#include "mpz.h"
|
2013-07-30 02:44:26 +00:00
|
|
|
#include "level.h"
|
2013-07-23 17:16:47 +00:00
|
|
|
#include "hash.h"
|
2013-07-30 04:28:22 +00:00
|
|
|
#include "buffer.h"
|
2013-07-22 11:03:46 +00:00
|
|
|
|
|
|
|
namespace lean {
|
|
|
|
/* =======================================
|
|
|
|
Expressions
|
|
|
|
expr ::= Var idx
|
|
|
|
| Constant name
|
|
|
|
| App [expr]
|
|
|
|
| Lambda name expr expr
|
|
|
|
| Pi name expr expr
|
|
|
|
| Type universe
|
|
|
|
| Numeral value
|
|
|
|
|
|
|
|
TODO: add meta-variables, let, constructor references and match.
|
|
|
|
|
|
|
|
The main API is divided in the following sections
|
|
|
|
- Testers
|
|
|
|
- Constructors
|
|
|
|
- Accessors
|
|
|
|
- Miscellaneous
|
|
|
|
======================================= */
|
2013-07-30 02:49:34 +00:00
|
|
|
enum class expr_kind { Var, Constant, App, Lambda, Pi, Type, Numeral };
|
2013-07-22 11:03:46 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
\brief Base class used to represent expressions.
|
|
|
|
|
|
|
|
In principle, the expr_cell class and subclasses should be located in the .cpp file.
|
|
|
|
However, this is performance critical code, and we want to be able to have
|
|
|
|
inline definitions.
|
|
|
|
*/
|
|
|
|
class expr_cell {
|
|
|
|
protected:
|
2013-07-24 08:16:35 +00:00
|
|
|
unsigned short m_kind;
|
|
|
|
std::atomic_ushort m_flags;
|
2013-07-23 15:59:39 +00:00
|
|
|
unsigned m_hash;
|
2013-07-22 11:03:46 +00:00
|
|
|
MK_LEAN_RC(); // Declare m_rc counter
|
|
|
|
void dealloc();
|
2013-07-23 18:31:31 +00:00
|
|
|
|
2013-07-24 08:16:35 +00:00
|
|
|
bool max_shared() const { return (m_flags & 1) != 0; }
|
|
|
|
void set_max_shared() { m_flags |= 1; }
|
2013-07-24 07:45:38 +00:00
|
|
|
friend class max_sharing_fn;
|
2013-07-23 18:31:31 +00:00
|
|
|
|
2013-07-24 08:16:35 +00:00
|
|
|
bool is_closed() const { return (m_flags & 2) != 0; }
|
|
|
|
void set_closed() { m_flags |= 2; }
|
2013-07-24 07:45:38 +00:00
|
|
|
friend class has_free_var_fn;
|
2013-07-22 11:03:46 +00:00
|
|
|
public:
|
|
|
|
expr_cell(expr_kind k, unsigned h);
|
2013-07-23 15:59:39 +00:00
|
|
|
expr_kind kind() const { return static_cast<expr_kind>(m_kind); }
|
2013-07-22 11:03:46 +00:00
|
|
|
unsigned hash() const { return m_hash; }
|
|
|
|
};
|
|
|
|
|
|
|
|
/**
|
|
|
|
\brief Exprs for encoding formulas/expressions, types and proofs.
|
|
|
|
*/
|
|
|
|
class expr {
|
|
|
|
private:
|
|
|
|
expr_cell * m_ptr;
|
|
|
|
explicit expr(expr_cell * ptr):m_ptr(ptr) {}
|
|
|
|
public:
|
|
|
|
expr():m_ptr(0) {}
|
|
|
|
expr(expr const & s):m_ptr(s.m_ptr) { if (m_ptr) m_ptr->inc_ref(); }
|
2013-08-01 20:57:43 +00:00
|
|
|
expr(expr && s):m_ptr(s.m_ptr) { s.m_ptr = nullptr; }
|
2013-07-22 11:03:46 +00:00
|
|
|
~expr() { if (m_ptr) m_ptr->dec_ref(); }
|
|
|
|
|
|
|
|
friend void swap(expr & a, expr & b) { std::swap(a.m_ptr, b.m_ptr); }
|
|
|
|
|
2013-07-30 03:59:15 +00:00
|
|
|
void release() { if (m_ptr) m_ptr->dec_ref(); m_ptr = nullptr; }
|
|
|
|
|
|
|
|
expr & operator=(expr const & s) { LEAN_COPY_REF(expr, s); }
|
|
|
|
expr & operator=(expr && s) { LEAN_MOVE_REF(expr, s); }
|
2013-07-22 11:03:46 +00:00
|
|
|
|
|
|
|
expr_kind kind() const { return m_ptr->kind(); }
|
|
|
|
unsigned hash() const { return m_ptr->hash(); }
|
|
|
|
|
|
|
|
expr_cell * raw() const { return m_ptr; }
|
|
|
|
|
|
|
|
friend expr var(unsigned idx);
|
|
|
|
friend expr constant(name const & n);
|
|
|
|
friend expr constant(name const & n, unsigned pos);
|
|
|
|
friend expr app(unsigned num_args, expr const * args);
|
|
|
|
friend expr app(std::initializer_list<expr> const & l);
|
|
|
|
friend expr lambda(name const & n, expr const & t, expr const & e);
|
|
|
|
friend expr pi(name const & n, expr const & t, expr const & e);
|
|
|
|
friend expr prop();
|
2013-07-30 02:44:26 +00:00
|
|
|
friend expr type(level const & l);
|
2013-07-22 11:03:46 +00:00
|
|
|
friend expr numeral(mpz const & n);
|
|
|
|
|
|
|
|
friend bool eqp(expr const & a, expr const & b) { return a.m_ptr == b.m_ptr; }
|
2013-07-23 18:56:15 +00:00
|
|
|
|
|
|
|
// Overloaded operator() can be used to create applications
|
|
|
|
expr operator()(expr const & a1) const;
|
|
|
|
expr operator()(expr const & a1, expr const & a2) const;
|
|
|
|
expr operator()(expr const & a1, expr const & a2, expr const & a3) const;
|
|
|
|
expr operator()(expr const & a1, expr const & a2, expr const & a3, expr const & a4) const;
|
2013-07-22 11:03:46 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
// =======================================
|
2013-07-23 15:59:39 +00:00
|
|
|
// Expr (internal) Representation
|
2013-07-26 18:43:53 +00:00
|
|
|
/** \brief Free variables. They are encoded using de Bruijn's indices. */
|
2013-07-22 11:03:46 +00:00
|
|
|
class expr_var : public expr_cell {
|
|
|
|
unsigned m_vidx; // de Bruijn index
|
|
|
|
public:
|
|
|
|
expr_var(unsigned idx);
|
|
|
|
unsigned get_vidx() const { return m_vidx; }
|
|
|
|
};
|
2013-07-26 18:43:53 +00:00
|
|
|
/** \brief Constants. */
|
2013-07-22 11:03:46 +00:00
|
|
|
class expr_const : public expr_cell {
|
|
|
|
name m_name;
|
|
|
|
unsigned m_pos; // position in the environment.
|
|
|
|
public:
|
|
|
|
expr_const(name const & n, unsigned pos = std::numeric_limits<unsigned>::max());
|
|
|
|
name const & get_name() const { return m_name; }
|
|
|
|
unsigned get_pos() const { return m_pos; }
|
|
|
|
};
|
2013-07-26 18:43:53 +00:00
|
|
|
/** \brief Function Applications */
|
2013-07-22 11:03:46 +00:00
|
|
|
class expr_app : public expr_cell {
|
|
|
|
unsigned m_num_args;
|
|
|
|
expr m_args[0];
|
|
|
|
friend expr app(unsigned num_args, expr const * args);
|
|
|
|
public:
|
|
|
|
expr_app(unsigned size);
|
|
|
|
~expr_app();
|
|
|
|
unsigned get_num_args() const { return m_num_args; }
|
|
|
|
expr const & get_arg(unsigned idx) const { lean_assert(idx < m_num_args); return m_args[idx]; }
|
2013-07-22 23:40:17 +00:00
|
|
|
expr const * begin_args() const { return m_args; }
|
|
|
|
expr const * end_args() const { return m_args + m_num_args; }
|
2013-07-22 11:03:46 +00:00
|
|
|
};
|
2013-07-26 18:43:53 +00:00
|
|
|
/** \brief Super class for lambda abstraction and pi (functional spaces). */
|
2013-07-22 11:03:46 +00:00
|
|
|
class expr_abstraction : public expr_cell {
|
|
|
|
name m_name;
|
|
|
|
expr m_type;
|
2013-07-24 04:49:19 +00:00
|
|
|
expr m_body;
|
2013-07-22 11:03:46 +00:00
|
|
|
public:
|
|
|
|
expr_abstraction(expr_kind k, name const & n, expr const & t, expr const & e);
|
|
|
|
name const & get_name() const { return m_name; }
|
|
|
|
expr const & get_type() const { return m_type; }
|
2013-07-24 04:49:19 +00:00
|
|
|
expr const & get_body() const { return m_body; }
|
2013-07-22 11:03:46 +00:00
|
|
|
};
|
2013-07-26 18:43:53 +00:00
|
|
|
/** \brief Lambda abstractions */
|
2013-07-22 11:03:46 +00:00
|
|
|
class expr_lambda : public expr_abstraction {
|
|
|
|
public:
|
|
|
|
expr_lambda(name const & n, expr const & t, expr const & e);
|
|
|
|
};
|
2013-07-26 18:43:53 +00:00
|
|
|
/** \brief (dependent) Functional spaces */
|
2013-07-22 11:03:46 +00:00
|
|
|
class expr_pi : public expr_abstraction {
|
|
|
|
public:
|
|
|
|
expr_pi(name const & n, expr const & t, expr const & e);
|
|
|
|
};
|
2013-07-26 18:43:53 +00:00
|
|
|
/** \brief Type */
|
2013-07-22 11:03:46 +00:00
|
|
|
class expr_type : public expr_cell {
|
2013-07-30 02:44:26 +00:00
|
|
|
level m_level;
|
2013-07-22 11:03:46 +00:00
|
|
|
public:
|
2013-07-30 02:44:26 +00:00
|
|
|
expr_type(level const & l);
|
2013-07-22 11:03:46 +00:00
|
|
|
~expr_type();
|
2013-07-30 02:44:26 +00:00
|
|
|
level const & get_level() const { return m_level; }
|
2013-07-22 11:03:46 +00:00
|
|
|
};
|
2013-07-26 18:43:53 +00:00
|
|
|
/** \brief Numerals (efficient encoding using GMP numbers) */
|
2013-07-22 11:03:46 +00:00
|
|
|
class expr_numeral : public expr_cell {
|
|
|
|
mpz m_numeral;
|
|
|
|
public:
|
|
|
|
expr_numeral(mpz const & n);
|
|
|
|
mpz const & get_num() const { return m_numeral; }
|
|
|
|
};
|
|
|
|
// =======================================
|
|
|
|
|
|
|
|
// =======================================
|
|
|
|
// Testers
|
|
|
|
inline bool is_var(expr_cell * e) { return e->kind() == expr_kind::Var; }
|
|
|
|
inline bool is_constant(expr_cell * e) { return e->kind() == expr_kind::Constant; }
|
|
|
|
inline bool is_app(expr_cell * e) { return e->kind() == expr_kind::App; }
|
|
|
|
inline bool is_lambda(expr_cell * e) { return e->kind() == expr_kind::Lambda; }
|
|
|
|
inline bool is_pi(expr_cell * e) { return e->kind() == expr_kind::Pi; }
|
|
|
|
inline bool is_type(expr_cell * e) { return e->kind() == expr_kind::Type; }
|
|
|
|
inline bool is_numeral(expr_cell * e) { return e->kind() == expr_kind::Numeral; }
|
|
|
|
inline bool is_abstraction(expr_cell * e) { return is_lambda(e) || is_pi(e); }
|
|
|
|
|
2013-07-25 02:36:54 +00:00
|
|
|
inline bool is_null(expr const & e) { return e.raw() == nullptr; }
|
2013-07-22 11:03:46 +00:00
|
|
|
inline bool is_var(expr const & e) { return e.kind() == expr_kind::Var; }
|
|
|
|
inline bool is_constant(expr const & e) { return e.kind() == expr_kind::Constant; }
|
|
|
|
inline bool is_app(expr const & e) { return e.kind() == expr_kind::App; }
|
|
|
|
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; }
|
|
|
|
inline bool is_type(expr const & e) { return e.kind() == expr_kind::Type; }
|
|
|
|
inline bool is_numeral(expr const & e) { return e.kind() == expr_kind::Numeral; }
|
|
|
|
inline bool is_abstraction(expr const & e) { return is_lambda(e) || is_pi(e); }
|
|
|
|
// =======================================
|
|
|
|
|
|
|
|
// =======================================
|
|
|
|
// Constructors
|
|
|
|
inline expr var(unsigned idx) { return expr(new expr_var(idx)); }
|
|
|
|
inline expr constant(name const & n) { return expr(new expr_const(n)); }
|
2013-07-23 16:37:32 +00:00
|
|
|
inline expr constant(char const * n) { return constant(name(n)); }
|
2013-07-22 11:03:46 +00:00
|
|
|
inline expr constant(name const & n, unsigned pos) { return expr(new expr_const(n, pos)); }
|
|
|
|
expr app(unsigned num_args, expr const * args);
|
2013-07-23 15:59:39 +00:00
|
|
|
inline expr app(expr const & e1, expr const & e2) { expr args[2] = {e1, e2}; return app(2, args); }
|
|
|
|
inline expr app(expr const & e1, expr const & e2, expr const & e3) { expr args[3] = {e1, e2, e3}; return app(3, args); }
|
|
|
|
inline expr app(expr const & e1, expr const & e2, expr const & e3, expr const & e4) { expr args[4] = {e1, e2, e3, e4}; return app(4, args); }
|
|
|
|
inline expr app(expr const & e1, expr const & e2, expr const & e3, expr const & e4, expr const & e5) { expr args[5] = {e1, e2, e3, e4, e5}; return app(5, args); }
|
2013-07-22 11:03:46 +00:00
|
|
|
inline expr lambda(name const & n, expr const & t, expr const & e) { return expr(new expr_lambda(n, t, e)); }
|
2013-07-23 16:37:32 +00:00
|
|
|
inline expr lambda(char const * n, expr const & t, expr const & e) { return lambda(name(n), t, e); }
|
2013-07-22 11:03:46 +00:00
|
|
|
inline expr pi(name const & n, expr const & t, expr const & e) { return expr(new expr_pi(n, t, e)); }
|
2013-07-23 16:37:32 +00:00
|
|
|
inline expr pi(char const * n, expr const & t, expr const & e) { return pi(name(n), t, e); }
|
2013-07-30 02:44:26 +00:00
|
|
|
inline expr type(level const & l) { return expr(new expr_type(l)); }
|
2013-07-22 11:03:46 +00:00
|
|
|
inline expr numeral(mpz const & n) { return expr(new expr_numeral(n)); }
|
2013-07-24 17:14:22 +00:00
|
|
|
inline expr numeral(int n) { return numeral(mpz(n)); }
|
2013-07-23 18:56:15 +00:00
|
|
|
|
|
|
|
inline expr expr::operator()(expr const & a1) const { return app(*this, a1); }
|
|
|
|
inline expr expr::operator()(expr const & a1, expr const & a2) const { return app(*this, a1, a2); }
|
|
|
|
inline expr expr::operator()(expr const & a1, expr const & a2, expr const & a3) const { return app(*this, a1, a2, a3); }
|
|
|
|
inline expr expr::operator()(expr const & a1, expr const & a2, expr const & a3, expr const & a4) const { return app(*this, a1, a2, a3, a4); }
|
2013-07-22 11:03:46 +00:00
|
|
|
// =======================================
|
|
|
|
|
|
|
|
// =======================================
|
2013-07-23 15:59:39 +00:00
|
|
|
// Casting (these functions are only needed for low-level code)
|
2013-07-22 11:03:46 +00:00
|
|
|
inline expr_var * to_var(expr_cell * e) { lean_assert(is_var(e)); return static_cast<expr_var*>(e); }
|
|
|
|
inline expr_const * to_constant(expr_cell * e) { lean_assert(is_constant(e)); return static_cast<expr_const*>(e); }
|
|
|
|
inline expr_app * to_app(expr_cell * e) { lean_assert(is_app(e)); return static_cast<expr_app*>(e); }
|
|
|
|
inline expr_abstraction * to_abstraction(expr_cell * e) { lean_assert(is_abstraction(e)); return static_cast<expr_abstraction*>(e); }
|
|
|
|
inline expr_lambda * to_lambda(expr_cell * e) { lean_assert(is_lambda(e)); return static_cast<expr_lambda*>(e); }
|
|
|
|
inline expr_pi * to_pi(expr_cell * e) { lean_assert(is_pi(e)); return static_cast<expr_pi*>(e); }
|
|
|
|
inline expr_type * to_type(expr_cell * e) { lean_assert(is_type(e)); return static_cast<expr_type*>(e); }
|
|
|
|
inline expr_numeral * to_numeral(expr_cell * e) { lean_assert(is_numeral(e)); return static_cast<expr_numeral*>(e); }
|
|
|
|
|
|
|
|
inline expr_var * to_var(expr const & e) { return to_var(e.raw()); }
|
|
|
|
inline expr_const * to_constant(expr const & e) { return to_constant(e.raw()); }
|
|
|
|
inline expr_app * to_app(expr const & e) { return to_app(e.raw()); }
|
|
|
|
inline expr_abstraction * to_abstraction(expr const & e) { return to_abstraction(e.raw()); }
|
|
|
|
inline expr_lambda * to_lambda(expr const & e) { return to_lambda(e.raw()); }
|
|
|
|
inline expr_pi * to_pi(expr const & e) { return to_pi(e.raw()); }
|
|
|
|
inline expr_type * to_type(expr const & e) { return to_type(e.raw()); }
|
|
|
|
inline expr_numeral * to_numeral(expr const & e) { return to_numeral(e.raw()); }
|
|
|
|
// =======================================
|
|
|
|
|
|
|
|
// =======================================
|
|
|
|
// Accessors
|
2013-07-30 02:44:26 +00:00
|
|
|
inline unsigned get_rc(expr_cell * e) { return e->get_rc(); }
|
|
|
|
inline bool is_shared(expr_cell * e) { return get_rc(e) > 1; }
|
|
|
|
inline unsigned var_idx(expr_cell * e) { return to_var(e)->get_vidx(); }
|
|
|
|
inline bool is_var(expr_cell * e, unsigned i) { return is_var(e) && var_idx(e) == i; }
|
|
|
|
inline name const & const_name(expr_cell * e) { return to_constant(e)->get_name(); }
|
|
|
|
inline unsigned const_pos(expr_cell * e) { return to_constant(e)->get_pos(); }
|
|
|
|
inline unsigned num_args(expr_cell * e) { return to_app(e)->get_num_args(); }
|
|
|
|
inline expr const & arg(expr_cell * e, unsigned idx) { return to_app(e)->get_arg(idx); }
|
|
|
|
inline name const & abst_name(expr_cell * e) { return to_abstraction(e)->get_name(); }
|
|
|
|
inline expr const & abst_type(expr_cell * e) { return to_abstraction(e)->get_type(); }
|
|
|
|
inline expr const & abst_body(expr_cell * e) { return to_abstraction(e)->get_body(); }
|
|
|
|
inline level const & ty_level(expr_cell * e) { return to_type(e)->get_level(); }
|
|
|
|
inline mpz const & num_value(expr_cell * e) { return to_numeral(e)->get_num(); }
|
|
|
|
|
|
|
|
inline unsigned get_rc(expr const & e) { return e.raw()->get_rc(); }
|
|
|
|
inline bool is_shared(expr const & e) { return get_rc(e) > 1; }
|
|
|
|
inline unsigned var_idx(expr const & e) { return to_var(e)->get_vidx(); }
|
|
|
|
inline bool is_var(expr const & e, unsigned i) { return is_var(e) && var_idx(e) == i; }
|
|
|
|
inline name const & const_name(expr const & e) { return to_constant(e)->get_name(); }
|
|
|
|
inline unsigned const_pos(expr const & e) { return to_constant(e)->get_pos(); }
|
|
|
|
inline unsigned num_args(expr const & e) { return to_app(e)->get_num_args(); }
|
|
|
|
inline expr const & arg(expr const & e, unsigned idx) { return to_app(e)->get_arg(idx); }
|
|
|
|
inline expr const * begin_args(expr const & e) { return to_app(e)->begin_args(); }
|
|
|
|
inline expr const * end_args(expr const & e) { return to_app(e)->end_args(); }
|
|
|
|
inline name const & abst_name(expr const & e) { return to_abstraction(e)->get_name(); }
|
|
|
|
inline expr const & abst_type(expr const & e) { return to_abstraction(e)->get_type(); }
|
|
|
|
inline expr const & abst_body(expr const & e) { return to_abstraction(e)->get_body(); }
|
|
|
|
inline level const & ty_level(expr const & e) { return to_type(e)->get_level(); }
|
|
|
|
inline mpz const & num_value(expr const & e) { return to_numeral(e)->get_num(); }
|
2013-07-22 11:03:46 +00:00
|
|
|
// =======================================
|
|
|
|
|
|
|
|
// =======================================
|
|
|
|
// Structural equality
|
|
|
|
bool operator==(expr const & a, expr const & b);
|
|
|
|
inline bool operator!=(expr const & a, expr const & b) { return !operator==(a, b); }
|
|
|
|
// =======================================
|
|
|
|
|
2013-07-23 17:16:47 +00:00
|
|
|
// =======================================
|
|
|
|
// Expression+Offset
|
|
|
|
typedef std::pair<expr, unsigned> expr_offset;
|
|
|
|
typedef std::pair<expr_cell*, unsigned> expr_cell_offset;
|
|
|
|
// =======================================
|
|
|
|
|
2013-07-23 17:09:04 +00:00
|
|
|
// =======================================
|
2013-07-24 07:45:38 +00:00
|
|
|
// Auxiliary functionals
|
2013-07-26 18:43:53 +00:00
|
|
|
/** \brief Functional object for hashing kernel expressions. */
|
2013-07-23 17:09:04 +00:00
|
|
|
struct expr_hash { unsigned operator()(expr const & e) const { return e.hash(); } };
|
2013-07-26 18:43:53 +00:00
|
|
|
/** \brief Functional object for testing pointer equality between kernel expressions. */
|
2013-07-23 17:09:04 +00:00
|
|
|
struct expr_eqp { bool operator()(expr const & e1, expr const & e2) const { return eqp(e1, e2); } };
|
2013-07-26 18:43:53 +00:00
|
|
|
/** \brief Functional object for hashing kernel expression cells. */
|
2013-07-23 17:09:04 +00:00
|
|
|
struct expr_cell_hash { unsigned operator()(expr_cell * e) const { return e->hash(); } };
|
2013-07-26 18:43:53 +00:00
|
|
|
/** \brief Functional object for testing pointer equality between kernel cell expressions. */
|
2013-07-23 17:09:04 +00:00
|
|
|
struct expr_cell_eqp { bool operator()(expr_cell * e1, expr_cell * e2) const { return e1 == e2; } };
|
2013-07-26 18:43:53 +00:00
|
|
|
/** \brief Functional object for hashing a pair (n,k) where n is a kernel expressions, and k is an offset. */
|
2013-07-23 17:16:47 +00:00
|
|
|
struct expr_offset_hash { unsigned operator()(expr_offset const & p) const { return hash(p.first.hash(), p.second); } };
|
2013-07-26 18:43:53 +00:00
|
|
|
/** \brief Functional object for comparing pairs (expression, offset). */
|
2013-07-23 17:16:47 +00:00
|
|
|
struct expr_offset_eqp { unsigned operator()(expr_offset const & p1, expr_offset const & p2) const { return eqp(p1.first, p2.first) && p1.second == p2.second; } };
|
2013-07-26 18:43:53 +00:00
|
|
|
/** \brief Functional object for hashing a pair (n,k) where n is a kernel cell expressions, and k is an offset. */
|
2013-07-23 17:16:47 +00:00
|
|
|
struct expr_cell_offset_hash { unsigned operator()(expr_cell_offset const & p) const { return hash(p.first->hash(), p.second); } };
|
2013-07-26 18:43:53 +00:00
|
|
|
/** \brief Functional object for comparing pairs (expression cell, offset). */
|
2013-07-23 17:16:47 +00:00
|
|
|
struct expr_cell_offset_eqp { unsigned operator()(expr_cell_offset const & p1, expr_cell_offset const & p2) const { return p1 == p2; } };
|
2013-07-23 17:09:04 +00:00
|
|
|
// =======================================
|
2013-07-22 11:03:46 +00:00
|
|
|
|
2013-07-23 17:09:04 +00:00
|
|
|
// =======================================
|
|
|
|
// Miscellaneous
|
|
|
|
std::ostream & operator<<(std::ostream & out, expr const & a);
|
2013-07-22 23:40:17 +00:00
|
|
|
/**
|
|
|
|
\brief Wrapper for iterating over application arguments.
|
2013-07-26 18:43:53 +00:00
|
|
|
|
|
|
|
If \c n is an application, it allows us to write
|
|
|
|
|
|
|
|
\code
|
2013-07-22 23:40:17 +00:00
|
|
|
for (expr const & arg : app_args(n)) {
|
|
|
|
... do something with argument
|
|
|
|
}
|
2013-07-26 18:43:53 +00:00
|
|
|
\endcode
|
2013-07-22 23:40:17 +00:00
|
|
|
*/
|
2013-07-23 18:47:36 +00:00
|
|
|
struct args {
|
2013-07-22 23:40:17 +00:00
|
|
|
expr const & m_app;
|
2013-07-23 18:47:36 +00:00
|
|
|
args(expr const & a):m_app(a) { lean_assert(is_app(a)); }
|
|
|
|
expr const * begin() const { return &arg(m_app, 0); }
|
|
|
|
expr const * end() const { return begin() + num_args(m_app); }
|
2013-07-22 23:40:17 +00:00
|
|
|
};
|
2013-07-24 17:14:22 +00:00
|
|
|
/**
|
|
|
|
\brief Return a shallow copy of \c e
|
|
|
|
*/
|
|
|
|
expr copy(expr const & e);
|
2013-07-23 17:09:04 +00:00
|
|
|
// =======================================
|
2013-07-30 04:28:22 +00:00
|
|
|
|
|
|
|
// =======================================
|
|
|
|
// Update
|
|
|
|
template<typename F> expr update_app(expr const & e, F f) {
|
|
|
|
buffer<expr> new_args;
|
|
|
|
bool modified = false;
|
|
|
|
for (expr const & a : args(e)) {
|
|
|
|
new_args.push_back(f(a));
|
|
|
|
if (!eqp(a, new_args.back()))
|
|
|
|
modified = true;
|
|
|
|
}
|
|
|
|
if (modified)
|
|
|
|
return app(new_args.size(), new_args.data());
|
|
|
|
else
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
template<typename F> expr update_abst(expr const & e, F f) {
|
|
|
|
expr const & old_t = abst_type(e);
|
|
|
|
expr const & old_b = abst_body(e);
|
|
|
|
std::pair<expr, expr> p = f(old_t, old_b);
|
|
|
|
if (!eqp(p.first, old_t) || !eqp(p.second, old_b)) {
|
|
|
|
name const & n = abst_name(e);
|
|
|
|
return is_pi(e) ? pi(n, p.first, p.second) : lambda(n, p.first, p.second);
|
|
|
|
}
|
|
|
|
else {
|
|
|
|
return e;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
// =======================================
|
2013-07-22 11:03:46 +00:00
|
|
|
}
|