483 lines
16 KiB
C++
483 lines
16 KiB
C++
/*
|
|
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
Author: Leonardo de Moura
|
|
*/
|
|
#include <limits>
|
|
#include <string>
|
|
#include "util/fresh_name.h"
|
|
#include "kernel/type_checker.h"
|
|
#include "library/io_state.h"
|
|
#include "library/util.h"
|
|
#include "library/attribute_manager.h"
|
|
#include "library/constants.h"
|
|
#include "library/vm/vm.h"
|
|
#include "library/vm/vm_option.h"
|
|
#include "library/vm/vm_nat.h"
|
|
#include "library/vm/vm_string.h"
|
|
#include "library/vm/vm_name.h"
|
|
#include "library/vm/vm_options.h"
|
|
#include "library/vm/vm_level.h"
|
|
#include "library/vm/vm_expr.h"
|
|
#include "library/vm/vm_declaration.h"
|
|
#include "library/vm/vm_environment.h"
|
|
#include "library/vm/vm_format.h"
|
|
#include "library/vm/vm_list.h"
|
|
#include "library/compiler/vm_compiler.h"
|
|
#include "library/tactic/tactic_state.h"
|
|
|
|
namespace lean {
|
|
vm_obj _vm_monitor_register(vm_obj const & vm_n, vm_obj const & vm_s) {
|
|
auto const & s = to_tactic_state(vm_s);
|
|
auto const & n = to_name(vm_n);
|
|
LEAN_TACTIC_TRY;
|
|
return mk_tactic_success(set_env(s, vm_monitor_register(s.env(), n)));
|
|
LEAN_TACTIC_CATCH(s);
|
|
}
|
|
|
|
vm_obj vm_core_map(vm_obj const &, vm_obj const &, vm_obj const & fn, vm_obj const & a, vm_obj const & s) {
|
|
vm_obj v = invoke(a, s);
|
|
return invoke(fn, v);
|
|
}
|
|
|
|
vm_obj vm_core_ret(vm_obj const &, vm_obj const & a, vm_obj const & /* s */) {
|
|
return a;
|
|
}
|
|
|
|
vm_obj vm_core_bind(vm_obj const &, vm_obj const &, vm_obj const & a, vm_obj const & b, vm_obj const & s) {
|
|
return invoke(b, invoke(a, s), s);
|
|
}
|
|
|
|
/*
|
|
inductive vm_obj_kind
|
|
| simple | constructor | closure | mpz
|
|
| name | level | expr | declaration
|
|
| environment | tactic_state | format
|
|
| options | other
|
|
*/
|
|
vm_obj _vm_obj_kind(vm_obj const & o) {
|
|
switch (o.kind()) {
|
|
case vm_obj_kind::Simple: return mk_vm_simple(0);
|
|
case vm_obj_kind::Constructor: return mk_vm_simple(1);
|
|
case vm_obj_kind::Closure: return mk_vm_simple(2);
|
|
case vm_obj_kind::NativeClosure: return mk_vm_simple(3);
|
|
case vm_obj_kind::MPZ: return mk_vm_simple(4);
|
|
case vm_obj_kind::External:
|
|
if (is_name(o)) return mk_vm_simple(5);
|
|
else if (is_level(o)) return mk_vm_simple(6);
|
|
else if (is_expr(o)) return mk_vm_simple(7);
|
|
else if (is_declaration(o)) return mk_vm_simple(8);
|
|
else if (is_env(o)) return mk_vm_simple(9);
|
|
else if (is_tactic_state(o)) return mk_vm_simple(10);
|
|
else if (is_format(o)) return mk_vm_simple(11);
|
|
else if (is_options(o)) return mk_vm_simple(12);
|
|
else return mk_vm_simple(13);
|
|
}
|
|
lean_unreachable();
|
|
}
|
|
|
|
vm_obj vm_obj_cidx(vm_obj const & o) {
|
|
switch (o.kind()) {
|
|
case vm_obj_kind::Simple:
|
|
case vm_obj_kind::Constructor:
|
|
return mk_vm_nat(cidx(o));
|
|
default:
|
|
return mk_vm_nat(0);
|
|
}
|
|
}
|
|
|
|
vm_obj vm_obj_fn_idx(vm_obj const & o) {
|
|
switch (o.kind()) {
|
|
case vm_obj_kind::Closure:
|
|
return mk_vm_nat(cfn_idx(o));
|
|
default:
|
|
return mk_vm_nat(0);
|
|
}
|
|
}
|
|
|
|
vm_obj vm_obj_fields(vm_obj const & o) {
|
|
switch (o.kind()) {
|
|
case vm_obj_kind::Constructor: {
|
|
unsigned i = csize(o);
|
|
vm_obj r = mk_vm_simple(0);
|
|
while (i > 0) {
|
|
--i;
|
|
r = mk_vm_constructor(1, cfield(o, i), r);
|
|
}
|
|
return r;
|
|
}
|
|
default:
|
|
return mk_vm_simple(0);
|
|
}
|
|
}
|
|
|
|
vm_obj vm_obj_to_nat(vm_obj const & o) {
|
|
switch (o.kind()) {
|
|
case vm_obj_kind::Simple:
|
|
case vm_obj_kind::MPZ:
|
|
return o;
|
|
default:
|
|
return mk_vm_nat(0);
|
|
}
|
|
}
|
|
|
|
vm_obj vm_obj_to_name(vm_obj const & o) {
|
|
if (is_name(o))
|
|
return o;
|
|
else
|
|
return to_obj(name());
|
|
}
|
|
|
|
vm_obj vm_obj_to_level(vm_obj const & o) {
|
|
if (is_level(o))
|
|
return o;
|
|
else
|
|
return to_obj(level());
|
|
}
|
|
|
|
vm_obj vm_obj_to_expr(vm_obj const & o) {
|
|
if (is_expr(o))
|
|
return o;
|
|
else
|
|
return to_obj(expr());
|
|
}
|
|
|
|
vm_obj vm_obj_to_declaration(vm_obj const & o) {
|
|
if (is_declaration(o))
|
|
return o;
|
|
else
|
|
return to_obj(declaration());
|
|
}
|
|
|
|
vm_obj vm_obj_to_environment(vm_obj const & o) {
|
|
if (is_env(o))
|
|
return o;
|
|
else
|
|
return to_obj(environment());
|
|
}
|
|
|
|
vm_obj vm_obj_to_tactic_state(vm_obj const & o) {
|
|
if (is_tactic_state(o))
|
|
return o;
|
|
else
|
|
return to_obj(mk_tactic_state_for(environment(), options(), local_context(), mk_Prop()));
|
|
}
|
|
|
|
vm_obj vm_obj_to_format(vm_obj const & o) {
|
|
if (is_format(o))
|
|
return o;
|
|
else
|
|
return to_obj(format());
|
|
}
|
|
|
|
struct vm_vm_decl : public vm_external {
|
|
vm_decl m_val;
|
|
vm_vm_decl(vm_decl const & v):m_val(v) {}
|
|
virtual ~vm_vm_decl() {}
|
|
virtual void dealloc() override { this->~vm_vm_decl(); get_vm_allocator().deallocate(sizeof(vm_vm_decl), this); }
|
|
};
|
|
|
|
vm_decl const & to_vm_decl(vm_obj const & o) {
|
|
lean_assert(is_external(o));
|
|
lean_assert(dynamic_cast<vm_vm_decl*>(to_external(o)));
|
|
return static_cast<vm_vm_decl*>(to_external(o))->m_val;
|
|
}
|
|
|
|
vm_obj to_obj(vm_decl const & e) {
|
|
return mk_vm_external(new (get_vm_allocator().allocate(sizeof(vm_vm_decl))) vm_vm_decl(e));
|
|
}
|
|
|
|
/*
|
|
inductive vm_decl_kind
|
|
| bytecode | builtin | cfun
|
|
*/
|
|
vm_obj _vm_decl_kind(vm_obj const & d) {
|
|
switch (to_vm_decl(d).kind()) {
|
|
case vm_decl_kind::Bytecode: return mk_vm_simple(0);
|
|
case vm_decl_kind::Builtin: return mk_vm_simple(1);
|
|
case vm_decl_kind::CFun: return mk_vm_simple(2);
|
|
}
|
|
lean_unreachable();
|
|
}
|
|
|
|
vm_obj vm_decl_to_name(vm_obj const & d) {
|
|
return to_obj(to_vm_decl(d).get_name());
|
|
}
|
|
|
|
vm_obj vm_decl_idx(vm_obj const & d) {
|
|
return mk_vm_nat(to_vm_decl(d).get_idx());
|
|
}
|
|
|
|
vm_obj vm_decl_arity(vm_obj const & d) {
|
|
return mk_vm_nat(to_vm_decl(d).get_arity());
|
|
}
|
|
|
|
vm_obj vm_decl_pos(vm_obj const & d) {
|
|
if (optional<pos_info> pos = to_vm_decl(d).get_pos_info())
|
|
return mk_vm_some(mk_vm_pair(mk_vm_nat(pos->first), mk_vm_nat(pos->second)));
|
|
else
|
|
return mk_vm_none();
|
|
}
|
|
|
|
vm_obj vm_decl_olean(vm_obj const & d) {
|
|
if (optional<std::string> olean = to_vm_decl(d).get_olean())
|
|
return mk_vm_some(to_obj(*olean));
|
|
else
|
|
return mk_vm_none();
|
|
}
|
|
|
|
vm_obj vm_decl_args_info(vm_obj const & d) {
|
|
return to_vm_list(to_vm_decl(d).get_args_info(),
|
|
[](vm_local_info const & info) {
|
|
return mk_vm_pair(to_obj(info.first), to_obj(info.second));
|
|
});
|
|
}
|
|
|
|
static vm_obj mk_vm_success(vm_obj const & o) {
|
|
return mk_vm_some(o);
|
|
}
|
|
|
|
static vm_obj mk_vm_failure() {
|
|
return mk_vm_none();
|
|
}
|
|
|
|
vm_obj vm_get_decl(vm_obj const & n, vm_obj const & /*s*/) {
|
|
if (optional<vm_decl> d = get_vm_state_being_debugged().get_decl(to_name(n)))
|
|
return mk_vm_success(to_obj(*d));
|
|
else
|
|
return mk_vm_failure();
|
|
}
|
|
|
|
vm_obj vm_stack_size(vm_obj const & /*s*/) {
|
|
return mk_vm_success(mk_vm_nat(get_vm_state_being_debugged().stack_size()));
|
|
}
|
|
|
|
vm_obj vm_stack_obj(vm_obj const & i, vm_obj const & /*s*/) {
|
|
auto const & vm = get_vm_state_being_debugged();
|
|
unsigned idx = force_to_unsigned(i);
|
|
if (idx >= vm.stack_size()) return mk_vm_failure();
|
|
return mk_vm_success(vm.get_core(idx));
|
|
}
|
|
|
|
vm_obj vm_stack_obj_info(vm_obj const & i, vm_obj const & /*s*/) {
|
|
auto const & vm = get_vm_state_being_debugged();
|
|
unsigned idx = force_to_unsigned(i);
|
|
vm_local_info info = vm.get_info(idx);
|
|
return mk_vm_success(mk_vm_pair(to_obj(info.first), to_obj(info.second)));
|
|
}
|
|
|
|
static format default_format(vm_state const & vm, unsigned idx) {
|
|
lean_assert(idx < vm.stack_size());
|
|
vm_obj o = vm.get_core(idx);
|
|
vm_local_info info = vm.get_info(idx);
|
|
if (auto type = info.second) {
|
|
try {
|
|
vm_state & curr_vm = get_vm_state();
|
|
type_context ctx(curr_vm.env());
|
|
level u = get_level(ctx, *type);
|
|
expr has_to_format = mk_app(mk_constant(get_has_to_format_name(), {u}), *type);
|
|
if (optional<expr> instance = ctx.mk_class_instance(has_to_format)) {
|
|
environment aux_env = curr_vm.env();
|
|
/* type -> format */
|
|
expr aux_type = mk_arrow(*type, mk_constant(get_format_name()));
|
|
/* (@to_fmt type *instance) */
|
|
expr aux_value = mk_app(mk_constant(get_to_fmt_name(), {u}), *type, *instance);
|
|
name aux_name = mk_tagged_fresh_name("_to_fmt_obj");
|
|
auto cd = check(aux_env, mk_definition(aux_env, aux_name, {}, aux_type, aux_value, true, false));
|
|
aux_env = aux_env.add(cd);
|
|
aux_env = vm_compile(aux_env, aux_env.get(aux_name));
|
|
curr_vm.update_env(aux_env);
|
|
vm_obj fn = curr_vm.get_constant(aux_name);
|
|
vm_obj r = invoke(fn, o);
|
|
lean_assert(is_format(r));
|
|
return to_format(r);
|
|
}
|
|
} catch (exception &) {
|
|
}
|
|
}
|
|
std::ostringstream out;
|
|
get_vm_state_being_debugged().display(out, o);
|
|
return format(out.str());
|
|
}
|
|
|
|
vm_obj vm_pp_stack_obj(vm_obj const & i, vm_obj const & /*s*/) {
|
|
auto const & vm = get_vm_state_being_debugged();
|
|
unsigned idx = force_to_unsigned(i);
|
|
if (idx >= vm.stack_size()) return mk_vm_failure();
|
|
vm_obj o = vm.get_core(idx);
|
|
|
|
format r;
|
|
if (is_expr(o)) {
|
|
formatter_factory const & fmtf = get_global_ios().get_formatter_factory();
|
|
type_context ctx(vm.env());
|
|
formatter fmt = fmtf(vm.env(), vm.get_options(), ctx);
|
|
try {
|
|
r = fmt(to_expr(o));
|
|
} catch (exception &) {
|
|
r = default_format(vm, idx);
|
|
}
|
|
} else if (is_tactic_state(o)) {
|
|
r = to_tactic_state(o).pp_core();
|
|
} else if (is_env(o)) {
|
|
r = format("[environment]");
|
|
} else {
|
|
r = default_format(vm, idx);
|
|
}
|
|
return mk_vm_success(to_obj(r));
|
|
}
|
|
|
|
vm_obj vm_call_stack_size(vm_obj const & /*s*/) {
|
|
return mk_vm_success(mk_vm_nat(get_vm_state_being_debugged().call_stack_size()));
|
|
}
|
|
|
|
vm_obj vm_call_stack_fn(vm_obj const & i, vm_obj const & /*s*/) {
|
|
auto const & vm = get_vm_state_being_debugged();
|
|
unsigned idx = force_to_unsigned(i);
|
|
if (idx >= vm.call_stack_size()) return mk_vm_failure();
|
|
return mk_vm_success(to_obj(vm.call_stack_fn(idx)));
|
|
}
|
|
|
|
vm_obj vm_call_stack_var_range(vm_obj const & i, vm_obj const & /*s*/) {
|
|
auto const & vm = get_vm_state_being_debugged();
|
|
unsigned idx = force_to_unsigned(i);
|
|
unsigned csz = vm.call_stack_size();
|
|
if (idx >= csz) {
|
|
return mk_vm_failure();
|
|
} else {
|
|
lean_assert(csz > 0);
|
|
unsigned start, end;
|
|
if (idx == csz - 1) {
|
|
start = vm.bp();
|
|
end = vm.stack_size();
|
|
} else if (idx == csz - 2) {
|
|
start = vm.call_stack_bp(csz - 1);
|
|
end = vm.bp();
|
|
} else {
|
|
lean_assert(idx < csz - 2);
|
|
start = vm.call_stack_bp(idx + 1);
|
|
end = vm.call_stack_bp(idx + 2);
|
|
}
|
|
return mk_vm_success(mk_vm_pair(mk_vm_nat(start), mk_vm_nat(end)));
|
|
}
|
|
}
|
|
|
|
vm_obj vm_bp(vm_obj const & /*s*/) {
|
|
return mk_vm_success(mk_vm_nat(get_vm_state_being_debugged().bp()));
|
|
}
|
|
|
|
vm_obj vm_pc(vm_obj const & /*s*/) {
|
|
return mk_vm_success(mk_vm_nat(get_vm_state_being_debugged().pc()));
|
|
}
|
|
|
|
vm_obj vm_get_options(vm_obj const & /*s*/) {
|
|
return mk_vm_success(to_obj(get_vm_state_being_debugged().get_options()));
|
|
}
|
|
|
|
vm_obj vm_curr_fn(vm_obj const & /*s*/) {
|
|
return mk_vm_success(to_obj(get_vm_state_being_debugged().curr_fn()));
|
|
}
|
|
|
|
vm_obj vm_obj_to_string(vm_obj const & o, vm_obj const & /*s*/) {
|
|
std::ostringstream out;
|
|
get_vm_state_being_debugged().display(out, o);
|
|
return mk_vm_success(to_obj(out.str()));
|
|
}
|
|
|
|
vm_obj vm_put_str(vm_obj const & str, vm_obj const &) {
|
|
get_global_ios().get_regular_stream() << to_string(str);
|
|
return mk_vm_success(mk_vm_unit());
|
|
}
|
|
|
|
vm_obj vm_get_line(vm_obj const &) {
|
|
if (get_global_ios().get_options().get_bool("server"))
|
|
return mk_vm_failure();
|
|
std::string str;
|
|
std::getline(std::cin, str);
|
|
return mk_vm_success(to_obj(str));
|
|
}
|
|
|
|
vm_obj vm_eof(vm_obj const &) {
|
|
if (get_global_ios().get_options().get_bool("server"))
|
|
return mk_vm_failure();
|
|
return mk_vm_success(mk_vm_bool(std::cin.eof()));
|
|
}
|
|
|
|
vm_obj vm_get_env(vm_obj const &) {
|
|
return mk_vm_success(to_obj(get_vm_state_being_debugged().env()));
|
|
}
|
|
|
|
vm_obj vm_get_attribute(vm_obj const & vm_n, vm_obj const &) {
|
|
auto const & n = to_name(vm_n);
|
|
buffer<name> b;
|
|
try {
|
|
environment const & env = get_vm_state_being_debugged().env();
|
|
get_attribute(env, n).get_instances(env, b);
|
|
return mk_vm_success(to_obj(b));
|
|
} catch (exception &) {
|
|
return mk_vm_failure();
|
|
}
|
|
}
|
|
|
|
vm_obj vm_pp_expr(vm_obj const & e, vm_obj const &) {
|
|
auto const & vm = get_vm_state_being_debugged();
|
|
formatter_factory const & fmtf = get_global_ios().get_formatter_factory();
|
|
type_context ctx(vm.env());
|
|
formatter fmt = fmtf(vm.env(), vm.get_options(), ctx);
|
|
try {
|
|
return mk_vm_success(to_obj(fmt(to_expr(e))));
|
|
} catch (exception &) {
|
|
std::ostringstream out;
|
|
out << to_expr(e);
|
|
return mk_vm_success(to_obj(format(out.str())));
|
|
}
|
|
}
|
|
|
|
void initialize_vm_monitor() {
|
|
DECLARE_VM_BUILTIN(name({"vm_monitor", "register"}), _vm_monitor_register);
|
|
DECLARE_VM_BUILTIN(name({"vm_core", "map"}), vm_core_map);
|
|
DECLARE_VM_BUILTIN(name({"vm_core", "ret"}), vm_core_ret);
|
|
DECLARE_VM_BUILTIN(name({"vm_core", "bind"}), vm_core_bind);
|
|
DECLARE_VM_BUILTIN(name({"vm_obj", "kind"}), _vm_obj_kind);
|
|
DECLARE_VM_BUILTIN(name({"vm_obj", "cidx"}), vm_obj_cidx);
|
|
DECLARE_VM_BUILTIN(name({"vm_obj", "fn_idx"}), vm_obj_fn_idx);
|
|
DECLARE_VM_BUILTIN(name({"vm_obj", "fields"}), vm_obj_fields);
|
|
DECLARE_VM_BUILTIN(name({"vm_obj", "to_nat"}), vm_obj_to_nat);
|
|
DECLARE_VM_BUILTIN(name({"vm_obj", "to_name"}), vm_obj_to_name);
|
|
DECLARE_VM_BUILTIN(name({"vm_obj", "to_level"}), vm_obj_to_level);
|
|
DECLARE_VM_BUILTIN(name({"vm_obj", "to_expr"}), vm_obj_to_expr);
|
|
DECLARE_VM_BUILTIN(name({"vm_obj", "to_declaration"}), vm_obj_to_declaration);
|
|
DECLARE_VM_BUILTIN(name({"vm_obj", "to_environment"}), vm_obj_to_environment);
|
|
DECLARE_VM_BUILTIN(name({"vm_obj", "to_tactic_state"}), vm_obj_to_tactic_state);
|
|
DECLARE_VM_BUILTIN(name({"vm_obj", "to_format"}), vm_obj_to_format);
|
|
DECLARE_VM_BUILTIN(name({"vm_decl", "kind"}), _vm_decl_kind);
|
|
DECLARE_VM_BUILTIN(name({"vm_decl", "to_name"}), vm_decl_to_name);
|
|
DECLARE_VM_BUILTIN(name({"vm_decl", "idx"}), vm_decl_idx);
|
|
DECLARE_VM_BUILTIN(name({"vm_decl", "arity"}), vm_decl_arity);
|
|
DECLARE_VM_BUILTIN(name({"vm_decl", "pos"}), vm_decl_pos);
|
|
DECLARE_VM_BUILTIN(name({"vm_decl", "olean"}), vm_decl_olean);
|
|
DECLARE_VM_BUILTIN(name({"vm_decl", "args_info"}), vm_decl_args_info);
|
|
DECLARE_VM_BUILTIN(name({"vm", "get_env"}), vm_get_env);
|
|
DECLARE_VM_BUILTIN(name({"vm", "get_decl"}), vm_get_decl);
|
|
DECLARE_VM_BUILTIN(name({"vm", "stack_size"}), vm_stack_size);
|
|
DECLARE_VM_BUILTIN(name({"vm", "stack_obj"}), vm_stack_obj);
|
|
DECLARE_VM_BUILTIN(name({"vm", "stack_obj_info"}), vm_stack_obj_info);
|
|
DECLARE_VM_BUILTIN(name({"vm", "call_stack_size"}), vm_call_stack_size);
|
|
DECLARE_VM_BUILTIN(name({"vm", "call_stack_fn"}), vm_call_stack_fn);
|
|
DECLARE_VM_BUILTIN(name({"vm", "call_stack_var_range"}), vm_call_stack_var_range);
|
|
DECLARE_VM_BUILTIN(name({"vm", "bp"}), vm_bp);
|
|
DECLARE_VM_BUILTIN(name({"vm", "pc"}), vm_pc);
|
|
DECLARE_VM_BUILTIN(name({"vm", "curr_fn"}), vm_curr_fn);
|
|
DECLARE_VM_BUILTIN(name({"vm", "get_options"}), vm_get_options);
|
|
DECLARE_VM_BUILTIN(name({"vm", "obj_to_string"}), vm_obj_to_string);
|
|
DECLARE_VM_BUILTIN(name({"vm", "pp_stack_obj"}), vm_pp_stack_obj);
|
|
DECLARE_VM_BUILTIN(name({"vm", "pp_expr"}), vm_pp_expr);
|
|
DECLARE_VM_BUILTIN(name({"vm", "put_str"}), vm_put_str);
|
|
DECLARE_VM_BUILTIN(name({"vm", "get_line"}), vm_get_line);
|
|
DECLARE_VM_BUILTIN(name({"vm", "eof"}), vm_eof);
|
|
DECLARE_VM_BUILTIN(name({"vm", "get_attribute"}), vm_get_attribute);
|
|
}
|
|
|
|
void finalize_vm_monitor() {
|
|
}
|
|
}
|