typeset-parser
Compile-time macro parser for the typeset pretty printing library.
This crate provides the layout!
procedural macro that allows you to write typeset layouts using a concise DSL syntax instead of manually constructing layout trees with function calls.
Features
- Concise syntax - Write layouts using operators instead of nested function calls
- Compile-time parsing - Zero runtime overhead, all parsing happens during compilation
- Type-safe - Full type checking and error reporting at compile time
- IDE support - Syntax highlighting and completion in supported editors
Quick Start
Add both typeset
and typeset-parser
to your Cargo.toml
:
[]
= "2.0.5"
= "2.0.5"
Then use the macro in your code:
use *;
use layout;
let my_layout = layout! ;
let doc = compile;
println!;
DSL Syntax Reference
Text Literals
layout!
// Equivalent to: text("Hello, World!".to_string())
Variables
You can reference Rust variables containing Box<Layout>
values:
let name = text;
let greeting = layout! ;
Null Layout
layout!
// Equivalent to: null()
Composition Operators
Operator | Name | Equivalent Function Call | Description |
---|---|---|---|
& |
Unpadded composition | comp(left, right, false, false) |
Join without spaces |
+ |
Padded composition | comp(left, right, true, false) |
Join with spaces |
!& |
Fixed unpadded | comp(left, right, false, true) |
Unpadded with infix fix |
!+ |
Fixed padded | comp(left, right, true, true) |
Padded with infix fix |
@ |
Line break | line(left, right) |
Force line break |
@@ |
Double line break | line(left, line(null(), right)) |
Force blank line |
Layout Constructors
Constructor | Syntax | Equivalent Function Call | Description |
---|---|---|---|
fix |
fix(layout) |
fix(layout) |
Prevent breaking |
grp |
grp(layout) |
grp(layout) |
Group breaking |
seq |
seq(layout) |
seq(layout) |
Sequential breaking |
nest |
nest(layout) |
nest(layout) |
Fixed indentation |
pack |
pack(layout) |
pack(layout) |
Aligned indentation |
Examples
Basic Usage
use layout;
// Simple composition
let basic = layout! ;
// With line breaks
let multiline = layout! ;
Complex Layouts
// Function signature formatting
let params = vec!;
let function = layout! ;
Document Formatting
let document = layout! ;
JSON-like Structure
let json_object = layout! ;
Advanced Features
Operator Precedence
The DSL respects standard operator precedence:
- Parentheses
()
- highest precedence - Constructors
fix
,grp
,seq
,nest
,pack
- Line breaks
@
,@@
- Compositions
&
,!&
,+
,!+
- lowest precedence
Parentheses for Grouping
Use parentheses to override default precedence:
layout!
Infix Fixed Operators
The !&
and !+
operators create infix-fixed compositions, which are syntactic sugar for fixing the boundary between two layouts:
// These are equivalent:
layout!
comp
// Useful for separators that must stay attached:
layout!
Error Handling
The macro provides helpful compile-time error messages:
// This will produce a clear error:
layout!
// ^^^^^^^^^^^^^^^^
// Error: Expected a unary operator
Integration with Manual Construction
You can freely mix DSL syntax with manual constructor calls:
let manual_part = comp;
let mixed = layout! ;
Performance
- Zero runtime overhead - All parsing happens at compile time
- Efficient output - Generates the same code as manual constructor calls
- Compile-time optimization - The macro can optimize simple cases
Debugging
To see what code the macro generates, use cargo expand
(requires cargo-expand
):
This will show you the expanded Rust code that the macro produces.
Grammar Reference
The complete grammar for the layout DSL:
layout ::= binary | atom
binary ::= atom operator layout
atom ::= primary | unary
unary ::= constructor primary
primary ::= variable | string | null | "(" layout ")"
operator ::= "@" | "@@" | "&" | "!&" | "+" | "!+"
constructor ::= "fix" | "grp" | "seq" | "nest" | "pack"
variable ::= IDENT
string ::= STRING_LITERAL
null ::= "null"
Comparison with Manual Construction
Manual | DSL | Notes |
---|---|---|
text("hello".to_string()) |
"hello" |
Much more concise |
comp(a, b, true, false) |
a + b |
Clearer intent |
line(a, b) |
a @ b |
More readable |
nest(comp(a, b, true, false)) |
nest(a + b) |
Easy nesting |
Complex nested calls | Flat operator syntax | Much easier to read |
The DSL is especially valuable for complex layouts where manual construction becomes unwieldy.
Contributing
This is a procedural macro crate built with:
syn
for parsing Rust syntaxquote
for generating Rust codeproc-macro2
for token stream manipulation
The main parsing logic is in src/lib.rs
with a recursive descent parser for the layout DSL grammar.
See Also
- typeset - The core pretty printing library
- Examples - Comprehensive usage examples
- typeset documentation - API reference