Anforderungen  |   Konzepte  |   Entwurf  |   Entwicklung  |   Qualitätssicherung  |   Lebenszyklus  |   Steuerung
 
 
 
 


Quelle  builder.rs   Sprache: unbekannt

 
//! Data collection.
//!
//! `ScopeBuilder` is the entry point of this module.
//!
//! Each AST node that will hold bindings (global, block, function, etc.) has a
//! corresponding scope builder type defined in this module:
//!   * `GlobalScopeBuilder`
//!   * `BlockScopeBuilder`
//!   * `FunctionExpressionScopeBuilder`
//!   * `FunctionParametersScopeBuilder`
//!   * `FunctionBodyScopeBuilder`
//!
//! They follow the pattern:
//!   * They are created and pushed to the `ScopeBuilderStack` when the
//!     algorithm enters a scope.
//!   * They collect the information necessary to build a `ScopeData` object
//!     (which will eventually become a `js::ScopeCreationData` on the
//!      C++ side).
//!   * They stay on the scope builder stack until the algorithm leaves that
//!     scope.
//!   * Then they are converted by `into_scope_data()`.
//!
//! Fields in the builder types mostly correspond to local variables in spec
//! algorithms.  For example, `GlobalScopeBuilder` has fields named
//! `functions_to_initialize`, `declared_function_names`, and
//! `declared_var_names` which correspond to the
//! [GlobalDeclarationInstantiation][1] algorithm's local variables
//! *functionsToInitialize*, *declaredFunctionNames*, and *declaredVarNames*.
//!
//! This module performs some steps of those algorithms -- the parts that can
//! be done at compile time. The results are passed along to the emitter and
//! ultimately the JS runtime.
//!
//! # Syntax-only mode
//!
//! When doing syntax-only parsing, we collect minimal information, that does
//! not include `ScopeData`, but `ScriptStencil` for functions.
//!
//! [1]: https://tc39.es/ecma262/#sec-globaldeclarationinstantiation

use crate::data::FunctionDeclarationPropertyMap;
use crate::free_name_tracker::FreeNameTracker;
use ast::associated_data::AssociatedData;
use ast::source_atom_set::{CommonSourceAtomSetIndices, SourceAtomSetIndex};
use ast::source_location_accessor::SourceLocationAccessor;
use ast::type_id::NodeTypeIdAccessor;
use indexmap::set::IndexSet;
use std::collections::hash_map::Keys;
use std::collections::{HashMap, HashSet};
use stencil::function::{FunctionFlags, FunctionSyntaxKind};
use stencil::scope::{
    BindingName, FunctionScopeData, GlobalScopeData, LexicalScopeData, ScopeData, ScopeDataList,
    ScopeDataMap, ScopeIndex, VarScopeData,
};
use stencil::script::{ScriptStencil, ScriptStencilIndex, ScriptStencilList, SourceExtent};

/// The kind of items inside the result of VarScopedDeclarations.
///
/// This enum isn't actually used, but just for simplifying comment in
/// ScopeKind.
#[derive(Debug, Clone, PartialEq)]
enum VarScopedDeclarationsItemKind {
    /// Static Semantics: VarScopedDeclarations
    /// https://tc39.es/ecma262/#sec-variable-statement-static-semantics-varscopeddeclarations
    ///
    /// VariableDeclarationList : VariableDeclaration
    ///
    /// 1. Return a new List containing VariableDeclaration.
    ///
    /// VariableDeclarationList : VariableDeclarationList, VariableDeclaration
    ///
    /// 1. Let declarations be VarScopedDeclarations of VariableDeclarationList.
    /// 2. Append VariableDeclaration to declarations.
    /// 3. Return declarations.
    #[allow(dead_code)]
    VariableDeclaration,

    /// Static Semantics: VarScopedDeclarations
    /// https://tc39.es/ecma262/#sec-for-in-and-for-of-statements-static-semantics-varscopeddeclarations
    ///
    /// IterationStatement :
    ///   for ( var ForBinding in Expression ) Statement
    ///   for ( var ForBinding of AssignmentExpression ) Statement
    ///   for await ( var ForBinding of AssignmentExpression ) Statement
    ///
    /// 1. Let declarations be a List containing ForBinding.
    /// 2. Append to declarations the elements of the VarScopedDeclarations of
    ///    Statement.
    /// 3. Return declarations.
    #[allow(dead_code)]
    ForBinding,

    /// Static Semantics: VarScopedDeclarations
    /// https://tc39.es/ecma262/#sec-function-definitions-static-semantics-varscopeddeclarations
    ///
    /// FunctionStatementList : StatementList
    ///
    /// 1. Return the TopLevelVarScopedDeclarations of StatementList.

    /// Static Semantics: VarScopedDeclarations
    /// https://tc39.es/ecma262/#sec-scripts-static-semantics-varscopeddeclarations
    ///
    /// ScriptBody : StatementList
    ///
    /// 1. Return TopLevelVarScopedDeclarations of StatementList.

    /// Static Semantics: TopLevelVarScopedDeclarations
    /// https://tc39.es/ecma262/#sec-block-static-semantics-toplevelvarscopeddeclarations
    ///
    /// StatementListItem : Declaration
    ///
    /// 1. If Declaration is Declaration : HoistableDeclaration, then
    ///   a. Let declaration be DeclarationPart of HoistableDeclaration.
    ///   b. Return « declaration ».
    /// 2. Return a new empty List.

    /// Static Semantics: DeclarationPart
    /// https://tc39.es/ecma262/#sec-static-semantics-declarationpart
    ///
    /// HoistableDeclaration : FunctionDeclaration
    ///
    /// 1. Return FunctionDeclaration.
    #[allow(dead_code)]
    FunctionDeclaration,

    /// HoistableDeclaration : GeneratorDeclaration
    ///
    /// 1. Return GeneratorDeclaration.
    #[allow(dead_code)]
    GeneratorDeclaration,

    /// HoistableDeclaration : AsyncFunctionDeclaration
    ///
    /// 1. Return AsyncFunctionDeclaration.
    #[allow(dead_code)]
    AsyncFunctionDeclaration,

    /// HoistableDeclaration : AsyncGeneratorDeclaration
    ///
    /// 1. Return AsyncGeneratorDeclaration.
    #[allow(dead_code)]
    AsyncGeneratorDeclaration,

    /// Static Semantics: TopLevelVarScopedDeclarations
    /// https://tc39.es/ecma262/#sec-labelled-statements-static-semantics-toplevelvarscopeddeclarations
    ///
    /// LabelledItem : FunctionDeclaration
    ///
    /// 1. Return a new List containing FunctionDeclaration.
    /* FunctionDeclaration */

    /// Annex B Initializers in ForIn Statement Heads
    /// https://tc39.es/ecma262/#sec-initializers-in-forin-statement-heads
    ///
    /// IterationStatement :
    ///   for ( var BindingIdentifier Initializer in Expression ) Statement
    ///
    /// 1. Let declarations be a List containing BindingIdentifier.
    /// 2. Append to declarations the elements of the VarScopedDeclarations of
    ///    Statement.
    /// 3. Return declarations.
    #[allow(dead_code)]
    BindingIdentifier,
}

/// The kind of items inside the result of LexicallyScopedDeclarations.
///
/// This enum isn't actually used, but just for simplifying comment in
/// ScopeKind.
#[derive(Debug, Clone, PartialEq)]
enum LexicallyScopedDeclarations {
    /// Static Semantics: LexicallyScopedDeclarations
    /// https://tc39.es/ecma262/#sec-block-static-semantics-lexicallyscopeddeclarations
    ///
    /// StatementListItem : Declaration
    ///
    /// 1. Return a new List containing DeclarationPart of Declaration.

    /// Static Semantics: DeclarationPart
    /// https://tc39.es/ecma262/#sec-static-semantics-declarationpart
    ///
    /// HoistableDeclaration : FunctionDeclaration
    ///
    /// 1. Return FunctionDeclaration.
    #[allow(dead_code)]
    FunctionDeclaration,

