Add output_channel and state abstractions

Signed-off-by: Leonardo de Moura <leonardo@microsoft.com>
This commit is contained in:
Leonardo de Moura 2013-08-20 12:19:28 -07:00
parent 73262e9786
commit 4fa2468a85
11 changed files with 260 additions and 65 deletions

View file

@ -1,3 +1,3 @@
add_library(exprlib basic_thms.cpp deep_copy.cpp max_sharing.cpp toplevel.cpp printer.cpp
formatter.cpp context_to_lambda.cpp)
formatter.cpp context_to_lambda.cpp state.cpp)
target_link_libraries(exprlib ${LEAN_LIBS})

View file

@ -11,23 +11,23 @@ Author: Leonardo de Moura
namespace lean {
class simple_formatter_cell : public formatter_cell {
public:
virtual format operator()(expr const & e) {
virtual format operator()(expr const & e, options const & opts) {
std::ostringstream s; s << e; return format(s.str());
}
virtual format operator()(context const & c) {
virtual format operator()(context const & c, options const & opts) {
std::ostringstream s; s << c; return format(s.str());
}
virtual format operator()(context const & c, expr const & e, bool format_ctx) {
virtual format operator()(context const & c, expr const & e, bool format_ctx, options const & opts) {
std::ostringstream s;
if (format_ctx)
s << c << "|-\n";
s << mk_pair(e,c);
return format(s.str());
}
virtual format operator()(object const & obj) {
virtual format operator()(object const & obj, options const & opts) {
std::ostringstream s; s << obj; return format(s.str());
}
virtual format operator()(environment const & env) {
virtual format operator()(environment const & env, options const & opts) {
std::ostringstream s; s << env; return format(s.str());
}
};

View file

@ -7,6 +7,7 @@ Author: Leonardo de Moura
#pragma once
#include <memory>
#include "context.h"
#include "options.h"
namespace lean {
class environment;
@ -18,9 +19,9 @@ class formatter_cell {
public:
virtual ~formatter_cell() {}
/** \brief Format the given expression. */
virtual format operator()(expr const & e) = 0;
virtual format operator()(expr const & e, options const & opts) = 0;
/** \brief Format the given context. */
virtual format operator()(context const & c) = 0;
virtual format operator()(context const & c, options const & opts) = 0;
/**
\brief Format the given expression with respect to the given
context.
@ -28,11 +29,11 @@ public:
\remark If format_ctx == false, then the context is not formatted. It just provides names
for the free variables
*/
virtual format operator()(context const & c, expr const & e, bool format_ctx = false) = 0;
virtual format operator()(context const & c, expr const & e, bool format_ctx, options const & opts) = 0;
/** \brief Format the given object */
virtual format operator()(object const & obj) = 0;
virtual format operator()(object const & obj, options const & opts) = 0;
/** \brief Format the given environment */
virtual format operator()(environment const & env) = 0;
virtual format operator()(environment const & env, options const & opts) = 0;
};
class formatter {
@ -40,11 +41,11 @@ class formatter {
public:
formatter(formatter_cell * c):m_cell(c) {}
formatter(std::shared_ptr<formatter_cell> const & c):m_cell(c) {}
format operator()(expr const & e) { return (*m_cell)(e); }
format operator()(context const & c) { return (*m_cell)(c); }
format operator()(context const & c, expr const & e, bool format_ctx = false) { return (*m_cell)(c, e, format_ctx); }
format operator()(object const & obj) { return (*m_cell)(obj); }
format operator()(environment const & env) { return (*m_cell)(env); }
format operator()(expr const & e, options const & opts = options()) { return (*m_cell)(e, opts); }
format operator()(context const & c, options const & opts = options()) { return (*m_cell)(c, opts); }
format operator()(context const & c, expr const & e, bool format_ctx = false, options const & opts = options()) { return (*m_cell)(c, e, format_ctx, opts); }
format operator()(object const & obj, options const & opts = options()) { return (*m_cell)(obj, opts); }
format operator()(environment const & env, options const & opts = options()) { return (*m_cell)(env, opts); }
};
formatter mk_simple_formatter();

40
src/exprlib/state.cpp Normal file
View file

@ -0,0 +1,40 @@
/*
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 "state.h"
namespace lean {
state::state():
m_formatter(mk_simple_formatter()),
m_regular_channel(new stdout_channel()),
m_diagnostic_channel(new stderr_channel()) {
}
state::state(options const & opts, formatter const & fmt):
m_options(opts),
m_formatter(fmt),
m_regular_channel(new stdout_channel()),
m_diagnostic_channel(new stderr_channel()) {
}
state::~state() {}
void state::set_regular_channel(std::shared_ptr<output_channel> const & out) {
m_regular_channel = out;
}
void state::set_diagnostic_channel(std::shared_ptr<output_channel> const & out) {
m_diagnostic_channel = out;
}
void state::set_options(options const & opts) {
m_options = opts;
}
void state::set_formatter(formatter const & f) {
m_formatter = f;
}
}

72
src/exprlib/state.h Normal file
View file

@ -0,0 +1,72 @@
/*
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
#include "output_channel.h"
#include "formatter.h"
#include "options.h"
namespace lean {
/**
\brief State provided to internal lean procedures that need to:
1- Access user defined options
2- Produce verbosity messages
3- Output results
4- Produce formatted output
*/
class state {
options m_options;
formatter m_formatter;
std::shared_ptr<output_channel> m_regular_channel;
std::shared_ptr<output_channel> m_diagnostic_channel;
public:
state();
state(options const & opts, formatter const & fmt);
~state();
options get_options() const { return m_options; }
formatter get_formatter() const { return m_formatter; }
output_channel & get_regular_channel() const { return *m_regular_channel; }
output_channel & get_diagnostic_channel() const { return *m_diagnostic_channel; }
void set_regular_channel(std::shared_ptr<output_channel> const & out);
void set_diagnostic_channel(std::shared_ptr<output_channel> const & out);
void set_options(options const & opts);
void set_formatter(formatter const & f);
};
struct regular {
state const & m_state;
regular(state const & s):m_state(s) {}
};
struct diagnostic {
state const & m_state;
diagnostic(state const & s):m_state(s) {}
};
template<typename T>
inline regular const & operator<<(regular const & out, T const & t) {
out.m_state.get_regular_channel().get_stream() << t;
return out;
}
template<typename T>
inline diagnostic const & operator<<(diagnostic const & out, T const & t) {
out.m_state.get_diagnostic_channel().get_stream() << t;
return out;
}
inline regular const & operator<<(regular const & out, expr const & e) {
out.m_state.get_regular_channel().get_stream() << out.m_state.get_formatter()(e, out.m_state.get_options());
return out;
}
inline diagnostic const & operator<<(diagnostic const & out, expr const & e) {
out.m_state.get_diagnostic_channel().get_stream() << out.m_state.get_formatter()(e, out.m_state.get_options());
return out;
}
}

View file

@ -11,6 +11,7 @@ Author: Leonardo de Moura
#include "operator_info.h"
#include "toplevel.h"
#include "builtin_notation.h"
#include "state.h"
#include "pp.h"
namespace lean {
@ -27,6 +28,7 @@ struct frontend::imp {
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)
implicit_table m_implicit_table; // track the number of implicit arguments for a symbol.
state m_state;
bool has_children() const { return m_num_children > 0; }
void inc_children() { m_num_children++; }
@ -168,7 +170,8 @@ struct frontend::imp {
explicit imp(std::shared_ptr<imp> const & parent):
m_num_children(0),
m_parent(parent),
m_env(m_parent->m_env.mk_child()) {
m_env(m_parent->m_env.mk_child()),
m_state(m_parent->m_state) {
m_parent->inc_children();
}
@ -181,8 +184,11 @@ struct frontend::imp {
frontend::frontend():m_imp(new imp(*this)) {
init_builtin_notation(*this);
init_toplevel(m_imp->m_env);
m_imp->m_state.set_formatter(mk_pp_formatter(*this));
}
frontend::frontend(imp * new_ptr):m_imp(new_ptr) {
m_imp->m_state.set_formatter(mk_pp_formatter(*this));
}
frontend::frontend(imp * new_ptr):m_imp(new_ptr) {}
frontend::frontend(std::shared_ptr<imp> const & ptr):m_imp(ptr) {}
frontend::~frontend() {}
@ -223,4 +229,9 @@ void frontend::add_mixfixc(unsigned sz, name const * opns, unsigned p, expr cons
operator_info frontend::find_op_for(expr const & n) const { return m_imp->find_op_for(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); }
state const & frontend::get_state() const { return m_imp->m_state; }
void frontend::set_options(options const & opts) { return m_imp->m_state.set_options(opts); }
void frontend::set_regular_channel(std::shared_ptr<output_channel> const & out) { return m_imp->m_state.set_regular_channel(out); }
void frontend::set_diagnostic_channel(std::shared_ptr<output_channel> const & out) { return m_imp->m_state.set_diagnostic_channel(out); }
}

View file

@ -8,6 +8,7 @@ Author: Leonardo de Moura
#include <memory>
#include "environment.h"
#include "operator_info.h"
#include "state.h"
namespace lean {
/**
@ -113,5 +114,16 @@ public:
*/
operator_info find_led(name const & n) const;
/*@}*/
/**
@name State management.
*/
/*@{*/
state const & get_state() const;
operator state const &() const { return get_state(); }
void set_options(options const & opts);
void set_regular_channel(std::shared_ptr<output_channel> const & out);
void set_diagnostic_channel(std::shared_ptr<output_channel> const & out);
/*@}*/
};
}

View file

@ -793,23 +793,22 @@ public:
class pp_formatter_cell : public formatter_cell {
frontend m_frontend;
options m_options;
unsigned m_indent;
format pp(expr const & e) {
return pp_fn(m_frontend, m_options)(e);
format pp(expr const & e, options const & opts) {
return pp_fn(m_frontend, opts)(e);
}
format pp(context const & c, expr const & e, bool include_e) {
format pp(context const & c, expr const & e, bool include_e, options const & opts) {
unsigned indent = get_pp_indent(opts);
format r;
bool first = true;
expr c2 = context_to_lambda(c, e);
while (is_fake_context(c2)) {
name n1 = get_unused_name(c2);
format entry = format{format(n1), space(), colon(), space(), pp(fake_context_domain(c2))};
format entry = format{format(n1), space(), colon(), space(), pp(fake_context_domain(c2), opts)};
expr val = fake_context_value(c2);
if (val)
entry += format{space(), g_assign_fmt, nest(m_indent, format{line(), pp(val)})};
entry += format{space(), g_assign_fmt, nest(indent, format{line(), pp(val, opts)})};
if (first) {
r = group(entry);
first = false;
@ -820,77 +819,77 @@ class pp_formatter_cell : public formatter_cell {
}
if (include_e) {
if (first)
r += format{line(), pp(c2)};
r += format{line(), pp(c2, opts)};
else
r = pp(c2);
r = pp(c2, opts);
} else {
return r;
}
return r;
}
format pp_definition(char const * kwd, name const & n, expr const & t, expr const & v) {
format pp_definition(char const * kwd, name const & n, expr const & t, expr const & v, options const & opts) {
unsigned indent = get_pp_indent(opts);
format def = format{highlight_command(format(kwd)), space(), format(n), space(), colon(), space(),
pp(t), space(), g_assign_fmt, line(), pp(v)};
return group(nest(m_indent, def));
pp(t, opts), space(), g_assign_fmt, line(), pp(v, opts)};
return group(nest(indent, def));
}
format pp_compact_definition(char const * kwd, name const & n, expr const & t, expr const & v) {
format pp_compact_definition(char const * kwd, name const & n, expr const & t, expr const & v, options const & opts) {
expr it1 = t;
expr it2 = v;
while (is_pi(it1) && is_lambda(it2)) {
if (abst_domain(it1) != abst_domain(it2))
return pp_definition(kwd, n, t, v);
return pp_definition(kwd, n, t, v, opts);
it1 = abst_body(it1);
it2 = abst_body(it2);
}
if (!is_lambda(v) || is_pi(it1)) {
return pp_definition(kwd, n, t, v);
return pp_definition(kwd, n, t, v, opts);
} else {
lean_assert(is_lambda(v));
format def = pp_fn(m_frontend, m_options).pp_definition(v, t);
format def = pp_fn(m_frontend, opts).pp_definition(v, t);
return format{highlight_command(format(kwd)), space(), format(n), def};
}
}
format pp_uvar_decl(object const & obj) {
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())};
}
format pp_postulate(object const & obj) {
return format{highlight_command(format(obj.keyword())), space(), format(obj.get_name()), space(), colon(), space(), pp(obj.get_type())};
format pp_postulate(object const & obj, options const & opts) {
return format{highlight_command(format(obj.keyword())), space(), format(obj.get_name()), space(), colon(), space(), pp(obj.get_type(), opts)};
}
format pp_definition(object const & obj) {
return pp_compact_definition(obj.keyword(), obj.get_name(), obj.get_type(), obj.get_value());
format pp_definition(object const & obj, options const & opts) {
return pp_compact_definition(obj.keyword(), obj.get_name(), obj.get_type(), obj.get_value(), opts);
}
format pp_notation_decl(object const & obj) {
format pp_notation_decl(object const & obj, options const & opts) {
notation_declaration const & n = *(static_cast<notation_declaration const *>(obj.cell()));
return format{::lean::pp(n.get_op()), space(), colon(), space(), pp(n.get_expr())};
return format{::lean::pp(n.get_op()), space(), colon(), space(), pp(n.get_expr(), opts)};
}
public:
pp_formatter_cell(frontend const & fe, options const & opts):
m_frontend(fe),
m_options(opts) {
m_indent = get_pp_indent(opts);
pp_formatter_cell(frontend const & fe):
m_frontend(fe) {
}
virtual ~pp_formatter_cell() {
}
virtual format operator()(expr const & e) {
return pp(e);
virtual format operator()(expr const & e, options const & opts) {
return pp(e, opts);
}
virtual format operator()(context const & c) {
return pp(c, Type(), false);
virtual format operator()(context const & c, options const & opts) {
return pp(c, Type(), false, opts);
}
virtual format operator()(context const & c, expr const & e, bool format_ctx) {
virtual format operator()(context const & c, expr const & e, bool format_ctx, options const & opts) {
if (format_ctx) {
return pp(c, e, true);
return pp(c, e, true, opts);
} else {
expr c2 = context_to_lambda(c, e);
while (is_fake_context(c2)) {
@ -898,20 +897,20 @@ public:
name n1 = get_unused_name(rest);
c2 = instantiate_with_closed(rest, mk_constant(n1));
}
return pp(c2);
return pp(c2, opts);
}
}
virtual format operator()(object const & obj) {
virtual format operator()(object const & obj, options const & opts) {
switch (obj.kind()) {
case object_kind::UVarDeclaration: return pp_uvar_decl(obj);
case object_kind::Postulate: return pp_postulate(obj);
case object_kind::Definition: return pp_definition(obj);
case object_kind::UVarDeclaration: return pp_uvar_decl(obj, opts);
case object_kind::Postulate: return pp_postulate(obj, opts);
case object_kind::Definition: return pp_definition(obj, opts);
case object_kind::Neutral:
if (dynamic_cast<notation_declaration const *>(obj.cell())) {
// If the object is not notation, then the object was
// created in different frontend, and we ignore it.
return pp_notation_decl(obj);
return pp_notation_decl(obj, opts);
} else {
return format("Unknown neutral object");
}
@ -920,25 +919,25 @@ public:
return format();
}
virtual format operator()(environment const & env) {
virtual format operator()(environment const & env, options const & opts) {
format r;
bool first = true;
std::for_each(env.begin_objects(),
env.end_objects(),
[&](object const & obj) {
if (first) first = false; else r += line();
r += operator()(obj);
r += operator()(obj, opts);
});
return r;
}
};
formatter mk_pp_formatter(frontend const & fe, options const & opts) {
return formatter(new pp_formatter_cell(fe, opts));
formatter mk_pp_formatter(frontend const & fe) {
return formatter(new pp_formatter_cell(fe));
}
std::ostream & operator<<(std::ostream & out, frontend const & fe) {
formatter fmt = mk_pp_formatter(fe, options());
formatter fmt = mk_pp_formatter(fe);
out << fmt(fe.get_environment());
return out;
}

View file

@ -11,6 +11,6 @@ Author: Leonardo de Moura
namespace lean {
class frontend;
formatter mk_pp_formatter(frontend const & fe, options const & opts = options());
formatter mk_pp_formatter(frontend const & fe);
std::ostream & operator<<(std::ostream & out, frontend const & fe);
}

View file

@ -7,6 +7,7 @@ Author: Leonardo de Moura
#include "frontend.h"
#include "printer.h"
#include "abstract.h"
#include "builtin.h"
#include "pp.h"
#include "test.h"
using namespace lean;
@ -36,8 +37,8 @@ static void tst2() {
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, options({"pp", "alias_min_weight"}, 100));
std::cout << fmt2(g(t, t, t)) << std::endl;
formatter fmt2 = mk_pp_formatter(f);
std::cout << fmt2(g(t, t, t), options({"pp", "alias_min_weight"}, 100)) << std::endl;
}
static void tst3() {
@ -56,9 +57,18 @@ static void tst3() {
std::cout << fmt(g(d, c, b, t)) << "\n";
}
static void tst4() {
frontend f;
state const & s = f.get_state();
regular(s) << And(Const("a"), Const("b")) << "\n";
regular(f) << And(Const("a"), Const("b")) << "\n";
diagnostic(f) << And(Const("a"), Const("b")) << "\n";
}
int main() {
tst1();
tst2();
tst3();
tst4();
return has_violations() ? 1 : 0;
}

50
src/util/output_channel.h Normal file
View file

@ -0,0 +1,50 @@
/*
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
#include <iostream>
#include <fstream>
namespace lean {
/**
\brief Wrapper for std::ostream.
The idea is to be able to have an output stream that can be
"reassigned".
std::unique_ptr<output_channel> out;
out = new stdout_channel();
(*out) << "writting to standard output";
out = new stderr_channel();
(*out) << "writting to standard input";
out = new file_output_channel("file.txt");
(*out) << "writting to file";
*/
class output_channel {
public:
virtual ~output_channel() {}
virtual std::ostream & get_stream() = 0;
};
class stdout_channel : public output_channel {
public:
virtual std::ostream & get_stream() { return std::cout; }
};
class stderr_channel : public output_channel {
public:
virtual std::ostream & get_stream() { return std::cerr; }
};
class file_output_channel : public output_channel {
std::ofstream m_out;
public:
file_output_channel(char const * fname):m_out(fname) {}
virtual ~file_output_channel() {}
virtual std::ostream & get_stream() { return m_out; }
};
template<typename T>
output_channel & operator<<(output_channel & out, T const & v) {
out.get_stream() << v;
return out;
}
}