Skip to content

Commit cfb2c6c

Browse files
authored
Merge pull request #1518 from cryspen/rengine-add-resguaring-nodes
Rust Engine: intro. resugared AST fragment
2 parents b88388d + a5c6892 commit cfb2c6c

File tree

7 files changed

+207
-2
lines changed

7 files changed

+207
-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: 52 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ pub mod diagnostics;
1414
pub mod fragment;
1515
pub mod identifiers;
1616
pub mod literals;
17+
pub mod resugared;
1718
pub mod span;
1819

1920
use crate::symbol::Symbol;
@@ -22,6 +23,7 @@ use fragment::Fragment;
2223
use hax_rust_engine_macros::*;
2324
use identifiers::*;
2425
use literals::*;
26+
use resugared::*;
2527
use span::Span;
2628

2729
/// Represents a generic value used in type applications (e.g., `T` in `Vec<T>`).
@@ -171,6 +173,11 @@ pub enum TyKind {
171173
/// ```
172174
Dyn(Vec<DynTraitGoal>),
173175

176+
/// A resugared type.
177+
/// This variant is introduced before printing only.
178+
/// Phases must not produce this variant.
179+
Resugared(ResugaredTyKind),
180+
174181
/// Fallback constructor to carry errors.
175182
Error(Diagnostic),
176183
}
@@ -368,6 +375,11 @@ pub enum PatKind {
368375
fields: Vec<(GlobalId, Pat)>,
369376
},
370377

378+
/// A resugared pattern.
379+
/// This variant is introduced before printing only.
380+
/// Phases must not produce this variant.
381+
Resugared(ResugaredPatKind),
382+
371383
/// Fallback constructor to carry errors.
372384
Error(Diagnostic),
373385
}
@@ -582,6 +594,11 @@ pub enum ImplItemKind {
582594
/// The list of the argument for the associated function (`&self` in the example).
583595
params: Vec<Param>,
584596
},
597+
598+
/// A resugared impl item.
599+
/// This variant is introduced before printing only.
600+
/// Phases must not produce this variant.
601+
Resugared(ResugaredImplItemKind),
585602
}
586603

587604
/// Represents a trait item (associated type, fn, or default)
@@ -628,6 +645,11 @@ pub enum TraitItemKind {
628645
/// The default body of the associated function (`x + 2` in the example).
629646
body: Expr,
630647
},
648+
649+
/// A resugared trait item.
650+
/// This variant is introduced before printing only.
651+
/// Phases must not produce this variant.
652+
Resugared(ResugaredTraitItemKind),
631653
}
632654

633655
/// A QuoteContent is a component of a quote: it can be a verbatim string, a Rust expression to embed in the quote, a pattern etc.
@@ -1019,6 +1041,11 @@ pub enum ExprKind {
10191041
contents: Quote,
10201042
},
10211043

1044+
/// A resugared expression.
1045+
/// This variant is introduced before printing only.
1046+
/// Phases must not produce this variant.
1047+
Resugared(ResugaredExprKind),
1048+
10221049
/// Fallback constructor to carry errors.
10231050
Error(Diagnostic),
10241051
}
@@ -1388,6 +1415,11 @@ pub enum ItemKind {
13881415
/// Fallback constructor to carry errors.
13891416
Error(Diagnostic),
13901417

1418+
/// A resugared item.
1419+
/// This variant is introduced before printing only.
1420+
/// Phases must not produce this variant.
1421+
Resugared(ResugaredItemKind),
1422+
13911423
/// Item that is not implemented yet
13921424
NotImplementedYet,
13931425
}
@@ -1455,8 +1487,26 @@ pub mod traits {
14551487
};
14561488
}
14571489

1458-
derive_has_metadata!(Item, Expr, Pat);
1459-
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+
}
14601510

14611511
impl Typed for Expr {
14621512
fn ty(&self) -> &Ty {

rust-engine/src/ast/resugared.rs

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
//! This module defines *resugared fragments* for the Hax Rust engine's AST.
2+
//!
3+
//! A resugared fragment is an additional AST node used solely for pretty-printing purposes.
4+
//! These nodes carry no semantic meaning in hax core logic but enable more accurate
5+
//! or backend-specific surface syntax reconstruction.
6+
//!
7+
//! For example, the engine represents the `unit` type as a zero-sized tuple `()`,
8+
//! mirroring Rust's internal representation. However, this may not suit all backends:
9+
//! in F*, `unit` is explicitly written as `unit`, not `()`.
10+
//!
11+
//! To accommodate such differences, we introduce resugared fragments (e.g. `UnitType`) that
12+
//! allow the printer to emit the expected syntax while maintaining the same internal semantics.
13+
14+
use hax_rust_engine_macros::*;
15+
16+
/// Resugared variants for items. This represent extra printing-only items, see [`super::ItemKind::Resugared`].
17+
#[derive_group_for_ast]
18+
pub enum ResugaredItemKind {}
19+
20+
/// Resugared variants for expressions. This represent extra printing-only expressions, see [`super::ExprKind::Resugared`].
21+
#[derive_group_for_ast]
22+
pub enum ResugaredExprKind {}
23+
24+
/// Resugared variants for patterns. This represent extra printing-only patterns, see [`super::PatKind::Resugared`].
25+
#[derive_group_for_ast]
26+
pub enum ResugaredPatKind {}
27+
28+
/// Resugared variants for types. This represent extra printing-only types, see [`super::TyKind::Resugared`].
29+
#[derive_group_for_ast]
30+
pub enum ResugaredTyKind {}
31+
32+
/// Resugared variants for impl. items. This represent extra printing-only impl. items, see [`super::ImplItemKind::Resugared`].
33+
#[derive_group_for_ast]
34+
pub enum ResugaredImplItemKind {}
35+
36+
/// Resugared variants for trait items. This represent extra printing-only trait items, see [`super::TraitItemKind::Resugared`].
37+
#[derive_group_for_ast]
38+
pub enum ResugaredTraitItemKind {}

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)