feat(frontends/lean): parameter and variable binder type update

see issue #532
This commit is contained in:
Leonardo de Moura 2015-04-22 12:22:17 -07:00
parent 91f21c007a
commit dc93603b4a
6 changed files with 175 additions and 11 deletions

View file

@ -182,6 +182,29 @@ static void check_variable_kind(parser & p, variable_kind k) {
} }
} }
static void update_local_binder_info(parser & p, variable_kind k, name const & n,
optional<binder_info> const & bi, pos_info const & pos) {
binder_info new_bi;
if (bi) new_bi = *bi;
if (k == variable_kind::Parameter) {
if (p.is_local_variable(n))
throw parser_error(sstream() << "invalid parameter binder type update, '"
<< n << "' is a variable", pos);
if (!p.update_local_binder_info(n, new_bi))
throw parser_error(sstream() << "invalid parameter binder type update, '"
<< n << "' is not a parameter", pos);
} else {
if (!p.update_local_binder_info(n, new_bi) || !p.is_local_variable(n))
throw parser_error(sstream() << "invalid variable binder type update, '"
<< n << "' is not a variable", pos);
}
}
static bool curr_is_binder_annotation(parser & p) {
return p.curr_is_token(get_lparen_tk()) || p.curr_is_token(get_lcurly_tk()) ||
p.curr_is_token(get_ldcurly_tk()) || p.curr_is_token(get_lbracket_tk());
}
static environment variable_cmd_core(parser & p, variable_kind k, bool is_protected = false) { static environment variable_cmd_core(parser & p, variable_kind k, bool is_protected = false) {
check_variable_kind(p, k); check_variable_kind(p, k);
auto pos = p.pos(); auto pos = p.pos();
@ -196,12 +219,18 @@ static environment variable_cmd_core(parser & p, variable_kind k, bool is_protec
parse_univ_params(p, ls_buffer); parse_univ_params(p, ls_buffer);
expr type; expr type;
if (!p.curr_is_token(get_colon_tk())) { if (!p.curr_is_token(get_colon_tk())) {
if (!curr_is_binder_annotation(p) && (k == variable_kind::Parameter || k == variable_kind::Variable)) {
p.parse_close_binder_info(bi);
update_local_binder_info(p, k, n, bi, pos);
return p.env();
} else {
buffer<expr> ps; buffer<expr> ps;
unsigned rbp = 0; unsigned rbp = 0;
auto lenv = p.parse_binders(ps, rbp); auto lenv = p.parse_binders(ps, rbp);
p.check_token_next(get_colon_tk(), "invalid declaration, ':' expected"); p.check_token_next(get_colon_tk(), "invalid declaration, ':' expected");
type = p.parse_scoped_expr(ps, lenv); type = p.parse_scoped_expr(ps, lenv);
type = Pi(ps, type, p); type = Pi(ps, type, p);
}
} else { } else {
p.next(); p.next();
type = p.parse_expr(); type = p.parse_expr();
@ -242,11 +271,29 @@ static environment variables_cmd_core(parser & p, variable_kind k, bool is_prote
optional<binder_info> bi = parse_binder_info(p, k); optional<binder_info> bi = parse_binder_info(p, k);
buffer<name> ids; buffer<name> ids;
while (!p.curr_is_token(get_colon_tk())) { while (p.curr_is_identifier()) {
name id = p.check_id_next("invalid parameters declaration, identifier expected"); name id = p.get_name_val();
p.next();
ids.push_back(id); ids.push_back(id);
} }
if (p.curr_is_token(get_colon_tk())) {
p.next(); p.next();
} else {
if (k == variable_kind::Parameter || k == variable_kind::Variable) {
p.parse_close_binder_info(bi);
for (name const & id : ids) {
update_local_binder_info(p, k, id, bi, pos);
}
if (curr_is_binder_annotation(p))
return variables_cmd_core(p, k);
else
return env;
} else {
throw parser_error("invalid variables/constants/axioms declaration, ':' expected", pos);
}
}
optional<parser::local_scope> scope1; optional<parser::local_scope> scope1;
if (k == variable_kind::Constant || k == variable_kind::Axiom) if (k == variable_kind::Constant || k == variable_kind::Axiom)
scope1.emplace(p); scope1.emplace(p);
@ -266,8 +313,7 @@ static environment variables_cmd_core(parser & p, variable_kind k, bool is_prote
new_ls = append(ls, new_ls); new_ls = append(ls, new_ls);
env = declare_var(p, env, id, new_ls, new_type, k, bi, pos, is_protected); env = declare_var(p, env, id, new_ls, new_type, k, bi, pos, is_protected);
} }
if (p.curr_is_token(get_lparen_tk()) || p.curr_is_token(get_lcurly_tk()) || if (curr_is_binder_annotation(p)) {
p.curr_is_token(get_ldcurly_tk()) || p.curr_is_token(get_lbracket_tk())) {
if (k == variable_kind::Constant || k == variable_kind::Axiom) { if (k == variable_kind::Constant || k == variable_kind::Axiom) {
// Hack: temporarily update the parser environment. // Hack: temporarily update the parser environment.
// We must do that to be able to process // We must do that to be able to process

View file

@ -36,6 +36,12 @@ public:
m_counter++; m_counter++;
m_entries = cons(mk_pair(k, v), m_entries); m_entries = cons(mk_pair(k, v), m_entries);
} }
void update(name const & k, V const & v) {
if (auto it = m_map.find(k))
m_map.insert(k, mk_pair(v, it->second));
else
lean_unreachable();
}
V const * find(name const & k) const { auto it = m_map.find(k); return it ? &(it->first) : nullptr; } V const * find(name const & k) const { auto it = m_map.find(k); return it ? &(it->first) : nullptr; }
unsigned find_idx(name const & k) const { auto it = m_map.find(k); return it ? it->second : 0; } unsigned find_idx(name const & k) const { auto it = m_map.find(k); return it ? it->second : 0; }
bool contains(name const & k) const { return m_map.contains(k); } bool contains(name const & k) const { return m_map.contains(k); }

View file

@ -515,6 +515,14 @@ void parser::add_parameter(name const & n, expr const & p) {
m_has_params = true; m_has_params = true;
} }
bool parser::update_local_binder_info(name const & n, binder_info const & bi) {
auto it = get_local(n);
if (!it) return false;
if (!is_local(*it)) return false;
m_local_decls.update(n, update_local(*it, bi));
return true;
}
unsigned parser::get_local_level_index(name const & n) const { unsigned parser::get_local_level_index(name const & n) const {
return m_local_level_decls.find_idx(n); return m_local_level_decls.find_idx(n);
} }

View file

@ -408,6 +408,8 @@ public:
bool is_local_level_variable(name const & n) const { return m_level_variables.contains(n); } bool is_local_level_variable(name const & n) const { return m_level_variables.contains(n); }
bool is_local_variable(name const & n) const { return m_variables.contains(n); } bool is_local_variable(name const & n) const { return m_variables.contains(n); }
bool is_local_variable(expr const & e) const { return is_local_variable(local_pp_name(e)); } bool is_local_variable(expr const & e) const { return is_local_variable(local_pp_name(e)); }
/** \brief Update binder information for the section parameter n, return true if success, and false if n is not a section parameter. */
bool update_local_binder_info(name const & n, binder_info const & bi);
void include_variable(name const & n) { m_include_vars.insert(n); } void include_variable(name const & n) { m_include_vars.insert(n); }
void omit_variable(name const & n) { m_include_vars.erase(n); } void omit_variable(name const & n) { m_include_vars.erase(n); }
bool is_include_variable(name const & n) const { return m_include_vars.contains(n); } bool is_include_variable(name const & n) const { return m_include_vars.contains(n); }

View file

@ -0,0 +1,83 @@
section
parameter {A : Type}
parameter A
definition id (a : A) := a
parameter {A}
definition id₂ (a : A) := a
end
check @id
check @id₂
section
parameters {A : Type} {B : Type}
definition foo1 (a : A) (b : B) := a
parameters {A} (B)
definition foo2 (a : A) (b : B) := a
parameters (A) {B}
definition foo3 (a : A) (b : B) := a
parameters (A) (B)
definition foo4 (a : A) (b : B) := a
check @foo1
check @foo2
-- check @foo3 -- TODO
check @foo4
end
check @foo1
check @foo2
check @foo3
check @foo4
section
variables {A : Type} {B : Type}
definition boo1 (a : A) (b : B) := a
variables {A} (B)
definition boo2 (a : A) (b : B) := a
variables (A) {B}
definition boo3 (a : A) (b : B) := a
variables (A) (B)
definition boo4 (a : A) (b : B) := a
check @boo1
check @boo2
check @boo3
check @boo4
end
section
variables {A : Type} {B : Type}
parameter (A) -- ERROR
variable (C) -- ERROR
variables (C) (D) -- ERROR
variables C -- ERROR
definition id3 (a : A) := a
parameter id3 -- ERROR
parameter (C : Type)
variables {C} -- ERROR
end

View file

@ -0,0 +1,19 @@
id : Π (A : Type), A → A
id₂ : Π {A : Type}, A → A
foo1 : A → B → A
foo2 : A → B → A
foo4 : A → B → A
foo1 : Π {A : Type} {B : Type}, A → B → A
foo2 : Π {A : Type} (B : Type), A → B → A
foo3 : Π (A : Type) {B : Type}, A → B → A
foo4 : Π (A : Type) (B : Type), A → B → A
boo1 : Π {A : Type} {B : Type}, A → B → A
boo2 : Π {A : Type} (B : Type), A → B → A
boo3 : Π (A : Type) {B : Type}, A → B → A
boo4 : Π (A : Type) (B : Type), A → B → A
param_binder_update.lean:70:12: error: invalid parameter binder type update, 'A' is a variable
param_binder_update.lean:71:11: error: invalid variable binder type update, 'C' is not a variable
param_binder_update.lean:72:12: error: invalid variable binder type update, 'C' is not a variable
param_binder_update.lean:73:12: error: invalid variable binder type update, 'C' is not a variable
param_binder_update.lean:77:12: error: invalid parameter binder type update, 'id3' is not a parameter
param_binder_update.lean:81:12: error: invalid variable binder type update, 'C' is not a variable