    /// HoistableDeclaration : GeneratorDeclaration
    ///
    /// 1. Return GeneratorDeclaration.
    #[allow(dead_code)]
    GeneratorDeclaration,

    /// HoistableDeclaration : AsyncFunctionDeclaration
    ///
    /// 1. Return AsyncFunctionDeclaration.
    #[allow(dead_code)]
    AsyncFunctionDeclaration,

    /// HoistableDeclaration : AsyncGeneratorDeclaration
    ///
    /// 1. Return AsyncGeneratorDeclaration.
    #[allow(dead_code)]
    AsyncGeneratorDeclaration,

    /// Declaration : ClassDeclaration
    ///
    /// 1. Return ClassDeclaration.
    #[allow(dead_code)]
    ClassDeclaration,

    /// Declaration : LexicalDeclaration
    ///
    /// 1. Return LexicalDeclaration.
    #[allow(dead_code)]
    LexicalDeclarationWithLet,
    #[allow(dead_code)]
    LexicalDeclarationWithConst,

    /// Static Semantics: LexicallyScopedDeclarations
    /// https://tc39.es/ecma262/#sec-labelled-statements-static-semantics-lexicallyscopeddeclarations
    ///
    /// LabelledItem : FunctionDeclaration
    ///
    /// 1. Return a new List containing FunctionDeclaration.
    /* FunctionDeclaration */

    /// Static Semantics: LexicallyScopedDeclarations
    /// https://tc39.es/ecma262/#sec-function-definitions-static-semantics-lexicallyscopeddeclarations
    ///
    /// FunctionStatementList : StatementList
    ///
    /// 1. Return the TopLevelLexicallyScopedDeclarations of StatementList.

    /// Static Semantics: LexicallyScopedDeclarations
    /// https://tc39.es/ecma262/#sec-scripts-static-semantics-lexicallyscopeddeclarations
    ///
    /// ScriptBody : StatementList
    ///
    /// 1. Return TopLevelLexicallyScopedDeclarations of StatementList.

    /// Static Semantics: TopLevelLexicallyScopedDeclarations
    /// https://tc39.es/ecma262/#sec-block-static-semantics-toplevellexicallyscopeddeclarations
    ///
    /// StatementListItem : Declaration
    ///
    /// 1. If Declaration is Declaration : HoistableDeclaration, then
    ///   a. Return « ».
    /// 2. Return a new List containing Declaration.

    /// Static Semantics: LexicallyScopedDeclarations
    /// https://tc39.es/ecma262/#sec-exports-static-semantics-lexicallyscopeddeclarations
    ///
    /// ExportDeclaration : export Declaration
    ///
    /// 1. Return a new List containing DeclarationPart of Declaration.

    /// ExportDeclaration : export default HoistableDeclaration
    ///
    /// 1. Return a new List containing DeclarationPart of HoistableDeclaration.

    /// ExportDeclaration : export default ClassDeclaration
    ///
    /// 1. Return a new List containing ClassDeclaration.
    /* ClassDeclaration */

    /// ExportDeclaration : export default AssignmentExpression ;
    ///
    /// 1. Return a new List containing this ExportDeclaration.
    #[allow(dead_code)]
    ExportDeclarationWithAssignmentExpression,
}

/// Items on the ScopeBuilder.scope_stack.
/// Specifies the kind of BindingIdentifier.
///
/// This includes only BindingIdentifier that appears inside list or recursive
/// structure.
///
/// BindingIdentifier that appears only once for a structure
/// (e.g. Function.name) should be handled immediately, without using
/// ScopeBuilder.scope_stack.
#[derive(Debug, Clone, PartialEq)]
enum ScopeKind {
    /// VarScopedDeclarationsItemKind::VariableDeclaration
    /// VarScopedDeclarationsItemKind::ForBinding
    /// VarScopedDeclarationsItemKind::BindingIdentifier
    Var,

    /// LexicallyScopedDeclarations::LexicalDeclarationWithLet
    Let,

    /// LexicallyScopedDeclarations::LexicalDeclarationWithConst
    Const,

    /// Pushed when entering function, to catch function name.
    FunctionName,

    /// Pushed when entering function parameter, to disable FunctionName's
    /// effect.
    /// Equivalent to the case there's no kind on the stack.
    FunctionParametersAndBody,

    FormalParameter,

    #[allow(dead_code)]
    CatchParameter,

    /// LexicallyScopedDeclarations::ExportDeclarationWithAssignmentExpression
    #[allow(dead_code)]
    Export,

    /// VarScopedDeclarationsItemKind::FunctionDeclaration
    /// VarScopedDeclarationsItemKind::GeneratorDeclaration
    /// VarScopedDeclarationsItemKind::AsyncFunctionDeclaration
    /// VarScopedDeclarationsItemKind::AsyncGeneratorDeclaration
    #[allow(dead_code)]
    ScriptBodyStatementList,
    #[allow(dead_code)]
    FunctionStatementList,

    /// LexicallyScopedDeclarations::FunctionDeclaration
    /// LexicallyScopedDeclarations::GeneratorDeclaration
    /// LexicallyScopedDeclarations::AsyncFunctionDeclaration
    /// LexicallyScopedDeclarations::AsyncGeneratorDeclaration
    /// LexicallyScopedDeclarations::ClassDeclaration
    #[allow(dead_code)]
    BlockStatementList,
}

/// Index into BaseScopeData.bindings.
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct BindingIndex {
    index: usize,
}
impl BindingIndex {
    fn new(index: usize) -> Self {
        Self { index }
    }

    pub fn next(&self) -> Self {
        Self {
            index: self.index + 1,
        }
    }
}

impl From<BindingIndex> for usize {
    fn from(index: BindingIndex) -> usize {
        index.index
    }
}

#[derive(Debug)]
struct PossiblyAnnexBFunction {
    #[allow(dead_code)]
    name: SourceAtomSetIndex,
    #[allow(dead_code)]
    owner_scope_index: ScopeIndex,
    #[allow(dead_code)]
    binding_index: BindingIndex,

    /// Index of the script in the list of `functions` in the
    /// `FunctionScriptStencilBuilder`.
    script_index: ScriptStencilIndex,
}

#[derive(Debug)]
struct PossiblyAnnexBFunctionList {
    functions: HashMap<SourceAtomSetIndex, Vec<PossiblyAnnexBFunction>>,
}

impl PossiblyAnnexBFunctionList {
    fn new() -> Self {
        Self {
            functions: HashMap::new(),
        }
    }

    fn push(
        &mut self,
        name: SourceAtomSetIndex,
        owner_scope_index: ScopeIndex,
        binding_index: BindingIndex,
        script_index: ScriptStencilIndex,
    ) {
        if let Some(functions) = self.functions.get_mut(&name) {
            functions.push(PossiblyAnnexBFunction {
                name,
                owner_scope_index,
                binding_index,
                script_index,
            });
            return;
        }

        let mut functions = Vec::with_capacity(1);
        functions.push(PossiblyAnnexBFunction {
            name,
            owner_scope_index,
            binding_index,
            script_index,
        });
        self.functions.insert(name, functions);
    }

    fn remove_if_exists(&mut self, name: SourceAtomSetIndex) {
        self.functions.remove(&name);
    }

    fn mark_annex_b(&self, function_declaration_properties: &mut FunctionDeclarationPropertyMap) {
        for functions in &mut self.functions.values() {
            for fun in functions {
                function_declaration_properties.mark_annex_b(fun.script_index);
            }
        }
    }

    fn names(&self) -> Keys<SourceAtomSetIndex, Vec<PossiblyAnnexBFunction>> {
        self.functions.keys()
    }

    fn clear(&mut self) {
        self.functions.clear();
    }
}

/// Common fields across all *ScopeBuilder.
#[derive(Debug)]
struct BaseScopeBuilder {
    name_tracker: FreeNameTracker,

