//! Types for the output of scope analysis. //! //! The top-level output of this analysis is the `ScopeDataMap`, which holds //! the following: //! * `LexicalScopeData` for each lexial scope in the AST //! * `GlobalScopeData` for the global scope //! * `VarScopeData` for extra body var scope in function //! * `FunctionScopeData` for the function scope //! //! Each scope contains a list of bindings (`BindingName`).
usecrate::frame_slot::FrameSlot; usecrate::script::ScriptStencilIndex; use ast::associated_data::AssociatedData; use ast::source_atom_set::SourceAtomSetIndex; use ast::source_location_accessor::SourceLocationAccessor; use ast::type_id::NodeTypeIdAccessor;
/// Corresponds to js::BindingKind in m-c/js/src/vm/Scope.h. #[derive(Debug, Clone, Copy, PartialEq)] pubenum BindingKind {
Var, Let, Const,
}
/// Information about a single binding in a JS script. /// /// Corresponds to `js::BindingName` in m-c/js/src/vm/Scope.h. #[derive(Debug)] pubstruct BindingName { pub name: SourceAtomSetIndex, pub is_closed_over: bool, pub is_top_level_function: bool,
}
/// Corresponds to the accessor part of `js::BindingIter` in /// m-c/js/src/vm/Scope.h. pubstruct BindingIterItem<'a> {
name: &'a BindingName,
kind: BindingKind,
}
#[derive(Debug)] pubstruct BaseScopeData<BindingItemT> where
BindingItemT: MaybeBindingName,
{ /// Corresponds to `*Scope::Data.{length, trailingNames}.` /// The layout is defined by *ScopeData structs below, that has /// this struct. pub bindings: Vec<BindingItemT>, pub has_eval: bool, pub has_with: bool,
}
pubfn is_all_bindings_closed_over(&self) -> bool { // `with` and direct `eval` can dynamically access any binding in this // scope. self.has_eval || self.has_with
}
/// Returns true if this scope needs to be allocated on heap as /// EnvironmentObject. pubfn needs_environment_object(&self) -> bool { // `with` and direct `eval` can dynamically access bindings in this // scope. ifself.is_all_bindings_closed_over() { returntrue;
}
// If a binding in this scope is closed over by inner function, // it can be accessed when this frame isn't on the stack. for binding in &self.bindings { if binding.is_closed_over() { returntrue;
}
}
false
}
}
/// Bindings created in global environment. /// /// Maps to js::GlobalScope::Data in m-c/js/src/vm/Scope.h. #[derive(Debug)] pubstruct GlobalScopeData { /// Bindings are sorted by kind: /// /// * `base.bindings[0..let_start]` - `var`s /// * `base.bindings[let_start..const_start]` - `let`s /// * `base.bindings[const_start..]` - `const`s pub base: BaseScopeData<BindingName>,
pub let_start: usize, pub const_start: usize,
/// The global functions in this script. pub functions: Vec<ScriptStencilIndex>,
}
/// Corresponds to the iteration part of js::BindingIter /// in m-c/js/src/vm/Scope.h. pubstruct GlobalBindingIter<'a> {
data: &'a GlobalScopeData,
i: usize,
}
/// Bindings created in var environment. /// /// Maps to js::VarScope::Data in m-c/js/src/vm/Scope.h, /// and the parameter for js::frontend::ScopeCreationData::create /// in m-c/js/src/frontend/Stencil.h #[derive(Debug)] pubstruct VarScopeData { /// All bindings are `var`. pub base: BaseScopeData<BindingName>,
/// The first frame slot of this scope. /// /// Unlike VarScope::Data, this struct holds the first frame slot, /// instead of the next frame slot. /// /// This is because ScopeCreationData::create receives the first frame slot /// and VarScope::Data.nextFrameSlot is calculated there. pub first_frame_slot: FrameSlot,
pub function_has_extensible_scope: bool,
/// ScopeIndex of the enclosing scope. /// /// A parameter for ScopeCreationData::create. pub enclosing: ScopeIndex,
}
Self {
base: BaseScopeData::new(capacity), // Set to the correct value in EmitterScopeStack::enter_lexical.
first_frame_slot: FrameSlot::new(0),
function_has_extensible_scope,
enclosing,
}
}
}
/// Bindings created in lexical environment. /// /// Maps to js::LexicalScope::Data in m-c/js/src/vm/Scope.h, /// and the parameter for js::frontend::ScopeCreationData::create /// in m-c/js/src/frontend/Stencil.h #[derive(Debug)] pubstruct LexicalScopeData { /// Bindings are sorted by kind: /// /// * `base.bindings[0..const_start]` - `let`s /// * `base.bindings[const_start..]` - `const`s pub base: BaseScopeData<BindingName>,
pub const_start: usize,
/// The first frame slot of this scope. /// /// Unlike LexicalScope::Data, this struct holds the first frame slot, /// instead of the next frame slot. /// /// This is because ScopeCreationData::create receives the first frame slot /// and LexicalScope::Data.nextFrameSlot is calculated there. pub first_frame_slot: FrameSlot,
/// ScopeIndex of the enclosing scope. /// /// A parameter for ScopeCreationData::create. pub enclosing: ScopeIndex,
/// Functions in this scope. pub functions: Vec<ScriptStencilIndex>,
}
Self {
base: BaseScopeData::new(capacity),
const_start: let_count, // Set to the correct value in EmitterScopeStack::enter_lexical.
first_frame_slot: FrameSlot::new(0),
enclosing,
functions,
}
}
/// Corresponds to the iteration part of js::BindingIter /// in m-c/js/src/vm/Scope.h. pubstruct LexicalBindingIter<'a> {
data: &'a LexicalScopeData,
i: usize,
}
/// Bindings created in function environment. /// /// Maps to js::FunctionScope::Data in m-c/js/src/vm/Scope.h, /// and the parameter for js::frontend::ScopeCreationData::create /// in m-c/js/src/frontend/Stencil.h #[derive(Debug)] pubstruct FunctionScopeData { /// Bindings are sorted by kind: /// /// * `base.bindings[0..non_positional_formal_start]` - /// positional foparameters: /// - single binding parameter with/without default /// - single binding rest parameter /// * `base.bindings[non_positional_formal_start..var_start]` - /// non positional parameters: /// - destructuring parameter /// - destructuring rest parameter /// * `base.bindings[var_start..]` - `var`s /// /// Given positional parameters range can have null slot for destructuring, /// use Vec of Option<BindingName>, instead of BindingName like others. pub base: BaseScopeData<Option<BindingName>>,
/// The first frame slot of this scope. /// /// Unlike FunctionScope::Data, this struct holds the first frame slot, /// instead of the next frame slot. /// /// This is because ScopeCreationData::create receives the first frame slot /// and FunctionScope::Data.nextFrameSlot is calculated there. pub first_frame_slot: FrameSlot,
/// ScopeIndex of the enclosing scope. /// /// A parameter for ScopeCreationData::create. pub enclosing: ScopeIndex,
pub function_index: ScriptStencilIndex,
/// True if the function is an arrow function. pub is_arrow: bool,
}
Self {
base: BaseScopeData::new(capacity),
has_parameter_exprs,
non_positional_formal_start: positional_parameter_count,
var_start: positional_parameter_count + non_positional_formal_start, // Set to the correct value in EmitterScopeStack::enter_function.
first_frame_slot: FrameSlot::new(0),
enclosing,
function_index,
is_arrow,
}
}
}
#[derive(Debug)] pubenum ScopeData { /// No scope should be generated, but this scope becomes an alias to /// enclosing scope. This is used, for example, when we see a function, /// and set aside a ScopeData for its lexical bindings, but upon /// reaching the end of the function body, we find that there were no /// lexical bindings and the spec actually says not to generate a Lexical /// Environment when this function is called. /// /// In other places, the spec does say to create a Lexical Environment, but /// it turns out it doesn't have any bindings in it and we can optimize it /// away. /// /// NOTE: Alias can be chained.
Alias(ScopeIndex),
/// A vector of scopes, incrementally populated during analysis. /// The goal is to build a `Vec<ScopeData>`. #[derive(Debug)] pubstruct ScopeDataList { /// Uses Option to allow `allocate()` and `populate()` to be called /// separately.
scopes: Vec<Option<ScopeData>>,
}
impl From<ScopeDataList> for Vec<ScopeData> { fn from(list: ScopeDataList) -> Vec<ScopeData> {
list.scopes
.into_iter()
.map(|g| g.expect("Should be populated"))
.collect()
}
}
/// The collection of all scope data associated with bindings and scopes in the /// AST. #[derive(Debug)] pubstruct ScopeDataMap {
scopes: ScopeDataList,
global: ScopeIndex,
/// Associates every AST node that's a scope with an index into `scopes`.
non_global: AssociatedData<ScopeIndex>,
}
pubfn get_index<NodeT>(&self, node: &NodeT) -> ScopeIndex where
NodeT: SourceLocationAccessor + NodeTypeIdAccessor,
{ self.non_global
.get(node)
.expect("There should be a scope data associated")
.clone()
}
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.