oxc-project / oxc-project/backlog
Visit GAT (Generic Associated Types) + Fold pattern
Nobody has claimed this yet.
- Dominant language
- No language data
- Stars
- 7
- Forks
- 0
- PR merge metrics
- No merged PRs in 30d
Description
A bit of context before you read this: oxc-project/backlog#184
I'm working on the AST template macro, My current approach is something like this:
a. use oxc_ast_codegen to generate a visitor with support for every visitable AST type(placed at oxc_ast_quote/src/generated/{here}) that would:
- accept an interop resolver or map
- visit each node
- visit inner nodes to get their
TokenStream - produce a
TokenStreamto create that node at runtime - short circuit on literals and enums that are either unit or wrapping literals
b. proc-macro
- substitute and map the interpolation spans to their inner value(which would support identifiers for now but it can be extended to accept rust expressions as well)
i. In the initial implementation we use raw string manipulation here
ii. as our next step we can add support forQuoteInterpolationin our parser with anast_quote_parserfeature to prevent multiple iterations on the source code(but with caching, we might not need this). - parse the macro input with
oxc_parser - check for errors and retrieve the valid program
- use the visitor generated in step
ato create something likeStatement(BlockStatement { ... }) - add support for generating tracing boilerplate to mimic what
ast_builderwould've done before as our single point of construction(e.g. counting allocations in debug builds)
As you might already see it feels like a good place to introduce the Fold pattern to our arsenal, So I'm re-proposing one of my old suggestions which is adding a generic associated type Result to both Visit and VisitMut this way we won't need a new visiting paradigm while being able to selectively return from our visitor implementations.
It goes like this:
pub trait VisitResult: Default {
fn extend(&mut self, next: Self);
}
impl VisitResult for () {
fn extend(&mut self, next: Self) {}
}
pub trait Visit<'a>: Sized {
type Result: VisitResult;
fn visit_program(&mut self, it: &Program<'a>) -> Self::Result {
walk_program(self, it)
}
// ...
}
pub fn walk_program<...>(visitor: V, it: &Program<'a>) -> V::Result {
let mut result = V::Result::default();
let kind = AstKind::Program(visitor.alloc(it));
visitor.enter_node(kind);
visitor.enter_scope(
{
let mut flags = ScopeFlags::Top;
if it.source_type.is_strict() || it.directives.iter().any(Directive::is_use_strict)
{
flags |= ScopeFlags::StrictMode;
}
flags
},
&it.scope_id,
);
result.extend(visitor.visit_directives(&it.directives));
if let Some(hashbang) = &it.hashbang {
result.extend(visitor.visit_hashbang(hashbang));
}
result.extend(visitor.visit_statements(&it.body));
visitor.leave_scope();
visitor.leave_node(kind);
result
}
Our current implementations would only need to add this one line:
impl<'a> Visit<'a> for X {
type Result = ();
// ...
}
A similar implementation in rustc.
Contributor guide
No contributing guide indexed for this repository
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Read the context in oxc-project/backlog#184 and compare the proposed VisitResult and GAT Result design with rustc's compiler/rustc_ast/src/visit.rs. Trace the existing Visit and VisitMut implementations before deciding whether the Fold pattern fits; done means a resolved design and corresponding visitor changes with current implementations preserved.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Feature
- Difficulty
- 5/5
- Estimated time
- Over a week
- Activity status
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 25/100