summaryrefslogtreecommitdiffstats
path: root/third_party/rust/jsparagus-generated-parser/src/early_errors.rs
diff options
context:
space:
mode:
Diffstat (limited to 'third_party/rust/jsparagus-generated-parser/src/early_errors.rs')
-rw-r--r--third_party/rust/jsparagus-generated-parser/src/early_errors.rs2358
1 files changed, 2358 insertions, 0 deletions
diff --git a/third_party/rust/jsparagus-generated-parser/src/early_errors.rs b/third_party/rust/jsparagus-generated-parser/src/early_errors.rs
new file mode 100644
index 0000000000..a9d1fb891c
--- /dev/null
+++ b/third_party/rust/jsparagus-generated-parser/src/early_errors.rs
@@ -0,0 +1,2358 @@
+use crate::context_stack::{ControlInfo, ControlKind, LabelKind};
+use crate::parser_tables_generated::TerminalId;
+use crate::DeclarationKind;
+use crate::Token;
+use crate::{ParseError, Result};
+use ast::arena;
+use ast::source_atom_set::{CommonSourceAtomSetIndices, SourceAtomSet, SourceAtomSetIndex};
+use std::collections::HashMap;
+
+#[derive(Clone, Copy, Debug, PartialEq)]
+struct DeclarationInfo {
+ kind: DeclarationKind,
+ offset: usize,
+}
+
+impl DeclarationInfo {
+ fn new(kind: DeclarationKind, offset: usize) -> Self {
+ Self { kind, offset }
+ }
+}
+
+pub type EarlyErrorsResult<'alloc> = Result<'alloc, ()>;
+
+pub trait LexicalEarlyErrorsContext {
+ fn declare_lex<'alloc>(
+ &mut self,
+ name: SourceAtomSetIndex,
+ kind: DeclarationKind,
+ offset: usize,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc>;
+}
+
+pub trait VarEarlyErrorsContext {
+ fn declare_var<'alloc>(
+ &mut self,
+ name: SourceAtomSetIndex,
+ kind: DeclarationKind,
+ offset: usize,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc>;
+}
+
+pub trait ParameterEarlyErrorsContext {
+ fn declare<'alloc>(
+ &mut self,
+ name: SourceAtomSetIndex,
+ offset: usize,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc>;
+}
+
+pub trait ControlEarlyErrorsContext {
+ fn on_unhandled_break_or_continue<'alloc>(
+ &self,
+ info: &ControlInfo,
+ ) -> EarlyErrorsResult<'alloc>;
+}
+
+// ===========================================================================
+// Identifiers
+// https://tc39.es/ecma262/#sec-identifiers
+// ===========================================================================
+
+#[derive(Debug, PartialEq)]
+pub struct IdentifierEarlyErrorsContext {}
+
+impl IdentifierEarlyErrorsContext {
+ pub fn new() -> Self {
+ Self {}
+ }
+
+ fn is_strict<'alloc>(&self) -> Result<'alloc, bool> {
+ Err(ParseError::NotImplemented("strict-mode-only early error is not yet supported").into())
+ }
+
+ // Not used due to NotImplemented before the callsite.
+ /*
+ fn is_module(&self) -> Result<bool, ParseError<'alloc>> {
+ Err(ParseError::NotImplemented(
+ "module-only early error is not yet supported",
+ ))
+ }
+ */
+
+ fn is_arguments_identifier<'alloc>(token: &arena::Box<'alloc, Token>) -> bool {
+ return (token.terminal_id == TerminalId::Name
+ || token.terminal_id == TerminalId::NameWithEscape)
+ && token.value.as_atom() == CommonSourceAtomSetIndices::arguments();
+ }
+
+ fn is_eval_identifier<'alloc>(token: &arena::Box<'alloc, Token>) -> bool {
+ return (token.terminal_id == TerminalId::Name
+ || token.terminal_id == TerminalId::NameWithEscape)
+ && token.value.as_atom() == CommonSourceAtomSetIndices::eval();
+ }
+
+ fn is_yield_identifier<'alloc>(token: &arena::Box<'alloc, Token>) -> bool {
+ return token.terminal_id == TerminalId::Yield
+ || (token.terminal_id == TerminalId::NameWithEscape
+ && token.value.as_atom() == CommonSourceAtomSetIndices::yield_());
+ }
+
+ fn is_await_identifier<'alloc>(token: &arena::Box<'alloc, Token>) -> bool {
+ return token.terminal_id == TerminalId::Await
+ || (token.terminal_id == TerminalId::NameWithEscape
+ && token.value.as_atom() == CommonSourceAtomSetIndices::await_());
+ }
+
+ pub fn check_binding_identifier<'alloc>(
+ &self,
+ token: &arena::Box<'alloc, Token>,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ if Self::is_arguments_identifier(token) || Self::is_eval_identifier(token) {
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-identifiers-static-semantics-early-errors
+ //
+ // BindingIdentifier : Identifier
+ //
+ // * It is a Syntax Error if the code matched by this
+ // production is contained in strict mode code and the
+ // StringValue of Identifier is "arguments" or "eval".
+ if self.is_strict()? {
+ let name = atoms.get(token.value.as_atom());
+ let offset = token.loc.start;
+ return Err(ParseError::InvalidIdentifier(name.clone(), offset).into());
+ }
+
+ return Ok(());
+ }
+
+ if Self::is_yield_identifier(token) {
+ // BindingIdentifier : yield
+ //
+ // * It is a Syntax Error if this production has a [Yield]
+ // parameter.
+ return Err(ParseError::NotImplemented("[Yield] parameter").into());
+
+ // return self.check_yield_common();
+ }
+
+ if Self::is_await_identifier(token) {
+ // BindingIdentifier : await
+ //
+ // * It is a Syntax Error if this production has an [Await]
+ // parameter.
+ return Err(ParseError::NotImplemented("[Await] parameter").into());
+
+ // return self.check_await_common();
+ }
+
+ self.check_identifier(token, atoms)
+ }
+
+ pub fn check_label_identifier<'alloc>(
+ &self,
+ token: &arena::Box<'alloc, Token>,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ if Self::is_yield_identifier(token) {
+ return self.check_yield_common(token, atoms);
+ }
+
+ if Self::is_await_identifier(token) {
+ return self.check_await_common(token, atoms);
+ }
+
+ self.check_identifier(token, atoms)
+ }
+
+ pub fn check_identifier_reference<'alloc>(
+ &self,
+ token: &arena::Box<'alloc, Token>,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ if Self::is_yield_identifier(token) {
+ return self.check_yield_common(token, atoms);
+ }
+
+ if Self::is_await_identifier(token) {
+ return self.check_await_common(token, atoms);
+ }
+
+ self.check_identifier(token, atoms)
+ }
+
+ fn check_yield_common<'alloc>(
+ &self,
+ _token: &arena::Box<'alloc, Token>,
+ _atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-identifiers-static-semantics-early-errors
+ //
+ // IdentifierReference[Yield, Await] : Identifier
+ //
+ // BindingIdentifier[Yield, Await] : Identifier
+ //
+ // LabelIdentifier[Yield, Await] : Identifier
+ //
+ // * It is a Syntax Error if this production has a [Yield] parameter
+ // and StringValue of Identifier is "yield".
+ return Err(ParseError::NotImplemented("[Yield] parameter").into());
+
+ // IdentifierReference : yield
+ //
+ // BindingIdentifier : yield
+ //
+ // LabelIdentifier : yield
+ //
+ // * It is a Syntax Error if the code matched by this production is
+ // contained in strict mode code.
+ //
+ // and
+ //
+ // Identifier : IdentifierName but not ReservedWord
+ //
+ // * It is a Syntax Error if this phrase is contained in strict mode
+ // code and the StringValue of IdentifierName is: "implements",
+ // "interface", "let", "package", "private", "protected", "public",
+ // "static", or "yield".
+ //
+ // if self.is_strict()? {
+ // return Err(ParseError::InvalidIdentifier(
+ // atoms.get(token.value.as_atom()),
+ // offset,
+ // ));
+ // }
+ //
+ // Ok(())
+ }
+
+ fn check_await_common<'alloc>(
+ &self,
+ _token: &arena::Box<'alloc, Token>,
+ _atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-identifiers-static-semantics-early-errors
+ //
+ // IdentifierReference[Yield, Await] : Identifier
+ //
+ // BindingIdentifier[Yield, Await] : Identifier
+ //
+ // LabelIdentifier[Yield, Await] : Identifier
+ //
+ // * It is a Syntax Error if this production has an [Await] parameter
+ // and StringValue of Identifier is "await".
+ return Err(ParseError::NotImplemented("[Await] parameter").into());
+
+ // IdentifierReference : await
+ //
+ // BindingIdentifier : await
+ //
+ // LabelIdentifier : await
+ //
+ // * It is a Syntax Error if the goal symbol of the syntactic
+ // grammar is Module.
+ //
+ // and
+ //
+ // Identifier : IdentifierName but not ReservedWord
+ //
+ // * It is a Syntax Error if the goal symbol of the syntactic grammar
+ // is Module and the StringValue of IdentifierName is "await".
+ //
+ // if self.is_module()? {
+ // return Err(ParseError::InvalidIdentifier(
+ // atoms.get(token.value.as_atom()),
+ // offset,
+ // ));
+ // }
+ //
+ // Ok(())
+ }
+
+ fn is_contextual_keyword_excluding_yield(name: SourceAtomSetIndex) -> bool {
+ name == CommonSourceAtomSetIndices::implements()
+ || name == CommonSourceAtomSetIndices::interface()
+ || name == CommonSourceAtomSetIndices::let_()
+ || name == CommonSourceAtomSetIndices::package()
+ || name == CommonSourceAtomSetIndices::private()
+ || name == CommonSourceAtomSetIndices::protected()
+ || name == CommonSourceAtomSetIndices::public()
+ || name == CommonSourceAtomSetIndices::static_()
+ }
+
+ fn is_keyword(name: SourceAtomSetIndex) -> bool {
+ name == CommonSourceAtomSetIndices::break_()
+ || name == CommonSourceAtomSetIndices::case()
+ || name == CommonSourceAtomSetIndices::catch()
+ || name == CommonSourceAtomSetIndices::class()
+ || name == CommonSourceAtomSetIndices::const_()
+ || name == CommonSourceAtomSetIndices::continue_()
+ || name == CommonSourceAtomSetIndices::debugger()
+ || name == CommonSourceAtomSetIndices::default()
+ || name == CommonSourceAtomSetIndices::delete()
+ || name == CommonSourceAtomSetIndices::do_()
+ || name == CommonSourceAtomSetIndices::else_()
+ || name == CommonSourceAtomSetIndices::enum_()
+ || name == CommonSourceAtomSetIndices::export()
+ || name == CommonSourceAtomSetIndices::extends()
+ || name == CommonSourceAtomSetIndices::false_()
+ || name == CommonSourceAtomSetIndices::finally()
+ || name == CommonSourceAtomSetIndices::for_()
+ || name == CommonSourceAtomSetIndices::function()
+ || name == CommonSourceAtomSetIndices::if_()
+ || name == CommonSourceAtomSetIndices::import()
+ || name == CommonSourceAtomSetIndices::in_()
+ || name == CommonSourceAtomSetIndices::instanceof()
+ || name == CommonSourceAtomSetIndices::new_()
+ || name == CommonSourceAtomSetIndices::null()
+ || name == CommonSourceAtomSetIndices::return_()
+ || name == CommonSourceAtomSetIndices::super_()
+ || name == CommonSourceAtomSetIndices::switch()
+ || name == CommonSourceAtomSetIndices::this()
+ || name == CommonSourceAtomSetIndices::throw()
+ || name == CommonSourceAtomSetIndices::true_()
+ || name == CommonSourceAtomSetIndices::try_()
+ || name == CommonSourceAtomSetIndices::typeof_()
+ || name == CommonSourceAtomSetIndices::var()
+ || name == CommonSourceAtomSetIndices::void()
+ || name == CommonSourceAtomSetIndices::while_()
+ || name == CommonSourceAtomSetIndices::with()
+ }
+
+ fn check_identifier<'alloc>(
+ &self,
+ token: &arena::Box<'alloc, Token>,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ match token.terminal_id {
+ TerminalId::NameWithEscape => {
+ let name = token.value.as_atom();
+ if Self::is_contextual_keyword_excluding_yield(name) {
+ // Identifier : IdentifierName but not ReservedWord
+ //
+ // * It is a Syntax Error if this phrase is contained
+ // in strict mode code and the StringValue of
+ // IdentifierName is:
+ // "implements", "interface", "let", "package",
+ // "private", "protected", "public", "static",
+ // or "yield".
+ //
+ // NOTE: "yield" case is handled in
+ // `check_yield_common`.
+ if self.is_strict()? {
+ let name = atoms.get(token.value.as_atom());
+ let offset = token.loc.start;
+ return Err(ParseError::InvalidIdentifier(name, offset).into());
+ }
+ } else if Self::is_keyword(name) {
+ // Identifier : IdentifierName but not ReservedWord
+ //
+ // * It is a Syntax Error if StringValue of
+ // IdentifierName is the same String value as the
+ // StringValue of any ReservedWord except for yield
+ // or await.
+ let name = atoms.get(token.value.as_atom());
+ let offset = token.loc.start;
+ return Err(ParseError::InvalidIdentifier(name, offset).into());
+ }
+ }
+ TerminalId::Implements
+ | TerminalId::Interface
+ | TerminalId::Let
+ | TerminalId::Package
+ | TerminalId::Private
+ | TerminalId::Protected
+ | TerminalId::Public
+ | TerminalId::Static => {
+ // Identifier : IdentifierName but not ReservedWord
+ //
+ // * It is a Syntax Error if this phrase is contained in strict
+ // mode code and the StringValue of IdentifierName is:
+ // "implements", "interface", "let", "package", "private",
+ // "protected", "public", "static", or "yield".
+ //
+ // NOTE: "yield" case is handled in `check_yield_common`.
+ if self.is_strict()? {
+ let name = atoms.get(token.value.as_atom());
+ let offset = token.loc.start;
+ return Err(ParseError::InvalidIdentifier(name, offset).into());
+ }
+ }
+ _ => {}
+ }
+
+ Ok(())
+ }
+}
+
+// ===========================================================================
+// Block
+// https://tc39.es/ecma262/#sec-block
+// ===========================================================================
+
+#[derive(Debug, PartialEq)]
+pub struct BlockEarlyErrorsContext {
+ lex_names_of_stmt_list: HashMap<SourceAtomSetIndex, DeclarationInfo>,
+ var_names_of_stmt_list: HashMap<SourceAtomSetIndex, DeclarationInfo>,
+}
+
+impl BlockEarlyErrorsContext {
+ pub fn new() -> Self {
+ Self {
+ lex_names_of_stmt_list: HashMap::new(),
+ var_names_of_stmt_list: HashMap::new(),
+ }
+ }
+
+ fn is_supported_lexical(kind: DeclarationKind) -> bool {
+ match kind {
+ // LexicallyDeclaredNames of StatementList
+ //
+ // Static Semantics: LexicallyDeclaredNames
+ // https://tc39.es/ecma262/#sec-block-static-semantics-lexicallydeclarednames
+ //
+ // StatementList => StatementListItem => Declaration
+ // 1. Return the BoundNames of Declaration.
+ // Declaration => HoistableDeclaration => FunctionDeclaration
+ // 1. Return the BoundNames of BindingIdentifier.
+ // 1. Return « "*default*" ».
+ //
+ // and
+ //
+ // StatementList => StatementListItem => Statement
+ // 1. If Statement is Statement: LabelledStatement, return
+ // LexicallyDeclaredNames of LabelledStatement.
+ // 2. Return a new empty List.
+ // LabelledStatement => LabelledItem => FunctionDeclaration
+ // 1. Return BoundNames of FunctionDeclaration.
+ // FunctionDeclaration
+ // 1. Return the BoundNames of BindingIdentifier.
+ // 1. Return « "*default*" ».
+ //
+ // NOTE: This is separated from LexicalAsyncOrGenerator to support
+ // https://tc39.es/ecma262/#sec-block-duplicates-allowed-static-semantics
+ DeclarationKind::LexicalFunction |
+
+ // StatementList => StatementListItem => Declaration
+ // 1. Return the BoundNames of Declaration.
+ // Declaration => HoistableDeclaration => FunctionDeclaration
+ // Declaration => HoistableDeclaration => GeneratorDeclaration
+ // Declaration => HoistableDeclaration => AsyncFunctionDeclaration
+ // Declaration => HoistableDeclaration => AsyncGeneratorDeclaration
+ // 1. Return the BoundNames of BindingIdentifier.
+ // 1. Return « "*default*" ».
+ DeclarationKind::LexicalAsyncOrGenerator |
+
+ // StatementList => StatementListItem => Declaration
+ // 1. Return the BoundNames of Declaration.
+ // Declaration => ClassDeclaration
+ // 1. Return the BoundNames of BindingIdentifier.
+ // 1. Return « "*default*" ».
+ DeclarationKind::Class |
+
+ // StatementList => StatementListItem => Declaration
+ // 1. Return the BoundNames of Declaration.
+ // Declaration => LexicalDeclaration => BindingList
+ // => LexicalBinding
+ // 1. Return the BoundNames of BindingIdentifier.
+ // 1. Return the BoundNames of BindingPattern.
+ DeclarationKind::Let |
+ DeclarationKind::Const => true,
+ _ => false,
+ }
+ }
+
+ fn is_supported_var(kind: DeclarationKind) -> bool {
+ match kind {
+ // VarDeclaredNames of StatementList
+ //
+ // Static Semantics: VarDeclaredNames
+ // https://tc39.es/ecma262/#sec-block-static-semantics-vardeclarednames
+ //
+ // StatementList => StatementListItem => Statement
+ // => VariableStatement
+ // 1. Return BoundNames of VariableDeclarationList.
+ // VariableDeclarationList => VariableDeclaration
+ // 1. Return the BoundNames of BindingIdentifier.
+ // 1. Return the BoundNames of BindingPattern.
+ //
+ // and
+ //
+ // StatementList => StatementListItem => Statement
+ // => BreakableStatement => IterationStatement => c-style-for-var
+ // 1. Let names be BoundNames of VariableDeclarationList.
+ // 2. Append to names the elements of the VarDeclaredNames of
+ // Statement.
+ // 3. Return names.
+ // VariableDeclarationList => VariableDeclaration
+ // 1. Return the BoundNames of BindingIdentifier.
+ // 1. Return the BoundNames of BindingPattern.
+ //
+ // and
+ //
+ // StatementList => StatementListItem => Statement
+ // => BreakableStatement => IterationStatement => for-in-var
+ // 1. Let names be the BoundNames of ForBinding.
+ // 2. Append to names the elements of the VarDeclaredNames of
+ // Statement.
+ // 3. Return names.
+ // ForBinding => BindingIdentifier
+ // ForBinding => BindingPattern
+ DeclarationKind::Var |
+
+ // StatementList => StatementListItem => Statement => BlockStatement
+ // => Block
+
+ // StatementList => StatementListItem => Statement => IfStatement
+ // => Statement
+
+ // StatementList => StatementListItem => Statement
+ // => BreakableStatement => IterationStatement => do-while
+ // => Statement
+
+ // StatementList => StatementListItem => Statement
+ // => BreakableStatement => IterationStatement => while => Statement
+
+ // StatementList => StatementListItem => Statement
+ // => BreakableStatement => IterationStatement => c-style-for
+ // => Statement
+
+ // StatementList => StatementListItem => Statement
+ // => BreakableStatement => IterationStatement => for-in
+ // => Statement
+
+ // StatementList => StatementListItem => Statement
+ // => BreakableStatement => SwitchStatement => CaseBlock
+ // => CaseClauses => StatementList
+
+ // StatementList => StatementListItem => Statement
+ // => BreakableStatement => SwitchStatement => CaseBlock
+ // => DefaultClause => StatementList
+
+ // StatementList => StatementListItem => Statement => WithStatement
+ // => Statement
+
+ // StatementList => StatementListItem => Statement
+ // => LabelledStatement => LabelledItem => Statement
+
+ // StatementList => StatementListItem => Statement
+ // => LabelledStatement => LabelledItem => FunctionDeclaration
+ // 1. Return a new empty List.
+
+ // StatementList => StatementListItem => Statement => TryStatement
+ // => Block
+ // StatementList => StatementListItem => Statement => TryStatement
+ // => Catch => Block
+ // StatementList => StatementListItem => Statement => TryStatement
+ // => Finally => Block
+
+ // StatementList => StatementListItem => Declaration
+ // 1. Return a new empty List.
+
+ // StatementList => StatementListItem => Declaration
+ // => HoistableDeclaration => FunctionDeclaration
+ //
+ // Changes to FunctionDeclarationInstantiation
+ // https://tc39.es/ecma262/#sec-web-compat-functiondeclarationinstantiation
+ //
+ // During FunctionDeclarationInstantiation the following steps are
+ // performed in place of step 29:
+ //
+ // 1. If strict is false, then
+ // a. For each FunctionDeclaration f that is directly contained
+ // in the StatementList of a Block, CaseClause, or
+ // DefaultClause, do
+ // i. Let F be StringValue of the BindingIdentifier of f.
+ // 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
+ //
+ // and
+ //
+ // Changes to GlobalDeclarationInstantiation
+ // https://tc39.es/ecma262/#sec-web-compat-globaldeclarationinstantiation
+ //
+ // During GlobalDeclarationInstantiation the following steps are
+ // performed in place of step 14:
+ //
+ // 1. Let strict be IsStrict of script.
+ // 2. If strict is false, then
+ // d. For each FunctionDeclaration f that is directly contained
+ // in the StatementList of a Block , CaseClause , or
+ // DefaultClause Contained within script, do
+ // i. Let F be StringValue of the BindingIdentifier of f.
+ // ii. If replacing the FunctionDeclaration f with a
+ // VariableStatement that has F as a BindingIdentifier
+ // would not produce any Early Errors for script, then
+ //
+ // This isn't used while checking actual Early Errors.
+ DeclarationKind::VarForAnnexBLexicalFunction => true,
+ _ => false,
+ }
+ }
+
+ fn is_strict<'alloc>(&self) -> Result<'alloc, bool> {
+ Err(ParseError::NotImplemented("strict-mode-only early error is not yet supported").into())
+ }
+}
+
+impl LexicalEarlyErrorsContext for BlockEarlyErrorsContext {
+ fn declare_lex<'alloc>(
+ &mut self,
+ name: SourceAtomSetIndex,
+ kind: DeclarationKind,
+ offset: usize,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ debug_assert!(Self::is_supported_lexical(kind));
+
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-block-static-semantics-early-errors
+ //
+ // Block : { StatementList }
+ //
+ // * It is a Syntax Error if the LexicallyDeclaredNames of StatementList
+ // contains any duplicate entries.
+ //
+ if let Some(info) = self.lex_names_of_stmt_list.get(&name) {
+ // Changes to Block Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-block-duplicates-allowed-static-semantics
+ //
+ // Block : { StatementList }
+ //
+ // * It is a Syntax Error if the LexicallyDeclaredNames of
+ // StatementList contains any duplicate entries, ** unless the
+ // source code matching this production is not strict mode
+ // code and the duplicate entries are only bound by
+ // FunctionDeclarations **.
+ if !(!self.is_strict()?
+ && info.kind == DeclarationKind::LexicalFunction
+ && kind == DeclarationKind::LexicalFunction)
+ {
+ let name = atoms.get(name);
+ return Err(ParseError::DuplicateBinding(
+ name,
+ info.kind,
+ info.offset,
+ kind,
+ offset,
+ )
+ .into());
+ }
+ }
+
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-block-static-semantics-early-errors
+ //
+ // Block : { StatementList }
+ //
+ // * It is a Syntax Error if any element of the LexicallyDeclaredNames
+ // of StatementList also occurs in the VarDeclaredNames of
+ // StatementList.
+ if let Some(info) = self.var_names_of_stmt_list.get(&name) {
+ let name = atoms.get(name);
+ return Err(
+ ParseError::DuplicateBinding(name, info.kind, info.offset, kind, offset).into(),
+ );
+ }
+
+ self.lex_names_of_stmt_list
+ .insert(name, DeclarationInfo::new(kind, offset));
+
+ Ok(())
+ }
+}
+
+impl VarEarlyErrorsContext for BlockEarlyErrorsContext {
+ fn declare_var<'alloc>(
+ &mut self,
+ name: SourceAtomSetIndex,
+ kind: DeclarationKind,
+ offset: usize,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ debug_assert!(Self::is_supported_var(kind));
+
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-block-static-semantics-early-errors
+ //
+ // Block : { StatementList }
+ //
+ // * It is a Syntax Error if any element of the LexicallyDeclaredNames
+ // of StatementList also occurs in the VarDeclaredNames of
+ // StatementList.
+ if let Some(info) = self.lex_names_of_stmt_list.get(&name) {
+ let name = atoms.get(name);
+ return Err(
+ ParseError::DuplicateBinding(name, info.kind, info.offset, kind, offset).into(),
+ );
+ }
+
+ self.var_names_of_stmt_list
+ .insert(name, DeclarationInfo::new(kind, offset));
+
+ Ok(())
+ }
+}
+
+// ===========================================================================
+// The for Statement
+// https://tc39.es/ecma262/#sec-for-statement
+//
+// The for-in, for-of, and for-await-of Statements
+// https://tc39.es/ecma262/#sec-for-in-and-for-of-statements
+// ===========================================================================
+
+#[derive(Debug, PartialEq)]
+pub struct LexicalForHeadEarlyErrorsContext {
+ bound_names_of_decl: HashMap<SourceAtomSetIndex, DeclarationInfo>,
+}
+
+impl LexicalForHeadEarlyErrorsContext {
+ pub fn new() -> Self {
+ Self {
+ bound_names_of_decl: HashMap::new(),
+ }
+ }
+
+ fn is_supported_lexical(kind: DeclarationKind) -> bool {
+ match kind {
+ // BoundNames of BindingList
+ //
+ // Static Semantics: BoundNames
+ // https://tc39.es/ecma262/#sec-let-and-const-declarations-static-semantics-boundnames
+ //
+ // BindingList => LexicalBinding
+ // 1. Return the BoundNames of BindingIdentifier.
+ // 1. Return the BoundNames of BindingPattern.
+ //
+ // and
+ //
+ // BoundNames of ForDeclaration
+ //
+ // Static Semantics: BoundNames
+ // https://tc39.es/ecma262/#sec-let-and-const-declarations-static-semantics-boundnames
+ //
+ // ForDeclaration => BindingList => LexicalBinding
+ // 1. Return the BoundNames of BindingIdentifier.
+ // 1. Return the BoundNames of BindingPattern.
+ DeclarationKind::Let | DeclarationKind::Const => true,
+ _ => false,
+ }
+ }
+}
+
+impl LexicalEarlyErrorsContext for LexicalForHeadEarlyErrorsContext {
+ fn declare_lex<'alloc>(
+ &mut self,
+ name: SourceAtomSetIndex,
+ kind: DeclarationKind,
+ offset: usize,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ debug_assert!(Self::is_supported_lexical(kind));
+
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-semantics-static-semantics-early-errors
+ //
+ // IterationStatement :
+ // for ( LexicalDeclaration Expression_opt ; Expression_opt )
+ // Statement
+ //
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-let-and-const-declarations-static-semantics-early-errors
+ //
+ // LexicalDeclaration : LetOrConst BindingList ;
+ //
+ // * It is a Syntax Error if the BoundNames of BindingList contains any
+ // duplicate entries.
+ //
+ // and
+ //
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-for-in-and-for-of-statements-static-semantics-early-errors
+ //
+ // IterationStatement :
+ // for ( ForDeclaration in Expression ) Statement
+ // for ( ForDeclaration of AssignmentExpression ) Statement
+ // for await ( ForDeclaration of AssignmentExpression ) Statement
+ //
+ // * It is a Syntax Error if the BoundNames of ForDeclaration contains
+ // any duplicate entries.
+ if let Some(info) = self.bound_names_of_decl.get(&name) {
+ let name = atoms.get(name);
+ return Err(
+ ParseError::DuplicateBinding(name, info.kind, info.offset, kind, offset).into(),
+ );
+ }
+
+ self.bound_names_of_decl
+ .insert(name, DeclarationInfo::new(kind, offset));
+
+ Ok(())
+ }
+}
+
+#[derive(Debug, PartialEq)]
+struct InternalForBodyEarlyErrorsContext {
+ var_names_of_stmt: HashMap<SourceAtomSetIndex, DeclarationInfo>,
+}
+
+impl InternalForBodyEarlyErrorsContext {
+ fn new() -> Self {
+ Self {
+ var_names_of_stmt: HashMap::new(),
+ }
+ }
+
+ fn is_supported_var(kind: DeclarationKind) -> bool {
+ match kind {
+ // VarDeclaredNames of Statement
+ //
+ // See Block::is_supported_var for the details.
+ DeclarationKind::Var => true,
+
+ _ => false,
+ }
+ }
+}
+
+impl VarEarlyErrorsContext for InternalForBodyEarlyErrorsContext {
+ fn declare_var<'alloc>(
+ &mut self,
+ name: SourceAtomSetIndex,
+ kind: DeclarationKind,
+ offset: usize,
+ _atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ debug_assert!(Self::is_supported_var(kind));
+
+ self.var_names_of_stmt
+ .insert(name, DeclarationInfo::new(kind, offset));
+
+ Ok(())
+ }
+}
+
+#[derive(Debug, PartialEq)]
+pub struct LexicalForBodyEarlyErrorsContext {
+ head: LexicalForHeadEarlyErrorsContext,
+ body: InternalForBodyEarlyErrorsContext,
+}
+
+impl LexicalForBodyEarlyErrorsContext {
+ pub fn new(head: LexicalForHeadEarlyErrorsContext) -> Self {
+ Self {
+ head,
+ body: InternalForBodyEarlyErrorsContext::new(),
+ }
+ }
+}
+
+impl VarEarlyErrorsContext for LexicalForBodyEarlyErrorsContext {
+ fn declare_var<'alloc>(
+ &mut self,
+ name: SourceAtomSetIndex,
+ kind: DeclarationKind,
+ offset: usize,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-for-statement-static-semantics-early-errors
+ //
+ // IterationStatement :
+ // for ( LexicalDeclaration Expression_opt ; Expression_opt )
+ // Statement
+ //
+ // * It is a Syntax Error if any element of the BoundNames of
+ // LexicalDeclaration also occurs in the VarDeclaredNames of
+ // Statement.
+ //
+ // and
+ //
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-for-in-and-for-of-statements-static-semantics-early-errors
+ //
+ // IterationStatement :
+ // for ( ForDeclaration in Expression ) Statement
+ // for ( ForDeclaration of AssignmentExpression ) Statement
+ // for await ( ForDeclaration of AssignmentExpression ) Statement
+ //
+ // * It is a Syntax Error if any element of the BoundNames of
+ // ForDeclaration also occurs in the VarDeclaredNames of Statement.
+ if let Some(info) = self.head.bound_names_of_decl.get(&name) {
+ let name = atoms.get(name);
+ return Err(
+ ParseError::DuplicateBinding(name, info.kind, info.offset, kind, offset).into(),
+ );
+ }
+
+ self.body.declare_var(name, kind, offset, atoms)
+ }
+}
+
+// ===========================================================================
+// LabelledStatements
+// https://tc39.es/ecma262/#sec-labelled-statements
+// ===========================================================================
+
+pub struct LabelledStatementEarlyErrorsContext {
+ name: SourceAtomSetIndex,
+ kind: LabelKind,
+}
+
+impl LabelledStatementEarlyErrorsContext {
+ pub fn new(name: SourceAtomSetIndex, kind: LabelKind) -> Self {
+ Self { name, kind }
+ }
+
+ pub fn check_duplicate_label<'alloc>(
+ &self,
+ inner_label_name: SourceAtomSetIndex,
+ ) -> EarlyErrorsResult<'alloc> {
+ // Static Semantics: ContainsDuplicateLabels
+ // https://tc39.es/ecma262/#sec-labelled-statements-static-semantics-containsduplicatelabels
+ //
+ // LabelledStatement : LabelIdentifier : LabelledItem
+ //
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-scripts-static-semantics-early-errors
+ //
+ // * It is a Syntax Error if ContainsDuplicateLabels of StatementList with argument « » is
+ // true.
+ //
+ // and
+ //
+ // https://tc39.es/ecma262/#sec-module-semantics-static-semantics-early-errors
+ //
+ // * It is a Syntax Error if ContainsDuplicateLabels of ModuleItemList with argument « » is
+ // true.
+ //
+ // and
+ //
+ // https://tc39.es/ecma262/#sec-function-definitions-static-semantics-early-errors
+ // * It is a Syntax Error if ContainsDuplicateLabels of FunctionStatementList with argument
+ // « » is true.
+ if inner_label_name == self.name {
+ return Err(ParseError::DuplicateLabel.into());
+ }
+ Ok(())
+ }
+
+ pub fn check_labelled_continue_to_non_loop<'alloc>(
+ &self,
+ info: &ControlInfo,
+ ) -> EarlyErrorsResult<'alloc> {
+ // Continues outside of iterators and Unlabelled breaks can not be detected at the
+ // function / script level easily, because we only have binding information there, not
+ // whether the label in question is associated with a loop or not. The nesting errors
+ // also cannot be detected at the {Break,Continue}Statement level, as we don't have that
+ // information there either. So we are handling these errors here. This handles labelled
+ // continues that would otherwise pass.
+ //
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-continue-statement-static-semantics-early-e
+ //
+ // ContinueStatement : continue LabelIdentifier ;
+ //
+ // * It is a Syntax Error if this ContinueStatement is not nested, directly
+ // indirectly (but not crossing function boundaries), within an
+ // IterationStatement.
+ if let Some(name) = info.label {
+ if self.kind != LabelKind::Loop
+ && info.kind == ControlKind::Continue
+ && name == self.name
+ {
+ return Err(ParseError::BadContinue.into());
+ }
+ }
+
+ Ok(())
+ }
+}
+
+// ===========================================================================
+// The switch Statement
+// https://tc39.es/ecma262/#sec-switch-statement
+// ===========================================================================
+
+#[derive(Debug, PartialEq)]
+pub struct CaseBlockEarlyErrorsContext {
+ lex_names_of_case_block: HashMap<SourceAtomSetIndex, DeclarationInfo>,
+ var_names_of_case_block: HashMap<SourceAtomSetIndex, DeclarationInfo>,
+}
+
+impl CaseBlockEarlyErrorsContext {
+ pub fn new() -> Self {
+ Self {
+ lex_names_of_case_block: HashMap::new(),
+ var_names_of_case_block: HashMap::new(),
+ }
+ }
+
+ fn is_supported_lexical(kind: DeclarationKind) -> bool {
+ // CaseBlock => CaseClauses => CaseClause => StatementList
+ // CaseBlock => DefaultClause => StatementList
+ BlockEarlyErrorsContext::is_supported_lexical(kind)
+ }
+
+ fn is_supported_var(kind: DeclarationKind) -> bool {
+ BlockEarlyErrorsContext::is_supported_var(kind)
+ }
+
+ fn is_strict<'alloc>(&self) -> Result<'alloc, bool> {
+ Err(ParseError::NotImplemented("strict-mode-only early error is not yet supported").into())
+ }
+}
+
+impl LexicalEarlyErrorsContext for CaseBlockEarlyErrorsContext {
+ fn declare_lex<'alloc>(
+ &mut self,
+ name: SourceAtomSetIndex,
+ kind: DeclarationKind,
+ offset: usize,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ debug_assert!(Self::is_supported_lexical(kind));
+
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-switch-statement-static-semantics-early-errors
+ //
+ // SwitchStatement : switch ( Expression ) CaseBlock
+ //
+ // * It is a Syntax Error if the LexicallyDeclaredNames of CaseBlock
+ // contains any duplicate entries.
+ if let Some(info) = self.lex_names_of_case_block.get(&name) {
+ // Changes to switch Statement Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-switch-duplicates-allowed-static-semantics
+ //
+ // SwitchStatement : switch ( Expression ) CaseBlock
+ //
+ // * It is a Syntax Error if the LexicallyDeclaredNames of
+ // CaseBlock contains any duplicate entries, ** unless the source
+ // code matching this production is not strict mode code and the
+ // duplicate entries are only bound by FunctionDeclarations **.
+ if !(!self.is_strict()?
+ && info.kind == DeclarationKind::LexicalFunction
+ && kind == DeclarationKind::LexicalFunction)
+ {
+ let name = atoms.get(name);
+ return Err(ParseError::DuplicateBinding(
+ name,
+ info.kind,
+ info.offset,
+ kind,
+ offset,
+ )
+ .into());
+ }
+ }
+
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-switch-statement-static-semantics-early-errors
+ //
+ // SwitchStatement : switch ( Expression ) CaseBlock
+ //
+ // * It is a Syntax Error if any element of the LexicallyDeclaredNames
+ // of CaseBlock also occurs in the VarDeclaredNames of CaseBlock.
+ if let Some(info) = self.var_names_of_case_block.get(&name) {
+ let name = atoms.get(name);
+ return Err(
+ ParseError::DuplicateBinding(name, info.kind, info.offset, kind, offset).into(),
+ );
+ }
+
+ self.lex_names_of_case_block
+ .insert(name, DeclarationInfo::new(kind, offset));
+
+ Ok(())
+ }
+}
+
+impl VarEarlyErrorsContext for CaseBlockEarlyErrorsContext {
+ fn declare_var<'alloc>(
+ &mut self,
+ name: SourceAtomSetIndex,
+ kind: DeclarationKind,
+ offset: usize,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ debug_assert!(Self::is_supported_var(kind));
+
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-switch-statement-static-semantics-early-errors
+ //
+ // SwitchStatement : switch ( Expression ) CaseBlock
+ //
+ // * It is a Syntax Error if any element of the LexicallyDeclaredNames
+ // of CaseBlock also occurs in the VarDeclaredNames of CaseBlock.
+ if let Some(info) = self.lex_names_of_case_block.get(&name) {
+ let name = atoms.get(name);
+ return Err(
+ ParseError::DuplicateBinding(name, info.kind, info.offset, kind, offset).into(),
+ );
+ }
+
+ self.var_names_of_case_block
+ .insert(name, DeclarationInfo::new(kind, offset));
+
+ Ok(())
+ }
+}
+
+// ===========================================================================
+// The try Statement
+// https://tc39.es/ecma262/#sec-try-statement
+// ===========================================================================
+
+#[derive(Debug, PartialEq)]
+pub struct CatchParameterEarlyErrorsContext {
+ bound_names_of_catch_param: HashMap<SourceAtomSetIndex, DeclarationInfo>,
+ is_simple: bool,
+}
+
+impl CatchParameterEarlyErrorsContext {
+ pub fn new_with_binding_identifier() -> Self {
+ Self {
+ bound_names_of_catch_param: HashMap::new(),
+ is_simple: true,
+ }
+ }
+
+ pub fn new_with_binding_pattern() -> Self {
+ Self {
+ bound_names_of_catch_param: HashMap::new(),
+ is_simple: false,
+ }
+ }
+}
+
+impl ParameterEarlyErrorsContext for CatchParameterEarlyErrorsContext {
+ fn declare<'alloc>(
+ &mut self,
+ name: SourceAtomSetIndex,
+ offset: usize,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ // BoundNames of CatchParameter
+ //
+ // CatchParameter => BindingIdentifier
+ // CatchParameter => BindingPattern
+ let kind = DeclarationKind::CatchParameter;
+
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-try-statement-static-semantics-early-errors
+ //
+ // Catch : catch ( CatchParameter ) Block
+ //
+ // * It is a Syntax Error if BoundNames of CatchParameter contains any
+ // duplicate elements.
+ if let Some(info) = self.bound_names_of_catch_param.get(&name) {
+ let name = atoms.get(name);
+ return Err(ParseError::DuplicateBinding(name, info.kind, offset, kind, offset).into());
+ }
+
+ self.bound_names_of_catch_param
+ .insert(name, DeclarationInfo::new(kind, offset));
+
+ Ok(())
+ }
+}
+
+#[derive(Debug, PartialEq)]
+pub struct CatchBlockEarlyErrorsContext {
+ param: CatchParameterEarlyErrorsContext,
+ block: BlockEarlyErrorsContext,
+}
+
+impl CatchBlockEarlyErrorsContext {
+ pub fn new(param: CatchParameterEarlyErrorsContext) -> Self {
+ Self {
+ param,
+ block: BlockEarlyErrorsContext::new(),
+ }
+ }
+}
+
+impl LexicalEarlyErrorsContext for CatchBlockEarlyErrorsContext {
+ fn declare_lex<'alloc>(
+ &mut self,
+ name: SourceAtomSetIndex,
+ kind: DeclarationKind,
+ offset: usize,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-try-statement-static-semantics-early-errors
+ //
+ // Catch : catch ( CatchParameter ) Block
+ //
+ // * It is a Syntax Error if any element of the BoundNames of
+ // CatchParameter also occurs in the LexicallyDeclaredNames of Block.
+ if let Some(info) = self.param.bound_names_of_catch_param.get(&name) {
+ let name = atoms.get(name);
+ return Err(ParseError::DuplicateBinding(name, info.kind, offset, kind, offset).into());
+ }
+
+ self.block.declare_lex(name, kind, offset, atoms)
+ }
+}
+
+impl VarEarlyErrorsContext for CatchBlockEarlyErrorsContext {
+ fn declare_var<'alloc>(
+ &mut self,
+ name: SourceAtomSetIndex,
+ kind: DeclarationKind,
+ offset: usize,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-try-statement-static-semantics-early-errors
+ //
+ // Catch : catch ( CatchParameter ) Block
+ //
+ // * It is a Syntax Error if any element of the BoundNames of
+ // CatchParameter also occurs in the VarDeclaredNames of Block.
+ //
+ if let Some(info) = self.param.bound_names_of_catch_param.get(&name) {
+ // VariableStatements in Catch Blocks
+ // https://tc39.es/ecma262/#sec-variablestatements-in-catch-blocks
+ //
+ // Catch : catch ( CatchParameter ) Block
+ //
+ // * It is a Syntax Error if any element of the BoundNames of
+ // CatchParameter also occurs in the VarDeclaredNames of Block **
+ // unless CatchParameter is CatchParameter : BindingIdentifier **.
+ if !self.param.is_simple {
+ let name = atoms.get(name);
+ return Err(ParseError::DuplicateBinding(
+ name,
+ info.kind,
+ info.offset,
+ kind,
+ offset,
+ )
+ .into());
+ }
+ }
+
+ self.block.declare_var(name, kind, offset, atoms)
+ }
+}
+
+// ===========================================================================
+// Function Definitions
+// https://tc39.es/ecma262/#sec-function-definitions
+//
+// Arrow Function Definitions
+// https://tc39.es/ecma262/#sec-arrow-function-definitions
+//
+// Method Definitions
+// https://tc39.es/ecma262/#sec-method-definitions
+//
+// Generator Function Definitions
+// https://tc39.es/ecma262/#sec-generator-function-definitions
+//
+// Async Generator Function Definitions
+// https://tc39.es/ecma262/#sec-async-generator-function-definitions
+//
+// Async Function Definitions
+// https://tc39.es/ecma262/#sec-async-function-definitions
+//
+// Async Arrow Function Definitions
+// https://tc39.es/ecma262/#sec-async-arrow-function-definitions
+// ===========================================================================
+
+#[derive(Debug, PartialEq)]
+pub struct FormalParametersEarlyErrorsContext {
+ bound_names_of_params: HashMap<SourceAtomSetIndex, DeclarationInfo>,
+ is_simple: bool,
+}
+
+impl FormalParametersEarlyErrorsContext {
+ pub fn new_simple() -> Self {
+ Self {
+ bound_names_of_params: HashMap::new(),
+ is_simple: true,
+ }
+ }
+
+ pub fn new_non_simple() -> Self {
+ Self {
+ bound_names_of_params: HashMap::new(),
+ is_simple: false,
+ }
+ }
+}
+
+impl ParameterEarlyErrorsContext for FormalParametersEarlyErrorsContext {
+ fn declare<'alloc>(
+ &mut self,
+ name: SourceAtomSetIndex,
+ offset: usize,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ // BoundNames of FormalParameterList
+ //
+ // Static Semantics: BoundNames
+ // https://tc39.es/ecma262/#sec-function-definitions-static-semantics-boundnames
+ //
+ // FormalParameters => FunctionParameterList => FormalParameter
+ // => BindingElement => SingleNameBinding => BindingIdentifier
+ //
+ // and
+ //
+ // FormalParameters => FunctionParameterList => FormalParameter
+ // => BindingElement => BindingPattern
+ //
+ // and
+ //
+ // FormalParameters => FunctionRestParameter => BindingRestElement
+ // => BindingIdentifier
+ //
+ // and
+ //
+ // FormalParameters => FunctionRestParameter => BindingRestElement
+ // => BindingPattern
+ let kind = DeclarationKind::FormalParameter;
+
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-function-definitions-static-semantics-early-errors
+ //
+ // FormalParameters : FormalParameterList
+ //
+ // * It is a Syntax Error if IsSimpleParameterList of
+ // FormalParameterList is false and BoundNames of FormalParameterList
+ // contains any duplicate elements.
+ if let Some(info) = self.bound_names_of_params.get(&name) {
+ if !self.is_simple {
+ let name = atoms.get(name);
+ return Err(ParseError::DuplicateBinding(
+ name,
+ info.kind,
+ info.offset,
+ kind,
+ offset,
+ )
+ .into());
+ }
+ }
+
+ self.bound_names_of_params
+ .insert(name, DeclarationInfo::new(kind, offset));
+
+ Ok(())
+ }
+}
+
+#[derive(Debug, PartialEq)]
+pub struct UniqueFormalParametersEarlyErrorsContext {
+ bound_names_of_params: HashMap<SourceAtomSetIndex, DeclarationInfo>,
+}
+
+impl UniqueFormalParametersEarlyErrorsContext {
+ pub fn new() -> Self {
+ Self {
+ bound_names_of_params: HashMap::new(),
+ }
+ }
+}
+
+impl ParameterEarlyErrorsContext for UniqueFormalParametersEarlyErrorsContext {
+ fn declare<'alloc>(
+ &mut self,
+ name: SourceAtomSetIndex,
+ offset: usize,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ let kind = DeclarationKind::FormalParameter;
+
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-function-definitions-static-semantics-early-errors
+ //
+ // UniqueFormalParameters : FormalParameters
+ //
+ // * It is a Syntax Error if BoundNames of FormalParameters contains any
+ // duplicate elements.
+ //
+ // and
+ //
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-method-definitions-static-semantics-early-errors
+ //
+ // MethodDefinition :
+ // set PropertyName ( PropertySetParameterList ) { FunctionBody }
+ //
+ // * It is a Syntax Error if BoundNames of PropertySetParameterList
+ // contains any duplicate elements.
+ if let Some(info) = self.bound_names_of_params.get(&name) {
+ let name = atoms.get(name);
+ return Err(
+ ParseError::DuplicateBinding(name, info.kind, info.offset, kind, offset).into(),
+ );
+ }
+
+ self.bound_names_of_params
+ .insert(name, DeclarationInfo::new(kind, offset));
+
+ Ok(())
+ }
+}
+
+#[derive(Debug, PartialEq)]
+struct InternalFunctionBodyEarlyErrorsContext {
+ lex_names_of_body: HashMap<SourceAtomSetIndex, DeclarationInfo>,
+ var_names_of_body: HashMap<SourceAtomSetIndex, DeclarationInfo>,
+}
+
+impl InternalFunctionBodyEarlyErrorsContext {
+ fn new() -> Self {
+ Self {
+ lex_names_of_body: HashMap::new(),
+ var_names_of_body: HashMap::new(),
+ }
+ }
+
+ fn is_supported_lexical(kind: DeclarationKind) -> bool {
+ match kind {
+ // LexicallyDeclaredNames of FunctionStatementList
+ //
+ // Static Semantics: LexicallyDeclaredNames
+ // https://tc39.es/ecma262/#sec-function-definitions-static-semantics-lexicallydeclarednames
+ //
+ // FunctionStatementList
+ // 1. Return TopLevelLexicallyDeclaredNames of StatementList.
+ //
+ // Static Semantics: TopLevelLexicallyDeclaredNames
+ // https://tc39.es/ecma262/#sec-block-static-semantics-toplevellexicallydeclarednames
+ //
+ // StatementList => StatementListItem => Statement
+ // 1. Return a new empty List.
+ //
+ // StatementList => StatementListItem => Declaration
+ // 1. If Declaration is Declaration : HoistableDeclaration, then
+ // a. Return « ».
+ // 2. Return the BoundNames of Declaration.
+ //
+ // See Block::is_supported_lexical for the details.
+ DeclarationKind::Class | DeclarationKind::Let | DeclarationKind::Const => true,
+ _ => false,
+ }
+ }
+
+ fn is_supported_var(kind: DeclarationKind) -> bool {
+ match kind {
+ // VarDeclaredNames of FunctionStatementList
+ //
+ // Static Semantics: VarDeclaredNames
+ // https://tc39.es/ecma262/#sec-function-definitions-static-semantics-vardeclarednames
+ //
+ // FunctionStatementList
+ // 1. Return TopLevelVarDeclaredNames of StatementList.
+ //
+ // Static Semantics: TopLevelVarDeclaredNames
+ // https://tc39.es/ecma262/#sec-block-static-semantics-toplevelvardeclarednames
+ //
+ // StatementList => StatementListItem => Declaration
+ // 1. If Declaration is Declaration : HoistableDeclaration, then
+ // a. Return the BoundNames of HoistableDeclaration.
+ // 2. Return a new empty List.
+ //
+ // HoistableDeclaration => FunctionDeclaration
+ // 1. Return the BoundNames of BindingIdentifier.
+ // 1. Return « "*default*" ».
+ //
+ // and
+ //
+ // Static Semantics: TopLevelVarDeclaredNames
+ // https://tc39.es/ecma262/#sec-block-static-semantics-toplevelvardeclarednames
+ //
+ // StatementList => StatementListItem => Statement
+ // 1. If Statement is Statement : LabelledStatement, return
+ // TopLevelVarDeclaredNames of Statement.
+ //
+ // Static Semantics: TopLevelVarDeclaredNames
+ // https://tc39.es/ecma262/#sec-labelled-statements-static-semantics-toplevelvardeclarednames
+ //
+ // LabelledStatement => LabelledItem => Statement
+ // 1. If Statement is Statement : LabelledStatement, return
+ // TopLevelVarDeclaredNames of Statement.
+ // 2. Return VarDeclaredNames of Statement.
+ //
+ // LabelledStatement => LabelledItem => FunctionDeclaration
+ // 1. Return BoundNames of FunctionDeclaration.
+ DeclarationKind::BodyLevelFunction |
+
+ // Static Semantics: TopLevelVarDeclaredNames
+ // https://tc39.es/ecma262/#sec-block-static-semantics-toplevelvardeclarednames
+ //
+ // StatementList => StatementListItem => Statement
+ // 2. Return VarDeclaredNames of Statement.
+ //
+ // and
+ //
+ // Static Semantics: TopLevelVarDeclaredNames
+ // https://tc39.es/ecma262/#sec-block-static-semantics-toplevelvardeclarednames
+ //
+ // StatementList => StatementListItem => Statement
+ // 1. If Statement is Statement : LabelledStatement, return
+ // TopLevelVarDeclaredNames of Statement.
+ //
+ // Static Semantics: TopLevelVarDeclaredNames
+ // https://tc39.es/ecma262/#sec-labelled-statements-static-semantics-toplevelvardeclarednames
+ //
+ // LabelledStatement => LabelledItem => Statement
+ // 2. Return VarDeclaredNames of Statement.
+ //
+ // See Block::is_supported_var for the details.
+ DeclarationKind::Var |
+ DeclarationKind::VarForAnnexBLexicalFunction => true,
+ _ => false,
+ }
+ }
+}
+
+impl LexicalEarlyErrorsContext for InternalFunctionBodyEarlyErrorsContext {
+ fn declare_lex<'alloc>(
+ &mut self,
+ name: SourceAtomSetIndex,
+ kind: DeclarationKind,
+ offset: usize,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ debug_assert!(Self::is_supported_lexical(kind));
+
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-function-definitions-static-semantics-early-errors
+ //
+ // FunctionBody : FunctionStatementList
+ //
+ // * It is a Syntax Error if the LexicallyDeclaredNames of
+ // FunctionStatementList contains any duplicate entries.
+ if let Some(info) = self.lex_names_of_body.get(&name) {
+ let name = atoms.get(name);
+ return Err(
+ ParseError::DuplicateBinding(name, info.kind, info.offset, kind, offset).into(),
+ );
+ }
+
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-function-definitions-static-semantics-early-errors
+ //
+ // FunctionBody : FunctionStatementList
+ //
+ // * It is a Syntax Error if any element of the LexicallyDeclaredNames
+ // of FunctionStatementList also occurs in the VarDeclaredNames of
+ // FunctionStatementList.
+ if let Some(info) = self.var_names_of_body.get(&name) {
+ let name = atoms.get(name);
+ return Err(
+ ParseError::DuplicateBinding(name, info.kind, info.offset, kind, offset).into(),
+ );
+ }
+
+ self.lex_names_of_body
+ .insert(name, DeclarationInfo::new(kind, offset));
+
+ Ok(())
+ }
+}
+
+impl VarEarlyErrorsContext for InternalFunctionBodyEarlyErrorsContext {
+ fn declare_var<'alloc>(
+ &mut self,
+ name: SourceAtomSetIndex,
+ kind: DeclarationKind,
+ offset: usize,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ debug_assert!(Self::is_supported_var(kind));
+
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-function-definitions-static-semantics-early-errors
+ //
+ // FunctionBody : FunctionStatementList
+ //
+ // * It is a Syntax Error if any element of the LexicallyDeclaredNames
+ // of FunctionStatementList also occurs in the VarDeclaredNames of
+ // FunctionStatementList.
+ if let Some(info) = self.lex_names_of_body.get(&name) {
+ let name = atoms.get(name);
+ return Err(
+ ParseError::DuplicateBinding(name, info.kind, info.offset, kind, offset).into(),
+ );
+ }
+
+ self.var_names_of_body
+ .insert(name, DeclarationInfo::new(kind, offset));
+
+ Ok(())
+ }
+}
+
+impl ControlEarlyErrorsContext for InternalFunctionBodyEarlyErrorsContext {
+ fn on_unhandled_break_or_continue<'alloc>(
+ &self,
+ info: &ControlInfo,
+ ) -> EarlyErrorsResult<'alloc> {
+ ModuleScriptOrFunctionEarlyErrorsContext::on_unhandled_break_or_continue(info)
+ }
+}
+
+// Functions with FormalParameters + FunctionBody.
+//
+// This is used for the following:
+// * function declaration
+// * function expression
+// * generator declaration
+// * generator expression
+// * async generator declaration
+// * async generator expression
+// * async function declaration
+// * async function expression
+
+#[derive(Debug, PartialEq)]
+pub struct FunctionBodyEarlyErrorsContext {
+ param: FormalParametersEarlyErrorsContext,
+ body: InternalFunctionBodyEarlyErrorsContext,
+}
+
+impl FunctionBodyEarlyErrorsContext {
+ pub fn new(param: FormalParametersEarlyErrorsContext) -> Self {
+ Self {
+ param,
+ body: InternalFunctionBodyEarlyErrorsContext::new(),
+ }
+ }
+}
+
+impl LexicalEarlyErrorsContext for FunctionBodyEarlyErrorsContext {
+ fn declare_lex<'alloc>(
+ &mut self,
+ name: SourceAtomSetIndex,
+ kind: DeclarationKind,
+ offset: usize,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-function-definitions-static-semantics-early-errors
+ //
+ // FunctionDeclaration :
+ // function BindingIdentifier ( FormalParameters ) { FunctionBody }
+ // FunctionDeclaration :
+ // function ( FormalParameters ) { FunctionBody }
+ // FunctionExpression :
+ // function BindingIdentifier_opt ( FormalParameters )
+ // { FunctionBody }
+ //
+ // * It is a Syntax Error if any element of the BoundNames of
+ // FormalParameters also occurs in the LexicallyDeclaredNames of
+ // FunctionBody.
+ //
+ // and
+ //
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-generator-function-definitions-static-semantics-early-errors
+ //
+ // GeneratorDeclaration :
+ // function * BindingIdentifier ( FormalParameters ) { GeneratorBody }
+ // GeneratorDeclaration :
+ // function * ( FormalParameters ) { GeneratorBody }
+ // GeneratorExpression :
+ // function * BindingIdentifier_opt ( FormalParameters )
+ // { GeneratorBody }
+ //
+ // * It is a Syntax Error if any element of the BoundNames of
+ // FormalParameters also occurs in the LexicallyDeclaredNames of
+ // GeneratorBody.
+ //
+ // and
+ //
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-async-generator-function-definitions-static-semantics-early-errors
+ //
+ // AsyncGeneratorDeclaration :
+ // async function * BindingIdentifier ( FormalParameters )
+ // { AsyncGeneratorBody }
+ // AsyncGeneratorDeclaration :
+ // async function * ( FormalParameters ) { AsyncGeneratorBody }
+ // AsyncGeneratorExpression :
+ // async function * BindingIdentifier_opt ( FormalParameters )
+ // { AsyncGeneratorBody }
+ //
+ // * It is a Syntax Error if any element of the BoundNames of
+ // FormalParameters also occurs in the LexicallyDeclaredNames of
+ // AsyncGeneratorBody.
+ //
+ // and
+ //
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-async-function-definitions-static-semantics-early-errors
+ //
+ // AsyncFunctionDeclaration :
+ // async function BindingIdentifier ( FormalParameters )
+ // { AsyncFunctionBody }
+ // AsyncFunctionDeclaration :
+ // async function ( FormalParameters ) { AsyncFunctionBody }
+ // AsyncFunctionExpression :
+ // async function ( FormalParameters ) { AsyncFunctionBody }
+ // AsyncFunctionExpression :
+ // async function BindingIdentifier ( FormalParameters )
+ // { AsyncFunctionBody }
+ //
+ // * It is a Syntax Error if any element of the BoundNames of
+ // FormalParameters also occurs in the LexicallyDeclaredNames of
+ // AsyncFunctionBody.
+ if let Some(info) = self.param.bound_names_of_params.get(&name) {
+ let name = atoms.get(name);
+ return Err(
+ ParseError::DuplicateBinding(name, info.kind, info.offset, kind, offset).into(),
+ );
+ }
+
+ self.body.declare_lex(name, kind, offset, atoms)
+ }
+}
+
+impl VarEarlyErrorsContext for FunctionBodyEarlyErrorsContext {
+ fn declare_var<'alloc>(
+ &mut self,
+ name: SourceAtomSetIndex,
+ kind: DeclarationKind,
+ offset: usize,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ self.body.declare_var(name, kind, offset, atoms)
+ }
+}
+
+impl ControlEarlyErrorsContext for FunctionBodyEarlyErrorsContext {
+ fn on_unhandled_break_or_continue<'alloc>(
+ &self,
+ info: &ControlInfo,
+ ) -> EarlyErrorsResult<'alloc> {
+ self.body.on_unhandled_break_or_continue(info)
+ }
+}
+
+// Functions with UniqueFormalParameters + FunctionBody
+//
+// This is used for the following:
+// * arrow function
+// * method definition
+// * setter
+// * generator method
+// * async generator method
+// * async method
+// * async arrow function
+
+#[derive(Debug, PartialEq)]
+pub struct UniqueFunctionBodyEarlyErrorsContext {
+ param: UniqueFormalParametersEarlyErrorsContext,
+ body: InternalFunctionBodyEarlyErrorsContext,
+}
+
+impl UniqueFunctionBodyEarlyErrorsContext {
+ pub fn new(param: UniqueFormalParametersEarlyErrorsContext) -> Self {
+ Self {
+ param,
+ body: InternalFunctionBodyEarlyErrorsContext::new(),
+ }
+ }
+}
+
+impl LexicalEarlyErrorsContext for UniqueFunctionBodyEarlyErrorsContext {
+ fn declare_lex<'alloc>(
+ &mut self,
+ name: SourceAtomSetIndex,
+ kind: DeclarationKind,
+ offset: usize,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-arrow-function-definitions-static-semantics-early-errors
+ //
+ // ArrowFunction : ArrowParameters => ConciseBody
+ //
+ // * It is a Syntax Error if any element of the BoundNames of
+ // ArrowParameters also occurs in the LexicallyDeclaredNames of
+ // ConciseBody.
+ //
+ // and
+ //
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-method-definitions-static-semantics-early-errors
+ //
+ // MethodDefinition :
+ // PropertyName ( UniqueFormalParameters ) { FunctionBody }
+ //
+ // * It is a Syntax Error if any element of the BoundNames of
+ // UniqueFormalParameters also occurs in the LexicallyDeclaredNames of
+ // FunctionBody.
+ //
+ // MethodDefinition :
+ // set PropertyName ( PropertySetParameterList ) { FunctionBody }
+ //
+ // * It is a Syntax Error if any element of the BoundNames of
+ // PropertySetParameterList also occurs in the LexicallyDeclaredNames
+ // of FunctionBody.
+ //
+ // and
+ //
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-generator-function-definitions-static-semantics-early-errors
+ //
+ // GeneratorMethod :
+ // * PropertyName ( UniqueFormalParameters ) { GeneratorBody }
+ //
+ // * It is a Syntax Error if any element of the BoundNames of
+ // UniqueFormalParameters also occurs in the LexicallyDeclaredNames of
+ // GeneratorBody.
+ //
+ // and
+ //
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-async-generator-function-definitions-static-semantics-early-errors
+ //
+ // AsyncGeneratorMethod :
+ // async * PropertyName ( UniqueFormalParameters )
+ // { AsyncGeneratorBody }
+ //
+ // * It is a Syntax Error if any element of the BoundNames of
+ // UniqueFormalParameters also occurs in the LexicallyDeclaredNames of
+ // AsyncGeneratorBody.
+ //
+ // and
+ //
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-async-function-definitions-static-semantics-early-errors
+ //
+ // AsyncMethod :
+ // async PropertyName ( UniqueFormalParameters ) { AsyncFunctionBody }
+ //
+ // * It is a Syntax Error if any element of the BoundNames of
+ // UniqueFormalParameters also occurs in the LexicallyDeclaredNames of
+ // AsyncFunctionBody.
+ //
+ // and
+ //
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-async-arrow-function-definitions-static-semantics-early-errors
+ //
+ // AsyncArrowFunction :
+ // async AsyncArrowBindingIdentifier => AsyncConciseBody
+ //
+ // * It is a Syntax Error if any element of the BoundNames of
+ // AsyncArrowBindingIdentifier also occurs in the
+ // LexicallyDeclaredNames of AsyncConciseBody.
+ //
+ // AsyncArrowFunction :
+ // CoverCallExpressionAndAsyncArrowHead => AsyncConciseBody
+ //
+ // * It is a Syntax Error if any element of the BoundNames of
+ // CoverCallExpressionAndAsyncArrowHead also occurs in the
+ // LexicallyDeclaredNames of AsyncConciseBody.
+ if let Some(info) = self.param.bound_names_of_params.get(&name) {
+ let name = atoms.get(name);
+ return Err(
+ ParseError::DuplicateBinding(name, info.kind, info.offset, kind, offset).into(),
+ );
+ }
+
+ self.body.declare_lex(name, kind, offset, atoms)
+ }
+}
+
+impl VarEarlyErrorsContext for UniqueFunctionBodyEarlyErrorsContext {
+ fn declare_var<'alloc>(
+ &mut self,
+ name: SourceAtomSetIndex,
+ kind: DeclarationKind,
+ offset: usize,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ self.body.declare_var(name, kind, offset, atoms)
+ }
+}
+
+impl ControlEarlyErrorsContext for UniqueFunctionBodyEarlyErrorsContext {
+ fn on_unhandled_break_or_continue<'alloc>(
+ &self,
+ info: &ControlInfo,
+ ) -> EarlyErrorsResult<'alloc> {
+ self.body.on_unhandled_break_or_continue(info)
+ }
+}
+
+// ===========================================================================
+// Scripts
+// https://tc39.es/ecma262/#sec-scripts
+// ===========================================================================
+
+#[derive(Debug, PartialEq)]
+pub struct ScriptEarlyErrorsContext {
+ lex_names_of_body: HashMap<SourceAtomSetIndex, DeclarationInfo>,
+ var_names_of_body: HashMap<SourceAtomSetIndex, DeclarationInfo>,
+}
+
+impl ScriptEarlyErrorsContext {
+ pub fn new() -> Self {
+ Self {
+ lex_names_of_body: HashMap::new(),
+ var_names_of_body: HashMap::new(),
+ }
+ }
+
+ fn is_supported_lexical(kind: DeclarationKind) -> bool {
+ match kind {
+ // LexicallyDeclaredNames of ScriptBody
+ //
+ // Static Semantics: LexicallyDeclaredNames
+ // https://tc39.es/ecma262/#sec-scripts-static-semantics-lexicallydeclarednames
+ //
+ // ScriptBody => StatementList
+ // 1. Return TopLevelLexicallyDeclaredNames of StatementList.
+ // StatementList => StatementListItem => Declaration
+ // 1. If Declaration is Declaration : HoistableDeclaration, then
+ // a. Return « ».
+ // 2. Return the BoundNames of Declaration.
+ //
+ // See Block::is_supported_lexical for the details.
+ DeclarationKind::Class | DeclarationKind::Let | DeclarationKind::Const => true,
+ _ => false,
+ }
+ }
+
+ fn is_supported_var(kind: DeclarationKind) -> bool {
+ match kind {
+ // VarDeclaredNames of ScriptBody
+ //
+ // Static Semantics: VarDeclaredNames
+ // https://tc39.es/ecma262/#sec-scripts-static-semantics-vardeclarednames
+ //
+ // ScriptBody => StatementList
+ // 1. Return TopLevelVarDeclaredNames of StatementList.
+ //
+ // See Block::is_supported_var for the detail.
+ DeclarationKind::Var
+ | DeclarationKind::BodyLevelFunction
+ | DeclarationKind::VarForAnnexBLexicalFunction => true,
+ _ => false,
+ }
+ }
+}
+
+impl LexicalEarlyErrorsContext for ScriptEarlyErrorsContext {
+ fn declare_lex<'alloc>(
+ &mut self,
+ name: SourceAtomSetIndex,
+ kind: DeclarationKind,
+ offset: usize,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ debug_assert!(Self::is_supported_lexical(kind));
+
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-scripts-static-semantics-early-errors
+ //
+ // Script : ScriptBody
+ //
+ // * It is a Syntax Error if the LexicallyDeclaredNames of ScriptBody
+ // contains any duplicate entries.
+ if let Some(info) = self.lex_names_of_body.get(&name) {
+ let name = atoms.get(name);
+ return Err(
+ ParseError::DuplicateBinding(name, info.kind, info.offset, kind, offset).into(),
+ );
+ }
+
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-scripts-static-semantics-early-errors
+ //
+ // Script : ScriptBody
+ //
+ // * It is a Syntax Error if any element of the LexicallyDeclaredNames
+ // of ScriptBody also occurs in the VarDeclaredNames of ScriptBody.
+ if let Some(info) = self.var_names_of_body.get(&name) {
+ let name = atoms.get(name);
+ return Err(
+ ParseError::DuplicateBinding(name, info.kind, info.offset, kind, offset).into(),
+ );
+ }
+
+ self.lex_names_of_body
+ .insert(name, DeclarationInfo::new(kind, offset));
+
+ Ok(())
+ }
+}
+
+impl VarEarlyErrorsContext for ScriptEarlyErrorsContext {
+ fn declare_var<'alloc>(
+ &mut self,
+ name: SourceAtomSetIndex,
+ kind: DeclarationKind,
+ offset: usize,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ debug_assert!(Self::is_supported_var(kind));
+
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-scripts-static-semantics-early-errors
+ //
+ // Script : ScriptBody
+ //
+ // * It is a Syntax Error if any element of the LexicallyDeclaredNames
+ // of ScriptBody also occurs in the VarDeclaredNames of ScriptBody.
+ if let Some(info) = self.lex_names_of_body.get(&name) {
+ let name = atoms.get(name);
+ return Err(
+ ParseError::DuplicateBinding(name, info.kind, info.offset, kind, offset).into(),
+ );
+ }
+
+ self.var_names_of_body
+ .insert(name, DeclarationInfo::new(kind, offset));
+
+ Ok(())
+ }
+}
+
+impl ControlEarlyErrorsContext for ScriptEarlyErrorsContext {
+ fn on_unhandled_break_or_continue<'alloc>(
+ &self,
+ info: &ControlInfo,
+ ) -> EarlyErrorsResult<'alloc> {
+ ModuleScriptOrFunctionEarlyErrorsContext::on_unhandled_break_or_continue(info)
+ }
+}
+
+// ===========================================================================
+// Modules
+// https://tc39.es/ecma262/#sec-modules
+// ===========================================================================
+
+#[derive(Debug, PartialEq)]
+pub struct ModuleEarlyErrorsContext {
+ lex_names_of_item_list: HashMap<SourceAtomSetIndex, DeclarationInfo>,
+ var_names_of_item_list: HashMap<SourceAtomSetIndex, DeclarationInfo>,
+ exported_names_of_item_list: HashMap<SourceAtomSetIndex, usize>,
+ exported_bindings_of_item_list: HashMap<SourceAtomSetIndex, usize>,
+}
+
+impl ModuleEarlyErrorsContext {
+ pub fn new() -> Self {
+ Self {
+ lex_names_of_item_list: HashMap::new(),
+ var_names_of_item_list: HashMap::new(),
+ exported_names_of_item_list: HashMap::new(),
+ exported_bindings_of_item_list: HashMap::new(),
+ }
+ }
+
+ fn is_supported_lexical(kind: DeclarationKind) -> bool {
+ match kind {
+ // LexicallyDeclaredNames of ModuleItemList
+ //
+ // Static Semantics: LexicallyDeclaredNames
+ // https://tc39.es/ecma262/#sec-module-semantics-static-semantics-lexicallydeclarednames
+ //
+ // ModuleItemList => ModuleItem => ImportDeclaration
+ // 1. Return the BoundNames of ImportDeclaration.
+ //
+ // ImportDeclaration ... => ImportedBinding => BindingIdentifier
+ DeclarationKind::Import |
+
+ // ModuleItemList => ModuleItem => ExportDeclaration
+ // 1. If ExportDeclaration is export VariableStatement, return a
+ // new empty List.
+ // 2. Return the BoundNames of ExportDeclaration.
+ //
+ // ExportDeclaration => Declaration
+ // 1. Return the BoundNames of Declaration.
+
+ // ExportDeclaration => HoistableDeclaration
+ // 1. Let declarationNames be the BoundNames of
+ // HoistableDeclaration.
+ // 2. If declarationNames does not include the element
+ // "*default*", append "*default*" to declarationNames.
+ // 3. Return declarationNames.
+
+ // ExportDeclaration => ClassDeclaration
+ // 1. Let declarationNames be the BoundNames of ClassDeclaration.
+ // 2. If declarationNames does not include the element
+ // "*default*", append "*default*" to declarationNames.
+ // 3. Return declarationNames.
+
+ // ExportDeclaration => AssignmentExpression
+ // 1. Return « "*default*" ».
+
+ // ModuleItemList => ModuleItem => StatementListItem
+ //
+ // See Block::is_supported_lexical for the details.
+ //
+ // Function declaration in the top level of module script is
+ // lexical, but here isn't LexicalFunction/LexicalAsyncOrGenerator
+ // distinction because B.3.3.4 doesn't apply to Module.
+ DeclarationKind::BodyLevelFunction |
+ DeclarationKind::Class |
+ DeclarationKind::Let |
+ DeclarationKind::Const => true,
+ _ => false,
+ }
+ }
+
+ fn is_supported_var(kind: DeclarationKind) -> bool {
+ match kind {
+ // VarDeclaredNames of ModuleItemList
+ //
+ // Static Semantics: VarDeclaredNames
+ // https://tc39.es/ecma262/#sec-module-semantics-static-semantics-vardeclarednames
+ //
+ // ModuleItemList => ModuleItem => ImportDeclaration
+ // 1. Return a new empty List.
+
+ // ModuleItemList => ModuleItem => ExportDeclaration
+ // 1. If ExportDeclaration is export VariableStatement, return
+ // BoundNames of ExportDeclaration.
+ // 2. Return a new empty List.
+ //
+ // and
+ //
+ // ModuleItemList => ModuleItem => StatementList
+ DeclarationKind::Var => true,
+ _ => false,
+ }
+ }
+
+ #[allow(dead_code)]
+ pub fn add_exported_name<'alloc>(
+ &mut self,
+ name: SourceAtomSetIndex,
+ offset: usize,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-module-semantics-static-semantics-early-errors
+ //
+ // ModuleBody : ModuleItemList
+ //
+ // * It is a Syntax Error if the ExportedNames of ModuleItemList
+ // contains any duplicate entries.
+ if let Some(prev_offset) = self.exported_names_of_item_list.get(&name) {
+ let name = atoms.get(name);
+ return Err(ParseError::DuplicateExport(name, prev_offset.clone(), offset).into());
+ }
+
+ self.exported_names_of_item_list.insert(name, offset);
+
+ Ok(())
+ }
+
+ #[allow(dead_code)]
+ pub fn add_exported_binding(&mut self, name: SourceAtomSetIndex, offset: usize) {
+ self.exported_bindings_of_item_list.insert(name, offset);
+ }
+
+ #[allow(dead_code)]
+ pub fn check_exported_name<'alloc>(
+ &self,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-module-semantics-static-semantics-early-errors
+ //
+ // ModuleBody : ModuleItemList
+ //
+ // * It is a Syntax Error if any element of the ExportedBindings of
+ // ModuleItemList does not also occur in either the VarDeclaredNames
+ // of ModuleItemList, or the LexicallyDeclaredNames of ModuleItemList.
+ for (name, offset) in &self.exported_bindings_of_item_list {
+ if !self.var_names_of_item_list.contains_key(name)
+ && !self.lex_names_of_item_list.contains_key(name)
+ {
+ let name = atoms.get(*name);
+ return Err(ParseError::MissingExport(name, offset.clone()).into());
+ }
+ }
+
+ Ok(())
+ }
+}
+
+impl LexicalEarlyErrorsContext for ModuleEarlyErrorsContext {
+ fn declare_lex<'alloc>(
+ &mut self,
+ name: SourceAtomSetIndex,
+ kind: DeclarationKind,
+ offset: usize,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ debug_assert!(Self::is_supported_lexical(kind));
+
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-module-semantics-static-semantics-early-errors
+ //
+ // ModuleBody : ModuleItemList
+ //
+ // * It is a Syntax Error if the LexicallyDeclaredNames of
+ // ModuleItemList contains any duplicate entries.
+ //
+ // and
+ //
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-imports-static-semantics-early-errors
+ //
+ // ModuleItem : ImportDeclaration
+ //
+ // * It is a Syntax Error if the BoundNames of ImportDeclaration
+ // contains any duplicate entries.
+ if let Some(info) = self.lex_names_of_item_list.get(&name) {
+ let name = atoms.get(name);
+ return Err(
+ ParseError::DuplicateBinding(name, info.kind, info.offset, kind, offset).into(),
+ );
+ }
+
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-module-semantics-static-semantics-early-errors
+
+ //
+ // ModuleBody : ModuleItemList
+ //
+ // * It is a Syntax Error if any element of the LexicallyDeclaredNames
+ // of ModuleItemList also occurs in the VarDeclaredNames of
+ // ModuleItemList.
+ if let Some(info) = self.var_names_of_item_list.get(&name) {
+ let name = atoms.get(name);
+ return Err(
+ ParseError::DuplicateBinding(name, info.kind, info.offset, kind, offset).into(),
+ );
+ }
+
+ self.lex_names_of_item_list
+ .insert(name, DeclarationInfo::new(kind, offset));
+
+ Ok(())
+ }
+}
+
+impl VarEarlyErrorsContext for ModuleEarlyErrorsContext {
+ fn declare_var<'alloc>(
+ &mut self,
+ name: SourceAtomSetIndex,
+ kind: DeclarationKind,
+ offset: usize,
+ atoms: &SourceAtomSet<'alloc>,
+ ) -> EarlyErrorsResult<'alloc> {
+ debug_assert!(Self::is_supported_var(kind));
+
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-module-semantics-static-semantics-early-errors
+ //
+ // ModuleBody : ModuleItemList
+ //
+ // * It is a Syntax Error if any element of the LexicallyDeclaredNames
+ // of ModuleItemList also occurs in the VarDeclaredNames of
+ // ModuleItemList.
+ if let Some(info) = self.lex_names_of_item_list.get(&name) {
+ let name = atoms.get(name);
+ return Err(
+ ParseError::DuplicateBinding(name, info.kind, info.offset, kind, offset).into(),
+ );
+ }
+
+ self.var_names_of_item_list
+ .insert(name, DeclarationInfo::new(kind, offset));
+
+ Ok(())
+ }
+}
+
+impl ControlEarlyErrorsContext for ModuleEarlyErrorsContext {
+ fn on_unhandled_break_or_continue<'alloc>(
+ &self,
+ info: &ControlInfo,
+ ) -> EarlyErrorsResult<'alloc> {
+ ModuleScriptOrFunctionEarlyErrorsContext::on_unhandled_break_or_continue(info)
+ }
+}
+
+struct ModuleScriptOrFunctionEarlyErrorsContext {}
+
+impl ModuleScriptOrFunctionEarlyErrorsContext {
+ fn on_unhandled_break_or_continue<'alloc>(info: &ControlInfo) -> EarlyErrorsResult<'alloc> {
+ if let Some(_) = info.label {
+ match info.kind {
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-scripts-static-semantics-early-errors
+ //
+ // Script : ScriptBody
+ //
+ // * It is a Syntax Error if ContainsUndefinedContinueTarget of StatementList
+ // with arguments « » and « » is true.
+ //
+ // https://tc39.es/ecma262/#sec-module-semantics-static-semantics-early-errors
+ //
+ // ModuleBody : ModuleItemList
+ //
+ // * It is a Syntax Error if ContainsUndefinedContinueTarget of ModuleItemList
+ // with arguments « » and « » is true.
+ ControlKind::Continue => {
+ return Err(ParseError::BadContinue.into());
+ }
+
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-scripts-static-semantics-early-errors
+ //
+ // Script : ScriptBody
+ //
+ // * It is a Syntax Error if ContainsUndefinedBreakTarget of StatementList
+ // with argument « » is true.
+ //
+ // https://tc39.es/ecma262/#sec-module-semantics-static-semantics-early-errors
+ //
+ // ModuleBody : ModuleItemList
+ //
+ // * It is a Syntax Error if ContainsUndefinedBreakTarget of ModuleItemList
+ // with argument « » is true.
+ ControlKind::Break => {
+ return Err(ParseError::LabelNotFound.into());
+ }
+ }
+ } else {
+ match info.kind {
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-continue-statement-static-semantics-early-errors
+ //
+ // ContinueStatement : continue ;
+ // ContinueStatement : continueLabelIdentifier ;
+ //
+ // * It is a Syntax Error if this ContinueStatement is not nested, directly or
+ // indirectly (but not crossing function boundaries), within an
+ // IterationStatement.
+ ControlKind::Continue => {
+ return Err(ParseError::BadContinue.into());
+ }
+ // Static Semantics: Early Errors
+ // https://tc39.es/ecma262/#sec-break-statement-static-semantics-early-errors
+ //
+ // BreakStatement : break ;
+ //
+ // * It is a Syntax Error if this BreakStatement is not nested, directly or
+ // indirectly (but not crossing function boundaries), within an
+ // IterationStatement or a SwitchStatement.
+ ControlKind::Break => {
+ return Err(ParseError::ToughBreak.into());
+ }
+ }
+ }
+ }
+}