/home/vfoley/projects/ppbert
/mnt/font/Go Mono/12a/font
/mnt/font/Go Mono/16a/font
0.0000000 59.8437500
w win win Newcol Kill Putall Dump Exit Dump /home/vfoley/projects/ppbert/acme.dump
c 0 New Cut Paste Snarf Sort Zerox Delcol
c 1 New Cut Paste Snarf Sort Zerox Delcol Font
F 0 0 0 0 1.8216683 5388
1 66 5388 0 1 /home/vfoley/projects/ppbert/src/bertterm.rs Del Snarf | Look Font
use std::fmt::{self, Write};
use num::bigint;
pub const DEFAULT_INDENT_WIDTH: usize = 2;
pub const DEFAULT_MAX_TERMS_PER_LINE: usize = 4;
#[derive(Debug, PartialEq)]
pub enum BertTerm {
Nil,
Int(i32),
BigInt(bigint::BigInt),
Float(f64),
Atom(String),
Tuple(Vec<BertTerm>),
List(Vec<BertTerm>),
Map(Vec<BertTerm>, Vec<BertTerm>),
String(Vec<u8>),
Binary(Vec<u8>)
}
impl BertTerm {
fn is_basic(&self) -> bool {
match *self {
BertTerm::Int(_)
| BertTerm::BigInt(_)
| BertTerm::Float(_)
| BertTerm::Atom(_)
| BertTerm::String(_)
| BertTerm::Binary(_)
| BertTerm::Nil => true,
BertTerm::List(_)
| BertTerm::Tuple(_)
| BertTerm::Map(_, _) => false
}
}
}
impl fmt::Display for BertTerm {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
let pp = PrettyPrinter::new(self,
DEFAULT_INDENT_WIDTH,
DEFAULT_MAX_TERMS_PER_LINE);
write!(f, "{}", pp)
}
}
pub struct PrettyPrinter<'a> {
term: &'a BertTerm,
indent_width: usize,
max_terms_per_line: usize
}
impl <'a> fmt::Display for PrettyPrinter<'a> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.write_term(self.term, f, 0)
}
}
impl <'a> PrettyPrinter<'a> {
/// Creates a pretty printer for `term` where sub-terms
/// are indented with a width of `indent_width` and a
/// maximum of `max_terms_per_line` basic terms (i.e.,
/// integers, floats, strings) can be printed per line.
pub fn new(term: &'a BertTerm,
indent_width: usize,
max_terms_per_line: usize) -> Self {
PrettyPrinter { term, indent_width, max_terms_per_line }
}
fn write_term(&self, term: &BertTerm, f: &mut fmt::Formatter, depth: usize) -> fmt::Result {
match *term {
BertTerm::Nil => f.write_str("[]"),
BertTerm::Int(n) => write!(f, "{}", n),
BertTerm::BigInt(ref n) => write!(f, "{}", n),
BertTerm::Float(x) => write!(f, "{}", x),
BertTerm::Atom(ref s) => f.write_str(s),
BertTerm::String(ref bytes) => self.write_string(bytes, f, "\"", "\""),
BertTerm::Binary(ref bytes) => self.write_string(bytes, f, "<<\"", "\">>"),
BertTerm::List(ref terms) => self.write_collection(terms, f, depth, '[', ']'),
BertTerm::Tuple(ref terms) => self.write_collection(terms, f, depth, '{', '}'),
BertTerm::Map(ref keys, ref vals) => self.write_map(keys, vals, f, depth)
}
}
fn write_string(&self,
bytes: &[u8],
f: &mut fmt::Formatter,
open: &str,
close: &str) -> fmt::Result {
f.write_str(open)?;
for &b in bytes {
if is_printable(b) {
f.write_char(b as char)?;
} else {
write!(f, "\\x{:02x}", b)?;
}
}
f.write_str(close)
}
fn write_collection(&self,
terms: &[BertTerm],
f: &mut fmt::Formatter,
depth: usize,
open: char,
close: char) -> fmt::Result {
let multi_line = !self.is_small_collection(terms);
// Every element will have the same indentation,
// so pre-compute it once.
let prefix =
if multi_line {
self.indentation(depth+1)
} else {
String::new()
};
f.write_char(open)?;
let mut comma = "";
for t in terms {
f.write_str(comma)?;
f.write_str(&prefix)?;
self.write_term(t, f, depth + 1)?;
comma = ", ";
}
if multi_line {
f.write_str(&self.indentation(depth))?;
}
f.write_char(close)
}
fn write_map(&self,
keys: &[BertTerm],
vals: &[BertTerm],
f: &mut fmt::Formatter,
depth: usize) -> fmt::Result {
let multi_line =
!self.is_small_collection(keys) || !self.is_small_collection(vals);
let prefix =
if multi_line {
self.indentation(depth+1)
} else {
String::new()
};
f.write_str("#{")?;
let mut comma = "";
for i in 0 .. keys.len() {
f.write_str(comma)?;
f.write_str(&prefix)?;
self.write_term(&keys[i], f, depth + 1)?;
f.write_str(" => ")?;
self.write_term(&vals[i], f, depth + 1)?;
comma = ", ";
}
if multi_line {
f.write_str(&self.indentation(depth))?;
}
f.write_str("}")
}
fn is_small_collection(&self, terms: &[BertTerm]) -> bool {
terms.len() <= self.max_terms_per_line &&
terms.iter().all(BertTerm::is_basic)
}
fn indentation(&self, depth: usize) -> String {
::std::iter::once('\n')
.chain((0 .. depth * self.indent_width).map(|_| ' '))
.collect()
}
}
fn is_printable(b: u8) -> bool {
b >= 0x20 && b <= 0x7e
}
f 1 2 0 0 1.8216683
2 54 113 1 0 /home/vfoley/projects/ppbert/ Del Snarf Get | Look win
f 1 3 0 0 5.3691275
3 55 57 1 0 /home/vfoley/projects/ppbert/src/ Del Snarf Get | Look
F 1 2 1162 1162 13.8063279 1162
4 58 1162 0 1 /home/vfoley/projects/ppbert/src/+Errors Del Snarf | Look
Compiling ppbert v0.2.3 (file:///home/vfoley/projects/ppbert)
Finished dev [unoptimized + debuginfo] target(s) in 6.19 secs
Compiling ppbert v0.2.3 (file:///home/vfoley/projects/ppbert)
Finished dev [unoptimized + debuginfo] target(s) in 1.19 secs
Running /home/vfoley/projects/ppbert/target/debug/deps/parser_integration-627579b80b29e501
running 15 tests
test atom ... ok
test atom_utf8 ... ok
test binary ... ok
test bigint ... ok
test integer ... ok
test map ... ok
test list ... ok
test new_float ... ok
test nil ... ok
test old_float ... ok
test small_integer ... ok
test string ... ok
test tuple ... ok
test magic_number ... ok
test consume_all ... ok
test result: ok. 15 passed; 0 failed; 0 ignored; 0 measured
Running /home/vfoley/projects/ppbert/target/debug/deps/ppbert-c4fa1d43729b2869
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
Running /home/vfoley/projects/ppbert/target/debug/deps/ppbert-68ce8e46f7510931
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
Doc-tests ppbert
running 0 tests
test result: ok. 0 passed; 0 failed; 0 ignored; 0 measured
e 1 0 0 0 41.8024928
7 57 20 0 1 /home/vfoley/projects/ppbert/-t470 Del Snarf | Look Send
/home/vfoley/projects/ppbert/
win
F 1 4 12 22 78.5234899 22
5 56 22 0 1 /home/vfoley/projects/ppbert/src/guide Del Snarf | Look
cargo build
cargo test