Create pp::unicode option. The idea is to be able to disable unicode characters, but still be able to use mixfix notation.

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2013-09-03 10:09:19 -07:00
parent e031d7bc10
commit 544229e5d3
28 changed files with 227 additions and 59 deletions

View file

@ -27,7 +27,7 @@ struct frontend::imp {
// Remark: only named objects are stored in the dictionary. // Remark: only named objects are stored in the dictionary.
typedef std::unordered_map<name, operator_info, name_hash, name_eq> operator_table; typedef std::unordered_map<name, operator_info, name_hash, name_eq> operator_table;
typedef std::unordered_map<name, implicit_info, name_hash, name_eq> implicit_table; typedef std::unordered_map<name, implicit_info, name_hash, name_eq> implicit_table;
typedef std::unordered_map<expr, operator_info, expr_hash, std::equal_to<expr>> expr_to_operator; typedef std::unordered_map<expr, list<operator_info>, expr_hash, std::equal_to<expr>> expr_to_operators;
typedef std::unordered_map<expr_pair, expr, expr_pair_hash, expr_pair_eq> coercion_map; typedef std::unordered_map<expr_pair, expr, expr_pair_hash, expr_pair_eq> coercion_map;
typedef std::unordered_set<expr, expr_hash, std::equal_to<expr>> coercion_set; typedef std::unordered_set<expr, expr_hash, std::equal_to<expr>> coercion_set;
@ -36,7 +36,7 @@ struct frontend::imp {
environment m_env; environment m_env;
operator_table m_nud; // nud table for Pratt's parser operator_table m_nud; // nud table for Pratt's parser
operator_table m_led; // led table for Pratt's parser operator_table m_led; // led table for Pratt's parser
expr_to_operator m_expr_to_operator; // map denotations to operators (this is used for pretty printing) expr_to_operators m_expr_to_operators; // map denotations to operators (this is used for pretty printing)
implicit_table m_implicit_table; // track the number of implicit arguments for a symbol. implicit_table m_implicit_table; // track the number of implicit arguments for a symbol.
coercion_map m_coercion_map; // mapping from (given_type, expected_type) -> coercion coercion_map m_coercion_map; // mapping from (given_type, expected_type) -> coercion
coercion_set m_coercion_set; // Set of coercions coercion_set m_coercion_set; // Set of coercions
@ -95,12 +95,18 @@ struct frontend::imp {
} }
/** \brief Find the operator that is used as notation for the given expression. */ /** \brief Find the operator that is used as notation for the given expression. */
operator_info find_op_for(expr const & e) const { operator_info find_op_for(expr const & e, bool unicode) const {
auto it = m_expr_to_operator.find(e); auto it = m_expr_to_operators.find(e);
if (it != m_expr_to_operator.end()) if (it != m_expr_to_operators.end()) {
return it->second; auto l = it->second;
else if (has_parent()) for (auto op : l) {
return m_parent->find_op_for(e); if (unicode || op.is_safe_ascii())
return op;
}
}
if (has_parent())
return m_parent->find_op_for(e, unicode);
else else
return operator_info(); return operator_info();
} }
@ -108,20 +114,26 @@ struct frontend::imp {
/** \brief Remove all internal denotations that are associated with the given operator symbol (aka notation) */ /** \brief Remove all internal denotations that are associated with the given operator symbol (aka notation) */
void remove_bindings(operator_info const & op) { void remove_bindings(operator_info const & op) {
for (expr const & d : op.get_denotations()) { for (expr const & d : op.get_denotations()) {
if (has_parent() && m_parent->find_op_for(d)) { if (has_parent() && m_parent->find_op_for(d, true)) {
// parent has an association for d... we must hide it. // parent has an association for d... we must hide it.
insert(m_expr_to_operator, d, operator_info()); insert(m_expr_to_operators, d, list<operator_info>(operator_info()));
} else { } else {
m_expr_to_operator.erase(d); m_expr_to_operators.erase(d);
} }
} }
} }
/** \brief Add a new entry d -> op in the mapping m_expr_to_operators */
void insert_expr_to_operator_entry(expr const & d, operator_info const & op) {
list<operator_info> & l = m_expr_to_operators[d];
l = cons(op, l);
}
/** \brief Register the new operator in the tables for parsing and pretty printing. */ /** \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) { void register_new_op(operator_info new_op, expr const & d, bool led) {
new_op.add_expr(d); new_op.add_expr(d);
insert_op(new_op, led); insert_op(new_op, led);
insert(m_expr_to_operator, d, new_op); insert_expr_to_operator_entry(d, new_op);
} }
/** /**
@ -173,7 +185,7 @@ struct frontend::imp {
// overload // overload
if (defined_here(old_op, led)) { if (defined_here(old_op, led)) {
old_op.add_expr(d); old_op.add_expr(d);
insert(m_expr_to_operator, d, old_op); insert_expr_to_operator_entry(d, old_op);
} else { } else {
// we must copy the operator because it was defined in // we must copy the operator because it was defined in
// a parent frontend. // a parent frontend.
@ -391,7 +403,7 @@ void frontend::add_mixfixl(unsigned sz, name const * opns, unsigned p, expr cons
void frontend::add_mixfixr(unsigned sz, name const * opns, unsigned p, expr const & d) { m_imp->add_mixfixr(sz, opns, p, d); } void frontend::add_mixfixr(unsigned sz, name const * opns, unsigned p, expr const & d) { m_imp->add_mixfixr(sz, opns, p, d); }
void frontend::add_mixfixc(unsigned sz, name const * opns, unsigned p, expr const & d) { m_imp->add_mixfixc(sz, opns, p, d); } void frontend::add_mixfixc(unsigned sz, name const * opns, unsigned p, expr const & d) { m_imp->add_mixfixc(sz, opns, p, d); }
void frontend::add_mixfixo(unsigned sz, name const * opns, unsigned p, expr const & d) { m_imp->add_mixfixo(sz, opns, p, d); } void frontend::add_mixfixo(unsigned sz, name const * opns, unsigned p, expr const & d) { m_imp->add_mixfixo(sz, opns, p, d); }
operator_info frontend::find_op_for(expr const & n) const { return m_imp->find_op_for(n); } operator_info frontend::find_op_for(expr const & n, bool unicode) const { return m_imp->find_op_for(n, unicode); }
operator_info frontend::find_nud(name const & n) const { return m_imp->find_nud(n); } operator_info frontend::find_nud(name const & n) const { return m_imp->find_nud(n); }
operator_info frontend::find_led(name const & n) const { return m_imp->find_led(n); } operator_info frontend::find_led(name const & n) const { return m_imp->find_led(n); }

View file

@ -93,8 +93,11 @@ public:
return the null operator. return the null operator.
\remark This is used for pretty printing. \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) const; operator_info find_op_for(expr const & e, bool unicode) const;
/** /**
\brief Return the operator (if one exists) that can appear at \brief Return the operator (if one exists) that can appear at
the beginning of a language construct. the beginning of a language construct.

View file

@ -65,6 +65,11 @@ name const & operator_info::get_op_name() const { lean_assert(m_ptr); return car
list<name> const & operator_info::get_op_name_parts() const { lean_assert(m_ptr); return m_ptr->m_op_parts; } list<name> const & operator_info::get_op_name_parts() const { lean_assert(m_ptr); return m_ptr->m_op_parts; }
bool operator_info::is_safe_ascii() const {
auto l = get_op_name_parts();
return std::all_of(l.begin(), l.end(), [](name const & p) { return p.is_safe_ascii(); });
}
operator_info operator_info::copy() const { return operator_info(new imp(*m_ptr)); } operator_info operator_info::copy() const { return operator_info(new imp(*m_ptr)); }
bool operator==(operator_info const & op1, operator_info const & op2) { bool operator==(operator_info const & op1, operator_info const & op2) {

View file

@ -83,6 +83,9 @@ public:
/** \brief Return the operators parts. */ /** \brief Return the operators parts. */
list<name> const & get_op_name_parts() const; list<name> const & get_op_name_parts() const;
/** \brief Return true if all parts of the operator use only safe ASCII characters */
bool is_safe_ascii() const;
/** \brief Return a copy of the operator. */ /** \brief Return a copy of the operator. */
operator_info copy() const; operator_info copy() const;

View file

@ -1137,7 +1137,7 @@ class parser::imp {
regular(m_frontend) << m_frontend << endl; regular(m_frontend) << m_frontend << endl;
} }
} else if (opt_id == g_options_kwd) { } else if (opt_id == g_options_kwd) {
regular(m_frontend) << m_frontend.get_state().get_options() << endl; regular(m_frontend) << pp(m_frontend.get_state().get_options()) << endl;
} else { } else {
throw parser_error("invalid Show command, expression, 'Options' or 'Environment' expected", m_last_cmd_pos); throw parser_error("invalid Show command, expression, 'Options' or 'Environment' expected", m_last_cmd_pos);
} }

