mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
feat(ast, ast_codegen): pass the scope_id to the enter_scope event. (#4168)
This commit is contained in:
parent
c8f5664e0a
commit
67fe75ec6c
7 changed files with 203 additions and 197 deletions
|
|
@ -16,8 +16,10 @@
|
|||
clippy::match_wildcard_for_single_variants
|
||||
)]
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
use oxc_allocator::Vec;
|
||||
use oxc_syntax::scope::ScopeFlags;
|
||||
use oxc_syntax::scope::{ScopeFlags, ScopeId};
|
||||
|
||||
use crate::{ast::*, ast_kind::AstKind};
|
||||
|
||||
|
|
@ -28,7 +30,7 @@ pub trait Visit<'a>: Sized {
|
|||
fn enter_node(&mut self, kind: AstKind<'a>) {}
|
||||
fn leave_node(&mut self, kind: AstKind<'a>) {}
|
||||
|
||||
fn enter_scope(&mut self, flags: ScopeFlags) {}
|
||||
fn enter_scope(&mut self, flags: ScopeFlags, scope_id: &Cell<Option<ScopeId>>) {}
|
||||
fn leave_scope(&mut self) {}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -1350,13 +1352,17 @@ pub mod walk {
|
|||
|
||||
#[inline]
|
||||
pub fn walk_program<'a, V: Visit<'a>>(visitor: &mut V, it: &Program<'a>) {
|
||||
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
|
||||
});
|
||||
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,
|
||||
);
|
||||
let kind = AstKind::Program(visitor.alloc(it));
|
||||
visitor.enter_node(kind);
|
||||
visitor.visit_directives(&it.directives);
|
||||
|
|
@ -1433,7 +1439,7 @@ pub mod walk {
|
|||
|
||||
#[inline]
|
||||
pub fn walk_block_statement<'a, V: Visit<'a>>(visitor: &mut V, it: &BlockStatement<'a>) {
|
||||
visitor.enter_scope(ScopeFlags::empty());
|
||||
visitor.enter_scope(ScopeFlags::empty(), &it.scope_id);
|
||||
let kind = AstKind::BlockStatement(visitor.alloc(it));
|
||||
visitor.enter_node(kind);
|
||||
visitor.visit_statements(&it.body);
|
||||
|
|
@ -1699,13 +1705,16 @@ pub mod walk {
|
|||
visitor: &mut V,
|
||||
it: &ArrowFunctionExpression<'a>,
|
||||
) {
|
||||
visitor.enter_scope({
|
||||
let mut flags = ScopeFlags::Function | ScopeFlags::Arrow;
|
||||
if it.body.has_use_strict_directive() {
|
||||
flags |= ScopeFlags::StrictMode;
|
||||
}
|
||||
flags
|
||||
});
|
||||
visitor.enter_scope(
|
||||
{
|
||||
let mut flags = ScopeFlags::Function | ScopeFlags::Arrow;
|
||||
if it.body.has_use_strict_directive() {
|
||||
flags |= ScopeFlags::StrictMode;
|
||||
}
|
||||
flags
|
||||
},
|
||||
&it.scope_id,
|
||||
);
|
||||
let kind = AstKind::ArrowFunctionExpression(visitor.alloc(it));
|
||||
visitor.enter_node(kind);
|
||||
visitor.visit_formal_parameters(&it.params);
|
||||
|
|
@ -2064,7 +2073,7 @@ pub mod walk {
|
|||
|
||||
#[inline]
|
||||
pub fn walk_ts_type_parameter<'a, V: Visit<'a>>(visitor: &mut V, it: &TSTypeParameter<'a>) {
|
||||
visitor.enter_scope(ScopeFlags::empty());
|
||||
visitor.enter_scope(ScopeFlags::empty(), &it.scope_id);
|
||||
let kind = AstKind::TSTypeParameter(visitor.alloc(it));
|
||||
visitor.enter_node(kind);
|
||||
visitor.visit_binding_identifier(&it.name);
|
||||
|
|
@ -2916,7 +2925,7 @@ pub mod walk {
|
|||
let kind = AstKind::Class(visitor.alloc(it));
|
||||
visitor.enter_node(kind);
|
||||
visitor.visit_decorators(&it.decorators);
|
||||
visitor.enter_scope(ScopeFlags::StrictMode);
|
||||
visitor.enter_scope(ScopeFlags::StrictMode, &it.scope_id);
|
||||
if let Some(id) = &it.id {
|
||||
visitor.visit_binding_identifier(id);
|
||||
}
|
||||
|
|
@ -2972,7 +2981,7 @@ pub mod walk {
|
|||
|
||||
#[inline]
|
||||
pub fn walk_static_block<'a, V: Visit<'a>>(visitor: &mut V, it: &StaticBlock<'a>) {
|
||||
visitor.enter_scope(ScopeFlags::ClassStaticBlock);
|
||||
visitor.enter_scope(ScopeFlags::ClassStaticBlock, &it.scope_id);
|
||||
let kind = AstKind::StaticBlock(visitor.alloc(it));
|
||||
visitor.enter_node(kind);
|
||||
visitor.visit_statements(&it.body);
|
||||
|
|
@ -3003,13 +3012,16 @@ pub mod walk {
|
|||
it: &Function<'a>,
|
||||
flags: Option<ScopeFlags>,
|
||||
) {
|
||||
visitor.enter_scope({
|
||||
let mut flags = flags.unwrap_or(ScopeFlags::empty()) | ScopeFlags::Function;
|
||||
if it.body.as_ref().is_some_and(|body| body.has_use_strict_directive()) {
|
||||
flags |= ScopeFlags::StrictMode;
|
||||
}
|
||||
flags
|
||||
});
|
||||
visitor.enter_scope(
|
||||
{
|
||||
let mut flags = flags.unwrap_or(ScopeFlags::empty()) | ScopeFlags::Function;
|
||||
if it.body.as_ref().is_some_and(|body| body.has_use_strict_directive()) {
|
||||
flags |= ScopeFlags::StrictMode;
|
||||
}
|
||||
flags
|
||||
},
|
||||
&it.scope_id,
|
||||
);
|
||||
let kind = AstKind::Function(visitor.alloc(it));
|
||||
visitor.enter_node(kind);
|
||||
if let Some(id) = &it.id {
|
||||
|
|
@ -3473,7 +3485,7 @@ pub mod walk {
|
|||
pub fn walk_for_in_statement<'a, V: Visit<'a>>(visitor: &mut V, it: &ForInStatement<'a>) {
|
||||
let scope_events_cond = it.left.is_lexical_declaration();
|
||||
if scope_events_cond {
|
||||
visitor.enter_scope(ScopeFlags::empty());
|
||||
visitor.enter_scope(ScopeFlags::empty(), &it.scope_id);
|
||||
}
|
||||
let kind = AstKind::ForInStatement(visitor.alloc(it));
|
||||
visitor.enter_node(kind);
|
||||
|
|
@ -3544,7 +3556,7 @@ pub mod walk {
|
|||
pub fn walk_for_of_statement<'a, V: Visit<'a>>(visitor: &mut V, it: &ForOfStatement<'a>) {
|
||||
let scope_events_cond = it.left.is_lexical_declaration();
|
||||
if scope_events_cond {
|
||||
visitor.enter_scope(ScopeFlags::empty());
|
||||
visitor.enter_scope(ScopeFlags::empty(), &it.scope_id);
|
||||
}
|
||||
let kind = AstKind::ForOfStatement(visitor.alloc(it));
|
||||
visitor.enter_node(kind);
|
||||
|
|
@ -3562,7 +3574,7 @@ pub mod walk {
|
|||
let scope_events_cond =
|
||||
it.init.as_ref().is_some_and(ForStatementInit::is_lexical_declaration);
|
||||
if scope_events_cond {
|
||||
visitor.enter_scope(ScopeFlags::empty());
|
||||
visitor.enter_scope(ScopeFlags::empty(), &it.scope_id);
|
||||
}
|
||||
let kind = AstKind::ForStatement(visitor.alloc(it));
|
||||
visitor.enter_node(kind);
|
||||
|
|
@ -3630,7 +3642,7 @@ pub mod walk {
|
|||
let kind = AstKind::SwitchStatement(visitor.alloc(it));
|
||||
visitor.enter_node(kind);
|
||||
visitor.visit_expression(&it.discriminant);
|
||||
visitor.enter_scope(ScopeFlags::empty());
|
||||
visitor.enter_scope(ScopeFlags::empty(), &it.scope_id);
|
||||
visitor.visit_switch_cases(&it.cases);
|
||||
visitor.leave_node(kind);
|
||||
visitor.leave_scope();
|
||||
|
|
@ -3680,7 +3692,7 @@ pub mod walk {
|
|||
pub fn walk_catch_clause<'a, V: Visit<'a>>(visitor: &mut V, it: &CatchClause<'a>) {
|
||||
let scope_events_cond = it.param.is_some();
|
||||
if scope_events_cond {
|
||||
visitor.enter_scope(ScopeFlags::empty());
|
||||
visitor.enter_scope(ScopeFlags::empty(), &it.scope_id);
|
||||
}
|
||||
let kind = AstKind::CatchClause(visitor.alloc(it));
|
||||
visitor.enter_node(kind);
|
||||
|
|
@ -3704,7 +3716,7 @@ pub mod walk {
|
|||
|
||||
#[inline]
|
||||
pub fn walk_finally_clause<'a, V: Visit<'a>>(visitor: &mut V, it: &BlockStatement<'a>) {
|
||||
visitor.enter_scope(ScopeFlags::empty());
|
||||
visitor.enter_scope(ScopeFlags::empty(), &it.scope_id);
|
||||
let kind = AstKind::FinallyClause(visitor.alloc(it));
|
||||
visitor.enter_node(kind);
|
||||
visitor.visit_statements(&it.body);
|
||||
|
|
@ -3817,7 +3829,7 @@ pub mod walk {
|
|||
let kind = AstKind::TSEnumDeclaration(visitor.alloc(it));
|
||||
visitor.enter_node(kind);
|
||||
visitor.visit_binding_identifier(&it.id);
|
||||
visitor.enter_scope(ScopeFlags::empty());
|
||||
visitor.enter_scope(ScopeFlags::empty(), &it.scope_id);
|
||||
visitor.visit_ts_enum_members(&it.members);
|
||||
visitor.leave_node(kind);
|
||||
visitor.leave_scope();
|
||||
|
|
@ -3859,13 +3871,16 @@ pub mod walk {
|
|||
let kind = AstKind::TSModuleDeclaration(visitor.alloc(it));
|
||||
visitor.enter_node(kind);
|
||||
visitor.visit_ts_module_declaration_name(&it.id);
|
||||
visitor.enter_scope({
|
||||
let mut flags = ScopeFlags::TsModuleBlock;
|
||||
if it.body.as_ref().is_some_and(TSModuleDeclarationBody::is_strict) {
|
||||
flags |= ScopeFlags::StrictMode;
|
||||
}
|
||||
flags
|
||||
});
|
||||
visitor.enter_scope(
|
||||
{
|
||||
let mut flags = ScopeFlags::TsModuleBlock;
|
||||
if it.body.as_ref().is_some_and(TSModuleDeclarationBody::is_strict) {
|
||||
flags |= ScopeFlags::StrictMode;
|
||||
}
|
||||
flags
|
||||
},
|
||||
&it.scope_id,
|
||||
);
|
||||
if let Some(body) = &it.body {
|
||||
visitor.visit_ts_module_declaration_body(body);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,19 +16,21 @@
|
|||
clippy::match_wildcard_for_single_variants
|
||||
)]
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
use oxc_allocator::Vec;
|
||||
use oxc_syntax::scope::ScopeFlags;
|
||||
use oxc_syntax::scope::{ScopeFlags, ScopeId};
|
||||
|
||||
use crate::{ast::*, ast_kind::AstType};
|
||||
|
||||
use walk_mut::*;
|
||||
|
||||
/// Syntax tree traversal to mutate an exclusive borrow of a syntax tree in place.
|
||||
/// Syntax tree traversal
|
||||
pub trait VisitMut<'a>: Sized {
|
||||
fn enter_node(&mut self, ty: AstType) {}
|
||||
fn leave_node(&mut self, ty: AstType) {}
|
||||
fn enter_node(&mut self, kind: AstType) {}
|
||||
fn leave_node(&mut self, kind: AstType) {}
|
||||
|
||||
fn enter_scope(&mut self, flags: ScopeFlags) {}
|
||||
fn enter_scope(&mut self, flags: ScopeFlags, scope_id: &Cell<Option<ScopeId>>) {}
|
||||
fn leave_scope(&mut self) {}
|
||||
|
||||
#[inline]
|
||||
|
|
@ -1342,13 +1344,17 @@ pub mod walk_mut {
|
|||
|
||||
#[inline]
|
||||
pub fn walk_program<'a, V: VisitMut<'a>>(visitor: &mut V, it: &mut Program<'a>) {
|
||||
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
|
||||
});
|
||||
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,
|
||||
);
|
||||
let kind = AstType::Program;
|
||||
visitor.enter_node(kind);
|
||||
visitor.visit_directives(&mut it.directives);
|
||||
|
|
@ -1425,7 +1431,7 @@ pub mod walk_mut {
|
|||
|
||||
#[inline]
|
||||
pub fn walk_block_statement<'a, V: VisitMut<'a>>(visitor: &mut V, it: &mut BlockStatement<'a>) {
|
||||
visitor.enter_scope(ScopeFlags::empty());
|
||||
visitor.enter_scope(ScopeFlags::empty(), &it.scope_id);
|
||||
let kind = AstType::BlockStatement;
|
||||
visitor.enter_node(kind);
|
||||
visitor.visit_statements(&mut it.body);
|
||||
|
|
@ -1718,13 +1724,16 @@ pub mod walk_mut {
|
|||
visitor: &mut V,
|
||||
it: &mut ArrowFunctionExpression<'a>,
|
||||
) {
|
||||
visitor.enter_scope({
|
||||
let mut flags = ScopeFlags::Function | ScopeFlags::Arrow;
|
||||
if it.body.has_use_strict_directive() {
|
||||
flags |= ScopeFlags::StrictMode;
|
||||
}
|
||||
flags
|
||||
});
|
||||
visitor.enter_scope(
|
||||
{
|
||||
let mut flags = ScopeFlags::Function | ScopeFlags::Arrow;
|
||||
if it.body.has_use_strict_directive() {
|
||||
flags |= ScopeFlags::StrictMode;
|
||||
}
|
||||
flags
|
||||
},
|
||||
&it.scope_id,
|
||||
);
|
||||
let kind = AstType::ArrowFunctionExpression;
|
||||
visitor.enter_node(kind);
|
||||
visitor.visit_formal_parameters(&mut it.params);
|
||||
|
|
@ -2125,7 +2134,7 @@ pub mod walk_mut {
|
|||
visitor: &mut V,
|
||||
it: &mut TSTypeParameter<'a>,
|
||||
) {
|
||||
visitor.enter_scope(ScopeFlags::empty());
|
||||
visitor.enter_scope(ScopeFlags::empty(), &it.scope_id);
|
||||
let kind = AstType::TSTypeParameter;
|
||||
visitor.enter_node(kind);
|
||||
visitor.visit_binding_identifier(&mut it.name);
|
||||
|
|
@ -3040,7 +3049,7 @@ pub mod walk_mut {
|
|||
let kind = AstType::Class;
|
||||
visitor.enter_node(kind);
|
||||
visitor.visit_decorators(&mut it.decorators);
|
||||
visitor.enter_scope(ScopeFlags::StrictMode);
|
||||
visitor.enter_scope(ScopeFlags::StrictMode, &it.scope_id);
|
||||
if let Some(id) = &mut it.id {
|
||||
visitor.visit_binding_identifier(id);
|
||||
}
|
||||
|
|
@ -3099,7 +3108,7 @@ pub mod walk_mut {
|
|||
|
||||
#[inline]
|
||||
pub fn walk_static_block<'a, V: VisitMut<'a>>(visitor: &mut V, it: &mut StaticBlock<'a>) {
|
||||
visitor.enter_scope(ScopeFlags::ClassStaticBlock);
|
||||
visitor.enter_scope(ScopeFlags::ClassStaticBlock, &it.scope_id);
|
||||
let kind = AstType::StaticBlock;
|
||||
visitor.enter_node(kind);
|
||||
visitor.visit_statements(&mut it.body);
|
||||
|
|
@ -3133,13 +3142,16 @@ pub mod walk_mut {
|
|||
it: &mut Function<'a>,
|
||||
flags: Option<ScopeFlags>,
|
||||
) {
|
||||
visitor.enter_scope({
|
||||
let mut flags = flags.unwrap_or(ScopeFlags::empty()) | ScopeFlags::Function;
|
||||
if it.body.as_ref().is_some_and(|body| body.has_use_strict_directive()) {
|
||||
flags |= ScopeFlags::StrictMode;
|
||||
}
|
||||
flags
|
||||
});
|
||||
visitor.enter_scope(
|
||||
{
|
||||
let mut flags = flags.unwrap_or(ScopeFlags::empty()) | ScopeFlags::Function;
|
||||
if it.body.as_ref().is_some_and(|body| body.has_use_strict_directive()) {
|
||||
flags |= ScopeFlags::StrictMode;
|
||||
}
|
||||
flags
|
||||
},
|
||||
&it.scope_id,
|
||||
);
|
||||
let kind = AstType::Function;
|
||||
visitor.enter_node(kind);
|
||||
if let Some(id) = &mut it.id {
|
||||
|
|
@ -3654,7 +3666,7 @@ pub mod walk_mut {
|
|||
) {
|
||||
let scope_events_cond = it.left.is_lexical_declaration();
|
||||
if scope_events_cond {
|
||||
visitor.enter_scope(ScopeFlags::empty());
|
||||
visitor.enter_scope(ScopeFlags::empty(), &it.scope_id);
|
||||
}
|
||||
let kind = AstType::ForInStatement;
|
||||
visitor.enter_node(kind);
|
||||
|
|
@ -3734,7 +3746,7 @@ pub mod walk_mut {
|
|||
) {
|
||||
let scope_events_cond = it.left.is_lexical_declaration();
|
||||
if scope_events_cond {
|
||||
visitor.enter_scope(ScopeFlags::empty());
|
||||
visitor.enter_scope(ScopeFlags::empty(), &it.scope_id);
|
||||
}
|
||||
let kind = AstType::ForOfStatement;
|
||||
visitor.enter_node(kind);
|
||||
|
|
@ -3752,7 +3764,7 @@ pub mod walk_mut {
|
|||
let scope_events_cond =
|
||||
it.init.as_ref().is_some_and(ForStatementInit::is_lexical_declaration);
|
||||
if scope_events_cond {
|
||||
visitor.enter_scope(ScopeFlags::empty());
|
||||
visitor.enter_scope(ScopeFlags::empty(), &it.scope_id);
|
||||
}
|
||||
let kind = AstType::ForStatement;
|
||||
visitor.enter_node(kind);
|
||||
|
|
@ -3832,7 +3844,7 @@ pub mod walk_mut {
|
|||
let kind = AstType::SwitchStatement;
|
||||
visitor.enter_node(kind);
|
||||
visitor.visit_expression(&mut it.discriminant);
|
||||
visitor.enter_scope(ScopeFlags::empty());
|
||||
visitor.enter_scope(ScopeFlags::empty(), &it.scope_id);
|
||||
visitor.visit_switch_cases(&mut it.cases);
|
||||
visitor.leave_node(kind);
|
||||
visitor.leave_scope();
|
||||
|
|
@ -3885,7 +3897,7 @@ pub mod walk_mut {
|
|||
pub fn walk_catch_clause<'a, V: VisitMut<'a>>(visitor: &mut V, it: &mut CatchClause<'a>) {
|
||||
let scope_events_cond = it.param.is_some();
|
||||
if scope_events_cond {
|
||||
visitor.enter_scope(ScopeFlags::empty());
|
||||
visitor.enter_scope(ScopeFlags::empty(), &it.scope_id);
|
||||
}
|
||||
let kind = AstType::CatchClause;
|
||||
visitor.enter_node(kind);
|
||||
|
|
@ -3909,7 +3921,7 @@ pub mod walk_mut {
|
|||
|
||||
#[inline]
|
||||
pub fn walk_finally_clause<'a, V: VisitMut<'a>>(visitor: &mut V, it: &mut BlockStatement<'a>) {
|
||||
visitor.enter_scope(ScopeFlags::empty());
|
||||
visitor.enter_scope(ScopeFlags::empty(), &it.scope_id);
|
||||
let kind = AstType::FinallyClause;
|
||||
visitor.enter_node(kind);
|
||||
visitor.visit_statements(&mut it.body);
|
||||
|
|
@ -4028,7 +4040,7 @@ pub mod walk_mut {
|
|||
let kind = AstType::TSEnumDeclaration;
|
||||
visitor.enter_node(kind);
|
||||
visitor.visit_binding_identifier(&mut it.id);
|
||||
visitor.enter_scope(ScopeFlags::empty());
|
||||
visitor.enter_scope(ScopeFlags::empty(), &it.scope_id);
|
||||
visitor.visit_ts_enum_members(&mut it.members);
|
||||
visitor.leave_node(kind);
|
||||
visitor.leave_scope();
|
||||
|
|
@ -4076,13 +4088,16 @@ pub mod walk_mut {
|
|||
let kind = AstType::TSModuleDeclaration;
|
||||
visitor.enter_node(kind);
|
||||
visitor.visit_ts_module_declaration_name(&mut it.id);
|
||||
visitor.enter_scope({
|
||||
let mut flags = ScopeFlags::TsModuleBlock;
|
||||
if it.body.as_ref().is_some_and(TSModuleDeclarationBody::is_strict) {
|
||||
flags |= ScopeFlags::StrictMode;
|
||||
}
|
||||
flags
|
||||
});
|
||||
visitor.enter_scope(
|
||||
{
|
||||
let mut flags = ScopeFlags::TsModuleBlock;
|
||||
if it.body.as_ref().is_some_and(TSModuleDeclarationBody::is_strict) {
|
||||
flags |= ScopeFlags::StrictMode;
|
||||
}
|
||||
flags
|
||||
},
|
||||
&it.scope_id,
|
||||
);
|
||||
if let Some(body) = &mut it.body {
|
||||
visitor.visit_ts_module_declaration_body(body);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
use std::cell::Cell;
|
||||
|
||||
use oxc_allocator::Box;
|
||||
#[allow(clippy::wildcard_imports)]
|
||||
use oxc_ast::ast::*;
|
||||
|
|
@ -135,7 +137,8 @@ impl<'a> IsolatedDeclarations<'a> {
|
|||
block: &Box<'a, TSModuleBlock<'a>>,
|
||||
) -> Box<'a, TSModuleBlock<'a>> {
|
||||
// We need to enter a new scope for the module block, avoid add binding to the parent scope
|
||||
self.scope.enter_scope(ScopeFlags::TsModuleBlock);
|
||||
// TODO: doesn't have a scope_id!
|
||||
self.scope.enter_scope(ScopeFlags::TsModuleBlock, &Cell::default());
|
||||
let stmts = self.transform_statements_on_demand(&block.body);
|
||||
self.scope.leave_scope();
|
||||
self.ast.alloc_ts_module_block(SPAN, self.ast.vec(), stmts)
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
use std::cell::Cell;
|
||||
|
||||
use oxc_ast::{
|
||||
ast::{
|
||||
ArrowFunctionExpression, BindingIdentifier, Expression, Function, FunctionBody,
|
||||
|
|
@ -6,7 +8,7 @@ use oxc_ast::{
|
|||
AstBuilder, Visit,
|
||||
};
|
||||
use oxc_span::{Atom, GetSpan, SPAN};
|
||||
use oxc_syntax::scope::ScopeFlags;
|
||||
use oxc_syntax::scope::{ScopeFlags, ScopeId};
|
||||
|
||||
use crate::{diagnostics::type_containing_private_name, IsolatedDeclarations};
|
||||
|
||||
|
|
@ -114,7 +116,7 @@ impl<'a> FunctionReturnType<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Visit<'a> for FunctionReturnType<'a> {
|
||||
fn enter_scope(&mut self, _flags: ScopeFlags) {
|
||||
fn enter_scope(&mut self, _flags: ScopeFlags, _: &Cell<Option<ScopeId>>) {
|
||||
self.scope_depth += 1;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1,3 +1,5 @@
|
|||
use std::cell::Cell;
|
||||
|
||||
use oxc_allocator::{Allocator, Vec};
|
||||
#[allow(clippy::wildcard_imports)]
|
||||
use oxc_ast::ast::*;
|
||||
|
|
@ -5,7 +7,7 @@ use oxc_ast::AstBuilder;
|
|||
#[allow(clippy::wildcard_imports)]
|
||||
use oxc_ast::{visit::walk::*, Visit};
|
||||
use oxc_span::Atom;
|
||||
use oxc_syntax::scope::ScopeFlags;
|
||||
use oxc_syntax::scope::{ScopeFlags, ScopeId};
|
||||
use rustc_hash::FxHashSet;
|
||||
|
||||
/// Declaration scope.
|
||||
|
|
@ -100,7 +102,7 @@ impl<'a> ScopeTree<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Visit<'a> for ScopeTree<'a> {
|
||||
fn enter_scope(&mut self, flags: ScopeFlags) {
|
||||
fn enter_scope(&mut self, flags: ScopeFlags, _: &Cell<Option<ScopeId>>) {
|
||||
let scope = Scope::new(flags);
|
||||
self.levels.push(scope);
|
||||
}
|
||||
|
|
@ -216,7 +218,8 @@ impl<'a> Visit<'a> for ScopeTree<'a> {
|
|||
/// Because the type parameter is can be used in following nodes
|
||||
/// until the end of the function. So we leave the scope in the parent node (Function)
|
||||
fn visit_ts_type_parameter_declaration(&mut self, decl: &TSTypeParameterDeclaration<'a>) {
|
||||
self.enter_scope(ScopeFlags::empty());
|
||||
// TODO: doesn't have a scope_id!
|
||||
self.enter_scope(ScopeFlags::empty(), &Cell::default());
|
||||
decl.params.iter().for_each(|param| self.visit_ts_type_parameter(param));
|
||||
// exit scope in parent AST node
|
||||
}
|
||||
|
|
@ -291,8 +294,9 @@ impl<'a> Visit<'a> for ScopeTree<'a> {
|
|||
/// ^^^^^^^^^^^^^^^^^^^^
|
||||
/// We need to add both `T` and `K` to the scope
|
||||
fn visit_ts_mapped_type(&mut self, ty: &TSMappedType<'a>) {
|
||||
// TODO: doesn't have a scope_id!
|
||||
self.enter_scope(ScopeFlags::empty(), &Cell::default());
|
||||
// copy from walk_ts_mapped_type
|
||||
self.enter_scope(ScopeFlags::empty());
|
||||
self.visit_ts_type_parameter(&ty.type_parameter);
|
||||
if let Some(name) = &ty.name_type {
|
||||
self.visit_ts_type(name);
|
||||
|
|
@ -308,7 +312,8 @@ impl<'a> Visit<'a> for ScopeTree<'a> {
|
|||
/// `Item` is a type parameter
|
||||
/// We need to add `Item` to the scope
|
||||
fn visit_conditional_expression(&mut self, expr: &ConditionalExpression<'a>) {
|
||||
self.enter_scope(ScopeFlags::empty());
|
||||
// TODO: doesn't have a scope_id!
|
||||
self.enter_scope(ScopeFlags::empty(), &Cell::default());
|
||||
walk_conditional_expression(self, expr);
|
||||
self.leave_scope();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,6 +1,10 @@
|
|||
//! Semantic Builder
|
||||
|
||||
use std::{cell::RefCell, path::PathBuf, sync::Arc};
|
||||
use std::{
|
||||
cell::{Cell, RefCell},
|
||||
path::PathBuf,
|
||||
sync::Arc,
|
||||
};
|
||||
|
||||
#[allow(clippy::wildcard_imports)]
|
||||
use oxc_ast::{ast::*, AstKind, Trivias, Visit};
|
||||
|
|
@ -417,7 +421,7 @@ impl<'a> SemanticBuilder<'a> {
|
|||
}
|
||||
|
||||
impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
||||
fn enter_scope(&mut self, flags: ScopeFlags) {
|
||||
fn enter_scope(&mut self, flags: ScopeFlags, _: &Cell<Option<ScopeId>>) {
|
||||
let parent_scope_id =
|
||||
if flags.contains(ScopeFlags::Top) { None } else { Some(self.current_scope_id) };
|
||||
|
||||
|
|
@ -456,13 +460,16 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
|||
|
||||
fn visit_program(&mut self, program: &Program<'a>) {
|
||||
let kind = AstKind::Program(self.alloc(program));
|
||||
self.enter_scope({
|
||||
let mut flags = ScopeFlags::Top;
|
||||
if program.is_strict() {
|
||||
flags |= ScopeFlags::StrictMode;
|
||||
}
|
||||
flags
|
||||
});
|
||||
self.enter_scope(
|
||||
{
|
||||
let mut flags = ScopeFlags::Top;
|
||||
if program.is_strict() {
|
||||
flags |= ScopeFlags::StrictMode;
|
||||
}
|
||||
flags
|
||||
},
|
||||
&program.scope_id,
|
||||
);
|
||||
program.scope_id.set(Some(self.current_scope_id));
|
||||
|
||||
/* cfg */
|
||||
|
|
@ -491,7 +498,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
|||
|
||||
fn visit_block_statement(&mut self, stmt: &BlockStatement<'a>) {
|
||||
let kind = AstKind::BlockStatement(self.alloc(stmt));
|
||||
self.enter_scope(ScopeFlags::empty());
|
||||
self.enter_scope(ScopeFlags::empty(), &stmt.scope_id);
|
||||
stmt.scope_id.set(Some(self.current_scope_id));
|
||||
self.enter_node(kind);
|
||||
|
||||
|
|
@ -759,7 +766,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
|||
let is_lexical_declaration =
|
||||
stmt.init.as_ref().is_some_and(ForStatementInit::is_lexical_declaration);
|
||||
if is_lexical_declaration {
|
||||
self.enter_scope(ScopeFlags::empty());
|
||||
self.enter_scope(ScopeFlags::empty(), &stmt.scope_id);
|
||||
stmt.scope_id.set(Some(self.current_scope_id));
|
||||
}
|
||||
self.enter_node(kind);
|
||||
|
|
@ -845,7 +852,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
|||
let kind = AstKind::ForInStatement(self.alloc(stmt));
|
||||
let is_lexical_declaration = stmt.left.is_lexical_declaration();
|
||||
if is_lexical_declaration {
|
||||
self.enter_scope(ScopeFlags::empty());
|
||||
self.enter_scope(ScopeFlags::empty(), &stmt.scope_id);
|
||||
stmt.scope_id.set(Some(self.current_scope_id));
|
||||
}
|
||||
self.enter_node(kind);
|
||||
|
|
@ -910,7 +917,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
|||
let kind = AstKind::ForOfStatement(self.alloc(stmt));
|
||||
let is_lexical_declaration = stmt.left.is_lexical_declaration();
|
||||
if is_lexical_declaration {
|
||||
self.enter_scope(ScopeFlags::empty());
|
||||
self.enter_scope(ScopeFlags::empty(), &stmt.scope_id);
|
||||
stmt.scope_id.set(Some(self.current_scope_id));
|
||||
}
|
||||
self.enter_node(kind);
|
||||
|
|
@ -1096,7 +1103,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
|||
let kind = AstKind::SwitchStatement(self.alloc(stmt));
|
||||
self.enter_node(kind);
|
||||
self.visit_expression(&stmt.discriminant);
|
||||
self.enter_scope(ScopeFlags::empty());
|
||||
self.enter_scope(ScopeFlags::empty(), &stmt.scope_id);
|
||||
stmt.scope_id.set(Some(self.current_scope_id));
|
||||
|
||||
/* cfg */
|
||||
|
|
@ -1343,7 +1350,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
|||
|
||||
fn visit_catch_clause(&mut self, clause: &CatchClause<'a>) {
|
||||
let kind = AstKind::CatchClause(self.alloc(clause));
|
||||
self.enter_scope(ScopeFlags::empty());
|
||||
self.enter_scope(ScopeFlags::empty(), &clause.scope_id);
|
||||
clause.scope_id.set(Some(self.current_scope_id));
|
||||
self.enter_node(kind);
|
||||
if let Some(param) = &clause.param {
|
||||
|
|
@ -1356,7 +1363,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
|||
|
||||
fn visit_finally_clause(&mut self, clause: &BlockStatement<'a>) {
|
||||
let kind = AstKind::FinallyClause(self.alloc(clause));
|
||||
self.enter_scope(ScopeFlags::empty());
|
||||
self.enter_scope(ScopeFlags::empty(), &clause.scope_id);
|
||||
clause.scope_id.set(Some(self.current_scope_id));
|
||||
self.enter_node(kind);
|
||||
self.visit_statements(&clause.body);
|
||||
|
|
@ -1441,13 +1448,16 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
|||
|
||||
fn visit_function(&mut self, func: &Function<'a>, flags: Option<ScopeFlags>) {
|
||||
let kind = AstKind::Function(self.alloc(func));
|
||||
self.enter_scope({
|
||||
let mut flags = flags.unwrap_or(ScopeFlags::empty()) | ScopeFlags::Function;
|
||||
if func.is_strict() {
|
||||
flags |= ScopeFlags::StrictMode;
|
||||
}
|
||||
flags
|
||||
});
|
||||
self.enter_scope(
|
||||
{
|
||||
let mut flags = flags.unwrap_or(ScopeFlags::empty()) | ScopeFlags::Function;
|
||||
if func.is_strict() {
|
||||
flags |= ScopeFlags::StrictMode;
|
||||
}
|
||||
flags
|
||||
},
|
||||
&func.scope_id,
|
||||
);
|
||||
func.scope_id.set(Some(self.current_scope_id));
|
||||
|
||||
/* cfg */
|
||||
|
|
@ -1516,7 +1526,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
|||
if is_class_expr {
|
||||
// Class expressions create a temporary scope with the class name as its only variable
|
||||
// E.g., `let c = class A { foo() { console.log(A) } }`
|
||||
self.enter_scope(ScopeFlags::empty());
|
||||
self.enter_scope(ScopeFlags::empty(), &class.scope_id);
|
||||
class.scope_id.set(Some(self.current_scope_id));
|
||||
}
|
||||
|
||||
|
|
@ -1545,7 +1555,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
|||
|
||||
fn visit_static_block(&mut self, block: &StaticBlock<'a>) {
|
||||
let kind = AstKind::StaticBlock(self.alloc(block));
|
||||
self.enter_scope(ScopeFlags::ClassStaticBlock);
|
||||
self.enter_scope(ScopeFlags::ClassStaticBlock, &block.scope_id);
|
||||
block.scope_id.set(Some(self.current_scope_id));
|
||||
self.enter_node(kind);
|
||||
self.visit_statements(&block.body);
|
||||
|
|
@ -1555,7 +1565,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
|||
|
||||
fn visit_arrow_function_expression(&mut self, expr: &ArrowFunctionExpression<'a>) {
|
||||
let kind = AstKind::ArrowFunctionExpression(self.alloc(expr));
|
||||
self.enter_scope(ScopeFlags::Function | ScopeFlags::Arrow);
|
||||
self.enter_scope(ScopeFlags::Function | ScopeFlags::Arrow, &expr.scope_id);
|
||||
expr.scope_id.set(Some(self.current_scope_id));
|
||||
|
||||
/* cfg */
|
||||
|
|
@ -1605,7 +1615,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
|||
let kind = AstKind::TSEnumDeclaration(self.alloc(decl));
|
||||
self.enter_node(kind);
|
||||
self.visit_binding_identifier(&decl.id);
|
||||
self.enter_scope(ScopeFlags::empty());
|
||||
self.enter_scope(ScopeFlags::empty(), &decl.scope_id);
|
||||
decl.scope_id.set(Some(self.current_scope_id));
|
||||
for member in &decl.members {
|
||||
self.visit_ts_enum_member(member);
|
||||
|
|
@ -1621,7 +1631,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
|||
TSModuleDeclarationName::Identifier(ident) => self.visit_identifier_name(ident),
|
||||
TSModuleDeclarationName::StringLiteral(lit) => self.visit_string_literal(lit),
|
||||
}
|
||||
self.enter_scope(ScopeFlags::TsModuleBlock);
|
||||
self.enter_scope(ScopeFlags::TsModuleBlock, &decl.scope_id);
|
||||
decl.scope_id.set(Some(self.current_scope_id));
|
||||
match &decl.body {
|
||||
Some(TSModuleDeclarationBody::TSModuleDeclaration(decl)) => {
|
||||
|
|
@ -1638,7 +1648,7 @@ impl<'a> Visit<'a> for SemanticBuilder<'a> {
|
|||
|
||||
fn visit_ts_type_parameter(&mut self, ty: &TSTypeParameter<'a>) {
|
||||
let kind = AstKind::TSTypeParameter(self.alloc(ty));
|
||||
self.enter_scope(ScopeFlags::empty());
|
||||
self.enter_scope(ScopeFlags::empty(), &ty.scope_id);
|
||||
ty.scope_id.set(Some(self.current_scope_id));
|
||||
self.enter_node(kind);
|
||||
if let Some(constraint) = &ty.constraint {
|
||||
|
|
|
|||
|
|
@ -37,7 +37,7 @@ impl Generator for VisitGenerator {
|
|||
}
|
||||
|
||||
fn generate(&mut self, ctx: &CodegenCtx) -> GeneratorOutput {
|
||||
GeneratorOutput::Stream(("visit", generate_visit(ctx)))
|
||||
GeneratorOutput::Stream(("visit", generate_visit::<false>(ctx)))
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -47,11 +47,11 @@ impl Generator for VisitMutGenerator {
|
|||
}
|
||||
|
||||
fn generate(&mut self, ctx: &CodegenCtx) -> GeneratorOutput {
|
||||
GeneratorOutput::Stream(("visit_mut", generate_visit_mut(ctx)))
|
||||
GeneratorOutput::Stream(("visit_mut", generate_visit::<true>(ctx)))
|
||||
}
|
||||
}
|
||||
|
||||
static CLIPPY_ALLOW: &str = "\
|
||||
const CLIPPY_ALLOW: &str = "\
|
||||
unused_variables,\
|
||||
clippy::extra_unused_type_parameters,\
|
||||
clippy::explicit_iter_loop,\
|
||||
|
|
@ -59,7 +59,7 @@ static CLIPPY_ALLOW: &str = "\
|
|||
clippy::semicolon_if_nothing_returned,\
|
||||
clippy::match_wildcard_for_single_variants";
|
||||
|
||||
fn generate_visit(ctx: &CodegenCtx) -> TokenStream {
|
||||
fn generate_visit<const MUT: bool>(ctx: &CodegenCtx) -> TokenStream {
|
||||
let header = generated_header!();
|
||||
// we evaluate it outside of quote to take advantage of expression evaluation
|
||||
// otherwise the `\n\` wouldn't work!
|
||||
|
|
@ -71,41 +71,18 @@ fn generate_visit(ctx: &CodegenCtx) -> TokenStream {
|
|||
//! * [rustc visitor](https://github.com/rust-lang/rust/blob/master/compiler/rustc_ast/src/visit.rs)\n\
|
||||
"};
|
||||
|
||||
let (visits, walks) = VisitBuilder::new(ctx, false).build();
|
||||
let (visits, walks) = VisitBuilder::new(ctx, MUT).build();
|
||||
let clippy_attr = insert!("#![allow({})]", CLIPPY_ALLOW);
|
||||
|
||||
quote! {
|
||||
#header
|
||||
#file_docs
|
||||
#clippy_attr
|
||||
|
||||
endl!();
|
||||
|
||||
use oxc_allocator::Vec;
|
||||
use oxc_syntax::scope::ScopeFlags;
|
||||
|
||||
endl!();
|
||||
|
||||
use crate::{ast::*, ast_kind::AstKind};
|
||||
|
||||
endl!();
|
||||
|
||||
use walk::*;
|
||||
|
||||
endl!();
|
||||
|
||||
/// Syntax tree traversal
|
||||
pub trait Visit<'a>: Sized {
|
||||
fn enter_node(&mut self, kind: AstKind<'a>) {}
|
||||
fn leave_node(&mut self, kind: AstKind<'a>) {}
|
||||
|
||||
endl!();
|
||||
|
||||
fn enter_scope(&mut self, flags: ScopeFlags) {}
|
||||
fn leave_scope(&mut self) {}
|
||||
|
||||
endl!();
|
||||
let walk_mod = if MUT { quote!(walk_mut) } else { quote!(walk) };
|
||||
let trait_name = if MUT { quote!(VisitMut) } else { quote!(Visit) };
|
||||
let ast_kind_type = if MUT { quote!(AstType) } else { quote!(AstKind) };
|
||||
let ast_kind_life = if MUT { TokenStream::default() } else { quote!(<'a>) };
|
||||
|
||||
let may_alloc = if MUT {
|
||||
TokenStream::default()
|
||||
} else {
|
||||
quote! {
|
||||
#[inline]
|
||||
fn alloc<T>(&self, t: &T) -> &'a T {
|
||||
insert!("// SAFETY:");
|
||||
|
|
@ -116,35 +93,8 @@ fn generate_visit(ctx: &CodegenCtx) -> TokenStream {
|
|||
std::mem::transmute(t)
|
||||
}
|
||||
}
|
||||
|
||||
#(#visits)*
|
||||
}
|
||||
|
||||
endl!();
|
||||
|
||||
pub mod walk {
|
||||
use super::*;
|
||||
|
||||
#(#walks)*
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn generate_visit_mut(ctx: &CodegenCtx) -> TokenStream {
|
||||
let header = generated_header!();
|
||||
// we evaluate it outside of quote to take advantage of expression evaluation
|
||||
// otherwise the `\n\` wouldn't work!
|
||||
let file_docs = insert! {"\
|
||||
//! Visitor Pattern\n\
|
||||
//!\n\
|
||||
//! See:\n\
|
||||
//! * [visitor pattern](https://rust-unofficial.github.io/patterns/patterns/behavioural/visitor.html)\n\
|
||||
//! * [rustc visitor](https://github.com/rust-lang/rust/blob/master/compiler/rustc_ast/src/visit.rs)\n\
|
||||
"};
|
||||
|
||||
let (visits, walks) = VisitBuilder::new(ctx, true).build();
|
||||
let clippy_attr = insert!("#![allow({})]", CLIPPY_ALLOW);
|
||||
};
|
||||
|
||||
quote! {
|
||||
#header
|
||||
|
|
@ -153,37 +103,43 @@ fn generate_visit_mut(ctx: &CodegenCtx) -> TokenStream {
|
|||
|
||||
endl!();
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
endl!();
|
||||
|
||||
use oxc_allocator::Vec;
|
||||
use oxc_syntax::scope::ScopeFlags;
|
||||
use oxc_syntax::scope::{ScopeFlags, ScopeId};
|
||||
|
||||
endl!();
|
||||
|
||||
use crate::{ast::*, ast_kind::AstType};
|
||||
use crate::{ast::*, ast_kind::#ast_kind_type};
|
||||
|
||||
endl!();
|
||||
|
||||
use walk_mut::*;
|
||||
use #walk_mod::*;
|
||||
|
||||
endl!();
|
||||
|
||||
/// Syntax tree traversal to mutate an exclusive borrow of a syntax tree in place.
|
||||
pub trait VisitMut<'a>: Sized {
|
||||
fn enter_node(&mut self, ty: AstType) {}
|
||||
fn leave_node(&mut self, ty: AstType) {}
|
||||
/// Syntax tree traversal
|
||||
pub trait #trait_name <'a>: Sized {
|
||||
fn enter_node(&mut self, kind: #ast_kind_type #ast_kind_life) {}
|
||||
fn leave_node(&mut self, kind: #ast_kind_type #ast_kind_life) {}
|
||||
|
||||
endl!();
|
||||
|
||||
fn enter_scope(&mut self, flags: ScopeFlags) {}
|
||||
fn enter_scope(&mut self, flags: ScopeFlags, scope_id: &Cell<Option<ScopeId>>) {}
|
||||
fn leave_scope(&mut self) {}
|
||||
|
||||
endl!();
|
||||
|
||||
#may_alloc
|
||||
|
||||
#(#visits)*
|
||||
}
|
||||
|
||||
endl!();
|
||||
|
||||
pub mod walk_mut {
|
||||
pub mod #walk_mod {
|
||||
use super::*;
|
||||
|
||||
#(#walks)*
|
||||
|
|
@ -533,7 +489,7 @@ impl<'a> VisitBuilder<'a> {
|
|||
let flags = scope_args
|
||||
.flags
|
||||
.map_or_else(|| quote!(ScopeFlags::empty()), |it| it.to_token_stream());
|
||||
let args = if let Some(strict_if) = scope_args.strict_if {
|
||||
let flags = if let Some(strict_if) = scope_args.strict_if {
|
||||
let strict_if =
|
||||
strict_if.to_token_stream().replace_ident("self", &format_ident!("it"));
|
||||
quote! {{
|
||||
|
|
@ -547,7 +503,7 @@ impl<'a> VisitBuilder<'a> {
|
|||
flags
|
||||
};
|
||||
let mut enter = cond.as_ref().into_token_stream();
|
||||
enter.extend(maybe_conditional(quote!(visitor.enter_scope(#args);)));
|
||||
enter.extend(maybe_conditional(quote!(visitor.enter_scope(#flags, &it.scope_id);)));
|
||||
let leave = maybe_conditional(quote!(visitor.leave_scope();));
|
||||
(enter, leave)
|
||||
},
|
||||
|
|
|
|||
Loading…
Reference in a new issue