Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 7 additions & 0 deletions crates/oxc_traverse/src/context/bound_identifier.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ use oxc_syntax::{reference::ReferenceFlags, symbol::SymbolId};

use crate::TraverseCtx;

use super::MaybeBoundIdentifier;

/// Info about a binding, from which one can create a `BindingIdentifier` or `IdentifierReference`s.
///
/// Typical usage:
Expand Down Expand Up @@ -54,6 +56,11 @@ impl<'a> BoundIdentifier<'a> {
Self { name: ident.name.clone(), symbol_id: ident.symbol_id() }
}

/// Convert `BoundIdentifier` to `MaybeBoundIdentifier`
pub fn to_maybe_bound_identifier(&self) -> MaybeBoundIdentifier<'a> {
MaybeBoundIdentifier::new(self.name.clone(), Some(self.symbol_id))
}

/// Create `BindingIdentifier` for this binding
pub fn create_binding_identifier(&self, ctx: &TraverseCtx<'a>) -> BindingIdentifier<'a> {
ctx.ast.binding_identifier_with_symbol_id(SPAN, self.name.clone(), self.symbol_id)
Expand Down
247 changes: 247 additions & 0 deletions crates/oxc_traverse/src/context/maybe_bound_identifier.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,247 @@
use oxc_ast::ast::{AssignmentTarget, Expression, IdentifierReference};
use oxc_span::{Atom, Span, SPAN};
use oxc_syntax::{reference::ReferenceFlags, symbol::SymbolId};

use crate::TraverseCtx;

use super::BoundIdentifier;

/// A factory for generating `IdentifierReference`s.
///
/// Typical usage:
///
/// ```rs
/// // Create `MaybeBoundIdentifier` from an existing `IdentifierReference`
/// let binding = MaybeBoundIdentifier::from_identifier_reference(ident, ctx);
///
/// // Generate `IdentifierReference`s and insert them into AST
/// assign_expr.left = binding.create_write_target(ctx);
/// assign_expr.right = binding.create_read_expression(ctx);
/// ```
///
/// Notes:
///
/// * The original `IdentifierReference` must also be used in the AST, or it'll be a dangling reference.
/// * `MaybeBoundIdentifier` is smaller than `IdentifierReference`, so takes less memory when you store
/// it for later use.
/// * `MaybeBoundIdentifier` re-uses the same `Atom` for all `BindingIdentifier` / `IdentifierReference`s
/// created from it.
/// * `MaybeBoundIdentifier` looks up the `SymbolId` for the reference only once,
/// rather than `TraverseCtx::clone_identifier_reference` which looks it up every time you create
/// an `IdentifierReference`.
#[derive(Debug, Clone)]
pub struct MaybeBoundIdentifier<'a> {
pub name: Atom<'a>,
pub symbol_id: Option<SymbolId>,
}

impl<'a> MaybeBoundIdentifier<'a> {
/// Create `MaybeBoundIdentifier` for `name` and `Option<SymbolId>`
pub fn new(name: Atom<'a>, symbol_id: Option<SymbolId>) -> Self {
Self { name, symbol_id }
}

/// Create `MaybeBoundIdentifier` from an `IdentifierReference`
pub fn from_identifier_reference(
ident: &IdentifierReference<'a>,
ctx: &TraverseCtx<'a>,
) -> Self {
let symbol_id = ctx.symbols().get_reference(ident.reference_id()).symbol_id();
Self { name: ident.name.clone(), symbol_id }
}

/// Convert `MaybeBoundIdentifier` to `BoundIdentifier`.
///
/// Returns `None` if symbol is not bound.
pub fn to_bound_identifier(&self) -> Option<BoundIdentifier<'a>> {
self.symbol_id.map(|symbol_id| BoundIdentifier::new(self.name.clone(), symbol_id))
}

// --- Read only ---

/// Create `IdentifierReference` referencing this binding, which is read from, with dummy `Span`
pub fn create_read_reference(&self, ctx: &mut TraverseCtx<'a>) -> IdentifierReference<'a> {
self.create_spanned_read_reference(SPAN, ctx)
}

/// Create `Expression::Identifier` referencing this binding, which is read from, with dummy `Span`
pub fn create_read_expression(&self, ctx: &mut TraverseCtx<'a>) -> Expression<'a> {
self.create_spanned_read_expression(SPAN, ctx)
}

/// Create `IdentifierReference` referencing this binding, which is read from, with specified `Span`
pub fn create_spanned_read_reference(
&self,
span: Span,
ctx: &mut TraverseCtx<'a>,
) -> IdentifierReference<'a> {
self.create_spanned_reference(span, ReferenceFlags::Read, ctx)
}

/// Create `Expression::Identifier` referencing this binding, which is read from, with specified `Span`
pub fn create_spanned_read_expression(
&self,
span: Span,
ctx: &mut TraverseCtx<'a>,
) -> Expression<'a> {
self.create_spanned_expression(span, ReferenceFlags::Read, ctx)
}

// --- Write only ---

/// Create `IdentifierReference` referencing this binding, which is written to, with dummy `Span`
pub fn create_write_reference(&self, ctx: &mut TraverseCtx<'a>) -> IdentifierReference<'a> {
self.create_spanned_write_reference(SPAN, ctx)
}

/// Create `Expression::Identifier` referencing this binding, which is written to, with dummy `Span`
pub fn create_write_expression(&self, ctx: &mut TraverseCtx<'a>) -> Expression<'a> {
self.create_spanned_write_expression(SPAN, ctx)
}

/// Create `AssignmentTarget` referencing this binding, which is written to, with dummy `Span`
pub fn create_write_target(&self, ctx: &mut TraverseCtx<'a>) -> AssignmentTarget<'a> {
self.create_spanned_write_target(SPAN, ctx)
}

/// Create `IdentifierReference` referencing this binding, which is written to, with specified `Span`
pub fn create_spanned_write_reference(
&self,
span: Span,
ctx: &mut TraverseCtx<'a>,
) -> IdentifierReference<'a> {
self.create_spanned_reference(span, ReferenceFlags::Write, ctx)
}

/// Create `Expression::Identifier` referencing this binding, which is written to, with specified `Span`
pub fn create_spanned_write_expression(
&self,
span: Span,
ctx: &mut TraverseCtx<'a>,
) -> Expression<'a> {
self.create_spanned_expression(span, ReferenceFlags::Write, ctx)
}

/// Create `AssignmentTarget` referencing this binding, which is written to, with specified `Span`
pub fn create_spanned_write_target(
&self,
span: Span,
ctx: &mut TraverseCtx<'a>,
) -> AssignmentTarget<'a> {
self.create_spanned_target(span, ReferenceFlags::Write, ctx)
}

// --- Read and write ---

/// Create `IdentifierReference` referencing this binding, which is read from + written to,
/// with dummy `Span`
pub fn create_read_write_reference(
&self,
ctx: &mut TraverseCtx<'a>,
) -> IdentifierReference<'a> {
self.create_spanned_read_write_reference(SPAN, ctx)
}

