feat(frontends/lean): add 'print fields' command
This commit is contained in:
parent
354baf4d13
commit
4650791108
7 changed files with 70 additions and 9 deletions
|
@ -15,7 +15,7 @@
|
||||||
"alias" "help" "environment" "options" "precedence" "reserve" "postfix" "prefix"
|
"alias" "help" "environment" "options" "precedence" "reserve" "postfix" "prefix"
|
||||||
"calc_trans" "calc_subst" "calc_refl" "calc_symm"
|
"calc_trans" "calc_subst" "calc_refl" "calc_symm"
|
||||||
"infix" "infixl" "infixr" "notation" "eval" "check" "exit" "coercion" "end"
|
"infix" "infixl" "infixr" "notation" "eval" "check" "exit" "coercion" "end"
|
||||||
"using" "namespace" "instance" "class" "section"
|
"using" "namespace" "instance" "class" "section" "fields"
|
||||||
"set_option" "add_rewrite" "extends" "include" "omit" "classes" "instances" "coercions" "raw")
|
"set_option" "add_rewrite" "extends" "include" "omit" "classes" "instances" "coercions" "raw")
|
||||||
"lean keywords")
|
"lean keywords")
|
||||||
|
|
||||||
|
|
|
@ -90,6 +90,20 @@ static void print_prefix(parser & p) {
|
||||||
p.regular_stream() << "no declaration starting with prefix '" << prefix << "'" << endl;
|
p.regular_stream() << "no declaration starting with prefix '" << prefix << "'" << endl;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void print_fields(parser & p) {
|
||||||
|
auto pos = p.pos();
|
||||||
|
environment const & env = p.env();
|
||||||
|
name S = p.check_constant_next("invalid 'print fields' command, constant expected");
|
||||||
|
if (!is_structure(env, S))
|
||||||
|
throw parser_error(sstream() << "invalid 'print fields' command, '" << S << "' is not a structure", pos);
|
||||||
|
buffer<name> field_names;
|
||||||
|
get_structure_fields(env, S, field_names);
|
||||||
|
for (name const & field_name : field_names) {
|
||||||
|
declaration d = env.get(field_name);
|
||||||
|
p.regular_stream() << d.get_name() << " : " << d.get_type() << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
environment print_cmd(parser & p) {
|
environment print_cmd(parser & p) {
|
||||||
if (p.curr() == scanner::token_kind::String) {
|
if (p.curr() == scanner::token_kind::String) {
|
||||||
p.regular_stream() << p.get_str_val() << endl;
|
p.regular_stream() << p.get_str_val() << endl;
|
||||||
|
@ -141,6 +155,9 @@ environment print_cmd(parser & p) {
|
||||||
} else if (p.curr_is_token_or_id(get_axioms_tk())) {
|
} else if (p.curr_is_token_or_id(get_axioms_tk())) {
|
||||||
p.next();
|
p.next();
|
||||||
print_axioms(p);
|
print_axioms(p);
|
||||||
|
} else if (p.curr_is_token_or_id(get_fields_tk())) {
|
||||||
|
p.next();
|
||||||
|
print_fields(p);
|
||||||
} else {
|
} else {
|
||||||
throw parser_error("invalid print command", p.pos());
|
throw parser_error("invalid print command", p.pos());
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,31 @@ void finalize_structure_cmd() {
|
||||||
delete g_tmp_prefix;
|
delete g_tmp_prefix;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/** \brief Return true iff the type named \c S can be viewed as
|
||||||
|
a structure in the given environment.
|
||||||
|
|
||||||
|
If not, generate an error message using \c pos.
|
||||||
|
*/
|
||||||
|
bool is_structure(environment const & env, name const & S) {
|
||||||
|
optional<inductive::inductive_decls> idecls = inductive::is_inductive_decl(env, S);
|
||||||
|
if (!idecls || length(std::get<2>(*idecls)) != 1)
|
||||||
|
return false;
|
||||||
|
inductive::inductive_decl decl = head(std::get<2>(*idecls));
|
||||||
|
return length(inductive::inductive_decl_intros(decl)) == 1 && *inductive::get_num_indices(env, S) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/** \brief Return the universe parameters, number of parameters and introduction rule for the given parent structure
|
||||||
|
|
||||||
|
\pre is_structure(env, S)
|
||||||
|
*/
|
||||||
|
static auto get_structure_info(environment const & env, name const & S)
|
||||||
|
-> std::tuple<level_param_names, unsigned, inductive::intro_rule> {
|
||||||
|
lean_assert(is_structure(env, S));
|
||||||
|
inductive::inductive_decls idecls = *inductive::is_inductive_decl(env, S);
|
||||||
|
inductive::intro_rule intro = head(inductive::inductive_decl_intros(head(std::get<2>(idecls))));
|
||||||
|
return std::make_tuple(std::get<0>(idecls), std::get<1>(idecls), intro);
|
||||||
|
}
|
||||||
|
|
||||||
struct structure_cmd_fn {
|
struct structure_cmd_fn {
|
||||||
typedef std::unique_ptr<type_checker> type_checker_ptr;
|
typedef std::unique_ptr<type_checker> type_checker_ptr;
|
||||||
typedef std::vector<pair<name, name>> rename_vector;
|
typedef std::vector<pair<name, name>> rename_vector;
|
||||||
|
@ -123,19 +148,13 @@ struct structure_cmd_fn {
|
||||||
if (!is_constant(fn))
|
if (!is_constant(fn))
|
||||||
throw parser_error("invalid 'structure', expression must be a 'parent' structure", pos);
|
throw parser_error("invalid 'structure', expression must be a 'parent' structure", pos);
|
||||||
name const & S = const_name(fn);
|
name const & S = const_name(fn);
|
||||||
optional<inductive::inductive_decls> idecls = inductive::is_inductive_decl(m_env, S);
|
if (!is_structure(m_env, S))
|
||||||
if (!idecls || length(std::get<2>(*idecls)) != 1)
|
|
||||||
throw parser_error(sstream() << "invalid 'structure' extends, '" << S << "' is not a structure", pos);
|
|
||||||
inductive::inductive_decl decl = head(std::get<2>(*idecls));
|
|
||||||
if (length(inductive::inductive_decl_intros(decl)) != 1 || *inductive::get_num_indices(m_env, S) != 0)
|
|
||||||
throw parser_error(sstream() << "invalid 'structure' extends, '" << S << "' is not a structure", pos);
|
throw parser_error(sstream() << "invalid 'structure' extends, '" << S << "' is not a structure", pos);
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief Return the universe parameters, number of parameters and introduction rule for the given parent structure */
|
/** \brief Return the universe parameters, number of parameters and introduction rule for the given parent structure */
|
||||||
std::tuple<level_param_names, unsigned, inductive::intro_rule> get_parent_info(name const & parent) {
|
std::tuple<level_param_names, unsigned, inductive::intro_rule> get_parent_info(name const & parent) {
|
||||||
inductive::inductive_decls idecls = *inductive::is_inductive_decl(m_env, parent);
|
return get_structure_info(m_env, parent);
|
||||||
inductive::intro_rule intro = head(inductive::inductive_decl_intros(head(std::get<2>(idecls))));
|
|
||||||
return std::make_tuple(std::get<0>(idecls), std::get<1>(idecls), intro);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/** \brief Sign an error if the constructor \c intro_type does not have a field named \c from_id */
|
/** \brief Sign an error if the constructor \c intro_type does not have a field named \c from_id */
|
||||||
|
@ -792,6 +811,20 @@ environment structure_cmd(parser & p) {
|
||||||
return structure_cmd_fn(p)();
|
return structure_cmd_fn(p)();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void get_structure_fields(environment const & env, name const & S, buffer<name> & fields) {
|
||||||
|
lean_assert(is_structure(env, S));
|
||||||
|
level_param_names ls; unsigned nparams; inductive::intro_rule intro;
|
||||||
|
std::tie(ls, nparams, intro) = get_structure_info(env, S);
|
||||||
|
expr intro_type = inductive::intro_rule_type(intro);
|
||||||
|
unsigned i = 0;
|
||||||
|
while (is_pi(intro_type)) {
|
||||||
|
if (i >= nparams)
|
||||||
|
fields.push_back(S + binding_name(intro_type));
|
||||||
|
i++;
|
||||||
|
intro_type = binding_body(intro_type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void register_structure_cmd(cmd_table & r) {
|
void register_structure_cmd(cmd_table & r) {
|
||||||
add_cmd(r, cmd_info("structure", "declare a new structure/record type", structure_cmd));
|
add_cmd(r, cmd_info("structure", "declare a new structure/record type", structure_cmd));
|
||||||
}
|
}
|
||||||
|
|
|
@ -7,6 +7,8 @@ Author: Leonardo de Moura
|
||||||
#pragma once
|
#pragma once
|
||||||
#include "frontends/lean/cmd_table.h"
|
#include "frontends/lean/cmd_table.h"
|
||||||
namespace lean {
|
namespace lean {
|
||||||
|
bool is_structure(environment const & env, name const & S);
|
||||||
|
void get_structure_fields(environment const & env, name const & S, buffer<name> & fields);
|
||||||
void register_structure_cmd(cmd_table & r);
|
void register_structure_cmd(cmd_table & r);
|
||||||
void initialize_structure_cmd();
|
void initialize_structure_cmd();
|
||||||
void finalize_structure_cmd();
|
void finalize_structure_cmd();
|
||||||
|
|
|
@ -91,6 +91,7 @@ static name * g_notation = nullptr;
|
||||||
static name * g_call = nullptr;
|
static name * g_call = nullptr;
|
||||||
static name * g_persistent = nullptr;
|
static name * g_persistent = nullptr;
|
||||||
static name * g_root = nullptr;
|
static name * g_root = nullptr;
|
||||||
|
static name * g_fields = nullptr;
|
||||||
|
|
||||||
void initialize_tokens() {
|
void initialize_tokens() {
|
||||||
g_period = new name(".");
|
g_period = new name(".");
|
||||||
|
@ -177,11 +178,13 @@ void initialize_tokens() {
|
||||||
g_call = new name("call");
|
g_call = new name("call");
|
||||||
g_persistent = new name("[persistent]");
|
g_persistent = new name("[persistent]");
|
||||||
g_root = new name("_root_");
|
g_root = new name("_root_");
|
||||||
|
g_fields = new name("fields");
|
||||||
}
|
}
|
||||||
|
|
||||||
void finalize_tokens() {
|
void finalize_tokens() {
|
||||||
delete g_persistent;
|
delete g_persistent;
|
||||||
delete g_root;
|
delete g_root;
|
||||||
|
delete g_fields;
|
||||||
delete g_prev;
|
delete g_prev;
|
||||||
delete g_scoped;
|
delete g_scoped;
|
||||||
delete g_foldr;
|
delete g_foldr;
|
||||||
|
@ -350,4 +353,5 @@ name const & get_notation_tk() { return *g_notation; }
|
||||||
name const & get_call_tk() { return *g_call; }
|
name const & get_call_tk() { return *g_call; }
|
||||||
name const & get_persistent_tk() { return *g_persistent; }
|
name const & get_persistent_tk() { return *g_persistent; }
|
||||||
name const & get_root_tk() { return *g_root; }
|
name const & get_root_tk() { return *g_root; }
|
||||||
|
name const & get_fields_tk() { return *g_fields; }
|
||||||
}
|
}
|
||||||
|
|
|
@ -93,4 +93,5 @@ name const & get_notation_tk();
|
||||||
name const & get_call_tk();
|
name const & get_call_tk();
|
||||||
name const & get_persistent_tk();
|
name const & get_persistent_tk();
|
||||||
name const & get_root_tk();
|
name const & get_root_tk();
|
||||||
|
name const & get_fields_tk();
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,6 +27,8 @@ structure monoid [class] (A : Type) extends semigroup A, has_one A :=
|
||||||
-- We can suppress := and :: when we are not declaring any new field.
|
-- We can suppress := and :: when we are not declaring any new field.
|
||||||
structure comm_monoid [class] (A : Type) extends monoid A renaming mul→add, comm_semigroup A
|
structure comm_monoid [class] (A : Type) extends monoid A renaming mul→add, comm_semigroup A
|
||||||
|
|
||||||
|
print fields comm_monoid
|
||||||
|
|
||||||
structure group [class] (A : Type) extends monoid A, has_inv A :=
|
structure group [class] (A : Type) extends monoid A, has_inv A :=
|
||||||
(is_inv : ∀ a, mul a (inv a) = one)
|
(is_inv : ∀ a, mul a (inv a) = one)
|
||||||
|
|
||||||
|
@ -49,6 +51,8 @@ structure ring [class] (A : Type)
|
||||||
(dist_left : ∀ a b c, mul a (add b c) = add (mul a b) (mul a c))
|
(dist_left : ∀ a b c, mul a (add b c) = add (mul a b) (mul a c))
|
||||||
(dist_right : ∀ a b c, mul (add a b) c = add (mul a c) (mul b c))
|
(dist_right : ∀ a b c, mul (add a b) c = add (mul a c) (mul b c))
|
||||||
|
|
||||||
|
print fields ring
|
||||||
|
|
||||||
variable A : Type₁
|
variable A : Type₁
|
||||||
variables a b c d : A
|
variables a b c d : A
|
||||||
variable R : ring A
|
variable R : ring A
|
||||||
|
|
Loading…
Reference in a new issue