refactor(frontends/lean): remove frontend class, it is not needed anymore

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2013-12-18 14:37:55 -08:00
parent 2aaa9a5273
commit 97b872a05c
14 changed files with 630 additions and 698 deletions

View file

@ -26,6 +26,15 @@ Author: Leonardo de Moura
#include "frontends/lean/pp.h"
namespace lean {
/**
\brief Import all definitions and notation.
*/
void init_frontend(environment const & env, io_state & ios) {
ios.set_formatter(mk_pp_formatter(env));
import_all(env);
init_builtin_notation(env, ios);
}
static std::vector<bool> g_empty_vector;
/**
\brief Environment extension object for the Lean default frontend.
@ -160,23 +169,23 @@ struct lean_extension : public environment_extension {
l = cons(op, l);
}
void check_precedence(name const & n, unsigned prec, io_state & st) const {
void check_precedence(name const & n, unsigned prec, io_state const & ios) const {
auto old_prec = get_lbp(n);
if (old_prec && *old_prec != prec)
diagnostic(st) << "The precedence of '" << n << "' changed from " << *old_prec << " to " << prec << ".\n";
diagnostic(ios) << "The precedence of '" << n << "' changed from " << *old_prec << " to " << prec << ".\n";
}
/** \brief Register the new operator in the tables for parsing and pretty printing. */
void register_new_op(operator_info new_op, expr const & d, bool led, io_state & st) {
void register_new_op(operator_info new_op, expr const & d, bool led, io_state const & ios) {
new_op.add_expr(d);
insert_op(new_op, led);
insert_expr_to_operator_entry(d, new_op);
auto parts = new_op.get_op_name_parts();
auto prec = new_op.get_precedence();
if (led)
check_precedence(head(parts), prec, st);
check_precedence(head(parts), prec, ios);
for (name const & part : tail(parts)) {
check_precedence(part, prec, st);
check_precedence(part, prec, ios);
m_other_lbp[part] = prec;
}
}
@ -246,11 +255,11 @@ struct lean_extension : public environment_extension {
2) It is a real conflict, and report the issue in the
diagnostic channel, and override the existing operator (aka notation).
*/
void add_op(operator_info new_op, expr const & d, bool led, environment const & env, io_state & st) {
void add_op(operator_info new_op, expr const & d, bool led, environment const & env, io_state const & ios) {
name const & opn = new_op.get_op_name();
operator_info old_op = find_op(opn, led);
if (!old_op) {
register_new_op(new_op, d, led, st);
register_new_op(new_op, d, led, ios);
} else if (old_op == new_op) {
if (compatible_denotations(old_op, d)) {
// overload
@ -261,20 +270,20 @@ struct lean_extension : public environment_extension {
// we must copy the operator because it was defined in
// a parent frontend.
new_op = old_op.copy();
register_new_op(new_op, d, led, st);
register_new_op(new_op, d, led, ios);
}
} else {
diagnostic(st) << "The denotation(s) for the existing notation:\n " << old_op
<< "\nhave been replaced with the new denotation:\n " << d
<< "\nbecause they conflict on how implicit arguments are used.\n";
diagnostic(ios) << "The denotation(s) for the existing notation:\n " << old_op
<< "\nhave been replaced with the new denotation:\n " << d
<< "\nbecause they conflict on how implicit arguments are used.\n";
remove_bindings(old_op);
register_new_op(new_op, d, led, st);
register_new_op(new_op, d, led, ios);
}
} else {
diagnostic(st) << "Notation has been redefined, the existing notation:\n " << old_op
<< "\nhas been replaced with:\n " << new_op << "\nbecause they conflict with each other.\n";
diagnostic(ios) << "Notation has been redefined, the existing notation:\n " << old_op
<< "\nhas been replaced with:\n " << new_op << "\nbecause they conflict with each other.\n";
remove_bindings(old_op);
register_new_op(new_op, d, led, st);
register_new_op(new_op, d, led, ios);
}
env->add_neutral_object(new notation_declaration(new_op, d));
}
@ -432,26 +441,33 @@ static lean_extension & to_ext(environment const & env) {
return env->get_extension<lean_extension>(g_lean_extension_initializer.m_extid);
}
bool is_explicit(ro_environment const & env, name const & n) {
return to_ext(env).is_explicit(n);
void add_infix(environment const & env, io_state const & ios, name const & opn, unsigned p, expr const & d) {
to_ext(env).add_op(infix(opn, p), d, true, env, ios);
}
bool has_implicit_arguments(ro_environment const & env, name const & n) {
return to_ext(env).has_implicit_arguments(n);
void add_infixl(environment const & env, io_state const & ios, name const & opn, unsigned p, expr const & d) {
to_ext(env).add_op(infixl(opn, p), d, true, env, ios);
}
name const & get_explicit_version(ro_environment const & env, name const & n) {
return to_ext(env).get_explicit_version(n);
void add_infixr(environment const & env, io_state const & ios, name const & opn, unsigned p, expr const & d) {
to_ext(env).add_op(infixr(opn, p), d, true, env, ios);
}
std::vector<bool> const & get_implicit_arguments(ro_environment const & env, name const & n) {
return to_ext(env).get_implicit_arguments(n);
void add_prefix(environment const & env, io_state const & ios, name const & opn, unsigned p, expr const & d) {
to_ext(env).add_op(prefix(opn, p), d, false, env, ios);
}
bool is_coercion(ro_environment const & env, expr const & f) {
return to_ext(env).is_coercion(f);
void add_postfix(environment const & env, io_state const & ios, name const & opn, unsigned p, expr const & d) {
to_ext(env).add_op(postfix(opn, p), d, true, env, ios);
}
void add_mixfixl(environment const & env, io_state const & ios, unsigned sz, name const * opns, unsigned p, expr const & d) {
to_ext(env).add_op(mixfixl(sz, opns, p), d, false, env, ios);
}
void add_mixfixr(environment const & env, io_state const & ios, unsigned sz, name const * opns, unsigned p, expr const & d) {
to_ext(env).add_op(mixfixr(sz, opns, p), d, true, env, ios);
}
void add_mixfixc(environment const & env, io_state const & ios, unsigned sz, name const * opns, unsigned p, expr const & d) {
to_ext(env).add_op(mixfixc(sz, opns, p), d, false, env, ios);
}
void add_mixfixo(environment const & env, io_state const & ios, unsigned sz, name const * opns, unsigned p, expr const & d) {
to_ext(env).add_op(mixfixo(sz, opns, p), d, true, env, ios);
}
operator_info find_op_for(ro_environment const & env, expr const & n, bool unicode) {
operator_info r = to_ext(env).find_op_for(n, unicode);
if (r || !is_constant(n)) {
@ -464,110 +480,69 @@ operator_info find_op_for(ro_environment const & env, expr const & n, bool unico
return r;
}
}
frontend::frontend() {
m_state.set_formatter(mk_pp_formatter(m_env));
import_all(m_env);
init_builtin_notation(*this);
operator_info find_nud(ro_environment const & env, name const & n) {
return to_ext(env).find_nud(n);
}
frontend::frontend(environment const & env, io_state const & s):m_env(env), m_state(s) {
import_all(m_env);
init_builtin_notation(*this);
operator_info find_led(ro_environment const & env, name const & n) {
return to_ext(env).find_led(n);
}
void frontend::add_infix(name const & opn, unsigned p, expr const & d) {
to_ext(m_env).add_op(infix(opn, p), d, true, m_env, m_state);
optional<unsigned> get_lbp(ro_environment const & env, name const & n) {
return to_ext(env).get_lbp(n);
}
void frontend::add_infixl(name const & opn, unsigned p, expr const & d) {
to_ext(m_env).add_op(infixl(opn, p), d, true, m_env, m_state);
void mark_implicit_arguments(environment const & env, name const & n, unsigned sz, bool const * implicit) {
to_ext(env).mark_implicit_arguments(n, sz, implicit, env);
}
void frontend::add_infixr(name const & opn, unsigned p, expr const & d) {
to_ext(m_env).add_op(infixr(opn, p), d, true, m_env, m_state);
}
void frontend::add_prefix(name const & opn, unsigned p, expr const & d) {
to_ext(m_env).add_op(prefix(opn, p), d, false, m_env, m_state);
}
void frontend::add_postfix(name const & opn, unsigned p, expr const & d) {
to_ext(m_env).add_op(postfix(opn, p), d, true, m_env, m_state);
}
void frontend::add_mixfixl(unsigned sz, name const * opns, unsigned p, expr const & d) {
to_ext(m_env).add_op(mixfixl(sz, opns, p), d, false, m_env, m_state);
}
void frontend::add_mixfixr(unsigned sz, name const * opns, unsigned p, expr const & d) {
to_ext(m_env).add_op(mixfixr(sz, opns, p), d, true, m_env, m_state);
}
void frontend::add_mixfixc(unsigned sz, name const * opns, unsigned p, expr const & d) {
to_ext(m_env).add_op(mixfixc(sz, opns, p), d, false, m_env, m_state);
}
void frontend::add_mixfixo(unsigned sz, name const * opns, unsigned p, expr const & d) {
to_ext(m_env).add_op(mixfixo(sz, opns, p), d, true, m_env, m_state);
}
operator_info frontend::find_op_for(expr const & n, bool unicode) const {
return ::lean::find_op_for(m_env, n, unicode);
}
operator_info frontend::find_nud(name const & n) const {
return to_ext(m_env).find_nud(n);
}
operator_info frontend::find_led(name const & n) const {
return to_ext(m_env).find_led(n);
}
optional<unsigned> frontend::get_lbp(name const & n) const {
return to_ext(m_env).get_lbp(n);
}
void frontend::mark_implicit_arguments(name const & n, unsigned sz, bool const * implicit) {
to_ext(m_env).mark_implicit_arguments(n, sz, implicit, m_env);
}
void frontend::mark_implicit_arguments(name const & n, unsigned prefix_sz) {
void mark_implicit_arguments(environment const & env, name const & n, unsigned prefix_sz) {
buffer<bool> implicit; implicit.resize(prefix_sz, true);
mark_implicit_arguments(n, implicit.size(), implicit.data());
mark_implicit_arguments(env, n, implicit.size(), implicit.data());
}
void frontend::mark_implicit_arguments(expr const & n, unsigned prefix_sz) {
void mark_implicit_arguments(environment const & env, expr const & n, unsigned prefix_sz) {
if (is_constant(n)) {
mark_implicit_arguments(const_name(n), prefix_sz);
mark_implicit_arguments(env, const_name(n), prefix_sz);
} else {
lean_assert(is_value(n));
mark_implicit_arguments(to_value(n).get_name(), prefix_sz);
mark_implicit_arguments(env, to_value(n).get_name(), prefix_sz);
}
}
void frontend::mark_implicit_arguments(name const & n, std::initializer_list<bool> const & l) {
mark_implicit_arguments(n, l.size(), l.begin());
void mark_implicit_arguments(environment const & env, name const & n, std::initializer_list<bool> const & l) {
mark_implicit_arguments(env, n, l.size(), l.begin());
}
void frontend::mark_implicit_arguments(expr const & n, std::initializer_list<bool> const & l) {
void mark_implicit_arguments(environment const & env, expr const & n, std::initializer_list<bool> const & l) {
if (is_constant(n)) {
mark_implicit_arguments(const_name(n), l);
mark_implicit_arguments(env, const_name(n), l);
} else {
lean_assert(is_value(n));
mark_implicit_arguments(to_value(n).get_name(), l);
mark_implicit_arguments(env, to_value(n).get_name(), l);
}
}
bool frontend::has_implicit_arguments(name const & n) const {
return to_ext(m_env).has_implicit_arguments(n);
bool has_implicit_arguments(ro_environment const & env, name const & n) {
return to_ext(env).has_implicit_arguments(n);
}
std::vector<bool> const & frontend::get_implicit_arguments(name const & n) const {
return to_ext(m_env).get_implicit_arguments(n);
std::vector<bool> const & get_implicit_arguments(ro_environment const & env, name const & n) {
return to_ext(env).get_implicit_arguments(n);
}
std::vector<bool> const & frontend::get_implicit_arguments(expr const & n) const {
std::vector<bool> const & get_implicit_arguments(ro_environment const & env, expr const & n) {
if (is_constant(n))
return get_implicit_arguments(const_name(n));
return get_implicit_arguments(env, const_name(n));
else
return g_empty_vector;
}
name const & frontend::get_explicit_version(name const & n) const {
return to_ext(m_env).get_explicit_version(n);
name const & get_explicit_version(ro_environment const & env, name const & n) {
return to_ext(env).get_explicit_version(n);
}
bool frontend::is_explicit(name const & n) const {
return to_ext(m_env).is_explicit(n);
bool is_explicit(ro_environment const & env, name const & n) {
return to_ext(env).is_explicit(n);
}
void frontend::add_coercion(expr const & f) {
to_ext(m_env).add_coercion(f, m_env);
void add_coercion(environment const & env, expr const & f) {
to_ext(env).add_coercion(f, env);
}
optional<expr> frontend::get_coercion(expr const & from_type, expr const & to_type) const {
return to_ext(m_env).get_coercion(from_type, to_type);
optional<expr> get_coercion(ro_environment const & env, expr const & from_type, expr const & to_type) {
return to_ext(env).get_coercion(from_type, to_type);
}
list<expr_pair> frontend::get_coercions(expr const & from_type) const {
return to_ext(m_env).get_coercions(from_type);
list<expr_pair> get_coercions(ro_environment const & env, expr const & from_type) {
return to_ext(env).get_coercions(from_type);
}
bool frontend::is_coercion(expr const & f) const {
return to_ext(m_env).is_coercion(f);
bool is_coercion(ro_environment const & env, expr const & f) {
return to_ext(env).is_coercion(f);
}
}

View file

@ -14,197 +14,148 @@ Author: Leonardo de Moura
namespace lean {
/**
\brief Wrapper for environment/state that provides additional objects
that are specific to the Lean frontend.
This wrapper provides APIs for accessing/using the Lean frontend
extension data in the environment.
\brief Import all definitions and notation.
*/
class frontend {
environment m_env;
io_state m_state;
public:
frontend();
frontend(environment const & env, io_state const & s);
void init_frontend(environment const & env, io_state & ios);
frontend mk_child() const { return frontend(m_env->mk_child(), m_state); }
bool has_children() const { return m_env->has_children(); }
bool has_parent() const { return m_env->has_parent(); }
environment const & get_environment() const { return m_env; }
operator environment const &() const { return get_environment(); }
operator ro_environment() const { return ro_environment(m_env); }
/**
@name Environment API
*/
/*@{*/
level add_uvar(name const & n, level const & l) { return m_env->add_uvar(n, l); }
level add_uvar(name const & n) { return m_env->add_uvar(n); }
level get_uvar(name const & n) const { return m_env->get_uvar(n); }
void add_definition(name const & n, expr const & t, expr const & v, bool opaque = false) { m_env->add_definition(n, t, v, opaque); }
void add_theorem(name const & n, expr const & t, expr const & v) { m_env->add_theorem(n, t, v); }
void add_definition(name const & n, expr const & v, bool opaque = false) { m_env->add_definition(n, v, opaque); }
void add_axiom(name const & n, expr const & t) { m_env->add_axiom(n, t); }
void add_var(name const & n, expr const & t) { m_env->add_var(n, t); }
object get_object(name const & n) const { return m_env->get_object(n); }
optional<object> find_object(name const & n) const { return m_env->find_object(n); }
bool has_object(name const & n) const { return m_env->has_object(n); }
typedef environment_cell::object_iterator object_iterator;
object_iterator begin_objects() const { return m_env->begin_objects(); }
object_iterator end_objects() const { return m_env->end_objects(); }
object_iterator begin_local_objects() const { return m_env->begin_local_objects(); }
object_iterator end_local_objects() const { return m_env->end_local_objects(); }
/*@}*/
/**
@name Notation for parsing and pretty printing.
*/
/*@{*/
void add_infix(name const & opn, unsigned precedence, expr const & d);
void add_infixl(name const & opn, unsigned precedence, expr const & d);
void add_infixr(name const & opn, unsigned precedence, expr const & d);
void add_prefix(name const & opn, unsigned precedence, expr const & d);
void add_postfix(name const & opn, unsigned precedence, expr const & d);
void add_mixfixl(unsigned sz, name const * opns, unsigned precedence, expr const & d);
void add_mixfixr(unsigned sz, name const * opns, unsigned precedence, expr const & d);
void add_mixfixc(unsigned sz, name const * opns, unsigned precedence, expr const & d);
void add_mixfixo(unsigned sz, name const * opns, unsigned precedence, expr const & d);
void add_mixfixl(std::initializer_list<name> const & l, unsigned p, expr const & d) { add_mixfixl(l.size(), l.begin(), p, d); }
void add_mixfixr(std::initializer_list<name> const & l, unsigned p, expr const & d) { add_mixfixr(l.size(), l.begin(), p, d); }
void add_mixfixc(std::initializer_list<name> const & l, unsigned p, expr const & d) { add_mixfixc(l.size(), l.begin(), p, d); }
void add_mixfixo(std::initializer_list<name> const & l, unsigned p, expr const & d) { add_mixfixo(l.size(), l.begin(), p, d); }
/**
\brief Return the operator (if one exists) associated with the
given expression.
\remark If an operator is not associated with \c e, then
return the null operator.
\remark This is used for pretty printing.
\remark If unicode is false, then only operators containing
safe ASCII chars are considered.
*/
operator_info find_op_for(expr const & e, bool unicode) const;
/**
\brief Return the operator (if one exists) that can appear at
the beginning of a language construct.
\remark If there isn't a nud operator starting with \c n, then
return the null operator.
\remark This is used for parsing.
*/
operator_info find_nud(name const & n) const;
/**
\brief Return the operator (if one exists) that can appear
inside of a language construct.
\remark If there isn't a led operator starting with \c n, then
return the null operator.
\remark This is used for parsing.
*/
operator_info find_led(name const & n) const;
/** \brief Return the precedence (aka binding power) of the given name. */
optional<unsigned> get_lbp(name const & n) const;
/*@}*/
/**
@name Implicit arguments.
*/
/**
\brief Mark the given arguments of \c n as implicit.
The bit-vector array specify the position of the implicit arguments.
*/
void mark_implicit_arguments(name const & n, unsigned sz, bool const * mask);
void mark_implicit_arguments(name const & n, std::initializer_list<bool> const & l);
void mark_implicit_arguments(expr const & n, std::initializer_list<bool> const & l);
/**
\brief Syntax sugar for mark_implicit_arguments(n, {true, ..., true}), with prefix_sz true's.
*/
void mark_implicit_arguments(name const & n, unsigned prefix_sz);
void mark_implicit_arguments(expr const & n, unsigned prefix_sz);
/** \brief Return true iff \c n has implicit arguments */
bool has_implicit_arguments(name const & n) const;
/** \brief Return the position of the arguments that are implicit. */
std::vector<bool> const & get_implicit_arguments(name const & n) const;
/**
\brief Return the position of the arguments that are implicit.
\remark If \c n is not a constant, then return the empty vector.
*/
std::vector<bool> const & get_implicit_arguments(expr const & n) const;
/**
\brief This frontend associates an definition with each
definition (or postulate) that has implicit arguments. The
additional definition has explicit arguments, and it is called
n::explicit. The explicit version can be used when the Lean
frontend can't figure out the value for the implicit
arguments.
*/
name const & get_explicit_version(name const & n) const;
/**
\brief Return true iff \c n is the name of the "explicit"
version of an object with implicit arguments
*/
bool is_explicit(name const & n) const;
/*@}*/
/**
@name Coercions
We support a very basic form of coercion. It is an expression
with type T1 -> T2. This expression can be used to convert
an expression of type T1 into an expression of type T2 whenever
T2 is expected, but T1 was provided.
*/
/**
\brief Add a new coercion to the frontend.
It throws an exception if f does not have type T1 -> T2, or if there is already a
coercion from T1 to T2.
*/
void add_coercion(expr const & f);
/**
\brief Return a coercion from given_type to expected_type if it exists.
*/
optional<expr> get_coercion(expr const & from_type, expr const & to_type) const;
/**
\brief Return the list of coercions for the given type.
The result is a list of pairs (to_type, function).
*/
list<expr_pair> get_coercions(expr const & from_type) const;
/**
\brief Return true iff the given expression is a coercion. That is, it was added using
\c add_coercion.
*/
bool is_coercion(expr const & f) const;
/*@}*/
/**
@name State management.
*/
/*@{*/
io_state const & get_state() const { return m_state; }
operator io_state const &() const { return m_state; }
io_state & get_state() { return m_state; }
operator io_state &() { return m_state; }
options get_options() const { return m_state.get_options(); }
void set_options(options const & opts) { return m_state.set_options(opts); }
template<typename T> void set_option(name const & n, T const & v) { m_state.set_option(n, v); }
void set_regular_channel(std::shared_ptr<output_channel> const & out) { m_state.set_regular_channel(out); }
void set_diagnostic_channel(std::shared_ptr<output_channel> const & out) { m_state.set_diagnostic_channel(out); }
/*@}*/
};
bool is_explicit(ro_environment const & env, name const & n);
bool has_implicit_arguments(ro_environment const & env, name const & n);
name const & get_explicit_version(ro_environment const & env, name const & n);
std::vector<bool> const & get_implicit_arguments(ro_environment const & env, name const & n);
bool is_coercion(ro_environment const & env, expr const & f);
operator_info find_op_for(ro_environment const & env, expr const & e, bool unicode);
/**
@name Notation for parsing and pretty printing.
*/
/*@{*/
void add_infix(environment const & env, io_state const & ios, name const & opn, unsigned p, expr const & d);
void add_infixl(environment const & env, io_state const & ios, name const & opn, unsigned p, expr const & d);
void add_infixr(environment const & env, io_state const & ios, name const & opn, unsigned p, expr const & d);
void add_prefix(environment const & env, io_state const & ios, name const & opn, unsigned p, expr const & d);
void add_postfix(environment const & env, io_state const & ios, name const & opn, unsigned p, expr const & d);
void add_mixfixl(environment const & env, io_state const & ios, unsigned sz, name const * opns, unsigned precedence, expr const & d);
void add_mixfixr(environment const & env, io_state const & ios, unsigned sz, name const * opns, unsigned precedence, expr const & d);
void add_mixfixc(environment const & env, io_state const & ios, unsigned sz, name const * opns, unsigned precedence, expr const & d);
void add_mixfixo(environment const & env, io_state const & ios, unsigned sz, name const * opns, unsigned precedence, expr const & d);
inline void add_mixfixl(environment const & env, io_state const & ios, std::initializer_list<name> const & l, unsigned p, expr const & d) {
add_mixfixl(env, ios, l.size(), l.begin(), p, d);
}
inline void add_mixfixr(environment const & env, io_state const & ios, std::initializer_list<name> const & l, unsigned p, expr const & d) {
add_mixfixr(env, ios, l.size(), l.begin(), p, d);
}
inline void add_mixfixc(environment const & env, io_state const & ios, std::initializer_list<name> const & l, unsigned p, expr const & d) {
add_mixfixc(env, ios, l.size(), l.begin(), p, d);
}
inline void add_mixfixo(environment const & env, io_state const & ios, std::initializer_list<name> const & l, unsigned p, expr const & d) {
add_mixfixo(env, ios, l.size(), l.begin(), p, d);
}
/**
\brief Return the operator (if one exists) that can appear at
the beginning of a language construct.
\remark If there isn't a nud operator starting with \c n, then
return the null operator.
\remark This is used for parsing.
*/
operator_info find_nud(ro_environment const & env, name const & n);
/**
\brief Return the operator (if one exists) that can appear
inside of a language construct.
\remark If there isn't a led operator starting with \c n, then
return the null operator.
\remark This is used for parsing.
*/
operator_info find_led(ro_environment const & env, name const & n);
/**
\brief Return the precedence (aka binding power) of the given name.
*/
optional<unsigned> get_lbp(ro_environment const & env, name const & n);
/**
\brief Return the operator (if one exists) associated with the
given expression.
\remark If an operator is not associated with \c e, then
return the null operator.
\remark This is used for pretty printing.
\remark If unicode is false, then only operators containing
safe ASCII chars are considered.
*/
operator_info find_op_for(ro_environment const & env, expr const & e, bool unicode);
/*@}*/
/**
@name Implicit arguments.
*/
/*@{*/
/**
\brief Mark the given arguments of \c n as implicit.
The bit-vector array specify the position of the implicit arguments.
*/
void mark_implicit_arguments(environment const & env, name const & n, unsigned sz, bool const * implicit);
void mark_implicit_arguments(environment const & env, name const & n, std::initializer_list<bool> const & l);
void mark_implicit_arguments(environment const & env, expr const & n, std::initializer_list<bool> const & l);
/**
\brief Syntax sugar for mark_implicit_arguments(n, {true, ..., true}), with prefix_sz true's.
*/
void mark_implicit_arguments(environment const & env, name const & n, unsigned prefix_sz);
void mark_implicit_arguments(environment const & env, expr const & n, unsigned prefix_sz);
/**
\brief Return true iff \c n has implicit arguments
*/
bool has_implicit_arguments(ro_environment const & env, name const & n);
/**
\brief Return the position of the arguments that are implicit.
*/
std::vector<bool> const & get_implicit_arguments(ro_environment const & env, name const & n);
/**
\brief Return the position of the arguments that are implicit.
\remark If \c n is not a constant, then return the empty vector.
*/
std::vector<bool> const & get_implicit_arguments(ro_environment const & env, expr const & n);
/**
\brief This frontend associates an definition with each
definition (or postulate) that has implicit arguments. The
additional definition has explicit arguments, and it is called
n::explicit. The explicit version can be used when the Lean
frontend can't figure out the value for the implicit
arguments.
*/
name const & get_explicit_version(ro_environment const & env, name const & n);
/**
\brief Return true iff \c n is the name of the "explicit"
version of an object with implicit arguments
*/
bool is_explicit(ro_environment const & env, name const & n);
/*@}*/
/**
@name Coercions
We support a very basic form of coercion. It is an expression
with type T1 -> T2. This expression can be used to convert
an expression of type T1 into an expression of type T2 whenever
T2 is expected, but T1 was provided.
*/
/*@{*/
/**
\brief Add a new coercion to the frontend.
It throws an exception if f does not have type T1 -> T2, or if there is already a
coercion from T1 to T2.
*/
void add_coercion(environment const & env, expr const & f);
/**
\brief Return true iff the given expression is a coercion. That is, it was added using
\c add_coercion.
*/
bool is_coercion(ro_environment const & env, expr const & f);
/**
\brief Return a coercion from given_type to expected_type if it exists.
*/
optional<expr> get_coercion(ro_environment const & env, expr const & from_type, expr const & to_type);
/**
\brief Return the list of coercions for the given type.
The result is a list of pairs (to_type, function).
*/
list<expr_pair> get_coercions(ro_environment const & env, expr const & from_type);
/*@}*/
}

View file

@ -125,7 +125,6 @@ inline justification mk_overload_justification(context const & ctx, expr const &
\brief Actual implementation of the frontend_elaborator.
*/
class frontend_elaborator::imp {
frontend const & m_frontend;
environment const & m_env;
type_checker m_type_checker;
type_inferer m_type_inferer;
@ -150,6 +149,8 @@ class frontend_elaborator::imp {
return ::lean::instantiate(e, v, m_ref.m_menv);
}
environment const & env() const { return m_ref.m_env; }
virtual expr visit_constant(expr const & e, context const & ctx) {
if (is_placeholder(e)) {
expr m = m_ref.m_menv->mk_metavar(ctx, visit(const_type(e), ctx));
@ -243,7 +244,7 @@ class frontend_elaborator::imp {
if (!has_metavar(expected) && !has_metavar(*given)) {
if (m_ref.m_type_checker.is_convertible(*given, expected, ctx)) {
// compatible
} else if (m_ref.m_frontend.get_coercion(*given, expected)) {
} else if (get_coercion(env(), *given, expected)) {
// compatible if using coercion
num_coercions++;
} else {
@ -334,7 +335,7 @@ class frontend_elaborator::imp {
args[0] = mk_overload_mvar(f_choices, ctx, e);
for (unsigned i = 1; i < args.size(); i++) {
if (arg_types[i]) {
list<expr_pair> coercions = m_ref.m_frontend.get_coercions(*(arg_types[i]));
list<expr_pair> coercions = get_coercions(env(), *(arg_types[i]));
if (coercions)
args[i] = add_coercion_mvar_app(coercions, args[i], *(arg_types[i]), ctx, arg(e, i));
}
@ -358,7 +359,7 @@ class frontend_elaborator::imp {
expr new_a = args[i];
optional<expr> new_a_t = arg_types[i];
if (new_a_t) {
list<expr_pair> coercions = m_ref.m_frontend.get_coercions(*new_a_t);
list<expr_pair> coercions = get_coercions(env(), *new_a_t);
if (coercions) {
if (!f_t) {
new_a = add_coercion_mvar_app(coercions, new_a, *new_a_t, ctx, a);
@ -390,7 +391,7 @@ class frontend_elaborator::imp {
if (new_t) {
optional<expr> new_v_t = get_type(new_v, ctx);
if (new_v_t && *new_t != *new_v_t) {
list<expr_pair> coercions = m_ref.m_frontend.get_coercions(*new_v_t);
list<expr_pair> coercions = get_coercions(env(), *new_v_t);
if (coercions) {
new_v = add_coercion_mvar_app(coercions, new_v, *new_v_t, ctx, v);
}
@ -427,9 +428,8 @@ class frontend_elaborator::imp {
}
public:
imp(frontend const & fe):
m_frontend(fe),
m_env(fe.get_environment()),
imp(environment const & env):
m_env(env),
m_type_checker(m_env),
m_type_inferer(m_env),
m_normalizer(m_env) {
@ -503,7 +503,7 @@ public:
}
};
frontend_elaborator::frontend_elaborator(frontend const & fe):m_ptr(new imp(fe)) {}
frontend_elaborator::frontend_elaborator(environment const & env):m_ptr(new imp(env)) {}
frontend_elaborator::~frontend_elaborator() {}
expr frontend_elaborator::operator()(expr const & e) { return m_ptr->elaborate(e); }
std::tuple<expr, expr, metavar_env> frontend_elaborator::operator()(name const & n, expr const & t, expr const & e) {

View file

@ -23,7 +23,7 @@ class frontend_elaborator {
std::shared_ptr<imp> m_ptr;
static void print(imp * ptr);
public:
explicit frontend_elaborator(frontend const & fe);
explicit frontend_elaborator(environment const & env);
~frontend_elaborator();
/**

View file

@ -11,117 +11,117 @@ Author: Leonardo de Moura
#include "frontends/lean/frontend.h"
namespace lean {
void add_alias(frontend & f, name const & n, name const & m) {
object const & obj = f.get_object(n);
f.add_definition(m, obj.get_type(), mk_constant(n));
void add_alias(environment const & env, name const & n, name const & m) {
object const & obj = env->get_object(n);
env->add_definition(m, obj.get_type(), mk_constant(n));
}
/**
\brief Initialize builtin notation.
*/
void init_builtin_notation(frontend & f) {
if (!f.get_environment()->mark_builtin_imported("lean_notation"))
void init_builtin_notation(environment const & env, io_state & ios) {
if (!env->mark_builtin_imported("lean_notation"))
return;
f.add_infix("=", 50, mk_homo_eq_fn());
f.mark_implicit_arguments(mk_homo_eq_fn(), 1);
f.mark_implicit_arguments(mk_if_fn(), 1);
add_infix(env, ios, "=", 50, mk_homo_eq_fn());
mark_implicit_arguments(env, mk_homo_eq_fn(), 1);
mark_implicit_arguments(env, mk_if_fn(), 1);
f.add_prefix("\u00ac", 40, mk_not_fn()); // "¬"
f.add_infixr("&&", 35, mk_and_fn()); // "&&"
f.add_infixr("/\\", 35, mk_and_fn()); // "/\"
f.add_infixr("\u2227", 35, mk_and_fn()); // "∧"
f.add_infixr("||", 30, mk_or_fn()); // "||"
f.add_infixr("\\/", 30, mk_or_fn()); // "\/"
f.add_infixr("\u2228", 30, mk_or_fn()); // ""
f.add_infixr("=>", 25, mk_implies_fn()); // "=>"
f.add_infixr("\u21D2", 25, mk_implies_fn()); // "⇒"
f.add_infixr("<=>", 25, mk_iff_fn()); // "<=>"
f.add_infixr("\u21D4", 25, mk_iff_fn()); // "⇔"
add_prefix(env, ios, "\u00ac", 40, mk_not_fn()); // "¬"
add_infixr(env, ios, "&&", 35, mk_and_fn()); // "&&"
add_infixr(env, ios, "/\\", 35, mk_and_fn()); // "/\"
add_infixr(env, ios, "\u2227", 35, mk_and_fn()); // "∧"
add_infixr(env, ios, "||", 30, mk_or_fn()); // "||"
add_infixr(env, ios, "\\/", 30, mk_or_fn()); // "\/"
add_infixr(env, ios, "\u2228", 30, mk_or_fn()); // ""
add_infixr(env, ios, "=>", 25, mk_implies_fn()); // "=>"
add_infixr(env, ios, "\u21D2", 25, mk_implies_fn()); // "⇒"
add_infixr(env, ios, "<=>", 25, mk_iff_fn()); // "<=>"
add_infixr(env, ios, "\u21D4", 25, mk_iff_fn()); // "⇔"
f.add_infixl("+", 65, mk_nat_add_fn());
f.add_infixl("-", 65, mk_nat_sub_fn());
f.add_prefix("-", 75, mk_nat_neg_fn());
f.add_infixl("*", 70, mk_nat_mul_fn());
f.add_infix("<=", 50, mk_nat_le_fn());
f.add_infix("\u2264", 50, mk_nat_le_fn()); // ≤
f.add_infix(">=", 50, mk_nat_ge_fn());
f.add_infix("\u2265", 50, mk_nat_ge_fn()); // ≥
f.add_infix("<", 50, mk_nat_lt_fn());
f.add_infix(">", 50, mk_nat_gt_fn());
f.add_mixfixc({"|", "|"}, 55, mk_nat_id_fn()); // absolute value for naturals is the identity function
add_infixl(env, ios, "+", 65, mk_nat_add_fn());
add_infixl(env, ios, "-", 65, mk_nat_sub_fn());
add_prefix(env, ios, "-", 75, mk_nat_neg_fn());
add_infixl(env, ios, "*", 70, mk_nat_mul_fn());
add_infix(env, ios, "<=", 50, mk_nat_le_fn());
add_infix(env, ios, "\u2264", 50, mk_nat_le_fn()); // ≤
add_infix(env, ios, ">=", 50, mk_nat_ge_fn());
add_infix(env, ios, "\u2265", 50, mk_nat_ge_fn()); // ≥
add_infix(env, ios, "<", 50, mk_nat_lt_fn());
add_infix(env, ios, ">", 50, mk_nat_gt_fn());
add_mixfixc(env, ios, {"|", "|"}, 55, mk_nat_id_fn()); // absolute value for naturals is the identity function
f.add_infixl("+", 65, mk_int_add_fn());
f.add_infixl("-", 65, mk_int_sub_fn());
f.add_prefix("-", 75, mk_int_neg_fn());
f.add_infixl("*", 70, mk_int_mul_fn());
f.add_infixl("div", 70, mk_int_div_fn());
f.add_infixl("mod", 70, mk_int_mod_fn());
f.add_infix("|", 50, mk_int_divides_fn());
f.add_mixfixc({"|", "|"}, 55, mk_int_abs_fn());
f.add_infix("<=", 50, mk_int_le_fn());
f.add_infix("\u2264", 50, mk_int_le_fn()); // ≤
f.add_infix(">=", 50, mk_int_ge_fn());
f.add_infix("\u2265", 50, mk_int_ge_fn()); // ≥
f.add_infix("<", 50, mk_int_lt_fn());
f.add_infix(">", 50, mk_int_gt_fn());
add_infixl(env, ios, "+", 65, mk_int_add_fn());
add_infixl(env, ios, "-", 65, mk_int_sub_fn());
add_prefix(env, ios, "-", 75, mk_int_neg_fn());
add_infixl(env, ios, "*", 70, mk_int_mul_fn());
add_infixl(env, ios, "div", 70, mk_int_div_fn());
add_infixl(env, ios, "mod", 70, mk_int_mod_fn());
add_infix(env, ios, "|", 50, mk_int_divides_fn());
add_mixfixc(env, ios, {"|", "|"}, 55, mk_int_abs_fn());
add_infix(env, ios, "<=", 50, mk_int_le_fn());
add_infix(env, ios, "\u2264", 50, mk_int_le_fn()); // ≤
add_infix(env, ios, ">=", 50, mk_int_ge_fn());
add_infix(env, ios, "\u2265", 50, mk_int_ge_fn()); // ≥
add_infix(env, ios, "<", 50, mk_int_lt_fn());
add_infix(env, ios, ">", 50, mk_int_gt_fn());
f.add_infixl("+", 65, mk_real_add_fn());
f.add_infixl("-", 65, mk_real_sub_fn());
f.add_prefix("-", 75, mk_real_neg_fn());
f.add_infixl("*", 70, mk_real_mul_fn());
f.add_infixl("/", 70, mk_real_div_fn());
f.add_mixfixc({"|", "|"}, 55, mk_real_abs_fn());
f.add_infix("<=", 50, mk_real_le_fn());
f.add_infix("\u2264", 50, mk_real_le_fn()); // ≤
f.add_infix(">=", 50, mk_real_ge_fn());
f.add_infix("\u2265", 50, mk_real_ge_fn()); // ≥
f.add_infix("<", 50, mk_real_lt_fn());
f.add_infix(">", 50, mk_real_gt_fn());
add_infixl(env, ios, "+", 65, mk_real_add_fn());
add_infixl(env, ios, "-", 65, mk_real_sub_fn());
add_prefix(env, ios, "-", 75, mk_real_neg_fn());
add_infixl(env, ios, "*", 70, mk_real_mul_fn());
add_infixl(env, ios, "/", 70, mk_real_div_fn());
add_mixfixc(env, ios, {"|", "|"}, 55, mk_real_abs_fn());
add_infix(env, ios, "<=", 50, mk_real_le_fn());
add_infix(env, ios, "\u2264", 50, mk_real_le_fn()); // ≤
add_infix(env, ios, ">=", 50, mk_real_ge_fn());
add_infix(env, ios, "\u2265", 50, mk_real_ge_fn()); // ≥
add_infix(env, ios, "<", 50, mk_real_lt_fn());
add_infix(env, ios, ">", 50, mk_real_gt_fn());
f.add_coercion(mk_nat_to_int_fn());
f.add_coercion(mk_int_to_real_fn());
f.add_coercion(mk_nat_to_real_fn());
add_coercion(env, mk_nat_to_int_fn());
add_coercion(env, mk_int_to_real_fn());
add_coercion(env, mk_nat_to_real_fn());
// implicit arguments for builtin axioms
f.mark_implicit_arguments(mk_cast_fn(), 2);
f.mark_implicit_arguments(mk_mp_fn(), 2);
f.mark_implicit_arguments(mk_discharge_fn(), 2);
f.mark_implicit_arguments(mk_refl_fn(), 1);
f.mark_implicit_arguments(mk_subst_fn(), 4);
add_alias(f, "Subst", "SubstP");
f.mark_implicit_arguments("SubstP", 3);
f.mark_implicit_arguments(mk_trans_ext_fn(), 6);
f.mark_implicit_arguments(mk_eta_fn(), 2);
f.mark_implicit_arguments(mk_abst_fn(), 4);
f.mark_implicit_arguments(mk_imp_antisym_fn(), 2);
f.mark_implicit_arguments(mk_dom_inj_fn(), 4);
f.mark_implicit_arguments(mk_ran_inj_fn(), 4);
mark_implicit_arguments(env, mk_cast_fn(), 2);
mark_implicit_arguments(env, mk_mp_fn(), 2);
mark_implicit_arguments(env, mk_discharge_fn(), 2);
mark_implicit_arguments(env, mk_refl_fn(), 1);
mark_implicit_arguments(env, mk_subst_fn(), 4);
add_alias(env, "Subst", "SubstP");
mark_implicit_arguments(env, "SubstP", 3);
mark_implicit_arguments(env, mk_trans_ext_fn(), 6);
mark_implicit_arguments(env, mk_eta_fn(), 2);
mark_implicit_arguments(env, mk_abst_fn(), 4);
mark_implicit_arguments(env, mk_imp_antisym_fn(), 2);
mark_implicit_arguments(env, mk_dom_inj_fn(), 4);
mark_implicit_arguments(env, mk_ran_inj_fn(), 4);
// implicit arguments for basic theorems
f.mark_implicit_arguments(mk_absurd_fn(), 1);
f.mark_implicit_arguments(mk_double_neg_elim_fn(), 1);
f.mark_implicit_arguments(mk_mt_fn(), 2);
f.mark_implicit_arguments(mk_contrapos_fn(), 2);
f.mark_implicit_arguments(mk_eq_mp_fn(), 2);
f.mark_implicit_arguments(mk_not_imp1_fn(), 2);
f.mark_implicit_arguments(mk_not_imp2_fn(), 2);
f.mark_implicit_arguments(mk_conj_fn(), 2);
f.mark_implicit_arguments(mk_conjunct1_fn(), 2);
f.mark_implicit_arguments(mk_conjunct2_fn(), 2);
f.mark_implicit_arguments(mk_disj1_fn(), 1);
f.mark_implicit_arguments(mk_disj2_fn(), 1);
f.mark_implicit_arguments(mk_disj_cases_fn(), 3);
f.mark_implicit_arguments(mk_refute_fn(), 1);
f.mark_implicit_arguments(mk_symm_fn(), 3);
f.mark_implicit_arguments(mk_trans_fn(), 4);
f.mark_implicit_arguments(mk_eqt_elim_fn(), 1);
f.mark_implicit_arguments(mk_eqt_intro_fn(), 1);
f.mark_implicit_arguments(mk_congr1_fn(), 4);
f.mark_implicit_arguments(mk_congr2_fn(), 4);
f.mark_implicit_arguments(mk_congr_fn(), 6);
f.mark_implicit_arguments(mk_forall_elim_fn(), 2);
f.mark_implicit_arguments(mk_forall_intro_fn(), 2);
f.mark_implicit_arguments(mk_exists_elim_fn(), 3);
f.mark_implicit_arguments(mk_exists_intro_fn(), 2);
mark_implicit_arguments(env, mk_absurd_fn(), 1);
mark_implicit_arguments(env, mk_double_neg_elim_fn(), 1);
mark_implicit_arguments(env, mk_mt_fn(), 2);
mark_implicit_arguments(env, mk_contrapos_fn(), 2);
mark_implicit_arguments(env, mk_eq_mp_fn(), 2);
mark_implicit_arguments(env, mk_not_imp1_fn(), 2);
mark_implicit_arguments(env, mk_not_imp2_fn(), 2);
mark_implicit_arguments(env, mk_conj_fn(), 2);
mark_implicit_arguments(env, mk_conjunct1_fn(), 2);
mark_implicit_arguments(env, mk_conjunct2_fn(), 2);
mark_implicit_arguments(env, mk_disj1_fn(), 1);
mark_implicit_arguments(env, mk_disj2_fn(), 1);
mark_implicit_arguments(env, mk_disj_cases_fn(), 3);
mark_implicit_arguments(env, mk_refute_fn(), 1);
mark_implicit_arguments(env, mk_symm_fn(), 3);
mark_implicit_arguments(env, mk_trans_fn(), 4);
mark_implicit_arguments(env, mk_eqt_elim_fn(), 1);
mark_implicit_arguments(env, mk_eqt_intro_fn(), 1);
mark_implicit_arguments(env, mk_congr1_fn(), 4);
mark_implicit_arguments(env, mk_congr2_fn(), 4);
mark_implicit_arguments(env, mk_congr_fn(), 6);
mark_implicit_arguments(env, mk_forall_elim_fn(), 2);
mark_implicit_arguments(env, mk_forall_intro_fn(), 2);
mark_implicit_arguments(env, mk_exists_elim_fn(), 3);
mark_implicit_arguments(env, mk_exists_intro_fn(), 2);
}
}

View file

@ -8,6 +8,7 @@ Author: Leonardo de Moura
namespace lean {
constexpr unsigned g_eq_precedence = 50;
constexpr unsigned g_arrow_precedence = 25;
class frontend;
void init_builtin_notation(frontend & fe);
class environment;
class io_state;
void init_builtin_notation(environment const & env, io_state & st);
}

View file

@ -135,13 +135,15 @@ static name g_unused = name::mk_internal_unique_name();
operators.
*/
class parser::imp {
friend class parser;
typedef scoped_map<name, unsigned, name_hash, name_eq> local_decls;
typedef name_map<expr> builtins;
typedef std::pair<unsigned, unsigned> pos_info;
typedef expr_map<pos_info> expr_pos_info;
typedef expr_map<tactic> tactic_hints; // a mapping from placeholder to tactic
typedef buffer<std::tuple<pos_info, name, expr, bool>> bindings_buffer;
frontend & m_frontend;
environment m_env;
io_state m_io_state;
scanner m_scanner;
frontend_elaborator m_elaborator;
type_inferer m_type_inferer;
@ -181,8 +183,8 @@ class parser::imp {
template<typename F>
typename std::result_of<F(lua_State * L)>::type using_script(F && f) {
return m_script_state->apply([&](lua_State * L) {
set_io_state set1(L, m_frontend.get_state());
set_environment set2(L, m_frontend.get_environment());
set_io_state set1(L, m_io_state);
set_environment set2(L, m_env);
return f(L);
});
}
@ -190,8 +192,8 @@ class parser::imp {
template<typename F>
void code_with_callbacks(F && f) {
m_script_state->apply([&](lua_State * L) {
set_io_state set1(L, m_frontend.get_state());
set_environment set2(L, m_frontend.get_environment());
set_io_state set1(L, m_io_state);
set_environment set2(L, m_env);
m_script_state->exec_unprotected([&]() {
f();
});
@ -319,10 +321,10 @@ class parser::imp {
/*@{*/
void display_error_pos(unsigned line, unsigned pos) {
regular(m_frontend) << "Error (line: " << line;
regular(m_io_state) << "Error (line: " << line;
if (pos != static_cast<unsigned>(-1))
regular(m_frontend) << ", pos: " << pos;
regular(m_frontend) << ")";
regular(m_io_state) << ", pos: " << pos;
regular(m_io_state) << ")";
}
void display_error_pos(pos_info const & p) { display_error_pos(p.first, p.second); }
@ -341,7 +343,7 @@ class parser::imp {
void display_error(char const * msg, unsigned line, unsigned pos) {
display_error_pos(line, pos);
regular(m_frontend) << " " << msg << endl;
regular(m_io_state) << " " << msg << endl;
}
void display_error(char const * msg) {
@ -354,7 +356,7 @@ class parser::imp {
display_error_pos(some_expr(m_elaborator.get_original(*main_expr)));
else
display_error_pos(main_expr);
regular(m_frontend) << " " << ex << endl;
regular(m_io_state) << " " << ex << endl;
}
struct lean_pos_info_provider : public pos_info_provider {
@ -370,25 +372,25 @@ class parser::imp {
};
void display_error(elaborator_exception const & ex) {
formatter fmt = m_frontend.get_state().get_formatter();
options opts = m_frontend.get_state().get_options();
formatter fmt = m_io_state.get_formatter();
options opts = m_io_state.get_options();
lean_pos_info_provider pos_provider(*this);
regular(m_frontend) << mk_pair(ex.get_justification().pp(fmt, opts, &pos_provider, true), opts) << endl;
regular(m_io_state) << mk_pair(ex.get_justification().pp(fmt, opts, &pos_provider, true), opts) << endl;
}
void display_error(script_exception const & ex) {
switch (ex.get_source()) {
case script_exception::source::String:
display_error_pos(ex.get_line() + m_last_script_pos.first - 1, static_cast<unsigned>(-1));
regular(m_frontend) << " executing script," << ex.get_msg() << endl;
regular(m_io_state) << " executing script," << ex.get_msg() << endl;
break;
case script_exception::source::File:
display_error_pos(m_last_script_pos);
regular(m_frontend) << " executing external script (" << ex.get_filename() << ":" << ex.get_line() << ")," << ex.get_msg() << endl;
regular(m_io_state) << " executing external script (" << ex.get_filename() << ":" << ex.get_line() << ")," << ex.get_msg() << endl;
break;
case script_exception::source::Unknown:
display_error_pos(m_last_script_pos);
regular(m_frontend) << " executing script, but could not decode position information, " << ex.what() << endl;
regular(m_io_state) << " executing script, but could not decode position information, " << ex.what() << endl;
break;
}
}
@ -446,7 +448,7 @@ class parser::imp {
throw;
} catch (interrupted & ex) {
if (m_verbose)
regular(m_frontend) << "!!!Interrupted!!!" << endl;
regular(m_io_state) << "!!!Interrupted!!!" << endl;
reset_interrupt();
sync();
if (m_use_exceptions)
@ -508,7 +510,7 @@ class parser::imp {
return parse_level_max();
} else {
next();
return m_frontend.get_uvar(id);
return m_env->get_uvar(id);
}
}
@ -586,7 +588,7 @@ class parser::imp {
\brief Return the size of the implicit vector associated with the given denotation.
*/
unsigned get_implicit_vector_size(expr const & d) {
return m_frontend.get_implicit_arguments(d).size();
return get_implicit_arguments(m_env, d).size();
}
/**
@ -597,7 +599,7 @@ class parser::imp {
std::vector<bool> const * r = nullptr;
unsigned m = std::numeric_limits<unsigned>::max();
for (expr const & d : ds) {
std::vector<bool> const & v = m_frontend.get_implicit_arguments(d);
std::vector<bool> const & v = get_implicit_arguments(m_env, d);
unsigned s = v.size();
if (s == 0) {
return v;
@ -803,12 +805,12 @@ class parser::imp {
to check if \c id is a builtin symbol. If it is not throws an error.
*/
expr get_name_ref(name const & id, pos_info const & p) {
optional<object> obj = m_frontend.find_object(id);
optional<object> obj = m_env->find_object(id);
if (obj) {
object_kind k = obj->kind();
if (k == object_kind::Definition || k == object_kind::Postulate || k == object_kind::Builtin) {
if (m_frontend.has_implicit_arguments(obj->get_name())) {
std::vector<bool> const & imp_args = m_frontend.get_implicit_arguments(obj->get_name());
if (has_implicit_arguments(m_env, obj->get_name())) {
std::vector<bool> const & imp_args = get_implicit_arguments(m_env, obj->get_name());
buffer<expr> args;
pos_info p = pos();
expr f = (k == object_kind::Builtin) ? obj->get_value() : mk_constant(obj->get_name());
@ -850,7 +852,7 @@ class parser::imp {
if (it != m_local_decls.end()) {
return save(mk_var(m_num_local_decls - it->second - 1), p);
} else {
operator_info op = m_frontend.find_nud(id);
operator_info op = find_nud(m_env, id);
if (op) {
switch (op.get_fixity()) {
case fixity::Prefix: return parse_prefix(op);
@ -882,7 +884,7 @@ class parser::imp {
if (it != m_local_decls.end()) {
return save(mk_app(left, save(mk_var(m_num_local_decls - it->second - 1), p)), p2);
} else {
operator_info op = m_frontend.find_led(id);
operator_info op = find_led(m_env, id);
if (op) {
switch (op.get_fixity()) {
case fixity::Infix: return parse_infix(left, op);
@ -1205,7 +1207,7 @@ class parser::imp {
return ::lean::apply_tactic(pr, pr_type);
} else {
name n = check_identifier_next("invalid apply command, identifier, '(' expr ')', or 'script-block' expected");
optional<object> o = m_frontend.find_object(n);
optional<object> o = m_env->find_object(n);
if (o && (o->is_theorem() || o->is_axiom())) {
return ::lean::apply_tactic(n);
} else {
@ -1306,7 +1308,7 @@ class parser::imp {
if (it != m_local_decls.end()) {
return app_lbp;
} else {
optional<unsigned> prec = m_frontend.get_lbp(id);
optional<unsigned> prec = get_lbp(m_env, id);
if (prec)
return *prec;
else
@ -1352,11 +1354,11 @@ class parser::imp {
found = true;
}
if (found)
m_frontend.mark_implicit_arguments(n, imp_args.size(), imp_args.data());
mark_implicit_arguments(m_env, n, imp_args.size(), imp_args.data());
}
void display_proof_state(proof_state s) {
regular(m_frontend) << "Proof state:\n" << s << endl;
regular(m_io_state) << "Proof state:\n" << s << endl;
}
void display_proof_state_if_interactive(proof_state s) {
@ -1375,7 +1377,7 @@ class parser::imp {
proof_state_seq::maybe_pair r;
code_with_callbacks([&]() {
// t may have call-backs we should set ios in the script_state
proof_state_seq seq = t(m_frontend.get_environment(), m_frontend.get_state(), s);
proof_state_seq seq = t(m_env, m_io_state, s);
r = seq.pull();
});
if (r) {
@ -1403,9 +1405,9 @@ class parser::imp {
// Example: apply_tactic.
metavar_env menv = s.get_menv().copy();
buffer<unification_constraint> ucs;
expr pr_type = type_checker(m_frontend.get_environment()).infer_type(pr, ctx, menv, ucs);
expr pr_type = type_checker(m_env).infer_type(pr, ctx, menv, ucs);
ucs.push_back(mk_convertible_constraint(ctx, pr_type, expected_type, mk_type_match_justification(ctx, expected_type, pr)));
elaborator elb(m_frontend.get_environment(), menv, ucs.size(), ucs.data(), m_frontend.get_options());
elaborator elb(m_env, menv, ucs.size(), ucs.data(), m_io_state.get_options());
metavar_env new_menv = elb.next();
pr = new_menv->instantiate_metavars(pr);
if (has_metavar(pr))
@ -1604,7 +1606,7 @@ class parser::imp {
context mvar_ctx(to_list(new_entries.begin(), new_entries.end()));
if (!m_type_inferer.is_proposition(mvar_type, mvar_ctx))
throw exception("failed to synthesize metavar, its type is not a proposition");
proof_state s = to_proof_state(m_frontend.get_environment(), mvar_ctx, mvar_type);
proof_state s = to_proof_state(m_env, mvar_ctx, mvar_type);
std::pair<optional<tactic>, pos_info> hint_and_pos = get_tactic_for(mvar);
if (hint_and_pos.first) {
// metavariable has an associated tactic hint
@ -1669,13 +1671,13 @@ class parser::imp {
if (has_metavar(val))
throw exception("invalid definition, value still contains metavariables after elaboration");
if (is_definition) {
m_frontend.add_definition(id, type, val);
m_env->add_definition(id, type, val);
if (m_verbose)
regular(m_frontend) << " Defined: " << id << endl;
regular(m_io_state) << " Defined: " << id << endl;
} else {
m_frontend.add_theorem(id, type, val);
m_env->add_theorem(id, type, val);
if (m_verbose)
regular(m_frontend) << " Proved: " << id << endl;
regular(m_io_state) << " Proved: " << id << endl;
}
register_implicit_arguments(id, bindings);
}
@ -1719,11 +1721,11 @@ class parser::imp {
type = m_elaborator(mk_abstraction(false, bindings, type_body));
}
if (is_var)
m_frontend.add_var(id, type);
m_env->add_var(id, type);
else
m_frontend.add_axiom(id, type);
m_env->add_axiom(id, type);
if (m_verbose)
regular(m_frontend) << " Assumed: " << id << endl;
regular(m_io_state) << " Assumed: " << id << endl;
register_implicit_arguments(id, bindings);
}
@ -1747,15 +1749,15 @@ class parser::imp {
parse_simple_bindings(bindings, false, false);
for (auto b : bindings) {
name const & id = std::get<1>(b);
if (m_frontend.find_object(id))
throw already_declared_exception(m_frontend.get_environment(), id);
if (m_env->find_object(id))
throw already_declared_exception(m_env, id);
}
for (auto b : bindings) {
name const & id = std::get<1>(b);
expr const & type = std::get<2>(b);
m_frontend.add_var(id, type);
m_env->add_var(id, type);
if (m_verbose)
regular(m_frontend) << " Assumed: " << id << endl;
regular(m_io_state) << " Assumed: " << id << endl;
}
}
@ -1773,9 +1775,9 @@ class parser::imp {
void parse_eval() {
next();
expr v = m_elaborator(parse_expr());
normalizer norm(m_frontend.get_environment());
normalizer norm(m_env);
expr r = norm(v);
regular(m_frontend) << r << endl;
regular(m_io_state) << r << endl;
}
/** \brief Parse
@ -1791,27 +1793,27 @@ class parser::imp {
if (opt_id == g_env_kwd) {
if (curr_is_nat()) {
unsigned i = parse_unsigned("invalid argument, value does not fit in a machine integer");
auto end = m_frontend.end_objects();
auto beg = m_frontend.begin_objects();
auto end = m_env->end_objects();
auto beg = m_env->begin_objects();
auto it = end;
while (it != beg && i != 0) {
--i;
--it;
}
for (; it != end; ++it) {
regular(m_frontend) << *it << endl;
regular(m_io_state) << *it << endl;
}
} else {
regular(m_frontend) << m_frontend << endl;
regular(m_io_state) << m_env << endl;
}
} else if (opt_id == g_options_kwd) {
regular(m_frontend) << pp(m_frontend.get_state().get_options()) << endl;
regular(m_io_state) << pp(m_io_state.get_options()) << endl;
} else {
throw parser_error("invalid Show command, expression, 'Options' or 'Environment' expected", m_last_cmd_pos);
}
} else {
expr v = m_elaborator(parse_expr());
regular(m_frontend) << v << endl;
regular(m_io_state) << v << endl;
}
}
@ -1819,12 +1821,12 @@ class parser::imp {
void parse_check() {
next();
expr v = m_elaborator(parse_expr());
expr t = infer_type(v, m_frontend.get_environment());
formatter fmt = m_frontend.get_state().get_formatter();
options opts = m_frontend.get_state().get_options();
expr t = infer_type(v, m_env);
formatter fmt = m_io_state.get_formatter();
options opts = m_io_state.get_options();
unsigned indent = get_pp_indent(opts);
format r = group(format{fmt(v, opts), space(), colon(), nest(indent, compose(line(), fmt(t, opts)))});
regular(m_frontend) << mk_pair(r, opts) << endl;
regular(m_io_state) << mk_pair(r, opts) << endl;
}
/** \brief Return the (optional) precedence of a user-defined operator. */
@ -1855,9 +1857,9 @@ class parser::imp {
name name_id = check_identifier_next("invalid operator definition, identifier expected");
expr d = mk_constant(name_id);
switch (fx) {
case fixity::Infix: m_frontend.add_infix(op_id, prec, d); break;
case fixity::Infixl: m_frontend.add_infixl(op_id, prec, d); break;
case fixity::Infixr: m_frontend.add_infixr(op_id, prec, d); break;
case fixity::Infix: add_infix(m_env, m_io_state, op_id, prec, d); break;
case fixity::Infixl: add_infixl(m_env, m_io_state, op_id, prec, d); break;
case fixity::Infixr: add_infixr(m_env, m_io_state, op_id, prec, d); break;
default: lean_unreachable(); // LCOV_EXCL_LINE
}
}
@ -1898,29 +1900,29 @@ class parser::imp {
if (parts.size() == 1) {
if (first_placeholder && prev_placeholder) {
// infix: _ ID _
m_frontend.add_infix(parts[0], prec, d);
add_infix(m_env, m_io_state, parts[0], prec, d);
} else if (first_placeholder) {
// postfix: _ ID
m_frontend.add_postfix(parts[0], prec, d);
add_postfix(m_env, m_io_state, parts[0], prec, d);
} else if (prev_placeholder) {
// prefix: ID _
m_frontend.add_prefix(parts[0], prec, d);
add_prefix(m_env, m_io_state, parts[0], prec, d);
} else {
throw parser_error("invalid notation declaration, at least one placeholder expected", p);
}
} else {
if (first_placeholder && prev_placeholder) {
// mixfixo: _ ID ... ID _
m_frontend.add_mixfixo(parts.size(), parts.data(), prec, d);
add_mixfixo(m_env, m_io_state, parts.size(), parts.data(), prec, d);
} else if (first_placeholder) {
// mixfixr: _ ID ... ID
m_frontend.add_mixfixr(parts.size(), parts.data(), prec, d);
add_mixfixr(m_env, m_io_state, parts.size(), parts.data(), prec, d);
} else if (prev_placeholder) {
// mixfixl: ID _ ... ID _
m_frontend.add_mixfixl(parts.size(), parts.data(), prec, d);
add_mixfixl(m_env, m_io_state, parts.size(), parts.data(), prec, d);
} else {
// mixfixc: ID _ ... _ ID
m_frontend.add_mixfixc(parts.size(), parts.data(), prec, d);
add_mixfixc(m_env, m_io_state, parts.size(), parts.data(), prec, d);
}
}
return;
@ -1941,7 +1943,7 @@ class parser::imp {
void parse_echo() {
next();
std::string msg = check_string_next("invalid echo command, string expected");
regular(m_frontend) << msg << endl;
regular(m_io_state) << msg << endl;
}
/** Parse 'Set' [id] [value] */
@ -1966,9 +1968,9 @@ class parser::imp {
if (k != BoolOption)
throw parser_error(sstream() << "invalid option value, given option is not Boolean", pos());
if (curr_name() == "true")
m_frontend.set_option(id, true);
m_io_state.set_option(id, true);
else if (curr_name() == "false")
m_frontend.set_option(id, false);
m_io_state.set_option(id, false);
else
throw parser_error("invalid Boolean option value, 'true' or 'false' expected", pos());
next();
@ -1976,25 +1978,25 @@ class parser::imp {
case scanner::token::StringVal:
if (k != StringOption)
throw parser_error("invalid option value, given option is not a string", pos());
m_frontend.set_option(id, curr_string());
m_io_state.set_option(id, curr_string());
next();
break;
case scanner::token::NatVal:
if (k != IntOption && k != UnsignedOption)
throw parser_error("invalid option value, given option is not an integer", pos());
m_frontend.set_option(id, parse_unsigned("invalid option value, value does not fit in a machine integer"));
m_io_state.set_option(id, parse_unsigned("invalid option value, value does not fit in a machine integer"));
break;
case scanner::token::DecimalVal:
if (k != DoubleOption)
throw parser_error("invalid option value, given option is not floating point value", pos());
m_frontend.set_option(id, parse_double());
m_io_state.set_option(id, parse_double());
break;
default:
throw parser_error("invalid option value, 'true', 'false', string, integer or decimal value expected", pos());
}
updt_options();
if (m_verbose)
regular(m_frontend) << " Set: " << id << endl;
regular(m_io_state) << " Set: " << id << endl;
}
void parse_import() {
@ -2003,14 +2005,14 @@ class parser::imp {
std::ifstream in(fname);
if (!in.is_open())
throw parser_error(sstream() << "invalid import command, failed to open file '" << fname << "'", m_last_cmd_pos);
if (!m_frontend.get_environment()->mark_imported(fname.c_str())) {
diagnostic(m_frontend) << "Module '" << fname << "' has already been imported" << endl;
if (!m_env->mark_imported(fname.c_str())) {
diagnostic(m_io_state) << "Module '" << fname << "' has already been imported" << endl;
return;
}
try {
if (m_verbose)
regular(m_frontend) << "Importing file '" << fname << "'" << endl;
parser import_parser(m_frontend, in, m_script_state, true /* use exceptions */, false /* not interactive */);
regular(m_io_state) << "Importing file '" << fname << "'" << endl;
parser import_parser(m_env, m_io_state, in, m_script_state, true /* use exceptions */, false /* not interactive */);
import_parser();
} catch (interrupted &) {
throw;
@ -2025,17 +2027,17 @@ class parser::imp {
name opt_id = curr_name();
next();
if (opt_id == g_options_kwd) {
regular(m_frontend) << "Available options:" << endl;
regular(m_io_state) << "Available options:" << endl;
for (auto p : get_option_declarations()) {
auto opt = p.second;
regular(m_frontend) << " " << opt.get_name() << " (" << opt.kind() << ") "
regular(m_io_state) << " " << opt.get_name() << " (" << opt.kind() << ") "
<< opt.get_description() << " (default: " << opt.get_default_value() << ")" << endl;
}
} else {
throw parser_error("invalid help command", m_last_cmd_pos);
}
} else {
regular(m_frontend) << "Available commands:" << endl
regular(m_io_state) << "Available commands:" << endl
<< " Axiom [id] : [type] assert/postulate a new axiom" << endl
<< " Check [expr] type check the given expression" << endl
<< " Definition [id] : [type] := [expr] define a new element" << endl
@ -2055,7 +2057,7 @@ class parser::imp {
<< " Variable [id] : [type] declare/postulate an element of the given type" << endl
<< " Universe [id] [level] declare a new universe variable that is >= the given level" << endl;
#if !defined(LEAN_WINDOWS)
regular(m_frontend) << "Type Ctrl-D to exit" << endl;
regular(m_io_state) << "Type Ctrl-D to exit" << endl;
#endif
}
}
@ -2064,9 +2066,9 @@ class parser::imp {
void parse_coercion() {
next();
expr coercion = parse_expr();
m_frontend.add_coercion(coercion);
add_coercion(m_env, coercion);
if (m_verbose)
regular(m_frontend) << " Coercion " << coercion << endl;
regular(m_io_state) << " Coercion " << coercion << endl;
}
/** \brief Parse a Lean command. */
@ -2122,8 +2124,8 @@ class parser::imp {
/*@}*/
void updt_options() {
m_verbose = get_parser_verbose(m_frontend.get_state().get_options());
m_show_errors = get_parser_show_errors(m_frontend.get_state().get_options());
m_verbose = get_parser_verbose(m_io_state.get_options());
m_show_errors = get_parser_show_errors(m_io_state.get_options());
}
/**
@ -2147,11 +2149,12 @@ class parser::imp {
void parse_script_expr() { return parse_script(true); }
public:
imp(frontend & fe, std::istream & in, script_state * S, bool use_exceptions, bool interactive):
m_frontend(fe),
imp(environment const & env, io_state const & st, std::istream & in, script_state * S, bool use_exceptions, bool interactive):
m_env(env),
m_io_state(st),
m_scanner(in),
m_elaborator(fe),
m_type_inferer(fe.get_environment()),
m_elaborator(env),
m_type_inferer(env),
m_use_exceptions(use_exceptions),
m_interactive(interactive) {
m_script_state = S;
@ -2162,21 +2165,21 @@ public:
scan();
}
static void show_prompt(bool interactive, frontend & fe) {
static void show_prompt(bool interactive, io_state const & ios) {
if (interactive) {
regular(fe) << "# ";
regular(fe).flush();
regular(ios) << "# ";
regular(ios).flush();
}
}
void show_prompt() {
show_prompt(m_interactive, m_frontend);
show_prompt(m_interactive, m_io_state);
}
void show_tactic_prompt() {
if (m_interactive) {
regular(m_frontend) << "## ";
regular(m_frontend).flush();
regular(m_io_state) << "## ";
regular(m_io_state).flush();
}
}
@ -2216,9 +2219,14 @@ public:
}
};
parser::parser(frontend & fe, std::istream & in, script_state * S, bool use_exceptions, bool interactive) {
parser::imp::show_prompt(interactive, fe);
m_ptr.reset(new imp(fe, in, S, use_exceptions, interactive));
parser::parser(environment const & env, io_state const & ios, std::istream & in, script_state * S, bool use_exceptions, bool interactive) {
parser::imp::show_prompt(interactive, ios);
m_ptr.reset(new imp(env, ios, in, S, use_exceptions, interactive));
}
parser::parser(environment const & env, std::istream & in, script_state * S, bool use_exceptions, bool interactive):
parser(env, io_state(), in, S, use_exceptions, interactive) {
m_ptr->m_io_state.set_formatter(mk_pp_formatter(m_ptr->m_env));
}
parser::~parser() {
@ -2232,7 +2240,15 @@ expr parser::parse_expr() {
return m_ptr->parse_expr_main();
}
shell::shell(frontend & fe, script_state * S):m_frontend(fe), m_script_state(S) {
io_state parser::get_io_state() const {
return m_ptr->m_io_state;
}
shell::shell(environment const & env, io_state const & ios, script_state * S):m_env(env), m_io_state(ios), m_script_state(S) {
}
shell::shell(environment const & env, script_state * S):m_env(env), m_io_state(), m_script_state(S) {
m_io_state.set_formatter(mk_pp_formatter(m_env));
}
shell::~shell() {
@ -2248,37 +2264,29 @@ bool shell::operator()() {
add_history(input);
std::istringstream strm(input);
{
parser p(m_frontend, strm, m_script_state, false, false);
parser p(m_env, m_io_state, strm, m_script_state, false, false);
if (!p())
errors = true;
}
free(input);
}
#else
parser p(m_frontend, std::cin, m_script_state, false, true);
parser p(m_env, m_io_state, std::cin, m_script_state, false, true);
return p();
#endif
}
bool parse_commands(frontend & fe, std::istream & in, script_state * S, bool use_exceptions, bool interactive) {
return parser(fe, in, S, use_exceptions, interactive)();
}
bool parse_commands(environment const & env, io_state & st, std::istream & in, script_state * S, bool use_exceptions, bool interactive) {
frontend f(env, st);
bool r = parse_commands(f, in, S, use_exceptions, interactive);
st = f.get_state();
bool parse_commands(environment const & env, io_state & ios, std::istream & in, script_state * S, bool use_exceptions, bool interactive) {
parser p(env, ios, in, S, use_exceptions, interactive);
bool r = p();
ios = p.get_io_state();
return r;
}
expr parse_expr(frontend & fe, std::istream & in, script_state * S, bool use_exceptions) {
return parser(fe, in, S, use_exceptions).parse_expr();
}
expr parse_expr(environment const & env, io_state & st, std::istream & in, script_state * S, bool use_exceptions) {
frontend f(env, st);
expr r = parse_expr(f, in, S, use_exceptions);
st = f.get_state();
expr parse_expr(environment const & env, io_state & ios, std::istream & in, script_state * S, bool use_exceptions) {
parser p(env, ios, in, S, use_exceptions);
expr r = p.parse_expr();
ios = p.get_io_state();
return r;
}
}

View file

@ -6,18 +6,18 @@ Author: Leonardo de Moura
*/
#pragma once
#include <iostream>
#include "kernel/environment.h"
#include "library/io_state.h"
namespace lean {
class script_state;
class frontend;
class io_state;
class environment;
/** \brief Functional object for parsing commands and expressions */
class parser {
class imp;
std::unique_ptr<imp> m_ptr;
public:
parser(frontend & fe, std::istream & in, script_state * S, bool use_exceptions = true, bool interactive = false);
parser(environment const & env, io_state const & st, std::istream & in, script_state * S, bool use_exceptions = true, bool interactive = false);
parser(environment const & env, std::istream & in, script_state * S, bool use_exceptions = true, bool interactive = false);
~parser();
/** \brief Parse a sequence of commands */
@ -25,21 +25,24 @@ public:
/** \brief Parse a single expression */
expr parse_expr();
io_state get_io_state() const;
};
/** \brief Implements the Read Eval Print loop */
class shell {
frontend & m_frontend;
script_state * m_script_state;
environment m_env;
io_state m_io_state;
script_state * m_script_state;
public:
shell(frontend & fe, script_state * S);
shell(environment const & env, io_state const & st, script_state * S);
shell(environment const & env, script_state * S);
~shell();
bool operator()();
io_state get_io_state() const { return m_io_state; }
};
bool parse_commands(frontend & fe, std::istream & in, script_state * S = nullptr, bool use_exceptions = true, bool interactive = false);
bool parse_commands(environment const & env, io_state & st, std::istream & in, script_state * S = nullptr, bool use_exceptions = true, bool interactive = false);
expr parse_expr(frontend & fe, std::istream & in, script_state * S = nullptr, bool use_exceptions = true);
expr parse_expr(environment const & env, io_state & st, std::istream & in, script_state * S = nullptr, bool use_exceptions = true);
}

View file

@ -1377,17 +1377,4 @@ public:
formatter mk_pp_formatter(ro_environment const & env) {
return mk_formatter(pp_formatter_cell(env));
}
std::ostream & operator<<(std::ostream & out, frontend const & fe) {
options const & opts = fe.get_state().get_options();
formatter fmt = mk_pp_formatter(fe.get_environment());
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);
});
return out;
}
}

View file

@ -125,8 +125,10 @@ static int parse_lean_cmds(lua_State * L) {
}
static int mk_environment(lua_State * L) {
frontend f;
return push_environment(L, f.get_environment());
environment env;
io_state ios;
init_frontend(env, ios);
return push_environment(L, env);
}
static int mk_lean_formatter(lua_State * L) {

View file

@ -16,6 +16,7 @@ Author: Leonardo de Moura
#include "util/script_state.h"
#include "util/thread.h"
#include "kernel/printer.h"
#include "kernel/environment.h"
#include "library/io_state.h"
#include "library/kernel_bindings.h"
#include "frontends/lean/parser.h"
@ -26,12 +27,13 @@ Author: Leonardo de Moura
#include "githash.h" // NOLINT
using lean::shell;
using lean::frontend;
using lean::parser;
using lean::script_state;
using lean::unreachable_reached;
using lean::invoke_debugger;
using lean::notify_assertion_violation;
using lean::environment;
using lean::io_state;
enum class input_kind { Unspecified, Lean, Lua };
@ -133,9 +135,11 @@ int main(int argc, char ** argv) {
#else
std::cout << "Type Ctrl-D or 'Exit.' to exit or 'Help.' for help."<< std::endl;
#endif
frontend f;
environment env;
io_state ios;
init_frontend(env, ios);
script_state S;
shell sh(f, &S);
shell sh(env, &S);
return sh() ? 0 : 1;
} else {
lean_assert(default_k == input_kind::Lua);
@ -143,7 +147,9 @@ int main(int argc, char ** argv) {
S.dostring(g_lua_repl);
}
} else {
frontend f;
environment env;
io_state ios;
init_frontend(env, ios);
script_state S;
bool ok = true;
for (int i = optind; i < argc; i++) {
@ -162,8 +168,7 @@ int main(int argc, char ** argv) {
std::cerr << "Failed to open file '" << argv[i] << "'\n";
return 1;
}
parser p(f, in, &S, false, false);
if (!p())
if (!parse_commands(env, ios, in, &S, false, false))
ok = false;
} else if (k == input_kind::Lua) {
try {

View file

@ -17,11 +17,11 @@ Author: Leonardo de Moura
using namespace lean;
static void tst1() {
frontend f;
f.add_uvar("tst");
frontend c = f.mk_child();
lean_assert(c.get_uvar("tst") == f.get_uvar("tst"));
lean_assert(f.get_environment()->has_children());
environment env; io_state ios; init_frontend(env, ios);
env->add_uvar("tst");
environment c = env->mk_child();
lean_assert(c->get_uvar("tst") == env->get_uvar("tst"));
lean_assert(env->has_children());
}
static void tst2() {
@ -53,14 +53,14 @@ static void tst2() {
}
static void tst3() {
frontend f;
environment env;
std::cout << "====================\n";
std::cout << f << "\n";
std::cout << env << "\n";
}
static void tst4() {
frontend f;
formatter fmt = mk_pp_formatter(f);
environment env; io_state ios; init_frontend(env, ios);
formatter fmt = mk_pp_formatter(env);
context c;
c = extend(c, "x", Bool);
c = extend(c, "y", Bool);
@ -73,18 +73,18 @@ static void tst4() {
static void tst5() {
std::cout << "=================\n";
frontend f;
formatter fmt = mk_pp_formatter(f);
f.add_var("A", Type());
f.add_var("x", Const("A"));
optional<object> obj = f.find_object("x");
environment env; io_state ios; init_frontend(env, ios);
formatter fmt = mk_pp_formatter(env);
env->add_var("A", Type());
env->add_var("x", Const("A"));
optional<object> obj = env->find_object("x");
lean_assert(obj);
lean_assert(obj->get_name() == "x");
std::cout << fmt(*obj) << "\n";
optional<object> obj2 = f.find_object("y");
optional<object> obj2 = env->find_object("y");
lean_assert(!obj2);
try {
f.get_object("y");
env->get_object("y");
lean_unreachable();
} catch (unknown_name_exception & ex) {
std::cout << ex.what() << " " << ex.get_name() << "\n";
@ -101,61 +101,60 @@ public:
static void tst6() {
std::cout << "=================\n";
frontend f;
environment env;
environment env; io_state ios; init_frontend(env, ios);
env->add_neutral_object(new alien_cell());
formatter fmt = mk_pp_formatter(f);
formatter fmt = mk_pp_formatter(env);
std::cout << fmt(env) << "\n";
}
static void tst7() {
frontend f;
formatter fmt = mk_pp_formatter(f);
environment env; io_state ios; init_frontend(env, ios);
formatter fmt = mk_pp_formatter(env);
std::cout << fmt(And(Const("x"), Const("y"))) << "\n";
}
static void tst8() {
frontend fe;
formatter fmt = mk_pp_formatter(fe);
fe.add_infixl("<-$->", 10, mk_refl_fn());
std::cout << fmt(*(fe.find_object("Trivial"))) << "\n";
environment env; io_state ios; init_frontend(env, ios);
formatter fmt = mk_pp_formatter(env);
add_infixl(env, ios, "<-$->", 10, mk_refl_fn());
std::cout << fmt(*(env->find_object("Trivial"))) << "\n";
}
static void tst9() {
frontend f;
lean_assert(!f.has_children());
environment env; io_state ios; init_frontend(env, ios);
lean_assert(!env->has_children());
{
frontend c = f.mk_child();
lean_assert(f.has_children());
environment c = env->mk_child();
lean_assert(env->has_children());
}
lean_assert(!f.has_children());
f.add_uvar("l", level()+1);
lean_assert(f.get_uvar("l") == level("l"));
try { f.get_uvar("l2"); lean_unreachable(); }
lean_assert(!env->has_children());
env->add_uvar("l", level()+1);
lean_assert(env->get_uvar("l") == level("l"));
try { env->get_uvar("l2"); lean_unreachable(); }
catch (exception &) {}
f.add_definition("x", Bool, True);
object const & obj = f.get_object("x");
env->add_definition("x", Bool, True);
object const & obj = env->get_object("x");
lean_assert(obj.get_name() == "x");
lean_assert(is_bool(obj.get_type()));
lean_assert(obj.get_value() == True);
try { f.get_object("y"); lean_unreachable(); }
try { env->get_object("y"); lean_unreachable(); }
catch (exception &) {}
lean_assert(!f.find_object("y"));
f.add_definition("y", False);
lean_assert(is_bool(f.find_object("y")->get_type()));
lean_assert(f.has_object("y"));
lean_assert(!f.has_object("z"));
lean_assert(!env->find_object("y"));
env->add_definition("y", False);
lean_assert(is_bool(env->find_object("y")->get_type()));
lean_assert(env->has_object("y"));
lean_assert(!env->has_object("z"));
bool found = false;
std::for_each(f.begin_objects(), f.end_objects(), [&](object const & obj) { if (obj.has_name() && obj.get_name() == "y") found = true; });
std::for_each(env->begin_objects(), env->end_objects(), [&](object const & obj) { if (obj.has_name() && obj.get_name() == "y") found = true; });
lean_assert(found);
f.add_postfix("!", 10, Const("factorial"));
add_postfix(env, ios, "!", 10, Const("factorial"));
name parts[] = {"if", "then", "else"};
f.add_mixfixl(3, parts, 10, Const("if"));
add_mixfixl(env, ios, 3, parts, 10, Const("if"));
}
static void tst10() {
frontend f;
formatter fmt = mk_pp_formatter(f);
environment env; io_state ios; init_frontend(env, ios);
formatter fmt = mk_pp_formatter(env);
expr x = Const("xxxxxxxxxxxx");
expr y = Const("y");
expr z = Const("foo");
@ -165,39 +164,39 @@ static void tst10() {
}
static void tst11() {
frontend f;
environment env; io_state ios; init_frontend(env, ios);
expr A = Const("A");
f.add_var("g", Pi({A, Type()}, A >> (A >> A)));
lean_assert(!f.has_implicit_arguments("g"));
f.mark_implicit_arguments("g", {true, false, false});
lean_assert(f.has_implicit_arguments("g"))
name gexp = f.get_explicit_version("g");
lean_assert(f.find_object(gexp));
lean_assert(f.find_object("g")->get_type() == f.find_object(gexp)->get_type());
lean_assert(f.get_implicit_arguments("g") == std::vector<bool>({true})); // the trailing "false" marks are removed
env->add_var("g", Pi({A, Type()}, A >> (A >> A)));
lean_assert(!has_implicit_arguments(env, "g"));
mark_implicit_arguments(env, "g", {true, false, false});
lean_assert(has_implicit_arguments(env, "g"))
name gexp = get_explicit_version(env, "g");
lean_assert(env->find_object(gexp));
lean_assert(env->find_object("g")->get_type() == env->find_object(gexp)->get_type());
lean_assert(get_implicit_arguments(env, "g") == std::vector<bool>({true})); // the trailing "false" marks are removed
try {
f.mark_implicit_arguments("g", {true, false, false});
mark_implicit_arguments(env, "g", {true, false, false});
lean_unreachable();
} catch (exception & ex) {
std::cout << "Expected error: " << ex.what() << std::endl;
}
f.add_var("s", Pi({A, Type()}, A >> (A >> A)));
env->add_var("s", Pi({A, Type()}, A >> (A >> A)));
try {
f.mark_implicit_arguments("s", {true, true, true, true});
mark_implicit_arguments(env, "s", {true, true, true, true});
lean_unreachable();
} catch (exception & ex) {
std::cout << "Expected error: " << ex.what() << std::endl;
}
f.add_var(name{"h", "explicit"}, Pi({A, Type()}, A >> (A >> A)));
f.add_var("h", Pi({A, Type()}, A >> (A >> A)));
env->add_var(name{"h", "explicit"}, Pi({A, Type()}, A >> (A >> A)));
env->add_var("h", Pi({A, Type()}, A >> (A >> A)));
try {
f.mark_implicit_arguments("h", {true, false, false});
mark_implicit_arguments(env, "h", {true, false, false});
lean_unreachable();
} catch (exception & ex) {
std::cout << "Expected error: " << ex.what() << std::endl;
}
try {
f.mark_implicit_arguments("u", {true, false});
mark_implicit_arguments(env, "u", {true, false});
lean_unreachable();
} catch (exception & ex) {
std::cout << "Expected error: " << ex.what() << std::endl;

View file

@ -17,13 +17,14 @@ Author: Leonardo de Moura
#include "frontends/lean/pp.h"
using namespace lean;
static void parse(frontend & fe, char const * str) {
frontend child = fe.mk_child();
static void parse(environment const & env, io_state const & ios, char const * str) {
environment child = env->mk_child();
io_state ios_copy = ios;
std::istringstream in(str);
if (parse_commands(child, in)) {
formatter fmt = mk_pp_formatter(child);
std::for_each(child.begin_local_objects(),
child.end_local_objects(),
if (parse_commands(child, ios_copy, in)) {
formatter fmt = mk_pp_formatter(env);
std::for_each(child->begin_local_objects(),
child->end_local_objects(),
[&](object const & obj) {
std::cout << fmt(obj) << "\n";
std::cout << obj << "\n";
@ -31,9 +32,9 @@ static void parse(frontend & fe, char const * str) {
}
}
static void parse_error(frontend & fe, char const * str) {
static void parse_error(environment const & env, io_state const & ios, char const * str) {
try {
parse(fe, str);
parse(env, ios, str);
lean_unreachable();
} catch (exception & ex) {
std::cout << "expected error: " << ex.what() << "\n";
@ -41,20 +42,20 @@ static void parse_error(frontend & fe, char const * str) {
}
static void tst1() {
frontend fe;
parse(fe, "Variable x : Bool Variable y : Bool Axiom H : x && y || x => x");
parse(fe, "Eval true && true");
parse(fe, "Show true && false Eval true && false");
parse(fe, "Infixl 35 & : and Show true & false & false Eval true & false");
parse(fe, "Notation 100 if _ then _ fi : implies Show if true then false fi");
parse(fe, "Show Pi (A : Type), A -> A");
parse(fe, "Check Pi (A : Type), A -> A");
environment env; io_state ios; init_frontend(env, ios);
parse(env, ios, "Variable x : Bool Variable y : Bool Axiom H : x && y || x => x");
parse(env, ios, "Eval true && true");
parse(env, ios, "Show true && false Eval true && false");
parse(env, ios, "Infixl 35 & : and Show true & false & false Eval true & false");
parse(env, ios, "Notation 100 if _ then _ fi : implies Show if true then false fi");
parse(env, ios, "Show Pi (A : Type), A -> A");
parse(env, ios, "Check Pi (A : Type), A -> A");
}
static void check(frontend & fe, char const * str, expr const & expected) {
static void check(environment const & env, io_state & ios, char const * str, expr const & expected) {
std::istringstream in(str);
try {
expr got = parse_expr(fe, in);
expr got = parse_expr(env, ios, in);
lean_assert(expected == got);
} catch (exception &) {
lean_unreachable();
@ -62,47 +63,47 @@ static void check(frontend & fe, char const * str, expr const & expected) {
}
static void tst2() {
frontend fe;
fe.add_var("x", Bool);
fe.add_var("y", Bool);
fe.add_var("z", Bool);
environment env; io_state ios; init_frontend(env, ios);
env->add_var("x", Bool);
env->add_var("y", Bool);
env->add_var("z", Bool);
expr x = Const("x"); expr y = Const("y"); expr z = Const("z");
check(fe, "x && y", And(x, y));
check(fe, "x && y || z", Or(And(x, y), z));
check(fe, "x || y && z", Or(x, And(y, z)));
check(fe, "x || y || x && z", Or(x, Or(y, And(x, z))));
check(fe, "x || y || x && z => x && y", Implies(Or(x, Or(y, And(x, z))), And(x, y)));
check(fe, "x y x ∧ z ⇒ x ∧ y", Implies(Or(x, Or(y, And(x, z))), And(x, y)));
check(fe, "x⇒y⇒z⇒x", Implies(x, Implies(y, Implies(z, x))));
check(fe, "x=>y=>z=>x", Implies(x, Implies(y, Implies(z, x))));
check(fe, "x=>(y=>z)=>x", Implies(x, Implies(Implies(y, z), x)));
check(env, ios, "x && y", And(x, y));
check(env, ios, "x && y || z", Or(And(x, y), z));
check(env, ios, "x || y && z", Or(x, And(y, z)));
check(env, ios, "x || y || x && z", Or(x, Or(y, And(x, z))));
check(env, ios, "x || y || x && z => x && y", Implies(Or(x, Or(y, And(x, z))), And(x, y)));
check(env, ios, "x y x ∧ z ⇒ x ∧ y", Implies(Or(x, Or(y, And(x, z))), And(x, y)));
check(env, ios, "x⇒y⇒z⇒x", Implies(x, Implies(y, Implies(z, x))));
check(env, ios, "x=>y=>z=>x", Implies(x, Implies(y, Implies(z, x))));
check(env, ios, "x=>(y=>z)=>x", Implies(x, Implies(Implies(y, z), x)));
}
static void tst3() {
frontend fe;
parse(fe, "Help");
parse(fe, "Help Options");
parse_error(fe, "Help Echo");
check(fe, "10.3", mk_real_value(mpq(103, 10)));
parse(fe, "Variable f : Real -> Real. Check f 10.3.");
parse(fe, "Variable g : Type 1 -> Type. Check g Type");
parse_error(fe, "Check fun .");
parse_error(fe, "Definition foo .");
parse_error(fe, "Check a");
parse_error(fe, "Check U");
parse(fe, "Variable h : Real -> Real -> Real. Notation 10 [ _ ; _ ] : h. Check [ 10.3 ; 20.1 ].");
parse_error(fe, "Variable h : Real -> Real -> Real. Notation 10 [ _ ; _ ] : h. Check [ 10.3 | 20.1 ].");
parse_error(fe, "Set pp::indent true");
parse(fe, "Set pp::indent 10");
parse_error(fe, "Set pp::colors foo");
parse_error(fe, "Set pp::colors \"foo\"");
parse(fe, "Set pp::colors true");
parse_error(fe, "Notation 10 : Int::add");
parse_error(fe, "Notation 10 _ : Int::add");
parse(fe, "Notation 10 _ ++ _ : Int::add. Eval 10 ++ 20.");
parse(fe, "Notation 10 _ -- : Int::neg. Eval 10 --");
parse(fe, "Notation 30 -- _ : Int::neg. Eval -- 10");
parse_error(fe, "10 + 30");
environment env; io_state ios; init_frontend(env, ios);
parse(env, ios, "Help");
parse(env, ios, "Help Options");
parse_error(env, ios, "Help Echo");
check(env, ios, "10.3", mk_real_value(mpq(103, 10)));
parse(env, ios, "Variable f : Real -> Real. Check f 10.3.");
parse(env, ios, "Variable g : Type 1 -> Type. Check g Type");
parse_error(env, ios, "Check fun .");
parse_error(env, ios, "Definition foo .");
parse_error(env, ios, "Check a");
parse_error(env, ios, "Check U");
parse(env, ios, "Variable h : Real -> Real -> Real. Notation 10 [ _ ; _ ] : h. Check [ 10.3 ; 20.1 ].");
parse_error(env, ios, "Variable h : Real -> Real -> Real. Notation 10 [ _ ; _ ] : h. Check [ 10.3 | 20.1 ].");
parse_error(env, ios, "Set pp::indent true");
parse(env, ios, "Set pp::indent 10");
parse_error(env, ios, "Set pp::colors foo");
parse_error(env, ios, "Set pp::colors \"foo\"");
parse(env, ios, "Set pp::colors true");
parse_error(env, ios, "Notation 10 : Int::add");
parse_error(env, ios, "Notation 10 _ : Int::add");
parse(env, ios, "Notation 10 _ ++ _ : Int::add. Eval 10 ++ 20.");
parse(env, ios, "Notation 10 _ -- : Int::neg. Eval 10 --");
parse(env, ios, "Notation 30 -- _ : Int::neg. Eval -- 10");
parse_error(env, ios, "10 + 30");
}
int main() {

View file

@ -22,8 +22,8 @@ static expr mk_shared_expr(unsigned depth) {
}
static void tst1() {
frontend f;
formatter fmt = mk_pp_formatter(f);
environment env; io_state ios; init_frontend(env, ios);
formatter fmt = mk_pp_formatter(env);
std::cout << "Basic printer\n";
std::cout << mk_shared_expr(10) << std::endl;
std::cout << "----------------------------\nPretty printer\n";
@ -31,19 +31,19 @@ static void tst1() {
}
static void tst2() {
frontend f;
formatter fmt = mk_pp_formatter(f);
environment env; io_state ios; init_frontend(env, ios);
formatter fmt = mk_pp_formatter(env);
expr a = Const("a");
expr t = Fun({a, Type()}, mk_shared_expr(10));
expr g = Const("g");
std::cout << fmt(g(t, t, t)) << std::endl;
formatter fmt2 = mk_pp_formatter(f);
formatter fmt2 = mk_pp_formatter(env);
std::cout << fmt2(g(t, t, t), options({"lean", "pp", "alias_min_weight"}, 100)) << std::endl;
}
static void tst3() {
frontend f;
formatter fmt = mk_pp_formatter(f);
environment env; io_state ios; init_frontend(env, ios);
formatter fmt = mk_pp_formatter(env);
expr g = Const("g");
expr a = Const("\u03BA");
expr b = Const("\u03C1");
@ -58,28 +58,28 @@ static void tst3() {
}
static void tst4() {
frontend f;
io_state const & s1 = f.get_state();
io_state s2 = f.get_state();
environment env; io_state ios; init_frontend(env, ios);
io_state const & s1 = ios;
io_state s2 = ios;
regular(s1) << And(Const("a"), Const("b")) << "\n";
regular(f) << And(Const("a"), Const("b")) << "\n";
diagnostic(f) << And(Const("a"), Const("b")) << "\n";
f.set_option(name{"lean", "pp", "notation"}, false);
regular(f) << And(Const("a"), Const("b")) << "\n";
regular(ios) << And(Const("a"), Const("b")) << "\n";
diagnostic(ios) << And(Const("a"), Const("b")) << "\n";
ios.set_option(name{"lean", "pp", "notation"}, false);
regular(ios) << And(Const("a"), Const("b")) << "\n";
regular(s1) << And(Const("a"), Const("b")) << "\n";
regular(s2) << And(Const("a"), Const("b")) << "\n";
}
static void tst5() {
frontend f;
environment env; io_state ios; init_frontend(env, ios);
std::shared_ptr<string_output_channel> out(new string_output_channel());
f.set_regular_channel(out);
f.set_option(name{"pp", "unicode"}, true);
f.set_option(name{"lean", "pp", "notation"}, true);
regular(f) << And(Const("a"), Const("b"));
ios.set_regular_channel(out);
ios.set_option(name{"pp", "unicode"}, true);
ios.set_option(name{"lean", "pp", "notation"}, true);
regular(ios) << And(Const("a"), Const("b"));
lean_assert(out->str() == "a ∧ b");
f.set_option(name{"lean", "pp", "notation"}, false);
regular(f) << " " << And(Const("a"), Const("b"));
ios.set_option(name{"lean", "pp", "notation"}, false);
regular(ios) << " " << And(Const("a"), Const("b"));
lean_assert(out->str() == "a ∧ b and a b");
}
@ -91,14 +91,14 @@ static expr mk_deep(unsigned depth) {
}
static void tst6() {
frontend f;
environment env; io_state ios; init_frontend(env, ios);
std::shared_ptr<string_output_channel> out(new string_output_channel());
f.set_regular_channel(out);
ios.set_regular_channel(out);
expr t = mk_deep(10);
f.set_option(name{"lean", "pp", "max_depth"}, 5);
f.set_option(name{"pp", "colors"}, false);
f.set_option(name{"pp", "unicode"}, false);
regular(f) << t;
ios.set_option(name{"lean", "pp", "max_depth"}, 5);
ios.set_option(name{"pp", "colors"}, false);
ios.set_option(name{"pp", "unicode"}, false);
regular(ios) << t;
lean_assert(out->str() == "f (f (f (f (f (...)))))");
}