From a7910e1fe7af9926c309d1aaa1861c382c9dca94 Mon Sep 17 00:00:00 2001 From: Soonho Kong Date: Wed, 24 Jul 2013 17:50:51 -0700 Subject: [PATCH] Update format.cpp & format.h + Update format tests --- src/tests/util/format.cpp | 88 ++++++++---- src/util/format.cpp | 287 +++++++++++++++++++++++++++++--------- src/util/format.h | 244 +++++++++++++++++++++++--------- 3 files changed, 458 insertions(+), 161 deletions(-) diff --git a/src/tests/util/format.cpp b/src/tests/util/format.cpp index 81d56fe73..dcda82fa9 100644 --- a/src/tests/util/format.cpp +++ b/src/tests/util/format.cpp @@ -4,49 +4,85 @@ Released under Apache 2.0 license as described in the file LICENSE. Author: Soonho Kong */ +#include +#include #include "format.h" #include "test.h" +#include "sexpr_funcs.h" using namespace lean; -void color(const char *s, int n) { - std::cout << "\e[" << (31 + n % 7) << "m" << s << "\e[0m"; -} +using std::cout; +using std::endl; static void tst1() { format f_atom1("foo"); format f_atom2("bar"); format f_atom3(1); format f_atom4(3.1415); - format f1(f_atom1, f_atom2); - format f2(f1); - format f3 = choice(f1, f2); + format f1(highlight(f_atom1), f_atom2); +// format f2{f_atom1, f_atom2, highlight(f_atom3, format::format_color::ORANGE), f_atom4}; + format f2{f_atom1, highlight(f_atom3, format::format_color::ORANGE)}; + format f3 = compose(f1, f2); format f4 = nest(3, f3); format f5 = line(); format f6(f4, f5); - format f7(f6, f3); + format f7 = nest(10, format{f6, f4, f6, f4}); +// format f8(f_atom1, nest(3, format(line(), f_atom1))); + format f8 = f7; + format f9 = f7 + f8; + format f10; + f10 += f6 + f5 + f3; + format f11 = above(f1, above(above(f2, f3), f4)); - std::cout << "f_atom1 = " << f_atom1 << std::endl - << "f_atom2 = " << f_atom2 << std::endl - << "f_atom3 = " << f_atom3 << std::endl - << "f_atom4 = " << f_atom4 << std::endl - ; + std::vector > v = + {{"f1", f1}, + {"f2", f2}, + {"f3", f3}, + {"f4", f4}, + {"f5", f5}, + {"f6", f6}, + {"f7", f7}, + {"f8", f8}, + {"f9", f9}, + {"f10", f10}, + {"f11", f11}, + }; - std::cout << "f1 = " << f1 << std::endl - << "f2 = " << f2 << std::endl - << "f3 = " << f3 << std::endl - << "f4 = " << f4 << std::endl - << "f5 = " << f5 << std::endl - << "f6 = " << f6 << std::endl - << "f7 = " << f7 << std::endl - ; + std::for_each(v.begin(), v.end(), + [](std::pair const & p) { + cout << "---- " << p.first << " ----------" << endl + << p.second << endl + << "--------------------" << endl << endl; + }); - color("This ", 0); - color("is ", 1); - color("how ", 2); - color("we ", 3); - color("work.", 4); - std::cout << std::endl; +// std::vector ss = {"Last", "weekend's", "revelation", "that", "J.K.", "Rowling", "is", "the", "author", "of", "the", "critically", "acclaimed", "and", "--", "until", "now", "--", "commercially", "unsuccessful", "crime", "novel", "The", "Cuckoo's", "Calling", "has", "electrified", "the", "book", "world", "and", "solidified", "Rowling's", "reputation", "as", "a", "genuine", "writing", "talent:", "After", "all,", "if", "she", "can", "impress", "the", "critics", "without", "the", "benefit", "of", "her", "towering", "reputation,", "then", "surely", "her", "success", "is", "deserved."}; + + std::vector ss = {"Last", "weekend's", "revelation", "that", "J.K.", "Rowling", "is", "the", "author", "of", "the", "critically", "acclaimed"}; + + std::vector sl = {f1, f2, f3, f4}; + + cout << "fill" << endl; + cout << std::string(40, '=') << endl; + pretty(cout, 60, fill(sl.begin(), sl.end())); + cout << endl; + cout << std::string(40, '=') << endl; + + + cout << "stack" << endl; + cout << std::string(40, '=') << endl; + pretty(cout, 60, stack(sl.begin(), sl.end())); + cout << endl; + cout << std::string(40, '=') << endl; + + cout << "spread" << endl; + cout << std::string(40, '=') << endl; + pretty(cout, 60, spread(sl.begin(), sl.end())); + cout << endl; + cout << std::string(40, '=') << endl; + +// cout << fill(ss.begin(), ss.end()) << endl; + return; } int main() { diff --git a/src/util/format.cpp b/src/util/format.cpp index 452570928..a9ed70e9e 100644 --- a/src/util/format.cpp +++ b/src/util/format.cpp @@ -1,96 +1,245 @@ /* -Copyright (c) 2013 Microsoft Corporation. All rights reserved. -Released under Apache 2.0 license as described in the file LICENSE. + Copyright (c) 2013 Microsoft Corporation. All rights reserved. + Released under Apache 2.0 license as described in the file LICENSE. -Author: Soonho Kong + Author: Soonho Kong */ -#include #include "sexpr.h" #include "format.h" +#include "sexpr_funcs.h" namespace lean { -std::ostream & layout(std::ostream & out, sexpr const & s) { - if(is_cons(s)) { - sexpr v = cdr(s); - switch (to_int(car(s))) { - case format::format_kind::NIL: - out << "NIL"; - break; - case format::format_kind::NEST: - out << "NEST(" - << car(v) - << ", "; - layout(out, cdr(v)); - out << ")"; - break; - case format::format_kind::COMPOSE: - out << "COMPOSE("; - layout(out, car(v)); - out << ", "; - layout(out, cdr(v)); - out << ")"; - break; - case format::format_kind::CHOICE: - out << "CHOICE("; - layout(out, car(v)); - out << ", "; - layout(out, cdr(v)); - out << ")"; - break; - case format::format_kind::LINE: - out << "LINE()"; - break; +static int default_width = 78; + +std::ostream & layout(std::ostream & out, sexpr const & s) { + lean_assert(!is_nil(s)); + switch (format::sexpr_kind(s)) { + case format::format_kind::NEST: + case format::format_kind::CHOICE: + case format::format_kind::COMPOSE: + lean_unreachable(); + break; + + case format::format_kind::NIL: + out << ""; + break; + + case format::format_kind::LINE: + out << std::endl; + break; + + case format::format_kind::TEXT: + { + sexpr const & v = cdr(s); + if(is_string(v)) { + out << to_string(v); + } else { + out << v; } - } else { - out << s; + break; + } + + case format::format_kind::COLOR_BEGIN: + { + format::format_color c = static_cast(to_int(cdr(s))); + out << "\e[" << (31 + c % 7) << "m"; + break; + } + + case format::format_kind::COLOR_END: + out << "\e[0m"; + break; } return out; } -std::ostream & operator<<(std::ostream & out, format const & f) { - return layout(out, f.m_value); +std::ostream & layout_list(std::ostream & out, sexpr const & s) { + foreach(s, [&out](sexpr const & s) { + layout(out, s); + }); + return out; } -sexpr flatten(sexpr const & s) { - if(is_cons(s)) { - sexpr v = cdr(s); - switch (to_int(car(s))) { - case format::format_kind::NIL: - /* flatten NIL = NIL */ - return s; +format compose(format const & f1, format const & f2) { + return format(format::sexpr_compose({f1.m_value, f2.m_value})); +} +format nest(int i, format const & f) { + return format(format::sexpr_nest(i, f.m_value)); +} +format highlight(format const & f, format::format_color const c) { + return format(format::sexpr_highlight(f.m_value, c)); +} +format line() { + return format(format::sexpr_line()); +} - case format::format_kind::NEST: - /* flatten (NEST i x) = flatten x */ - return flatten(cdr(v)); - - case format::format_kind::COMPOSE: - /* flatten (x <> y) = flatten x <> flatten y */ - return sexpr(format::format_kind::COMPOSE, - sexpr(flatten(car(v)), - flatten(cdr(v)))); - - case format::format_kind::CHOICE: - /* flatten (x <|> y) = flatten x */ - return flatten(car(v)); - - case format::format_kind::LINE: - return sexpr(" "); - - } +sexpr format::flatten(sexpr const & s) { + lean_assert(is_cons(s)); + switch (sexpr_kind(s)) { + case format_kind::NIL: + /* flatten NIL = NIL */ + return s; + case format_kind::NEST: + /* flatten (NEST i x) = flatten x */ + return flatten(sexpr_nest_s(s)); + case format_kind::COMPOSE: + /* flatten (s_1 <> ... <> s_n ) = flatten s_1 <> ... <> flatten s_n */ + return sexpr_compose(map(sexpr_compose_list(s), + [](sexpr const & s) { + return flatten(s); + })); + case format_kind::CHOICE: + /* flatten (x <|> y) = flatten x */ + return flatten(sexpr_choice_1(s)); + case format_kind::LINE: + return sexpr_text(sexpr(" ")); + case format_kind::TEXT: + case format_kind::COLOR_BEGIN: + case format_kind::COLOR_END: + return s; } + lean_unreachable(); return s; } - -format flatten(format const & f){ +format format::flatten(format const & f){ return format(flatten(f.m_value)); } - format group(format const & f) { - return choice(flatten(f), f); + return choice(format::flatten(f), f); +} +format above(format const & f1, format const & f2) { + return format{f1, line(), f2}; +} +format bracket(std::string const l, format const & x, std::string const r) { + return group(format{format(l), + nest(2, format(line(), x)), + line(), + format(r)}); } +// wrap = <+/> +// wrap x y = x <> (text " " :<|> line) <> y +format wrap(format const & f1, format const & f2) { + return format{f1, + choice(format(" "), line()), + f2}; +} +bool format::fits(int w, sexpr const & s) { + lean_assert(is_list(s)); + if (is_nil(s)) + return true; + if (w < 0) + return false; + + sexpr const & x = car(s); + switch (sexpr_kind(x)) { + case format_kind::NIL: + case format_kind::COLOR_BEGIN: + case format_kind::COLOR_END: + return fits(w, cdr(s)); + + case format_kind::TEXT: + { + sexpr const & v = sexpr_text_t(x); + int l = to_string(v).length(); + if(l > w) + return false; + else + return fits(w - l, cdr(s)); + } + + case format_kind::LINE: + return true; + + case format_kind::COMPOSE: + case format_kind::NEST: + case format_kind::CHOICE: + lean_unreachable(); + break; + } + lean_unreachable(); + return false; } +sexpr format::be(int w, int k, sexpr const & s, sexpr const & r) { + /* be w k [] = Nil */ + if(is_nil(s)) { + if(is_nil(r)) { + // s == Nil && r == Nil + return sexpr(); + } else { + // s == Nil && r != Nil + return be(w, k, car(r), cdr(r)); + } + } -void pp(lean::format const & n) { std::cout << "pp" << "\n"; } + /* s = (i, v) :: z, where h has the type int x format */ + sexpr const & h = car(s); + sexpr const & z = cdr(s); + int i = to_int(car(h)); + sexpr const & v = cdr(h); + + switch (sexpr_kind(v)) { + case format_kind::NIL: + return be(w, k, z, r); + case format_kind::COLOR_BEGIN: + case format_kind::COLOR_END: + return sexpr(v, be(w, k, z, r)); + case format_kind::COMPOSE: + { + sexpr const & list = sexpr_compose_list(v); + sexpr const & list_ = map(list, + [i](sexpr const & s) { + return sexpr(i, s); + }); + return be(w, k, list_, sexpr(z, r)); + } + case format_kind::NEST: + { + int j = sexpr_nest_i(v); + sexpr const & x = sexpr_nest_s(v); + return be(w, k, sexpr(sexpr(i + j, x), z), r); + } + case format_kind::TEXT: + { + sexpr const & l = sexpr_text_t(v); + return sexpr(v, be(w, k + to_string(l).length(), z, r)); + } + case format_kind::LINE: + return sexpr(v, sexpr(sexpr_text(std::string(i, ' ')), be(w, i, z, r))); + case format_kind::CHOICE: + { + sexpr const & x = sexpr_choice_1(v); + sexpr const & y = sexpr_choice_2(v);; + sexpr const & s1 = be(w, k, sexpr(sexpr(i, x), z), r); + if (fits(w - k, s1)) { + return s1; + } else { + sexpr const & s2 = be(w, k, sexpr(sexpr(i, y), z), r); + return s2; + } + } + } + lean_unreachable(); + return sexpr(); +} + +sexpr format::best(int w, int k, sexpr const & s) { + return be(w, k, sexpr{sexpr(0, s)}, sexpr()); +} + +std::ostream & operator<<(std::ostream & out, format const & f) +{ + return pretty(out, default_width, f); +} + +format operator+(format const & f1, format const & f2) { + return format{f1, format(" "), f2}; +} + +std::ostream & pretty(std::ostream & out, unsigned w, format const & f) { + sexpr const & b = format::best(w, 0, f.m_value); + return layout_list(out, b); +} +} diff --git a/src/util/format.h b/src/util/format.h index 77398d349..d8f98d85c 100644 --- a/src/util/format.h +++ b/src/util/format.h @@ -6,7 +6,9 @@ Author: Soonho Kong */ #pragma once #include "sexpr.h" +#include "debug.h" #include +#include namespace lean { /** @@ -14,88 +16,198 @@ namespace lean { uses `sexpr` as an internal representation. - nil = nil sexpr - text s = ("TEXT" s ) - nest f = ("NEST" f ) - choice f1 f2 = ("CHOICE" f1 f2) - compose f1 f2 = ("COMPOSE" f1 f2) - line = ("LINE") - nest n f = ("NEST" n f) - + nil = ["NIL"] + text s = ("TEXT" . s) + choice f1 f2 = ("CHOICE" f1 . f2) + compose f1 ... fn = ["COMPOSE" f1 ... fn] + line = ["LINE"] + nest n f = ("NEST" n . f) + highlight c f = ("HIGHLIGHT" c . f) */ class format { - sexpr m_value; - public: - enum format_kind { NIL, NEST, COMPOSE, CHOICE, LINE, TEXT }; + enum format_kind { NIL, NEST, COMPOSE, CHOICE, LINE, TEXT, COLOR_BEGIN, COLOR_END}; + enum format_color {RED, GREEN, ORANGE, BLUE, PINK, CYAN, GREY}; +private: + sexpr m_value; + static sexpr flatten(sexpr const & s); + static format flatten(format const & f); - format():m_value(sexpr()) {} - explicit format(sexpr const & v):m_value(v) {} - explicit format(char const * v):m_value(v) {} - explicit format(std::string const & v):m_value(v) {} - explicit format(int v):m_value(v) {} - explicit format(double v):m_value(v) {} - explicit format(name const & v):m_value(v) {} - explicit format(mpz const & v):m_value(v) {} - explicit format(mpq const & v):m_value(v) {} - format(format const & f1, format const & f2) { - m_value = sexpr(sexpr(COMPOSE), sexpr(f1.m_value, f2.m_value)); + // Functions for the internal sexpr representation + static inline format_kind sexpr_kind(sexpr const & s) { + lean_assert(is_cons(s)); + return static_cast(to_int(car(s))); } - format(format const & f):m_value(f.m_value) {} - - format_kind kind() const { - if(is_nil(m_value)) { - return NIL; - } - if(is_cons(m_value)) { - /* CHOICE, COMPOSE, LINE, NEST */ - return static_cast(to_int(car(m_value))); - } - return TEXT; + static inline sexpr sexpr_compose(sexpr const & l) { + lean_assert(is_list(l)); + return sexpr(sexpr(format_kind::COMPOSE), l); + } + static inline sexpr sexpr_compose(std::initializer_list const & l) { + return sexpr_compose(sexpr(l)); + } + static inline sexpr const & sexpr_compose_list(sexpr const & s) { + lean_assert(sexpr_kind(s) == format_kind::COMPOSE); + return cdr(s); + } + static inline sexpr sexpr_choice(sexpr const & s1, sexpr const & s2) { + return sexpr(sexpr(format_kind::CHOICE), sexpr(s1, s2)); + } + static inline sexpr const & sexpr_choice_1(sexpr const & s) { + return car(cdr(s)); + } + static inline sexpr const & sexpr_choice_2(sexpr const & s) { + return cdr(cdr(s)); + } + static inline sexpr sexpr_nest(int i, sexpr const & s) { + return sexpr(sexpr(format_kind::NEST), sexpr(i, s)); + } + static inline int sexpr_nest_i(sexpr const & s) { + lean_assert(sexpr_kind(s) == format_kind::NEST); + return to_int(car(cdr(s))); + } + static inline sexpr const & sexpr_nest_s(sexpr const & s) { + lean_assert(sexpr_kind(s) == format_kind::NEST); + return cdr(cdr(s)); + } + static inline sexpr sexpr_text(sexpr const & s) { + return sexpr(sexpr(format_kind::TEXT), s); + } + static inline sexpr const & sexpr_text_t(sexpr const & s) { + lean_assert(sexpr_kind(s) == format_kind::TEXT); + return cdr(s); + } + static inline sexpr sexpr_text(std::string const & s) { + return sexpr(sexpr(format_kind::TEXT), sexpr(s)); + } + static inline sexpr sexpr_color_begin(format_color c) { + return sexpr(sexpr(format_kind::COLOR_BEGIN), sexpr(c)); + } + static inline format_color sexpr_color_begin(sexpr const & s) { + lean_assert(sexpr_kind(s) == format_kind::TEXT); + return static_cast(to_int(cdr(s))); + } + static inline sexpr sexpr_color_end() { + return sexpr{sexpr(format_kind::COLOR_END)}; + } + static inline sexpr sexpr_highlight(sexpr const & s, format_color c) { + return sexpr_compose({sexpr_color_begin(c), s, sexpr_color_end()}); + } + static inline sexpr sexpr_nil() { + return sexpr{sexpr(format::format_kind::NIL)}; + } + static inline sexpr sexpr_line() { + return sexpr{sexpr(format::format_kind::LINE)}; } - unsigned hash() const { return m_value.hash(); } + // Functions used inside of pretty printing + static bool fits(int w, sexpr const & s); + static sexpr better(int w, int k, sexpr const & s1, sexpr const & s2); + static sexpr be(int w, int k, sexpr const & s, sexpr const & r); + static sexpr best(int w, int k, sexpr const & s); - format & operator=(format const & s); - format & operator=(format&& s); - template - format & operator=(T const & v) { return operator=(format(v)); } - - std::ostream & display(std::ostream & out, sexpr const & s); - friend std::ostream & operator<<(std::ostream & out, format const & f); - - friend format compose(format const & f1, format const & f2) { - return format(f1, f2); + static bool is_fnil(format const & f) { + return to_int(car(f.m_value)) == format_kind::NIL; + } + static bool is_compose(format const & f) { + return to_int(car(f.m_value)) == format_kind::COMPOSE; + } + static bool is_nest(format const & f) { + return to_int(car(f.m_value)) == format_kind::NEST; + } + static bool is_text(format const & f) { + return to_int(car(f.m_value)) == format_kind::TEXT; + } + static bool is_line(format const & f) { + return to_int(car(f.m_value)) == format_kind::LINE; + } + static bool is_choice(format const & f) { + return to_int(car(f.m_value)) == format_kind::CHOICE; } friend format choice(format const & f1, format const & f2) { - return format(sexpr(sexpr(CHOICE), sexpr(f1.m_value, f2.m_value))); - } - friend format nest(int i, format const & f) { - return format(sexpr(sexpr(NEST), sexpr(sexpr(i), f.m_value))); + return format(sexpr_choice(f1.m_value, f2.m_value)); } - friend bool is_compose(format const & f) { - return is_cons(f.m_value) && to_int(car(f.m_value)) == format_kind::COMPOSE; - } - friend bool is_nest(format const & f) { - return is_cons(f.m_value) && to_int(car(f.m_value)) == format_kind::NEST; - } - friend bool is_text(format const & f) { - return !is_cons(f.m_value); - } - friend bool is_line(format const & f) { - return is_cons(f.m_value) && to_int(car(f.m_value)) == format_kind::LINE; - } - friend bool is_choice(format const & f) { - return is_cons(f.m_value) && to_int(car(f.m_value)) == format_kind::CHOICE; +public: + // Constructors + format():m_value(sexpr_nil()) {} + explicit format(sexpr const & v):m_value(v) {} + explicit format(char const * v):m_value(sexpr_text(sexpr(v))) {} + explicit format(std::string const & v):m_value(sexpr_text(sexpr(v))) {} + explicit format(int v):m_value(sexpr_text(sexpr(std::to_string(v)))) {} + explicit format(double v):m_value(sexpr_text(sexpr(std::to_string(v)))) {} + explicit format(name const & v):m_value(sexpr_text(sexpr(v))) {} + + // TODO: need to convert mpz and mpq to string, and then pass to sexpr + explicit format(mpz const & v):m_value(sexpr_text(sexpr(v))) {} + explicit format(mpq const & v):m_value(sexpr_text(sexpr(v))) {} + format(format const & f1, format const & f2):m_value(sexpr_compose({f1.m_value, f2.m_value})) {} + format(format const & f):m_value(f.m_value) {} + format(std::initializer_list const & l):format() { + lean_assert(l.size() >= 2); + auto it = l.begin(); + sexpr const & s1 = (it++)->m_value; + sexpr const & s2 = (it++)->m_value; + m_value = sexpr_compose({s1, s2}); + + m_value = std::accumulate(it, l.end(), m_value, + [](sexpr const & result, const format f) { + return sexpr_compose({result, f.m_value}); + } + ); } - friend format flatten(format const & f); + format_kind kind() const { + return sexpr_kind(m_value); + } + unsigned hash() const { return m_value.hash(); } + + friend format compose(format const & f1, format const & f2); + friend format nest(int i, format const & f); + friend format highlight(format const & f, format::format_color const c = RED); + friend format line(); + + friend format group(format const & f); + friend format above(format const & f1, format const & f2); + friend format bracket(std::string const l, format const & x, std::string const r); + friend format wrap(format const & f1, format const & f2); + + format & operator+=(format const & f) { + *this = format{*this, format(" "), f}; + return *this; + } + friend std::ostream & operator<<(std::ostream & out, format const & f); + // x <+> y = x <> text " " <> y + friend format operator+(format const & f1, format const & f2); + friend std::ostream & layout(std::ostream & out, sexpr const & s); + friend std::ostream & pretty(std::ostream & out, unsigned w, format const & f); }; -inline format line() { - return format(sexpr(format::format_kind::LINE)); -} +format wrap(format const & f1, format const & f2); +format compose(format const & f1, format const & f2); +format nest(int i, format const & f); +format highlight(format const & f, format::format_color const c); +format line(); +format group(format const & f); +format above(format const & f1, format const & f2); +format bracket(std::string const l, format const & x, std::string const r); +format wrap(format const & f1, format const & f2); +template +format folddoc(InputIterator first, InputIterator last, F f) { + auto first_elem = *first; + return std::accumulate(++first, last, first_elem, f); +} +template +format spread(InputIterator first, InputIterator last) { + return folddoc(first, last, compose); +} +template +format stack(InputIterator first, InputIterator last) { + return folddoc(first, last, above); +} +template +format fill(InputIterator first, InputIterator last) { + return folddoc(first, last, wrap); +} }