Skip to content

Commit

Permalink
feat: Add the BlockDoc formatter
Browse files Browse the repository at this point in the history
Refinement of the formatter I have used use to format lambdas, object and array expressions (and other similar expressions) in [gluon](https://github.com/gluon-lang/gluon) (later refined in [flux](https://github.com/influxdata/flux)).
  • Loading branch information
Marwes committed Mar 30, 2023
1 parent 83ade2c commit d4106e4
Show file tree
Hide file tree
Showing 3 changed files with 85 additions and 6 deletions.
1 change: 1 addition & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ unicode-segmentation = "1"
[dev-dependencies]
criterion = "0.4"
difference = "2"
expect-test = "1"
tempfile = "3.1.0"

[[example]]
Expand Down
83 changes: 79 additions & 4 deletions src/block.rs
Original file line number Diff line number Diff line change
@@ -1,4 +1,8 @@
use super::*;
//! Document formatting of "blocks" such as where some number of prefixes and suffixes would
//! ideally be layed out onto a single line instead of breaking them up into multiple lines. See
//! `BlockDoc` for an example

use crate::{docs, Doc, DocAllocator, DocBuilder};

pub struct Affixes<'doc, D, A>
where
Expand Down Expand Up @@ -42,7 +46,35 @@ where
}
}

/// Formats a set of `prefix` and `suffix` documents around a body
/// Formats a set of `prefix` and `suffix` documents around a `body`
///
/// The following document split into the prefixes [\x y ->, \z ->, {], suffixes [nil, nil, }] and
/// body [result: x + y - z] will try to be formatted
///
/// ```gluon
/// \x y -> \z -> { result: x + y - z }
/// ```
///
/// ```gluon
/// \x y -> \z -> {
/// result: x + y - z
/// }
/// ```
///
/// ```gluon
/// \x y -> \z ->
/// {
/// result: x + y - z
/// }
/// ```
///
/// ```gluon
/// \x y ->
/// \z ->
/// {
/// result: x + y - z
/// }
/// ```
pub struct BlockDoc<'doc, D, A>
where
D: DocAllocator<'doc, A>,
Expand All @@ -57,10 +89,9 @@ where
D::Doc: Clone,
A: Clone,
{
pub fn format(mut self, nest: isize) -> DocBuilder<'doc, D, A> {
pub fn format(self, nest: isize) -> DocBuilder<'doc, D, A> {
let arena = self.body.0;

self.affixes.reverse();
let fail_on_multi_line = arena.fail().flat_alt(arena.nil());

(1..self.affixes.len() + 1)
Expand Down Expand Up @@ -124,3 +155,47 @@ where
.unwrap_or(self.body)
}
}

#[cfg(test)]
mod tests {
use super::*;

use crate::Arena;

#[test]
fn format_block() {
let arena = &Arena::<()>::new();
let mk_doc = || BlockDoc {
affixes: vec![
Affixes::new(docs![arena, "\\x y ->"], arena.nil()).nest(),
Affixes::new(docs![arena, arena.line(), "\\z ->"], arena.nil()).nest(),
Affixes::new(
docs![arena, arena.line(), "{"],
docs![arena, arena.line(), "}"],
)
.nest(),
],
body: docs![arena, arena.line(), "result"],
};
expect_test::expect![[r#"\x y -> \z -> { result }"#]]
.assert_eq(&mk_doc().format(4).1.pretty(40).to_string());
expect_test::expect![[r#"
\x y -> \z -> {
result
}"#]]
.assert_eq(&mk_doc().format(4).1.pretty(15).to_string());
expect_test::expect![[r#"
\x y -> \z ->
{
result
}"#]]
.assert_eq(&mk_doc().format(4).1.pretty(14).to_string());
expect_test::expect![[r#"
\x y ->
\z ->
{
result
}"#]]
.assert_eq(&mk_doc().format(4).1.pretty(12).to_string());
}
}
7 changes: 5 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,7 @@ use std::{
#[cfg(feature = "termcolor")]
use termcolor::{ColorSpec, WriteColor};

mod block;
pub mod block;
mod render;

pub use self::block::{Affixes, BlockDoc};
Expand Down Expand Up @@ -1224,7 +1224,10 @@ where
/// ```
#[macro_export]
macro_rules! docs {
($alloc: expr, $first: expr $(, $rest: expr)* $(,)?) => {{
($alloc: expr, $first: expr $(,)?) => {
$crate::Pretty::pretty($first, $alloc)
};
($alloc: expr, $first: expr $(, $rest: expr)+ $(,)?) => {{
let mut doc = $crate::Pretty::pretty($first, $alloc);
$(
doc = doc.append($rest);
Expand Down

0 comments on commit d4106e4

Please sign in to comment.