/// Create `Expression::Identifier` referencing this binding, which is read from + written to,
/// with dummy `Span`
pub fn create_read_write_expression(&self, ctx: &mut TraverseCtx<'a>) -> Expression<'a> {
self.create_spanned_read_write_expression(SPAN, ctx)
}

/// Create `AssignmentTarget` referencing this binding, which is read from + written to,
/// with dummy `Span`
pub fn create_read_write_target(&self, ctx: &mut TraverseCtx<'a>) -> AssignmentTarget<'a> {
self.create_spanned_read_write_target(SPAN, ctx)
}

/// Create `IdentifierReference` referencing this binding, which is read from + written to,
/// with specified `Span`
pub fn create_spanned_read_write_reference(
&self,
span: Span,
ctx: &mut TraverseCtx<'a>,
) -> IdentifierReference<'a> {
self.create_spanned_reference(span, ReferenceFlags::Read | ReferenceFlags::Write, ctx)
}

/// Create `Expression::Identifier` referencing this binding, which is read from + written to,
/// with specified `Span`
pub fn create_spanned_read_write_expression(
&self,
span: Span,
ctx: &mut TraverseCtx<'a>,
) -> Expression<'a> {
self.create_spanned_expression(span, ReferenceFlags::Read | ReferenceFlags::Write, ctx)
}

/// Create `AssignmentTarget` referencing this binding, which is read from + written to,
/// with specified `Span`
pub fn create_spanned_read_write_target(
&self,
span: Span,
ctx: &mut TraverseCtx<'a>,
) -> AssignmentTarget<'a> {
self.create_spanned_target(span, ReferenceFlags::Read | ReferenceFlags::Write, ctx)
}

// --- Specified ReferenceFlags ---

/// Create `IdentifierReference` referencing this binding, with specified `ReferenceFlags`
pub fn create_reference(
&self,
flags: ReferenceFlags,
ctx: &mut TraverseCtx<'a>,
) -> IdentifierReference<'a> {
self.create_spanned_reference(SPAN, flags, ctx)
}

/// Create `Expression::Identifier` referencing this binding, with specified `ReferenceFlags`
pub fn create_expression(
&self,
flags: ReferenceFlags,
ctx: &mut TraverseCtx<'a>,
) -> Expression<'a> {
self.create_spanned_expression(SPAN, flags, ctx)
}

/// Create `AssignmentTarget` referencing this binding, with specified `ReferenceFlags`
pub fn create_target(
&self,
flags: ReferenceFlags,
ctx: &mut TraverseCtx<'a>,
) -> AssignmentTarget<'a> {
self.create_spanned_target(SPAN, flags, ctx)
}

/// Create `IdentifierReference` referencing this binding, with specified `Span` and `ReferenceFlags`
pub fn create_spanned_reference(
&self,
span: Span,
flags: ReferenceFlags,
ctx: &mut TraverseCtx<'a>,
) -> IdentifierReference<'a> {
ctx.create_reference_id(span, self.name.clone(), self.symbol_id, flags)
}

/// Create `Expression::Identifier` referencing this binding, with specified `Span` and `ReferenceFlags`
pub fn create_spanned_expression(
&self,
span: Span,
flags: ReferenceFlags,
ctx: &mut TraverseCtx<'a>,
) -> Expression<'a> {
let ident = self.create_spanned_reference(span, flags, ctx);
Expression::Identifier(ctx.alloc(ident))
}

/// Create `Expression::Identifier` referencing this binding, with specified `Span` and `ReferenceFlags`
pub fn create_spanned_target(
&self,
span: Span,
flags: ReferenceFlags,
ctx: &mut TraverseCtx<'a>,
) -> AssignmentTarget<'a> {
let ident = self.create_spanned_reference(span, flags, ctx);
AssignmentTarget::AssignmentTargetIdentifier(ctx.alloc(ident))
}
}
2 changes: 2 additions & 0 deletions crates/oxc_traverse/src/context/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,12 @@ use crate::{

mod ancestry;
mod bound_identifier;
mod maybe_bound_identifier;
mod scoping;
use ancestry::PopToken;
pub use ancestry::TraverseAncestry;
pub use bound_identifier::BoundIdentifier;
pub use maybe_bound_identifier::MaybeBoundIdentifier;
pub use scoping::TraverseScoping;

/// Traverse context.
Expand Down
4 changes: 3 additions & 1 deletion crates/oxc_traverse/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,9 @@ use oxc_semantic::{ScopeTree, SymbolTable};

pub mod ast_operations;
mod context;
pub use context::{BoundIdentifier, TraverseAncestry, TraverseCtx, TraverseScoping};
pub use context::{
BoundIdentifier, MaybeBoundIdentifier, TraverseAncestry, TraverseCtx, TraverseScoping,
};

mod generated {
pub mod ancestor;
Expand Down