feat(frontends/lean): allow parameters to be used in sections

Restriction:
- coercions and notations cannot be defined in parametric sections

closes #401
This commit is contained in:
Leonardo de Moura 2015-01-23 17:42:19 -08:00
parent b643063955
commit b5c4e603db
9 changed files with 73 additions and 12 deletions

View file

@ -537,8 +537,9 @@ environment open_cmd(parser & p) { return open_export_cmd(p, true); }
environment export_cmd(parser & p) { return open_export_cmd(p, false); }
environment coercion_cmd(parser & p) {
if (in_context(p.env()))
throw parser_error("invalid 'coercion' command, coercions cannot be defined in contexts", p.pos());
if (in_context_or_parametric_section(p))
throw parser_error("invalid 'coercion' command, coercions cannot be defined in contexts or "
"sections containing parameters", p.pos());
bool persistent = false;
parse_persistent(p, persistent);
name f = p.check_constant_next("invalid 'coercion' command, constant expected");

View file

@ -116,7 +116,7 @@ static environment declare_var(parser & p, environment env,
if (_bi) bi = *_bi;
if (k == variable_kind::Parameter || k == variable_kind::Variable) {
if (k == variable_kind::Parameter) {
check_in_context(p);
check_in_context_or_section(p);
check_parameter_type(p, n, type, pos);
}
if (p.get_local(n))
@ -124,6 +124,9 @@ static environment declare_var(parser & p, environment env,
<< n << "' has already been declared", pos);
name u = p.mk_fresh_name();
expr l = p.save_pos(mk_local(u, n, type, bi), pos);
if (k == variable_kind::Parameter)
p.add_parameter(n, l);
else
p.add_local_expr(n, l, k == variable_kind::Variable);
return env;
} else {
@ -162,10 +165,9 @@ static void check_variable_kind(parser & p, variable_kind k) {
if (k == variable_kind::Axiom || k == variable_kind::Constant)
throw parser_error("invalid declaration, 'constant/axiom' cannot be used in contexts",
p.pos());
} else {
if (k == variable_kind::Parameter)
} else if (!in_section(p.env()) && !in_context(p.env()) && k == variable_kind::Parameter) {
throw parser_error("invalid declaration, 'parameter/hypothesis/conjecture' "
"can only be used in contexts", p.pos());
"can only be used in contexts and sections", p.pos());
}
}

View file

@ -629,6 +629,7 @@ struct notation_modifiers {
};
static environment notation_cmd_core(parser & p, bool overload, bool reserve) {
check_not_in_parametric_section(p);
notation_modifiers mods;
mods.parse(p);
flet<bool> set_allow_local(g_allow_local, in_context(p.env()) || !mods.m_persistent);
@ -642,6 +643,7 @@ static environment notation_cmd_core(parser & p, bool overload, bool reserve) {
}
static environment mixfix_cmd(parser & p, mixfix_kind k, bool overload, bool reserve) {
check_not_in_parametric_section(p);
notation_modifiers mods;
mods.parse(p);
flet<bool> set_allow_local(g_allow_local, in_context(p.env()) || !mods.m_persistent);

View file

@ -104,6 +104,7 @@ parser::parser(environment const & env, io_state const & ios,
m_scanner(strm, strm_name, s ? s->m_line : 1),
m_theorem_queue(*this, num_threads > 1 ? num_threads - 1 : 0),
m_snapshot_vector(sv), m_info_manager(im), m_cache(nullptr), m_index(nullptr) {
m_has_params = false;
m_keep_theorem_mode = tmode;
if (s) {
m_local_level_decls = s->m_lds;
@ -438,7 +439,8 @@ void parser::push_local_scope(bool save_options) {
optional<options> opts;
if (save_options)
opts = m_ios.get_options();
m_parser_scope_stack = cons(parser_scope_stack_elem(opts, m_level_variables, m_variables, m_include_vars, m_undef_ids.size()),
m_parser_scope_stack = cons(parser_scope_stack_elem(opts, m_level_variables, m_variables, m_include_vars,
m_undef_ids.size(), m_has_params),
m_parser_scope_stack);
}
@ -457,6 +459,7 @@ void parser::pop_local_scope() {
m_level_variables = s.m_level_variables;
m_variables = s.m_variables;
m_include_vars = s.m_include_vars;
m_has_params = s.m_has_params;
m_undef_ids.shrink(s.m_num_undef_ids);
m_parser_scope_stack = tail(m_parser_scope_stack);
}
@ -481,6 +484,12 @@ void parser::add_local_expr(name const & n, expr const & p, bool is_variable) {
}
}
void parser::add_parameter(name const & n, expr const & p) {
lean_assert(is_local(p));
add_local_expr(n, p, false);
m_has_params = true;
}
unsigned parser::get_local_level_index(name const & n) const {
return m_local_level_decls.find_idx(n);
}

View file

@ -53,9 +53,11 @@ struct parser_scope_stack_elem {
name_set m_variables;
name_set m_include_vars;
unsigned m_num_undef_ids;
bool m_has_params;
parser_scope_stack_elem(optional<options> const & o, name_set const & lvs, name_set const & vs, name_set const & ivs,
unsigned num_undef_ids):
m_options(o), m_level_variables(lvs), m_variables(vs), m_include_vars(ivs), m_num_undef_ids(num_undef_ids) {}
unsigned num_undef_ids, bool has_params):
m_options(o), m_level_variables(lvs), m_variables(vs), m_include_vars(ivs),
m_num_undef_ids(num_undef_ids), m_has_params(has_params) {}
};
typedef list<parser_scope_stack_elem> parser_scope_stack;
@ -97,6 +99,7 @@ class parser {
scanner::token_kind m_curr;
local_level_decls m_local_level_decls;
local_expr_decls m_local_decls;
bool m_has_params; // true context context contains parameters
name_set m_level_variables;
name_set m_variables; // subset of m_local_decls that is marked as variables
name_set m_include_vars; // subset of m_local_decls that is marked as include
@ -383,7 +386,9 @@ public:
bool has_locals() const { return !m_local_decls.empty() || !m_local_level_decls.empty(); }
void add_local_level(name const & n, level const & l, bool is_variable = false);
void add_local_expr(name const & n, expr const & p, bool is_variable = false);
void add_parameter(name const & n, expr const & p);
void add_local(expr const & p) { return add_local_expr(local_pp_name(p), p); }
bool has_params() const { return m_has_params; }
bool is_local_decl(expr const & l) const { return is_local(l) && m_local_decls.contains(local_pp_name(l)); }
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); }

View file

@ -40,9 +40,29 @@ void check_in_context(parser const & p) {
if (!in_context(p.env()))
throw exception(sstream() << "invalid command, it must be used in a (local) context");
}
void check_in_context_or_section(parser const & p) {
if (!in_context(p.env()) && !in_section(p.env()))
throw exception(sstream() << "invalid command, it must be used in a (local) context or section");
}
bool in_parametric_section(parser const & p) {
return in_section(p.env()) && p.has_params();
}
void check_not_in_parametric_section(parser const & p) {
if (in_parametric_section(p))
throw exception(sstream() << "invalid command, it cannot be used in sections containing parameters");
}
bool in_context_or_parametric_section(parser const & p) {
return in_context(p.env()) || in_parametric_section(p);
}
bool is_root_namespace(name const & n) {
return n == get_root_tk();
}
name remove_root_prefix(name const & n) {
return n.replace_prefix(get_root_tk(), name());
}

View file

@ -21,6 +21,10 @@ bool parse_persistent(parser & p, bool & persistent);
void check_atomic(name const & n);
void check_in_context(parser const & p);
void check_in_context_or_section(parser const & p);
void check_not_in_parametric_section(parser const & p);
bool in_parametric_section(parser const & p);
bool in_context_or_parametric_section(parser const & p);
bool is_root_namespace(name const & n);
name remove_root_prefix(name const & n);
/** \brief Return the local levels in \c ls that are not tagged as variables.

View file

@ -1,2 +1,2 @@
bad_coercions.lean:12:18: error: invalid '[coercion]' modifier, coercions cannot be defined in contexts
bad_coercions.lean:18:11: error: invalid 'coercion' command, coercions cannot be defined in contexts
bad_coercions.lean:18:11: error: invalid 'coercion' command, coercions cannot be defined in contexts or sections containing parameters

View file

@ -0,0 +1,18 @@
section foo
parameter A : Type
variable a : A
definition foo := a
check foo
structure point [class] :=
(x : A) (y : A)
end foo
check foo
definition point_nat [instance] : point nat :=
point.mk nat.zero nat.zero
print classes
check point