feat(library/tactic): add hole_command bookkeeping

This commit is contained in:
Leonardo de Moura 2017-06-13 21:12:29 -07:00
parent bb2c39b471
commit dac6eec556
9 changed files with 157 additions and 1 deletions

View file

@ -0,0 +1,48 @@
/-
Copyright (c) 2017 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Authors: Leonardo de Moura
-/
prelude
import init.meta.tactic
/--
The front-end (e.g., Emacs, VS Code) can invoke commands for holes {! ... !} in
a declaration. A command is a tactic that takes the optional pre-term in the
hole, and returns a list of expressions. The Lean server converts the list
into a list of strings using the pretty printer, and return it to the front-end.
Each string represents a different way to fill the hole.
The front-end is responsible for replacing the hole with the user selected alternative.
This infra-structure can be use to implement auto-fill and/or refine commands.
An action may return an empty list. This is useful for actions that just return
information such as the type of an expression, its normal form, etc.
-/
meta structure hole_command :=
(name : string)
(descr : string)
(action : option pexpr → tactic (list expr))
open tactic
@[hole_command]
meta def infer_type_cmd : hole_command :=
{ name := "Infer",
descr := "Infer type of the expression in the hole",
action := λ o, do
some p ← return o | fail "Infer command, hole does not contain a term",
e ← to_expr p,
t ← infer_type e,
trace t,
return []
}
@[hole_command]
meta def show_goal_cmd : hole_command :=
{ name := "Show",
descr := "Show the current goal",
action := λ _, do
trace_state,
return []
}

View file