    /// Bindings in this scope can be accessed dynamically by:
    ///   * direct `eval`
    ///   * `with` statement
    ///   * `delete name` statement
    bindings_accessed_dynamically: bool,
}

impl BaseScopeBuilder {
    fn new() -> Self {
        Self {
            name_tracker: FreeNameTracker::new(),
            bindings_accessed_dynamically: false,
        }
    }

    fn propagate_common(&mut self, inner: &BaseScopeBuilder) {
        // When construct such as `eval`, `with` and `delete` access
        // name dynamically in inner scopes, we have to propagate this
        // flag to the outer scope such that we prevent optimizations.
        self.bindings_accessed_dynamically |= inner.bindings_accessed_dynamically;
    }

    fn propagate_from_inner_non_script(&mut self, inner: &BaseScopeBuilder) {
        self.propagate_common(inner);
        self.name_tracker
            .propagate_from_inner_non_script(&inner.name_tracker);
    }

    fn propagate_from_inner_script(&mut self, inner: &BaseScopeBuilder) {
        self.propagate_common(inner);
        self.name_tracker
            .propagate_from_inner_script(&inner.name_tracker);
    }

    fn declare_var(&mut self, name: SourceAtomSetIndex) {
        self.name_tracker.note_def(name);
    }

    fn declare_let(&mut self, name: SourceAtomSetIndex) {
        self.name_tracker.note_def(name);
    }

    fn declare_const(&mut self, name: SourceAtomSetIndex) {
        self.name_tracker.note_def(name);
    }

    fn declare_function(&mut self, name: SourceAtomSetIndex) {
        self.name_tracker.note_def(name);
    }

    fn set_function_name(&mut self, name: SourceAtomSetIndex) {
        self.name_tracker.note_def(name);
    }

    fn declare_param(&mut self, name: SourceAtomSetIndex) {
        self.name_tracker.note_def(name);
    }
}

/// Variables declared/used in GlobalDeclarationInstantiation.
#[derive(Debug)]
struct GlobalScopeBuilder {
    base: BaseScopeBuilder,

    /// Runtime Semantics: GlobalDeclarationInstantiation ( script, env )
    /// https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
    ///
    /// Step 8. Let functionsToInitialize be a new empty List.
    functions_to_initialize: Vec<ScriptStencilIndex>,

    /// Step 9. Let declaredFunctionNames be a new empty List.
    declared_function_names: IndexSet<SourceAtomSetIndex>,

    /// Step 11. Let declaredVarNames be a new empty List.
    /// NOTE: This is slightly different than the spec that this can contain
    ///       names in declaredFunctionNames.
    ///       The duplication should be filtered before the use.
    declared_var_names: IndexSet<SourceAtomSetIndex>,

    /// Step 15. Let lexDeclarations be the LexicallyScopedDeclarations of
    ///          script.
    let_names: Vec<SourceAtomSetIndex>,
    const_names: Vec<SourceAtomSetIndex>,

    scope_index: ScopeIndex,
}

impl GlobalScopeBuilder {
    fn new(scope_index: ScopeIndex) -> Self {
        Self {
            base: BaseScopeBuilder::new(),
            functions_to_initialize: Vec::new(),
            declared_function_names: IndexSet::new(),
            declared_var_names: IndexSet::new(),
            let_names: Vec::new(),
            const_names: Vec::new(),
            scope_index,
        }
    }

    fn declare_var(&mut self, name: SourceAtomSetIndex) {
        // Runtime Semantics: GlobalDeclarationInstantiation ( script, env )
        // https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
        //
        // Step 7. Let varDeclarations be the VarScopedDeclarations of script.
        //
        // Step 12. For each d in varDeclarations, do
        // Step 12.a. If d is a VariableDeclaration, a ForBinding, or a
        //            BindingIdentifier, then
        // Step 12.a.i. For each String vn in the BoundNames of d, do
        // (implicit)

        // Step 12.a.i.i If vn is not an element of declaredFunctionNames, then
        // (done in remove_function_names_from_var_names)

        // Step 12.a.i.1.a. Let vnDefinable be ? envRec.CanDeclareGlobalVar(vn).
        // Step 12.a.i.1.b. If vnDefinable is false, throw a TypeError
        //                  exception.
        // (done in runtime)

        // Step 12.a.i.1.c. If vn is not an element of declaredVarNames, then
        // Step 12.a.i.1.a.i. Append vn to declaredVarNames.
        self.declared_var_names.insert(name);
        self.base.declare_var(name);
    }

    fn declare_let(&mut self, name: SourceAtomSetIndex) {
        // Runtime Semantics: GlobalDeclarationInstantiation ( script, env )
        // https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
        //
        // Step 15. Let lexDeclarations be the LexicallyScopedDeclarations of
        //          script.
        self.let_names.push(name);
        self.base.declare_let(name);
    }

    fn declare_const(&mut self, name: SourceAtomSetIndex) {
        // Runtime Semantics: GlobalDeclarationInstantiation ( script, env )
        // https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
        //
        // Step 15. Let lexDeclarations be the LexicallyScopedDeclarations of
        //          script.
        self.const_names.push(name);
        self.base.declare_const(name);
    }

    fn declare_function(&mut self, name: SourceAtomSetIndex, fun_index: ScriptStencilIndex) {
        // Runtime Semantics: GlobalDeclarationInstantiation ( script, env )
        // https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
        //
        // Step 10. For each d in varDeclarations, in reverse list order, do
        // Step 10.a. If d is neither a VariableDeclaration nor a ForBinding
        //            nor a BindingIdentifier, then
        // (implicit)

        // Step 10.a.i. Assert: d is either a FunctionDeclaration,
        //              a GeneratorDeclaration, an AsyncFunctionDeclaration,
        //              or an AsyncGeneratorDeclaration.

        // Step 10.a.ii. NOTE: If there are multiple function declarations for
        //               the same name, the last declaration is used.

        // Step 10.a.iii. Let fn be the sole element of the BoundNames of d.

        // Step 10.a.iv. If fn is not an element of declaredFunctionNames, then
        //
        // NOTE: Instead of iterating in reverse list oder, we iterate in
        // normal order and overwrite existing item.

        // Steps 10.a.iv.1. Let fnDefinable be
        //                  ? envRec.CanDeclareGlobalFunction(fn).
        // Steps 10.a.iv.2. If fnDefinable is false, throw a TypeError
        //                  exception.
        // (done in runtime)

        // Step 10.a.iv.3. Append fn to declaredFunctionNames.
        self.declared_function_names.insert(name.clone());

        // Step 10.a.iv.4. Insert d as the first element of
        //                 functionsToInitialize.
        self.functions_to_initialize.push(fun_index);

        self.base.declare_function(name);
    }

    fn remove_function_names_from_var_names(&mut self) {
        // Runtime Semantics: GlobalDeclarationInstantiation ( script, env )
        // https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
        //
        // Step 12.a.i.i If vn is not an element of declaredFunctionNames, then
        //
        // To avoid doing 2-pass, we note all var names, and filter function
        // names out after visiting all of them.
        for n in &self.declared_function_names {
            self.declared_var_names.remove(n);
        }
    }

    fn perform_annex_b(
        &mut self,
        function_declaration_properties: &mut FunctionDeclarationPropertyMap,
        possibly_annex_b_functions: &mut PossiblyAnnexBFunctionList,
    ) {
        // Annex B
        // Changes to GlobalDeclarationInstantiation
        // https://tc39.es/ecma262/#sec-web-compat-globaldeclarationinstantiation
        //
        // Step 1. Let strict be IsStrict of script.
        //
        // FIXME: Once directives are supported, reflect it here.
        let strict = false;

        // Step 2. If strict is false, then
        if strict {
            return;
        }

        // Step 2.a. Let declaredFunctionOrVarNames be a new empty List.
        // Step 2.b. Append to declaredFunctionOrVarNames the elements of
        //           declaredFunctionNames.
        // Step 2.c. Append to declaredFunctionOrVarNames the elements of
        //           declaredVarNames.
        //
        // NOTE: Use `self.declared_var_names` to avoid duplication against
        //       `declaredVarNames`.
        //       And duplication against `declaredFunctionNames` will be
        //       removed in `remove_function_names_from_var_names`.

        // Step 2.d. For each FunctionDeclaration f that is directly contained
        //           in the StatementList of a Block, CaseClause, or
        //           DefaultClause Contained within script, do
        //
        // NOTE: `possibly_annex_b_functions` contains all of them.

        // Step 2.d.i. Let F be StringValue of the BindingIdentifier of f.
        // Step 2.d.ii. If replacing the FunctionDeclaration f with a
        //              VariableStatement that has F as a BindingIdentifier
        //              would not produce any Early Errors for script, then
        //
        // NOTE: Early Errors happen if any of top-level lexical has
        //       the same name.  Filter out those functions here.
        for n in &self.let_names {
            possibly_annex_b_functions.remove_if_exists(*n);
        }
        for n in &self.const_names {
            possibly_annex_b_functions.remove_if_exists(*n);
        }

        // Step 2.d.ii.1. If env.HasLexicalDeclaration(F) is false, then
        // Step 2.d.ii.1.a. Let fnDefinable be ? env.CanDeclareGlobalVar(F).
        // Step 2.d.ii.1.b. If fnDefinable is true, then
        //
        // FIXME: Are these steps performed by any implementation?
        //        https://github.com/tc39/ecma262/issues/2019

        // Step 2.d.ii.1.b.i. NOTE: A var binding for F is only instantiated
        //                    here if it is neither a VarDeclaredName nor
        //                    the name of another FunctionDeclaration.
        // Step 2.d.ii.1.b.ii. If declaredFunctionOrVarNames does not
        //                     contain F, then
        // Step 2.d.ii.1.b.ii.1. Perform
        //                       ?env.CreateGlobalVarBinding(F, false).
        // Step 2.d.ii.1.b.ii.2. Append F to declaredFunctionOrVarNames.
        for n in possibly_annex_b_functions.names() {
            self.declare_var(*n);
        }

        // Step 2.d.ii.1.b.iii. When the FunctionDeclaration f is evaluated,
        //                      perform the following steps in place of the
        //                      FunctionDeclaration Evaluation algorithm
        //                      provided in
        //                      https://tc39.es/ecma262/#sec-function-definitions-runtime-semantics-evaluation :
        // Step 2.d.ii.1.b.iii.1. Let genv be the running execution
        //                        context's VariableEnvironment.
        // Step 2.d.ii.1.b.iii.2. Let benv be the running execution
        //                        context's LexicalEnvironment.
        // Step 2.d.ii.1.b.iii.3. Let fobj be
        //                        ! benv.GetBindingValue(F, false).
        // Step 2.d.ii.1.b.iii.4. Perform
        //                        ? genv.SetMutableBinding(F, fobj, false).
        // Step 2.d.ii.1.b.iii.5. Return NormalCompletion(empty).
        possibly_annex_b_functions.mark_annex_b(function_declaration_properties);
    }

    fn into_scope_data(
        mut self,
        function_declaration_properties: &mut FunctionDeclarationPropertyMap,
        possibly_annex_b_functions: &mut PossiblyAnnexBFunctionList,
    ) -> ScopeData {
        // Runtime Semantics: GlobalDeclarationInstantiation ( script, env )
        // https://tc39.es/ecma262/#sec-globaldeclarationinstantiation
        //
        // NOTE: Steps are reordered to match the order of binding in runtime.

        // Step 13. NOTE: Annex B adds additional steps at this point.
        //
        // NOTE: Reordered here to reflect the change to
        //       self.declared_var_names.
        self.perform_annex_b(function_declaration_properties, possibly_annex_b_functions);

        // Step 12.a.i.i If vn is not an element of declaredFunctionNames, then
        self.remove_function_names_from_var_names();

        let mut data = GlobalScopeData::new(
            self.declared_var_names.len() + self.declared_function_names.len(),
            self.let_names.len(),
            self.const_names.len(),
            self.functions_to_initialize,
        );

        // Step 18. For each String vn in declaredVarNames, in list order, do
        for n in &self.declared_var_names {
            // 18.a. Perform ? envRec.CreateGlobalVarBinding(vn, false).
            let is_closed_over = self.base.name_tracker.is_closed_over_def(n);
            data.base
                .bindings
                .push(BindingName::new(*n, is_closed_over))
        }

        // Step 17. For each Parse Node f in functionsToInitialize, do
        for n in &self.declared_function_names {
            // Step 17.a. Let fn be the sole element of the BoundNames of f.
            // Step 17.b. Let fo be InstantiateFunctionObject of f with
            //            argument env.
            // Step 17.c. Perform
            //            ? envRec.CreateGlobalFunctionBinding(fn, fo, false).
            let is_closed_over = self.base.name_tracker.is_closed_over_def(n);
            data.base
                .bindings
                .push(BindingName::new_top_level_function(*n, is_closed_over));
        }

        // Step 15. Let lexDeclarations be the LexicallyScopedDeclarations of
        //          script.
        // Step 16. For each element d in lexDeclarations, do
        // Step 16.b. For each element dn of the BoundNames of d, do
        for n in &self.let_names {
            // Step 16.b.ii. Else,
            // Step 16.b.ii.1. Perform ? envRec.CreateMutableBinding(dn, false).
            let is_closed_over = self.base.name_tracker.is_closed_over_def(n);
            data.base
                .bindings
                .push(BindingName::new(*n, is_closed_over))
        }
        for n in &self.const_names {
            // Step 16.b.i. If IsConstantDeclaration of d is true, then
            // Step 16.b.i.1. Perform ? envRec.CreateImmutableBinding(dn, true).
            let is_closed_over = self.base.name_tracker.is_closed_over_def(n);
            data.base
                .bindings
                .push(BindingName::new(*n, is_closed_over))
        }

        ScopeData::Global(data)
    }
}

#[derive(Debug)]
struct FunctionNameAndStencilIndex {
    name: SourceAtomSetIndex,
    stencil: ScriptStencilIndex,
}

/// Variables declared/used in BlockDeclarationInstantiation
#[derive(Debug)]
struct BlockScopeBuilder {
    base: BaseScopeBuilder,

    /// Runtime Semantics: BlockDeclarationInstantiation ( code, env )
    /// https://tc39.es/ecma262/#sec-blockdeclarationinstantiation
    ///
    /// Step 3. Let declarations be the LexicallyScopedDeclarations of code.
    let_names: Vec<SourceAtomSetIndex>,
    const_names: Vec<SourceAtomSetIndex>,

    /// Runtime Semantics: BlockDeclarationInstantiation ( code, env )
    /// https://tc39.es/ecma262/#sec-blockdeclarationinstantiation
    ///
    /// Step 4.b. If d is a FunctionDeclaration, a GeneratorDeclaration, an
    ///           AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration,
    ///           then
    functions: Vec<FunctionNameAndStencilIndex>,

    /// Scope associated to this builder.
    scope_index: ScopeIndex,
}

impl BlockScopeBuilder {
    fn new(scope_index: ScopeIndex) -> Self {
        Self {
            base: BaseScopeBuilder::new(),
            let_names: Vec::new(),
            const_names: Vec::new(),
            functions: Vec::new(),
            scope_index,
        }
    }

    fn declare_let(&mut self, name: SourceAtomSetIndex) {
        // Runtime Semantics: BlockDeclarationInstantiation ( code, env )
        // https://tc39.es/ecma262/#sec-blockdeclarationinstantiation
        //
        // Step 3. Let declarations be the LexicallyScopedDeclarations of code.
        self.let_names.push(name);
        self.base.declare_let(name);
    }

