Skip to content

Commit 52dc959

Browse files
committed
Add initial pretty-printing via pretty crate
1 parent c19f7c6 commit 52dc959

File tree

8 files changed

+157
-2
lines changed

8 files changed

+157
-2
lines changed

Cargo.toml

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,10 @@ authors = ["Markus Mayer <[email protected]>"]
1111
edition = "2021"
1212
rust-version = "1.68.0"
1313

14+
[features]
15+
default = ["pretty"]
16+
1417
[dependencies]
1518
nom = "7.1.3"
19+
pretty = { version = "0.12.1", optional = true }
1620
thiserror = "1.0.40"

src/lib.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,6 @@ mod briefcase_world;
44
pub mod parsers;
55
pub mod types;
66
pub(crate) mod visitor;
7+
8+
#[cfg(feature = "pretty")]
9+
pub(crate) mod pretty_print;

src/pretty_print/mod.rs

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
use pretty::RcDoc;
2+
3+
mod name;
4+
mod r#type;
5+
6+
#[derive(Default)]
7+
pub struct PrettyRenderer;
8+
9+
impl PrettyRenderer {
10+
pub fn to_pretty(&self, doc: RcDoc<'_>, width: usize) -> String {
11+
let mut w = Vec::new();
12+
doc.render(width, &mut w).unwrap();
13+
String::from_utf8(w).unwrap()
14+
}
15+
}
16+
17+
/// Helper macro to quickly prettify an element.
18+
#[cfg(test)]
19+
macro_rules! prettify {
20+
($x:expr, $n:literal) => {{
21+
let renderer = PrettyRenderer::default();
22+
let doc = $x.accept(&renderer);
23+
renderer.to_pretty(doc, $n)
24+
}};
25+
}
26+
27+
#[cfg(test)]
28+
pub(crate) use prettify;

src/pretty_print/name.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
use crate::pretty_print::PrettyRenderer;
2+
use crate::types::{FunctionSymbol, Name, Variable};
3+
use crate::visitor::Visitor;
4+
use pretty::RcDoc;
5+
6+
impl<'a> Visitor<Name<'a>, RcDoc<'a>> for PrettyRenderer {
7+
fn visit(&self, value: &Name<'a>) -> RcDoc<'a> {
8+
RcDoc::text(value.as_str())
9+
}
10+
}
11+
12+
impl<'a> Visitor<Variable<'a>, RcDoc<'a>> for PrettyRenderer {
13+
fn visit(&self, value: &Variable<'a>) -> RcDoc<'a> {
14+
RcDoc::text("?").append(value.as_str())
15+
}
16+
}
17+
18+
impl<'a> Visitor<FunctionSymbol<'a>, RcDoc<'a>> for PrettyRenderer {
19+
fn visit(&self, value: &FunctionSymbol<'a>) -> RcDoc<'a> {
20+
RcDoc::text(value.as_str())
21+
}
22+
}
23+
24+
#[cfg(test)]
25+
mod tests {
26+
use super::*;
27+
use crate::pretty_print::prettify;
28+
use crate::visitor::Accept;
29+
30+
#[test]
31+
fn name_works() {
32+
let x = Name::new("name");
33+
assert_eq!(prettify!(x, 10), "name");
34+
}
35+
36+
#[test]
37+
fn variable_works() {
38+
let x = Variable::new("var");
39+
assert_eq!(prettify!(x, 10), "?var");
40+
}
41+
42+
#[test]
43+
fn function_symbol_works() {
44+
let x = FunctionSymbol::new("fun-sym");
45+
assert_eq!(prettify!(x, 10), "fun-sym");
46+
}
47+
}

src/pretty_print/type.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
use crate::pretty_print::PrettyRenderer;
2+
use crate::types::{PrimitiveType, Type};
3+
use crate::visitor::{Accept, Visitor};
4+
use pretty::RcDoc;
5+
6+
impl<'a> Visitor<PrimitiveType<'a>, RcDoc<'a>> for PrettyRenderer {
7+
fn visit(&self, value: &PrimitiveType<'a>) -> RcDoc<'a> {
8+
RcDoc::text(value.as_str())
9+
}
10+
}
11+
12+
impl<'a> Visitor<Type<'a>, RcDoc<'a>> for PrettyRenderer {
13+
fn visit(&self, value: &Type<'a>) -> RcDoc<'a> {
14+
match value {
15+
Type::Exactly(t) => RcDoc::text(t.as_str()),
16+
Type::EitherOf(ts) => RcDoc::text("(either")
17+
.append(RcDoc::softline())
18+
.group()
19+
.nest(4)
20+
.append(RcDoc::intersperse(
21+
ts.iter().map(|t| t.accept(self)),
22+
RcDoc::softline(),
23+
))
24+
.nest(4)
25+
.group()
26+
.append(")"),
27+
}
28+
}
29+
}
30+
31+
#[cfg(test)]
32+
mod tests {
33+
use super::*;
34+
use crate::pretty_print::prettify;
35+
use crate::visitor::Accept;
36+
37+
#[test]
38+
fn primitive_type_works() {
39+
let x = PrimitiveType::new("pt");
40+
assert_eq!(prettify!(x, 10), "pt");
41+
}
42+
43+
#[test]
44+
fn simple_type_works() {
45+
let x = Type::from("a");
46+
assert_eq!(prettify!(x, 10), "a");
47+
}
48+
49+
#[test]
50+
fn either_type_works() {
51+
let x = Type::from_iter(["a", "b"]);
52+
assert_eq!(prettify!(x, 12), "(either a b)");
53+
assert_eq!(prettify!(x, 10), "(either a\n b)");
54+
assert_eq!(prettify!(x, 8), "(either\n a b)");
55+
}
56+
}

src/types/function_symbols.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,11 @@ use std::ops::Deref;
88
pub struct FunctionSymbol<'a>(Name<'a>);
99

1010
impl<'a> FunctionSymbol<'a> {
11+
#[inline(always)]
12+
pub fn new<N: Into<Name<'a>>>(name: N) -> Self {
13+
Self::from_name(name.into())
14+
}
15+
1116
#[inline(always)]
1217
pub const fn from_str(name: &'a str) -> Self {
1318
Self(Name::new(name))

src/types/name.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
//! Contains names.
1+
//! Contains the [`Name`] type.
22
33
use crate::types::{PrimitiveType, ToTyped, Type, Typed};
44
use std::fmt::{Display, Formatter};
@@ -14,6 +14,11 @@ impl<'a> Name<'a> {
1414
Self(name)
1515
}
1616

17+
#[inline(always)]
18+
pub const fn as_str(&self) -> &'a str {
19+
self.0
20+
}
21+
1722
pub const fn is_empty(&self) -> bool {
1823
self.0.is_empty()
1924
}

src/types/type.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,13 @@ impl<'a> Type<'a> {
4747
}
4848
}
4949

50+
impl<'a> PrimitiveType<'a> {
51+
#[inline(always)]
52+
pub fn new<T: Into<Name<'a>>>(t: T) -> Self {
53+
Self(t.into())
54+
}
55+
}
56+
5057
impl<'a> Default for Type<'a> {
5158
fn default() -> Self {
5259
Self::Exactly(TYPE_OBJECT)
@@ -105,7 +112,7 @@ impl<'a> AsRef<str> for PrimitiveType<'a> {
105112
}
106113

107114
impl<'a> Deref for PrimitiveType<'a> {
108-
type Target = str;
115+
type Target = Name<'a>;
109116

110117
fn deref(&self) -> &Self::Target {
111118
&self.0

0 commit comments

Comments
 (0)