refactor(kernel/expr): for_each_fn, replace_fn, and find_fn without templates
Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
parent
69b9f2dd37
commit
533f44e224
7 changed files with 280 additions and 269 deletions
|
@ -1,5 +1,5 @@
|
||||||
add_library(kernel level.cpp diff_cnstrs.cpp expr.cpp expr_eq_fn.cpp
|
add_library(kernel level.cpp diff_cnstrs.cpp expr.cpp expr_eq_fn.cpp
|
||||||
occurs.cpp
|
for_each_fn.cpp occurs.cpp replace_fn.cpp
|
||||||
# free_vars.cpp abstract.cpp instantiate.cpp
|
# free_vars.cpp abstract.cpp instantiate.cpp
|
||||||
# normalizer.cpp context.cpp level.cpp object.cpp environment.cpp
|
# normalizer.cpp context.cpp level.cpp object.cpp environment.cpp
|
||||||
# type_checker.cpp kernel.cpp occurs.cpp metavar.cpp
|
# type_checker.cpp kernel.cpp occurs.cpp metavar.cpp
|
||||||
|
|
|
@ -9,16 +9,16 @@ Author: Leonardo de Moura
|
||||||
#include "kernel/expr.h"
|
#include "kernel/expr.h"
|
||||||
|
|
||||||
namespace lean {
|
namespace lean {
|
||||||
template<typename P>
|
|
||||||
class find_fn {
|
class find_fn {
|
||||||
|
template<typename P>
|
||||||
struct pred_fn {
|
struct pred_fn {
|
||||||
optional<expr> & m_result;
|
optional<expr> & m_result;
|
||||||
P m_p;
|
P m_p;
|
||||||
pred_fn(optional<expr> & result, P const & p):m_result(result), m_p(p) {}
|
pred_fn(optional<expr> & result, P const & p):m_result(result), m_p(p) {}
|
||||||
bool operator()(expr const & e, unsigned) {
|
bool operator()(expr const & e, unsigned offset) {
|
||||||
if (m_result) {
|
if (m_result) {
|
||||||
return false; // already found result, stop the search
|
return false; // already found result, stop the search
|
||||||
} else if (m_p(e)) {
|
} else if (m_p(e, offset)) {
|
||||||
m_result = e;
|
m_result = e;
|
||||||
return false; // stop the search
|
return false; // stop the search
|
||||||
} else {
|
} else {
|
||||||
|
@ -26,18 +26,17 @@ class find_fn {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
optional<expr> m_result;
|
optional<expr> m_result;
|
||||||
for_each_fn<pred_fn> m_proc;
|
for_each_fn m_proc;
|
||||||
public:
|
public:
|
||||||
find_fn(P const & p):m_proc(pred_fn(m_result, p)) {}
|
template<typename P> find_fn(P const & p):m_proc(pred_fn<P>(m_result, p)) {}
|
||||||
optional<expr> operator()(expr const & e) { m_proc(e); return m_result; }
|
optional<expr> operator()(expr const & e) { m_proc(e); return m_result; }
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
\brief Return a subexpression of \c e that satisfies the predicate \c p.
|
\brief Return a subexpression of \c e that satisfies the predicate \c p.
|
||||||
*/
|
*/
|
||||||
template<typename P>
|
template<typename P> optional<expr> find(expr const & e, P p) {
|
||||||
optional<expr> find(expr const & e, P p) {
|
return find_fn(p)(e);
|
||||||
return find_fn<P>(p)(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
75
src/kernel/for_each_fn.cpp
Normal file
75
src/kernel/for_each_fn.cpp
Normal file
|
@ -0,0 +1,75 @@
|
||||||
|
/*
|
||||||
|
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 "kernel/for_each_fn.h"
|
||||||
|
|
||||||
|
namespace lean {
|
||||||
|
void for_each_fn::apply(expr const & e, unsigned offset) {
|
||||||
|
buffer<std::pair<expr const &, unsigned>> todo;
|
||||||
|
todo.emplace_back(e, offset);
|
||||||
|
while (true) {
|
||||||
|
begin_loop:
|
||||||
|
if (todo.empty())
|
||||||
|
break;
|
||||||
|
auto p = todo.back();
|
||||||
|
todo.pop_back();
|
||||||
|
expr const & e = p.first;
|
||||||
|
unsigned offset = p.second;
|
||||||
|
|
||||||
|
switch (e.kind()) {
|
||||||
|
case expr_kind::Constant: case expr_kind::Var:
|
||||||
|
case expr_kind::Sort: case expr_kind::Macro:
|
||||||
|
m_f(e, offset);
|
||||||
|
goto begin_loop;
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_shared(e)) {
|
||||||
|
expr_cell_offset p(e.raw(), offset);
|
||||||
|
if (!m_visited)
|
||||||
|
m_visited.reset(new expr_cell_offset_set());
|
||||||
|
if (m_visited->find(p) != m_visited->end())
|
||||||
|
goto begin_loop;
|
||||||
|
m_visited->insert(p);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!m_f(e, offset))
|
||||||
|
goto begin_loop;
|
||||||
|
|
||||||
|
switch (e.kind()) {
|
||||||
|
case expr_kind::Constant: case expr_kind::Var:
|
||||||
|
case expr_kind::Sort: case expr_kind::Macro:
|
||||||
|
goto begin_loop;
|
||||||
|
case expr_kind::Meta: case expr_kind::Local:
|
||||||
|
todo.emplace_back(mlocal_type(e), offset);
|
||||||
|
goto begin_loop;
|
||||||
|
case expr_kind::App:
|
||||||
|
todo.emplace_back(app_arg(e), offset);
|
||||||
|
todo.emplace_back(app_fn(e), offset);
|
||||||
|
goto begin_loop;
|
||||||
|
case expr_kind::Pair:
|
||||||
|
todo.emplace_back(pair_type(e), offset);
|
||||||
|
todo.emplace_back(pair_second(e), offset);
|
||||||
|
todo.emplace_back(pair_first(e), offset);
|
||||||
|
goto begin_loop;
|
||||||
|
case expr_kind::Fst: case expr_kind::Snd:
|
||||||
|
todo.emplace_back(proj_arg(e), offset);
|
||||||
|
goto begin_loop;
|
||||||
|
case expr_kind::Lambda: case expr_kind::Pi: case expr_kind::Sigma:
|
||||||
|
todo.emplace_back(binder_body(e), offset + 1);
|
||||||
|
todo.emplace_back(binder_domain(e), offset);
|
||||||
|
goto begin_loop;
|
||||||
|
case expr_kind::Let:
|
||||||
|
todo.emplace_back(let_body(e), offset + 1);
|
||||||
|
todo.emplace_back(let_value(e), offset);
|
||||||
|
if (let_type(e))
|
||||||
|
todo.emplace_back(*let_type(e), offset);
|
||||||
|
goto begin_loop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
|
@ -7,99 +7,34 @@ Author: Leonardo de Moura
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <memory>
|
#include <memory>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
|
#include <functional>
|
||||||
#include "util/buffer.h"
|
#include "util/buffer.h"
|
||||||
#include "kernel/expr.h"
|
#include "kernel/expr.h"
|
||||||
#include "kernel/expr_sets.h"
|
#include "kernel/expr_sets.h"
|
||||||
|
|
||||||
namespace lean {
|
namespace lean {
|
||||||
/**
|
/**
|
||||||
\brief Template for implementing expression visitors.
|
\brief Expression visitor.
|
||||||
The argument \c F must be a function object containing the method
|
|
||||||
<code>
|
The argument \c F must be a lambda (function object) containing the method
|
||||||
void operator()(expr const & e, unsigned offset)
|
|
||||||
</code>
|
<code>
|
||||||
The \c offset is the number of binders under which \c e occurs.
|
void operator()(expr const & e, unsigned offset)
|
||||||
|
</code>
|
||||||
|
|
||||||
|
The \c offset is the number of binders under which \c e occurs.
|
||||||
*/
|
*/
|
||||||
template<typename F, bool CacheAtomic = false>
|
|
||||||
class for_each_fn {
|
class for_each_fn {
|
||||||
std::unique_ptr<expr_cell_offset_set> m_visited;
|
std::unique_ptr<expr_cell_offset_set> m_visited;
|
||||||
F m_f;
|
std::function<bool(expr const &, unsigned)> m_f;
|
||||||
static_assert(std::is_same<typename std::result_of<F(expr const &, unsigned)>::type, bool>::value,
|
void apply(expr const & e, unsigned offset);
|
||||||
"for_each_fn: return type of m_f is not bool");
|
|
||||||
|
|
||||||
void apply(expr const & e, unsigned offset) {
|
|
||||||
buffer<std::pair<expr const &, unsigned>> todo;
|
|
||||||
todo.emplace_back(e, offset);
|
|
||||||
while (true) {
|
|
||||||
begin_loop:
|
|
||||||
if (todo.empty())
|
|
||||||
break;
|
|
||||||
auto p = todo.back();
|
|
||||||
todo.pop_back();
|
|
||||||
expr const & e = p.first;
|
|
||||||
unsigned offset = p.second;
|
|
||||||
if (!CacheAtomic) {
|
|
||||||
switch (e.kind()) {
|
|
||||||
case expr_kind::Constant: case expr_kind::Var:
|
|
||||||
case expr_kind::Sort: case expr_kind::Macro:
|
|
||||||
m_f(e, offset);
|
|
||||||
goto begin_loop;
|
|
||||||
default:
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (is_shared(e)) {
|
|
||||||
expr_cell_offset p(e.raw(), offset);
|
|
||||||
if (!m_visited)
|
|
||||||
m_visited.reset(new expr_cell_offset_set());
|
|
||||||
if (m_visited->find(p) != m_visited->end())
|
|
||||||
goto begin_loop;
|
|
||||||
m_visited->insert(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!m_f(e, offset))
|
|
||||||
goto begin_loop;
|
|
||||||
|
|
||||||
switch (e.kind()) {
|
|
||||||
case expr_kind::Constant: case expr_kind::Var:
|
|
||||||
case expr_kind::Sort: case expr_kind::Macro:
|
|
||||||
goto begin_loop;
|
|
||||||
case expr_kind::Meta: case expr_kind::Local:
|
|
||||||
todo.emplace_back(mlocal_type(e), offset);
|
|
||||||
goto begin_loop;
|
|
||||||
case expr_kind::App:
|
|
||||||
todo.emplace_back(app_arg(e), offset);
|
|
||||||
todo.emplace_back(app_fn(e), offset);
|
|
||||||
goto begin_loop;
|
|
||||||
case expr_kind::Pair:
|
|
||||||
todo.emplace_back(pair_type(e), offset);
|
|
||||||
todo.emplace_back(pair_second(e), offset);
|
|
||||||
todo.emplace_back(pair_first(e), offset);
|
|
||||||
goto begin_loop;
|
|
||||||
case expr_kind::Fst: case expr_kind::Snd:
|
|
||||||
todo.emplace_back(proj_arg(e), offset);
|
|
||||||
goto begin_loop;
|
|
||||||
case expr_kind::Lambda: case expr_kind::Pi: case expr_kind::Sigma:
|
|
||||||
todo.emplace_back(binder_body(e), offset + 1);
|
|
||||||
todo.emplace_back(binder_domain(e), offset);
|
|
||||||
goto begin_loop;
|
|
||||||
case expr_kind::Let:
|
|
||||||
todo.emplace_back(let_body(e), offset + 1);
|
|
||||||
todo.emplace_back(let_value(e), offset);
|
|
||||||
if (let_type(e))
|
|
||||||
todo.emplace_back(*let_type(e), offset);
|
|
||||||
goto begin_loop;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
public:
|
public:
|
||||||
for_each_fn(F const & f):m_f(f) {}
|
template<typename F> for_each_fn(F && f):m_f(f) {}
|
||||||
|
template<typename F> for_each_fn(F const & f):m_f(f) {}
|
||||||
void operator()(expr const & e) { apply(e, 0); }
|
void operator()(expr const & e) { apply(e, 0); }
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename F>
|
template<typename F> void for_each(expr const & e, F && f) {
|
||||||
void for_each(expr const & e, F f) {
|
return for_each_fn(f)(e);
|
||||||
return for_each_fn<F>(f)(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -9,10 +9,10 @@ Author: Leonardo de Moura
|
||||||
|
|
||||||
namespace lean {
|
namespace lean {
|
||||||
bool occurs(expr const & n, expr const & m) {
|
bool occurs(expr const & n, expr const & m) {
|
||||||
return static_cast<bool>(find(m, [&](expr const & e) { return n == e; }));
|
return static_cast<bool>(find(m, [&](expr const & e, unsigned) { return n == e; }));
|
||||||
}
|
}
|
||||||
|
|
||||||
bool occurs(name const & n, expr const & m) {
|
bool occurs(name const & n, expr const & m) {
|
||||||
return static_cast<bool>(find(m, [&](expr const & e) { return is_constant(e) && const_name(e) == n; }));
|
return static_cast<bool>(find(m, [&](expr const & e, unsigned) { return is_constant(e) && const_name(e) == n; }));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
157
src/kernel/replace_fn.cpp
Normal file
157
src/kernel/replace_fn.cpp
Normal file
|
@ -0,0 +1,157 @@
|
||||||
|
/*
|
||||||
|
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 "kernel/replace_fn.h"
|
||||||
|
|
||||||
|
namespace lean {
|
||||||
|
bool replace_fn::is_atomic(expr const & e) {
|
||||||
|
switch (e.kind()) {
|
||||||
|
case expr_kind::Constant: case expr_kind::Sort:
|
||||||
|
case expr_kind::Macro: case expr_kind::Var:
|
||||||
|
return true;
|
||||||
|
default:
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void replace_fn::save_result(expr const & e, expr const & r, unsigned offset, bool shared) {
|
||||||
|
if (shared)
|
||||||
|
m_cache.insert(std::make_pair(expr_cell_offset(e.raw(), offset), r));
|
||||||
|
m_post(e, r);
|
||||||
|
m_rs.push_back(r);
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Visit \c e at the given offset. Return true iff the result is on the
|
||||||
|
result stack \c m_rs. Return false iff a new frame was pushed on the stack \c m_fs.
|
||||||
|
The idea is that after the frame is processed, the result will be on the result stack.
|
||||||
|
*/
|
||||||
|
bool replace_fn::visit(expr const & e, unsigned offset) {
|
||||||
|
bool shared = false;
|
||||||
|
if (is_shared(e)) {
|
||||||
|
expr_cell_offset p(e.raw(), offset);
|
||||||
|
auto it = m_cache.find(p);
|
||||||
|
if (it != m_cache.end()) {
|
||||||
|
m_rs.push_back(it->second);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
shared = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
expr r = m_f(e, offset);
|
||||||
|
if (is_atomic(r) || !is_eqp(e, r)) {
|
||||||
|
save_result(e, r, offset, shared);
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
m_fs.emplace_back(e, offset, shared);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
\brief Return true iff <tt>f.m_index == idx</tt>.
|
||||||
|
When the result is true, <tt>f.m_index</tt> is incremented.
|
||||||
|
*/
|
||||||
|
bool replace_fn::check_index(frame & f, unsigned idx) {
|
||||||
|
if (f.m_index == idx) {
|
||||||
|
f.m_index++;
|
||||||
|
return true;
|
||||||
|
} else {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expr const & replace_fn::rs(int i) {
|
||||||
|
lean_assert(i < 0);
|
||||||
|
return m_rs[m_rs.size() + i];
|
||||||
|
}
|
||||||
|
|
||||||
|
void replace_fn::pop_rs(unsigned num) {
|
||||||
|
m_rs.shrink(m_rs.size() - num);
|
||||||
|
}
|
||||||
|
|
||||||
|
expr replace_fn::operator()(expr const & e) {
|
||||||
|
expr r;
|
||||||
|
visit(e, 0);
|
||||||
|
while (!m_fs.empty()) {
|
||||||
|
begin_loop:
|
||||||
|
check_interrupted();
|
||||||
|
frame & f = m_fs.back();
|
||||||
|
expr const & e = f.m_expr;
|
||||||
|
unsigned offset = f.m_offset;
|
||||||
|
switch (e.kind()) {
|
||||||
|
case expr_kind::Constant: case expr_kind::Sort:
|
||||||
|
case expr_kind::Macro: case expr_kind::Var:
|
||||||
|
lean_unreachable(); // LCOV_EXCL_LINE
|
||||||
|
case expr_kind::Meta: case expr_kind::Local:
|
||||||
|
if (check_index(f, 0) && !visit(mlocal_type(e), offset))
|
||||||
|
goto begin_loop;
|
||||||
|
r = update_mlocal(e, rs(-1));
|
||||||
|
pop_rs(1);
|
||||||
|
break;
|
||||||
|
case expr_kind::Pair:
|
||||||
|
if (check_index(f, 0) && !visit(pair_first(e), offset))
|
||||||
|
goto begin_loop;
|
||||||
|
if (check_index(f, 1) && !visit(pair_second(e), offset))
|
||||||
|
goto begin_loop;
|
||||||
|
if (check_index(f, 2) && !visit(pair_type(e), offset))
|
||||||
|
goto begin_loop;
|
||||||
|
r = update_pair(e, rs(-3), rs(-2), rs(-1));
|
||||||
|
pop_rs(3);
|
||||||
|
break;
|
||||||
|
case expr_kind::Fst: case expr_kind::Snd:
|
||||||
|
if (check_index(f, 0) && !visit(proj_arg(e), offset))
|
||||||
|
goto begin_loop;
|
||||||
|
r = update_proj(e, rs(-1));
|
||||||
|
pop_rs(1);
|
||||||
|
break;
|
||||||
|
case expr_kind::App:
|
||||||
|
if (check_index(f, 0) && !visit(app_fn(e), offset))
|
||||||
|
goto begin_loop;
|
||||||
|
if (check_index(f, 1) && !visit(app_arg(e), offset))
|
||||||
|
goto begin_loop;
|
||||||
|
r = update_app(e, rs(-2), rs(-1));
|
||||||
|
pop_rs(2);
|
||||||
|
break;
|
||||||
|
case expr_kind::Sigma: case expr_kind::Pi: case expr_kind::Lambda:
|
||||||
|
if (check_index(f, 0) && !visit(binder_domain(e), offset))
|
||||||
|
goto begin_loop;
|
||||||
|
if (check_index(f, 1) && !visit(binder_body(e), offset + 1))
|
||||||
|
goto begin_loop;
|
||||||
|
r = update_binder(e, rs(-2), rs(-1));
|
||||||
|
pop_rs(2);
|
||||||
|
break;
|
||||||
|
case expr_kind::Let:
|
||||||
|
if (check_index(f, 0) && let_type(e) && !visit(*let_type(e), offset))
|
||||||
|
goto begin_loop;
|
||||||
|
if (check_index(f, 1) && !visit(let_value(e), offset))
|
||||||
|
goto begin_loop;
|
||||||
|
if (check_index(f, 2) && !visit(let_body(e), offset + 1))
|
||||||
|
goto begin_loop;
|
||||||
|
if (let_type(e)) {
|
||||||
|
r = update_let(e, some_expr(rs(-3)), rs(-2), rs(-1));
|
||||||
|
pop_rs(3);
|
||||||
|
} else {
|
||||||
|
r = update_let(e, none_expr(), rs(-2), rs(-1));
|
||||||
|
pop_rs(2);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
save_result(e, r, offset, f.m_shared);
|
||||||
|
m_fs.pop_back();
|
||||||
|
}
|
||||||
|
lean_assert(m_rs.size() == 1);
|
||||||
|
r = m_rs.back();
|
||||||
|
m_rs.pop_back();
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
void replace_fn::clear() {
|
||||||
|
m_cache.clear();
|
||||||
|
m_fs.clear();
|
||||||
|
m_rs.clear();
|
||||||
|
}
|
||||||
|
}
|
|
@ -35,15 +35,7 @@ public:
|
||||||
P is a "post-processing" functional object that is applied to each
|
P is a "post-processing" functional object that is applied to each
|
||||||
pair (old, new)
|
pair (old, new)
|
||||||
*/
|
*/
|
||||||
template<typename F, typename P = default_replace_postprocessor>
|
|
||||||
class replace_fn {
|
class replace_fn {
|
||||||
static_assert(std::is_same<typename std::result_of<F(expr const &, unsigned)>::type, expr>::value,
|
|
||||||
"replace_fn: return type of F is not expr");
|
|
||||||
// the return type of P()(e1, e2) should be void
|
|
||||||
static_assert(std::is_same<typename std::result_of<decltype(std::declval<P>())(expr const &, expr const &)>::type,
|
|
||||||
void>::value,
|
|
||||||
"The return type of P()(e1, e2) is not void");
|
|
||||||
|
|
||||||
struct frame {
|
struct frame {
|
||||||
expr m_expr;
|
expr m_expr;
|
||||||
unsigned m_offset;
|
unsigned m_offset;
|
||||||
|
@ -54,179 +46,32 @@ class replace_fn {
|
||||||
typedef buffer<frame> frame_stack;
|
typedef buffer<frame> frame_stack;
|
||||||
typedef buffer<expr> result_stack;
|
typedef buffer<expr> result_stack;
|
||||||
|
|
||||||
expr_cell_offset_map<expr> m_cache;
|
expr_cell_offset_map<expr> m_cache;
|
||||||
F m_f;
|
std::function<expr(expr const &, unsigned)> m_f;
|
||||||
P m_post;
|
std::function<void(expr const &, expr const &)> m_post;
|
||||||
frame_stack m_fs;
|
frame_stack m_fs;
|
||||||
result_stack m_rs;
|
result_stack m_rs;
|
||||||
|
|
||||||
static bool is_atomic(expr const & e) {
|
static bool is_atomic(expr const & e);
|
||||||
switch (e.kind()) {
|
void save_result(expr const & e, expr const & r, unsigned offset, bool shared);
|
||||||
case expr_kind::Constant: case expr_kind::Type: case expr_kind::Value:
|
bool visit(expr const & e, unsigned offset);
|
||||||
case expr_kind::Var: case expr_kind::MetaVar:
|
bool check_index(frame & f, unsigned idx);
|
||||||
return true;
|
expr const & rs(int i);
|
||||||
default:
|
void pop_rs(unsigned num);
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void save_result(expr const & e, expr const & r, unsigned offset, bool shared) {
|
|
||||||
if (shared)
|
|
||||||
m_cache.insert(std::make_pair(expr_cell_offset(e.raw(), offset), r));
|
|
||||||
m_post(e, r);
|
|
||||||
m_rs.push_back(r);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
\brief Visit \c e at the given offset. Return true iff the result is on the
|
|
||||||
result stack \c m_rs. Return false iff a new frame was pushed on the stack \c m_fs.
|
|
||||||
The idea is that after the frame is processed, the result will be on the result stack.
|
|
||||||
*/
|
|
||||||
bool visit(expr const & e, unsigned offset) {
|
|
||||||
bool shared = false;
|
|
||||||
if (is_shared(e)) {
|
|
||||||
expr_cell_offset p(e.raw(), offset);
|
|
||||||
auto it = m_cache.find(p);
|
|
||||||
if (it != m_cache.end()) {
|
|
||||||
m_rs.push_back(it->second);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
shared = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
expr r = m_f(e, offset);
|
|
||||||
if (is_atomic(r) || !is_eqp(e, r)) {
|
|
||||||
save_result(e, r, offset, shared);
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
m_fs.emplace_back(e, offset, shared);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
\brief Return true iff <tt>f.m_index == idx</tt>.
|
|
||||||
When the result is true, <tt>f.m_index</tt> is incremented.
|
|
||||||
*/
|
|
||||||
bool check_index(frame & f, unsigned idx) {
|
|
||||||
if (f.m_index == idx) {
|
|
||||||
f.m_index++;
|
|
||||||
return true;
|
|
||||||
} else {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
expr const & rs(int i) {
|
|
||||||
lean_assert(i < 0);
|
|
||||||
return m_rs[m_rs.size() + i];
|
|
||||||
}
|
|
||||||
|
|
||||||
void pop_rs(unsigned num) {
|
|
||||||
m_rs.shrink(m_rs.size() - num);
|
|
||||||
}
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
template<typename F, typename P = default_replace_postprocessor>
|
||||||
replace_fn(F const & f, P const & p = P()):
|
replace_fn(F const & f, P const & p = P()):
|
||||||
m_f(f),
|
m_f(f), m_post(p) {}
|
||||||
m_post(p) {
|
expr operator()(expr const & e);
|
||||||
}
|
void clear();
|
||||||
|
|
||||||
expr operator()(expr const & e) {
|
|
||||||
expr r;
|
|
||||||
visit(e, 0);
|
|
||||||
while (!m_fs.empty()) {
|
|
||||||
begin_loop:
|
|
||||||
check_interrupted();
|
|
||||||
frame & f = m_fs.back();
|
|
||||||
expr const & e = f.m_expr;
|
|
||||||
unsigned offset = f.m_offset;
|
|
||||||
switch (e.kind()) {
|
|
||||||
case expr_kind::Constant: case expr_kind::Type: case expr_kind::Value: case expr_kind::Var: case expr_kind::MetaVar:
|
|
||||||
lean_unreachable(); // LCOV_EXCL_LINE
|
|
||||||
case expr_kind::HEq:
|
|
||||||
if (check_index(f, 0) && !visit(heq_lhs(e), offset))
|
|
||||||
goto begin_loop;
|
|
||||||
if (check_index(f, 1) && !visit(heq_rhs(e), offset))
|
|
||||||
goto begin_loop;
|
|
||||||
r = update_heq(e, rs(-2), rs(-1));
|
|
||||||
pop_rs(2);
|
|
||||||
break;
|
|
||||||
case expr_kind::Pair:
|
|
||||||
if (check_index(f, 0) && !visit(pair_first(e), offset))
|
|
||||||
goto begin_loop;
|
|
||||||
if (check_index(f, 1) && !visit(pair_second(e), offset))
|
|
||||||
goto begin_loop;
|
|
||||||
if (check_index(f, 2) && !visit(pair_type(e), offset))
|
|
||||||
goto begin_loop;
|
|
||||||
r = update_pair(e, rs(-3), rs(-2), rs(-1));
|
|
||||||
pop_rs(3);
|
|
||||||
break;
|
|
||||||
case expr_kind::Proj:
|
|
||||||
if (check_index(f, 0) && !visit(proj_arg(e), offset))
|
|
||||||
goto begin_loop;
|
|
||||||
r = update_proj(e, rs(-1));
|
|
||||||
pop_rs(1);
|
|
||||||
break;
|
|
||||||
case expr_kind::App: {
|
|
||||||
unsigned num = num_args(e);
|
|
||||||
while (f.m_index < num) {
|
|
||||||
expr const & c = arg(e, f.m_index);
|
|
||||||
f.m_index++;
|
|
||||||
if (!visit(c, offset))
|
|
||||||
goto begin_loop;
|
|
||||||
}
|
|
||||||
r = update_app(e, num, m_rs.end() - num_args(e));
|
|
||||||
pop_rs(num);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
case expr_kind::Sigma: case expr_kind::Pi: case expr_kind::Lambda:
|
|
||||||
if (check_index(f, 0) && !visit(abst_domain(e), offset))
|
|
||||||
goto begin_loop;
|
|
||||||
if (check_index(f, 1) && !visit(abst_body(e), offset + 1))
|
|
||||||
goto begin_loop;
|
|
||||||
r = update_abstraction(e, rs(-2), rs(-1));
|
|
||||||
pop_rs(2);
|
|
||||||
break;
|
|
||||||
case expr_kind::Let:
|
|
||||||
if (check_index(f, 0) && let_type(e) && !visit(*let_type(e), offset))
|
|
||||||
goto begin_loop;
|
|
||||||
if (check_index(f, 1) && !visit(let_value(e), offset))
|
|
||||||
goto begin_loop;
|
|
||||||
if (check_index(f, 2) && !visit(let_body(e), offset + 1))
|
|
||||||
goto begin_loop;
|
|
||||||
if (let_type(e)) {
|
|
||||||
r = update_let(e, some_expr(rs(-3)), rs(-2), rs(-1));
|
|
||||||
pop_rs(3);
|
|
||||||
} else {
|
|
||||||
r = update_let(e, none_expr(), rs(-2), rs(-1));
|
|
||||||
pop_rs(2);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
save_result(e, r, offset, f.m_shared);
|
|
||||||
m_fs.pop_back();
|
|
||||||
}
|
|
||||||
lean_assert(m_rs.size() == 1);
|
|
||||||
r = m_rs.back();
|
|
||||||
m_rs.pop_back();
|
|
||||||
return r;
|
|
||||||
}
|
|
||||||
|
|
||||||
void clear() {
|
|
||||||
m_cache.clear();
|
|
||||||
m_fs.clear();
|
|
||||||
m_rs.clear();
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
template<typename F>
|
template<typename F> expr replace(expr const & e, F const & f) {
|
||||||
expr replace(expr const & e, F f) {
|
return replace_fn(f)(e);
|
||||||
return replace_fn<F>(f)(e);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename F, typename P>
|
template<typename F, typename P> expr replace(expr const & e, F const & f, P const & p) {
|
||||||
expr replace(expr const & e, F f, P p) {
|
return replace_fn(f, p)(e);
|
||||||
return replace_fn<F, P>(f, p)(e);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue