Skip to content

Commit

Permalink
refactor(js_semantic): wrap scope id for niche optimization and clarity
Browse files Browse the repository at this point in the history
  • Loading branch information
Conaclos committed Jul 11, 2024
1 parent 08f0c8f commit 25e31a6
Show file tree
Hide file tree
Showing 6 changed files with 93 additions and 71 deletions.
34 changes: 17 additions & 17 deletions crates/biome_js_semantic/src/events.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,8 @@ use std::collections::VecDeque;
use std::mem;
use JsSyntaxKind::*;

use crate::ScopeId;

/// Events emitted by the [SemanticEventExtractor].
/// These events are later made into the Semantic Model.
#[derive(Debug, Eq, PartialEq)]
Expand All @@ -25,8 +27,8 @@ pub enum SemanticEvent {
/// - Type parameters
DeclarationFound {
range: TextRange,
scope_id: u32,
hoisted_scope_id: Option<u32>,
scope_id: ScopeId,
hoisted_scope_id: Option<ScopeId>,
},

/// Tracks where a symbol is read, but only if its declaration is before this reference.
Expand All @@ -35,7 +37,7 @@ pub enum SemanticEvent {
Read {
range: TextRange,
declaration_at: TextSize,
scope_id: u32,
scope_id: ScopeId,
},

/// Tracks where a symbol is read, but only if its declaration was hoisted.
Expand All @@ -44,7 +46,7 @@ pub enum SemanticEvent {
HoistedRead {
range: TextRange,
declaration_at: TextSize,
scope_id: u32,
scope_id: ScopeId,
},

/// Tracks where a symbol is written, but only if its declaration is before this reference.
Expand All @@ -53,7 +55,7 @@ pub enum SemanticEvent {
Write {
range: TextRange,
declaration_at: TextSize,
scope_id: u32,
scope_id: ScopeId,
},

/// Tracks where a symbol is written, but only if its declaration was hoisted.
Expand All @@ -63,7 +65,7 @@ pub enum SemanticEvent {
HoistedWrite {
range: TextRange,
declaration_at: TextSize,
scope_id: u32,
scope_id: ScopeId,
},

/// Tracks references that do no have any matching binding
Expand All @@ -78,8 +80,7 @@ pub enum SemanticEvent {
ScopeStarted {
/// Scope range
range: TextRange,
scope_id: u32,
parent_scope_id: Option<u32>,
parent_scope_id: Option<ScopeId>,
is_closure: bool,
},

Expand All @@ -90,7 +91,7 @@ pub enum SemanticEvent {
ScopeEnded {
/// Scope range
range: TextRange,
scope_id: u32,
scope_id: ScopeId,
},

/// Tracks where a symbol is exported.
Expand Down Expand Up @@ -156,7 +157,7 @@ pub struct SemanticEventExtractor {
scopes: Vec<Scope>,
/// Number of generated scopes
/// This allows assigning a unique id to every scope.
scope_count: u32,
scope_count: usize,
/// At any point this is the set of available bindings and their range in the current scope
bindings: FxHashMap<BindingName, BindingInfo>,
/// Type parameters bound in a `infer T` clause.
Expand Down Expand Up @@ -274,7 +275,7 @@ enum ScopeHoisting {

#[derive(Debug)]
struct Scope {
scope_id: u32,
scope_id: ScopeId,
/// All bindings declared inside this scope
bindings: Vec<BindingName>,
/// References that still needs to be bound and will be solved at the end of the scope
Expand Down Expand Up @@ -780,11 +781,10 @@ impl SemanticEventExtractor {
}

fn push_scope(&mut self, range: TextRange, hoisting: ScopeHoisting, is_closure: bool) {
let scope_id = self.scope_count;
let scope_id = ScopeId::new(self.scope_count);
self.scope_count += 1;
self.stash.push_back(SemanticEvent::ScopeStarted {
range,
scope_id,
parent_scope_id: self.scopes.iter().last().map(|x| x.scope_id),
is_closure,
});
Expand Down Expand Up @@ -913,13 +913,13 @@ impl SemanticEventExtractor {
SemanticEvent::Read {
range,
declaration_at,
scope_id: 0,
scope_id: ScopeId::new(0),
}
} else {
SemanticEvent::HoistedRead {
range,
declaration_at,
scope_id: 0,
scope_id: ScopeId::new(0),
}
};
self.stash.push_back(event);
Expand Down Expand Up @@ -979,7 +979,7 @@ impl SemanticEventExtractor {
///
/// This method when called inside the `f` scope will return
/// the `f` scope index.
fn scope_index_to_hoist_declarations(&mut self, skip: u32) -> Option<u32> {
fn scope_index_to_hoist_declarations(&mut self, skip: u32) -> Option<ScopeId> {
debug_assert!(self.scopes.len() > (skip as usize));
// We should at least have the global scope
// that do not hoist
Expand All @@ -999,7 +999,7 @@ impl SemanticEventExtractor {
/// Push the binding `binding` into the hoisted scope if it exists, or into the current scope.
fn push_binding(
&mut self,
hoisted_scope_id: Option<u32>,
hoisted_scope_id: Option<ScopeId>,
binding_name: BindingName,
binding_info: BindingInfo,
) {
Expand Down
23 changes: 10 additions & 13 deletions crates/biome_js_semantic/src/semantic_model/builder.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,8 +16,8 @@ pub struct SemanticModelBuilder {
globals: Vec<SemanticModelGlobalBindingData>,
globals_by_name: FxHashMap<String, Option<u32>>,
scopes: Vec<SemanticModelScopeData>,
scope_range_by_start: FxHashMap<TextSize, BTreeSet<Interval<u32, u32>>>,
scope_hoisted_to_by_range: FxHashMap<TextSize, u32>,
scope_range_by_start: FxHashMap<TextSize, BTreeSet<Interval<u32, ScopeId>>>,
scope_hoisted_to_by_range: FxHashMap<TextSize, ScopeId>,
bindings: Vec<SemanticModelBindingData>,
/// maps a binding range start to its index inside SemanticModelBuilder::bindings vec
bindings_by_start: FxHashMap<TextSize, u32>,
Expand Down Expand Up @@ -128,11 +128,10 @@ impl SemanticModelBuilder {
ScopeStarted {
range,
parent_scope_id,
scope_id,
is_closure,
} => {
// Scopes will be raised in order
debug_assert!((scope_id as usize) == self.scopes.len());
let scope_id = ScopeId::new(self.scopes.len());

self.scopes.push(SemanticModelScopeData {
range,
Expand All @@ -146,9 +145,7 @@ impl SemanticModelBuilder {
});

if let Some(parent_scope_id) = parent_scope_id {
self.scopes[parent_scope_id as usize]
.children
.push(scope_id);
self.scopes[parent_scope_id.index()].children.push(scope_id);
}

let start = range.start();
Expand All @@ -171,7 +168,7 @@ impl SemanticModelBuilder {

// SAFETY: this scope id is guaranteed to exist because they were generated by the
// event extractor
debug_assert!((binding_scope_id as usize) < self.scopes.len());
debug_assert!((binding_scope_id.index()) < self.scopes.len());

let binding_id = self.bindings.len() as u32;
self.bindings.push(SemanticModelBindingData {
Expand All @@ -181,7 +178,7 @@ impl SemanticModelBuilder {
});
self.bindings_by_start.insert(range.start(), binding_id);

let scope = &mut self.scopes[binding_scope_id as usize];
let scope = &mut self.scopes[binding_scope_id.index()];

scope.bindings.push(binding_id);
// Handle bindings with a bogus name
Expand Down Expand Up @@ -214,7 +211,7 @@ impl SemanticModelBuilder {
ty: SemanticModelReferenceType::Read { hoisted: false },
});

let scope = &mut self.scopes[scope_id as usize];
let scope = &mut self.scopes[scope_id.index()];
scope.read_references.push(SemanticModelScopeReference {
binding_id,
reference_id: reference_index,
Expand All @@ -237,7 +234,7 @@ impl SemanticModelBuilder {
ty: SemanticModelReferenceType::Read { hoisted: true },
});

let scope = &mut self.scopes[scope_id as usize];
let scope = &mut self.scopes[scope_id.index()];
scope.read_references.push(SemanticModelScopeReference {
binding_id,
reference_id: reference_index,
Expand All @@ -260,7 +257,7 @@ impl SemanticModelBuilder {
ty: SemanticModelReferenceType::Write { hoisted: false },
});

let scope = &mut self.scopes[scope_id as usize];
let scope = &mut self.scopes[scope_id.index()];
scope.read_references.push(SemanticModelScopeReference {
binding_id,
reference_id: reference_index,
Expand All @@ -283,7 +280,7 @@ impl SemanticModelBuilder {
ty: SemanticModelReferenceType::Write { hoisted: true },
});

let scope = &mut self.scopes[scope_id as usize];
let scope = &mut self.scopes[scope_id.index()];
scope.read_references.push(SemanticModelScopeReference {
binding_id,
reference_id: reference_index,
Expand Down
24 changes: 12 additions & 12 deletions crates/biome_js_semantic/src/semantic_model/closure.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,7 +120,7 @@ impl Capture {
pub struct AllCapturesIter {
data: Rc<SemanticModelData>,
closure_range: TextRange,
scopes: Vec<u32>,
scopes: Vec<ScopeId>,
references: Vec<SemanticModelScopeReference>,
}

Expand All @@ -143,7 +143,7 @@ impl Iterator for AllCapturesIter {
}

'scopes: while let Some(scope_id) = self.scopes.pop() {
let scope = &self.data.scopes[scope_id as usize];
let scope = &self.data.scopes[scope_id.index()];

if scope.is_closure {
continue 'scopes;
Expand All @@ -167,15 +167,15 @@ impl FusedIterator for AllCapturesIter {}
/// Iterate all immediate children closures of a specific closure
pub struct ChildrenIter {
data: Rc<SemanticModelData>,
scopes: Vec<u32>,
scopes: Vec<ScopeId>,
}

impl Iterator for ChildrenIter {
type Item = Closure;

fn next(&mut self) -> Option<Self::Item> {
while let Some(scope_id) = self.scopes.pop() {
let scope = &self.data.scopes[scope_id as usize];
let scope = &self.data.scopes[scope_id.index()];
if scope.is_closure {
return Some(Closure {
data: self.data.clone(),
Expand All @@ -195,15 +195,15 @@ impl FusedIterator for ChildrenIter {}
/// Iterate all descendents closures of a specific closure
pub struct DescendentsIter {
data: Rc<SemanticModelData>,
scopes: Vec<u32>,
scopes: Vec<ScopeId>,
}

impl Iterator for DescendentsIter {
type Item = Closure;

fn next(&mut self) -> Option<Self::Item> {
while let Some(scope_id) = self.scopes.pop() {
let scope = &self.data.scopes[scope_id as usize];
let scope = &self.data.scopes[scope_id.index()];
self.scopes.extend(scope.children.iter());
if scope.is_closure {
return Some(Closure {
Expand All @@ -223,7 +223,7 @@ impl FusedIterator for DescendentsIter {}
#[derive(Clone)]
pub struct Closure {
data: Rc<SemanticModelData>,
scope_id: u32,
scope_id: ScopeId,
}

impl Closure {
Expand All @@ -234,8 +234,8 @@ impl Closure {
Closure { data, scope_id }
}

pub(super) fn from_scope(data: Rc<SemanticModelData>, scope_id: u32) -> Option<Closure> {
let node = &data.scope_node_by_range[&data.scopes[scope_id as usize].range];
pub(super) fn from_scope(data: Rc<SemanticModelData>, scope_id: ScopeId) -> Option<Closure> {
let node = &data.scope_node_by_range[&data.scopes[scope_id.index()].range];
match node.kind() {
JsSyntaxKind::JS_FUNCTION_DECLARATION
| JsSyntaxKind::JS_FUNCTION_EXPRESSION
Expand All @@ -246,7 +246,7 @@ impl Closure {

/// Range of this [Closure]
pub fn closure_range(&self) -> &TextRange {
&self.data.scopes[self.scope_id as usize].range
&self.data.scopes[self.scope_id.index()].range
}

/// Return all [Reference] this closure captures, not taking into
Expand All @@ -263,7 +263,7 @@ impl Closure {
/// assert!(model.closure(function_f).all_captures(), &["a"]);
/// ```
pub fn all_captures(&self) -> impl Iterator<Item = Capture> {
let scope = &self.data.scopes[self.scope_id as usize];
let scope = &self.data.scopes[self.scope_id.index()];

let scopes = scope.children.clone();

Expand Down Expand Up @@ -293,7 +293,7 @@ impl Closure {
/// assert!(model.closure(function_f).children(), &["g"]);
/// ```
pub fn children(&self) -> impl Iterator<Item = Closure> {
let scope = &self.data.scopes[self.scope_id as usize];
let scope = &self.data.scopes[self.scope_id.index()];
ChildrenIter {
data: self.data.clone(),
scopes: scope.children.clone(),
Expand Down
Loading

0 comments on commit 25e31a6

Please sign in to comment.