@ -119,6 +119,7 @@ name const * g_heq_refl = nullptr;
name const * g_heq_symm = nullptr;
name const * g_heq_trans = nullptr;
name const * g_heq_of_eq = nullptr;
name const * g_hole_command = nullptr;
name const * g_id_locked = nullptr;
name const * g_if_neg = nullptr;
name const * g_if_pos = nullptr;
@ -491,6 +492,7 @@ void initialize_constants() {
g_heq_symm = new name{"heq", "symm"};
g_heq_trans = new name{"heq", "trans"};
g_heq_of_eq = new name{"heq_of_eq"};
g_hole_command = new name{"hole_command"};
g_id_locked = new name{"id_locked"};
g_if_neg = new name{"if_neg"};
g_if_pos = new name{"if_pos"};
@ -864,6 +866,7 @@ void finalize_constants() {
delete g_heq_symm;
delete g_heq_trans;
delete g_heq_of_eq;
delete g_hole_command;
delete g_id_locked;
delete g_if_neg;
delete g_if_pos;
@ -1236,6 +1239,7 @@ name const & get_heq_refl_name() { return *g_heq_refl; }
name const & get_heq_symm_name() { return *g_heq_symm; }
name const & get_heq_trans_name() { return *g_heq_trans; }
name const & get_heq_of_eq_name() { return *g_heq_of_eq; }
name const & get_hole_command_name() { return *g_hole_command; }
name const & get_id_locked_name() { return *g_id_locked; }
name const & get_if_neg_name() { return *g_if_neg; }
name const & get_if_pos_name() { return *g_if_pos; }

View file

@ -121,6 +121,7 @@ name const & get_heq_refl_name();
name const & get_heq_symm_name();
name const & get_heq_trans_name();
name const & get_heq_of_eq_name();
name const & get_hole_command_name();
name const & get_id_locked_name();
name const & get_if_neg_name();
name const & get_if_pos_name();

View file

@ -114,6 +114,7 @@ heq.refl
heq.symm
heq.trans
heq_of_eq
hole_command
id_locked
if_neg
if_pos

View file

@ -8,5 +8,5 @@ add_library(tactic OBJECT occurrences.cpp kabstract.cpp tactic_state.cpp
hsubstitution.cpp gexpr.cpp elaborate.cpp init_module.cpp
simp_result.cpp user_attribute.cpp eval.cpp
simp_lemmas.cpp eqn_lemmas.cpp dsimplify.cpp simplify.cpp
vm_monitor.cpp destruct_tactic.cpp norm_num_tactic.cpp
vm_monitor.cpp destruct_tactic.cpp norm_num_tactic.cpp hole_command.cpp
elaborator_exception.cpp algebraic_normalizer.cpp tactic_evaluator.cpp)

View file

@ -0,0 +1,87 @@
/*
Copyright (c) 2017 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#include <string>
#include <limits>
#include "util/name_hash_map.h"
#include "library/constants.h"
#include "library/util.h"
#include "library/attribute_manager.h"
#include "library/scoped_ext.h"
#include "library/vm/vm_string.h"
#include "library/tactic/tactic_state.h"
namespace lean {
/* Persisting */
struct hole_command_ext : public environment_extension {
name_map<pair<name, std::string>> m_cmds;
};
struct hole_command_ext_reg {
unsigned m_ext_id;
hole_command_ext_reg() { m_ext_id = environment::register_extension(std::make_shared<hole_command_ext>()); }
};
static hole_command_ext_reg * g_ext = nullptr;
static hole_command_ext const & get_extension(environment const & env) {
return static_cast<hole_command_ext const &>(env.get_extension(g_ext->m_ext_id));
}
static environment update(environment const & env, hole_command_ext const & ext) {
return env.update(g_ext->m_ext_id, std::make_shared<hole_command_ext>(ext));
}
static environment add_hole_command(environment const & env, name const & d) {
auto const & ty = env.get(d).get_type();
if (!is_constant(ty, get_hole_command_name()))
throw exception("invalid [hole_command], must be applied to definition of type hole_command");
vm_state vm(env, options());
vm_obj o = vm.invoke(d, {});
name n(to_string(cfield(o, 0)));
hole_command_ext ext = get_extension(env);
if (ext.m_cmds.contains(n))
throw exception(sstream() << "hole commad named [" << n << "] has already been registered");
std::string descr = to_string(cfield(o, 1));
ext.m_cmds.insert(n, {n, descr});
return update(env, ext);
}
struct hole_command_modification : public modification {
LEAN_MODIFICATION("HOLE_CMD")
name m_name;
hole_command_modification() {}
hole_command_modification(name const & name) : m_name(name) {}
void perform(environment & env) const override {
env = add_hole_command(env, m_name);
}
void serialize(serializer & s) const override {
s << m_name;
}
static std::shared_ptr<modification const> deserialize(deserializer & d) {
return std::make_shared<hole_command_modification>(read_name(d));
}
};
void initialize_hole_command() {
register_system_attribute(basic_attribute(
"hole_command", "register a definition of type `hole_command` in the system",
[](environment const & env, io_state const &, name const & n, unsigned, bool persistent) {
if (!persistent)
throw exception("illegal [hole_command] application, cannot be used locally");
return module::add_and_perform(env, std::make_shared<hole_command_modification>(n));
}));
g_ext = new hole_command_ext_reg();
hole_command_modification::init();
}
void finalize_hole_command() {
hole_command_modification::finalize();
delete g_ext;
}
}

View file

@ -0,0 +1,11 @@
/*
Copyright (c) 2017 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#pragma once
namespace lean {
void initialize_hole_command();
void finalize_hole_command();
}

View file

@ -35,6 +35,7 @@ Author: Leonardo de Moura
#include "library/tactic/norm_num_tactic.h"
#include "library/tactic/destruct_tactic.h"
#include "library/tactic/algebraic_normalizer.h"
#include "library/tactic/hole_command.h"
#include "library/tactic/backward/init_module.h"
#include "library/tactic/smt/init_module.h"
@ -72,10 +73,12 @@ void initialize_tactic_module() {
initialize_vm_monitor();
initialize_destruct_tactic();
initialize_algebraic_normalizer();
initialize_hole_command();
initialize_smt_module();
}
void finalize_tactic_module() {
finalize_smt_module();
finalize_hole_command();
finalize_algebraic_normalizer();
finalize_destruct_tactic();
finalize_vm_monitor();

View file

@ -119,6 +119,7 @@ run_cmd script_check_id `heq.refl
run_cmd script_check_id `heq.symm
run_cmd script_check_id `heq.trans
run_cmd script_check_id `heq_of_eq
run_cmd script_check_id `hole_command
run_cmd script_check_id `id_locked
run_cmd script_check_id `if_neg
run_cmd script_check_id `if_pos