lean4-htt/src/library/vm/interaction_state_imp.h
2018-10-02 08:44:05 -07:00

288 lines
10 KiB
C++

/*
Copyright (c) 2017 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura, Sebastian Ullrich
*/
#pragma once
#include "runtime/sstream.h"
#include "util/fresh_name.h"
#include "kernel/instantiate.h"
#include "library/profiling.h"
#include "library/constants.h"
#include "library/message_builder.h"
#include "library/time_task.h"
#include "library/vm/interaction_state.h"
#include "library/vm/vm_format.h"
#include "library/vm/vm_string.h"
#include "library/vm/vm_options.h"
#include "library/vm/vm_name.h"
#include "library/vm/vm_nat.h"
#include "library/vm/vm_option.h"
#include "library/vm/vm_pos_info.h"
#include "library/compiler/vm_compiler.h"
namespace lean {
template<typename State>
interaction_monad<State>::vm_State::vm_State(State const & v) : m_val(v) {}
template<typename State>
interaction_monad<State>::vm_State::~vm_State() {}
template<typename State>
void interaction_monad<State>::vm_State::dealloc() {
delete this;
}
template<typename State>
vm_external * interaction_monad<State>::vm_State::ts_clone(vm_clone_fn const &) {
return new vm_State(m_val);
}
template<typename State>
vm_external * interaction_monad<State>::vm_State::clone(vm_clone_fn const &) {
return new vm_State(m_val);
}
template<typename State>
bool interaction_monad<State>::is_state(vm_obj const & o) {
return is_external(o) && dynamic_cast<vm_State *>(to_external(o));
}
template<typename State>
auto interaction_monad<State>::to_state(vm_obj const & o) -> State const & {
lean_vm_check(dynamic_cast<vm_State*>(to_external(o)));
return static_cast<vm_State *>(to_external(o))->m_val;
}
template<typename State>
vm_obj interaction_monad<State>::to_obj(State const & s) {
return mk_vm_external(new vm_State(s));
}
template<typename State>
bool interaction_monad<State>::is_silent_exception(vm_obj const & ex) {
return is_constructor(ex) && cidx(ex) == 1 && is_none(cfield(ex, 0));
}
template<typename State>
vm_obj interaction_monad<State>::mk_success(vm_obj const & a, vm_obj const & s) {
lean_assert(is_state(s));
return mk_vm_constructor(0, a, s);
}
template<typename State>
bool interaction_monad<State>::is_result_exception(vm_obj const & r) {
return is_constructor(r) && cidx(r) == 1;
}
template<typename State>
vm_obj interaction_monad<State>::get_exception_message(vm_obj const & r) {
lean_assert(is_result_exception(r));
return cfield(r, 0);
}
template<typename State>
vm_obj interaction_monad<State>::get_exception_pos(vm_obj const & r) {
lean_assert(is_result_exception(r));
return cfield(r, 1);
}
template<typename State>
vm_obj interaction_monad<State>::get_exception_state(vm_obj const & r) {
lean_assert(is_result_exception(r));
return cfield(r, 2);
}
template<typename State>
bool interaction_monad<State>::is_result_success(vm_obj const & r) {
return is_constructor(r) && cidx(r) == 0;
}
template<typename State>
vm_obj interaction_monad<State>::get_success_value(vm_obj const & r) {
lean_assert(is_result_success(r));
return cfield(r, 0);
}
template<typename State>
vm_obj interaction_monad<State>::get_success_state(vm_obj const & r) {
lean_assert(is_result_success(r));
return cfield(r, 1);
}
template<typename State>
vm_obj interaction_monad<State>::mk_success(vm_obj const & a, State const & s) {
return mk_vm_constructor(0, a, to_obj(s));
}
template<typename State>
vm_obj interaction_monad<State>::mk_success(State const & s) {
return mk_success(mk_vm_unit(), s);
}
template<typename State>
vm_obj interaction_monad<State>::mk_exception(vm_obj const & fn, State const & s) {
return mk_vm_constructor(1, mk_vm_some(fn), mk_vm_none(), to_obj(s));
}
template<typename State>
vm_obj interaction_monad<State>::mk_silent_exception(State const & s) {
return mk_vm_constructor(1, mk_vm_none(), mk_vm_none(), to_obj(s));
}
template<typename State>
vm_obj interaction_monad<State>::mk_exception(vm_obj const & fn, vm_obj const & pos, State const & s) {
return mk_vm_constructor(1, mk_vm_some(fn), pos, to_obj(s));
}
template<typename State>
vm_obj interaction_monad<State>::update_exception_state(vm_obj const & ex, State const & s) {
lean_assert(is_result_exception(ex));
return mk_exception(get_exception_message(ex), get_exception_pos(ex), s);
}
template<typename State>
vm_obj interaction_monad<State>::mk_exception(std::exception_ptr const &, State const &) {
// vm_exceptional has been deleted
lean_unreachable();
}
template<typename State>
vm_obj interaction_monad<State>::mk_exception(format const & fmt, State const & s) {
vm_state const & S = get_vm_state();
if (optional<vm_decl> K = S.get_decl(get_combinator_K_name())) {
return mk_exception(mk_vm_closure(K->get_idx(), lean::to_obj(fmt), mk_vm_unit(), mk_vm_unit()), s);
} else {
throw exception("failed to create tactic exceptional result, combinator.K is not in the environment, "
"this can happen when users are hacking the init folder");
}
}
template<typename State>
vm_obj interaction_monad<State>::mk_exception(char const * msg, State const & s) {
return mk_exception(format(msg), s);
}
template<typename State>
vm_obj interaction_monad<State>::mk_exception(sstream const & strm, State const & s) {
return mk_exception(strm.str().c_str(), s);
}
template<typename State>
vm_obj interaction_monad<State>::mk_exception(std::function<format()> const & thunk, State const & s) {
return mk_exception(mk_vm_format_thunk(thunk), s);
}
template<typename State>
void interaction_monad<State>::report_exception(vm_state & S, vm_obj const & r) {
if (optional<exception_info> ex = is_exception(S, r)) {
format fmt = std::get<0>(*ex);
optional<pos_info> pos = std::get<1>(*ex);
throw formatted_exception(pos, fmt);
}
}
template<typename State>
auto interaction_monad<State>::is_success(vm_obj const & r) -> optional<State> {
if (is_result_success(r))
return some(to_state(get_success_state(r)));
return {};
}
template<typename State>
auto interaction_monad<State>::is_exception(vm_state & S, vm_obj const & ex) -> optional<exception_info> {
if (is_result_exception(ex) && !is_none(get_exception_message(ex))) {
vm_obj fmt = S.invoke(get_some_value(get_exception_message(ex)), mk_vm_unit());
optional<pos_info> p;
if (!is_none(get_exception_pos(ex))) {
auto vm_p = get_some_value(get_exception_pos(ex));
p = some(to_pos_info(vm_p));
}
return optional<exception_info>(to_format(fmt), p, to_state(get_exception_state(ex)));
} else {
return {};
}
}
template<typename State>
void interaction_monad<State>::evaluator::process_failure(vm_state & S, vm_obj const & r) {
report_exception(S, r);
/* Do nothing if it is a silent failure */
lean_assert(is_silent_exception(r));
}
template<typename State>
environment interaction_monad<State>::evaluator::compile(name const & interaction_name, expr const & interaction) {
pos_info_provider * provider = get_pos_info_provider();
expr interaction_type = m_ctx.infer(interaction);
environment new_env = m_ctx.env();
bool is_meta = true;
new_env = new_env.add(mk_definition(new_env, interaction_name, {}, interaction_type, interaction, is_meta));
try {
bool optimize_bytecode = false;
if (provider) {
auto out = message_builder(environment(), get_global_ios(),
get_pos_info_provider()->get_file_name(),
get_pos_info_provider()->get_pos_info_or_some(interaction),
INFORMATION);
time_task _("elaboration: tactic compilation", out);
return vm_compile(new_env, get_global_ios().get_options(), new_env.get(interaction_name), optimize_bytecode);
} else {
return vm_compile(new_env, get_global_ios().get_options(), new_env.get(interaction_name), optimize_bytecode);
}
} catch (exception & ex) {
throw formatted_exception(some(interaction), format(ex.what()));
}
}
template<typename State>
vm_obj interaction_monad<State>::evaluator::invoke(vm_state & S, name const & interaction_name, std::initializer_list<vm_obj> const & args) {
vm_state::profiler prof(S, m_opts);
vm_obj r = S.invoke(interaction_name, args);
if (prof.enabled()) {
prof.get_snapshots().display("tactic", m_opts, get_global_ios().get_regular_stream());
}
return r;
}
template<typename State>
interaction_monad<State>::evaluator::evaluator(type_context_old & ctx, options const & opts, bool allow_profiler):
m_ctx(ctx), m_opts(opts) {
if (!allow_profiler)
// do not bother to invoke the profiler for most trivial calls into Lean
m_opts = m_opts.update("profiler", false);
}
template<typename State>
vm_obj interaction_monad<State>::evaluator::operator()(expr const & interaction, buffer<vm_obj> const & args, State const & s) {
name interaction_name("_interaction");
environment new_env = compile(interaction_name, interaction);
vm_state S(new_env, m_opts);
scope_vm_state scope(S);
vm_state::profiler prof(S, m_opts);
buffer<vm_obj> args_s;
args_s.append(args);
args_s.push_back(to_obj(s));
vm_obj r = S.invoke(S.get_constant(interaction_name), args_s.size(), args_s.data());
if (prof.enabled() && get_pos_info_provider()) {
auto out = message_builder(environment(), get_global_ios(),
get_pos_info_provider()->get_file_name(),
get_pos_info_provider()->get_pos_info_or_some(interaction),
INFORMATION);
out.set_caption("tactic profile data");
if (prof.get_snapshots().display("elaboration: tactic", m_opts, out.get_text_stream().get_stream()))
out.report();
}
if (!is_success(r))
process_failure(S, r);
return r;
}
template<typename State>
vm_obj interaction_monad<State>::evaluator::operator()(expr const & interaction, State const & s) {
buffer<vm_obj> args;
return operator()(interaction, args, s);
}
}