    fn declare_const(&mut self, name: SourceAtomSetIndex) {
        // Runtime Semantics: BlockDeclarationInstantiation ( code, env )
        // https://tc39.es/ecma262/#sec-blockdeclarationinstantiation
        //
        // Step 3. Let declarations be the LexicallyScopedDeclarations of code.
        self.const_names.push(name);
        self.base.declare_const(name);
    }

    fn declare_function(&mut self, name: SourceAtomSetIndex, fun_index: ScriptStencilIndex) {
        // Runtime Semantics: BlockDeclarationInstantiation ( code, env )
        // https://tc39.es/ecma262/#sec-blockdeclarationinstantiation
        //
        // Step 3. Let declarations be the LexicallyScopedDeclarations of code.
        //
        // Step 4.b. If d is a FunctionDeclaration, a GeneratorDeclaration, an
        //           AsyncFunctionDeclaration, or an AsyncGeneratorDeclaration,
        //           then
        self.functions.push(FunctionNameAndStencilIndex {
            name,
            stencil: fun_index,
        });

        self.base.declare_function(name);
    }

    fn into_scope_data(
        self,
        enclosing: ScopeIndex,
        possibly_annex_b_functions: &mut PossiblyAnnexBFunctionList,
    ) -> ScopeData {
        let mut data = LexicalScopeData::new_block(
            self.let_names.len() + self.functions.len(),
            self.const_names.len(),
            enclosing,
            self.functions.iter().map(|n| n.stencil).collect(),
        );

        // Runtime Semantics: BlockDeclarationInstantiation ( code, env )
        // https://tc39.es/ecma262/#sec-blockdeclarationinstantiation
        //
        // Step 1. Let envRec be env's EnvironmentRecord.
        // Step 2. Assert: envRec is a declarative Environment Record.
        // (implicit)

        // Step 4. For each element d in declarations, do
        // Step 4.a. For each element dn of the BoundNames of d, do
        for n in &self.let_names {
            // Step 4.a.ii. Else,
            // Step 4.a.ii.1. Perform ! envRec.CreateMutableBinding(dn, false).
            let is_closed_over = self.base.name_tracker.is_closed_over_def(n);
            data.base
                .bindings
                .push(BindingName::new(*n, is_closed_over));
        }
        for n in &self.functions {
            // Step 4.b. If d is a FunctionDeclaration, a GeneratorDeclaration,
            //           an AsyncFunctionDeclaration,
            //           or an AsyncGeneratorDeclaration, then
            // Step 4.b.i. Let fn be the sole element of the BoundNames of d.
            // Step 4.b.ii. Let fo be InstantiateFunctionObject of d with
            //              argument env.
            // Step 4.b.iii. Perform envRec.InitializeBinding(fn, fo).
            let is_closed_over = self.base.name_tracker.is_closed_over_def(&n.name);
            let binding_index = BindingIndex::new(data.base.bindings.len());
            data.base
                .bindings
                .push(BindingName::new(n.name, is_closed_over));

            possibly_annex_b_functions.push(n.name, self.scope_index, binding_index, n.stencil);
        }
        for n in &self.const_names {
            // Step 4.a.i. If IsConstantDeclaration of d is true, then
            // Step 4.a.i.1. Perform ! envRec.CreateImmutableBinding(dn, true).
            let is_closed_over = self.base.name_tracker.is_closed_over_def(n);
            data.base
                .bindings
                .push(BindingName::new(*n, is_closed_over));
        }

        ScopeData::Lexical(data)
    }
}

/// Scope for a FunctionExpression.
///
/// The FunctionExpression `(function f() { return f; })` introduces a lexical
/// scope with a single binding `f`, set to the function itself. We create this
/// scope builder whether the FunctionExpression has a name or not, for
/// consistency.
#[derive(Debug)]
struct FunctionExpressionScopeBuilder {
    base: BaseScopeBuilder,

    function_expression_name: Option<SourceAtomSetIndex>,

    scope_index: ScopeIndex,
}

impl FunctionExpressionScopeBuilder {
    fn new(scope_index: ScopeIndex) -> Self {
        Self {
            base: BaseScopeBuilder::new(),
            function_expression_name: None,
            scope_index,
        }
    }

    fn set_function_name(&mut self, name: SourceAtomSetIndex) {
        self.function_expression_name = Some(name);
        self.base.set_function_name(name);
    }

    fn into_scope_data(self, enclosing: ScopeIndex) -> ScopeData {
        match &self.function_expression_name {
            Some(name) => {
                // Runtime Semantics: Evaluation
                // https://tc39.es/ecma262/#sec-function-definitions-runtime-semantics-evaluation
                //
                // FunctionExpression :
                //   function BindingIdentifier ( FormalParameters )
                //   { FunctionBody }
                //
                // Step 1. Let scope be the running execution context's
                //         LexicalEnvironment.
                // Step 2. Let funcEnv be NewDeclarativeEnvironment(scope).
                // Step 3. Let envRec be funcEnv's EnvironmentRecord.
                let mut data = LexicalScopeData::new_named_lambda(enclosing);

                // Step 4. Let name be StringValue of BindingIdentifier .
                // Step 5. Perform envRec.CreateImmutableBinding(name, false).
                let is_closed_over = self.base.name_tracker.is_closed_over_def(name);
                data.base
                    .bindings
                    .push(BindingName::new(*name, is_closed_over));

                ScopeData::Lexical(data)
            }
            None => ScopeData::Alias(enclosing),
        }
    }
}

/// The value of [[ThisMode]] internal slot of function object.
/// https://tc39.es/ecma262/#sec-ecmascript-function-objects
///
/// Defines how this references are interpreted within the formal parameters
/// and code body of the function.
#[derive(Debug, Clone, PartialEq)]
enum ThisMode {
    /// `this` refers to the `this` value of a lexically enclosing function.
    Lexical,

    /// `this` value is used exactly as provided by an invocation of the
    /// function.
    #[allow(dead_code)]
    Strict,

    /// `this` value of `undefined` is interpreted as a reference to the global
    /// object.
    Global,
}

/// The result of converting the builder of function parameters and body
/// into scope data.
struct FunctionScopeDataSet {
    /// ScopeData::Function.
    function: ScopeData,

    /// Either ScopeData::Var or ScopeData::Alias.
    extra_body_var: ScopeData,

    /// Either ScopeData::Lexical or ScopeData::Alias.
    lexical: ScopeData,
}

/// See FunctionParametersScopeBuilder.state.
#[derive(Debug)]
enum FunctionParametersState {
    /// Entered FormalParameters.
    Init,

    /// Entered Parameter.
    /// At this point, this parameter can be either non-destructuring or
    /// destructuring.
    /// If BindingIdentifier is found in this state, this parameter is
    /// non-destructuring.
    Parameter,

    /// Entered BindingPattern inside Parameter.
    /// This parameter is destructuring.
    DestructuringParameter,

    /// Entered rest parameter.
    /// At this point, the rest parameter can be either non-destructuring or
    /// destructuring.
    /// If BindingIdentifier is found in this state, the rest parameter is
    /// non-destructuring.
    RestParameter,

    /// Entered BindingPattern inside rest parameter.
    /// The rest parameter is destructuring.
    DestructuringRestParameter,
}

/// Function parameters in FormalParameters, and variables used in
/// FormalParameters
/// Shared part between full-parse and syntax-only parse.
#[derive(Debug)]
struct SharedFunctionParametersScopeBuilder {
    base: BaseScopeBuilder,

    /// FunctionDeclarationInstantiation ( func, argumentsList )
    /// https://tc39.es/ecma262/#sec-functiondeclarationinstantiation
    ///
    /// Step 3. Let strict be func.[[Strict]].
    strict: bool,

    /// Step 5. Let parameterNames be the BoundNames of formals.
    parameter_names: HashSet<SourceAtomSetIndex>,

    /// Step 7. Let simpleParameterList be IsSimpleParameterList of formals.
    simple_parameter_list: bool,

