mirror of
https://github.com/danbulant/oxc
synced 2026-05-19 12:19:15 +00:00
refactor(traverse): codegen ChildScopeCollector (#5119)
Codegen `ChildScopeCollector`, so that if more types have scopes added, we don't forget to add them (like the problem #5118 fixed). The methods are in different order in the generated version, but otherwise identical to before this PR. `visit_finally_clause` has to be added manually, as `oxc_traverse` codegen does not read or understand `#[visit(as)]` attrs.
This commit is contained in:
parent
25d6e20bba
commit
eba5033a58
5 changed files with 186 additions and 122 deletions
|
|
@ -19,6 +19,7 @@ import getTypesFromCode from './lib/parse.mjs';
|
|||
import generateTraverseTraitCode from './lib/traverse.mjs';
|
||||
import generateAncestorsCode from './lib/ancestor.mjs';
|
||||
import generateWalkFunctionsCode from './lib/walk.mjs';
|
||||
import generateScopesCollectorCode from './lib/scopes_collector.mjs';
|
||||
|
||||
const execAsync = promisify(exec);
|
||||
|
||||
|
|
@ -32,6 +33,7 @@ const outputDirPath = pathJoin(fileURLToPath(import.meta.url), '../../src/genera
|
|||
await writeToFile('traverse.rs', generateTraverseTraitCode(types));
|
||||
await writeToFile('ancestor.rs', generateAncestorsCode(types));
|
||||
await writeToFile('walk.rs', generateWalkFunctionsCode(types));
|
||||
await writeToFile('scopes_collector.rs', generateScopesCollectorCode(types));
|
||||
|
||||
async function writeToFile(filename, code) {
|
||||
code = `${PREAMBLE}${code}`;
|
||||
|
|
|
|||
50
crates/oxc_traverse/scripts/lib/scopes_collector.mjs
Normal file
50
crates/oxc_traverse/scripts/lib/scopes_collector.mjs
Normal file
|
|
@ -0,0 +1,50 @@
|
|||
import {camelToSnake} from './utils.mjs';
|
||||
|
||||
export default function generateScopesCollectorCode(types) {
|
||||
let methods = '';
|
||||
for (const type of Object.values(types)) {
|
||||
if (type.kind === 'enum' || !type.scopeArgs) continue;
|
||||
|
||||
const extraParams = type.scopeArgs.flags === 'flags' ? ', _flags: ScopeFlags' : '';
|
||||
methods += `
|
||||
#[inline]
|
||||
fn visit_${camelToSnake(type.name)}(&mut self, it: &${type.rawName}${extraParams}) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
||||
return `
|
||||
use std::cell::Cell;
|
||||
|
||||
#[allow(clippy::wildcard_imports)]
|
||||
use oxc_ast::{ast::*, visit::Visit};
|
||||
use oxc_syntax::scope::{ScopeFlags, ScopeId};
|
||||
|
||||
/// Visitor that locates all child scopes.
|
||||
/// NB: Child scopes only, not grandchild scopes.
|
||||
/// Does not do full traversal - stops each time it hits a node with a scope.
|
||||
pub(crate) struct ChildScopeCollector {
|
||||
pub(crate) scope_ids: Vec<ScopeId>,
|
||||
}
|
||||
|
||||
impl ChildScopeCollector {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self { scope_ids: vec![] }
|
||||
}
|
||||
|
||||
pub(crate) fn add_scope(&mut self, scope_id: &Cell<Option<ScopeId>>) {
|
||||
self.scope_ids.push(scope_id.get().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Visit<'a> for ChildScopeCollector {
|
||||
${methods}
|
||||
|
||||
#[inline]
|
||||
fn visit_finally_clause(&mut self, it: &BlockStatement<'a>) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
}
|
||||
`;
|
||||
}
|
||||
|
|
@ -12,6 +12,7 @@ use oxc_syntax::{
|
|||
};
|
||||
|
||||
use super::ast_operations::GatherNodeParts;
|
||||
use crate::scopes_collector::ChildScopeCollector;
|
||||
|
||||
/// Traverse scope context.
|
||||
///
|
||||
|
|
@ -516,125 +517,3 @@ fn create_uid_name_base(name: &str) -> CompactString {
|
|||
str.push_str(name);
|
||||
str
|
||||
}
|
||||
|
||||
/// Visitor that locates all child scopes.
|
||||
/// NB: Child scopes only, not grandchild scopes.
|
||||
/// Does not do full traversal - stops each time it hits a node with a scope.
|
||||
struct ChildScopeCollector {
|
||||
scope_ids: Vec<ScopeId>,
|
||||
}
|
||||
|
||||
impl ChildScopeCollector {
|
||||
fn new() -> Self {
|
||||
Self { scope_ids: vec![] }
|
||||
}
|
||||
|
||||
fn add_scope(&mut self, scope_id: &Cell<Option<ScopeId>>) {
|
||||
self.scope_ids.push(scope_id.get().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Visit<'a> for ChildScopeCollector {
|
||||
#[inline]
|
||||
fn visit_program(&mut self, program: &Program<'a>) {
|
||||
self.add_scope(&program.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_block_statement(&mut self, stmt: &BlockStatement<'a>) {
|
||||
self.add_scope(&stmt.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_for_statement(&mut self, stmt: &ForStatement<'a>) {
|
||||
self.add_scope(&stmt.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_for_in_statement(&mut self, stmt: &ForInStatement<'a>) {
|
||||
self.add_scope(&stmt.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_for_of_statement(&mut self, stmt: &ForOfStatement<'a>) {
|
||||
self.add_scope(&stmt.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_switch_statement(&mut self, stmt: &SwitchStatement<'a>) {
|
||||
self.add_scope(&stmt.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_catch_clause(&mut self, clause: &CatchClause<'a>) {
|
||||
self.add_scope(&clause.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_finally_clause(&mut self, block: &BlockStatement<'a>) {
|
||||
self.add_scope(&block.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_function(&mut self, func: &Function<'a>, _flags: ScopeFlags) {
|
||||
self.add_scope(&func.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_class(&mut self, class: &Class<'a>) {
|
||||
self.add_scope(&class.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_static_block(&mut self, block: &StaticBlock<'a>) {
|
||||
self.add_scope(&block.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_arrow_function_expression(&mut self, expr: &ArrowFunctionExpression<'a>) {
|
||||
self.add_scope(&expr.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_ts_enum_declaration(&mut self, decl: &TSEnumDeclaration<'a>) {
|
||||
self.add_scope(&decl.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_ts_module_declaration(&mut self, decl: &TSModuleDeclaration<'a>) {
|
||||
self.add_scope(&decl.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_ts_interface_declaration(&mut self, it: &TSInterfaceDeclaration<'a>) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_ts_mapped_type(&mut self, it: &TSMappedType<'a>) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_ts_conditional_type(&mut self, it: &TSConditionalType<'a>) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_ts_type_alias_declaration(&mut self, it: &TSTypeAliasDeclaration<'a>) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_ts_method_signature(&mut self, it: &TSMethodSignature<'a>) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_ts_construct_signature_declaration(
|
||||
&mut self,
|
||||
it: &TSConstructSignatureDeclaration<'a>,
|
||||
) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
131
crates/oxc_traverse/src/generated/scopes_collector.rs
Normal file
131
crates/oxc_traverse/src/generated/scopes_collector.rs
Normal file
|
|
@ -0,0 +1,131 @@
|
|||
// Auto-generated code, DO NOT EDIT DIRECTLY!
|
||||
// Generated by `oxc_traverse/scripts/build.mjs`.
|
||||
// To alter this generated file you have to edit the codegen.
|
||||
|
||||
use std::cell::Cell;
|
||||
|
||||
#[allow(clippy::wildcard_imports)]
|
||||
use oxc_ast::{ast::*, visit::Visit};
|
||||
use oxc_syntax::scope::{ScopeFlags, ScopeId};
|
||||
|
||||
/// Visitor that locates all child scopes.
|
||||
/// NB: Child scopes only, not grandchild scopes.
|
||||
/// Does not do full traversal - stops each time it hits a node with a scope.
|
||||
pub(crate) struct ChildScopeCollector {
|
||||
pub(crate) scope_ids: Vec<ScopeId>,
|
||||
}
|
||||
|
||||
impl ChildScopeCollector {
|
||||
pub(crate) fn new() -> Self {
|
||||
Self { scope_ids: vec![] }
|
||||
}
|
||||
|
||||
pub(crate) fn add_scope(&mut self, scope_id: &Cell<Option<ScopeId>>) {
|
||||
self.scope_ids.push(scope_id.get().unwrap());
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> Visit<'a> for ChildScopeCollector {
|
||||
#[inline]
|
||||
fn visit_program(&mut self, it: &Program<'a>) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_block_statement(&mut self, it: &BlockStatement<'a>) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_for_statement(&mut self, it: &ForStatement<'a>) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_for_in_statement(&mut self, it: &ForInStatement<'a>) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_for_of_statement(&mut self, it: &ForOfStatement<'a>) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_switch_statement(&mut self, it: &SwitchStatement<'a>) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_catch_clause(&mut self, it: &CatchClause<'a>) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_function(&mut self, it: &Function<'a>, _flags: ScopeFlags) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_arrow_function_expression(&mut self, it: &ArrowFunctionExpression<'a>) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_class(&mut self, it: &Class<'a>) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_static_block(&mut self, it: &StaticBlock<'a>) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_ts_enum_declaration(&mut self, it: &TSEnumDeclaration<'a>) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_ts_conditional_type(&mut self, it: &TSConditionalType<'a>) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_ts_type_alias_declaration(&mut self, it: &TSTypeAliasDeclaration<'a>) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_ts_interface_declaration(&mut self, it: &TSInterfaceDeclaration<'a>) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_ts_method_signature(&mut self, it: &TSMethodSignature<'a>) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_ts_construct_signature_declaration(
|
||||
&mut self,
|
||||
it: &TSConstructSignatureDeclaration<'a>,
|
||||
) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_ts_module_declaration(&mut self, it: &TSModuleDeclaration<'a>) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_ts_mapped_type(&mut self, it: &TSMappedType<'a>) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn visit_finally_clause(&mut self, it: &BlockStatement<'a>) {
|
||||
self.add_scope(&it.scope_id);
|
||||
}
|
||||
}
|
||||
|
|
@ -69,11 +69,13 @@ pub use context::{TraverseAncestry, TraverseCtx, TraverseScoping};
|
|||
|
||||
mod generated {
|
||||
pub mod ancestor;
|
||||
pub(super) mod scopes_collector;
|
||||
pub mod traverse;
|
||||
pub(super) mod walk;
|
||||
}
|
||||
pub use generated::ancestor;
|
||||
pub use generated::ancestor::Ancestor;
|
||||
use generated::scopes_collector;
|
||||
pub use generated::traverse::Traverse;
|
||||
use generated::walk;
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue