Update format.cpp & format.h + Update format tests

This commit is contained in:
Soonho Kong 2013-07-24 17:50:51 -07:00
parent 092b8889e4
commit a7910e1fe7
3 changed files with 458 additions and 161 deletions

View file

@ -4,49 +4,85 @@ Released under Apache 2.0 license as described in the file LICENSE.
Author: Soonho Kong
*/
#include <vector>
#include <algorithm>
#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<std::pair<std::string, format> > 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<std::string, format> 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<std::string> 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<std::string> ss = {"Last", "weekend's", "revelation", "that", "J.K.", "Rowling", "is", "the", "author", "of", "the", "critically", "acclaimed"};
std::vector<format> 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() {

View file

@ -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 <cstring>
#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<format::format_color>(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);
}
}

View file

@ -6,7 +6,9 @@ Author: Soonho Kong
*/
#pragma once
#include "sexpr.h"
#include "debug.h"
#include <iostream>
#include <algorithm>
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<format_kind>(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<format_kind>(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<sexpr> 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<format_color>(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<typename T>
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<format> 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 <class InputIterator, typename F>
format folddoc(InputIterator first, InputIterator last, F f) {
auto first_elem = *first;
return std::accumulate(++first, last, first_elem, f);
}
template <class InputIterator>
format spread(InputIterator first, InputIterator last) {
return folddoc(first, last, compose);
}
template <class InputIterator>
format stack(InputIterator first, InputIterator last) {
return folddoc(first, last, above);
}
template <typename InputIterator>
format fill(InputIterator first, InputIterator last) {
return folddoc(first, last, wrap);
}
}