    /// Step 8. Let hasParameterExpressions be ContainsExpression of formals.
    has_parameter_expressions: bool,

    /// Step 17. Else if "arguments" is an element of parameterNames, then
    parameter_has_arguments: bool,
}

impl SharedFunctionParametersScopeBuilder {
    fn new(is_arrow: bool) -> Self {
        let mut base = BaseScopeBuilder::new();

        if !is_arrow {
            // Arrow function closes over this/arguments from enclosing
            // function.
            base.name_tracker
                .note_def(CommonSourceAtomSetIndices::this());
            base.name_tracker
                .note_def(CommonSourceAtomSetIndices::arguments());
        }

        Self {
            base,

            // FIMXE: Receive the enclosing strictness,
            //        and update on directive in body.
            strict: false,

            parameter_names: HashSet::new(),
            simple_parameter_list: true,
            has_parameter_expressions: false,
            parameter_has_arguments: false,
        }
    }

    fn perform_annex_b(
        &self,
        function_declaration_properties: &mut FunctionDeclarationPropertyMap,
        possibly_annex_b_functions: &mut PossiblyAnnexBFunctionList,
        body_scope_builder: &mut SharedFunctionBodyScopeBuilder,
    ) {
        // Annex B
        // Changes to FunctionDeclarationInstantiation
        // https://tc39.es/ecma262/#sec-web-compat-functiondeclarationinstantiation
        //
        // Step 1. If strict is false, then
        //
        // FIXME: Once directives are supported, reflect it here.
        let strict = false;
        if strict {
            return;
        }

        // Step 1.a. For each FunctionDeclaration f that is directly contained
        //           in the StatementList of a Block, CaseClause, or
        //           DefaultClause, do
        //
        // NOTE: `possibly_annex_b_functions` contains all of them.

        // Step 1.a.i. Let F be StringValue of the BindingIdentifier of f.
        // Step 1.a.ii. If replacing the FunctionDeclaration f with a
        //              VariableStatement that has F as a BindingIdentifier
        //              would not produce any Early Errors for func and F is
        //              not an element of parameterNames, then
        //
        // NOTE: Early Errors happen if any of top-level lexical has
        //       the same name.  Filter out those functions here.
        for n in &body_scope_builder.let_names {
            possibly_annex_b_functions.remove_if_exists(*n);
        }
        for n in &body_scope_builder.const_names {
            possibly_annex_b_functions.remove_if_exists(*n);
        }
        for n in &self.parameter_names {
            possibly_annex_b_functions.remove_if_exists(*n);
        }

        // Step 1.a.ii.1. NOTE: A var binding for F is only instantiated here
        //                if it is neither a VarDeclaredName, the name of a
        //                formal parameter, or another FunctionDeclaration.
        //
        // NOTE: The binding is merged into the list of other var names.

        // Step 1.a.ii.2. If initializedBindings does not contain F and F is
        //                not "arguments", then
        possibly_annex_b_functions.remove_if_exists(CommonSourceAtomSetIndices::arguments());

        // Step 1.a.ii.2.a. Perform ! varEnv.CreateMutableBinding(F, false).
        // Step 1.a.ii.2.b. Perform varEnv.InitializeBinding(F, undefined).
        // Step 1.a.ii.2.c. Append F to instantiatedVarNames.
        for n in possibly_annex_b_functions.names() {
            body_scope_builder.declare_var(*n);
        }

        // Step 1.a.ii.3. When the FunctionDeclaration f is evaluated, perform
        //                the following steps in place of the
        //                FunctionDeclaration Evaluation algorithm provided in
        //                https://tc39.es/ecma262/#sec-function-definitions-runtime-semantics-evaluation
        // Step 1.a.ii.3.a. Let fenv be the running execution context's
        //                  VariableEnvironment.
        // Step 1.a.ii.3.b. Let benv be the running execution context's
        //                  LexicalEnvironment.
        // Step 1.a.ii.3.c. Let fobj be ! benv.GetBindingValue(F, false).
        // Step 1.a.ii.3.d. Perform ! fenv.SetMutableBinding(F, fobj, false).
        // Step 1.a.ii.3.e. Return NormalCompletion(empty).
        possibly_annex_b_functions.mark_annex_b(function_declaration_properties);
    }

    fn before_binding_pattern(&mut self) {
        // Static Semantics: IsSimpleParameterList
        // https://tc39.es/ecma262/#sec-destructuring-binding-patterns-static-semantics-issimpleparameterlist
        //
        // BindingElement : BindingPattern
        //
        //   1. Return false.
        //
        // BindingElement : BindingPattern Initializer
        //
        //   1. Return false.
        self.simple_parameter_list = false;
    }

    fn before_rest_parameter(&mut self) {
        // Static Semantics: IsSimpleParameterList
        // https://tc39.es/ecma262/#sec-function-definitions-static-semantics-issimpleparameterlist
        //
        // FormalParameters : FunctionRestParameter
        //
        //   1. Return false.
        //
        // FormalParameters : FormalParameterList , FunctionRestParameter
        //
        //   1. Return false.
        self.simple_parameter_list = false;
    }

    fn after_initializer(&mut self) {
        // Static Semantics: IsSimpleParameterList
        // https://tc39.es/ecma262/#sec-destructuring-binding-patterns-static-semantics-issimpleparameterlist
        //
        // BindingElement : BindingPattern Initializer
        //
        //   1. Return false.
        //
        // SingleNameBinding : BindingIdentifier Initializer
        //
        //   1. Return false.
        self.simple_parameter_list = false;

        // FunctionDeclarationInstantiation ( func, argumentsList )
        // https://tc39.es/ecma262/#sec-functiondeclarationinstantiation
        //
        // Step 8. Let hasParameterExpressions be ContainsExpression of formals.

        // Static Semantics: ContainsExpression
        // https://tc39.es/ecma262/#sec-destructuring-binding-patterns-static-semantics-containsexpression
        //
        // BindingElement : BindingPattern Initializer
        //
        //   1. Return true.
        //
        // SingleNameBinding : BindingIdentifier Initializer
        //
        //   1. Return true.
        self.has_parameter_expressions = true;
    }

    fn before_computed_property_name(&mut self) {
        // FunctionDeclarationInstantiation ( func, argumentsList )
        // https://tc39.es/ecma262/#sec-functiondeclarationinstantiation
        //
        // Step 8. Let hasParameterExpressions be ContainsExpression of formals.

        // Static Semantics: ContainsExpression
        // https://tc39.es/ecma262/#sec-destructuring-binding-patterns-static-semantics-containsexpression
        //
        // BindingProperty : PropertyName : BindingElement
        //
        //   1. Let has be IsComputedPropertyKey of PropertyName .
        //   2. If has is true, return true.
        //   3. Return ContainsExpression of BindingElement .
        self.has_parameter_expressions = true;
    }

    fn declare_param(&mut self, name: SourceAtomSetIndex) {
        // Step 17. Else if "arguments" is an element of parameterNames,
        //          then
        if name == CommonSourceAtomSetIndices::arguments() {
            self.parameter_has_arguments = true;
        }

        self.parameter_names.insert(name.clone());
        self.base.declare_param(name);
    }

    fn is_parameter_closed_over(&self) -> bool {
        for name in &self.parameter_names {
            if self.base.name_tracker.is_closed_over_def(name) {
                return true;
            }
        }

        false
    }
}

/// Function parameters in FormalParameters, and variables used in
/// FormalParameters
/// For full-parse.
#[derive(Debug)]
struct FunctionParametersScopeBuilder {
    shared: SharedFunctionParametersScopeBuilder,

    /// State of the analysis.
    /// This is used to determine what kind of binding the parameter is.
    state: FunctionParametersState,

    /// List of positional parameter or None if destructuring.
    /// This includes rest parameter.
    positional_parameter_names: Vec<Option<SourceAtomSetIndex>>,

