feat(frontends/lean): allow the user to mark subterms that should be automatically abstracted into new definitions
closes #484
This commit is contained in:
parent
7bad9fe554
commit
3d9b557cfd
15 changed files with 366 additions and 8 deletions
|
@ -11,7 +11,7 @@
|
||||||
'("import" "prelude" "tactic_hint" "protected" "private" "definition" "renaming"
|
'("import" "prelude" "tactic_hint" "protected" "private" "definition" "renaming"
|
||||||
"hiding" "exposing" "parameter" "parameters" "begin" "begin+" "proof" "qed" "conjecture" "constant" "constants"
|
"hiding" "exposing" "parameter" "parameters" "begin" "begin+" "proof" "qed" "conjecture" "constant" "constants"
|
||||||
"hypothesis" "lemma" "corollary" "variable" "variables" "premise" "premises"
|
"hypothesis" "lemma" "corollary" "variable" "variables" "premise" "premises"
|
||||||
"print" "theorem" "example" "abbreviation"
|
"print" "theorem" "example" "abbreviation" "abstract"
|
||||||
"open" "as" "export" "override" "axiom" "axioms" "inductive" "with" "structure" "record" "universe" "universes"
|
"open" "as" "export" "override" "axiom" "axioms" "inductive" "with" "structure" "record" "universe" "universes"
|
||||||
"alias" "help" "environment" "options" "precedence" "reserve"
|
"alias" "help" "environment" "options" "precedence" "reserve"
|
||||||
"match" "infix" "infixl" "infixr" "notation" "postfix" "prefix"
|
"match" "infix" "infixl" "infixr" "notation" "postfix" "prefix"
|
||||||
|
|
|
@ -9,6 +9,6 @@ coercion_elaborator.cpp info_tactic.cpp
|
||||||
init_module.cpp elaborator_context.cpp calc_proof_elaborator.cpp
|
init_module.cpp elaborator_context.cpp calc_proof_elaborator.cpp
|
||||||
parse_tactic_location.cpp parse_rewrite_tactic.cpp builtin_tactics.cpp
|
parse_tactic_location.cpp parse_rewrite_tactic.cpp builtin_tactics.cpp
|
||||||
type_util.cpp elaborator_exception.cpp migrate_cmd.cpp local_ref_info.cpp
|
type_util.cpp elaborator_exception.cpp migrate_cmd.cpp local_ref_info.cpp
|
||||||
obtain_expr.cpp decl_attributes.cpp)
|
obtain_expr.cpp decl_attributes.cpp nested_declaration.cpp)
|
||||||
|
|
||||||
target_link_libraries(lean_frontend ${LEAN_LIBS})
|
target_link_libraries(lean_frontend ${LEAN_LIBS})
|
||||||
|
|
|
@ -33,6 +33,7 @@ Author: Leonardo de Moura
|
||||||
#include "frontends/lean/info_annotation.h"
|
#include "frontends/lean/info_annotation.h"
|
||||||
#include "frontends/lean/structure_cmd.h"
|
#include "frontends/lean/structure_cmd.h"
|
||||||
#include "frontends/lean/obtain_expr.h"
|
#include "frontends/lean/obtain_expr.h"
|
||||||
|
#include "frontends/lean/nested_declaration.h"
|
||||||
|
|
||||||
namespace lean {
|
namespace lean {
|
||||||
namespace notation {
|
namespace notation {
|
||||||
|
@ -626,6 +627,7 @@ parse_table init_nud_table() {
|
||||||
r = r.add({transition("assert", mk_ext_action(parse_assert))}, x0);
|
r = r.add({transition("assert", mk_ext_action(parse_assert))}, x0);
|
||||||
r = r.add({transition("show", mk_ext_action(parse_show))}, x0);
|
r = r.add({transition("show", mk_ext_action(parse_show))}, x0);
|
||||||
r = r.add({transition("obtain", mk_ext_action(parse_obtain))}, x0);
|
r = r.add({transition("obtain", mk_ext_action(parse_obtain))}, x0);
|
||||||
|
r = r.add({transition("abstract", mk_ext_action(parse_nested_declaration))}, x0);
|
||||||
r = r.add({transition("if", mk_ext_action(parse_if_then_else))}, x0);
|
r = r.add({transition("if", mk_ext_action(parse_if_then_else))}, x0);
|
||||||
r = r.add({transition("(", Expr), transition(")", mk_ext_action(parse_rparen))}, x0);
|
r = r.add({transition("(", Expr), transition(")", mk_ext_action(parse_rparen))}, x0);
|
||||||
r = r.add({transition("(", Expr), transition(":", Expr), transition(")", mk_ext_action(parse_typed_expr))}, x0);
|
r = r.add({transition("(", Expr), transition(":", Expr), transition(")", mk_ext_action(parse_typed_expr))}, x0);
|
||||||
|
|
|
@ -246,4 +246,20 @@ environment decl_attributes::apply(environment env, io_state const & ios, name c
|
||||||
env = mark_multiple_instances(env, d, m_persistent);
|
env = mark_multiple_instances(env, d, m_persistent);
|
||||||
return env;
|
return env;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void decl_attributes::write(serializer & s) const {
|
||||||
|
s << m_def_only << m_is_abbrev << m_persistent << m_is_instance << m_is_coercion
|
||||||
|
<< m_is_reducible << m_is_irreducible << m_is_semireducible << m_is_quasireducible
|
||||||
|
<< m_is_class << m_is_parsing_only << m_has_multiple_instances << m_unfold_f_hint
|
||||||
|
<< m_constructor_hint << m_symm << m_trans << m_refl << m_subst << m_recursor
|
||||||
|
<< m_rewrite << m_recursor_major_pos << m_priority << m_unfold_c_hint;
|
||||||
|
}
|
||||||
|
|
||||||
|
void decl_attributes::read(deserializer & d) {
|
||||||
|
d >> m_def_only >> m_is_abbrev >> m_persistent >> m_is_instance >> m_is_coercion
|
||||||
|
>> m_is_reducible >> m_is_irreducible >> m_is_semireducible >> m_is_quasireducible
|
||||||
|
>> m_is_class >> m_is_parsing_only >> m_has_multiple_instances >> m_unfold_f_hint
|
||||||
|
>> m_constructor_hint >> m_symm >> m_trans >> m_refl >> m_subst >> m_recursor
|
||||||
|
>> m_rewrite >> m_recursor_major_pos >> m_priority >> m_unfold_c_hint;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -43,5 +43,7 @@ public:
|
||||||
void parse(parser & p);
|
void parse(parser & p);
|
||||||
environment apply(environment env, io_state const & ios, name const & d) const;
|
environment apply(environment env, io_state const & ios, name const & d) const;
|
||||||
bool is_parsing_only() const { return m_is_parsing_only; }
|
bool is_parsing_only() const { return m_is_parsing_only; }
|
||||||
|
void write(serializer & s) const;
|
||||||
|
void read(deserializer & d);
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,7 @@ Author: Leonardo de Moura
|
||||||
#include "frontends/lean/tokens.h"
|
#include "frontends/lean/tokens.h"
|
||||||
#include "frontends/lean/decl_attributes.h"
|
#include "frontends/lean/decl_attributes.h"
|
||||||
#include "frontends/lean/update_environment_exception.h"
|
#include "frontends/lean/update_environment_exception.h"
|
||||||
|
#include "frontends/lean/nested_declaration.h"
|
||||||
|
|
||||||
namespace lean {
|
namespace lean {
|
||||||
static environment declare_universe(parser & p, environment env, name const & n, bool local) {
|
static environment declare_universe(parser & p, environment env, name const & n, bool local) {
|
||||||
|
@ -671,6 +672,12 @@ class definition_cmd_fn {
|
||||||
m_name = m_p.check_id_next("invalid declaration, identifier expected");
|
m_name = m_p.check_id_next("invalid declaration, identifier expected");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
expr extract_nested(expr const & v) {
|
||||||
|
expr new_v;
|
||||||
|
std::tie(m_env, new_v) = extract_nested_declarations(m_env, m_p.ios(), m_name, v);
|
||||||
|
return new_v;
|
||||||
|
}
|
||||||
|
|
||||||
void parse_type_value() {
|
void parse_type_value() {
|
||||||
// Parse universe parameters
|
// Parse universe parameters
|
||||||
parser::local_scope scope1(m_p);
|
parser::local_scope scope1(m_p);
|
||||||
|
@ -690,6 +697,7 @@ class definition_cmd_fn {
|
||||||
m_type = m_p.parse_expr();
|
m_type = m_p.parse_expr();
|
||||||
save_checkpoint();
|
save_checkpoint();
|
||||||
if (is_curr_with_or_comma_or_bar(m_p)) {
|
if (is_curr_with_or_comma_or_bar(m_p)) {
|
||||||
|
allow_nested_decls_scope scope2(is_definition());
|
||||||
m_value = parse_equations(m_p, m_name, m_type, m_aux_decls,
|
m_value = parse_equations(m_p, m_name, m_type, m_aux_decls,
|
||||||
optional<local_environment>(), buffer<expr>(), m_pos);
|
optional<local_environment>(), buffer<expr>(), m_pos);
|
||||||
} else if (!is_definition() && !m_p.curr_is_token(get_assign_tk())) {
|
} else if (!is_definition() && !m_p.curr_is_token(get_assign_tk())) {
|
||||||
|
@ -697,6 +705,7 @@ class definition_cmd_fn {
|
||||||
m_value = m_p.save_pos(mk_expr_placeholder(), pos);
|
m_value = m_p.save_pos(mk_expr_placeholder(), pos);
|
||||||
} else {
|
} else {
|
||||||
m_p.check_token_next(get_assign_tk(), "invalid declaration, ':=' expected");
|
m_p.check_token_next(get_assign_tk(), "invalid declaration, ':=' expected");
|
||||||
|
allow_nested_decls_scope scope2(is_definition());
|
||||||
m_value = m_p.save_pos(m_p.parse_expr(), pos);
|
m_value = m_p.save_pos(m_p.parse_expr(), pos);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
@ -711,11 +720,13 @@ class definition_cmd_fn {
|
||||||
m_type = Pi(ps, type, m_p);
|
m_type = Pi(ps, type, m_p);
|
||||||
save_checkpoint();
|
save_checkpoint();
|
||||||
if (is_curr_with_or_comma_or_bar(m_p)) {
|
if (is_curr_with_or_comma_or_bar(m_p)) {
|
||||||
|
allow_nested_decls_scope scope2(is_definition());
|
||||||
m_value = parse_equations(m_p, m_name, type, m_aux_decls, lenv, ps, m_pos);
|
m_value = parse_equations(m_p, m_name, type, m_aux_decls, lenv, ps, m_pos);
|
||||||
} else if (!is_definition() && !m_p.curr_is_token(get_assign_tk())) {
|
} else if (!is_definition() && !m_p.curr_is_token(get_assign_tk())) {
|
||||||
check_end_of_theorem(m_p);
|
check_end_of_theorem(m_p);
|
||||||
m_value = m_p.save_pos(mk_expr_placeholder(), pos);
|
m_value = m_p.save_pos(mk_expr_placeholder(), pos);
|
||||||
} else {
|
} else {
|
||||||
|
allow_nested_decls_scope scope2(is_definition());
|
||||||
m_p.check_token_next(get_assign_tk(), "invalid declaration, ':=' expected");
|
m_p.check_token_next(get_assign_tk(), "invalid declaration, ':=' expected");
|
||||||
m_value = m_p.parse_scoped_expr(ps, *lenv);
|
m_value = m_p.parse_scoped_expr(ps, *lenv);
|
||||||
}
|
}
|
||||||
|
@ -730,6 +741,7 @@ class definition_cmd_fn {
|
||||||
m_type = Pi(ps, m_type, m_p);
|
m_type = Pi(ps, m_type, m_p);
|
||||||
save_checkpoint();
|
save_checkpoint();
|
||||||
m_p.check_token_next(get_assign_tk(), "invalid declaration, ':=' expected");
|
m_p.check_token_next(get_assign_tk(), "invalid declaration, ':=' expected");
|
||||||
|
allow_nested_decls_scope scope2(is_definition());
|
||||||
m_value = m_p.parse_scoped_expr(ps, *lenv);
|
m_value = m_p.parse_scoped_expr(ps, *lenv);
|
||||||
}
|
}
|
||||||
erase_local_binder_info(ps);
|
erase_local_binder_info(ps);
|
||||||
|
@ -837,6 +849,7 @@ class definition_cmd_fn {
|
||||||
cd = check(mk_axiom(m_real_name, c_ls, c_type));
|
cd = check(mk_axiom(m_real_name, c_ls, c_type));
|
||||||
m_env = module::add(m_env, *cd);
|
m_env = module::add(m_env, *cd);
|
||||||
} else {
|
} else {
|
||||||
|
c_value = extract_nested(c_value);
|
||||||
cd = check(mk_definition(m_env, m_real_name, c_ls, c_type, c_value));
|
cd = check(mk_definition(m_env, m_real_name, c_ls, c_type, c_value));
|
||||||
if (!m_is_private)
|
if (!m_is_private)
|
||||||
m_p.add_decl_index(m_real_name, m_pos, m_p.get_cmd_token(), c_type);
|
m_p.add_decl_index(m_real_name, m_pos, m_p.get_cmd_token(), c_type);
|
||||||
|
@ -947,7 +960,7 @@ class definition_cmd_fn {
|
||||||
if (aux_values.size() != m_real_aux_names.size())
|
if (aux_values.size() != m_real_aux_names.size())
|
||||||
throw exception("invalid declaration, failed to compile auxiliary declarations");
|
throw exception("invalid declaration, failed to compile auxiliary declarations");
|
||||||
m_type = postprocess(m_env, m_type);
|
m_type = postprocess(m_env, m_type);
|
||||||
m_value = postprocess(m_env, m_value);
|
m_value = extract_nested(postprocess(m_env, m_value));
|
||||||
for (unsigned i = 0; i < aux_values.size(); i++) {
|
for (unsigned i = 0; i < aux_values.size(); i++) {
|
||||||
m_aux_types[i] = postprocess(m_env, m_aux_types[i]);
|
m_aux_types[i] = postprocess(m_env, m_aux_types[i]);
|
||||||
aux_values[i] = postprocess(m_env, aux_values[i]);
|
aux_values[i] = postprocess(m_env, aux_values[i]);
|
||||||
|
@ -1005,10 +1018,12 @@ class definition_cmd_fn {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
std::tie(m_type, m_value, new_ls) = elaborate_definition(m_type, m_value);
|
std::tie(m_type, m_value, new_ls) = elaborate_definition(m_type, m_value);
|
||||||
new_ls = append(m_ls, new_ls);
|
new_ls = append(m_ls, new_ls);
|
||||||
m_type = postprocess(m_env, m_type);
|
m_type = postprocess(m_env, m_type);
|
||||||
m_value = postprocess(m_env, m_value);
|
m_value = postprocess(m_env, m_value);
|
||||||
m_env = module::add(m_env, check(mk_definition(m_env, m_real_name, new_ls, m_type, m_value)));
|
expr new_val = extract_nested(m_value);
|
||||||
|
m_env = module::add(m_env, check(mk_definition(m_env, m_real_name, new_ls, m_type, new_val)));
|
||||||
|
// Remark: we cache the definition with the nested declarations.
|
||||||
m_p.cache_definition(m_real_name, pre_type, pre_value, new_ls, m_type, m_value);
|
m_p.cache_definition(m_real_name, pre_type, pre_value, new_ls, m_type, m_value);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -52,6 +52,7 @@ Author: Leonardo de Moura
|
||||||
#include "frontends/lean/info_tactic.h"
|
#include "frontends/lean/info_tactic.h"
|
||||||
#include "frontends/lean/begin_end_ext.h"
|
#include "frontends/lean/begin_end_ext.h"
|
||||||
#include "frontends/lean/elaborator_exception.h"
|
#include "frontends/lean/elaborator_exception.h"
|
||||||
|
#include "frontends/lean/nested_declaration.h"
|
||||||
#include "frontends/lean/calc.h"
|
#include "frontends/lean/calc.h"
|
||||||
#include "frontends/lean/decl_cmds.h"
|
#include "frontends/lean/decl_cmds.h"
|
||||||
|
|
||||||
|
|
|
@ -31,6 +31,7 @@ Author: Leonardo de Moura
|
||||||
#include "frontends/lean/local_ref_info.h"
|
#include "frontends/lean/local_ref_info.h"
|
||||||
#include "frontends/lean/obtain_expr.h"
|
#include "frontends/lean/obtain_expr.h"
|
||||||
#include "frontends/lean/decl_cmds.h"
|
#include "frontends/lean/decl_cmds.h"
|
||||||
|
#include "frontends/lean/nested_declaration.h"
|
||||||
|
|
||||||
namespace lean {
|
namespace lean {
|
||||||
void initialize_frontend_lean_module() {
|
void initialize_frontend_lean_module() {
|
||||||
|
@ -61,8 +62,10 @@ void initialize_frontend_lean_module() {
|
||||||
initialize_local_ref_info();
|
initialize_local_ref_info();
|
||||||
initialize_obtain_expr();
|
initialize_obtain_expr();
|
||||||
initialize_decl_cmds();
|
initialize_decl_cmds();
|
||||||
|
initialize_nested_declaration();
|
||||||
}
|
}
|
||||||
void finalize_frontend_lean_module() {
|
void finalize_frontend_lean_module() {
|
||||||
|
finalize_nested_declaration();
|
||||||
finalize_decl_cmds();
|
finalize_decl_cmds();
|
||||||
finalize_obtain_expr();
|
finalize_obtain_expr();
|
||||||
finalize_local_ref_info();
|
finalize_local_ref_info();
|
||||||
|
|
221
src/frontends/lean/nested_declaration.cpp
Normal file
221
src/frontends/lean/nested_declaration.cpp
Normal file
|
@ -0,0 +1,221 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||||
|
Released under Apache 2.0 license as described in the file LICENSE.
|
||||||
|
|
||||||
|
Author: Leonardo de Moura
|
||||||
|
*/
|
||||||
|
#include <string>
|
||||||
|
#include "util/sstream.h"
|
||||||
|
#include "kernel/type_checker.h"
|
||||||
|
#include "kernel/find_fn.h"
|
||||||
|
#include "kernel/instantiate.h"
|
||||||
|
#include "kernel/abstract.h"
|
||||||
|
#include "library/locals.h"
|
||||||
|
#include "library/scoped_ext.h"
|
||||||
|
#include "library/kernel_serializer.h"
|
||||||
|
#include "library/replace_visitor.h"
|
||||||
|
#include "library/module.h"
|
||||||
|
#include "library/aliases.h"
|
||||||
|
#include "frontends/lean/decl_attributes.h"
|
||||||
|
#include "frontends/lean/tokens.h"
|
||||||
|
#include "frontends/lean/parser.h"
|
||||||
|
#include "frontends/lean/util.h"
|
||||||
|
#include "frontends/lean/nested_declaration.h"
|
||||||
|
|
||||||
|
namespace lean {
|
||||||
|
static name * g_nested_decl = nullptr;
|
||||||
|
static std::string * g_nested_decl_opcode = nullptr;
|
||||||
|
|
||||||
|
name const & get_nested_decl_name() { return *g_nested_decl; }
|
||||||
|
std::string const & get_nested_decl_opcode() { return *g_nested_decl_opcode; }
|
||||||
|
|
||||||
|
class nested_decl_macro_definition_cell : public macro_definition_cell {
|
||||||
|
optional<name> m_name;
|
||||||
|
decl_attributes m_attributes;
|
||||||
|
|
||||||
|
void check_macro(expr const & m) const {
|
||||||
|
if (!is_macro(m) || macro_num_args(m) != 1)
|
||||||
|
throw exception(sstream() << "invalid nested declaration, incorrect number of arguments");
|
||||||
|
}
|
||||||
|
public:
|
||||||
|
nested_decl_macro_definition_cell(optional<name> const & n, decl_attributes const & attrs):
|
||||||
|
m_name(n), m_attributes(attrs) {}
|
||||||
|
virtual name get_name() const { return get_nested_decl_name(); }
|
||||||
|
virtual pair<expr, constraint_seq> check_type(expr const & m, extension_context & ctx, bool infer_only) const {
|
||||||
|
check_macro(m);
|
||||||
|
return ctx.check_type(macro_arg(m, 0), infer_only);
|
||||||
|
}
|
||||||
|
virtual optional<expr> expand(expr const & m, extension_context &) const {
|
||||||
|
check_macro(m);
|
||||||
|
return some_expr(macro_arg(m, 0));
|
||||||
|
}
|
||||||
|
virtual void write(serializer & s) const {
|
||||||
|
s.write_string(get_nested_decl_opcode());
|
||||||
|
s << m_name;
|
||||||
|
m_attributes.write(s);
|
||||||
|
}
|
||||||
|
virtual unsigned hash() const {
|
||||||
|
return get_nested_decl_name().hash();
|
||||||
|
}
|
||||||
|
optional<name> const & get_decl_name() const { return m_name; }
|
||||||
|
decl_attributes const & get_decl_attributes() const { return m_attributes; }
|
||||||
|
};
|
||||||
|
|
||||||
|
expr mk_nested_declaration(optional<name> const & n, decl_attributes const & attrs, expr const & e) {
|
||||||
|
macro_definition def(new nested_decl_macro_definition_cell(n, attrs));
|
||||||
|
return mk_macro(def, 1, &e);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool is_nested_declaration(expr const & e) {
|
||||||
|
return is_macro(e) && macro_def(e).get_name() == get_nested_decl_name();
|
||||||
|
}
|
||||||
|
|
||||||
|
expr update_nested_declaration(expr const & e, expr const & new_d) {
|
||||||
|
lean_assert(is_nested_declaration(e));
|
||||||
|
return mk_macro(macro_def(e), 1, &new_d);
|
||||||
|
}
|
||||||
|
|
||||||
|
expr get_nested_declaration_arg(expr const & e) {
|
||||||
|
lean_assert(is_nested_declaration(e));
|
||||||
|
return macro_arg(e, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
optional<name> const & get_nested_declaration_name(expr const & d) {
|
||||||
|
lean_assert(is_nested_declaration(e));
|
||||||
|
return static_cast<nested_decl_macro_definition_cell const*>(macro_def(d).raw())->get_decl_name();
|
||||||
|
}
|
||||||
|
|
||||||
|
decl_attributes const & get_nested_declaration_attributes(expr const & d) {
|
||||||
|
lean_assert(is_nested_declaration(e));
|
||||||
|
return static_cast<nested_decl_macro_definition_cell const*>(macro_def(d).raw())->get_decl_attributes();
|
||||||
|
}
|
||||||
|
|
||||||
|
LEAN_THREAD_VALUE(bool, g_allow_nested_declarations, false);
|
||||||
|
|
||||||
|
allow_nested_decls_scope::allow_nested_decls_scope(bool enable) {
|
||||||
|
m_saved = g_allow_nested_declarations;
|
||||||
|
g_allow_nested_declarations = enable;
|
||||||
|
}
|
||||||
|
|
||||||
|
allow_nested_decls_scope::~allow_nested_decls_scope() {
|
||||||
|
g_allow_nested_declarations = m_saved;
|
||||||
|
}
|
||||||
|
|
||||||
|
expr parse_nested_declaration(parser & p, unsigned, expr const *, pos_info const & pos) {
|
||||||
|
try {
|
||||||
|
optional<name> n;
|
||||||
|
decl_attributes attrs;
|
||||||
|
if (!g_allow_nested_declarations)
|
||||||
|
throw parser_error("invalid 'abstract' expression, it is only allowed inside definitions", pos);
|
||||||
|
if (p.curr_is_token(get_as_tk())) {
|
||||||
|
p.next();
|
||||||
|
n = p.check_id_next("invalid 'abstract' expression, identifier expected");
|
||||||
|
}
|
||||||
|
attrs.parse(p);
|
||||||
|
expr e = p.parse_expr();
|
||||||
|
p.check_token_next(get_end_tk(), "invalid 'abstract' expression, 'end' expected");
|
||||||
|
return p.save_pos(mk_nested_declaration(n, attrs, e), pos);
|
||||||
|
} catch (exception & ex) {
|
||||||
|
consume_until_end(p);
|
||||||
|
ex.rethrow();
|
||||||
|
lean_unreachable();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool contains_nested_declarations(expr const & e) {
|
||||||
|
return static_cast<bool>(find(e, [&](expr const & n, unsigned) { return is_nested_declaration(n); }));
|
||||||
|
}
|
||||||
|
|
||||||
|
class extractor : public replace_visitor {
|
||||||
|
environment m_env;
|
||||||
|
io_state m_ios;
|
||||||
|
type_checker m_tc;
|
||||||
|
name m_dname;
|
||||||
|
unsigned m_idx;
|
||||||
|
public:
|
||||||
|
extractor(environment const & env, io_state const & ios, name const & dname):
|
||||||
|
m_env(env), m_ios(ios), m_tc(m_env), m_dname(dname), m_idx(1) {}
|
||||||
|
|
||||||
|
name mk_name_for(expr const & e) {
|
||||||
|
lean_assert(is_nested_declaration(e));
|
||||||
|
if (auto n = get_nested_declaration_name(e)) {
|
||||||
|
return *n;
|
||||||
|
} else {
|
||||||
|
name ns = get_namespace(m_env);
|
||||||
|
while (true) {
|
||||||
|
name aux = m_dname.append_after(m_idx);
|
||||||
|
m_idx++;
|
||||||
|
if (!m_env.find(ns + aux))
|
||||||
|
return aux;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expr extract(expr const & e) {
|
||||||
|
lean_assert(is_nested_declaration(e));
|
||||||
|
expr const & d = visit(get_nested_declaration_arg(e));
|
||||||
|
name new_name = mk_name_for(e);
|
||||||
|
name new_real_name = get_namespace(m_env) + new_name;
|
||||||
|
collected_locals locals;
|
||||||
|
collect_locals(d, locals);
|
||||||
|
buffer<name> uparams;
|
||||||
|
collect_univ_params(d).to_buffer(uparams);
|
||||||
|
expr new_value = Fun(locals.get_collected(), d);
|
||||||
|
expr new_type = m_tc.infer(new_value).first;
|
||||||
|
level_param_names new_ps = to_list(uparams);
|
||||||
|
levels ls = param_names_to_levels(new_ps);
|
||||||
|
m_env = module::add(m_env, check(m_env, mk_definition(m_env, new_real_name, new_ps,
|
||||||
|
new_type, new_value)));
|
||||||
|
if (new_name != new_real_name)
|
||||||
|
m_env = add_expr_alias_rec(m_env, new_name, new_real_name);
|
||||||
|
decl_attributes const & attrs = get_nested_declaration_attributes(e);
|
||||||
|
m_env = attrs.apply(m_env, m_ios, new_real_name);
|
||||||
|
return mk_app(mk_constant(new_real_name, ls), locals.get_collected());
|
||||||
|
}
|
||||||
|
|
||||||
|
expr visit_macro(expr const & e) {
|
||||||
|
if (is_nested_declaration(e)) {
|
||||||
|
return extract(e);
|
||||||
|
} else {
|
||||||
|
return replace_visitor::visit_macro(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
expr visit_binding(expr const & b) {
|
||||||
|
expr new_domain = visit(binding_domain(b));
|
||||||
|
expr l = mk_local(m_tc.mk_fresh_name(), new_domain);
|
||||||
|
expr new_body = abstract(visit(instantiate(binding_body(b), l)), l);
|
||||||
|
return update_binding(b, new_domain, new_body);
|
||||||
|
}
|
||||||
|
|
||||||
|
environment const & get_env() const { return m_env; }
|
||||||
|
};
|
||||||
|
|
||||||
|
std::tuple<environment, expr> extract_nested_declarations(environment const & env, io_state const & ios,
|
||||||
|
name const & dname, expr const & e) {
|
||||||
|
if (contains_nested_declarations(e)) {
|
||||||
|
extractor ex(env, ios, dname);
|
||||||
|
expr new_e = ex(e);
|
||||||
|
return std::make_tuple(ex.get_env(), new_e);
|
||||||
|
} else {
|
||||||
|
return std::make_tuple(env, e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void initialize_nested_declaration() {
|
||||||
|
g_nested_decl = new name("nested_decl");
|
||||||
|
g_nested_decl_opcode = new std::string("NDecl");
|
||||||
|
register_macro_deserializer(get_nested_decl_opcode(),
|
||||||
|
[](deserializer & d, unsigned num, expr const * args) {
|
||||||
|
if (num != 1)
|
||||||
|
throw corrupted_stream_exception();
|
||||||
|
optional<name> n; decl_attributes attrs;
|
||||||
|
d >> n; attrs.read(d);
|
||||||
|
return mk_nested_declaration(n, attrs, args[0]);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
void finalize_nested_declaration() {
|
||||||
|
delete g_nested_decl;
|
||||||
|
delete g_nested_decl_opcode;
|
||||||
|
}
|
||||||
|
}
|
24
src/frontends/lean/nested_declaration.h
Normal file
24
src/frontends/lean/nested_declaration.h
Normal file
|
@ -0,0 +1,24 @@
|
||||||
|
/*
|
||||||
|
Copyright (c) 2015 Microsoft Corporation. All rights reserved.
|
||||||
|
Released under Apache 2.0 license as described in the file LICENSE.
|
||||||
|
|
||||||
|
Author: Leonardo de Moura
|
||||||
|
*/
|
||||||
|
#pragma once
|
||||||
|
#include "util/flet.h"
|
||||||
|
#include "kernel/expr.h"
|
||||||
|
namespace lean {
|
||||||
|
class parser;
|
||||||
|
// auxiliary object used to temporarily enable nested declarations
|
||||||
|
class allow_nested_decls_scope {
|
||||||
|
bool m_saved;
|
||||||
|
public:
|
||||||
|
allow_nested_decls_scope(bool enable = true);
|
||||||
|
~allow_nested_decls_scope();
|
||||||
|
};
|
||||||
|
expr parse_nested_declaration(parser & p, unsigned, expr const *, pos_info const & pos);
|
||||||
|
std::tuple<environment, expr> extract_nested_declarations(environment const & env, io_state const & ios,
|
||||||
|
name const & def_name, expr const & e);
|
||||||
|
void initialize_nested_declaration();
|
||||||
|
void finalize_nested_declaration();
|
||||||
|
}
|
|
@ -97,7 +97,7 @@ void init_token_table(token_table & t) {
|
||||||
{".", 0}, {":", 0}, {"::", 0}, {"calc", 0}, {"rewrite", 0}, {"xrewrite", 0}, {"krewrite", 0},
|
{".", 0}, {":", 0}, {"::", 0}, {"calc", 0}, {"rewrite", 0}, {"xrewrite", 0}, {"krewrite", 0},
|
||||||
{"esimp", 0}, {"fold", 0}, {"unfold", 0},
|
{"esimp", 0}, {"fold", 0}, {"unfold", 0},
|
||||||
{"generalize", 0}, {"as", 0}, {":=", 0}, {"--", 0}, {"#", 0},
|
{"generalize", 0}, {"as", 0}, {":=", 0}, {"--", 0}, {"#", 0},
|
||||||
{"(*", 0}, {"/-", 0}, {"begin", g_max_prec}, {"begin+", g_max_prec},
|
{"(*", 0}, {"/-", 0}, {"begin", g_max_prec}, {"begin+", g_max_prec}, {"abstract", g_max_prec},
|
||||||
{"proof", g_max_prec}, {"qed", 0}, {"@", g_max_prec},
|
{"proof", g_max_prec}, {"qed", 0}, {"@", g_max_prec},
|
||||||
{"sorry", g_max_prec}, {"+", g_plus_prec}, {g_cup, g_cup_prec}, {"->", g_arrow_prec},
|
{"sorry", g_max_prec}, {"+", g_plus_prec}, {g_cup, g_cup_prec}, {"->", g_arrow_prec},
|
||||||
{"?(", g_max_prec}, {"⌞", g_max_prec}, {"⌟", 0}, {"match", 0},
|
{"?(", g_max_prec}, {"⌞", g_max_prec}, {"⌟", 0}, {"match", 0},
|
||||||
|
|
19
tests/lean/nested1.lean
Normal file
19
tests/lean/nested1.lean
Normal file
|
@ -0,0 +1,19 @@
|
||||||
|
import data.nat
|
||||||
|
open nat
|
||||||
|
|
||||||
|
namespace test
|
||||||
|
|
||||||
|
constant foo (a : nat) : a > 0 → nat
|
||||||
|
|
||||||
|
definition bla (a : nat) :=
|
||||||
|
foo
|
||||||
|
(succ (succ a))
|
||||||
|
abstract as foo.prf [irreducible] lt.step (zero_lt_succ a) end
|
||||||
|
|
||||||
|
print foo.prf
|
||||||
|
print bla
|
||||||
|
|
||||||
|
end test
|
||||||
|
|
||||||
|
print test.bla
|
||||||
|
print test.foo.prf
|
8
tests/lean/nested1.lean.expected.out
Normal file
8
tests/lean/nested1.lean.expected.out
Normal file
|
@ -0,0 +1,8 @@
|
||||||
|
definition test.foo.prf [irreducible] : ∀ (x : ℕ), 0 < succ (succ x)
|
||||||
|
λ (x : ℕ), lt.step (zero_lt_succ x)
|
||||||
|
definition test.bla : ℕ → ℕ
|
||||||
|
λ (a : ℕ), foo (succ (succ a)) (foo.prf a)
|
||||||
|
definition test.bla : ℕ → ℕ
|
||||||
|
λ (a : ℕ), test.foo (succ (succ a)) (test.foo.prf a)
|
||||||
|
definition test.foo.prf : ∀ (x : ℕ), 0 < succ (succ x)
|
||||||
|
λ (x : ℕ), lt.step (zero_lt_succ x)
|
32
tests/lean/nested2.lean
Normal file
32
tests/lean/nested2.lean
Normal file
|
@ -0,0 +1,32 @@
|
||||||
|
import data.nat data.list
|
||||||
|
open nat
|
||||||
|
|
||||||
|
constant foo (a : nat) : a > 0 → nat
|
||||||
|
|
||||||
|
definition bla (a : nat) :=
|
||||||
|
foo
|
||||||
|
(succ (succ a))
|
||||||
|
abstract lt.step abstract zero_lt_succ a end end
|
||||||
|
|
||||||
|
print bla
|
||||||
|
print bla_1
|
||||||
|
print bla_2
|
||||||
|
|
||||||
|
definition test (a : nat) :=
|
||||||
|
foo
|
||||||
|
(succ (succ a))
|
||||||
|
abstract [reducible] lt.step abstract [irreducible] zero_lt_succ a end end
|
||||||
|
|
||||||
|
print test_1
|
||||||
|
print test_2
|
||||||
|
|
||||||
|
constant voo {A : Type} (a b : A) : a ≠ b → bool
|
||||||
|
|
||||||
|
set_option pp.universes true
|
||||||
|
|
||||||
|
open list
|
||||||
|
definition tst {A : Type} (a : A) (l : list A) :=
|
||||||
|
voo (a::l) [] abstract by contradiction end
|
||||||
|
|
||||||
|
print tst_1
|
||||||
|
print tst
|
15
tests/lean/nested2.lean.expected.out
Normal file
15
tests/lean/nested2.lean.expected.out
Normal file
|
@ -0,0 +1,15 @@
|
||||||
|
definition bla : ℕ → ℕ
|
||||||
|
λ (a : ℕ), foo (succ (succ a)) (bla_2 a)
|
||||||
|
definition bla_1 : ∀ (x : ℕ), 0 < succ x
|
||||||
|
λ (x : ℕ), zero_lt_succ x
|
||||||
|
definition bla_2 : ∀ (x : ℕ), 0 < succ (succ x)
|
||||||
|
λ (x : ℕ), lt.step (bla_1 x)
|
||||||
|
definition test_1 [irreducible] : ∀ (x : ℕ), 0 < succ x
|
||||||
|
λ (x : ℕ), zero_lt_succ x
|
||||||
|
definition test_2 [reducible] : ∀ (x : ℕ), 0 < succ (succ x)
|
||||||
|
λ (x : ℕ), lt.step (test_1 x)
|
||||||
|
definition tst_1 : ∀ (x : Type.{l_1}) (x_1 : x) (x_2 : list.{l_1} x),
|
||||||
|
x_1 :: x_2 = nil.{l_1} → list.no_confusion_type.{0 l_1} false (x_1 :: x_2) nil.{l_1}
|
||||||
|
λ (x : Type.{l_1}) (x_1 : x) (x_2 : list.{l_1} x), list.no_confusion.{0 l_1}
|
||||||
|
definition tst : Π {A : Type.{l_1}}, A → list.{l_1} A → bool
|
||||||
|
λ (A : Type.{l_1}) (a : A) (l : list.{l_1} A), voo.{(max 1 l_1)} (a :: l) nil.{l_1} (tst_1.{l_1} A a l)
|
Loading…
Reference in a new issue