191 lines
8.1 KiB
C++
191 lines
8.1 KiB
C++
/*
|
|
Copyright (c) 2016 Microsoft Corporation. All rights reserved.
|
|
Released under Apache 2.0 license as described in the file LICENSE.
|
|
|
|
Author: Leonardo de Moura
|
|
*/
|
|
#pragma once
|
|
#include "kernel/expr.h"
|
|
#include "library/deep_copy.h"
|
|
#include "library/equations_compiler/equations.h"
|
|
#include "frontends/lean/decl_attributes.h"
|
|
namespace lean {
|
|
struct parser;
|
|
struct cmd_meta;
|
|
class elaborator;
|
|
|
|
enum class decl_cmd_kind { Theorem, Definition, OpaqueConst, Example, Instance, Var, Abbreviation };
|
|
|
|
struct decl_modifiers {
|
|
bool m_is_private{false};
|
|
bool m_is_protected{false};
|
|
bool m_is_unsafe{false};
|
|
bool m_is_partial{false};
|
|
bool m_is_mutual{false};
|
|
bool m_is_noncomputable{false};
|
|
|
|
operator bool() const {
|
|
return m_is_private || m_is_protected || m_is_unsafe || m_is_partial || m_is_mutual || m_is_noncomputable;
|
|
}
|
|
};
|
|
|
|
/** \brief In Lean, declarations may contain nested definitions.
|
|
This object is used to propagate relevant flags to
|
|
nested definitions.
|
|
|
|
It is used to set/restore the thread local information. */
|
|
class declaration_info_scope {
|
|
declaration_info_scope(name const & ns, decl_cmd_kind kind, decl_modifiers const & modifiers, bool is_extern);
|
|
public:
|
|
declaration_info_scope(parser const & p, decl_cmd_kind kind, decl_modifiers const & modifiers, bool is_extern);
|
|
declaration_info_scope(parser const & p, decl_cmd_kind kind, decl_modifiers const & modifiers):
|
|
declaration_info_scope(p, kind, modifiers, false) {}
|
|
declaration_info_scope(parser const & p, decl_cmd_kind kind, cmd_meta const & meta);
|
|
~declaration_info_scope();
|
|
bool gen_aux_lemmas() const;
|
|
};
|
|
|
|
/** \brief Similar to declaration_info_scope, but it is used to update
|
|
naming prefix for nested definitions. */
|
|
class declaration_name_scope {
|
|
name m_name;
|
|
name m_actual_name;
|
|
name m_old_prefix; /* save current user facing prefix */
|
|
name m_old_actual_prefix; /* save current prefix */
|
|
unsigned m_old_next_match_idx;
|
|
/* Remark: the operation prefix + name in the following constructors and methods tries to avoid propagating
|
|
the string `_main` into names. That is, `foo._main` + `bla` is `foo.bla`. */
|
|
public:
|
|
/* Save the current prefix and match_idx, and set m_name to current prefix + n. */
|
|
declaration_name_scope(name const & n);
|
|
/* Save the current prefix and match_idx, and reset get_definition_info().m_next_match_idx. */
|
|
declaration_name_scope();
|
|
/* Set m_name to current prefix + n. This method is used when the constructor declaration_name_scope
|
|
has been used. */
|
|
void set_name(name const & n);
|
|
/* Restore prefix and match_idx. */
|
|
~declaration_name_scope();
|
|
name const & get_name() const { return m_name; }
|
|
name const & get_actual_name() const { return m_actual_name; }
|
|
};
|
|
|
|
/* Get declaration name in the current scope. */
|
|
name get_curr_declaration_name();
|
|
|
|
/** \brief Auxiliary scope for setting m_actual_prefix.
|
|
It is used with declaration_name_scope. */
|
|
class private_name_scope {
|
|
name m_old_actual_prefix; /* save current prefix */
|
|
bool m_old_is_private;
|
|
public:
|
|
/* Remark: If is_private == false, then this auxiliary scope is a no-op. */
|
|
private_name_scope(bool is_private, environment & env);
|
|
~private_name_scope();
|
|
};
|
|
|
|
/** \brief Auxiliary scope to compute the name for a nested match expression.
|
|
In Lean, we create auxiliary declarations for match expressions. */
|
|
class match_definition_scope {
|
|
name m_name;
|
|
name m_actual_name;
|
|
public:
|
|
match_definition_scope(environment const & env);
|
|
name const & get_name() const { return m_name; }
|
|
name const & get_actual_name() const { return m_actual_name; }
|
|
};
|
|
|
|
/** \brief Auxiliary scope to switch to `unsafe` mode when processing a
|
|
`by tac` in a regular definition.
|
|
We need this because we may have a match expression nested
|
|
in `tac`, and we should not create equation lemmas for it. */
|
|
class unsafe_definition_scope {
|
|
bool m_old_is_unsafe;
|
|
public:
|
|
unsafe_definition_scope();
|
|
~unsafe_definition_scope();
|
|
};
|
|
|
|
/** \brief Auxiliary scope to switch to the mode specified by the user.
|
|
That is, unsafe if the `unsafe` keyword was used, and regular otherwise.
|
|
We need this because of quoted expressions used in tactics. */
|
|
class restore_decl_unsafe_scope {
|
|
bool m_old_is_unsafe;
|
|
public:
|
|
restore_decl_unsafe_scope();
|
|
~restore_decl_unsafe_scope();
|
|
};
|
|
|
|
/** \brief Return true if the current scope used match-expressions */
|
|
bool used_match_idx();
|
|
|
|
/** \brief Parse explict universe parameters of the form:
|
|
{u_1 ... u_k}
|
|
|
|
The universe parameters are automatically added to the parser scope. */
|
|
bool parse_univ_params(parser & p, buffer<name> & lp_names);
|
|
|
|
name synthesize_instance_name(parser & p, expr const & type, declaration_name_scope & scope, pos_info const & c_pos);
|
|
|
|
/** \brief Parse a declaration header of the form
|
|
|
|
{u_1 ... u_k} id (params) : type
|
|
|
|
The result is the local constant (c : type). The explicit universe level parameters are stored
|
|
at lp_names, and the optional parameters at params.
|
|
|
|
Both lp_names and params are added to the parser scope.
|
|
|
|
\remark Caller is responsible for using: parser::local_scope scope2(p, env); */
|
|
expr parse_single_header(parser & p, declaration_name_scope & s, buffer <name> & lp_names, buffer <expr> & params,
|
|
bool is_example = false, bool is_instance = false);
|
|
/** \brief Parse the header of a mutually recursive declaration. It has the form
|
|
|
|
{u_1 ... u_k} id_1, ... id_n (params)
|
|
|
|
The explicit universe parameters are stored at lp_names,
|
|
The constant names id_i are stored at cs.
|
|
The names are local constants. Position information for a constant cs[i] can be retrieved using
|
|
p.pos_of(cs[i]).
|
|
|
|
Both lp_names, params and cs are added to the parser scope.
|
|
\remark Caller is responsible for adding expressions encoding the c_names to the parser
|
|
scope.
|
|
\remark Caller is responsible for using: parser::local_scope scope2(p, env); */
|
|
void parse_mutual_header(parser & p, buffer <name> & lp_names, buffer <expr> & cs, buffer <expr> & params);
|
|
/** \brief Parse the header for one of the declarations in a mutually recursive declaration.
|
|
It has the form
|
|
|
|
with <attrs> id : type
|
|
|
|
The result is (type, attrs). */
|
|
pair<expr, decl_attributes> parse_inner_header(parser & p, name const & c_expected);
|
|
|
|
/** \brief Add section/namespace parameters (and universes) used by params and all_exprs.
|
|
We also add parameters included using the command 'include'.
|
|
lp_names and params are input/output. */
|
|
void collect_implicit_locals(parser & p, buffer<name> & lp_names, buffer<expr> & params, buffer<expr> const & all_exprs);
|
|
void collect_implicit_locals(parser & p, buffer<name> & lp_names, buffer<expr> & params, std::initializer_list<expr> const & all_exprs);
|
|
void collect_implicit_locals(parser & p, buffer<name> & lp_names, buffer<expr> & params, expr const & e);
|
|
|
|
/** \brief Elaborate the types of the parameters \c params, and update the elaborator local context using them.
|
|
Store the elaborated parameters at new_params.
|
|
|
|
\post params.size() == new_params.size() */
|
|
void elaborate_params(elaborator & elab, buffer<expr> const & params, buffer<expr> & new_params);
|
|
|
|
/** \brief Create an alias c_name --> (c_real_name.{level_params} params)
|
|
level_params and params are subsets of lp_names and var_params that were
|
|
declared using the parameter command. */
|
|
|
|
/** \brief Add alias for new declaration. */
|
|
environment add_alias(environment const & env, bool is_protected, name const & c_name, name const & c_real_name);
|
|
|
|
/** \brief Create an equations header for the given function names.
|
|
It uses the information set using declaration_info_scope */
|
|
equations_header mk_equations_header(names const & fn_names, names const & fn_actual_names);
|
|
equations_header mk_equations_header(name const & fn_name, name const & fn_actual_name);
|
|
equations_header mk_match_header(name const & n, name const & actual_n);
|
|
|
|
expr replace_locals_preserving_pos_info(expr const & e, buffer<expr> const & from, buffer<expr> const & to);
|
|
expr replace_local_preserving_pos_info(expr const & e, expr const & from, expr const & to);
|
|
}
|