Expand description

A proc macro for pretty-printing ASTs and other recursive data structures.

Basic Usage

Refer to the snippet below for a basic usage example, and see the integration test and these two repos (#1.1 + #1.2, #2.1) for larger samples.

// Import the macro
use ast2str::AstToStr;

type Span = std::ops::Range<usize>;

// Annotate some structs and enums as desired
#[derive(AstToStr)]
struct Label {
   #[quoted]
   name: &'static str,
   #[default = "Unresolved"]
   location: Option<usize>,
}

#[derive(AstToStr)]
enum Expr {
    Binary {
        left: Box<Expr>,
        #[quoted]
        operator: &'static str,
        right: Box<Expr>
    },
    Literal(#[rename = "value"] i32, #[skip] Span),
    List { items: Vec<Expr> },
    Label(#[forward] Label),
    Optional {
        #[skip_if = "Option::is_none"]
        value: Option<&'static str>
    }
}

let expr = Expr::Binary {
    left: Box::new(Expr::Literal(5, Span::default())),
    operator: "+",
    right: Box::new(Expr::List { items: vec![
       Expr::Label(Label { name: "x", location: Some(0) }),
       Expr::Label(Label { name: "y", location: Some(1) }),
       Expr::Label(Label { name: "z", location: None }),
       Expr::Optional { value: None },
       Expr::Optional { value: Some("a string") },
    ]})
};
assert_eq!(expr.ast_to_str(), r#"
Expr::Binary
├─left: Expr::Literal
│ ╰─value: 5
├─operator: `+`
╰─right: Expr::List
  ╰─items=↓
    ├─Label
    │ ├─name: `x`
    │ ╰─location: 0
    ├─Label
    │ ├─name: `y`
    │ ╰─location: 1
    ├─Label
    │ ├─name: `z`
    │ ╰─location: Unresolved
    ├─Expr::Optional
    ╰─Expr::Optional
      ╰─value: "a string"
"#.trim());

// The symbols used to draw the tree can be configured using the [`Symbols`] trait:
assert_eq!(expr.ast_to_str_impl(&ast2str::TestSymbols), r#"
Expr::Binary
  left: Expr::Literal
    value: 5
  operator: `+`
  right: Expr::List
    items=
      Label
        name: `x`
        location: 0
      Label
        name: `y`
        location: 1
      Label
        name: `z`
        location: Unresolved
      Expr::Optional
      Expr::Optional
        value: "a string"
"#.trim());

Available Attributes

Attribute
NoneFormat the value with AstToStr
#[forward]Skip all other fields and return the AstToStr of the annotated field
#[skip]Skip the annotated field
#[display]Format the annotated field with Display instead of AstToStr
#[debug]Format the annotated field with Debug instead of AstToStr
#[quoted]Like #[display] but also wraps the value with backticks
#[list]Format the annotated field by executing AstToStr on every element of (&field).into_iter()
#[list(name_or_closure)Format the annotated field by applying the callback on every element of (&field).into_iter()
#[callback(name_or_closure)]Apply the given function or closure to &field and return the result
#[delegate = "getter"]Call self.getter() and format the result as a field
#[default = "value"]Only applies to Option types. If the value is Some(T), format &T with AstToStr. Otherwise, return the value of default
#[skip_if = "my_condition_fn"]Skip the annotated field if the specified function returns true

Re-exports

pub use ast2str_lib;

Modules

This module defines the data structures and functions used to draw trees.

This module contains a simple wrapper for formatting Display objects as Debug and an extension method that can be called on strings. Mainly useful for testing.

Structs

The default set of symbols that produces neatly-drawn trees.

A set of symbols where every symbol is either whitespace ( ) or an empty string.

A builder struct for formatting AST nodes.

Traits

A trait for printing ASTs in a pretty manner.

A trait for supplying symbols to the AST formatting functions.

Derive Macros

Automatically implements the AstToStr trait for the given struct or enum. Every field of the given item must implement AstToStr or be annotated with one of the the attributes.