    /// List of non-positional parameters (destructuring parameters).
    non_positional_parameter_names: Vec<SourceAtomSetIndex>,

    /// FunctionDeclarationInstantiation ( func, argumentsList )
    /// https://tc39.es/ecma262/#sec-functiondeclarationinstantiation
    ///
    /// Step 16. If func.[[ThisMode]] is lexical, then
    this_mode: ThisMode,

    /// Step 6. If parameterNames has any duplicate entries, let hasDuplicates
    ///         be true. Otherwise, let hasDuplicates be false.
    has_duplicates: bool,

    scope_index: ScopeIndex,

    /// Index of the script in the list of `functions` in the
    /// `FunctionScriptStencilBuilder`.
    script_index: ScriptStencilIndex,

    has_direct_eval: bool,

    is_arrow: bool,
}

impl FunctionParametersScopeBuilder {
    fn new(scope_index: ScopeIndex, is_arrow: bool, script_index: ScriptStencilIndex) -> Self {
        Self {
            shared: SharedFunctionParametersScopeBuilder::new(is_arrow),

            state: FunctionParametersState::Init,

            positional_parameter_names: Vec::new(),
            non_positional_parameter_names: Vec::new(),

            // FIXME: Receive correct value.
            this_mode: ThisMode::Global,

            has_duplicates: false,
            scope_index,
            script_index,
            has_direct_eval: false,
            is_arrow,
        }
    }

    fn before_parameter(&mut self) {
        match self.state {
            FunctionParametersState::Init => {
                self.state = FunctionParametersState::Parameter;
            }
            FunctionParametersState::Parameter => {
                self.state = FunctionParametersState::Parameter;
            }
            FunctionParametersState::DestructuringParameter => {
                self.state = FunctionParametersState::Parameter;
            }
            FunctionParametersState::RestParameter
            | FunctionParametersState::DestructuringRestParameter => panic!("Invalid transition"),
        }
    }

    fn before_binding_pattern(&mut self) {
        self.shared.before_binding_pattern();

        match self.state {
            FunctionParametersState::Parameter => {
                self.positional_parameter_names.push(None);
                self.state = FunctionParametersState::DestructuringParameter;
            }
            FunctionParametersState::DestructuringParameter => {}
            FunctionParametersState::RestParameter => {
                self.positional_parameter_names.push(None);
                self.state = FunctionParametersState::DestructuringRestParameter;
            }
            FunctionParametersState::DestructuringRestParameter => {}
            FunctionParametersState::Init => panic!("Invalid transition"),
        }
    }

    fn before_rest_parameter(&mut self) {
        self.shared.before_rest_parameter();

        match self.state {
            FunctionParametersState::Init
            | FunctionParametersState::Parameter
            | FunctionParametersState::DestructuringParameter => {
                self.state = FunctionParametersState::RestParameter;
            }
            FunctionParametersState::RestParameter
            | FunctionParametersState::DestructuringRestParameter => panic!("Invalid transition"),
        }
    }

    fn after_initializer(&mut self) {
        self.shared.after_initializer();
    }

    fn before_computed_property_name(&mut self) {
        self.shared.before_computed_property_name();
    }

    fn declare_param(&mut self, name: SourceAtomSetIndex) {
        // FunctionDeclarationInstantiation ( func, argumentsList )
        // https://tc39.es/ecma262/#sec-functiondeclarationinstantiation
        //
        // Step 5. Let parameterNames be the BoundNames of formals.
        match self.state {
            FunctionParametersState::Init => panic!("Invalid state"),
            FunctionParametersState::Parameter => {
                self.positional_parameter_names.push(Some(name.clone()));
            }
            FunctionParametersState::DestructuringParameter => {
                self.non_positional_parameter_names.push(name.clone());
            }
            FunctionParametersState::RestParameter => {
                self.positional_parameter_names.push(Some(name.clone()));
            }
            FunctionParametersState::DestructuringRestParameter => {
                self.non_positional_parameter_names.push(name.clone());
            }
        }

        // Step 6. If parameterNames has any duplicate entries, let
        //         hasDuplicates be true. Otherwise, let hasDuplicates be
        //         false.
        if self.shared.parameter_names.contains(&name) {
            self.has_duplicates = true;
        }

        self.shared.declare_param(name);
    }

    fn into_scope_data_set(
        self,
        enclosing: ScopeIndex,
        body_scope_builder: FunctionBodyScopeBuilder,
    ) -> FunctionScopeDataSet {
        // FunctionDeclarationInstantiation ( func, argumentsList )
        // https://tc39.es/ecma262/#sec-functiondeclarationinstantiation
        //
        // Step 15. Let argumentsObjectNeeded be true.
        let mut arguments_object_needed = true;

        // Step 16. If func.[[ThisMode]] is lexical, then
        if self.this_mode == ThisMode::Lexical {
            // Step 16.a. NOTE: Arrow functions never have an arguments objects.
            // Step 16.b. Set argumentsObjectNeeded to false.
            arguments_object_needed = false;
        }
        // Step 17. Else if "arguments" is an element of parameterNames,
        //          then
        else if self.shared.parameter_has_arguments {
            // Step 17.a. Set argumentsObjectNeeded to false.
            arguments_object_needed = false;
        }
        // Step 18. Else if hasParameterExpressions is false, then
        else if !self.shared.parameter_has_arguments {
            // Step 18.a. If "arguments" is an element of functionNames or if
            //            "arguments" is
            //            an element of lexicalNames, then
            if body_scope_builder.shared.function_or_lexical_has_arguments {
                // Step 18.a.i. Set argumentsObjectNeeded to false.
                arguments_object_needed = false;
            }
        }

        // NOTE: In SpiderMonkey, single environment can have multiple
        //       binding kind.
        //       It's not necessary to create yet another environment here.
        //
        // Step 19. If strict is true or if hasParameterExpressions is false,
        //          then
        if self.shared.strict || !self.shared.has_parameter_expressions {
            // Step 19.a. NOTE: Only a single lexical environment is needed for
            //            the parameters and top-level vars.
            // Step 19.b. Let env be the LexicalEnvironment of calleeContext.
            // Step 19.c. Let envRec be env's EnvironmentRecord.
        }
        // Step 20. Else,
        else {
            // Step 20.a. NOTE: A separate Environment Record is needed to
            //            ensure that bindings created by direct eval calls in
            //            the formal parameter list are outside the environment
            //            where parameters are declared.
            // Step 20.b. Let calleeEnv be the LexicalEnvironment of
            //            calleeContext.
            // Step 20.c. Let env be NewDeclarativeEnvironment(calleeEnv).
            // Step 20.d. Let envRec be env's EnvironmentRecord.
            // Step 20.e. Assert: The VariableEnvironment of calleeContext is
            //            calleeEnv.
            // Step 20.f. Set the LexicalEnvironment of calleeContext to env.
        }

        let has_extra_body_var_scope = self.shared.has_parameter_expressions;

        // NOTE: Names in `body_scope_builder.var_names` is skipped if
        //       it's `arguments`, at step 27.c.i.
        //       The count here isn't the exact number of var bindings, but
        //       it's fine given FunctionScopeData::new doesn't require the
        //       exact number, but just maximum number.
        let function_max_var_names_count = if has_extra_body_var_scope {
            0
        } else {
            body_scope_builder.shared.var_names.len()
        };

        let mut function_scope_data = FunctionScopeData::new(
            self.shared.has_parameter_expressions,
            self.positional_parameter_names.len(),
            self.non_positional_parameter_names.len(),
            function_max_var_names_count,
            enclosing,
            self.script_index,
            self.is_arrow,
        );

        // FunctionDeclarationInstantiation ( func, argumentsList )
        // https://tc39.es/ecma262/#sec-functiondeclarationinstantiation
        //
        // Step 21. For each String paramName in parameterNames, do
        // Step 21.a. Let alreadyDeclared be envRec.HasBinding(paramName).
        // Step 21.b. NOTE: Early errors ensure that duplicate parameter names
        //            can only occur in non-strict functions that do not have
        //            parameter default values or rest parameters.
        // Step 21.c. If alreadyDeclared is false, then
        // Step 21.c.i. Perform ! envRec.CreateMutableBinding(paramName, false).
        // Step 21.c.ii. If hasDuplicates is true, then
        // Step 21.c.ii.1. Perform
        //                 ! envRec.InitializeBinding(paramName, undefined).
        //
        // NOTE: The existence of duplication isn't encoded in scope data.
        for maybe_name in &self.positional_parameter_names {
            match maybe_name {
                Some(n) => {
                    let is_closed_over = self.shared.base.name_tracker.is_closed_over_def(n)
                        || (!has_extra_body_var_scope
                            && body_scope_builder
                                .shared
                                .base
                                .name_tracker
                                .is_closed_over_def(n));
                    function_scope_data
                        .base
                        .bindings
                        .push(Some(BindingName::new(*n, is_closed_over)))
                }
                None => function_scope_data.base.bindings.push(None),
            }
        }
        for n in &self.non_positional_parameter_names {
            let is_closed_over = self.shared.base.name_tracker.is_closed_over_def(n)
                || (!has_extra_body_var_scope
                    && body_scope_builder
                        .shared
                        .base
                        .name_tracker
                        .is_closed_over_def(n));
            function_scope_data
                .base
                .bindings
                .push(Some(BindingName::new(*n, is_closed_over)))
        }

        // Step 22. If argumentsObjectNeeded is true, then
        // Steps 22.a-b. Create{Unm,M}appedArgumentsObject
        // (done in emitter)

        // Step 22.c. If strict is true, then
        // Step 22.c.i. Perform
        //              ! envRec.CreateImmutableBinding("arguments", false).
        // Step 22.d. Else,
        // Step 22.d.i. Perform
        //              ! envRec.CreateMutableBinding("arguments", false).
        // Step 22.e. Call envRec.InitializeBinding("arguments", ao).
        //
        // NOTE: In SpiderMonkey, whether immutable or not is not stored
        //       in scope data, but checked while parsing, including
        //       when parsing eval inside function.

        // Step 22.f. Let parameterBindings be a new List of parameterNames
        //            with "arguments" appended.
        //
        // NOTE: Done in each consumer of parameterNames.

        // Step 23. Else,
        // Step 23.a. Let parameterBindings be parameterNames.
        //
        // NOTE: Done in each consumer of parameterNames.

        // Steps 24-26. IteratorBindingInitialization
        // (done in emitter)

        // Step 27. If hasParameterExpressions is false, then
        let extra_body_var_scope_data = if !self.shared.has_parameter_expressions {
            debug_assert!(!has_extra_body_var_scope);

            // Step 27.a. NOTE: Only a single lexical environment is needed for
            //            the parameters and top-level vars.

            // Step 27.b. Let instantiatedVarNames be a copy of the List
            //            parameterBindings.

            // Step 27.c. For each n in varNames, do
            for n in &body_scope_builder.shared.var_names {
                // Step 27.c.i. If n is not an element of instantiatedVarNames,
                //              then
                // Step 27.c.i.1. Append n to instantiatedVarNames.
                //
                // NOTE: var_names is already unique.
                //       Check against parameters and `arguments` here.
                if self.shared.parameter_names.contains(n)
                    || (arguments_object_needed && *n == CommonSourceAtomSetIndices::arguments())
                {
                    continue;
                }

                // Step 27.c.i.2. Perform
                //                ! envRec.CreateMutableBinding(n, false).
                let is_closed_over = body_scope_builder
                    .shared
                    .base
                    .name_tracker
                    .is_closed_over_def(n);
                function_scope_data
                    .base
                    .bindings
                    .push(Some(BindingName::new(*n, is_closed_over)));

                // Step 27.c.i.3. Call envRec.InitializeBinding(n, undefined).
                // (done in runtime)
            }

            // Step 27.d. Let varEnv be env.
            // Step 27.e. Let varEnvRec be envRec.
            ScopeData::Alias(self.scope_index)
        }
        // Step 28. Else,
        else {
            debug_assert!(has_extra_body_var_scope);

            // In non-strict mode code, direct `eval` can extend function's
            // scope.
            let function_has_extensible_scope = !self.shared.strict && self.has_direct_eval;

            // Step 28.a. NOTE: A separate Environment Record is needed to
            //            ensure that closures created by expressions in the
            //            formal parameter list do not have visibility of
            //            declarations in the function body.

            // Step 28.b. Let varEnv be NewDeclarativeEnvironment(env).
            // Step 28.c. Set the VariableEnvironment of calleeContext to
            //            varEnv.
            let mut data = VarScopeData::new(
                body_scope_builder.shared.var_names.len(),
                function_has_extensible_scope,
                /* encloding= */ self.scope_index,
            );

            // Step 28.d. Let instantiatedVarNames be a new empty List.

            // Step 28.e. For each n in varNames, do
            for n in &body_scope_builder.shared.var_names {
                // Step 28.e.i. If n is not an element of instantiatedVarNames, then
                // Step 28.e.i.1. Append n to instantiatedVarNames.
                //
                // NOTE: var_names is already unique.

                // Step 28.e.i.2. Perform
                //                ! varEnv.CreateMutableBinding(n, false).
                let is_closed_over = body_scope_builder
                    .shared
                    .base
                    .name_tracker
                    .is_closed_over_def(n);
                data.base
                    .bindings
                    .push(BindingName::new(*n, is_closed_over));

                // Step 28.e.i.3. If n is not an element of parameterBindings or if
                //                n is an element of functionNames, let
                //                initialValue be undefined.
                // Step 28.e.i.4. Else,
                // Step 28.e.i.4.a. Let initialValue be
                //                  ! env.GetBindingValue(n, false).
                // Step 28.e.i.5. Call varEnv.InitializeBinding(n, initialValue).
                // (done in emitter)

                // Step 28.e.i.6. NOTE: A var with the same name as a formal
                //                parameter initially has the same value as the
                //                corresponding initialized parameter.
            }

            ScopeData::Var(data)
        };

        // Step 30. If strict is false, then
        // Step 30.a. Let lexEnv be NewDeclarativeEnvironment(varEnv).
        // Step 30.b. NOTE: Non-strict functions use a separate lexical
        //            Environment Record for top-level lexical declarations so
        //            that a direct eval can determine whether any var scoped
        //            declarations introduced by the eval code conflict with
        //            pre-existing top-level lexically scoped declarations.
        //            This is not needed for strict functions because a strict
        //            direct eval always places all declarations into a new
        //            Environment Record.
        // Step 31. Else, let lexEnv be varEnv.
        // Step 32. Let lexEnvRec be lexEnv's EnvironmentRecord.
        //
        // NOTE: SpiderMonkey creates lexical env whenever lexical binding
        //       exists.

        let lexical_scope_data = if body_scope_builder.shared.let_names.len() > 0
            || body_scope_builder.shared.const_names.len() > 0
        {
            let mut data = LexicalScopeData::new_function_lexical(
                body_scope_builder.shared.let_names.len(),
                body_scope_builder.shared.const_names.len(),
                /* encloding= */ body_scope_builder.var_scope_index,
            );

            // Step 33. Set the LexicalEnvironment of calleeContext to lexEnv.
--> --------------------

--> maximum size reached

--> --------------------

[ zur Elbe Produktseite wechseln0.56Quellennavigators  Analyse erneut starten  ]

                                                                                                                                                                                                                                                                                                                                                                                                     


Neuigkeiten

     Aktuelles
     Motto des Tages

Software

     Produkte
     Quellcodebibliothek

Aktivitäten

     Artikel über Sicherheit
     Anleitung zur Aktivierung von SSL

Muße

     Gedichte
     Musik
     Bilder

Jenseits des Üblichen ....

Besucherstatistik

Besucherstatistik

Monitoring

Montastic status badge