2014-07-29 02:04:57 +00:00
/*
Copyright ( c ) 2014 Microsoft Corporation . All rights reserved .
Released under Apache 2.0 license as described in the file LICENSE .
Author : Leonardo de Moura
*/
# include <memory>
# include <utility>
# include <vector>
# include <algorithm>
2014-11-03 22:14:40 +00:00
# include "util/sstream.h"
2014-12-09 20:40:09 +00:00
# include "util/sexpr/option_declarations.h"
2014-07-29 02:04:57 +00:00
# include "kernel/type_checker.h"
# include "kernel/instantiate.h"
2014-11-03 22:14:40 +00:00
# include "kernel/abstract.h"
2014-07-29 02:04:57 +00:00
# include "kernel/replace_fn.h"
2014-11-03 22:14:40 +00:00
# include "kernel/error_msgs.h"
# include "kernel/inductive/inductive.h"
2014-07-29 02:04:57 +00:00
# include "library/scoped_ext.h"
# include "library/placeholder.h"
# include "library/locals.h"
2014-09-19 20:30:08 +00:00
# include "library/reducible.h"
2014-11-03 22:14:40 +00:00
# include "library/unifier.h"
# include "library/module.h"
2014-11-03 23:50:41 +00:00
# include "library/aliases.h"
2014-11-04 01:55:59 +00:00
# include "library/coercion.h"
2014-11-04 01:39:52 +00:00
# include "library/explicit.h"
2014-11-03 22:50:12 +00:00
# include "library/protected.h"
2014-12-10 05:12:39 +00:00
# include "library/class.h"
2014-12-10 19:23:23 +00:00
# include "library/util.h"
2014-11-03 22:14:40 +00:00
# include "library/definitional/rec_on.h"
# include "library/definitional/induction_on.h"
# include "library/definitional/cases_on.h"
# include "library/definitional/projection.h"
2014-11-15 23:59:49 +00:00
# include "library/definitional/no_confusion.h"
2014-07-29 02:04:57 +00:00
# include "frontends/lean/parser.h"
# include "frontends/lean/util.h"
# include "frontends/lean/decl_cmds.h"
2014-09-23 17:00:36 +00:00
# include "frontends/lean/tokens.h"
2014-11-03 22:14:40 +00:00
# include "frontends/lean/elaborator_exception.h"
# include "frontends/lean/type_util.h"
2014-07-29 02:04:57 +00:00
2014-11-04 06:40:08 +00:00
# ifndef LEAN_DEFAULT_STRUCTURE_INTRO
# define LEAN_DEFAULT_STRUCTURE_INTRO "mk"
# endif
2014-12-09 20:40:09 +00:00
# ifndef LEAN_DEFAULT_STRUCTURE_ETA
# define LEAN_DEFAULT_STRUCTURE_ETA false
# endif
# ifndef LEAN_DEFAULT_STRUCTURE_PROJ_MK
# define LEAN_DEFAULT_STRUCTURE_PROJ_MK false
# endif
2014-07-29 02:04:57 +00:00
namespace lean {
2014-12-09 20:40:09 +00:00
static name * g_tmp_prefix = nullptr ;
static name * g_gen_eta = nullptr ;
static name * g_gen_proj_mk = nullptr ;
2014-07-29 02:04:57 +00:00
2014-09-23 17:00:36 +00:00
void initialize_structure_cmd ( ) {
2014-12-09 20:40:09 +00:00
g_tmp_prefix = new name ( name : : mk_internal_unique_name ( ) ) ;
g_gen_eta = new name { " structure " , " eta_thm " } ;
g_gen_proj_mk = new name { " structure " , " proj_mk_thm " } ;
register_bool_option ( * g_gen_eta , LEAN_DEFAULT_STRUCTURE_ETA ,
" (structure) automatically generate 'eta' theorem whenever declaring a new structure " ) ;
register_bool_option ( * g_gen_proj_mk , LEAN_DEFAULT_STRUCTURE_PROJ_MK ,
" (structure) automatically gneerate projection over introduction theorem when declaring a new structure, the theorem is never generated for proof irrelevant fields " ) ;
2014-09-23 17:00:36 +00:00
}
void finalize_structure_cmd ( ) {
delete g_tmp_prefix ;
2014-12-09 20:40:09 +00:00
delete g_gen_eta ;
delete g_gen_proj_mk ;
2014-09-23 17:00:36 +00:00
}
2014-07-29 02:04:57 +00:00
2014-12-09 20:40:09 +00:00
bool get_structure_eta_thm ( options const & o ) { return o . get_bool ( * g_gen_eta , LEAN_DEFAULT_STRUCTURE_ETA ) ; }
bool get_structure_proj_mk_thm ( options const & o ) { return o . get_bool ( * g_gen_proj_mk , LEAN_DEFAULT_STRUCTURE_ETA ) ; }
2014-11-05 22:06:54 +00:00
/** \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 ) ;
}
2014-07-29 02:04:57 +00:00
struct structure_cmd_fn {
typedef std : : unique_ptr < type_checker > type_checker_ptr ;
2014-08-19 23:28:58 +00:00
typedef std : : vector < pair < name , name > > rename_vector ;
2014-11-03 22:14:40 +00:00
// field_map[i] contains the position of the \c i-th field of a parent structure into this one.
typedef std : : vector < unsigned > field_map ;
typedef type_modifiers modifiers ;
2014-07-29 02:04:57 +00:00
parser & m_p ;
environment m_env ;
name_generator m_ngen ;
2014-11-03 22:14:40 +00:00
type_checker_ptr m_tc ;
2014-07-29 02:04:57 +00:00
name m_namespace ;
name m_name ;
2014-11-03 22:14:40 +00:00
pos_info m_name_pos ;
2014-07-29 02:04:57 +00:00
buffer < name > m_level_names ;
2014-11-03 22:14:40 +00:00
modifiers m_modifiers ;
2014-07-29 02:04:57 +00:00
buffer < expr > m_params ;
expr m_type ;
buffer < expr > m_parents ;
2014-11-04 07:15:15 +00:00
buffer < bool > m_private_parents ;
2014-11-03 22:14:40 +00:00
name m_mk ;
2014-11-04 17:10:25 +00:00
name m_mk_short ;
2014-11-03 22:14:40 +00:00
pos_info m_mk_pos ;
implicit_infer_kind m_mk_infer ;
2014-07-29 02:04:57 +00:00
buffer < expr > m_fields ;
std : : vector < rename_vector > m_renames ;
2014-11-03 22:14:40 +00:00
std : : vector < field_map > m_field_maps ;
2014-07-29 02:04:57 +00:00
bool m_infer_result_universe ;
bool m_using_explicit_levels ;
2014-11-03 23:50:41 +00:00
levels m_ctx_levels ; // context levels for creating aliases
buffer < expr > m_ctx_locals ; // context local constants for creating aliases
2014-07-29 02:04:57 +00:00
2014-12-09 20:40:09 +00:00
bool m_gen_eta ;
bool m_gen_proj_mk ;
2014-07-29 02:04:57 +00:00
structure_cmd_fn ( parser & p ) : m_p ( p ) , m_env ( p . env ( ) ) , m_ngen ( p . mk_ngen ( ) ) , m_namespace ( get_namespace ( m_env ) ) {
2014-11-03 22:14:40 +00:00
m_tc = mk_type_checker ( m_env , m_p . mk_ngen ( ) , false ) ;
2014-07-29 02:04:57 +00:00
m_infer_result_universe = false ;
m_using_explicit_levels = false ;
2014-12-09 20:40:09 +00:00
m_gen_eta = get_structure_eta_thm ( p . get_options ( ) ) ;
m_gen_proj_mk = get_structure_proj_mk_thm ( p . get_options ( ) ) ;
2014-07-29 02:04:57 +00:00
}
2014-11-03 22:14:40 +00:00
/** \brief Parse structure name and (optional) universe parameters */
2014-07-29 02:04:57 +00:00
void parse_decl_name ( ) {
2014-11-03 22:14:40 +00:00
m_name_pos = m_p . pos ( ) ;
2014-07-29 02:04:57 +00:00
m_name = m_p . check_atomic_id_next ( " invalid 'structure', identifier expected " ) ;
m_name = m_namespace + m_name ;
buffer < name > ls_buffer ;
if ( parse_univ_params ( m_p , ls_buffer ) ) {
m_infer_result_universe = false ;
m_level_names . append ( ls_buffer ) ;
} else {
m_infer_result_universe = true ;
}
2014-11-03 22:14:40 +00:00
m_modifiers . parse ( m_p ) ;
2014-07-29 02:04:57 +00:00
}
2014-11-03 22:14:40 +00:00
/** \brief Parse structure parameters */
2014-07-29 02:04:57 +00:00
void parse_params ( ) {
2014-11-24 00:42:53 +00:00
if ( ! m_p . curr_is_token ( get_extends_tk ( ) ) & & ! m_p . curr_is_token ( get_assign_tk ( ) ) & & ! m_p . curr_is_token ( get_colon_tk ( ) ) ) {
unsigned rbp = 0 ;
m_p . parse_binders ( m_params , rbp ) ;
}
2014-07-29 02:04:57 +00:00
for ( expr const & l : m_params )
m_p . add_local ( l ) ;
}
2014-11-03 22:14:40 +00:00
/** \brief Check whether \c parent is really an inductive datatype declaration that can be viewed as a "record".
That is , it is not part of a mutually recursive declaration , it has only one constructor ,
and it does not have indicies .
*/
void check_parent ( expr const & parent , pos_info const & pos ) {
expr const & fn = get_app_fn ( parent ) ;
if ( ! is_constant ( fn ) )
throw parser_error ( " invalid 'structure', expression must be a 'parent' structure " , pos ) ;
name const & S = const_name ( fn ) ;
2014-11-05 22:06:54 +00:00
if ( ! is_structure ( m_env , S ) )
2014-11-03 22:14:40 +00:00
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 */
std : : tuple < level_param_names , unsigned , inductive : : intro_rule > get_parent_info ( name const & parent ) {
2014-11-05 22:06:54 +00:00
return get_structure_info ( m_env , parent ) ;
2014-11-03 22:14:40 +00:00
}
/** \brief Sign an error if the constructor \c intro_type does not have a field named \c from_id */
void check_from_rename ( name const & parent_name , expr intro_type , name const & from_id , pos_info const & from_pos ) {
while ( is_pi ( intro_type ) ) {
if ( binding_name ( intro_type ) = = from_id )
return ;
intro_type = binding_body ( intro_type ) ;
}
throw parser_error ( sstream ( ) < < " invalid 'structure' renaming, parent structure ' " < < parent_name < < " ' "
< < " does not contain field ' " < < from_id < < " ' " , from_pos ) ;
}
/** \brief Parse optional extends clause */
2014-07-29 02:04:57 +00:00
void parse_extends ( ) {
2014-09-23 17:00:36 +00:00
if ( m_p . curr_is_token ( get_extends_tk ( ) ) ) {
2014-07-29 02:04:57 +00:00
m_p . next ( ) ;
while ( true ) {
2014-11-03 22:14:40 +00:00
auto pos = m_p . pos ( ) ;
2014-11-04 07:15:15 +00:00
bool is_private_parent = false ;
if ( m_p . curr_is_token ( get_private_tk ( ) ) ) {
m_p . next ( ) ;
is_private_parent = true ;
}
2014-11-03 22:14:40 +00:00
expr parent = m_p . parse_expr ( ) ;
m_parents . push_back ( parent ) ;
2014-11-04 07:15:15 +00:00
m_private_parents . push_back ( is_private_parent ) ;
2014-11-03 22:14:40 +00:00
check_parent ( parent , pos ) ;
name const & parent_name = const_name ( get_app_fn ( parent ) ) ;
auto parent_info = get_parent_info ( parent_name ) ;
unsigned nparams = std : : get < 1 > ( parent_info ) ;
inductive : : intro_rule intro = std : : get < 2 > ( parent_info ) ;
expr intro_type = inductive : : intro_rule_type ( intro ) ;
for ( unsigned i = 0 ; i < nparams ; i + + ) {
if ( ! is_pi ( intro_type ) )
throw parser_error ( " invalid 'structure' extends, parent structure seems to be ill-formed " , pos ) ;
intro_type = binding_body ( intro_type ) ;
}
2014-07-29 02:04:57 +00:00
m_renames . push_back ( rename_vector ( ) ) ;
2014-09-23 17:00:36 +00:00
if ( m_p . curr_is_token ( get_renaming_tk ( ) ) ) {
2014-07-29 02:04:57 +00:00
m_p . next ( ) ;
rename_vector & v = m_renames . back ( ) ;
2014-11-03 22:14:40 +00:00
while ( m_p . curr_is_identifier ( ) ) {
auto from_pos = m_p . pos ( ) ;
name from_id = m_p . get_name_val ( ) ;
if ( std : : find_if ( v . begin ( ) , v . end ( ) ,
[ & ] ( pair < name , name > const & p ) { return p . first = = from_id ; } ) ! = v . end ( ) )
throw parser_error ( sstream ( ) < < " invalid 'structure' renaming, a rename from ' " < <
from_id < < " ' has already been defined " , from_pos ) ;
check_from_rename ( parent_name , intro_type , from_id , from_pos ) ;
m_p . next ( ) ;
m_p . check_token_next ( get_arrow_tk ( ) , " invalid 'structure' renaming, '->' expected " ) ;
name to_id = m_p . check_id_next ( " invalid 'structure' renaming, identifier expected " ) ;
if ( from_id = = to_id )
throw parser_error ( sstream ( ) < < " invalid 'structure' renaming, redundant rename " , from_pos ) ;
v . emplace_back ( from_id , to_id ) ;
2014-07-29 02:04:57 +00:00
}
}
2014-09-23 17:00:36 +00:00
if ( ! m_p . curr_is_token ( get_comma_tk ( ) ) )
2014-07-29 02:04:57 +00:00
break ;
m_p . next ( ) ;
}
}
}
2014-11-05 06:19:23 +00:00
void throw_explicit_universe ( pos_info const & pos ) {
throw parser_error ( " invalid 'structure', the resultant universe must be provided when explicit universe levels are being used " , pos ) ;
}
2014-11-03 22:14:40 +00:00
/** \brief Parse resultant universe */
2014-07-29 02:04:57 +00:00
void parse_result_type ( ) {
auto pos = m_p . pos ( ) ;
2014-09-23 17:00:36 +00:00
if ( m_p . curr_is_token ( get_colon_tk ( ) ) ) {
2014-07-29 02:04:57 +00:00
m_p . next ( ) ;
m_type = m_p . parse_expr ( ) ;
if ( ! is_sort ( m_type ) )
throw parser_error ( " invalid 'structure', 'Type' expected " , pos ) ;
2014-11-05 19:55:41 +00:00
if ( m_infer_result_universe ) {
if ( ! is_placeholder ( sort_level ( m_type ) ) )
throw parser_error ( " invalid 'structure', resultant universe level is computed "
" automatically when universe level parameters are not provided " , pos ) ;
} else {
if ( has_placeholder ( m_type ) )
throw_explicit_universe ( pos ) ;
level l = sort_level ( m_type ) ;
if ( m_env . impredicative ( ) & & ! is_not_zero ( l ) )
throw parser_error ( " invalid 'structure', the resultant universe level should not be zero "
" for any universe parameter assignment " , pos ) ;
}
2014-07-29 02:04:57 +00:00
} else {
2014-11-05 06:19:23 +00:00
if ( ! m_infer_result_universe )
throw_explicit_universe ( pos ) ;
2014-07-29 02:04:57 +00:00
m_type = m_p . save_pos ( mk_sort ( mk_level_placeholder ( ) ) , pos ) ;
}
}
2014-11-03 22:14:40 +00:00
/** \brief Parse parameters, extends clauses and resultant type */
void parse_header ( ) {
parser : : local_scope scope ( m_p ) ;
parse_decl_name ( ) ;
parse_params ( ) ;
parse_extends ( ) ;
parse_result_type ( ) ;
}
/** \brief Update the local constants in \c locals using the content of the Pi expression \c new_tmp.
This method assumes that new_tmp contains at least locals . size ( ) nested Pi ' s .
*/
expr update_locals ( expr new_tmp , buffer < expr > & locals ) {
for ( unsigned i = 0 ; i < locals . size ( ) ; i + + ) {
expr new_local = mk_local ( binding_name ( new_tmp ) , binding_domain ( new_tmp ) , binding_info ( new_tmp ) ) ;
locals [ i ] = new_local ;
new_tmp = instantiate ( binding_body ( new_tmp ) , new_local ) ;
}
return new_tmp ;
}
2014-11-04 01:39:52 +00:00
expr update_parents ( expr new_tmp ) {
for ( unsigned i = 0 ; i < m_parents . size ( ) ; i + + ) {
m_parents [ i ] = copy_tag ( m_parents [ i ] , expr ( binding_domain ( new_tmp ) ) ) ;
new_tmp = binding_body ( new_tmp ) ;
lean_assert ( closed ( new_tmp ) ) ;
}
return new_tmp ;
}
2014-11-03 22:14:40 +00:00
/** \brief elaborate parameters and "parent" types */
void elaborate_header ( ) {
buffer < expr > include_vars ;
m_p . get_include_variables ( include_vars ) ;
buffer < expr > tmp_locals ;
tmp_locals . append ( m_params ) ;
for ( expr const & parent : m_parents )
tmp_locals . push_back ( mk_local ( m_ngen . next ( ) , parent ) ) ;
expr tmp = Pi_as_is ( include_vars , Pi ( tmp_locals , m_type , m_p ) , m_p ) ;
list < expr > ctx = m_p . locals_to_context ( ) ;
level_param_names new_ls ;
expr new_tmp ;
std : : tie ( new_tmp , new_ls ) = m_p . elaborate_type ( tmp , ctx ) ;
levels new_meta_ls = map2 < level > ( new_ls , [ ] ( name const & n ) { return mk_meta_univ ( n ) ; } ) ;
new_tmp = instantiate_univ_params ( new_tmp , new_ls , new_meta_ls ) ;
new_tmp = update_locals ( new_tmp , include_vars ) ;
new_tmp = update_locals ( new_tmp , m_params ) ;
buffer < expr > explicit_params ;
explicit_params . append ( m_params ) ;
m_params . clear ( ) ;
m_params . append ( include_vars ) ;
m_params . append ( explicit_params ) ;
2014-11-04 01:39:52 +00:00
new_tmp = update_parents ( new_tmp ) ;
2014-11-03 22:14:40 +00:00
m_type = new_tmp ;
}
void throw_ill_formed_parent ( name const & parent_name ) {
throw exception ( sstream ( ) < < " invalid 'structure' header, parent structure ' " < < parent_name < < " ' is ill-formed " ) ;
}
/** \brief Check if \c fname has been renamed, and return new name */
name rename ( rename_vector const & v , name const & fname ) {
for ( auto const & p : v ) {
if ( p . first = = fname )
return p . second ;
}
return fname ;
}
/** \brief If \c fname matches the name of an existing field, then check if
the types are definitionally equal ( store any generated unification constraints in cseq ) ,
and return the index of the existing field . */
optional < unsigned > merge ( expr const & parent , name const & fname , expr const & ftype , constraint_seq & cseq ) {
for ( unsigned i = 0 ; i < m_fields . size ( ) ; i + + ) {
if ( local_pp_name ( m_fields [ i ] ) = = fname ) {
if ( m_tc - > is_def_eq ( mlocal_type ( m_fields [ i ] ) , ftype , justification ( ) , cseq ) ) {
return optional < unsigned > ( i ) ;
} else {
expr prev_ftype = mlocal_type ( m_fields [ i ] ) ;
throw_elaborator_exception ( m_env , parent , [ = ] ( formatter const & fmt ) {
format r = format ( " invalid 'structure' header, field ' " ) ;
r + = format ( fname ) ;
r + = format ( " ' from ' " ) ;
r + = format ( const_name ( get_app_fn ( parent ) ) ) ;
r + = format ( " ' has already been declared with a different type " ) ;
r + = pp_indent_expr ( fmt , prev_ftype ) ;
r + = compose ( line ( ) , format ( " and " ) ) ;
r + = pp_indent_expr ( fmt , ftype ) ;
return r ;
} ) ;
}
}
}
return optional < unsigned > ( ) ;
}
/** \brief Process extends clauses.
Return unification constraints when processing fields of parent structures .
The constraints are generated when " merging " the fields from different parents .
This method also populates the vector m_field_maps and m_fields .
*/
constraint_seq process_extends ( ) {
lean_assert ( m_fields . empty ( ) ) ;
lean_assert ( m_field_maps . empty ( ) ) ;
constraint_seq cseq ;
for ( unsigned i = 0 ; i < m_parents . size ( ) ; i + + ) {
expr const & parent = m_parents [ i ] ;
rename_vector const & renames = m_renames [ i ] ;
m_field_maps . push_back ( field_map ( ) ) ;
field_map & fmap = m_field_maps . back ( ) ;
buffer < expr > args ;
expr const & parent_fn = get_app_args ( parent , args ) ;
level_param_names lparams ; unsigned nparams ; inductive : : intro_rule intro ;
name const & parent_name = const_name ( parent_fn ) ;
std : : tie ( lparams , nparams , intro ) = get_parent_info ( parent_name ) ;
expr intro_type = inductive : : intro_rule_type ( intro ) ;
intro_type = instantiate_univ_params ( intro_type , lparams , const_levels ( parent_fn ) ) ;
if ( nparams ! = args . size ( ) ) {
throw_elaborator_exception ( m_env ,
sstream ( ) < < " invalid 'structure' header, number of argument "
" mismatch for parent structure ' " < < parent_name < < " ' " ,
parent ) ;
}
for ( expr const & arg : args ) {
if ( ! is_pi ( intro_type ) )
throw_ill_formed_parent ( parent_name ) ;
intro_type = instantiate ( binding_body ( intro_type ) , arg ) ;
}
while ( is_pi ( intro_type ) ) {
name fname = binding_name ( intro_type ) ;
fname = rename ( renames , fname ) ;
expr const & ftype = binding_domain ( intro_type ) ;
expr field ;
if ( auto fidx = merge ( parent , fname , ftype , cseq ) ) {
fmap . push_back ( * fidx ) ;
field = m_fields [ * fidx ] ;
if ( local_info ( field ) ! = binding_info ( intro_type ) ) {
throw_elaborator_exception ( m_env ,
sstream ( ) < < " invalid 'structure' header, field ' " < < fname < <
" ' has already been declared with a different binder annotation " ,
parent ) ;
}
} else {
field = mk_local ( fname , ftype , binding_info ( intro_type ) ) ;
fmap . push_back ( m_fields . size ( ) ) ;
m_fields . push_back ( field ) ;
}
intro_type = instantiate ( binding_body ( intro_type ) , field ) ;
}
}
2014-11-04 01:39:52 +00:00
lean_assert ( m_parents . size ( ) = = m_field_maps . size ( ) ) ;
2014-11-03 22:14:40 +00:00
return cseq ;
}
void solve_constraints ( constraint_seq const & cseq ) {
if ( ! cseq )
2014-07-29 02:04:57 +00:00
return ;
2014-11-03 22:14:40 +00:00
buffer < constraint > cs ;
cseq . linearize ( cs ) ;
bool use_exceptions = true ;
bool discard = true ;
unifier_config cfg ( use_exceptions , discard ) ;
unify_result_seq rseq = unify ( m_env , cs . size ( ) , cs . data ( ) , m_ngen . mk_child ( ) , substitution ( ) , cfg ) ;
auto p = rseq . pull ( ) ;
lean_assert ( p ) ;
substitution subst = p - > first . first ;
for ( expr & parent : m_parents )
parent = subst . instantiate ( parent ) ;
for ( expr & param : m_params )
param = subst . instantiate ( param ) ;
for ( expr & field : m_fields )
field = subst . instantiate ( field ) ;
}
/** \brief Parse header, elaborate it, and process parents (aka extends clauses) */
void process_header ( ) {
parse_header ( ) ;
elaborate_header ( ) ;
constraint_seq cseq = process_extends ( ) ;
solve_constraints ( cseq ) ;
}
/** \brief Add params and fields to parser local scope */
void add_locals ( ) {
for ( expr const & param : m_params )
m_p . add_local ( param ) ;
for ( expr const & field : m_fields )
m_p . add_local ( field ) ;
}
/** \brief Check if new field names collide with fields inherited from parent datastructures */
void check_new_field_names ( buffer < expr > const & new_fields ) {
for ( expr const & new_field : new_fields ) {
if ( std : : find_if ( m_fields . begin ( ) , m_fields . end ( ) ,
[ & ] ( expr const & inherited_field ) {
return local_pp_name ( inherited_field ) = = local_pp_name ( new_field ) ;
} ) ! = m_fields . end ( ) ) {
throw_elaborator_exception ( m_env , sstream ( ) < < " field ' " < < local_pp_name ( new_field ) < <
" ' has been declared in parent structure " ,
new_field ) ;
}
}
}
/** \brief Parse new fields declared in this structure */
void parse_new_fields ( buffer < expr > & new_fields ) {
parser : : local_scope scope ( m_p ) ;
add_locals ( ) ;
2014-11-04 06:55:51 +00:00
m_p . parse_optional_binders ( new_fields ) ;
2014-11-03 22:14:40 +00:00
check_new_field_names ( new_fields ) ;
}
2014-11-04 01:39:52 +00:00
2014-11-03 22:14:40 +00:00
/** \brief Elaborate new fields, and copy them to m_fields */
void elaborate_new_fields ( buffer < expr > & new_fields ) {
list < expr > ctx = m_p . locals_to_context ( ) ;
expr dummy = mk_Prop ( ) ;
2014-11-04 01:39:52 +00:00
unsigned j = m_parents . size ( ) ;
while ( j > 0 ) {
- - j ;
dummy = mk_arrow ( mk_as_is ( m_parents [ j ] ) , dummy ) ;
}
expr tmp = Pi_as_is ( m_params , Pi_as_is ( m_fields , Pi ( new_fields , dummy , m_p ) , m_p ) , m_p ) ;
2014-11-03 22:14:40 +00:00
level_param_names new_ls ;
expr new_tmp ;
std : : tie ( new_tmp , new_ls ) = m_p . elaborate_type ( tmp , ctx ) ;
for ( auto new_l : new_ls )
m_level_names . push_back ( new_l ) ;
new_tmp = update_locals ( new_tmp , m_params ) ;
new_tmp = update_locals ( new_tmp , m_fields ) ;
new_tmp = update_locals ( new_tmp , new_fields ) ;
2014-11-04 01:39:52 +00:00
new_tmp = update_parents ( new_tmp ) ;
lean_assert ( new_tmp = = mk_Prop ( ) ) ;
2014-11-03 22:14:40 +00:00
m_fields . append ( new_fields ) ;
}
/** \brief Parse new fields declared by this structure, and elaborate them. */
void process_new_fields ( ) {
buffer < expr > new_fields ;
parse_new_fields ( new_fields ) ;
elaborate_new_fields ( new_fields ) ;
}
2014-11-04 06:17:43 +00:00
void process_empty_new_fields ( ) {
buffer < expr > new_fields ;
elaborate_new_fields ( new_fields ) ;
}
2014-11-03 22:14:40 +00:00
/** \brief Traverse fields and collect the universes they reside in \c r_lvls.
This information is used to compute the resultant universe level for the inductive datatype declaration .
*/
void accumulate_levels ( buffer < level > & r_lvls ) {
for ( expr const & field : m_fields ) {
expr s = m_tc - > ensure_type ( mlocal_type ( field ) ) . first ;
level l = sort_level ( s ) ;
if ( std : : find ( r_lvls . begin ( ) , r_lvls . end ( ) , l ) = = r_lvls . end ( ) ) {
r_lvls . push_back ( l ) ;
}
}
}
/** \brief Compute resultant universe (if it was not provided explicitly) based on the universes
where the fields " reside " */
void infer_resultant_universe ( ) {
if ( m_infer_result_universe ) {
buffer < level > r_lvls ;
accumulate_levels ( r_lvls ) ;
level r_lvl = mk_result_level ( m_env , r_lvls ) ;
m_type = mk_sort ( r_lvl ) ;
}
}
/** \brief Display m_fields (for debugging purposes) */
void display_fields ( std : : ostream & out ) {
for ( expr const & field : m_fields ) {
out < < " >> " < < mlocal_name ( field ) < < " : " < < mlocal_type ( field ) < < " \n " ;
}
}
/** \brief Collect context local constants used in the declaration. */
void collect_ctx_locals ( buffer < expr > & locals ) {
if ( ! m_p . has_locals ( ) )
return ;
expr dummy = mk_Prop ( ) ;
expr tmp = Pi ( m_params , Pi ( m_fields , dummy ) ) ;
expr_struct_set local_set ;
: : lean : : collect_locals ( tmp , local_set ) ;
sort_locals ( local_set , m_p , locals ) ;
}
/** \brief Add context locals as extra parameters */
void add_ctx_locals ( buffer < expr > const & ctx_locals ) {
buffer < expr > params ;
params . append ( m_params ) ;
m_params . clear ( ) ;
m_params . append ( ctx_locals ) ;
m_params . append ( params ) ;
}
/** \brief Include in m_level_names any local level referenced m_type and m_fields */
void include_ctx_levels ( ) {
2014-07-29 02:04:57 +00:00
name_set all_lvl_params ;
all_lvl_params = collect_univ_params ( m_type ) ;
for ( expr const & f : m_fields )
all_lvl_params = collect_univ_params ( mlocal_type ( f ) , all_lvl_params ) ;
buffer < name > section_lvls ;
all_lvl_params . for_each ( [ & ] ( name const & l ) {
if ( std : : find ( m_level_names . begin ( ) , m_level_names . end ( ) , l ) = = m_level_names . end ( ) )
section_lvls . push_back ( l ) ;
} ) ;
std : : sort ( section_lvls . begin ( ) , section_lvls . end ( ) , [ & ] ( name const & n1 , name const & n2 ) {
return m_p . get_local_level_index ( n1 ) < m_p . get_local_level_index ( n2 ) ;
} ) ;
buffer < name > new_levels ;
new_levels . append ( section_lvls ) ;
new_levels . append ( m_level_names ) ;
m_level_names . clear ( ) ;
m_level_names . append ( new_levels ) ;
}
2014-11-03 22:14:40 +00:00
expr mk_structure_type ( ) {
return Pi ( m_params , m_type ) ;
2014-07-29 02:04:57 +00:00
}
2014-11-03 22:14:40 +00:00
expr mk_intro_type ( ) {
levels ls = param_names_to_levels ( to_list ( m_level_names . begin ( ) , m_level_names . end ( ) ) ) ;
expr r = mk_app ( mk_constant ( m_name , ls ) , m_params ) ;
r = Pi ( m_params , Pi ( m_fields , r ) ) ;
return infer_implicit_params ( r , m_params . size ( ) , m_mk_infer ) ;
2014-07-29 02:04:57 +00:00
}
2014-11-03 22:14:40 +00:00
void save_info ( name const & n , name const & k , pos_info const & pos ) {
expr type = m_env . get ( n ) . get_type ( ) ;
m_p . add_decl_index ( n , pos , k , type ) ;
2014-07-29 02:04:57 +00:00
}
2014-11-03 23:50:41 +00:00
void add_alias ( name const & n , bool composite = true ) {
m_env = : : lean : : add_alias ( m_p , m_env , composite , n , m_ctx_levels , m_ctx_locals ) ;
}
void add_rec_alias ( name const & n ) {
bool composite = true ;
m_env = : : lean : : add_alias ( m_p , m_env , composite , n , levels ( mk_level_placeholder ( ) , m_ctx_levels ) , m_ctx_locals ) ;
}
2014-11-03 22:14:40 +00:00
void declare_inductive_type ( ) {
expr structure_type = mk_structure_type ( ) ;
expr intro_type = mk_intro_type ( ) ;
2014-07-29 02:04:57 +00:00
2014-11-03 22:14:40 +00:00
level_param_names lnames = to_list ( m_level_names . begin ( ) , m_level_names . end ( ) ) ;
inductive : : intro_rule intro ( m_mk , intro_type ) ;
inductive : : inductive_decl decl ( m_name , structure_type , to_list ( intro ) ) ;
m_env = module : : add_inductive ( m_env , lnames , m_params . size ( ) , to_list ( decl ) ) ;
save_info ( m_name , " structure " , m_name_pos ) ;
2014-11-03 22:50:12 +00:00
name rec_name = inductive : : get_elim_name ( m_name ) ;
save_info ( rec_name , " recursor " , m_name_pos ) ;
2014-11-03 22:14:40 +00:00
save_info ( m_mk , " intro " , m_mk_pos ) ;
2014-11-03 22:50:12 +00:00
m_env = add_namespace ( m_env , m_name ) ;
m_env = add_protected ( m_env , rec_name ) ;
2014-11-03 23:50:41 +00:00
add_alias ( m_name , false ) ;
add_alias ( m_mk ) ;
add_rec_alias ( rec_name ) ;
2014-11-04 01:46:03 +00:00
if ( m_modifiers . is_class ( ) )
m_env = add_class ( m_env , m_name ) ;
2014-07-29 02:04:57 +00:00
}
2014-11-03 22:14:40 +00:00
void save_def_info ( name const & n ) {
save_info ( n , " definition " , m_name_pos ) ;
2014-07-29 02:04:57 +00:00
}
2014-11-04 01:39:52 +00:00
void save_proj_info ( name const & n ) {
save_info ( n , " projection " , m_name_pos ) ;
}
2014-11-04 02:33:44 +00:00
void save_thm_info ( name const & n ) {
save_info ( n , " theorem " , m_name_pos ) ;
}
2014-11-03 23:50:41 +00:00
void declare_projections ( ) {
m_env = mk_projections ( m_env , m_name , m_modifiers . is_class ( ) ) ;
for ( expr const & field : m_fields ) {
name field_name = m_name + mlocal_name ( field ) ;
2014-11-04 01:39:52 +00:00
save_proj_info ( field_name ) ;
2014-11-03 23:50:41 +00:00
add_alias ( field_name ) ;
}
}
2014-11-15 23:59:49 +00:00
void add_rec_on_alias ( name const & n ) {
bool opaque = false ;
name rec_on_name ( m_name , " rec_on " ) ;
declaration rec_on_decl = m_env . get ( rec_on_name ) ;
declaration new_decl = mk_definition ( m_env , n , rec_on_decl . get_univ_params ( ) ,
rec_on_decl . get_type ( ) , rec_on_decl . get_value ( ) ,
opaque ) ;
m_env = module : : add ( m_env , check ( m_env , new_decl ) ) ;
m_env = set_reducible ( m_env , n , reducible_status : : On ) ;
save_def_info ( n ) ;
add_alias ( n ) ;
}
2014-11-03 22:14:40 +00:00
void declare_auxiliary ( ) {
m_env = mk_rec_on ( m_env , m_name ) ;
2014-11-03 23:50:41 +00:00
name rec_on_name ( m_name , " rec_on " ) ;
add_rec_alias ( rec_on_name ) ;
save_def_info ( rec_on_name ) ;
2014-12-05 22:34:02 +00:00
if ( m_env . impredicative ( ) ) {
m_env = mk_induction_on ( m_env , m_name ) ;
name induction_on_name ( m_name , " induction_on " ) ;
add_rec_alias ( induction_on_name ) ;
save_def_info ( induction_on_name ) ;
}
2014-11-15 23:59:49 +00:00
add_rec_on_alias ( name ( m_name , " destruct " ) ) ;
add_rec_on_alias ( name ( m_name , " cases_on " ) ) ;
2014-07-29 02:04:57 +00:00
}
2014-11-05 23:01:05 +00:00
void get_parent_names ( buffer < name > & parent_names ) {
for ( expr const & parent : m_parents )
parent_names . push_back ( const_name ( get_app_fn ( parent ) ) ) ;
}
void mk_coercion_names ( buffer < name > & coercion_names ) {
buffer < name > parent_names ;
get_parent_names ( parent_names ) ;
name_set found ;
name_map < unsigned > non_unique ;
for ( name const & n : parent_names ) {
if ( found . contains ( n ) )
non_unique . insert ( n , 1 ) ;
found . insert ( n ) ;
}
for ( name & n : parent_names ) {
if ( auto it = non_unique . find ( n ) ) {
unsigned idx = * it ;
non_unique . insert ( n , idx + 1 ) ;
n = n . append_after ( idx ) ;
}
name coercion_name = m_name + n . append_before ( " to_ " ) ;
coercion_names . push_back ( coercion_name ) ;
}
}
2014-11-04 01:39:52 +00:00
void declare_coercions ( ) {
lean_assert ( m_parents . size ( ) = = m_field_maps . size ( ) ) ;
2014-11-05 23:01:05 +00:00
buffer < name > coercion_names ;
mk_coercion_names ( coercion_names ) ;
2014-11-04 01:39:52 +00:00
level_param_names lnames = to_list ( m_level_names . begin ( ) , m_level_names . end ( ) ) ;
levels st_ls = param_names_to_levels ( lnames ) ;
for ( unsigned i = 0 ; i < m_parents . size ( ) ; i + + ) {
expr const & parent = m_parents [ i ] ;
field_map const & fmap = m_field_maps [ i ] ;
buffer < expr > parent_params ;
expr const & parent_fn = get_app_args ( parent , parent_params ) ;
levels const & parent_ls = const_levels ( parent_fn ) ;
name const & parent_name = const_name ( parent_fn ) ;
auto parent_info = get_parent_info ( parent_name ) ;
name const & parent_intro_name = inductive : : intro_rule_name ( std : : get < 2 > ( parent_info ) ) ;
expr parent_intro = mk_app ( mk_constant ( parent_intro_name , parent_ls ) , parent_params ) ;
expr parent_type = m_tc - > infer ( parent ) . first ;
if ( ! is_sort ( parent_type ) )
throw_ill_formed_parent ( parent_name ) ;
level parent_rlvl = sort_level ( parent_type ) ;
expr st_type = mk_app ( mk_constant ( m_name , st_ls ) , m_params ) ;
binder_info bi ;
if ( m_modifiers . is_class ( ) )
bi = mk_inst_implicit_binder_info ( ) ;
expr st = mk_local ( m_ngen . next ( ) , " s " , st_type , bi ) ;
expr coercion_type = infer_implicit ( Pi ( m_params , Pi ( st , parent ) ) , m_params . size ( ) , true ) ; ;
2014-11-04 03:18:10 +00:00
expr coercion_value = parent_intro ;
for ( unsigned idx : fmap ) {
expr const & field = m_fields [ idx ] ;
expr proj = mk_app ( mk_app ( mk_constant ( m_name + mlocal_name ( field ) , st_ls ) , m_params ) , st ) ;
coercion_value = mk_app ( coercion_value , proj ) ;
}
coercion_value = Fun ( m_params , Fun ( st , coercion_value ) ) ;
2014-11-05 23:01:05 +00:00
name coercion_name = coercion_names [ i ] ;
2014-11-04 01:39:52 +00:00
bool opaque = false ;
declaration coercion_decl = mk_definition ( m_env , coercion_name , lnames , coercion_type , coercion_value ,
opaque ) ;
m_env = module : : add ( m_env , check ( m_env , coercion_decl ) ) ;
m_env = set_reducible ( m_env , coercion_name , reducible_status : : On ) ;
save_def_info ( coercion_name ) ;
add_alias ( coercion_name ) ;
2014-11-04 07:15:15 +00:00
if ( ! m_private_parents [ i ] ) {
m_env = add_coercion ( m_env , coercion_name , m_p . ios ( ) ) ;
if ( m_modifiers . is_class ( ) & & is_class ( m_env , parent_name ) ) {
// if both are classes, then we also mark coercion_name as an instance
m_env = add_instance ( m_env , coercion_name ) ;
}
2014-11-04 01:55:59 +00:00
}
2014-11-04 01:39:52 +00:00
}
}
2014-11-04 02:33:44 +00:00
void declare_eta ( ) {
2014-12-09 20:40:09 +00:00
if ( ! m_gen_eta )
return ;
2014-11-04 02:33:44 +00:00
if ( ! has_eq_decls ( m_env ) )
return ;
level_param_names lnames = to_list ( m_level_names . begin ( ) , m_level_names . end ( ) ) ;
levels st_ls = param_names_to_levels ( lnames ) ;
expr st_type = mk_app ( mk_constant ( m_name , st_ls ) , m_params ) ;
expr st = mk_local ( m_ngen . next ( ) , " s " , st_type , binder_info ( ) ) ;
expr lhs = mk_app ( mk_constant ( m_mk , st_ls ) , m_params ) ;
for ( expr const & field : m_fields ) {
expr proj = mk_app ( mk_app ( mk_constant ( m_name + mlocal_name ( field ) , st_ls ) , m_params ) , st ) ;
lhs = mk_app ( lhs , proj ) ;
}
expr eq = mk_app ( mk_constant ( " eq " , to_list ( sort_level ( m_type ) ) ) , st_type , lhs , st ) ;
2014-12-06 17:43:42 +00:00
level eq_lvl = sort_level ( m_tc - > ensure_type ( eq ) . first ) ;
levels rec_ls = levels ( eq_lvl , st_ls ) ;
2014-11-04 02:33:44 +00:00
expr rec = mk_app ( mk_constant ( inductive : : get_elim_name ( m_name ) , rec_ls ) , m_params ) ;
expr type_former = Fun ( st , eq ) ;
expr mk = mk_app ( mk_app ( mk_constant ( m_mk , st_ls ) , m_params ) , m_fields ) ;
expr refl = mk_app ( mk_constant ( name { " eq " , " refl " } , to_list ( sort_level ( m_type ) ) ) , st_type , mk ) ;
refl = Fun ( m_fields , refl ) ;
rec = mk_app ( rec , type_former , refl , st ) ;
expr eta_type = infer_implicit ( Pi ( m_params , Pi ( st , eq ) ) , true ) ;
expr eta_value = Fun ( m_params , Fun ( st , rec ) ) ;
name eta_name ( m_name , " eta " ) ;
declaration eta_decl = mk_theorem ( eta_name , lnames , eta_type , eta_value ) ;
m_env = module : : add ( m_env , check ( m_env , eta_decl ) ) ;
save_thm_info ( eta_name ) ;
add_alias ( eta_name ) ;
}
2014-11-04 17:10:25 +00:00
void declare_proj_over_mk ( ) {
2014-12-09 20:40:09 +00:00
if ( ! m_gen_proj_mk )
return ;
2014-11-04 17:10:25 +00:00
if ( ! has_eq_decls ( m_env ) )
return ;
level_param_names lnames = to_list ( m_level_names . begin ( ) , m_level_names . end ( ) ) ;
levels st_ls = param_names_to_levels ( lnames ) ;
expr st_type = mk_app ( mk_constant ( m_name , st_ls ) , m_params ) ;
expr mk_fields = mk_app ( mk_app ( mk_constant ( m_mk , st_ls ) , m_params ) , m_fields ) ;
for ( unsigned i = 0 ; i < m_fields . size ( ) ; i + + ) {
expr const & field = m_fields [ i ] ;
name const & field_name = mlocal_name ( field ) ;
expr const & field_type = mlocal_type ( field ) ;
2014-12-09 20:40:09 +00:00
if ( m_env . prop_proof_irrel ( ) & & m_tc - > is_prop ( field_type ) . first )
continue ;
2014-11-04 17:10:25 +00:00
level field_level = sort_level ( m_tc - > ensure_type ( field_type ) . first ) ;
name proj_name = m_name + field_name ;
expr lhs = mk_app ( mk_app ( mk_constant ( proj_name , st_ls ) , m_params ) , mk_fields ) ;
expr rhs = field ;
expr eq = mk_app ( mk_constant ( " eq " , to_list ( field_level ) ) , field_type , lhs , rhs ) ;
expr refl = mk_app ( mk_constant ( name { " eq " , " refl " } , to_list ( field_level ) ) , field_type , lhs ) ;
name proj_over_name = m_name + field_name + m_mk_short ;
expr proj_over_type = infer_implicit ( Pi ( m_params , Pi ( m_fields , eq ) ) , m_params . size ( ) , true ) ;
expr proj_over_value = Fun ( m_params , Fun ( m_fields , refl ) ) ;
declaration proj_over_decl = mk_theorem ( proj_over_name , lnames , proj_over_type , proj_over_value ) ;
m_env = module : : add ( m_env , check ( m_env , proj_over_decl ) ) ;
save_thm_info ( proj_over_name ) ;
add_alias ( proj_over_name ) ;
}
}
2014-11-15 23:59:49 +00:00
void declare_no_confustion ( ) {
2014-12-09 06:11:48 +00:00
if ( ! has_eq_decls ( m_env ) )
return ;
if ( m_env . impredicative ( ) & & ! has_heq_decls ( m_env ) )
return ;
if ( ! m_env . impredicative ( ) & & ! has_lift_decls ( m_env ) )
2014-11-15 23:59:49 +00:00
return ;
m_env = mk_no_confusion ( m_env , m_name ) ;
name no_confusion_name ( m_name , " no_confusion " ) ;
save_def_info ( no_confusion_name ) ;
add_alias ( no_confusion_name ) ;
}
2014-07-29 02:04:57 +00:00
environment operator ( ) ( ) {
2014-11-03 22:14:40 +00:00
process_header ( ) ;
2014-11-04 06:17:43 +00:00
if ( m_p . curr_is_token ( get_assign_tk ( ) ) ) {
m_p . check_token_next ( get_assign_tk ( ) , " invalid 'structure', ':=' expected " ) ;
m_mk_pos = m_p . pos ( ) ;
2014-11-04 06:40:08 +00:00
if ( m_p . curr_is_token ( get_lparen_tk ( ) ) | | m_p . curr_is_token ( get_lcurly_tk ( ) ) | | m_p . curr_is_token ( get_lbracket_tk ( ) ) ) {
2014-11-04 17:10:25 +00:00
m_mk_short = LEAN_DEFAULT_STRUCTURE_INTRO ;
2014-11-04 06:40:08 +00:00
m_mk_infer = implicit_infer_kind : : Implicit ;
} else {
2014-11-04 17:10:25 +00:00
m_mk_short = m_p . check_atomic_id_next ( " invalid 'structure', identifier expected " ) ;
2014-11-04 06:40:08 +00:00
m_mk_infer = parse_implicit_infer_modifier ( m_p ) ;
2014-11-04 06:55:51 +00:00
if ( ! m_p . curr_is_command_like ( ) )
m_p . check_token_next ( get_dcolon_tk ( ) , " invalid 'structure', '::' expected " ) ;
2014-11-04 06:40:08 +00:00
}
2014-11-04 17:10:25 +00:00
m_mk = m_name + m_mk_short ;
2014-11-04 06:17:43 +00:00
process_new_fields ( ) ;
} else {
2014-11-04 06:40:08 +00:00
m_mk_pos = m_name_pos ;
2014-11-04 17:10:25 +00:00
m_mk_short = LEAN_DEFAULT_STRUCTURE_INTRO ;
2014-11-04 06:40:08 +00:00
m_mk_infer = implicit_infer_kind : : Implicit ;
2014-11-04 17:10:25 +00:00
m_mk = m_name + m_mk_short ;
2014-11-04 06:17:43 +00:00
process_empty_new_fields ( ) ;
}
2014-11-03 22:14:40 +00:00
infer_resultant_universe ( ) ;
2014-11-03 23:50:41 +00:00
collect_ctx_locals ( m_ctx_locals ) ;
add_ctx_locals ( m_ctx_locals ) ;
2014-11-03 22:14:40 +00:00
include_ctx_levels ( ) ;
2014-11-03 23:50:41 +00:00
m_ctx_levels = collect_local_nonvar_levels ( m_p , to_list ( m_level_names . begin ( ) , m_level_names . end ( ) ) ) ;
2014-11-03 22:14:40 +00:00
declare_inductive_type ( ) ;
declare_projections ( ) ;
declare_auxiliary ( ) ;
2014-11-04 01:39:52 +00:00
declare_coercions ( ) ;
2014-11-04 02:33:44 +00:00
declare_eta ( ) ;
2014-11-04 17:10:25 +00:00
declare_proj_over_mk ( ) ;
2014-11-15 23:59:49 +00:00
declare_no_confustion ( ) ;
2014-07-29 02:04:57 +00:00
return m_env ;
}
} ;
environment structure_cmd ( parser & p ) {
return structure_cmd_fn ( p ) ( ) ;
}
2014-11-05 22:06:54 +00:00
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 ) ;
}
}
2014-07-29 02:04:57 +00:00
void register_structure_cmd ( cmd_table & r ) {
add_cmd ( r , cmd_info ( " structure " , " declare a new structure/record type " , structure_cmd ) ) ;
}
}