PrettyPrint

Trait PrettyPrint 

Source
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§

Source

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§

Source

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)

Source

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§

Source§

impl Display for dyn PrettyPrint

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Formats the value using the given formatter. Read more

Implementations on Foreign Types§

Source§

impl PrettyPrint for Attribute

Source§

impl PrettyPrint for MetaExpr

Source§

impl PrettyPrint for ConstantExpr

Source§

impl PrettyPrint for SystemEventNode

Source§

impl PrettyPrint for DebugOptions

Source§

impl PrettyPrint for Instruction

Source§

impl PrettyPrint for InvocationTarget

Source§

impl PrettyPrint for Op

Source§

impl PrettyPrint for AliasTarget

Source§

impl PrettyPrint for Export

Source§

impl PrettyPrint for IntValue

Source§

impl PrettyPrint for DebugOptions

Source§

impl PrettyPrint for Decorator

Source§

impl PrettyPrint for Operation

Source§

impl PrettyPrint for Type

Source§

impl PrettyPrint for CallConv

Source§

impl PrettyPrint for AddressSpace

Source§

impl PrettyPrint for TypeRepr

Source§

impl PrettyPrint for bool

Source§

impl PrettyPrint for i8

Source§

impl PrettyPrint for i16

Source§

impl PrettyPrint for i32

Source§

impl PrettyPrint for i64

Source§

impl PrettyPrint for i128

Source§

impl PrettyPrint for isize

Source§

impl PrettyPrint for str

Source§

impl PrettyPrint for u8

Source§

impl PrettyPrint for u16

Source§

impl PrettyPrint for u32

Source§

impl PrettyPrint for u64

Source§

impl PrettyPrint for u128

Source§

impl PrettyPrint for usize

Source§

impl PrettyPrint for String

Source§

fn render(&self) -> Document

Source§

fn pretty_print(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Source§

impl PrettyPrint for NonZero<i8>

Source§

impl PrettyPrint for NonZero<i16>

Source§

impl PrettyPrint for NonZero<i32>

Source§

impl PrettyPrint for NonZero<i64>

Source§

impl PrettyPrint for NonZero<i128>

Source§

impl PrettyPrint for NonZero<isize>

Source§

impl PrettyPrint for NonZero<u8>

Source§

impl PrettyPrint for NonZero<u16>

Source§

impl PrettyPrint for NonZero<u32>

Source§

impl PrettyPrint for NonZero<u64>

Source§

impl PrettyPrint for NonZero<u128>

Source§

impl PrettyPrint for NonZero<usize>

Source§

impl PrettyPrint for Block

Source§

impl PrettyPrint for Constant

Source§

impl PrettyPrint for DocString

Source§

impl PrettyPrint for Import

Source§

impl PrettyPrint for ProcedureAlias

Source§

impl PrettyPrint for Procedure

Source§

impl PrettyPrint for WordValue

Source§

impl PrettyPrint for ArrayType

Source§

impl PrettyPrint for FunctionType

Source§

impl PrettyPrint for PointerType

Source§

impl PrettyPrint for StructField

Source§

impl PrettyPrint for StructType

Source§

impl<'a> PrettyPrint for Cow<'a, str>

Source§

fn render(&self) -> Document

Source§

fn pretty_print(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Source§

impl<'a, T> PrettyPrint for &'a T
where T: PrettyPrint + ?Sized,

Source§

impl<K, V> PrettyPrint for BTreeMap<K, V>
where K: PrettyPrint, V: PrettyPrint,

Source§

impl<T> PrettyPrint for Immediate<T>
where T: PrettyPrint,

Source§

impl<T> PrettyPrint for Box<T>
where T: PrettyPrint,

Source§

fn render(&self) -> Document

Source§

fn pretty_print(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Source§

impl<T> PrettyPrint for BTreeSet<T>
where T: PrettyPrint,

Source§

impl<T> PrettyPrint for Rc<T>
where T: PrettyPrint,

Source§

fn render(&self) -> Document

Source§

fn pretty_print(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Source§

impl<T> PrettyPrint for Arc<T>
where T: PrettyPrint,

Source§

fn render(&self) -> Document

Source§

fn pretty_print(&self, f: &mut Formatter<'_>) -> Result<(), Error>

Source§

impl<T> PrettyPrint for Vec<T>
where T: PrettyPrint,

Source§

impl<T> PrettyPrint for Span<T>
where T: PrettyPrint,

Implementors§