use oxc_allocator::{Allocator, Box};
use oxc_ast::{
ast::{Expression, IdentifierReference, Statement},
AstBuilder,
};
use oxc_semantic::{ScopeTree, SymbolTable};
use oxc_span::{Atom, CompactStr, Span};
use oxc_syntax::{
reference::{ReferenceFlag, ReferenceId},
scope::{ScopeFlags, ScopeId},
symbol::{SymbolFlags, SymbolId},
};
use crate::ancestor::{Ancestor, AncestorType};
mod ancestry;
pub use ancestry::TraverseAncestry;
mod scoping;
pub use scoping::TraverseScoping;
pub struct TraverseCtx<'a> {
pub ancestry: TraverseAncestry<'a>,
pub scoping: TraverseScoping,
pub ast: AstBuilder<'a>,
}
impl<'a> TraverseCtx<'a> {
pub fn new(scopes: ScopeTree, symbols: SymbolTable, allocator: &'a Allocator) -> Self {
let ancestry = TraverseAncestry::new();
let scoping = TraverseScoping::new(scopes, symbols);
let ast = AstBuilder::new(allocator);
Self { ancestry, scoping, ast }
}
#[inline]
pub fn alloc<T>(&self, node: T) -> Box<'a, T> {
self.ast.alloc(node)
}
#[inline]
pub fn parent(&self) -> &Ancestor<'a> {
self.ancestry.parent()
}
#[inline]
pub fn ancestor(&self, level: usize) -> Option<&Ancestor<'a>> {
self.ancestry.ancestor(level)
}
#[inline]
pub fn ancestors<'b>(&'b self) -> impl Iterator<Item = &'b Ancestor<'a>> {
self.ancestry.ancestors()
}
#[inline]
pub fn ancestors_depth(&self) -> usize {
self.ancestry.ancestors_depth()
}
#[inline]
pub fn current_scope_id(&self) -> ScopeId {
self.scoping.current_scope_id()
}
#[inline]
pub fn current_scope_flags(&self) -> ScopeFlags {
self.scoping.current_scope_flags()
}
#[inline]
pub fn scopes(&self) -> &ScopeTree {
self.scoping.scopes()
}
#[inline]
pub fn scopes_mut(&mut self) -> &mut ScopeTree {
self.scoping.scopes_mut()
}
#[inline]
pub fn symbols(&self) -> &SymbolTable {
self.scoping.symbols()
}
#[inline]
pub fn symbols_mut(&mut self) -> &mut SymbolTable {
self.scoping.symbols_mut()
}
pub fn ancestor_scopes(&self) -> impl Iterator<Item = ScopeId> + '_ {
self.scoping.ancestor_scopes()
}
pub fn create_child_scope(&mut self, parent_id: ScopeId, flags: ScopeFlags) -> ScopeId {
self.scoping.create_child_scope(parent_id, flags)
}
pub fn create_child_scope_of_current(&mut self, flags: ScopeFlags) -> ScopeId {
self.scoping.create_child_scope_of_current(flags)
}
pub fn insert_scope_below_statement(&mut self, stmt: &Statement, flags: ScopeFlags) -> ScopeId {
self.scoping.insert_scope_below_statement(stmt, flags)
}
pub fn insert_scope_below_expression(
&mut self,
expr: &Expression,
flags: ScopeFlags,
) -> ScopeId {
self.scoping.insert_scope_below_expression(expr, flags)
}
pub fn generate_uid(&mut self, name: &str, scope_id: ScopeId, flags: SymbolFlags) -> SymbolId {
self.scoping.generate_uid(name, scope_id, flags)
}
pub fn generate_uid_in_current_scope(&mut self, name: &str, flags: SymbolFlags) -> SymbolId {
self.scoping.generate_uid_in_current_scope(name, flags)
}
pub fn generate_uid_in_root_scope(&mut self, name: &str, flags: SymbolFlags) -> SymbolId {
self.scoping.generate_uid_in_root_scope(name, flags)
}
pub fn create_bound_reference(
&mut self,
symbol_id: SymbolId,
flag: ReferenceFlag,
) -> ReferenceId {
self.scoping.create_bound_reference(symbol_id, flag)
}
pub fn create_bound_reference_id(
&mut self,
span: Span,
name: Atom<'a>,
symbol_id: SymbolId,
flag: ReferenceFlag,
) -> IdentifierReference<'a> {
self.scoping.create_bound_reference_id(span, name, symbol_id, flag)
}
pub fn create_unbound_reference(
&mut self,
name: CompactStr,
flag: ReferenceFlag,
) -> ReferenceId {
self.scoping.create_unbound_reference(name, flag)
}
pub fn create_unbound_reference_id(
&mut self,
span: Span,
name: Atom<'a>,
flag: ReferenceFlag,
) -> IdentifierReference<'a> {
self.scoping.create_unbound_reference_id(span, name, flag)
}
pub fn create_reference(
&mut self,
name: CompactStr,
symbol_id: Option<SymbolId>,
flag: ReferenceFlag,
) -> ReferenceId {
self.scoping.create_reference(name, symbol_id, flag)
}
pub fn create_reference_id(
&mut self,
span: Span,
name: Atom<'a>,
symbol_id: Option<SymbolId>,
flag: ReferenceFlag,
) -> IdentifierReference<'a> {
self.scoping.create_reference_id(span, name, symbol_id, flag)
}
pub fn create_reference_in_current_scope(
&mut self,
name: CompactStr,
flag: ReferenceFlag,
) -> ReferenceId {
self.scoping.create_reference_in_current_scope(name, flag)
}
}
impl<'a> TraverseCtx<'a> {
#[inline]
pub(crate) fn push_stack(&mut self, ancestor: Ancestor<'a>) {
self.ancestry.push_stack(ancestor);
}
#[inline]
pub(crate) unsafe fn pop_stack(&mut self) {
self.ancestry.pop_stack();
}
#[inline]
pub(crate) unsafe fn retag_stack(&mut self, ty: AncestorType) {
self.ancestry.retag_stack(ty);
}
#[inline]
pub(crate) fn set_current_scope_id(&mut self, scope_id: ScopeId) {
self.scoping.set_current_scope_id(scope_id);
}
}