View file

@ -145,6 +145,7 @@ class pp_fn {
unsigned m_max_depth; unsigned m_max_depth;
unsigned m_max_steps; unsigned m_max_steps;
bool m_implict; //!< if true show implicit arguments bool m_implict; //!< if true show implicit arguments
bool m_unicode; //!< if true use unicode chars
bool m_coercion; //!< if true show coercions bool m_coercion; //!< if true show coercions
bool m_notation; //!< if true use notation bool m_notation; //!< if true use notation
bool m_extra_lets; //!< introduce extra let-expression to cope with sharing. bool m_extra_lets; //!< introduce extra let-expression to cope with sharing.
@ -197,7 +198,7 @@ class pp_fn {
} }
result pp_ellipsis() { result pp_ellipsis() {
return mk_result(m_notation ? g_ellipsis_n_fmt : g_ellipsis_fmt, 1); return mk_result(m_unicode ? g_ellipsis_n_fmt : g_ellipsis_fmt, 1);
} }
result pp_var(expr const & e) { result pp_var(expr const & e) {
@ -223,14 +224,14 @@ class pp_fn {
} }
result pp_value(expr const & e) { result pp_value(expr const & e) {
return mk_result(to_value(e).pp(m_notation), 1); return mk_result(to_value(e).pp(m_unicode), 1);
} }
result pp_type(expr const & e) { result pp_type(expr const & e) {
if (e == Type()) { if (e == Type()) {
return mk_result(g_Type_fmt, 1); return mk_result(g_Type_fmt, 1);
} else { } else {
return mk_result(format{g_Type_fmt, space(), ::lean::pp(ty_level(e))}, 1); return mk_result(format{g_Type_fmt, space(), ::lean::pp(ty_level(e), m_unicode)}, 1);
} }
} }
@ -312,7 +313,7 @@ class pp_fn {
local_names::mk_scope mk(m_local_names); local_names::mk_scope mk(m_local_names);
expr b = collect_nested_quantifiers(e, is_forall, nested); expr b = collect_nested_quantifiers(e, is_forall, nested);
format head; format head;
if (m_notation) if (m_unicode)
head = is_forall ? g_forall_n_fmt : g_exists_n_fmt; head = is_forall ? g_forall_n_fmt : g_exists_n_fmt;
else else
head = is_forall ? g_forall_fmt : g_exists_fmt; head = is_forall ? g_forall_fmt : g_exists_fmt;
@ -369,7 +370,7 @@ class pp_fn {
if (is_constant(e) && m_local_names.find(const_name(e)) != m_local_names.end()) if (is_constant(e) && m_local_names.find(const_name(e)) != m_local_names.end())
return operator_info(); return operator_info();
else else
return m_frontend.find_op_for(e); return m_frontend.find_op_for(e, m_unicode);
} }
/** /**
@ -760,7 +761,7 @@ class pp_fn {
lean_assert(!T); lean_assert(!T);
result p_lhs = pp_child(abst_domain(e), depth); result p_lhs = pp_child(abst_domain(e), depth);
result p_rhs = pp_arrow_body(abst_body(e), depth); result p_rhs = pp_arrow_body(abst_body(e), depth);
format r_format = group(format{p_lhs.first, space(), m_notation ? g_arrow_n_fmt : g_arrow_fmt, line(), p_rhs.first}); format r_format = group(format{p_lhs.first, space(), m_unicode ? g_arrow_n_fmt : g_arrow_fmt, line(), p_rhs.first});
return mk_result(r_format, p_lhs.second + p_rhs.second + 1); return mk_result(r_format, p_lhs.second + p_rhs.second + 1);
} else { } else {
buffer<std::pair<name, expr>> nested; buffer<std::pair<name, expr>> nested;
@ -770,7 +771,7 @@ class pp_fn {
unsigned head_indent = m_indent; unsigned head_indent = m_indent;
format head; format head;
if (!T && !implicit_args) { if (!T && !implicit_args) {
if (m_notation) { if (m_unicode) {
head = is_lambda(e) ? g_lambda_n_fmt : g_Pi_n_fmt; head = is_lambda(e) ? g_lambda_n_fmt : g_Pi_n_fmt;
head_indent = 2; head_indent = 2;
} else { } else {
@ -987,6 +988,7 @@ class pp_fn {
m_max_depth = get_pp_max_depth(opts); m_max_depth = get_pp_max_depth(opts);
m_max_steps = get_pp_max_steps(opts); m_max_steps = get_pp_max_steps(opts);
m_implict = get_pp_implicit(opts); m_implict = get_pp_implicit(opts);
m_unicode = get_pp_unicode(opts);
m_coercion = get_pp_coercion(opts); m_coercion = get_pp_coercion(opts);
m_notation = get_pp_notation(opts); m_notation = get_pp_notation(opts);
m_extra_lets = get_pp_extra_lets(opts); m_extra_lets = get_pp_extra_lets(opts);
@ -1146,7 +1148,8 @@ class pp_formatter_cell : public formatter_cell {
} }
format pp_uvar_decl(object const & obj, options const & opts) { format pp_uvar_decl(object const & obj, options const & opts) {
return format{highlight_command(format(obj.keyword())), space(), format(obj.get_name()), space(), format("\u2265"), space(), ::lean::pp(obj.get_cnstr_level())}; 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)};
} }
format pp_postulate(object const & obj, options const & opts) { format pp_postulate(object const & obj, options const & opts) {

View file

@ -33,7 +33,7 @@ static char g_normalized[256];
/** \brief Auxiliary class for initializing global variable \c g_normalized. */ /** \brief Auxiliary class for initializing global variable \c g_normalized. */
class init_normalized_table { class init_normalized_table {
void set(int i, char v) { g_normalized[static_cast<unsigned>(i)] = v; } void set(int i, char v) { g_normalized[static_cast<unsigned char>(i)] = v; }
public: public:
init_normalized_table() { init_normalized_table() {
// by default all characters are in group c, // by default all characters are in group c,

View file

@ -195,7 +195,7 @@ std::ostream & operator<<(std::ostream & out, level const & l) {
return out; return out;
} }
format pp(level const & l) { format pp(level const & l, bool unicode) {
switch (kind(l)) { switch (kind(l)) {
case level_kind::UVar: case level_kind::UVar:
if (l.is_bottom()) if (l.is_bottom())
@ -206,19 +206,30 @@ format pp(level const & l) {
if (lift_of(l).is_bottom()) if (lift_of(l).is_bottom())
return format(lift_offset(l)); return format(lift_offset(l));
else else
return format{pp(lift_of(l)), format("+"), format(lift_offset(l))}; return format{pp(lift_of(l), unicode), format("+"), format(lift_offset(l))};
case level_kind::Max: { case level_kind::Max: {
format r = pp(max_level(l, 0)); if (unicode) {
for (unsigned i = 1; i < max_size(l); i++) { format r = pp(max_level(l, 0), unicode);
r += format{space(), format("\u2294"), space()}; for (unsigned i = 1; i < max_size(l); i++) {
r += pp(max_level(l, i)); r += format{space(), format("\u2294"), line()};
r += pp(max_level(l, i), unicode);
}
return group(r);
} else {
format r = format("max");
for (unsigned i = 0; i < max_size(l); i++)
r += format{line(), pp(max_level(l, i), unicode)};
return group(nest(1, format{lp(), r, rp()}));
} }
return r;
}} }}
lean_unreachable(); lean_unreachable();
return format(); return format();
} }
format pp(level const & l, options const & opts) {
return pp(l, get_pp_unicode(opts));
}
level max(std::initializer_list<level> const & l) { level max(std::initializer_list<level> const & l) {
if (l.size() == 1) if (l.size() == 1)
return *(l.begin()); return *(l.begin());

View file

@ -8,6 +8,7 @@ Author: Leonardo de Moura
#include <iostream> #include <iostream>
#include "name.h" #include "name.h"
#include "format.h" #include "format.h"
#include "options.h"
namespace lean { namespace lean {
class environment; class environment;
@ -65,6 +66,7 @@ inline bool is_max (level const & l) { return kind(l) == level_kind::Max; }
inline level const * max_begin_levels(level const & l) { return &max_level(l, 0); } inline level const * max_begin_levels(level const & l) { return &max_level(l, 0); }
inline level const * max_end_levels(level const & l) { return max_begin_levels(l) + max_size(l); } inline level const * max_end_levels(level const & l) { return max_begin_levels(l) + max_size(l); }
format pp(level const & l); format pp(level const & l, bool unicode);
format pp(level const & l, options const & opts = options());
} }
void print(lean::level const & l); void print(lean::level const & l);

View file

@ -108,11 +108,21 @@ static void tst5() {
lean_assert(name(name("foo"), 0u).get_prefix().is_string()); lean_assert(name(name("foo"), 0u).get_prefix().is_string());
} }
static void tst6() {
lean_assert(name({"foo", "bla"}).is_safe_ascii());
lean_assert(name(123u).is_safe_ascii());
lean_assert(name(name(name(230u), "bla"), "foo").is_safe_ascii());
lean_assert(!name({"foo", "b\u2200aaa"}).is_safe_ascii());
lean_assert(!name({"\u2200", "boo"}).is_safe_ascii());
lean_assert(!name(name(name(230u), "bla\u2200"), "foo").is_safe_ascii());
}
int main() { int main() {
tst1(); tst1();
tst2(); tst2();
tst3(); tst3();
tst4(); tst4();
tst5(); tst5();
tst6();
return has_violations() ? 1 : 0; return has_violations() ? 1 : 0;
} }

View file

@ -1,2 +1,2 @@
add_library(util trace.cpp debug.cpp name.cpp exception.cpp add_library(util trace.cpp debug.cpp name.cpp exception.cpp
hash.cpp escaped.cpp bit_tricks.cpp safe_arith.cpp) hash.cpp escaped.cpp bit_tricks.cpp safe_arith.cpp ascii.cpp)

44
src/util/ascii.cpp Normal file
View file

@ -0,0 +1,44 @@
/*
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 <initializer_list>
namespace lean {
static char g_safe_ascii[256];
class init_safe_ascii {
void set(int i, bool v) { g_safe_ascii[static_cast<unsigned char>(i)] = v; }
public:
init_safe_ascii() {
for (int i = 0; i <= 255; i++)
set(i, false);
// digits and characters are safe
for (int i = '0'; i <= '9'; i++) set(i, true);
for (int i = 'a'; i <= 'z'; i++) set(i, true);
for (int i = 'A'; i <= 'Z'; i++) set(i, true);
// the following characters are also safe
for (unsigned char b : {'_', ' ', '\t', '\r', '\n', '(', ')', '{', '}', ':', '.', ',', '\"', '\'', '`', '!', '#',
'=', '<', '>', '@', '^', '|', '&', '~', '+', '-', '*', '/', '\\', '$', '%', '?', ';', '[', ']'})
set(b, true);
}
};
static init_safe_ascii g_init_safe_ascii;
bool is_safe_ascii(char c) {
return g_safe_ascii[static_cast<unsigned char>(c)];
}
bool is_safe_ascii(char const * str) {
if (str) {
while (*str != 0) {
if (!is_safe_ascii(*str))
return false;
str++;
}
}
return true;
}
}

19
src/util/ascii.h Normal file
View file

@ -0,0 +1,19 @@
/*
Copyright (c) 2013 Microsoft Corporation. All rights reserved.
Released under Apache 2.0 license as described in the file LICENSE.
Author: Leonardo de Moura
*/
#pragma once
namespace lean {
/**
\brief Return true iff \c c is a "safe" ASCII characters.
It is a "keyboard" character.
*/
bool is_safe_ascii(char c);
/**
\brief Return true iff the given string contains only "safe"
ASCII character.
*/
bool is_safe_ascii(char const * str);
}

View file

@ -28,6 +28,7 @@ class list {
public: public:
list():m_ptr(nullptr) {} list():m_ptr(nullptr) {}
list(T const & h, list const & t):m_ptr(new cell(h, t)) {} list(T const & h, list const & t):m_ptr(new cell(h, t)) {}
list(T const & h):m_ptr(new cell(h, list())) {}
list(list const & s):m_ptr(s.m_ptr) { if (m_ptr) m_ptr->inc_ref(); } list(list const & s):m_ptr(s.m_ptr) { if (m_ptr) m_ptr->inc_ref(); }
list(list&& s):m_ptr(s.m_ptr) { s.m_ptr = nullptr; } list(list&& s):m_ptr(s.m_ptr) { s.m_ptr = nullptr; }
list(std::initializer_list<T> const & l):list() { list(std::initializer_list<T> const & l):list() {

View file

@ -14,6 +14,7 @@ Author: Leonardo de Moura
#include "buffer.h" #include "buffer.h"
#include "hash.h" #include "hash.h"
#include "trace.h" #include "trace.h"
#include "ascii.h"
namespace lean { namespace lean {
constexpr char const * anonymous_str = "[anonymous]"; constexpr char const * anonymous_str = "[anonymous]";
@ -302,6 +303,18 @@ unsigned name::hash() const {
return m_ptr ? m_ptr->m_hash : 11; return m_ptr ? m_ptr->m_hash : 11;
} }
bool name::is_safe_ascii() const {
imp * i = m_ptr;
while (i) {
if (i->m_is_string) {
if (!::lean::is_safe_ascii(i->m_str))
return false;
}
i = i->m_prefix;
}
return true;
}
std::string name::to_string() const { std::string name::to_string() const {
std::ostringstream s; std::ostringstream s;
imp::display(s, m_ptr); imp::display(s, m_ptr);

View file

@ -55,11 +55,11 @@ public:
\brief Convert this hierarchical name into a string. \brief Convert this hierarchical name into a string.
*/ */
std::string to_string() const; std::string to_string() const;
/** /** \brief Size of the this name (in characters). */
\brief Size of the this name (in characters).
*/
size_t size() const; size_t size() const;
unsigned hash() const; unsigned hash() const;
/** \brief Return true iff the name contains only safe ASCII chars */
bool is_safe_ascii() const;
friend std::ostream & operator<<(std::ostream & out, name const & n); friend std::ostream & operator<<(std::ostream & out, name const & n);
}; };
struct name_hash { unsigned operator()(name const & n) const { return n.hash(); } }; struct name_hash { unsigned operator()(name const & n) const { return n.hash(); } };

View file

@ -15,6 +15,10 @@
#define LEAN_DEFAULT_PP_INDENTATION 4 #define LEAN_DEFAULT_PP_INDENTATION 4
#endif #endif
#ifndef LEAN_DEFAULT_PP_UNICODE
#define LEAN_DEFAULT_PP_UNICODE true
#endif
#ifndef LEAN_DEFAULT_PP_WIDTH #ifndef LEAN_DEFAULT_PP_WIDTH
#define LEAN_DEFAULT_PP_WIDTH 120 #define LEAN_DEFAULT_PP_WIDTH 120
#endif #endif
@ -37,10 +41,12 @@
namespace lean { namespace lean {
static name g_pp_indent{"pp", "indent"}; static name g_pp_indent{"pp", "indent"};
static name g_pp_unicode{"pp", "unicode"};
static name g_pp_colors{"pp", "colors"}; static name g_pp_colors{"pp", "colors"};
static name g_pp_width{"pp", "width"}; static name g_pp_width{"pp", "width"};
RegisterUnsignedOption(g_pp_indent, LEAN_DEFAULT_PP_INDENTATION, "(pretty printer) default indentation"); RegisterUnsignedOption(g_pp_indent, LEAN_DEFAULT_PP_INDENTATION, "(pretty printer) default indentation");
RegisterBoolOption(g_pp_unicode, LEAN_DEFAULT_PP_UNICODE, "(pretty printer) use unicode characters");
RegisterBoolOption(g_pp_colors, LEAN_DEFAULT_PP_COLORS, "(pretty printer) use colors"); RegisterBoolOption(g_pp_colors, LEAN_DEFAULT_PP_COLORS, "(pretty printer) use colors");
RegisterUnsignedOption(g_pp_width, LEAN_DEFAULT_PP_WIDTH, "(pretty printer) line width"); RegisterUnsignedOption(g_pp_width, LEAN_DEFAULT_PP_WIDTH, "(pretty printer) line width");
@ -48,6 +54,10 @@ unsigned get_pp_indent(options const & o) {
return o.get_unsigned(g_pp_indent, LEAN_DEFAULT_PP_INDENTATION); return o.get_unsigned(g_pp_indent, LEAN_DEFAULT_PP_INDENTATION);
} }
bool get_pp_unicode(options const & o) {
return o.get_bool(g_pp_unicode, LEAN_DEFAULT_PP_UNICODE);
}
bool get_pp_colors(options const & o) { bool get_pp_colors(options const & o) {
return o.get_bool(g_pp_colors, LEAN_DEFAULT_PP_COLORS); return o.get_bool(g_pp_colors, LEAN_DEFAULT_PP_COLORS);
} }

View file

@ -305,6 +305,8 @@ inline format fillwords(std::initializer_list<std::string> const & l) {
class options; class options;
/** \brief Extract indentation from options */ /** \brief Extract indentation from options */
unsigned get_pp_indent(options const & o); unsigned get_pp_indent(options const & o);
/** \brief Return unicode characters flag */
bool get_pp_unicode(options const & o);
/** \brief Format a hierarchical name */ /** \brief Format a hierarchical name */
format pp(name const & n); format pp(name const & n);

View file

@ -117,6 +117,7 @@ char const * options::get_string(char const * n, char const * default_value) con
static char const * g_left_angle_bracket = "\u27E8"; static char const * g_left_angle_bracket = "\u27E8";
static char const * g_right_angle_bracket = "\u27E9"; static char const * g_right_angle_bracket = "\u27E9";
static char const * g_arrow = "\u21a6"; static char const * g_arrow = "\u21a6";
static char const * g_assign = ":=";
options options::update(name const & n, sexpr const & v) const { options options::update(name const & n, sexpr const & v) const {
if (contains(n)) { if (contains(n)) {
@ -141,25 +142,31 @@ options join(options const & opts1, options const & opts2) {
} }
format pp(options const & o) { format pp(options const & o) {
bool unicode = get_pp_unicode(o);
format r; format r;
bool first = true; bool first = true;
char const * arrow = unicode ? g_arrow : g_assign;
for_each(o.m_value, [&](sexpr const & p) { for_each(o.m_value, [&](sexpr const & p) {
if (first) { first = false; } else { r += comma(); r += line(); } if (first) { first = false; } else { r += comma(); r += line(); }
name const & n = to_name(head(p)); name const & n = to_name(head(p));
unsigned sz = n.size(); unsigned sz = n.size();
r += group(nest(sz+3, format{pp(head(p)), space(), format(g_arrow), space(), pp(tail(p))})); unsigned indent = unicode ? sz+3 : sz+4;
r += group(nest(indent, format{pp(head(p)), space(), format(arrow), space(), pp(tail(p))}));
}); });
return group(nest(1, format{format(g_left_angle_bracket), r, format(g_right_angle_bracket)})); format open = unicode ? format(g_left_angle_bracket) : lp();
format close = unicode ? format(g_right_angle_bracket) : rp();
return group(nest(1, format{open, r, close}));
} }
std::ostream & operator<<(std::ostream & out, options const & o) { std::ostream & operator<<(std::ostream & out, options const & o) {
out << g_left_angle_bracket; bool unicode = get_pp_unicode(o);
out << (unicode ? g_left_angle_bracket : "(");
bool first = true; bool first = true;
for_each(o.m_value, [&](sexpr const & p) { for_each(o.m_value, [&](sexpr const & p) {
if (first) first = false; else out << ", "; if (first) first = false; else out << ", ";
out << head(p) << " " << g_arrow << " " << tail(p); out << head(p) << " " << (unicode ? g_arrow : g_assign) << " " << tail(p);
}); });
out << g_right_angle_bracket; out << (unicode ? g_right_angle_bracket : ")");
return out; return out;
} }
} }

View file

@ -70,7 +70,7 @@ struct mk_option_declaration {
#define LEAN_MAKE_OPTION_NAME_CORE(LINE) LEAN_OPTION_ ## LINE #define LEAN_MAKE_OPTION_NAME_CORE(LINE) LEAN_OPTION_ ## LINE
#define LEAN_MAKE_OPTION_NAME(LINE) LEAN_MAKE_OPTION_NAME_CORE(LINE) #define LEAN_MAKE_OPTION_NAME(LINE) LEAN_MAKE_OPTION_NAME_CORE(LINE)
#define LEAN_OPTION_UNIQUE_NAME LEAN_MAKE_OPTION_NAME(__LINE__) #define LEAN_OPTION_UNIQUE_NAME LEAN_MAKE_OPTION_NAME(__LINE__)
#define RegisterOption(N,K,D,DESC) ::lean::mk_option_declaration LEAN_OPTION_UNIQUE_NAME(N,K,D,DESC) #define RegisterOption(N,K,D,DESC) static ::lean::mk_option_declaration LEAN_OPTION_UNIQUE_NAME(N,K,D,DESC)
#define RegisterOptionCore(N,K,D,DESC) RegisterOption(N,K,#D,DESC) #define RegisterOptionCore(N,K,D,DESC) RegisterOption(N,K,#D,DESC)
#define RegisterBoolOption(N,D,DESC) RegisterOptionCore(N, BoolOption, D, DESC); #define RegisterBoolOption(N,D,DESC) RegisterOptionCore(N, BoolOption, D, DESC);
#define RegisterUnsignedOption(N,D,DESC) RegisterOptionCore(N, UnsignedOption, D, DESC); #define RegisterUnsignedOption(N,D,DESC) RegisterOptionCore(N, UnsignedOption, D, DESC);

View file

@ -4,6 +4,8 @@ Set pp::colors false
Show true Show true
Set lean::pp::notation false Set lean::pp::notation false
Show true && false Show true && false
Set pp::unicode false
Show true && false
Variable a : Bool Variable a : Bool
Variable a : Bool Variable a : Bool
Variable b : Bool Variable b : Bool

View file

@ -1,13 +1,15 @@
Set: pp::colors Set: pp::colors
Set: lean::pp::notation Set: lean::pp::notation
and
Set: pp::unicode
and true false and true false
Assumed: a Assumed: a
Error (line: 8, pos: 0) invalid object declaration, environment already has an object named 'a' Error (line: 10, pos: 0) invalid object declaration, environment already has an object named 'a'
Assumed: b Assumed: b
and a b and a b
Assumed: A Assumed: A
Error (line: 12, pos: 11) type mismatch at application Error (line: 14, pos: 11) type mismatch at application
and a A and a A
Function type: Function type:
Bool -> Bool -> Bool Bool -> Bool -> Bool
@ -15,8 +17,8 @@ Arguments types:
Bool Bool
Type Type
Variable A : Type Variable A : Type
⟨lean::pp::notation ↦ false, pp::colors ↦ false⟩ (pp::unicode := false, lean::pp::notation := false, pp::colors := false)
Error (line: 15, pos: 4) unknown option 'lean::p::notation', type 'Help Options.' for list of available options Error (line: 17, pos: 4) unknown option 'lean::p::notation', type 'Help Options.' for list of available options
Error (line: 16, pos: 23) invalid option value, given option is not an integer Error (line: 18, pos: 23) invalid option value, given option is not an integer
Set: lean::pp::notation Set: lean::pp::notation
a b a /\ b

View file

@ -3,8 +3,8 @@
Assumed: g Assumed: g
++ ⊥ ++ ++ ⊥ ++
Set: lean::pp::notation Set: lean::pp::notation
f (f true false) true f (f ⊥)
Assumed: a Assumed: a
Assumed: b Assumed: b
g (g a b) a g (g a b) a
f (f true false) false f (f ⊥) ⊥

View file

@ -1,5 +1,5 @@
Set pp::colors false
Show 1 + true Show 1 + true
Variable R : Type Variable R : Type
Variable T : Type Variable T : Type
Variable r2t : R -> T Variable r2t : R -> T

View file

@ -1,8 +1,9 @@
Error (line: 1, pos: 10) application type mismatch, none of the overloads can be used Set: pp::colors
Error (line: 2, pos: 9) application type mismatch, none of the overloads can be used
Candidates: Candidates:
Real::add : Real → Real → Real Real::add : Real → Real → Real
Int::add : Int → Int → Int Int::add : Int → Int → Int
Nat::add : Nat → Nat → Nat Nat::add : Nat → Nat → Nat
Arguments: Arguments:
1 : Nat 1 : Nat
: Bool : Bool
@ -23,8 +24,8 @@ f (r2t b) (t2r a)
f a b f a b
Error (line: 20, pos: 10) ambiguous overloads Error (line: 20, pos: 10) ambiguous overloads
Candidates: Candidates:
g : R -> T -> R g : R → T → R
f : T -> R -> T f : T → R → T
Arguments: Arguments:
b : R b : R
a : T a : T

View file

@ -2,7 +2,7 @@
Notation 10 if _ then _ : implies Notation 10 if _ then _ : implies
if then ⊥ if then ⊥
if then (if a then ⊥) if then (if a then ⊥)
implies true (implies a false) implies (implies a ⊥)
Notation 100 _ |- _ ; _ : f Notation 100 _ |- _ ; _ : f
f c d e f c d e
c |- d ; e c |- d ; e

9
tests/lean/unicode.lean Normal file
View file

@ -0,0 +1,9 @@
Set pp::colors false
Show true /\ false
Set pp::unicode false
Show true /\ false
Set pp::unicode true
Set lean::pp::notation false
Show true /\ false
Set pp::unicode false
Show true /\ false

View file

@ -0,0 +1,9 @@
Set: pp::colors
∧ ⊥
Set: pp::unicode
true /\ false
Set: pp::unicode
Set: lean::pp::notation
and
Set: pp::unicode
and true false