2013-08-16 01:54:01 +00:00
/*
Copyright ( c ) 2013 Microsoft Corporation . All rights reserved .
Released under Apache 2.0 license as described in the file LICENSE .
Author : Leonardo de Moura
*/
# include <limits>
# include <memory>
2013-09-13 10:35:29 +00:00
# include <utility>
# include <vector>
2013-09-13 03:04:10 +00:00
# include "util/scoped_map.h"
# include "util/exception.h"
# include "util/scoped_set.h"
# include "util/sexpr/options.h"
# include "util/interruptable_ptr.h"
# include "kernel/context.h"
# include "kernel/for_each.h"
# include "kernel/occurs.h"
# include "kernel/builtin.h"
# include "kernel/free_vars.h"
2013-09-17 02:21:40 +00:00
# include "kernel/replace.h"
2013-09-13 03:04:10 +00:00
# include "library/context_to_lambda.h"
2013-09-13 01:25:38 +00:00
# include "library/placeholder.h"
2013-09-13 03:09:35 +00:00
# include "frontends/lean/notation.h"
# include "frontends/lean/pp.h"
# include "frontends/lean/frontend.h"
# include "frontends/lean/coercion.h"
# include "frontends/lean/elaborator.h"
2013-08-16 01:54:01 +00:00
# ifndef LEAN_DEFAULT_PP_MAX_DEPTH
# define LEAN_DEFAULT_PP_MAX_DEPTH std::numeric_limits<unsigned>::max()
# endif
# ifndef LEAN_DEFAULT_PP_MAX_STEPS
# define LEAN_DEFAULT_PP_MAX_STEPS std::numeric_limits<unsigned>::max()
# endif
2013-09-02 02:08:49 +00:00
# ifndef LEAN_DEFAULT_PP_NOTATION
# define LEAN_DEFAULT_PP_NOTATION true
# endif
2013-08-16 01:54:01 +00:00
# ifndef LEAN_DEFAULT_PP_IMPLICIT
# define LEAN_DEFAULT_PP_IMPLICIT false
# endif
2013-09-02 02:08:49 +00:00
# ifndef LEAN_DEFAULT_PP_COERCION
# define LEAN_DEFAULT_PP_COERCION false
2013-08-16 01:54:01 +00:00
# endif
# ifndef LEAN_DEFAULT_PP_EXTRA_LETS
# define LEAN_DEFAULT_PP_EXTRA_LETS true
# endif
2013-08-19 19:04:40 +00:00
# ifndef LEAN_DEFAULT_PP_ALIAS_MIN_WEIGHT
# define LEAN_DEFAULT_PP_ALIAS_MIN_WEIGHT 20
2013-08-16 01:54:01 +00:00
# endif
namespace lean {
2013-08-17 03:39:24 +00:00
static format g_Type_fmt = highlight_builtin ( format ( " Type " ) ) ;
static format g_eq_fmt = format ( " = " ) ;
2013-08-21 19:42:55 +00:00
static format g_lambda_n_fmt = highlight_keyword ( format ( " \u03BB " ) ) ;
static format g_Pi_n_fmt = highlight_keyword ( format ( " \u03A0 " ) ) ;
static format g_lambda_fmt = highlight_keyword ( format ( " fun " ) ) ;
static format g_Pi_fmt = highlight_keyword ( format ( " Pi " ) ) ;
static format g_arrow_n_fmt = highlight_keyword ( format ( " \u2192 " ) ) ;
static format g_arrow_fmt = highlight_keyword ( format ( " -> " ) ) ;
static format g_forall_n_fmt = highlight_keyword ( format ( " \u2200 " ) ) ;
static format g_exists_n_fmt = highlight_keyword ( format ( " \u2203 " ) ) ;
static format g_forall_fmt = highlight_keyword ( format ( " forall " ) ) ;
static format g_exists_fmt = highlight_keyword ( format ( " exists " ) ) ;
static format g_ellipsis_n_fmt = highlight ( format ( " \u2026 " ) ) ;
static format g_ellipsis_fmt = highlight ( format ( " ... " ) ) ;
2013-08-17 03:39:24 +00:00
static format g_let_fmt = highlight_keyword ( format ( " let " ) ) ;
static format g_in_fmt = highlight_keyword ( format ( " in " ) ) ;
static format g_assign_fmt = highlight_keyword ( format ( " := " ) ) ;
static format g_geq_fmt = format ( " \u2265 " ) ;
2013-08-31 23:46:41 +00:00
static format g_lift_fmt = highlight_keyword ( format ( " lift " ) ) ;
2013-09-17 02:21:40 +00:00
static format g_inst_fmt = highlight_keyword ( format ( " inst " ) ) ;
2013-08-31 23:46:41 +00:00
2013-08-22 17:55:55 +00:00
static name g_pp_max_depth { " lean " , " pp " , " max_depth " } ;
static name g_pp_max_steps { " lean " , " pp " , " max_steps " } ;
static name g_pp_implicit { " lean " , " pp " , " implicit " } ;
static name g_pp_notation { " lean " , " pp " , " notation " } ;
static name g_pp_extra_lets { " lean " , " pp " , " extra_lets " } ;
static name g_pp_alias_min_weight { " lean " , " pp " , " alias_min_weight " } ;
2013-09-02 02:08:49 +00:00
static name g_pp_coercion { " lean " , " pp " , " coercion " } ;
2013-08-21 23:43:59 +00:00
RegisterUnsignedOption ( g_pp_max_depth , LEAN_DEFAULT_PP_MAX_DEPTH , " (lean pretty printer) maximum expression depth, after that it will use ellipsis " ) ;
RegisterUnsignedOption ( g_pp_max_steps , LEAN_DEFAULT_PP_MAX_STEPS , " (lean pretty printer) maximum number of visited expressions, after that it will use ellipsis " ) ;
RegisterBoolOption ( g_pp_implicit , LEAN_DEFAULT_PP_IMPLICIT , " (lean pretty printer) display implicit parameters " ) ;
RegisterBoolOption ( g_pp_notation , LEAN_DEFAULT_PP_NOTATION , " (lean pretty printer) disable/enable notation (infix, mixfix, postfix operators and unicode characters) " ) ;
2013-09-02 02:08:49 +00:00
RegisterBoolOption ( g_pp_coercion , LEAN_DEFAULT_PP_COERCION , " (lean pretty printer) display coercions " ) ;
2013-08-21 23:43:59 +00:00
RegisterBoolOption ( g_pp_extra_lets , LEAN_DEFAULT_PP_EXTRA_LETS , " (lean pretty printer) introduce extra let expressions when displaying shared terms " ) ;
RegisterUnsignedOption ( g_pp_alias_min_weight , LEAN_DEFAULT_PP_ALIAS_MIN_WEIGHT , " (lean pretty printer) mimimal weight (approx. size) of a term to be considered a shared term " ) ;
2013-08-19 19:04:40 +00:00
unsigned get_pp_max_depth ( options const & opts ) { return opts . get_unsigned ( g_pp_max_depth , LEAN_DEFAULT_PP_MAX_DEPTH ) ; }
unsigned get_pp_max_steps ( options const & opts ) { return opts . get_unsigned ( g_pp_max_steps , LEAN_DEFAULT_PP_MAX_STEPS ) ; }
bool get_pp_implicit ( options const & opts ) { return opts . get_bool ( g_pp_implicit , LEAN_DEFAULT_PP_IMPLICIT ) ; }
bool get_pp_notation ( options const & opts ) { return opts . get_bool ( g_pp_notation , LEAN_DEFAULT_PP_NOTATION ) ; }
2013-09-02 02:08:49 +00:00
bool get_pp_coercion ( options const & opts ) { return opts . get_bool ( g_pp_coercion , LEAN_DEFAULT_PP_COERCION ) ; }
2013-08-19 19:04:40 +00:00
bool get_pp_extra_lets ( options const & opts ) { return opts . get_bool ( g_pp_extra_lets , LEAN_DEFAULT_PP_EXTRA_LETS ) ; }
unsigned get_pp_alias_min_weight ( options const & opts ) { return opts . get_unsigned ( g_pp_alias_min_weight , LEAN_DEFAULT_PP_ALIAS_MIN_WEIGHT ) ; }
// =======================================
// Prefixes for naming aliases (auxiliary local decls)
static name g_kappa ( " \u03BA " ) ;
static name g_pho ( " \u03C1 " ) ;
static name g_nu ( " \u03BD " ) ;
// =======================================
2013-08-16 01:54:01 +00:00
2013-08-17 03:39:24 +00:00
/**
2013-08-18 21:29:32 +00:00
\ brief Return a fresh name for the given abstraction or let .
2013-08-30 20:25:12 +00:00
By fresh , we mean a name that is not used for any constant in
2013-08-31 23:46:41 +00:00
abst_body ( e ) .
2013-08-30 20:25:12 +00:00
2013-08-17 03:39:24 +00:00
The resultant name is based on abst_name ( e ) .
*/
2013-08-31 23:46:41 +00:00
name get_unused_name ( expr const & e ) {
2013-08-27 01:46:16 +00:00
lean_assert ( is_abstraction ( e ) | | is_let ( e ) ) ;
2013-08-18 21:29:32 +00:00
name const & n = is_abstraction ( e ) ? abst_name ( e ) : let_name ( e ) ;
2013-08-17 03:39:24 +00:00
name n1 = n ;
unsigned i = 1 ;
2013-08-18 21:29:32 +00:00
expr const & b = is_abstraction ( e ) ? abst_body ( e ) : let_body ( e ) ;
2013-08-31 23:46:41 +00:00
while ( occurs ( n1 , b ) ) {
2013-08-17 03:39:24 +00:00
n1 = name ( n , i ) ;
i + + ;
}
return n1 ;
}
2013-09-17 02:21:40 +00:00
/**
\ brief Replace free variable \ c 0 in \ c a with the name \ c n .
\ remark Metavariable context is ignored .
*/
expr replace_var_with_name ( expr const & a , name const & n ) {
expr c = mk_constant ( n ) ;
auto f = [ = ] ( expr const & m , unsigned offset ) - > expr {
if ( is_var ( m ) ) {
unsigned vidx = var_idx ( m ) ;
if ( vidx > = offset )
return vidx = = offset ? c : mk_var ( vidx - 1 ) ;
}
return m ;
} ;
return replace_fn < decltype ( f ) > ( f ) ( a ) ;
}
2013-08-16 01:54:01 +00:00
/** \brief Functional object for pretty printing expressions */
2013-08-16 16:02:07 +00:00
class pp_fn {
2013-08-16 01:54:01 +00:00
typedef scoped_map < expr , name , expr_hash , expr_eqp > aliases ;
typedef std : : vector < std : : pair < name , format > > aliases_defs ;
2013-08-30 20:25:12 +00:00
typedef scoped_set < name , name_hash , name_eq > local_names ;
2013-08-16 01:54:01 +00:00
frontend const & m_frontend ;
// State
aliases m_aliases ;
aliases_defs m_aliases_defs ;
2013-08-30 20:25:12 +00:00
local_names m_local_names ;
2013-08-16 01:54:01 +00:00
unsigned m_num_steps ;
name m_aux ;
// Configuration
unsigned m_indent ;
unsigned m_max_depth ;
unsigned m_max_steps ;
2013-09-02 02:08:49 +00:00
bool m_implict ; //!< if true show implicit arguments
2013-09-03 17:09:19 +00:00
bool m_unicode ; //!< if true use unicode chars
2013-09-02 02:08:49 +00:00
bool m_coercion ; //!< if true show coercions
2013-08-19 19:04:40 +00:00
bool m_notation ; //!< if true use notation
bool m_extra_lets ; //!< introduce extra let-expression to cope with sharing.
unsigned m_alias_min_weight ; //!< minimal weight for creating an alias
2013-08-24 23:11:35 +00:00
volatile bool m_interrupted ;
2013-08-16 01:54:01 +00:00
// Create a scope for local definitions
struct mk_scope {
pp_fn & m_fn ;
unsigned m_old_size ;
mk_scope ( pp_fn & fn ) : m_fn ( fn ) , m_old_size ( fn . m_aliases_defs . size ( ) ) {
m_fn . m_aliases . push ( ) ;
}
~ mk_scope ( ) {
lean_assert ( m_old_size < = m_fn . m_aliases_defs . size ( ) ) ;
m_fn . m_aliases . pop ( ) ;
m_fn . m_aliases_defs . resize ( m_old_size ) ;
}
} ;
format nest ( unsigned i , format const & f ) { return : : lean : : nest ( i , f ) ; }
typedef std : : pair < format , unsigned > result ;
2013-09-02 20:20:00 +00:00
bool is_coercion ( expr const & e ) {
2013-09-13 19:49:03 +00:00
return is_app ( e ) & & num_args ( e ) = = 2 & & m_frontend . is_coercion ( arg ( e , 0 ) ) ;
2013-09-02 20:20:00 +00:00
}
2013-08-16 01:54:01 +00:00
/**
\ brief Return true iff \ c e is an atomic operation .
*/
bool is_atomic ( expr const & e ) {
switch ( e . kind ( ) ) {
case expr_kind : : Var : case expr_kind : : Constant : case expr_kind : : Value : case expr_kind : : Type :
return true ;
2013-09-13 01:25:38 +00:00
case expr_kind : : MetaVar :
return ! metavar_ctx ( e ) ;
2013-09-02 20:20:00 +00:00
case expr_kind : : App :
if ( ! m_coercion & & is_coercion ( e ) )
2013-09-13 19:49:03 +00:00
return is_atomic ( arg ( e , 1 ) ) ;
2013-09-02 20:20:00 +00:00
else
return false ;
case expr_kind : : Lambda : case expr_kind : : Pi : case expr_kind : : Eq : case expr_kind : : Let :
2013-08-16 01:54:01 +00:00
return false ;
}
return false ;
}
result mk_result ( format const & fmt , unsigned depth ) {
return mk_pair ( fmt , depth ) ;
}
result pp_ellipsis ( ) {
2013-09-03 17:09:19 +00:00
return mk_result ( m_unicode ? g_ellipsis_n_fmt : g_ellipsis_fmt , 1 ) ;
2013-08-16 01:54:01 +00:00
}
result pp_var ( expr const & e ) {
unsigned vidx = var_idx ( e ) ;
return mk_result ( compose ( format ( " # " ) , format ( vidx ) ) , 1 ) ;
}
2013-08-30 20:25:12 +00:00
bool has_implicit_arguments ( name const & n ) const {
return m_frontend . has_implicit_arguments ( n ) & & m_local_names . find ( n ) = = m_local_names . end ( ) ;
}
2013-08-16 01:54:01 +00:00
result pp_constant ( expr const & e ) {
2013-08-27 03:21:05 +00:00
name const & n = const_name ( e ) ;
2013-09-01 00:11:06 +00:00
if ( is_placeholder ( e ) ) {
return mk_result ( format ( " _ " ) , 1 ) ;
2013-08-30 20:25:12 +00:00
} else if ( has_implicit_arguments ( n ) ) {
2013-08-27 03:21:05 +00:00
return mk_result ( format ( m_frontend . get_explicit_version ( n ) ) , 1 ) ;
2013-08-26 17:14:16 +00:00
} else {
2013-08-27 03:21:05 +00:00
return mk_result ( format ( n ) , 1 ) ;
2013-08-26 17:14:16 +00:00
}
2013-08-16 01:54:01 +00:00
}
result pp_value ( expr const & e ) {
2013-09-03 17:09:19 +00:00
return mk_result ( to_value ( e ) . pp ( m_unicode ) , 1 ) ;
2013-08-16 01:54:01 +00:00
}
result pp_type ( expr const & e ) {
if ( e = = Type ( ) ) {
return mk_result ( g_Type_fmt , 1 ) ;
} else {
2013-09-03 17:09:19 +00:00
return mk_result ( format { g_Type_fmt , space ( ) , : : lean : : pp ( ty_level ( e ) , m_unicode ) } , 1 ) ;
2013-08-16 01:54:01 +00:00
}
}
/**
2013-08-19 19:04:40 +00:00
\ brief Pretty print given expression and put parenthesis around
it IF the pp of the expression is not a simple name .
2013-08-16 01:54:01 +00:00
*/
result pp_child_with_paren ( expr const & e , unsigned depth ) {
result r = pp ( e , depth + 1 ) ;
2013-08-19 19:04:40 +00:00
if ( is_name ( r . first ) ) {
// We do not add a parenthis if the format object is just
// a name. This can happen when \c e is a complicated
// expression, but an alias is created for it.
return r ;
} else {
2013-09-04 20:21:57 +00:00
return mk_result ( paren ( r . first ) , r . second ) ;
2013-08-19 19:04:40 +00:00
}
2013-08-16 01:54:01 +00:00
}
/**
\ brief Pretty print given expression and put parenthesis around
it if it is not atomic .
*/
result pp_child ( expr const & e , unsigned depth ) {
if ( is_atomic ( e ) )
return pp ( e , depth + 1 ) ;
else
return pp_child_with_paren ( e , depth ) ;
}
2013-08-19 22:45:40 +00:00
bool is_forall_expr ( expr const & e ) {
return is_app ( e ) & & arg ( e , 0 ) = = mk_forall_fn ( ) & & num_args ( e ) = = 3 ;
}
bool is_exists_expr ( expr const & e ) {
return is_app ( e ) & & arg ( e , 0 ) = = mk_exists_fn ( ) & & num_args ( e ) = = 3 ;
}
bool is_quant_expr ( expr const & e , bool is_forall ) {
return is_forall ? is_forall_expr ( e ) : is_exists_expr ( e ) ;
}
/**
\ brief Collect nested quantifiers , and instantiate
variables with unused names . Store in \ c r the selected names
and associated domains . Return the body of the sequence of
nested quantifiers .
*/
expr collect_nested_quantifiers ( expr const & e , bool is_forall , buffer < std : : pair < name , expr > > & r ) {
lean_assert ( is_quant_expr ( e , is_forall ) ) ;
if ( is_lambda ( arg ( e , 2 ) ) ) {
expr lambda = arg ( e , 2 ) ;
name n1 = get_unused_name ( lambda ) ;
2013-08-30 20:25:12 +00:00
m_local_names . insert ( n1 ) ;
2013-08-19 22:45:40 +00:00
r . push_back ( mk_pair ( n1 , abst_domain ( lambda ) ) ) ;
2013-09-17 02:21:40 +00:00
expr b = replace_var_with_name ( abst_body ( lambda ) , n1 ) ;
2013-08-19 22:45:40 +00:00
if ( is_quant_expr ( b , is_forall ) )
return collect_nested_quantifiers ( b , is_forall , r ) ;
else
return b ;
} else {
// Quantifier is not in normal form. That is, it might be
// (forall t p) or (exists t p) where p is not a lambda
// abstraction
// So, we put it in normal form
// (forall t (fun x : t, p x))
// or
// (exists t (fun x : t, p x))
expr new_body = mk_lambda ( " x " , arg ( e , 1 ) , mk_app ( lift_free_vars ( arg ( e , 2 ) , 1 ) , mk_var ( 0 ) ) ) ;
expr normal_form = mk_app ( arg ( e , 0 ) , arg ( e , 1 ) , new_body ) ;
return collect_nested_quantifiers ( normal_form , is_forall , r ) ;
}
}
2013-08-27 16:45:00 +00:00
/** \brief Auxiliary function for pretty printing exists and
forall formulas */
2013-08-19 22:45:40 +00:00
result pp_quantifier ( expr const & e , unsigned depth , bool is_forall ) {
buffer < std : : pair < name , expr > > nested ;
2013-08-30 20:25:12 +00:00
local_names : : mk_scope mk ( m_local_names ) ;
2013-08-19 22:45:40 +00:00
expr b = collect_nested_quantifiers ( e , is_forall , nested ) ;
2013-08-21 19:42:55 +00:00
format head ;
2013-09-03 17:09:19 +00:00
if ( m_unicode )
2013-08-21 19:42:55 +00:00
head = is_forall ? g_forall_n_fmt : g_exists_n_fmt ;
else
head = is_forall ? g_forall_fmt : g_exists_fmt ;
2013-08-19 22:45:40 +00:00
format sep = comma ( ) ;
expr domain0 = nested [ 0 ] . second ;
2013-09-13 19:25:21 +00:00
// TODO(Leo): the following code is very similar to pp_abstraction
2013-08-19 22:45:40 +00:00
if ( std : : all_of ( nested . begin ( ) + 1 , nested . end ( ) , [ & ] ( std : : pair < name , expr > const & p ) { return p . second = = domain0 ; } ) ) {
// Domain of all binders is the same
format names = pp_bnames ( nested . begin ( ) , nested . end ( ) , false ) ;
result p_domain = pp_scoped_child ( domain0 , depth ) ;
result p_body = pp_scoped_child ( b , depth ) ;
format sig = format { names , space ( ) , colon ( ) , space ( ) , p_domain . first } ;
format r_format = group ( nest ( m_indent , format { head , space ( ) , sig , sep , line ( ) , p_body . first } ) ) ;
return mk_result ( r_format , p_domain . second + p_body . second + 1 ) ;
} else {
auto it = nested . begin ( ) ;
auto end = nested . end ( ) ;
unsigned r_weight = 1 ;
// PP binders in blocks (names ... : type)
bool first = true ;
format bindings ;
while ( it ! = end ) {
auto it2 = it ;
+ + it2 ;
while ( it2 ! = end & & it2 - > second = = it - > second ) {
+ + it2 ;
}
result p_domain = pp_scoped_child ( it - > second , depth ) ;
r_weight + = p_domain . second ;
format block = group ( nest ( m_indent , format { lp ( ) , pp_bnames ( it , it2 , true ) , space ( ) , colon ( ) , space ( ) , p_domain . first , rp ( ) } ) ) ;
if ( first ) {
bindings = block ;
first = false ;
} else {
bindings + = compose ( line ( ) , block ) ;
}
it = it2 ;
}
result p_body = pp_scoped_child ( b , depth ) ;
format r_format = group ( nest ( m_indent , format { head , space ( ) , group ( bindings ) , sep , line ( ) , p_body . first } ) ) ;
return mk_result ( r_format , r_weight + p_body . second ) ;
}
}
result pp_forall ( expr const & e , unsigned depth ) {
return pp_quantifier ( e , depth , true ) ;
}
result pp_exists ( expr const & e , unsigned depth ) {
return pp_quantifier ( e , depth , false ) ;
}
2013-08-30 20:25:12 +00:00
operator_info find_op_for ( expr const & e ) const {
if ( is_constant ( e ) & & m_local_names . find ( const_name ( e ) ) ! = m_local_names . end ( ) )
return operator_info ( ) ;
else
2013-09-03 17:09:19 +00:00
return m_frontend . find_op_for ( e , m_unicode ) ;
2013-08-30 20:25:12 +00:00
}
2013-08-27 16:45:00 +00:00
/**
\ brief Return the operator associated with \ c e .
Return the null operator if there is none .
We say \ c e has an operator associated with it , if :
1 ) \ c e is associated with an operator .
2 ) It is an application , and the function is associated with an
operator .
*/
operator_info get_operator ( expr const & e ) {
2013-08-30 20:25:12 +00:00
operator_info op = find_op_for ( e ) ;
2013-08-27 16:45:00 +00:00
if ( op )
return op ;
else if ( is_app ( e ) )
2013-08-30 20:25:12 +00:00
return find_op_for ( arg ( e , 0 ) ) ;
2013-08-27 16:45:00 +00:00
else
return operator_info ( ) ;
}
/**
\ brief Return the precedence of the given expression
*/
unsigned get_operator_precedence ( expr const & e ) {
2013-08-27 22:59:13 +00:00
operator_info op = get_operator ( e ) ;
if ( op ) {
return op . get_precedence ( ) ;
2013-08-27 16:45:00 +00:00
} else if ( is_eq ( e ) ) {
return g_eq_precedence ;
} else if ( is_arrow ( e ) ) {
return g_arrow_precedence ;
} else {
return 0 ;
}
}
2013-09-02 20:20:00 +00:00
/**
\ brief Return true iff the given expression has the given fixity .
*/
bool has_fixity ( expr const & e , fixity fx ) {
operator_info op = get_operator ( e ) ;
if ( op ) {
return op . get_fixity ( ) = = fx ;
} else if ( is_eq ( e ) ) {
return fixity : : Infix = = fx ;
} else if ( is_arrow ( e ) ) {
return fixity : : Infixr = = fx ;
} else {
return false ;
}
}
2013-08-27 16:45:00 +00:00
/**
\ brief Pretty print the child of an infix , prefix , postfix or
mixfix operator . It will add parethesis when needed .
*/
result pp_mixfix_child ( operator_info const & op , expr const & e , unsigned depth ) {
if ( is_atomic ( e ) ) {
return pp ( e , depth + 1 ) ;
} else {
if ( op . get_precedence ( ) < get_operator_precedence ( e ) )
return pp ( e , depth + 1 ) ;
else
return pp_child_with_paren ( e , depth ) ;
}
}
/**
\ brief Pretty print the child of an associative infix
operator . It will add parethesis when needed .
*/
2013-09-02 20:20:00 +00:00
result pp_infix_child ( operator_info const & op , expr const & e , unsigned depth , fixity fx ) {
2013-08-27 16:45:00 +00:00
if ( is_atomic ( e ) ) {
return pp ( e , depth + 1 ) ;
} else {
2013-09-02 20:20:00 +00:00
unsigned e_prec = get_operator_precedence ( e ) ;
if ( op . get_precedence ( ) < e_prec )
return pp ( e , depth + 1 ) ;
else if ( op . get_precedence ( ) = = e_prec & & has_fixity ( e , fx ) )
2013-08-27 16:45:00 +00:00
return pp ( e , depth + 1 ) ;
else
return pp_child_with_paren ( e , depth ) ;
}
}
result mk_infix ( operator_info const & op , result const & lhs , result const & rhs ) {
unsigned r_weight = lhs . second + rhs . second + 1 ;
format r_format = group ( format { lhs . first , space ( ) , format ( op . get_op_name ( ) ) , line ( ) , rhs . first } ) ;
return mk_result ( r_format , r_weight ) ;
}
/**
\ brief Wrapper for accessing the explicit arguments of an
application and its function .
\ remark If show_implicit is true , then we show the explicit
arguments even if the function has implicit arguments .
\ remark We also show the implicit arguments , if the
application does not have the necessary number of
arguments .
\ remark When we expose the implicit arguments , we use the
explicit version of the function . So , the user can
understand the pretty printed term .
*/
struct application {
expr const & m_app ;
expr m_f ;
std : : vector < bool > const * m_implicit_args ;
bool m_notation_enabled ;
2013-08-30 20:25:12 +00:00
application ( expr const & e , pp_fn const & owner , bool show_implicit ) : m_app ( e ) {
frontend const & fe = owner . m_frontend ;
2013-09-13 19:49:03 +00:00
expr const & f = arg ( e , 0 ) ;
2013-08-30 20:25:12 +00:00
if ( is_constant ( f ) & & owner . has_implicit_arguments ( const_name ( f ) ) ) {
2013-08-27 16:45:00 +00:00
m_implicit_args = & ( fe . get_implicit_arguments ( const_name ( f ) ) ) ;
if ( show_implicit | | num_args ( e ) - 1 < m_implicit_args - > size ( ) ) {
// we are showing implicit arguments, thus we do
// not need the bit-mask for implicit arguments
m_implicit_args = nullptr ;
// we use the explicit name of f, to make it clear
// that we are exposing implicit arguments
m_f = mk_constant ( fe . get_explicit_version ( const_name ( f ) ) ) ;
m_notation_enabled = false ;
} else {
m_f = f ;
m_notation_enabled = true ;
}
} else {
m_f = f ;
m_implicit_args = nullptr ;
m_notation_enabled = true ;
}
}
unsigned get_num_args ( ) const {
if ( m_implicit_args ) {
unsigned r = 0 ;
for ( unsigned i = 0 ; i < num_args ( m_app ) - 1 ; i + + ) {
2013-09-10 20:50:35 +00:00
// Remark: we need the test i >= m_implicit_args because the application
// m_app may contain more arguments than the declaration of m_f.
// Example:
// m_f was declared as
// Pi {A : Type} (a : A) : A
// Thus m_implicit_args has size 2, and contains {true, false}
// indicating that the first argument is implicit.
// Then, the actuall application is:
// f (Int -> Int) g 10
// Assuming g has type Int -> Int.
// This application is fine and has type Int.
// We should not print the argument (Int -> Int) since it is
// implicit.
// We should view the application above as:
// (f (Int -> Int) g) 10
// So, the arguments at position >= m_implicit_args->size()
// are explicit by default.
if ( i > = m_implicit_args - > size ( ) | | ! ( * m_implicit_args ) [ i ] )
2013-08-27 16:45:00 +00:00
r + + ;
}
return r ;
} else {
return num_args ( m_app ) - 1 ;
}
}
expr const & get_arg ( unsigned i ) const {
lean_assert ( i < get_num_args ( ) ) ;
if ( m_implicit_args ) {
unsigned n = num_args ( m_app ) ;
for ( unsigned j = 1 ; j < n ; j + + ) {
2013-09-10 20:50:35 +00:00
// See comment in get_num_args()
if ( j - 1 > = m_implicit_args - > size ( ) | | ! ( * m_implicit_args ) [ j - 1 ] ) {
2013-08-27 16:45:00 +00:00
// explicit argument found
if ( i = = 0 )
return arg ( m_app , j ) ;
- - i ;
}
}
lean_unreachable ( ) ;
} else {
return arg ( m_app , i + 1 ) ;
}
}
expr const & get_function ( ) const {
return m_f ;
}
bool notation_enabled ( ) const {
return m_notation_enabled ;
}
} ;
/** \brief Return true if the application \c app has the number of arguments expected by the operator \c op. */
bool has_expected_num_args ( application const & app , operator_info const & op ) {
switch ( op . get_fixity ( ) ) {
case fixity : : Infix : case fixity : : Infixl : case fixity : : Infixr :
return app . get_num_args ( ) = = 2 ;
case fixity : : Prefix : case fixity : : Postfix :
return app . get_num_args ( ) = = 1 ;
case fixity : : Mixfixl : case fixity : : Mixfixr :
return app . get_num_args ( ) = = length ( op . get_op_name_parts ( ) ) ;
2013-08-27 17:09:46 +00:00
case fixity : : Mixfixc :
return app . get_num_args ( ) = = length ( op . get_op_name_parts ( ) ) - 1 ;
case fixity : : Mixfixo :
return app . get_num_args ( ) = = length ( op . get_op_name_parts ( ) ) + 1 ;
2013-08-27 16:45:00 +00:00
}
lean_unreachable ( ) ;
}
2013-08-16 01:54:01 +00:00
/**
\ brief Pretty print an application .
*/
result pp_app ( expr const & e , unsigned depth ) {
2013-09-02 20:20:00 +00:00
if ( ! m_coercion & & is_coercion ( e ) )
2013-09-13 19:49:03 +00:00
return pp ( arg ( e , 1 ) , depth ) ;
2013-08-30 20:25:12 +00:00
application app ( e , * this , m_implict ) ;
2013-08-16 01:54:01 +00:00
operator_info op ;
2013-08-27 16:45:00 +00:00
if ( m_notation & & app . notation_enabled ( ) & & ( op = get_operator ( e ) ) & & has_expected_num_args ( app , op ) ) {
2013-08-16 01:54:01 +00:00
result p_arg ;
format r_format ;
unsigned sz ;
2013-08-19 19:04:40 +00:00
unsigned r_weight = 1 ;
2013-08-16 01:54:01 +00:00
switch ( op . get_fixity ( ) ) {
case fixity : : Infix :
2013-08-27 16:45:00 +00:00
return mk_infix ( op , pp_mixfix_child ( op , app . get_arg ( 0 ) , depth ) , pp_mixfix_child ( op , app . get_arg ( 1 ) , depth ) ) ;
2013-08-16 01:54:01 +00:00
case fixity : : Infixr :
2013-09-02 20:20:00 +00:00
return mk_infix ( op , pp_mixfix_child ( op , app . get_arg ( 0 ) , depth ) , pp_infix_child ( op , app . get_arg ( 1 ) , depth , fixity : : Infixr ) ) ;
2013-08-16 01:54:01 +00:00
case fixity : : Infixl :
2013-09-02 20:20:00 +00:00
return mk_infix ( op , pp_infix_child ( op , app . get_arg ( 0 ) , depth , fixity : : Infixl ) , pp_mixfix_child ( op , app . get_arg ( 1 ) , depth ) ) ;
2013-08-16 01:54:01 +00:00
case fixity : : Prefix :
2013-09-02 20:20:00 +00:00
p_arg = pp_infix_child ( op , app . get_arg ( 0 ) , depth , fixity : : Prefix ) ;
2013-08-16 01:54:01 +00:00
sz = op . get_op_name ( ) . size ( ) ;
return mk_result ( group ( format { format ( op . get_op_name ( ) ) , nest ( sz + 1 , format { line ( ) , p_arg . first } ) } ) ,
p_arg . second + 1 ) ;
case fixity : : Postfix :
2013-08-27 16:45:00 +00:00
p_arg = pp_mixfix_child ( op , app . get_arg ( 0 ) , depth ) ;
2013-08-16 01:54:01 +00:00
return mk_result ( group ( format { p_arg . first , space ( ) , format ( op . get_op_name ( ) ) } ) ,
p_arg . second + 1 ) ;
2013-08-27 17:09:46 +00:00
case fixity : : Mixfixr : case fixity : : Mixfixo : {
2013-08-16 01:54:01 +00:00
// _ ID ... _ ID
2013-08-27 17:09:46 +00:00
// _ ID ... _ ID _
2013-08-16 01:54:01 +00:00
list < name > parts = op . get_op_name_parts ( ) ;
auto it = parts . begin ( ) ;
2013-08-27 16:45:00 +00:00
unsigned num = app . get_num_args ( ) ;
for ( unsigned i = 0 ; i < num ; i + + ) {
result p_arg = pp_mixfix_child ( op , app . get_arg ( i ) , depth ) ;
2013-08-27 17:09:46 +00:00
if ( i = = num - 1 ) {
if ( op . get_fixity ( ) = = fixity : : Mixfixo )
r_format + = p_arg . first ;
else
r_format + = format { p_arg . first , space ( ) , format ( * it ) } ;
} else {
r_format + = format { p_arg . first , space ( ) , format ( * it ) , line ( ) } ;
2013-08-27 22:59:13 +00:00
+ + it ;
2013-08-27 17:09:46 +00:00
}
2013-08-19 19:04:40 +00:00
r_weight + = p_arg . second ;
2013-08-16 01:54:01 +00:00
}
2013-08-19 19:04:40 +00:00
return mk_result ( group ( r_format ) , r_weight ) ;
2013-08-16 01:54:01 +00:00
}
case fixity : : Mixfixl : case fixity : : Mixfixc : {
// ID _ ... _
// ID _ ... _ ID
list < name > parts = op . get_op_name_parts ( ) ;
auto it = parts . begin ( ) ;
2013-08-27 16:45:00 +00:00
unsigned num = app . get_num_args ( ) ;
for ( unsigned i = 0 ; i < num ; i + + ) {
result p_arg = pp_mixfix_child ( op , app . get_arg ( i ) , depth ) ;
2013-08-17 18:31:36 +00:00
unsigned sz = it - > size ( ) ;
2013-08-27 22:59:13 +00:00
if ( i > 0 ) r_format + = space ( ) ;
2013-08-16 01:54:01 +00:00
r_format + = format { format ( * it ) , nest ( sz + 1 , format { line ( ) , p_arg . first } ) } ;
2013-08-19 19:04:40 +00:00
r_weight + = p_arg . second ;
2013-08-16 01:54:01 +00:00
+ + it ;
}
if ( it ! = parts . end ( ) ) {
// it is Mixfixc
r_format + = format { space ( ) , format ( * it ) } ;
}
2013-08-19 19:04:40 +00:00
return mk_result ( group ( r_format ) , r_weight ) ;
2013-08-16 01:54:01 +00:00
} }
lean_unreachable ( ) ;
2013-08-19 22:45:40 +00:00
} else if ( m_notation & & is_forall_expr ( e ) ) {
return pp_forall ( e , depth ) ;
} else if ( m_notation & & is_exists_expr ( e ) ) {
return pp_exists ( e , depth ) ;
2013-08-16 01:54:01 +00:00
} else {
// standard function application
2013-08-27 16:45:00 +00:00
expr const & f = app . get_function ( ) ;
2013-09-13 01:25:38 +00:00
result p = is_constant ( f ) ? mk_result ( format ( const_name ( f ) ) , 1 ) : pp_child ( f , depth ) ;
bool simple = is_constant ( f ) & & const_name ( f ) . size ( ) < = m_indent + 4 ;
2013-08-27 16:45:00 +00:00
unsigned indent = simple ? const_name ( f ) . size ( ) + 1 : m_indent ;
format r_format = p . first ;
unsigned r_weight = p . second ;
unsigned num = app . get_num_args ( ) ;
for ( unsigned i = 0 ; i < num ; i + + ) {
result p_arg = pp_child ( app . get_arg ( i ) , depth ) ;
r_format + = format { i = = 0 & & simple ? space ( ) : line ( ) , p_arg . first } ;
r_weight + = p_arg . second ;
2013-08-16 01:54:01 +00:00
}
2013-08-19 19:04:40 +00:00
return mk_result ( group ( nest ( indent , r_format ) ) , r_weight ) ;
2013-08-16 01:54:01 +00:00
}
}
/**
\ brief Collect nested Lambdas ( or Pis ) , and instantiate
variables with unused names . Store in \ c r the selected names
and associated domains . Return the body of the sequence of
Lambda ( of Pis ) .
2013-08-16 02:56:29 +00:00
\ remark The argument B is only relevant when processing
condensed definitions . \ see pp_abstraction_core .
2013-08-16 01:54:01 +00:00
*/
2013-08-16 03:10:00 +00:00
std : : pair < expr , expr > collect_nested ( expr const & e , expr T , expr_kind k , buffer < std : : pair < name , expr > > & r ) {
2013-08-20 15:09:39 +00:00
if ( e . kind ( ) = = k & & ( ! T | | is_abstraction ( T ) ) ) {
2013-08-17 03:39:24 +00:00
name n1 = get_unused_name ( e ) ;
2013-08-30 20:25:12 +00:00
m_local_names . insert ( n1 ) ;
2013-08-16 01:54:01 +00:00
r . push_back ( mk_pair ( n1 , abst_domain ( e ) ) ) ;
2013-09-17 02:21:40 +00:00
expr b = replace_var_with_name ( abst_body ( e ) , n1 ) ;
2013-08-16 03:10:00 +00:00
if ( T )
2013-09-17 02:21:40 +00:00
T = replace_var_with_name ( abst_body ( T ) , n1 ) ;
2013-08-16 03:10:00 +00:00
return collect_nested ( b , T , k , r ) ;
2013-08-16 01:54:01 +00:00
} else {
2013-08-16 03:10:00 +00:00
return mk_pair ( e , T ) ;
2013-08-16 01:54:01 +00:00
}
}
2013-09-08 18:04:07 +00:00
result pp_scoped_child ( expr const & e , unsigned depth , unsigned prec = 0 ) {
2013-08-16 01:54:01 +00:00
if ( is_atomic ( e ) ) {
2013-08-19 19:04:40 +00:00
return pp ( e , depth + 1 , true ) ;
2013-08-16 01:54:01 +00:00
} else {
mk_scope s ( * this ) ;
2013-08-19 19:04:40 +00:00
result r = pp ( e , depth + 1 , true ) ;
if ( m_aliases_defs . size ( ) = = s . m_old_size ) {
2013-09-08 18:04:07 +00:00
if ( prec < = get_operator_precedence ( e ) )
return r ;
else
return mk_result ( paren ( r . first ) , r . second ) ;
2013-08-19 19:04:40 +00:00
} else {
format r_format = g_let_fmt ;
unsigned r_weight = 2 ;
unsigned begin = s . m_old_size ;
unsigned end = m_aliases_defs . size ( ) ;
for ( unsigned i = begin ; i < end ; i + + ) {
auto b = m_aliases_defs [ i ] ;
name const & n = b . first ;
format beg = i = = begin ? space ( ) : line ( ) ;
format sep = i < end - 1 ? comma ( ) : format ( ) ;
r_format + = nest ( 3 + 1 , format { beg , format ( n ) , space ( ) , g_assign_fmt , nest ( n . size ( ) + 1 + 2 + 1 , format { space ( ) , b . second , sep } ) } ) ;
// we do not store the alias definitin real weight. We know it is at least m_alias_min_weight
r_weight + = m_alias_min_weight + 1 ;
}
r_format + = format { line ( ) , g_in_fmt , space ( ) , nest ( 2 + 1 , r . first ) } ;
r_weight + = r . second ;
return mk_pair ( group ( r_format ) , r_weight ) ;
}
2013-08-16 01:54:01 +00:00
}
}
2013-09-08 18:04:07 +00:00
result pp_arrow_child ( expr const & e , unsigned depth ) {
return pp_scoped_child ( e , depth , g_arrow_precedence + 1 ) ;
}
2013-08-16 01:54:01 +00:00
result pp_arrow_body ( expr const & e , unsigned depth ) {
2013-09-08 18:04:07 +00:00
return pp_scoped_child ( e , depth , g_arrow_precedence ) ;
2013-08-16 01:54:01 +00:00
}
template < typename It >
format pp_bnames ( It const & begin , It const & end , bool use_line ) {
auto it = begin ;
format r = format ( it - > first ) ;
+ + it ;
for ( ; it ! = end ; + + it ) {
r + = compose ( use_line ? line ( ) : space ( ) , format ( it - > first ) ) ;
}
return r ;
}
2013-08-27 03:21:05 +00:00
bool is_implicit ( std : : vector < bool > const * implicit_args , unsigned arg_pos ) {
return implicit_args & & ( * implicit_args ) [ arg_pos ] ;
2013-08-27 01:46:16 +00:00
}
2013-09-08 18:04:07 +00:00
/**
\ brief Auxiliary method for computing where Pi can be pretty printed as an arrow .
Examples :
Pi x : Int , Pi y : Int , Int = = = > return 0
Pi A : Type , Pi x : A , Pi y : A , A = = = > return 1
Pi A : Type , Pi x : Int , A = = = > return 1
Pi A : Type , Pi x : Int , x > 0 = = = > return UINT_MAX ( there is no tail that can be printed as a arrow )
If \ c e is not Pi , it returns UINT_MAX
*/
unsigned get_arrow_starting_at ( expr e ) {
if ( ! is_pi ( e ) )
return std : : numeric_limits < unsigned > : : max ( ) ;
unsigned pos = 0 ;
while ( is_pi ( e ) ) {
expr e2 = abst_body ( e ) ;
unsigned num_vars = 1 ;
bool ok = true ;
while ( true ) {
if ( has_free_var ( e2 , 0 , num_vars ) ) {
ok = false ;
break ;
}
if ( is_pi ( e2 ) ) {
e2 = abst_body ( e2 ) ;
} else {
break ;
}
}
if ( ok ) {
return pos ;
}
e = abst_body ( e ) ;
pos + + ;
}
return std : : numeric_limits < unsigned > : : max ( ) ;
}
2013-08-16 02:56:29 +00:00
/**
\ brief Pretty print Lambdas , Pis and compact definitions .
2013-08-16 03:10:00 +00:00
When T ! = 0 , it is a compact definition .
2013-08-16 02:56:29 +00:00
A compact definition is of the form
2013-08-16 03:10:00 +00:00
Defintion Name Pi ( x : A ) , B : = Lambda ( x : A ) , C
2013-08-16 02:56:29 +00:00
it is printed as
2013-08-16 03:10:00 +00:00
Defintion Name ( x : A ) : B : = C
2013-08-16 02:56:29 +00:00
This method only generates the
2013-08-16 03:10:00 +00:00
( x : A ) : B : = C
2013-08-16 02:56:29 +00:00
for compact definitions .
2013-08-16 03:10:00 +00:00
\ remark if T ! = 0 , then T is Pi ( x : A ) , B
2013-08-16 02:56:29 +00:00
*/
2013-08-27 03:21:05 +00:00
result pp_abstraction_core ( expr const & e , unsigned depth , expr T , std : : vector < bool > const * implicit_args = nullptr ) {
2013-08-30 20:25:12 +00:00
local_names : : mk_scope mk ( m_local_names ) ;
2013-08-27 01:46:16 +00:00
if ( is_arrow ( e ) & & ! implicit_args ) {
2013-08-16 03:10:00 +00:00
lean_assert ( ! T ) ;
2013-09-08 18:04:07 +00:00
result p_lhs = pp_arrow_child ( abst_domain ( e ) , depth ) ;
2013-08-16 01:54:01 +00:00
result p_rhs = pp_arrow_body ( abst_body ( e ) , depth ) ;
2013-09-03 17:09:19 +00:00
format r_format = group ( format { p_lhs . first , space ( ) , m_unicode ? g_arrow_n_fmt : g_arrow_fmt , line ( ) , p_rhs . first } ) ;
2013-08-19 19:04:40 +00:00
return mk_result ( r_format , p_lhs . second + p_rhs . second + 1 ) ;
2013-08-16 01:54:01 +00:00
} else {
2013-09-08 18:04:07 +00:00
unsigned arrow_starting_at = get_arrow_starting_at ( e ) ;
2013-08-16 01:54:01 +00:00
buffer < std : : pair < name , expr > > nested ;
2013-08-16 03:10:00 +00:00
auto p = collect_nested ( e , T , e . kind ( ) , nested ) ;
2013-08-16 02:56:29 +00:00
expr b = p . first ;
2013-08-16 03:10:00 +00:00
T = p . second ;
2013-08-21 21:13:01 +00:00
unsigned head_indent = m_indent ;
2013-08-16 02:56:29 +00:00
format head ;
2013-08-27 01:46:16 +00:00
if ( ! T & & ! implicit_args ) {
2013-09-03 17:09:19 +00:00
if ( m_unicode ) {
2013-08-21 19:42:55 +00:00
head = is_lambda ( e ) ? g_lambda_n_fmt : g_Pi_n_fmt ;
2013-08-21 21:13:01 +00:00
head_indent = 2 ;
} else {
2013-08-21 19:42:55 +00:00
head = is_lambda ( e ) ? g_lambda_fmt : g_Pi_fmt ;
2013-08-21 21:13:01 +00:00
head_indent = is_lambda ( e ) ? 4 : 3 ;
}
2013-08-16 02:56:29 +00:00
}
format body_sep ;
2013-08-16 03:10:00 +00:00
if ( T ) {
format T_f = pp ( T , 0 ) . first ;
2013-08-17 03:39:24 +00:00
body_sep = format { space ( ) , colon ( ) , space ( ) , T_f , space ( ) , g_assign_fmt } ;
2013-08-27 01:46:16 +00:00
} else if ( implicit_args ) {
// This is a little hack to pretty print Variable and
// Axiom declarations that contain implicit arguments
body_sep = compose ( space ( ) , colon ( ) ) ;
2013-08-16 02:56:29 +00:00
} else {
body_sep = comma ( ) ;
}
2013-08-16 01:54:01 +00:00
expr domain0 = nested [ 0 ] . second ;
2013-08-27 01:46:16 +00:00
if ( std : : all_of ( nested . begin ( ) + 1 , nested . end ( ) , [ & ] ( std : : pair < name , expr > const & p ) { return p . second = = domain0 ; } ) & & ! implicit_args ) {
2013-08-16 01:54:01 +00:00
// Domain of all binders is the same
format names = pp_bnames ( nested . begin ( ) , nested . end ( ) , false ) ;
result p_domain = pp_scoped_child ( domain0 , depth ) ;
result p_body = pp_scoped_child ( b , depth ) ;
2013-08-16 02:56:29 +00:00
format sig = format { names , space ( ) , colon ( ) , space ( ) , p_domain . first } ;
2013-08-16 03:10:00 +00:00
if ( T )
2013-08-16 02:56:29 +00:00
sig = format { lp ( ) , sig , rp ( ) } ;
2013-08-21 21:13:01 +00:00
format r_format = group ( nest ( head_indent , format { head , space ( ) , sig , body_sep , line ( ) , p_body . first } ) ) ;
2013-08-19 19:04:40 +00:00
return mk_result ( r_format , p_domain . second + p_body . second + 1 ) ;
2013-08-16 01:54:01 +00:00
} else {
auto it = nested . begin ( ) ;
auto end = nested . end ( ) ;
2013-08-19 19:04:40 +00:00
unsigned r_weight = 1 ;
2013-08-27 01:46:16 +00:00
unsigned arg_pos = 0 ;
2013-08-16 01:54:01 +00:00
// PP binders in blocks (names ... : type)
bool first = true ;
format bindings ;
while ( it ! = end ) {
auto it2 = it ;
+ + it2 ;
2013-08-27 01:46:16 +00:00
bool implicit = is_implicit ( implicit_args , arg_pos ) ;
+ + arg_pos ;
2013-09-08 18:23:46 +00:00
if ( ! implicit_args & & arg_pos > arrow_starting_at ) {
// The rest is an arrow
// We do not use arrow pp when implicit_args marks are used.
format block ;
bool first_domain = true ;
for ( ; it ! = end ; + + it ) {
result p_domain = pp_arrow_child ( it - > second , depth ) ;
r_weight + = p_domain . second ;
if ( first_domain ) {
first_domain = false ;
block = p_domain . first ;
} else {
block + = format { space ( ) , m_unicode ? g_arrow_n_fmt : g_arrow_fmt , line ( ) , p_domain . first } ;
2013-09-08 18:04:07 +00:00
}
}
2013-09-08 18:23:46 +00:00
result p_body = pp_arrow_child ( b , depth ) ;
r_weight + = p_body . second ;
block + = format { space ( ) , m_unicode ? g_arrow_n_fmt : g_arrow_fmt , line ( ) , p_body . first } ;
block = group ( block ) ;
format r_format = group ( nest ( head_indent , format { head , space ( ) , group ( bindings ) , body_sep , line ( ) , block } ) ) ;
return mk_result ( r_format , r_weight ) ;
2013-09-08 18:04:07 +00:00
}
// Continue with standard encoding
2013-08-27 01:46:16 +00:00
while ( it2 ! = end & & it2 - > second = = it - > second & & implicit = = is_implicit ( implicit_args , arg_pos ) ) {
2013-08-16 01:54:01 +00:00
+ + it2 ;
2013-08-27 01:46:16 +00:00
+ + arg_pos ;
2013-08-16 01:54:01 +00:00
}
result p_domain = pp_scoped_child ( it - > second , depth ) ;
2013-08-19 19:04:40 +00:00
r_weight + = p_domain . second ;
2013-08-27 01:46:16 +00:00
format const & par_open = implicit ? lcurly ( ) : lp ( ) ;
format const & par_close = implicit ? rcurly ( ) : rp ( ) ;
format block = group ( nest ( m_indent , format { par_open , pp_bnames ( it , it2 , true ) , space ( ) , colon ( ) , space ( ) , p_domain . first , par_close } ) ) ;
2013-08-16 01:54:01 +00:00
if ( first ) {
bindings = block ;
first = false ;
} else {
bindings + = compose ( line ( ) , block ) ;
}
it = it2 ;
}
result p_body = pp_scoped_child ( b , depth ) ;
2013-08-21 21:13:01 +00:00
format r_format = group ( nest ( head_indent , format { head , space ( ) , group ( bindings ) , body_sep , line ( ) , p_body . first } ) ) ;
2013-08-19 19:04:40 +00:00
return mk_result ( r_format , r_weight + p_body . second ) ;
2013-08-16 01:54:01 +00:00
}
}
}
2013-08-16 02:56:29 +00:00
result pp_abstraction ( expr const & e , unsigned depth ) {
return pp_abstraction_core ( e , depth , expr ( ) ) ;
}
2013-09-06 17:06:26 +00:00
expr collect_nested_let ( expr const & e , buffer < std : : tuple < name , expr , expr > > & bindings ) {
2013-08-18 21:29:32 +00:00
if ( is_let ( e ) ) {
name n1 = get_unused_name ( e ) ;
2013-08-30 20:25:12 +00:00
m_local_names . insert ( n1 ) ;
2013-09-06 17:06:26 +00:00
bindings . push_back ( std : : make_tuple ( n1 , let_type ( e ) , let_value ( e ) ) ) ;
2013-09-17 02:21:40 +00:00
expr b = replace_var_with_name ( let_body ( e ) , n1 ) ;
2013-08-18 21:29:32 +00:00
return collect_nested_let ( b , bindings ) ;
} else {
return e ;
}
}
2013-08-16 01:54:01 +00:00
result pp_let ( expr const & e , unsigned depth ) {
2013-08-30 20:25:12 +00:00
local_names : : mk_scope mk ( m_local_names ) ;
2013-09-06 17:06:26 +00:00
buffer < std : : tuple < name , expr , expr > > bindings ;
2013-08-18 21:29:32 +00:00
expr body = collect_nested_let ( e , bindings ) ;
2013-08-19 19:04:40 +00:00
unsigned r_weight = 2 ;
2013-08-18 21:29:32 +00:00
format r_format = g_let_fmt ;
unsigned sz = bindings . size ( ) ;
for ( unsigned i = 0 ; i < sz ; i + + ) {
auto b = bindings [ i ] ;
2013-09-06 17:06:26 +00:00
name const & n = std : : get < 0 > ( b ) ;
2013-08-18 21:29:32 +00:00
format beg = i = = 0 ? space ( ) : line ( ) ;
format sep = i < sz - 1 ? comma ( ) : format ( ) ;
2013-09-06 17:06:26 +00:00
result p_def = pp ( std : : get < 2 > ( b ) , depth + 1 ) ;
expr type = std : : get < 1 > ( b ) ;
if ( type ) {
result p_type = pp ( type , depth + 1 ) ;
r_format + = nest ( 3 + 1 , compose ( beg , group ( format { format ( n ) , space ( ) ,
colon ( ) , nest ( n . size ( ) + 1 + 1 + 1 , compose ( space ( ) , p_type . first ) ) , space ( ) , g_assign_fmt ,
nest ( m_indent , format { line ( ) , p_def . first , sep } ) } ) ) ) ;
r_weight + = p_type . second + p_def . second ;
} else {
r_format + = nest ( 3 + 1 , format { beg , format ( n ) , space ( ) , g_assign_fmt , nest ( n . size ( ) + 1 + 2 + 1 , format { space ( ) , p_def . first , sep } ) } ) ;
r_weight + = p_def . second ;
}
2013-08-18 21:29:32 +00:00
}
result p_body = pp ( body , depth + 1 ) ;
2013-08-19 19:04:40 +00:00
r_weight + = p_body . second ;
2013-08-18 21:29:32 +00:00
r_format + = format { line ( ) , g_in_fmt , space ( ) , nest ( 2 + 1 , p_body . first ) } ;
2013-08-19 19:04:40 +00:00
return mk_pair ( group ( r_format ) , r_weight ) ;
2013-08-16 01:54:01 +00:00
}
/** \brief Pretty print the child of an equality. */
result pp_eq_child ( expr const & e , unsigned depth ) {
if ( is_atomic ( e ) ) {
return pp ( e , depth + 1 ) ;
} else {
2013-08-19 22:08:52 +00:00
if ( g_eq_precedence < get_operator_precedence ( e ) )
2013-08-16 01:54:01 +00:00
return pp ( e , depth + 1 ) ;
else
return pp_child_with_paren ( e , depth ) ;
}
}
/** \brief Pretty print an equality */
result pp_eq ( expr const & e , unsigned depth ) {
result p_arg1 , p_arg2 ;
format r_format ;
2013-08-21 19:42:55 +00:00
p_arg1 = pp_eq_child ( eq_lhs ( e ) , depth ) ;
p_arg2 = pp_eq_child ( eq_rhs ( e ) , depth ) ;
r_format = group ( format { p_arg1 . first , space ( ) , g_eq_fmt , line ( ) , p_arg2 . first } ) ;
2013-08-19 19:04:40 +00:00
return mk_result ( r_format , p_arg1 . second + p_arg2 . second + 1 ) ;
2013-08-16 01:54:01 +00:00
}
2013-09-03 03:05:47 +00:00
result pp_choice ( expr const & e , unsigned depth ) {
lean_assert ( is_choice ( e ) ) ;
unsigned num = get_num_choices ( e ) ;
format r_format ;
2013-09-04 11:40:43 +00:00
unsigned r_weight = 0 ;
2013-09-03 03:05:47 +00:00
for ( unsigned i = 0 ; i < num ; i + + ) {
if ( i > 0 )
r_format + = format { space ( ) , format ( " | " ) , line ( ) } ;
expr const & c = get_choice ( e , i ) ;
result p_c = pp_child ( c , depth ) ;
r_weight + = p_c . second ;
r_format + = p_c . first ;
}
return mk_result ( r_format , r_weight + 1 ) ;
}
2013-09-13 01:25:38 +00:00
result pp_metavar ( expr const & a , unsigned depth ) {
format mv_fmt = compose ( format ( " ?M " ) , format ( metavar_idx ( a ) ) ) ;
if ( metavar_ctx ( a ) ) {
format ctx_fmt ;
bool first = true ;
unsigned r_weight = 1 ;
for ( meta_entry const & e : metavar_ctx ( a ) ) {
format e_fmt ;
2013-09-17 02:29:19 +00:00
if ( e . is_lift ( ) ) {
e_fmt = format { g_lift_fmt , colon ( ) , format ( e . s ( ) ) , colon ( ) , format ( e . n ( ) ) } ;
} else {
lean_assert ( e . is_inst ( ) ) ;
2013-09-13 01:25:38 +00:00
auto p_e = pp_child_with_paren ( e . v ( ) , depth ) ;
r_weight + = p_e . second ;
2013-09-17 02:21:40 +00:00
e_fmt = format { g_inst_fmt , colon ( ) , format ( e . s ( ) ) , space ( ) , nest ( m_indent , p_e . first ) } ;
2013-09-17 02:29:19 +00:00
}
2013-09-13 01:25:38 +00:00
if ( first ) {
ctx_fmt = e_fmt ;
first = false ;
} else {
2013-09-17 02:21:40 +00:00
ctx_fmt + = format { comma ( ) , line ( ) , e_fmt } ;
2013-09-13 01:25:38 +00:00
}
}
return mk_result ( group ( compose ( mv_fmt , nest ( m_indent , format { lsb ( ) , ctx_fmt , rsb ( ) } ) ) ) , r_weight ) ;
} else {
return mk_result ( mv_fmt , 1 ) ;
}
}
2013-08-19 19:04:40 +00:00
result pp ( expr const & e , unsigned depth , bool main = false ) {
2013-08-25 18:00:48 +00:00
check_interrupted ( m_interrupted ) ;
2013-08-20 20:55:31 +00:00
if ( ! is_atomic ( e ) & & ( m_num_steps > m_max_steps | | depth > m_max_depth ) ) {
2013-08-16 01:54:01 +00:00
return pp_ellipsis ( ) ;
} else {
m_num_steps + + ;
if ( m_extra_lets & & is_shared ( e ) ) {
auto it = m_aliases . find ( e ) ;
if ( it ! = m_aliases . end ( ) )
return mk_result ( format ( it - > second ) , 1 ) ;
}
result r ;
2013-09-03 03:05:47 +00:00
if ( is_choice ( e ) ) {
return pp_choice ( e , depth ) ;
2013-08-31 23:46:41 +00:00
} else {
switch ( e . kind ( ) ) {
case expr_kind : : Var : r = pp_var ( e ) ; break ;
case expr_kind : : Constant : r = pp_constant ( e ) ; break ;
case expr_kind : : Value : r = pp_value ( e ) ; break ;
case expr_kind : : App : r = pp_app ( e , depth ) ; break ;
case expr_kind : : Lambda :
case expr_kind : : Pi : r = pp_abstraction ( e , depth ) ; break ;
case expr_kind : : Type : r = pp_type ( e ) ; break ;
case expr_kind : : Eq : r = pp_eq ( e , depth ) ; break ;
case expr_kind : : Let : r = pp_let ( e , depth ) ; break ;
2013-09-13 01:25:38 +00:00
case expr_kind : : MetaVar : r = pp_metavar ( e , depth ) ; break ;
2013-08-31 23:46:41 +00:00
}
2013-08-16 01:54:01 +00:00
}
2013-08-19 19:04:40 +00:00
if ( ! main & & m_extra_lets & & is_shared ( e ) & & r . second > m_alias_min_weight ) {
name new_aux = name ( m_aux , m_aliases_defs . size ( ) + 1 ) ;
2013-08-16 01:54:01 +00:00
m_aliases . insert ( e , new_aux ) ;
2013-08-19 19:04:40 +00:00
m_aliases_defs . push_back ( mk_pair ( new_aux , r . first ) ) ;
2013-08-16 01:54:01 +00:00
return mk_result ( format ( new_aux ) , 1 ) ;
}
return r ;
}
}
void set_options ( options const & opts ) {
2013-08-19 19:04:40 +00:00
m_indent = get_pp_indent ( opts ) ;
m_max_depth = get_pp_max_depth ( opts ) ;
m_max_steps = get_pp_max_steps ( opts ) ;
m_implict = get_pp_implicit ( opts ) ;
2013-09-03 17:09:19 +00:00
m_unicode = get_pp_unicode ( opts ) ;
2013-09-02 02:08:49 +00:00
m_coercion = get_pp_coercion ( opts ) ;
2013-08-19 19:04:40 +00:00
m_notation = get_pp_notation ( opts ) ;
m_extra_lets = get_pp_extra_lets ( opts ) ;
m_alias_min_weight = get_pp_alias_min_weight ( opts ) ;
}
struct found_prefix { } ;
bool uses_prefix ( expr const & e , name const & prefix ) {
2013-09-20 04:26:01 +00:00
auto f = [ & ] ( expr const & e , unsigned ) {
2013-08-19 19:04:40 +00:00
if ( is_constant ( e ) ) {
if ( is_prefix_of ( prefix , const_name ( e ) ) ) throw found_prefix ( ) ;
} else if ( is_abstraction ( e ) ) {
if ( is_prefix_of ( prefix , abst_name ( e ) ) ) throw found_prefix ( ) ;
} else if ( is_let ( e ) ) {
if ( is_prefix_of ( prefix , let_name ( e ) ) ) throw found_prefix ( ) ;
}
} ;
try {
for_each_fn < decltype ( f ) > visitor ( f ) ;
visitor ( e ) ;
return false ;
} catch ( found_prefix ) {
return true ;
}
}
name find_unused_prefix ( expr const & e ) {
2013-09-13 19:57:40 +00:00
if ( ! uses_prefix ( e , g_kappa ) ) {
2013-08-19 19:04:40 +00:00
return g_kappa ;
2013-09-13 19:57:40 +00:00
} else if ( ! uses_prefix ( e , g_pho ) ) {
2013-08-19 19:04:40 +00:00
return g_pho ;
2013-09-13 19:57:40 +00:00
} else {
2013-08-19 19:04:40 +00:00
unsigned i = 1 ;
name n ( g_nu , i ) ;
while ( uses_prefix ( e , n ) ) {
i + + ;
n = name ( g_nu , i ) ;
}
return n ;
}
2013-08-16 01:54:01 +00:00
}
2013-08-19 19:04:40 +00:00
void init ( expr const & e ) {
2013-08-16 16:02:07 +00:00
m_aliases . clear ( ) ;
m_aliases_defs . clear ( ) ;
m_num_steps = 0 ;
2013-08-19 19:04:40 +00:00
m_aux = find_unused_prefix ( e ) ;
2013-08-16 16:02:07 +00:00
}
public :
2013-08-17 03:39:24 +00:00
pp_fn ( frontend const & fe , options const & opts ) :
m_frontend ( fe ) {
2013-08-16 01:54:01 +00:00
set_options ( opts ) ;
2013-08-24 23:11:35 +00:00
m_interrupted = false ;
2013-08-16 01:54:01 +00:00
}
format operator ( ) ( expr const & e ) {
2013-08-19 19:04:40 +00:00
init ( e ) ;
return pp_scoped_child ( e , 0 ) . first ;
2013-08-16 01:54:01 +00:00
}
2013-08-16 16:02:07 +00:00
2013-08-27 03:21:05 +00:00
format pp_definition ( expr const & v , expr const & t , std : : vector < bool > const * implicit_args ) {
2013-08-19 19:04:40 +00:00
init ( mk_app ( v , t ) ) ;
2013-08-16 16:02:07 +00:00
expr T ( t ) ;
2013-08-27 01:46:16 +00:00
return pp_abstraction_core ( v , 0 , T , implicit_args ) . first ;
}
2013-08-27 03:21:05 +00:00
format pp_pi_with_implicit_args ( expr const & e , std : : vector < bool > const & implicit_args ) {
2013-08-27 01:46:16 +00:00
init ( e ) ;
return pp_abstraction_core ( e , 0 , expr ( ) , & implicit_args ) . first ;
2013-08-16 16:02:07 +00:00
}
2013-08-24 23:11:35 +00:00
void set_interrupt ( bool flag ) {
m_interrupted = flag ;
}
2013-08-31 23:46:41 +00:00
void register_local ( name const & n ) {
m_local_names . insert ( n ) ;
}
2013-08-16 01:54:01 +00:00
} ;
2013-08-17 18:29:43 +00:00
class pp_formatter_cell : public formatter_cell {
2013-08-24 23:11:35 +00:00
frontend const & m_frontend ;
interruptable_ptr < pp_fn > m_pp_fn ;
2013-08-25 18:00:48 +00:00
volatile bool m_interrupted ;
2013-08-16 01:54:01 +00:00
2013-08-20 19:19:28 +00:00
format pp ( expr const & e , options const & opts ) {
2013-08-24 23:11:35 +00:00
pp_fn fn ( m_frontend , opts ) ;
scoped_set_interruptable_ptr < pp_fn > set ( m_pp_fn , & fn ) ;
return fn ( e ) ;
2013-08-17 03:39:24 +00:00
}
2013-08-20 19:19:28 +00:00
format pp ( context const & c , expr const & e , bool include_e , options const & opts ) {
2013-08-31 23:46:41 +00:00
pp_fn fn ( m_frontend , opts ) ;
scoped_set_interruptable_ptr < pp_fn > set ( m_pp_fn , & fn ) ;
2013-08-20 19:19:28 +00:00
unsigned indent = get_pp_indent ( opts ) ;
2013-08-17 03:39:24 +00:00
format r ;
bool first = true ;
expr c2 = context_to_lambda ( c , e ) ;
while ( is_fake_context ( c2 ) ) {
2013-08-25 18:00:48 +00:00
check_interrupted ( m_interrupted ) ;
2013-08-31 23:46:41 +00:00
name n1 = get_unused_name ( c2 ) ;
fn . register_local ( n1 ) ;
format entry = format { format ( n1 ) , space ( ) , colon ( ) , space ( ) , fn ( fake_context_domain ( c2 ) ) } ;
2013-08-17 03:39:24 +00:00
expr val = fake_context_value ( c2 ) ;
if ( val )
2013-08-31 23:46:41 +00:00
entry + = format { space ( ) , g_assign_fmt , nest ( indent , format { line ( ) , fn ( val ) } ) } ;
2013-08-17 03:39:24 +00:00
if ( first ) {
r = group ( entry ) ;
first = false ;
} else {
r + = format { line ( ) , group ( entry ) } ;
}
2013-09-17 02:21:40 +00:00
c2 = replace_var_with_name ( fake_context_rest ( c2 ) , n1 ) ;
2013-08-17 03:39:24 +00:00
}
if ( include_e ) {
if ( first )
2013-08-31 23:46:41 +00:00
r + = format { line ( ) , fn ( c2 ) } ;
2013-08-17 03:39:24 +00:00
else
2013-08-31 23:46:41 +00:00
r = fn ( c2 ) ;
2013-08-17 03:39:24 +00:00
} else {
return r ;
}
return r ;
2013-08-16 01:54:01 +00:00
}
2013-08-20 19:19:28 +00:00
format pp_definition ( char const * kwd , name const & n , expr const & t , expr const & v , options const & opts ) {
unsigned indent = get_pp_indent ( opts ) ;
2013-08-17 03:39:24 +00:00
format def = format { highlight_command ( format ( kwd ) ) , space ( ) , format ( n ) , space ( ) , colon ( ) , space ( ) ,
2013-08-20 19:19:28 +00:00
pp ( t , opts ) , space ( ) , g_assign_fmt , line ( ) , pp ( v , opts ) } ;
return group ( nest ( indent , def ) ) ;
2013-08-16 01:54:01 +00:00
}
2013-08-16 02:56:29 +00:00
2013-08-20 19:19:28 +00:00
format pp_compact_definition ( char const * kwd , name const & n , expr const & t , expr const & v , options const & opts ) {
2013-08-16 02:56:29 +00:00
expr it1 = t ;
expr it2 = v ;
while ( is_pi ( it1 ) & & is_lambda ( it2 ) ) {
2013-08-25 18:00:48 +00:00
check_interrupted ( m_interrupted ) ;
2013-08-16 02:56:29 +00:00
if ( abst_domain ( it1 ) ! = abst_domain ( it2 ) )
2013-08-20 19:19:28 +00:00
return pp_definition ( kwd , n , t , v , opts ) ;
2013-08-16 02:56:29 +00:00
it1 = abst_body ( it1 ) ;
it2 = abst_body ( it2 ) ;
}
2013-08-20 15:09:39 +00:00
if ( ! is_lambda ( v ) | | is_pi ( it1 ) ) {
2013-08-20 19:19:28 +00:00
return pp_definition ( kwd , n , t , v , opts ) ;
2013-08-16 02:56:29 +00:00
} else {
lean_assert ( is_lambda ( v ) ) ;
2013-08-27 03:21:05 +00:00
std : : vector < bool > const * implicit_args = nullptr ;
2013-08-27 01:46:16 +00:00
if ( m_frontend . has_implicit_arguments ( n ) )
implicit_args = & ( m_frontend . get_implicit_arguments ( n ) ) ;
2013-08-24 23:11:35 +00:00
pp_fn fn ( m_frontend , opts ) ;
scoped_set_interruptable_ptr < pp_fn > set ( m_pp_fn , & fn ) ;
2013-08-27 01:46:16 +00:00
format def = fn . pp_definition ( v , t , implicit_args ) ;
2013-08-16 02:56:29 +00:00
return format { highlight_command ( format ( kwd ) ) , space ( ) , format ( n ) , def } ;
}
}
2013-08-17 03:39:24 +00:00
2013-08-20 19:19:28 +00:00
format pp_uvar_decl ( object const & obj , options const & opts ) {
2013-09-03 17:09:19 +00:00
bool unicode = get_pp_unicode ( opts ) ;
return format { highlight_command ( format ( obj . keyword ( ) ) ) , space ( ) , format ( obj . get_name ( ) ) , space ( ) , format ( unicode ? " \u2265 " : " >= " ) , space ( ) , : : lean : : pp ( obj . get_cnstr_level ( ) , unicode ) } ;
2013-08-17 03:39:24 +00:00
}
2013-08-20 19:19:28 +00:00
format pp_postulate ( object const & obj , options const & opts ) {
2013-08-27 01:46:16 +00:00
char const * kwd = obj . keyword ( ) ;
name const & n = obj . get_name ( ) ;
format r = format { highlight_command ( format ( kwd ) ) , space ( ) , format ( n ) } ;
if ( m_frontend . has_implicit_arguments ( n ) ) {
pp_fn fn ( m_frontend , opts ) ;
scoped_set_interruptable_ptr < pp_fn > set ( m_pp_fn , & fn ) ;
r + = fn . pp_pi_with_implicit_args ( obj . get_type ( ) , m_frontend . get_implicit_arguments ( n ) ) ;
} else {
r + = format { space ( ) , colon ( ) , space ( ) , pp ( obj . get_type ( ) , opts ) } ;
}
return r ;
2013-08-17 03:39:24 +00:00
}
2013-09-20 04:26:01 +00:00
format pp_builtin_set ( object const & obj , options const & ) {
2013-09-04 15:30:04 +00:00
char const * kwd = obj . keyword ( ) ;
name const & n = obj . get_name ( ) ;
return format { highlight_command ( format ( kwd ) ) , space ( ) , format ( n ) } ;
}
2013-08-20 19:19:28 +00:00
format pp_definition ( object const & obj , options const & opts ) {
2013-09-07 00:58:45 +00:00
if ( m_frontend . is_explicit ( obj . get_name ( ) ) ) {
// Hide implicit arguments when pretty printing the
// explicit version on an object.
// We do that because otherwise it looks like a recursive definition.
options new_opts = update ( opts , g_pp_implicit , false ) ;
return pp_compact_definition ( obj . keyword ( ) , obj . get_name ( ) , obj . get_type ( ) , obj . get_value ( ) , new_opts ) ;
} else {
return pp_compact_definition ( obj . keyword ( ) , obj . get_name ( ) , obj . get_type ( ) , obj . get_value ( ) , opts ) ;
}
2013-08-17 03:39:24 +00:00
}
2013-08-20 19:19:28 +00:00
format pp_notation_decl ( object const & obj , options const & opts ) {
2013-09-01 23:59:15 +00:00
notation_declaration const & n = * static_cast < notation_declaration const * > ( obj . cell ( ) ) ;
2013-08-27 16:45:00 +00:00
expr const & d = n . get_expr ( ) ;
format d_fmt = is_constant ( d ) ? format ( const_name ( d ) ) : pp ( d , opts ) ;
return format { : : lean : : pp ( n . get_op ( ) ) , space ( ) , colon ( ) , space ( ) , d_fmt } ;
2013-08-17 03:39:24 +00:00
}
2013-09-01 23:59:15 +00:00
format pp_coercion_decl ( object const & obj , options const & opts ) {
unsigned indent = get_pp_indent ( opts ) ;
coercion_declaration const & n = * static_cast < coercion_declaration const * > ( obj . cell ( ) ) ;
expr const & c = n . get_coercion ( ) ;
return group ( format { highlight_command ( format ( n . keyword ( ) ) ) , nest ( indent , format ( { line ( ) , pp ( c , opts ) } ) ) } ) ;
}
2013-08-17 03:39:24 +00:00
public :
2013-08-20 19:19:28 +00:00
pp_formatter_cell ( frontend const & fe ) :
m_frontend ( fe ) {
2013-08-25 18:00:48 +00:00
m_interrupted = false ;
2013-08-17 03:39:24 +00:00
}
2013-08-17 18:29:43 +00:00
virtual ~ pp_formatter_cell ( ) {
2013-08-17 03:39:24 +00:00
}
2013-08-20 19:19:28 +00:00
virtual format operator ( ) ( expr const & e , options const & opts ) {
return pp ( e , opts ) ;
2013-08-17 03:39:24 +00:00
}
2013-08-20 19:19:28 +00:00
virtual format operator ( ) ( context const & c , options const & opts ) {
return pp ( c , Type ( ) , false , opts ) ;
2013-08-17 03:39:24 +00:00
}
2013-08-20 19:19:28 +00:00
virtual format operator ( ) ( context const & c , expr const & e , bool format_ctx , options const & opts ) {
2013-08-17 03:39:24 +00:00
if ( format_ctx ) {
2013-08-20 19:19:28 +00:00
return pp ( c , e , true , opts ) ;
2013-08-17 03:39:24 +00:00
} else {
2013-08-31 23:46:41 +00:00
pp_fn fn ( m_frontend , opts ) ;
scoped_set_interruptable_ptr < pp_fn > set ( m_pp_fn , & fn ) ;
2013-08-17 03:39:24 +00:00
expr c2 = context_to_lambda ( c , e ) ;
while ( is_fake_context ( c2 ) ) {
2013-08-25 18:00:48 +00:00
check_interrupted ( m_interrupted ) ;
2013-08-31 23:46:41 +00:00
name n1 = get_unused_name ( c2 ) ;
fn . register_local ( n1 ) ;
2013-08-17 03:39:24 +00:00
expr const & rest = fake_context_rest ( c2 ) ;
2013-09-17 02:21:40 +00:00
c2 = replace_var_with_name ( rest , n1 ) ;
2013-08-17 03:39:24 +00:00
}
2013-08-31 23:46:41 +00:00
return fn ( c2 ) ;
2013-08-17 03:39:24 +00:00
}
}
2013-08-20 19:19:28 +00:00
virtual format operator ( ) ( object const & obj , options const & opts ) {
2013-08-17 17:55:42 +00:00
switch ( obj . kind ( ) ) {
2013-08-20 19:19:28 +00:00
case object_kind : : UVarDeclaration : return pp_uvar_decl ( obj , opts ) ;
case object_kind : : Postulate : return pp_postulate ( obj , opts ) ;
case object_kind : : Definition : return pp_definition ( obj , opts ) ;
2013-09-04 15:30:04 +00:00
case object_kind : : Builtin : return pp_postulate ( obj , opts ) ;
case object_kind : : BuiltinSet : return pp_builtin_set ( obj , opts ) ;
2013-08-17 17:55:42 +00:00
case object_kind : : Neutral :
2013-08-17 18:04:22 +00:00
if ( dynamic_cast < notation_declaration const * > ( obj . cell ( ) ) ) {
2013-08-20 19:19:28 +00:00
return pp_notation_decl ( obj , opts ) ;
2013-09-01 23:59:15 +00:00
} else if ( dynamic_cast < coercion_declaration const * > ( obj . cell ( ) ) ) {
return pp_coercion_decl ( obj , opts ) ;
2013-08-17 18:04:22 +00:00
} else {
2013-09-01 23:59:15 +00:00
// If the object is not notation or coercion
// declaration, then the object was created in
// different frontend, and we ignore it.
2013-08-17 18:04:22 +00:00
return format ( " Unknown neutral object " ) ;
}
2013-08-17 17:55:42 +00:00
}
lean_unreachable ( ) ;
}
2013-08-20 19:19:28 +00:00
virtual format operator ( ) ( environment const & env , options const & opts ) {
2013-08-17 03:39:24 +00:00
format r ;
bool first = true ;
std : : for_each ( env . begin_objects ( ) ,
env . end_objects ( ) ,
[ & ] ( object const & obj ) {
2013-08-25 18:00:48 +00:00
check_interrupted ( m_interrupted ) ;
2013-08-17 03:39:24 +00:00
if ( first ) first = false ; else r + = line ( ) ;
2013-08-20 19:19:28 +00:00
r + = operator ( ) ( obj , opts ) ;
2013-08-17 03:39:24 +00:00
} ) ;
return r ;
}
2013-08-24 23:11:35 +00:00
virtual void set_interrupt ( bool flag ) {
m_pp_fn . set_interrupt ( flag ) ;
2013-08-25 18:00:48 +00:00
m_interrupted = flag ;
2013-08-24 23:11:35 +00:00
}
2013-08-16 01:54:01 +00:00
} ;
2013-08-20 19:19:28 +00:00
formatter mk_pp_formatter ( frontend const & fe ) {
return formatter ( new pp_formatter_cell ( fe ) ) ;
2013-08-17 03:39:24 +00:00
}
std : : ostream & operator < < ( std : : ostream & out , frontend const & fe ) {
2013-08-21 19:42:55 +00:00
options const & opts = fe . get_state ( ) . get_options ( ) ;
2013-08-20 19:19:28 +00:00
formatter fmt = mk_pp_formatter ( fe ) ;
2013-09-07 01:31:47 +00:00
bool first = true ;
std : : for_each ( fe . begin_objects ( ) ,
fe . end_objects ( ) ,
[ & ] ( object const & obj ) {
if ( first ) first = false ; else out < < " \n " ;
out < < mk_pair ( fmt ( obj , opts ) , opts ) ;
} ) ;
2013-08-17 03:39:24 +00:00
return out ;
2013-08-16 01:54:01 +00:00
}
}