pub trait PrettyPrint {
// Required method
fn render(&self) -> Document;
// Provided methods
fn to_pretty_string(&self) -> String { ... }
fn pretty_print(&self, f: &mut Formatter<'_>) -> Result<(), Error> { ... }
}
Expand description
The PrettyPrint trait is used as a building block for pretty printing data or syntax trees, as commonly seen in tools like Prettier.
It relies on providing the desired layout for a given type in the form of a Document. The pretty printer algorithm then renders this document to an output stream, using details of the output and the document to drive the choices it makes as it displays the document.
To get started, simply implement PrettyPrint::render for the type you wish to have pretty printed. You can then call PrettyPrint::to_pretty_string to obtain a String containing the pretty printed output, or if you have a core::fmt::Formatter handy, you can pretty print directly to that formatter using PrettyPrint::pretty_print.
§Example
The following is the AST for a simple expression language with a couple ops, that we wish to implement a pretty printer for. Let’s take a look at how that is done, and how we can make use of the various document constructors to acheive various effects:
use miden_formatting::prettier::{self, PrettyPrint, Document};
pub enum Expr {
Term(Term),
Binary(BinaryOp),
}
pub struct BinaryOp {
pub op: Op,
pub lhs: Box<Expr>,
pub rhs: Box<Expr>,
}
#[derive(Copy, Clone)]
pub enum Op {
Add,
Sub,
Mul,
}
pub enum Term {
Var(String),
Num(isize),
}
impl PrettyPrint for Expr {
fn render(&self) -> Document {
match self {
Self::Term(term) => term.render(),
Self::Binary(expr) => expr.render(),
}
}
}
/// We can trivially implement Display for our AST with our PrettyPrint impl
impl core::fmt::Display for Expr {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
self.pretty_print(f)
}
}
impl PrettyPrint for BinaryOp {
fn render(&self) -> Document {
// Bring all of the document constructors into scope
use prettier::*;
let maybe_wrap = move |expr: &Expr| -> Document {
match expr {
Expr::Term(term) => term.render(),
Expr::Binary(expr) => '(' + expr.render() + ')',
}
};
// When the printer runs out of space to hold more of the document on a single line,
// it will prefer to introduce breaks at `nl`, but may also choose to break at any
// point where two documents are joined together. We can guide this behavior by providing
// a choice between two documents: the first being the single-line layout, and the second
// being the multi-line layout. The printer will choose the single-line layout unless it
// has insufficient space for it, in which case it will choose the multi-line layout instead.
let single_line = self.lhs.render()
+ ' '
+ display(self.op)
+ ' '
+ maybe_wrap(&self.rhs);
// Here, we're choosing to break after the operator, indent 4 spaces, then continue to
// print the remainder of the expression, e.g:
//
// $a + ($b * ($c -
// 256))
let multi_line =
indent(4, flatten(self.lhs.render() + ' ' + display(self.op))
+ nl()
+ maybe_wrap(&self.rhs)
);
single_line | multi_line
}
}
impl PrettyPrint for Term {
fn render(&self) -> Document {
use prettier::*;
// NOTE: We could have just used a Display impl for Term, but in more complex syntaxes
// terms might have aggregate data structures and things of that nature, where more
// complex pretty printing is desired. For now, this just demonstrates how you can
// implement PrettyPrint for types you don't control with custom formatting.
match self {
Self::Var(v) => text(format!("${v}")),
Self::Num(n) => display(*n),
}
}
}
/// Rather than implement both PrettyPrint and Display for things which reduce to keywords,
/// integers, etc., you can simply delegate to the Display implementation when building the
/// higher-level PrettyPrint impls using the `display` helper.
impl core::fmt::Display for Op {
fn fmt(&self, f: &mut core::fmt::Formatter) -> core::fmt::Result {
match self {
Self::Add => f.write_str("+"),
Self::Sub => f.write_str("-"),
Self::Mul => f.write_str("*"),
}
}
}
See the documentation for the various Document constructors for more information on their usage and semantics. I would recommend starting with indent, as that is a common one that you will want to use.
Required Methods§
Sourcefn render(&self) -> Document
fn render(&self) -> Document
The core of the PrettyPrint functionality.
When called, the implementation must render a Document which represents the layout of the thing being pretty-printed. The rendered Document is then displayed via the pretty printer, using details about the output stream, and the structure of the document, to make decisions about when and where to introduce line breaks, etc.
Implementations do not need to worry about or manage things like the width of the output, indentation level, etc. Instead the focus is purely on the layout, leaving the heavy lifting to the pretty printer.
This method is the only one required to be implemented.
Provided Methods§
Sourcefn to_pretty_string(&self) -> String
fn to_pretty_string(&self) -> String
Produce a String containing the results of pretty-printing this object.
The string is formatted with an assumed width of 80 columns. If you wish to customize this,
you should instead prefer to use PrettyPrint::pretty_print, or if you have implemented
core::fmt::Display for this type by delegating to PrettyPrint::pretty_print, you can
use the Rust formatting syntax to do this, e.g. format!("{:width$}", self, width = 100)
Sourcefn pretty_print(&self, f: &mut Formatter<'_>) -> Result<(), Error>
fn pretty_print(&self, f: &mut Formatter<'_>) -> Result<(), Error>
Pretty-print this object to the given core::fmt::Formatter.
You may implement core::fmt::Display for your type in terms of this function like so:
impl fmt::Display for Foo {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
self.pretty_print(f)
}
}
Trait Implementations§
Implementations on Foreign Types§
Source§impl PrettyPrint for ConstantExpr
impl PrettyPrint for ConstantExpr
Source§impl PrettyPrint for SystemEventNode
impl PrettyPrint for SystemEventNode
Source§impl PrettyPrint for DebugOptions
impl PrettyPrint for DebugOptions
Source§impl PrettyPrint for Instruction
impl PrettyPrint for Instruction
Source§impl PrettyPrint for InvocationTarget
impl PrettyPrint for InvocationTarget
Source§impl PrettyPrint for AliasTarget
impl PrettyPrint for AliasTarget
Source§impl PrettyPrint for DebugOptions
impl PrettyPrint for DebugOptions
Source§impl PrettyPrint for AddressSpace
impl PrettyPrint for AddressSpace
Source§impl PrettyPrint for String
impl PrettyPrint for String
Source§impl PrettyPrint for ProcedureAlias
impl PrettyPrint for ProcedureAlias
Source§impl PrettyPrint for FunctionType
impl PrettyPrint for FunctionType
Source§impl PrettyPrint for PointerType
impl PrettyPrint for PointerType
Source§impl PrettyPrint for StructField
impl PrettyPrint for StructField
Source§impl PrettyPrint for StructType
impl PrettyPrint for StructType
Source§impl<'a> PrettyPrint for Cow<'a, str>
impl<'a> PrettyPrint for Cow<'a, str>
Source§impl<'a, T> PrettyPrint for &'a Twhere
T: PrettyPrint + ?Sized,
impl<'a, T> PrettyPrint for &'a Twhere
T: PrettyPrint + ?Sized,
Source§impl<K, V> PrettyPrint for BTreeMap<K, V>where
K: PrettyPrint,
V: PrettyPrint,
impl<K, V> PrettyPrint for BTreeMap<K, V>where
K: PrettyPrint,
V: PrettyPrint,
Source§impl<T> PrettyPrint for Immediate<T>where
T: PrettyPrint,
impl<T> PrettyPrint for Immediate<T>where
T: PrettyPrint,
Source§impl<T> PrettyPrint for Box<T>where
T: PrettyPrint,
impl<T> PrettyPrint for Box<T>where
T: PrettyPrint,
Source§impl<T> PrettyPrint for BTreeSet<T>where
T: PrettyPrint,
impl<T> PrettyPrint for BTreeSet<T>where
T: PrettyPrint,
Source§impl<T> PrettyPrint for Rc<T>where
T: PrettyPrint,
impl<T> PrettyPrint for Rc<T>where
T: PrettyPrint,
Source§impl<T> PrettyPrint for Arc<T>where
T: PrettyPrint,
impl<T> PrettyPrint for Arc<T>where
T: PrettyPrint,
Source§impl<T> PrettyPrint for Vec<T>where
T: PrettyPrint,
impl<T> PrettyPrint for Vec<T>where
T: PrettyPrint,
Source§impl<T> PrettyPrint for Span<T>where
T: PrettyPrint,
impl<T> PrettyPrint for Span<T>where
T: PrettyPrint,
Implementors§
impl PrettyPrint for SystemEvent
impl PrettyPrint for PrintableProcedure
impl PrettyPrint for AccountCode
impl PrettyPrint for Module
The pretty-printer for Module