New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add scopes support to Traverse
/ transformer
#3189
Comments
All we need are the scope flags. During traversing, we keep a stack of scopes, and manage binding information while entering / leaving scopes.
The coolest approach is to treat scope as an individual AST node, something like struct Scope<T> {
inner: T
}
pub struct TryStatement<'a> {
pub block: Box<'a, Scope<BlockStatement<'a>>>,
pub handler: Option<Box<'a, Scope<CatchClause<'a>>>>,
pub finalizer: Option<Box<'a, Scope<BlockStatement<'a>>>>,
} But actually I've got no idea on how to implement it until I get my hands dirty on the new traverse API. |
If that's all we need, how about
You'd use it as follows: fn enter_binary_expression(&mut self, fn: &mut BinaryExpression<'a>, ctx: &TraverseCtx<'a>) {
if ctx.scope.is_strict_mode() {
// ...
}
} We could signal to the codegen when to update the scope stack with something like: #[visited_node(scope = "Function")]
pub struct Function<'a> {
pub r#type: FunctionType,
// ...
} NB: |
I need to store things associated with a scope, but I think I can work with what you proposed to get things started. |
Actually you don't need Something like this would do the same: let in_function = ctx.find_ancestor(
|ancestor| if ancestor.is_function() || ancestor.is_arrow_function_expression() {
FinderRet::Found(())
} else {
FinderRet::Continue
}
).is_some();
|
Related to #2859. |
Add scope flags to `TraverseCtx`. Closes #3189. `walk_*` functions build a stack of `ScopeFlags` as AST is traversed, and they can be queried from within visitors with `ctx.scope()`, `ctx.ancestor_scope()` and `ctx.find_scope()`. The codegen which generates `walk_*` functions gets the info about which AST types have scopes, and how to check for strict mode from the `#[visited_node]` attrs on AST type definitions in `oxc_ast`. A few notes: Each scope inherits the strict mode flag from the level before it in the stack, so if you need to know "am I in strict mode context here?", `ctx.scope().is_strict_mode()` will tell you - no need to travel back up the stack to find out. Scopes do *not* inherit any other flags from level before it. So `ctx.scope()` in a block nested in a function will return `ScopeFlags::empty()` not `ScopeFlags::Function`. I had to add an extra flag `ScopeFlags::Method`. The reason for this is to deal with when a `Function` is actually a `MethodDefinition`, and to avoid creating 2 scopes in this case. The principle I'm trying to follow is to encode as little logic in the codegen as possible, as it's rather hidden away. Instead the codegen follows a standard logic for every node, guided by attributes which are visible next to the types in `oxc_ast`. This hopefully makes how `Traverse`'s visitors are generated less mysterious, and easier to change. The case of `Function` within `MethodDefinition` is a weird one and would not be possible to implement without encoding a magic "special case" within the codegen without this extra `ScopeFlags::Method` variant. Its existence does not alter the operation of any other code in Oxc which uses `ScopeFlags`. In my view `ScopeFlags` might benefit from a little bit of an overhaul anyway. I believe we could pack more information into the bits and make it more useful.
Allow mutable access to scopes tree and symbol table. Closes #3189. This completes the v1 scopes-in-traverse implementation, and provides all the primitives required to implement the missing APIs listed in #3251. Performance is abysmal, as noted in #3304, but we can fix that later on by taking `Semantic` out of the picture, or optimizing it.
#3314 gave |
The intent is to replace
VisitMut
in transformer with the newoxc_traverse::Traverse
. #3182 is a starting point for that.However, transformers require scope information, which is not yet implemented.
VisitMut
provides only fairly minimal information - justScopeFlags
indicating:This would be fairly easy to replicate in
Traverse
.However, I assume transformers actually need more info than this, probably more like the info available from semantic. Opening this issue to discuss:
The text was updated successfully, but these errors were encountered: