Skip to content

Commit a5c6892

Browse files
authored
Merge pull request #1525 from cryspen/rengine-pretty-multibackends
Rust Engine: allow multiple backends to implement the `Pretty` trait
2 parents 0f521c8 + 3669d63 commit a5c6892

File tree

6 files changed

+137
-2
lines changed

6 files changed

+137
-2
lines changed

Cargo.lock

Lines changed: 24 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

rust-engine/Cargo.toml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,3 +17,4 @@ serde_json = { workspace = true, features = ["unbounded_depth"] }
1717
schemars.workspace = true
1818
serde-jsonlines = "0.5.0"
1919
serde_stacker = "0.1.12"
20+
pretty = "0.12.4"

rust-engine/src/ast.rs

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1487,8 +1487,26 @@ pub mod traits {
14871487
};
14881488
}
14891489

1490-
derive_has_metadata!(Item, Expr, Pat);
1491-
derive_has_kind!(Item => ItemKind, Expr => ExprKind, Pat => PatKind);
1490+
derive_has_metadata!(
1491+
Item,
1492+
Expr,
1493+
Pat,
1494+
Guard,
1495+
Arm,
1496+
ImplItem,
1497+
TraitItem,
1498+
GenericParam
1499+
);
1500+
derive_has_kind!(
1501+
Item => ItemKind, Expr => ExprKind, Pat => PatKind, Guard => GuardKind,
1502+
GenericParam => GenericParamKind, ImplItem => ImplItemKind, TraitItem => TraitItemKind
1503+
);
1504+
1505+
impl HasSpan for Attribute {
1506+
fn span(&self) -> Span {
1507+
self.span.clone()
1508+
}
1509+
}
14921510

14931511
impl Typed for Expr {
14941512
fn ty(&self) -> &Ty {

rust-engine/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,5 @@
1111
pub mod ast;
1212
pub mod hax_io;
1313
pub mod ocaml_engine;
14+
pub mod printer;
1415
pub mod symbol;

rust-engine/src/printer.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
//! This modules provides types and helper for the printers of hax.
2+
3+
mod allocator;
4+
pub use allocator::Allocator;
Lines changed: 87 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,87 @@
1+
//! This module provides a custom [`pretty`] allocator, indexed by a printer,
2+
//! enabling multiple printers to cohexist and to implement the type `Pretty`.
3+
4+
use crate::ast::span::Span;
5+
use pretty::*;
6+
7+
/// A printer-specific [`pretty`] allocator.
8+
pub struct Allocator<Printer> {
9+
/// The pretty allocator
10+
allocator: BoxAllocator,
11+
/// Extra printer-specific context
12+
pub printer: Printer,
13+
}
14+
15+
impl<Printer> Allocator<Printer> {
16+
/// Creates a new allocator from a printer.
17+
pub fn new(printer: Printer) -> Self {
18+
Self {
19+
allocator: BoxAllocator,
20+
printer,
21+
}
22+
}
23+
}
24+
25+
impl<'a, P, A: 'a> DocAllocator<'a, A> for Allocator<P> {
26+
type Doc = <BoxAllocator as DocAllocator<'a, A>>::Doc;
27+
28+
fn alloc(&'a self, doc: Doc<'a, Self::Doc, A>) -> Self::Doc {
29+
self.allocator.alloc(doc)
30+
}
31+
32+
fn alloc_column_fn(
33+
&'a self,
34+
f: impl Fn(usize) -> Self::Doc + 'a,
35+
) -> <Self::Doc as DocPtr<'a, A>>::ColumnFn {
36+
self.allocator.alloc_column_fn(f)
37+
}
38+
39+
fn alloc_width_fn(
40+
&'a self,
41+
f: impl Fn(isize) -> Self::Doc + 'a,
42+
) -> <Self::Doc as DocPtr<'a, A>>::WidthFn {
43+
self.allocator.alloc_width_fn(f)
44+
}
45+
}
46+
47+
/// A helper type used to manually implement `Pretty` for types that carry spans.
48+
///
49+
/// By default, we implement the `Pretty` trait for all span-carrying
50+
/// types. These implementations annotate spans in the generated document, allowing
51+
/// source spans to be produced during pretty-printing. However, this default behavior
52+
/// does not provide access to the underlying data, which is sometimes necessary
53+
/// for custom printing logic.
54+
///
55+
/// For example, when printing an item, it's often useful to access its attributes.
56+
/// To support this, the default `Pretty` implementations delegate to `Manual<Item>`,
57+
/// which allows printers to access the inner value directly.
58+
///
59+
/// In practice, calling `expr.pretty(..)` will internally use
60+
/// `Manual(expr).pretty(..)`, enabling more flexible control over printing behavior.
61+
struct Manual<T>(T);
62+
63+
use crate::ast::*;
64+
macro_rules! impl_pretty_kind_meta {
65+
($($type:ty),*) => {
66+
$(impl<'a, 'b, P> Pretty<'a, Allocator<P>, Span> for &'b $type
67+
where
68+
Manual<&'b $type>: Pretty<'a, Allocator<P>, Span>,
69+
{
70+
fn pretty(self, allocator: &'a Allocator<P>) -> DocBuilder<'a, Allocator<P>, Span> {
71+
let doc = Manual(self).pretty(allocator);
72+
doc.annotate(self.span())
73+
}
74+
})*
75+
};
76+
}
77+
impl_pretty_kind_meta!(
78+
Item,
79+
Expr,
80+
Pat,
81+
Guard,
82+
Arm,
83+
ImplItem,
84+
TraitItem,
85+
GenericParam,
86+
Attribute
87+
);

0 commit comments

Comments
 (0)