Skip to main content

boa_ast/operations/
mod.rs

1//! Definitions of various **Syntax-Directed Operations** used in the [spec].
2//!
3//! [spec]: https://tc39.es/ecma262/#sec-syntax-directed-operations
4
5use core::ops::ControlFlow;
6use std::convert::Infallible;
7
8use boa_interner::{Interner, Sym};
9use rustc_hash::FxHashSet;
10
11use crate::{
12    Declaration, Expression, LinearSpan, ModuleItem, Script, Statement, StatementList,
13    StatementListItem,
14    declaration::{
15        Binding, ExportDeclaration, ImportDeclaration, LexicalDeclaration, VarDeclaration, Variable,
16    },
17    expression::{
18        Await, Call, Identifier, NewTarget, OptionalOperationKind, SuperCall, This, Yield,
19        access::{PrivatePropertyAccess, SuperPropertyAccess},
20        literal::PropertyDefinition,
21        operator::BinaryInPrivate,
22    },
23    function::{
24        ArrowFunction, AsyncArrowFunction, AsyncFunctionDeclaration, AsyncFunctionExpression,
25        AsyncGeneratorDeclaration, AsyncGeneratorExpression, ClassDeclaration, ClassElement,
26        ClassElementName, ClassExpression, FormalParameterList, FunctionBody, FunctionDeclaration,
27        FunctionExpression, GeneratorDeclaration, GeneratorExpression, PrivateFieldDefinition,
28    },
29    statement::{
30        LabelledItem, With,
31        iteration::{ForLoopInitializer, IterableLoopInitializer},
32    },
33    visitor::{NodeRef, VisitWith, Visitor},
34};
35
36#[cfg(test)]
37mod tests;
38
39/// Represents all the possible symbols searched for by the [`Contains`][contains] operation.
40///
41/// [contains]: https://tc39.es/ecma262/#sec-syntax-directed-operations-contains
42#[derive(Clone, Copy, Debug, PartialEq, Eq)]
43#[non_exhaustive]
44pub enum ContainsSymbol {
45    /// A node with the `super` keyword (`super(args)` or `super.prop`).
46    Super,
47    /// A super property access (`super.prop`).
48    SuperProperty,
49    /// A super constructor call (`super(args)`).
50    SuperCall,
51    /// A yield expression (`yield 5`).
52    YieldExpression,
53    /// An await expression (`await 4`).
54    AwaitExpression,
55    /// The new target expression (`new.target`).
56    NewTarget,
57    /// The body of a class definition.
58    ClassBody,
59    /// The super class of a class definition.
60    ClassHeritage,
61    /// A this expression (`this`).
62    This,
63    /// A method definition.
64    MethodDefinition,
65    /// The `BindingIdentifier` "eval" or "arguments".
66    EvalOrArguments,
67    /// A direct call to `eval`.
68    DirectEval,
69}
70
71/// Returns `true` if the node contains the given symbol.
72///
73/// This is equivalent to the [`Contains`][spec] syntax operation in the spec.
74///
75/// [spec]: https://tc39.es/ecma262/#sec-static-semantics-contains
76#[must_use]
77pub fn contains<N>(node: &N, symbol: ContainsSymbol) -> bool
78where
79    N: VisitWith,
80{
81    /// Visitor used by the function to search for a specific symbol in a node.
82    #[derive(Debug, Clone, Copy)]
83    struct ContainsVisitor(ContainsSymbol);
84
85    impl ContainsVisitor {
86        fn visit_contains_eval(&mut self, contains_direct_eval: bool) -> ControlFlow<()> {
87            if self.0 == ContainsSymbol::DirectEval && contains_direct_eval {
88                ControlFlow::Break(())
89            } else {
90                ControlFlow::Continue(())
91            }
92        }
93    }
94
95    impl<'ast> Visitor<'ast> for ContainsVisitor {
96        type BreakTy = ();
97
98        fn visit_with(&mut self, node: &'ast With) -> ControlFlow<Self::BreakTy> {
99            self.visit_expression(node.expression())?;
100            node.statement().visit_with(self)
101        }
102
103        fn visit_call(&mut self, node: &'ast Call) -> ControlFlow<Self::BreakTy> {
104            if self.0 == ContainsSymbol::DirectEval
105                && let Expression::Identifier(ident) = node.function().flatten()
106                && ident.sym() == Sym::EVAL
107            {
108                return ControlFlow::Break(());
109            }
110
111            self.visit_expression(node.function())?;
112            for arg in node.args() {
113                self.visit_expression(arg)?;
114            }
115            ControlFlow::Continue(())
116        }
117
118        fn visit_identifier(&mut self, node: &'ast Identifier) -> ControlFlow<Self::BreakTy> {
119            if self.0 == ContainsSymbol::EvalOrArguments
120                && (node.sym() == Sym::EVAL || node.sym() == Sym::ARGUMENTS)
121            {
122                return ControlFlow::Break(());
123            }
124            ControlFlow::Continue(())
125        }
126
127        fn visit_function_expression(
128            &mut self,
129            node: &'ast FunctionExpression,
130        ) -> ControlFlow<Self::BreakTy> {
131            self.visit_contains_eval(node.contains_direct_eval)?;
132            ControlFlow::Continue(())
133        }
134
135        fn visit_function_declaration(
136            &mut self,
137            node: &'ast FunctionDeclaration,
138        ) -> ControlFlow<Self::BreakTy> {
139            self.visit_contains_eval(node.contains_direct_eval)?;
140            ControlFlow::Continue(())
141        }
142
143        fn visit_async_function_expression(
144            &mut self,
145            node: &'ast AsyncFunctionExpression,
146        ) -> ControlFlow<Self::BreakTy> {
147            self.visit_contains_eval(node.contains_direct_eval)?;
148            ControlFlow::Continue(())
149        }
150
151        fn visit_async_function_declaration(
152            &mut self,
153            node: &'ast AsyncFunctionDeclaration,
154        ) -> ControlFlow<Self::BreakTy> {
155            self.visit_contains_eval(node.contains_direct_eval)?;
156            ControlFlow::Continue(())
157        }
158
159        fn visit_generator_expression(
160            &mut self,
161            node: &'ast GeneratorExpression,
162        ) -> ControlFlow<Self::BreakTy> {
163            self.visit_contains_eval(node.contains_direct_eval)?;
164            ControlFlow::Continue(())
165        }
166
167        fn visit_generator_declaration(
168            &mut self,
169            node: &'ast GeneratorDeclaration,
170        ) -> ControlFlow<Self::BreakTy> {
171            self.visit_contains_eval(node.contains_direct_eval)?;
172            ControlFlow::Continue(())
173        }
174
175        fn visit_async_generator_expression(
176            &mut self,
177            node: &'ast AsyncGeneratorExpression,
178        ) -> ControlFlow<Self::BreakTy> {
179            self.visit_contains_eval(node.contains_direct_eval)?;
180            ControlFlow::Continue(())
181        }
182
183        fn visit_async_generator_declaration(
184            &mut self,
185            node: &'ast AsyncGeneratorDeclaration,
186        ) -> ControlFlow<Self::BreakTy> {
187            self.visit_contains_eval(node.contains_direct_eval)?;
188            ControlFlow::Continue(())
189        }
190
191        fn visit_class_expression(
192            &mut self,
193            node: &'ast ClassExpression,
194        ) -> ControlFlow<Self::BreakTy> {
195            if !node.elements().is_empty() && self.0 == ContainsSymbol::ClassBody {
196                return ControlFlow::Break(());
197            }
198
199            if node.super_ref().is_some() && self.0 == ContainsSymbol::ClassHeritage {
200                return ControlFlow::Break(());
201            }
202
203            node.visit_with(self)
204        }
205
206        fn visit_class_declaration(
207            &mut self,
208            node: &'ast ClassDeclaration,
209        ) -> ControlFlow<Self::BreakTy> {
210            if !node.elements().is_empty() && self.0 == ContainsSymbol::ClassBody {
211                return ControlFlow::Break(());
212            }
213
214            if node.super_ref().is_some() && self.0 == ContainsSymbol::ClassHeritage {
215                return ControlFlow::Break(());
216            }
217
218            node.visit_with(self)
219        }
220
221        // `ComputedPropertyContains`: https://tc39.es/ecma262/#sec-static-semantics-computedpropertycontains
222        fn visit_class_element(&mut self, node: &'ast ClassElement) -> ControlFlow<Self::BreakTy> {
223            match node {
224                ClassElement::MethodDefinition(m) => {
225                    if self.0 == ContainsSymbol::DirectEval {
226                        return ControlFlow::Continue(());
227                    }
228
229                    if let ClassElementName::PropertyName(name) = m.name() {
230                        name.visit_with(self)
231                    } else {
232                        ControlFlow::Continue(())
233                    }
234                }
235                ClassElement::FieldDefinition(field)
236                | ClassElement::StaticFieldDefinition(field) => field.name.visit_with(self),
237                _ => ControlFlow::Continue(()),
238            }
239        }
240
241        fn visit_property_definition(
242            &mut self,
243            node: &'ast PropertyDefinition,
244        ) -> ControlFlow<Self::BreakTy> {
245            if let PropertyDefinition::MethodDefinition(m) = node {
246                if self.0 == ContainsSymbol::DirectEval {
247                    return ControlFlow::Continue(());
248                }
249
250                if self.0 == ContainsSymbol::MethodDefinition {
251                    return ControlFlow::Break(());
252                }
253                return m.name().visit_with(self);
254            }
255
256            node.visit_with(self)
257        }
258
259        fn visit_arrow_function(
260            &mut self,
261            node: &'ast ArrowFunction,
262        ) -> ControlFlow<Self::BreakTy> {
263            if ![
264                ContainsSymbol::NewTarget,
265                ContainsSymbol::SuperProperty,
266                ContainsSymbol::SuperCall,
267                ContainsSymbol::Super,
268                ContainsSymbol::This,
269                ContainsSymbol::DirectEval,
270            ]
271            .contains(&self.0)
272            {
273                return ControlFlow::Continue(());
274            }
275
276            node.visit_with(self)
277        }
278
279        fn visit_async_arrow_function(
280            &mut self,
281            node: &'ast AsyncArrowFunction,
282        ) -> ControlFlow<Self::BreakTy> {
283            if ![
284                ContainsSymbol::NewTarget,
285                ContainsSymbol::SuperProperty,
286                ContainsSymbol::SuperCall,
287                ContainsSymbol::Super,
288                ContainsSymbol::This,
289                ContainsSymbol::DirectEval,
290            ]
291            .contains(&self.0)
292            {
293                return ControlFlow::Continue(());
294            }
295
296            node.visit_with(self)
297        }
298
299        fn visit_super_property_access(
300            &mut self,
301            node: &'ast SuperPropertyAccess,
302        ) -> ControlFlow<Self::BreakTy> {
303            if [ContainsSymbol::SuperProperty, ContainsSymbol::Super].contains(&self.0) {
304                return ControlFlow::Break(());
305            }
306            node.visit_with(self)
307        }
308
309        fn visit_super_call(&mut self, node: &'ast SuperCall) -> ControlFlow<Self::BreakTy> {
310            if [ContainsSymbol::SuperCall, ContainsSymbol::Super].contains(&self.0) {
311                return ControlFlow::Break(());
312            }
313            node.visit_with(self)
314        }
315
316        fn visit_yield(&mut self, node: &'ast Yield) -> ControlFlow<Self::BreakTy> {
317            if self.0 == ContainsSymbol::YieldExpression {
318                return ControlFlow::Break(());
319            }
320
321            node.visit_with(self)
322        }
323
324        fn visit_await(&mut self, node: &'ast Await) -> ControlFlow<Self::BreakTy> {
325            if self.0 == ContainsSymbol::AwaitExpression {
326                return ControlFlow::Break(());
327            }
328
329            node.visit_with(self)
330        }
331
332        fn visit_this(&mut self, _node: &'ast This) -> ControlFlow<Self::BreakTy> {
333            if self.0 == ContainsSymbol::This {
334                return ControlFlow::Break(());
335            }
336            ControlFlow::Continue(())
337        }
338
339        fn visit_new_target(&mut self, _node: &'ast NewTarget) -> ControlFlow<Self::BreakTy> {
340            if self.0 == ContainsSymbol::NewTarget {
341                return ControlFlow::Break(());
342            }
343            ControlFlow::Continue(())
344        }
345    }
346
347    node.visit_with(&mut ContainsVisitor(symbol)).is_break()
348}
349
350/// Returns true if the node contains an identifier reference with name `arguments`.
351///
352/// This is equivalent to the [`ContainsArguments`][spec] syntax operation in the spec.
353///
354/// [spec]: https://tc39.es/ecma262/#sec-static-semantics-containsarguments
355#[must_use]
356pub fn contains_arguments<N>(node: &N) -> bool
357where
358    N: VisitWith,
359{
360    /// Visitor used by the function to search for an identifier with the name `arguments`.
361    #[derive(Debug, Clone, Copy)]
362    struct ContainsArgsVisitor;
363
364    impl<'ast> Visitor<'ast> for ContainsArgsVisitor {
365        type BreakTy = ();
366
367        fn visit_identifier(&mut self, node: &'ast Identifier) -> ControlFlow<Self::BreakTy> {
368            if node.sym() == Sym::ARGUMENTS {
369                ControlFlow::Break(())
370            } else {
371                ControlFlow::Continue(())
372            }
373        }
374
375        fn visit_function_expression(
376            &mut self,
377            _: &'ast FunctionExpression,
378        ) -> ControlFlow<Self::BreakTy> {
379            ControlFlow::Continue(())
380        }
381
382        fn visit_function_declaration(
383            &mut self,
384            _: &'ast FunctionDeclaration,
385        ) -> ControlFlow<Self::BreakTy> {
386            ControlFlow::Continue(())
387        }
388
389        fn visit_async_function_expression(
390            &mut self,
391            _: &'ast AsyncFunctionExpression,
392        ) -> ControlFlow<Self::BreakTy> {
393            ControlFlow::Continue(())
394        }
395
396        fn visit_async_function_declaration(
397            &mut self,
398            _: &'ast AsyncFunctionDeclaration,
399        ) -> ControlFlow<Self::BreakTy> {
400            ControlFlow::Continue(())
401        }
402
403        fn visit_generator_expression(
404            &mut self,
405            _: &'ast GeneratorExpression,
406        ) -> ControlFlow<Self::BreakTy> {
407            ControlFlow::Continue(())
408        }
409
410        fn visit_generator_declaration(
411            &mut self,
412            _: &'ast GeneratorDeclaration,
413        ) -> ControlFlow<Self::BreakTy> {
414            ControlFlow::Continue(())
415        }
416
417        fn visit_async_generator_expression(
418            &mut self,
419            _: &'ast AsyncGeneratorExpression,
420        ) -> ControlFlow<Self::BreakTy> {
421            ControlFlow::Continue(())
422        }
423
424        fn visit_async_generator_declaration(
425            &mut self,
426            _: &'ast AsyncGeneratorDeclaration,
427        ) -> ControlFlow<Self::BreakTy> {
428            ControlFlow::Continue(())
429        }
430
431        fn visit_class_element(&mut self, node: &'ast ClassElement) -> ControlFlow<Self::BreakTy> {
432            if let ClassElement::MethodDefinition(m) = node
433                && let ClassElementName::PropertyName(name) = m.name()
434            {
435                return name.visit_with(self);
436            }
437
438            node.visit_with(self)
439        }
440
441        fn visit_property_definition(
442            &mut self,
443            node: &'ast PropertyDefinition,
444        ) -> ControlFlow<Self::BreakTy> {
445            if let PropertyDefinition::MethodDefinition(m) = node {
446                m.name().visit_with(self)
447            } else {
448                node.visit_with(self)
449            }
450        }
451    }
452    node.visit_with(&mut ContainsArgsVisitor).is_break()
453}
454
455/// Returns `true` if `method` has a super call in its parameters or body.
456///
457/// This is equivalent to the [`HasDirectSuper`][spec] syntax operation in the spec.
458///
459/// [spec]: https://tc39.es/ecma262/#sec-static-semantics-hasdirectsuper
460#[must_use]
461#[inline]
462pub fn has_direct_super_new(params: &FormalParameterList, body: &FunctionBody) -> bool {
463    contains(params, ContainsSymbol::SuperCall) || contains(body, ContainsSymbol::SuperCall)
464}
465
466/// A container that [`BoundNamesVisitor`] can use to push the found identifiers.
467pub(crate) trait IdentList {
468    fn add(&mut self, value: Sym, function: bool);
469}
470
471impl IdentList for Vec<Sym> {
472    fn add(&mut self, value: Sym, _function: bool) {
473        self.push(value);
474    }
475}
476
477impl IdentList for Vec<(Sym, bool)> {
478    fn add(&mut self, value: Sym, function: bool) {
479        self.push((value, function));
480    }
481}
482
483impl IdentList for FxHashSet<Sym> {
484    fn add(&mut self, value: Sym, _function: bool) {
485        self.insert(value);
486    }
487}
488
489/// The [`Visitor`] used to obtain the bound names of a node.
490#[derive(Debug)]
491pub(crate) struct BoundNamesVisitor<'a, T: IdentList>(pub(crate) &'a mut T);
492
493impl<'ast, T: IdentList> Visitor<'ast> for BoundNamesVisitor<'_, T> {
494    type BreakTy = Infallible;
495
496    fn visit_identifier(&mut self, node: &'ast Identifier) -> ControlFlow<Self::BreakTy> {
497        self.0.add(node.sym(), false);
498        ControlFlow::Continue(())
499    }
500
501    fn visit_expression(&mut self, _: &'ast Expression) -> ControlFlow<Self::BreakTy> {
502        ControlFlow::Continue(())
503    }
504
505    fn visit_function_expression(
506        &mut self,
507        node: &'ast FunctionExpression,
508    ) -> ControlFlow<Self::BreakTy> {
509        if let Some(ident) = node.name() {
510            self.0.add(ident.sym(), true);
511        }
512        ControlFlow::Continue(())
513    }
514
515    fn visit_function_declaration(
516        &mut self,
517        node: &'ast FunctionDeclaration,
518    ) -> ControlFlow<Self::BreakTy> {
519        self.0.add(node.name().sym(), true);
520        ControlFlow::Continue(())
521    }
522
523    fn visit_generator_expression(
524        &mut self,
525        node: &'ast GeneratorExpression,
526    ) -> ControlFlow<Self::BreakTy> {
527        if let Some(ident) = node.name() {
528            self.0.add(ident.sym(), false);
529        }
530        ControlFlow::Continue(())
531    }
532
533    fn visit_generator_declaration(
534        &mut self,
535        node: &'ast GeneratorDeclaration,
536    ) -> ControlFlow<Self::BreakTy> {
537        self.0.add(node.name().sym(), false);
538        ControlFlow::Continue(())
539    }
540
541    fn visit_async_function_expression(
542        &mut self,
543        node: &'ast AsyncFunctionExpression,
544    ) -> ControlFlow<Self::BreakTy> {
545        if let Some(ident) = node.name() {
546            self.0.add(ident.sym(), false);
547        }
548        ControlFlow::Continue(())
549    }
550
551    fn visit_async_function_declaration(
552        &mut self,
553        node: &'ast AsyncFunctionDeclaration,
554    ) -> ControlFlow<Self::BreakTy> {
555        self.0.add(node.name().sym(), false);
556        ControlFlow::Continue(())
557    }
558
559    fn visit_async_generator_expression(
560        &mut self,
561        node: &'ast AsyncGeneratorExpression,
562    ) -> ControlFlow<Self::BreakTy> {
563        if let Some(ident) = node.name() {
564            self.0.add(ident.sym(), false);
565        }
566        ControlFlow::Continue(())
567    }
568
569    fn visit_async_generator_declaration(
570        &mut self,
571        node: &'ast AsyncGeneratorDeclaration,
572    ) -> ControlFlow<Self::BreakTy> {
573        self.0.add(node.name().sym(), false);
574        ControlFlow::Continue(())
575    }
576
577    fn visit_class_expression(
578        &mut self,
579        node: &'ast ClassExpression,
580    ) -> ControlFlow<Self::BreakTy> {
581        if let Some(ident) = node.name() {
582            self.0.add(ident.sym(), false);
583        }
584        ControlFlow::Continue(())
585    }
586
587    fn visit_class_declaration(
588        &mut self,
589        node: &'ast ClassDeclaration,
590    ) -> ControlFlow<Self::BreakTy> {
591        self.0.add(node.name().sym(), false);
592        ControlFlow::Continue(())
593    }
594
595    fn visit_export_declaration(
596        &mut self,
597        node: &'ast ExportDeclaration,
598    ) -> ControlFlow<Self::BreakTy> {
599        match node {
600            ExportDeclaration::VarStatement(var) => self.visit_var_declaration(var)?,
601            ExportDeclaration::Declaration(decl) => self.visit_declaration(decl)?,
602            ExportDeclaration::DefaultFunctionDeclaration(f) => {
603                self.0.add(f.name().sym(), true);
604            }
605            ExportDeclaration::DefaultGeneratorDeclaration(g) => {
606                self.0.add(g.name().sym(), false);
607            }
608            ExportDeclaration::DefaultAsyncFunctionDeclaration(af) => {
609                self.0.add(af.name().sym(), false);
610            }
611            ExportDeclaration::DefaultAsyncGeneratorDeclaration(ag) => {
612                self.0.add(ag.name().sym(), false);
613            }
614            ExportDeclaration::DefaultClassDeclaration(cl) => {
615                self.0.add(cl.name().sym(), false);
616            }
617            ExportDeclaration::DefaultAssignmentExpression(_) => {
618                self.0.add(Sym::DEFAULT_EXPORT, false);
619            }
620            ExportDeclaration::ReExport { .. } | ExportDeclaration::List(_) => {}
621        }
622
623        ControlFlow::Continue(())
624    }
625}
626
627/// Returns a list with the bound names of an AST node, which may contain duplicates.
628///
629/// This is equivalent to the [`BoundNames`][spec] syntax operation in the spec.
630///
631/// [spec]: https://tc39.es/ecma262/#sec-static-semantics-boundnames
632#[must_use]
633pub fn bound_names<'a, N>(node: &'a N) -> Vec<Sym>
634where
635    &'a N: Into<NodeRef<'a>>,
636{
637    let mut names = Vec::new();
638    let _ = BoundNamesVisitor(&mut names).visit(node.into());
639
640    names
641}
642
643/// The [`Visitor`] used to obtain the lexically declared names of a node.
644#[derive(Debug)]
645struct LexicallyDeclaredNamesVisitor<'a, T: IdentList>(&'a mut T);
646
647impl<'ast, T: IdentList> Visitor<'ast> for LexicallyDeclaredNamesVisitor<'_, T> {
648    type BreakTy = Infallible;
649
650    fn visit_script(&mut self, node: &'ast Script) -> ControlFlow<Self::BreakTy> {
651        top_level_lexicals(node.statements(), self.0);
652        ControlFlow::Continue(())
653    }
654
655    fn visit_function_body(&mut self, node: &'ast FunctionBody) -> ControlFlow<Self::BreakTy> {
656        top_level_lexicals(node.statement_list(), self.0);
657        ControlFlow::Continue(())
658    }
659
660    fn visit_module_item(&mut self, node: &'ast ModuleItem) -> ControlFlow<Self::BreakTy> {
661        match node {
662            // ModuleItem : ImportDeclaration
663            ModuleItem::ImportDeclaration(import) => {
664                // 1. Return the BoundNames of ImportDeclaration.
665                BoundNamesVisitor(self.0).visit_import_declaration(import)
666            }
667
668            // ModuleItem : ExportDeclaration
669            ModuleItem::ExportDeclaration(export) => {
670                // 1. If ExportDeclaration is export VariableStatement, return a new empty List.
671                if matches!(export.as_ref(), ExportDeclaration::VarStatement(_)) {
672                    ControlFlow::Continue(())
673                } else {
674                    // 2. Return the BoundNames of ExportDeclaration.
675                    BoundNamesVisitor(self.0).visit_export_declaration(export)
676                }
677            }
678
679            // ModuleItem : StatementListItem
680            ModuleItem::StatementListItem(item) => {
681                // 1. Return LexicallyDeclaredNames of StatementListItem.
682                self.visit_statement_list_item(item)
683            }
684        }
685    }
686
687    fn visit_expression(&mut self, _: &'ast Expression) -> ControlFlow<Self::BreakTy> {
688        ControlFlow::Continue(())
689    }
690
691    fn visit_statement(&mut self, node: &'ast Statement) -> ControlFlow<Self::BreakTy> {
692        if let Statement::Labelled(labelled) = node {
693            return self.visit_labelled(labelled);
694        }
695        ControlFlow::Continue(())
696    }
697
698    fn visit_declaration(&mut self, node: &'ast Declaration) -> ControlFlow<Self::BreakTy> {
699        BoundNamesVisitor(self.0).visit_declaration(node)
700    }
701
702    fn visit_labelled_item(&mut self, node: &'ast LabelledItem) -> ControlFlow<Self::BreakTy> {
703        match node {
704            LabelledItem::FunctionDeclaration(f) => {
705                BoundNamesVisitor(self.0).visit_function_declaration(f)
706            }
707            LabelledItem::Statement(_) => ControlFlow::Continue(()),
708        }
709    }
710
711    fn visit_function_expression(
712        &mut self,
713        node: &'ast FunctionExpression,
714    ) -> ControlFlow<Self::BreakTy> {
715        self.visit_function_body(node.body())
716    }
717
718    fn visit_function_declaration(
719        &mut self,
720        node: &'ast FunctionDeclaration,
721    ) -> ControlFlow<Self::BreakTy> {
722        self.visit_function_body(node.body())
723    }
724
725    fn visit_async_function_expression(
726        &mut self,
727        node: &'ast AsyncFunctionExpression,
728    ) -> ControlFlow<Self::BreakTy> {
729        self.visit_function_body(node.body())
730    }
731
732    fn visit_async_function_declaration(
733        &mut self,
734        node: &'ast AsyncFunctionDeclaration,
735    ) -> ControlFlow<Self::BreakTy> {
736        self.visit_function_body(node.body())
737    }
738
739    fn visit_generator_expression(
740        &mut self,
741        node: &'ast GeneratorExpression,
742    ) -> ControlFlow<Self::BreakTy> {
743        self.visit_function_body(node.body())
744    }
745
746    fn visit_generator_declaration(
747        &mut self,
748        node: &'ast GeneratorDeclaration,
749    ) -> ControlFlow<Self::BreakTy> {
750        self.visit_function_body(node.body())
751    }
752
753    fn visit_async_generator_expression(
754        &mut self,
755        node: &'ast AsyncGeneratorExpression,
756    ) -> ControlFlow<Self::BreakTy> {
757        self.visit_function_body(node.body())
758    }
759
760    fn visit_async_generator_declaration(
761        &mut self,
762        node: &'ast AsyncGeneratorDeclaration,
763    ) -> ControlFlow<Self::BreakTy> {
764        self.visit_function_body(node.body())
765    }
766
767    fn visit_arrow_function(&mut self, node: &'ast ArrowFunction) -> ControlFlow<Self::BreakTy> {
768        self.visit_function_body(node.body())
769    }
770
771    fn visit_async_arrow_function(
772        &mut self,
773        node: &'ast AsyncArrowFunction,
774    ) -> ControlFlow<Self::BreakTy> {
775        self.visit_function_body(node.body())
776    }
777
778    fn visit_class_element(&mut self, node: &'ast ClassElement) -> ControlFlow<Self::BreakTy> {
779        if let ClassElement::StaticBlock(block) = node {
780            self.visit_function_body(&block.body)?;
781        }
782        ControlFlow::Continue(())
783    }
784
785    fn visit_import_declaration(
786        &mut self,
787        node: &'ast ImportDeclaration,
788    ) -> ControlFlow<Self::BreakTy> {
789        BoundNamesVisitor(self.0).visit_import_declaration(node)
790    }
791
792    fn visit_export_declaration(
793        &mut self,
794        node: &'ast ExportDeclaration,
795    ) -> ControlFlow<Self::BreakTy> {
796        if matches!(node, ExportDeclaration::VarStatement(_)) {
797            return ControlFlow::Continue(());
798        }
799        BoundNamesVisitor(self.0).visit_export_declaration(node)
800    }
801}
802
803/// Returns a list with the lexical bindings of a node, which may contain duplicates.
804///
805/// This is equivalent to the [`LexicallyDeclaredNames`][spec] syntax operation in the spec.
806///
807/// [spec]: https://tc39.es/ecma262/#sec-static-semantics-lexicallydeclarednames
808#[must_use]
809pub fn lexically_declared_names<'a, N>(node: &'a N) -> Vec<Sym>
810where
811    &'a N: Into<NodeRef<'a>>,
812{
813    let mut names = Vec::new();
814    let _ = LexicallyDeclaredNamesVisitor(&mut names).visit(node.into());
815    names
816}
817
818/// Returns a list with the lexical bindings of a node, which may contain duplicates.
819///
820/// If a declared name originates from a function declaration it is flagged as `true` in the returned
821/// list. (See [B.3.2.4 Changes to Block Static Semantics: Early Errors])
822///
823/// [spec]: https://tc39.es/ecma262/#sec-static-semantics-lexicallydeclarednames
824/// [changes]: https://tc39.es/ecma262/#sec-block-duplicates-allowed-static-semantics
825#[must_use]
826pub fn lexically_declared_names_legacy<'a, N>(node: &'a N) -> Vec<(Sym, bool)>
827where
828    &'a N: Into<NodeRef<'a>>,
829{
830    let mut names = Vec::new();
831    let _ = LexicallyDeclaredNamesVisitor(&mut names).visit(node.into());
832    names
833}
834
835/// The [`Visitor`] used to obtain the var declared names of a node.
836#[derive(Debug)]
837struct VarDeclaredNamesVisitor<'a>(&'a mut FxHashSet<Sym>);
838
839impl<'ast> Visitor<'ast> for VarDeclaredNamesVisitor<'_> {
840    type BreakTy = Infallible;
841
842    fn visit_script(&mut self, node: &'ast Script) -> ControlFlow<Self::BreakTy> {
843        top_level_vars(node.statements(), self.0);
844        ControlFlow::Continue(())
845    }
846
847    fn visit_function_body(&mut self, node: &'ast FunctionBody) -> ControlFlow<Self::BreakTy> {
848        top_level_vars(node.statement_list(), self.0);
849        ControlFlow::Continue(())
850    }
851
852    fn visit_module_item(&mut self, node: &'ast ModuleItem) -> ControlFlow<Self::BreakTy> {
853        match node {
854            // ModuleItem : ImportDeclaration
855            ModuleItem::ImportDeclaration(_) => {
856                // 1. Return a new empty List.
857                ControlFlow::Continue(())
858            }
859
860            // ModuleItem : ExportDeclaration
861            ModuleItem::ExportDeclaration(export) => {
862                // 1. If ExportDeclaration is export VariableStatement, return BoundNames of ExportDeclaration.
863                if let ExportDeclaration::VarStatement(var) = export.as_ref() {
864                    BoundNamesVisitor(self.0).visit_var_declaration(var)
865                } else {
866                    // 2. Return a new empty List.
867                    ControlFlow::Continue(())
868                }
869            }
870
871            ModuleItem::StatementListItem(item) => self.visit_statement_list_item(item),
872        }
873    }
874
875    fn visit_statement(&mut self, node: &'ast Statement) -> ControlFlow<Self::BreakTy> {
876        match node {
877            Statement::Empty
878            | Statement::Debugger
879            | Statement::Expression(_)
880            | Statement::Continue(_)
881            | Statement::Break(_)
882            | Statement::Return(_)
883            | Statement::Throw(_) => ControlFlow::Continue(()),
884            Statement::Block(node) => self.visit(node),
885            Statement::Var(node) => self.visit(node),
886            Statement::If(node) => self.visit(node),
887            Statement::DoWhileLoop(node) => self.visit(node),
888            Statement::WhileLoop(node) => self.visit(node),
889            Statement::ForLoop(node) => self.visit(node),
890            Statement::ForInLoop(node) => self.visit(node),
891            Statement::ForOfLoop(node) => self.visit(node),
892            Statement::Switch(node) => self.visit(node),
893            Statement::Labelled(node) => self.visit(node),
894            Statement::Try(node) => self.visit(node),
895            Statement::With(node) => self.visit(node),
896        }
897    }
898
899    fn visit_statement_list_item(
900        &mut self,
901        node: &'ast StatementListItem,
902    ) -> ControlFlow<Self::BreakTy> {
903        match node {
904            StatementListItem::Statement(stmt) => self.visit_statement(stmt),
905            StatementListItem::Declaration(_) => ControlFlow::Continue(()),
906        }
907    }
908
909    fn visit_variable(&mut self, node: &'ast Variable) -> ControlFlow<Self::BreakTy> {
910        BoundNamesVisitor(self.0).visit_variable(node)
911    }
912
913    fn visit_if(&mut self, node: &'ast crate::statement::If) -> ControlFlow<Self::BreakTy> {
914        if let Some(node) = node.else_node() {
915            self.visit(node)?;
916        }
917        self.visit(node.body())
918    }
919
920    fn visit_do_while_loop(
921        &mut self,
922        node: &'ast crate::statement::DoWhileLoop,
923    ) -> ControlFlow<Self::BreakTy> {
924        self.visit(node.body())
925    }
926
927    fn visit_while_loop(
928        &mut self,
929        node: &'ast crate::statement::WhileLoop,
930    ) -> ControlFlow<Self::BreakTy> {
931        self.visit(node.body())
932    }
933
934    fn visit_for_loop(
935        &mut self,
936        node: &'ast crate::statement::ForLoop,
937    ) -> ControlFlow<Self::BreakTy> {
938        if let Some(ForLoopInitializer::Var(node)) = node.init() {
939            BoundNamesVisitor(self.0).visit_var_declaration(node)?;
940        }
941        self.visit(node.body())
942    }
943
944    fn visit_for_in_loop(
945        &mut self,
946        node: &'ast crate::statement::ForInLoop,
947    ) -> ControlFlow<Self::BreakTy> {
948        if let IterableLoopInitializer::Var(node) = node.initializer() {
949            BoundNamesVisitor(self.0).visit_variable(node)?;
950        }
951        self.visit(node.body())
952    }
953
954    fn visit_for_of_loop(
955        &mut self,
956        node: &'ast crate::statement::ForOfLoop,
957    ) -> ControlFlow<Self::BreakTy> {
958        if let IterableLoopInitializer::Var(node) = node.initializer() {
959            BoundNamesVisitor(self.0).visit_variable(node)?;
960        }
961        self.visit(node.body())
962    }
963
964    fn visit_with(&mut self, node: &'ast With) -> ControlFlow<Self::BreakTy> {
965        self.visit(node.statement())
966    }
967
968    fn visit_switch(&mut self, node: &'ast crate::statement::Switch) -> ControlFlow<Self::BreakTy> {
969        for case in node.cases() {
970            self.visit(case)?;
971        }
972        if let Some(node) = node.default() {
973            self.visit(node)?;
974        }
975        ControlFlow::Continue(())
976    }
977
978    fn visit_labelled_item(&mut self, node: &'ast LabelledItem) -> ControlFlow<Self::BreakTy> {
979        match node {
980            LabelledItem::FunctionDeclaration(_) => ControlFlow::Continue(()),
981            LabelledItem::Statement(stmt) => self.visit(stmt),
982        }
983    }
984
985    fn visit_try(&mut self, node: &'ast crate::statement::Try) -> ControlFlow<Self::BreakTy> {
986        if let Some(node) = node.finally() {
987            self.visit(node)?;
988        }
989        if let Some(node) = node.catch() {
990            self.visit(node.block())?;
991        }
992        self.visit(node.block())
993    }
994
995    fn visit_function_expression(
996        &mut self,
997        node: &'ast FunctionExpression,
998    ) -> ControlFlow<Self::BreakTy> {
999        self.visit_function_body(node.body())
1000    }
1001
1002    fn visit_function_declaration(
1003        &mut self,
1004        node: &'ast FunctionDeclaration,
1005    ) -> ControlFlow<Self::BreakTy> {
1006        self.visit_function_body(node.body())
1007    }
1008
1009    fn visit_async_function_expression(
1010        &mut self,
1011        node: &'ast AsyncFunctionExpression,
1012    ) -> ControlFlow<Self::BreakTy> {
1013        self.visit_function_body(node.body())
1014    }
1015
1016    fn visit_async_function_declaration(
1017        &mut self,
1018        node: &'ast AsyncFunctionDeclaration,
1019    ) -> ControlFlow<Self::BreakTy> {
1020        self.visit_function_body(node.body())
1021    }
1022
1023    fn visit_generator_expression(
1024        &mut self,
1025        node: &'ast GeneratorExpression,
1026    ) -> ControlFlow<Self::BreakTy> {
1027        self.visit_function_body(node.body())
1028    }
1029
1030    fn visit_generator_declaration(
1031        &mut self,
1032        node: &'ast GeneratorDeclaration,
1033    ) -> ControlFlow<Self::BreakTy> {
1034        self.visit_function_body(node.body())
1035    }
1036
1037    fn visit_async_generator_expression(
1038        &mut self,
1039        node: &'ast AsyncGeneratorExpression,
1040    ) -> ControlFlow<Self::BreakTy> {
1041        self.visit_function_body(node.body())
1042    }
1043
1044    fn visit_async_generator_declaration(
1045        &mut self,
1046        node: &'ast AsyncGeneratorDeclaration,
1047    ) -> ControlFlow<Self::BreakTy> {
1048        self.visit_function_body(node.body())
1049    }
1050
1051    fn visit_class_element(&mut self, node: &'ast ClassElement) -> ControlFlow<Self::BreakTy> {
1052        if let ClassElement::StaticBlock(block) = node {
1053            self.visit_function_body(&block.body)?;
1054        }
1055        node.visit_with(self)
1056    }
1057
1058    fn visit_import_declaration(
1059        &mut self,
1060        _: &'ast ImportDeclaration,
1061    ) -> ControlFlow<Self::BreakTy> {
1062        ControlFlow::Continue(())
1063    }
1064
1065    fn visit_export_declaration(
1066        &mut self,
1067        node: &'ast ExportDeclaration,
1068    ) -> ControlFlow<Self::BreakTy> {
1069        match node {
1070            ExportDeclaration::VarStatement(var) => {
1071                BoundNamesVisitor(self.0).visit_var_declaration(var)
1072            }
1073            _ => ControlFlow::Continue(()),
1074        }
1075    }
1076}
1077
1078/// Returns a set with the var bindings of a node, with no duplicates.
1079///
1080/// This is equivalent to the [`VarDeclaredNames`][spec] syntax operation in the spec.
1081///
1082/// [spec]: https://tc39.es/ecma262/#sec-static-semantics-vardeclarednames
1083#[must_use]
1084pub fn var_declared_names<'a, N>(node: &'a N) -> FxHashSet<Sym>
1085where
1086    &'a N: Into<NodeRef<'a>>,
1087{
1088    let mut names = FxHashSet::default();
1089    let _ = VarDeclaredNamesVisitor(&mut names).visit(node.into());
1090    names
1091}
1092
1093/// Utility function that collects the top level lexicals of a statement list into `names`.
1094///
1095/// This is equivalent to the [`TopLevelLexicallyDeclaredNames`][spec] syntax operation in the spec.
1096///
1097/// [spec]: https://tc39.es/ecma262/#sec-static-semantics-toplevellexicallydeclarednames
1098fn top_level_lexicals<T: IdentList>(stmts: &StatementList, names: &mut T) {
1099    for stmt in stmts.statements() {
1100        if let StatementListItem::Declaration(decl) = stmt {
1101            match decl.as_ref() {
1102                // Note
1103                // At the top level of a function, or script, function declarations are treated like
1104                // var declarations rather than like lexical declarations.
1105                Declaration::FunctionDeclaration(_)
1106                | Declaration::GeneratorDeclaration(_)
1107                | Declaration::AsyncFunctionDeclaration(_)
1108                | Declaration::AsyncGeneratorDeclaration(_) => {}
1109                Declaration::ClassDeclaration(class) => {
1110                    let _ = BoundNamesVisitor(names).visit_class_declaration(class);
1111                }
1112                Declaration::Lexical(decl) => {
1113                    let _ = BoundNamesVisitor(names).visit_lexical_declaration(decl);
1114                }
1115            }
1116        }
1117    }
1118}
1119
1120/// Utility function that collects the top level vars of a statement list into `names`.
1121///
1122/// This is equivalent to the [`TopLevelVarDeclaredNames`][spec] syntax operation in the spec.
1123///
1124/// [spec]: https://tc39.es/ecma262/#sec-static-semantics-toplevelvardeclarednames
1125fn top_level_vars(stmts: &StatementList, names: &mut FxHashSet<Sym>) {
1126    for stmt in stmts.statements() {
1127        match stmt {
1128            StatementListItem::Declaration(decl) => {
1129                match decl.as_ref() {
1130                    // Note
1131                    // At the top level of a function, or script, function declarations are treated like
1132                    // var declarations rather than like lexical declarations.
1133                    Declaration::FunctionDeclaration(f) => {
1134                        let _ = BoundNamesVisitor(names).visit_function_declaration(f);
1135                    }
1136                    Declaration::GeneratorDeclaration(f) => {
1137                        let _ = BoundNamesVisitor(names).visit_generator_declaration(f);
1138                    }
1139                    Declaration::AsyncFunctionDeclaration(f) => {
1140                        let _ = BoundNamesVisitor(names).visit_async_function_declaration(f);
1141                    }
1142                    Declaration::AsyncGeneratorDeclaration(f) => {
1143                        let _ = BoundNamesVisitor(names).visit_async_generator_declaration(f);
1144                    }
1145                    Declaration::ClassDeclaration(_) | Declaration::Lexical(_) => {}
1146                }
1147            }
1148            StatementListItem::Statement(stmt) => {
1149                let mut stmt = Some(stmt.as_ref());
1150                while let Some(Statement::Labelled(labelled)) = stmt.as_ref() {
1151                    match labelled.item() {
1152                        LabelledItem::FunctionDeclaration(f) => {
1153                            let _ = BoundNamesVisitor(names).visit_function_declaration(f);
1154                            stmt = None;
1155                        }
1156                        LabelledItem::Statement(s) => stmt = Some(s),
1157                    }
1158                }
1159                if let Some(stmt) = stmt {
1160                    let _ = VarDeclaredNamesVisitor(names).visit(stmt);
1161                }
1162            }
1163        }
1164    }
1165}
1166
1167/// Returns `true` if all private identifiers in a node are valid.
1168///
1169/// This is equivalent to the [`AllPrivateIdentifiersValid`][spec] syntax operation in the spec.
1170///
1171/// [spec]: https://tc39.es/ecma262/#sec-static-semantics-allprivateidentifiersvalid
1172#[must_use]
1173#[inline]
1174pub fn all_private_identifiers_valid<'a, N>(node: &'a N, private_names: Vec<Sym>) -> bool
1175where
1176    &'a N: Into<NodeRef<'a>>,
1177{
1178    AllPrivateIdentifiersValidVisitor(private_names)
1179        .visit(node.into())
1180        .is_continue()
1181}
1182
1183struct AllPrivateIdentifiersValidVisitor(Vec<Sym>);
1184
1185impl<'ast> Visitor<'ast> for AllPrivateIdentifiersValidVisitor {
1186    type BreakTy = ();
1187
1188    fn visit_class_expression(
1189        &mut self,
1190        node: &'ast ClassExpression,
1191    ) -> ControlFlow<Self::BreakTy> {
1192        if let Some(node) = node.super_ref() {
1193            self.visit(node)?;
1194        }
1195
1196        let mut names = self.0.clone();
1197        for element in node.elements() {
1198            match element {
1199                ClassElement::MethodDefinition(m) => {
1200                    if let ClassElementName::PrivateName(name) = m.name() {
1201                        names.push(name.description());
1202                    }
1203                }
1204                ClassElement::PrivateFieldDefinition(PrivateFieldDefinition { name, .. })
1205                | ClassElement::PrivateStaticFieldDefinition(PrivateFieldDefinition {
1206                    name, ..
1207                }) => {
1208                    names.push(name.description());
1209                }
1210                _ => {}
1211            }
1212        }
1213
1214        let mut visitor = Self(names);
1215
1216        if let Some(node) = node.constructor() {
1217            visitor.visit(node)?;
1218        }
1219
1220        for element in node.elements() {
1221            match element {
1222                ClassElement::MethodDefinition(m) => {
1223                    if let ClassElementName::PropertyName(name) = m.name() {
1224                        visitor.visit(name)?;
1225                    }
1226                    visitor.visit(m.parameters())?;
1227                    visitor.visit(m.body())?;
1228                }
1229                ClassElement::FieldDefinition(field)
1230                | ClassElement::StaticFieldDefinition(field) => {
1231                    visitor.visit(&field.name)?;
1232                    if let Some(expression) = &field.initializer {
1233                        visitor.visit(expression)?;
1234                    }
1235                }
1236                ClassElement::PrivateFieldDefinition(PrivateFieldDefinition {
1237                    initializer,
1238                    ..
1239                })
1240                | ClassElement::PrivateStaticFieldDefinition(PrivateFieldDefinition {
1241                    initializer,
1242                    ..
1243                }) => {
1244                    if let Some(expression) = initializer {
1245                        visitor.visit(expression)?;
1246                    }
1247                }
1248                ClassElement::StaticBlock(block) => {
1249                    visitor.visit(&block.body)?;
1250                }
1251            }
1252        }
1253
1254        ControlFlow::Continue(())
1255    }
1256
1257    fn visit_class_declaration(
1258        &mut self,
1259        node: &'ast ClassDeclaration,
1260    ) -> ControlFlow<Self::BreakTy> {
1261        if let Some(node) = node.super_ref() {
1262            self.visit(node)?;
1263        }
1264
1265        let mut names = self.0.clone();
1266        for element in node.elements() {
1267            match element {
1268                ClassElement::MethodDefinition(m) => {
1269                    if let ClassElementName::PrivateName(name) = m.name() {
1270                        names.push(name.description());
1271                    }
1272                }
1273                ClassElement::PrivateFieldDefinition(PrivateFieldDefinition { name, .. })
1274                | ClassElement::PrivateStaticFieldDefinition(PrivateFieldDefinition {
1275                    name, ..
1276                }) => {
1277                    names.push(name.description());
1278                }
1279                _ => {}
1280            }
1281        }
1282
1283        let mut visitor = Self(names);
1284
1285        if let Some(node) = node.constructor() {
1286            visitor.visit(node)?;
1287        }
1288
1289        for element in node.elements() {
1290            match element {
1291                ClassElement::MethodDefinition(m) => {
1292                    if let ClassElementName::PropertyName(name) = m.name() {
1293                        visitor.visit(name)?;
1294                    }
1295                    visitor.visit(m.parameters())?;
1296                    visitor.visit(m.body())?;
1297                }
1298                ClassElement::FieldDefinition(field)
1299                | ClassElement::StaticFieldDefinition(field) => {
1300                    visitor.visit(&field.name)?;
1301                    if let Some(expression) = &field.initializer {
1302                        visitor.visit(expression)?;
1303                    }
1304                }
1305                ClassElement::PrivateFieldDefinition(PrivateFieldDefinition {
1306                    initializer,
1307                    ..
1308                })
1309                | ClassElement::PrivateStaticFieldDefinition(PrivateFieldDefinition {
1310                    initializer,
1311                    ..
1312                }) => {
1313                    if let Some(expression) = initializer {
1314                        visitor.visit(expression)?;
1315                    }
1316                }
1317                ClassElement::StaticBlock(block) => {
1318                    visitor.visit(&block.body)?;
1319                }
1320            }
1321        }
1322
1323        ControlFlow::Continue(())
1324    }
1325
1326    fn visit_private_property_access(
1327        &mut self,
1328        node: &'ast PrivatePropertyAccess,
1329    ) -> ControlFlow<Self::BreakTy> {
1330        if self.0.contains(&node.field().description()) {
1331            self.visit(node.target())
1332        } else {
1333            ControlFlow::Break(())
1334        }
1335    }
1336
1337    fn visit_binary_in_private(
1338        &mut self,
1339        node: &'ast BinaryInPrivate,
1340    ) -> ControlFlow<Self::BreakTy> {
1341        if self.0.contains(&node.lhs().description()) {
1342            self.visit(node.rhs())
1343        } else {
1344            ControlFlow::Break(())
1345        }
1346    }
1347
1348    fn visit_optional_operation_kind(
1349        &mut self,
1350        node: &'ast OptionalOperationKind,
1351    ) -> ControlFlow<Self::BreakTy> {
1352        match node {
1353            OptionalOperationKind::SimplePropertyAccess { field } => {
1354                self.visit_property_access_field(field)
1355            }
1356            OptionalOperationKind::PrivatePropertyAccess { field } => {
1357                if self.0.contains(&field.description()) {
1358                    ControlFlow::Continue(())
1359                } else {
1360                    ControlFlow::Break(())
1361                }
1362            }
1363            OptionalOperationKind::Call { args } => {
1364                for arg in args {
1365                    self.visit_expression(arg)?;
1366                }
1367                ControlFlow::Continue(())
1368            }
1369        }
1370    }
1371}
1372
1373/// Errors that can occur when checking labels.
1374#[derive(Debug, Clone, Copy)]
1375pub enum CheckLabelsError {
1376    /// A label was used multiple times.
1377    DuplicateLabel(Sym),
1378
1379    /// A `break` statement was used with a label that was not defined.
1380    UndefinedBreakTarget(Sym),
1381
1382    /// A `continue` statement was used with a label that was not defined.
1383    UndefinedContinueTarget(Sym),
1384
1385    /// A `break` statement was used in a non-looping context.
1386    IllegalBreakStatement,
1387
1388    /// A `continue` statement was used in a non-looping context.
1389    IllegalContinueStatement,
1390}
1391
1392impl CheckLabelsError {
1393    /// Returns an error message based on the error.
1394    #[must_use]
1395    pub fn message(&self, interner: &Interner) -> String {
1396        match self {
1397            Self::DuplicateLabel(label) => {
1398                format!("duplicate label: {}", interner.resolve_expect(*label))
1399            }
1400            Self::UndefinedBreakTarget(label) => {
1401                format!(
1402                    "undefined break target: {}",
1403                    interner.resolve_expect(*label)
1404                )
1405            }
1406            Self::UndefinedContinueTarget(label) => format!(
1407                "undefined continue target: {}",
1408                interner.resolve_expect(*label)
1409            ),
1410            Self::IllegalBreakStatement => "illegal break statement".into(),
1411            Self::IllegalContinueStatement => "illegal continue statement".into(),
1412        }
1413    }
1414}
1415
1416/// This function checks multiple syntax errors conditions for labels, `break` and `continue`.
1417///
1418/// The following syntax errors are checked:
1419/// - [`ContainsDuplicateLabels`][ContainsDuplicateLabels]
1420/// - [`ContainsUndefinedBreakTarget`][ContainsUndefinedBreakTarget]
1421/// - [`ContainsUndefinedContinueTarget`][ContainsUndefinedContinueTarget]
1422/// - Early errors for [`BreakStatement`][BreakStatement]
1423/// - Early errors for [`ContinueStatement`][ContinueStatement]
1424///
1425/// [ContainsDuplicateLabels]: https://tc39.es/ecma262/#sec-static-semantics-containsduplicatelabels
1426/// [ContainsUndefinedBreakTarget]: https://tc39.es/ecma262/#sec-static-semantics-containsundefinedbreaktarget
1427/// [ContainsUndefinedContinueTarget]: https://tc39.es/ecma262/#sec-static-semantics-containsundefinedcontinuetarget
1428/// [BreakStatement]: https://tc39.es/ecma262/#sec-break-statement-static-semantics-early-errors
1429/// [ContinueStatement]: https://tc39.es/ecma262/#sec-continue-statement-static-semantics-early-errors
1430///
1431/// # Errors
1432///
1433/// This function returns an error for the first syntax error that is found.
1434pub fn check_labels<N>(node: &N) -> Result<(), CheckLabelsError>
1435where
1436    N: VisitWith,
1437{
1438    #[derive(Debug, Clone)]
1439    struct CheckLabelsResolver {
1440        labels: FxHashSet<Sym>,
1441        continue_iteration_labels: FxHashSet<Sym>,
1442        continue_labels: Option<FxHashSet<Sym>>,
1443        iteration: bool,
1444        switch: bool,
1445    }
1446
1447    impl<'ast> Visitor<'ast> for CheckLabelsResolver {
1448        type BreakTy = CheckLabelsError;
1449
1450        fn visit_statement(&mut self, node: &'ast Statement) -> ControlFlow<Self::BreakTy> {
1451            match node {
1452                Statement::Block(node) => self.visit_block(node),
1453                Statement::Var(_)
1454                | Statement::Empty
1455                | Statement::Debugger
1456                | Statement::Expression(_)
1457                | Statement::Return(_)
1458                | Statement::Throw(_) => ControlFlow::Continue(()),
1459                Statement::If(node) => self.visit_if(node),
1460                Statement::DoWhileLoop(node) => self.visit_do_while_loop(node),
1461                Statement::WhileLoop(node) => self.visit_while_loop(node),
1462                Statement::ForLoop(node) => self.visit_for_loop(node),
1463                Statement::ForInLoop(node) => self.visit_for_in_loop(node),
1464                Statement::ForOfLoop(node) => self.visit_for_of_loop(node),
1465                Statement::Switch(node) => self.visit_switch(node),
1466                Statement::Labelled(node) => self.visit_labelled(node),
1467                Statement::Try(node) => self.visit_try(node),
1468                Statement::Continue(node) => self.visit_continue(node),
1469                Statement::Break(node) => self.visit_break(node),
1470                Statement::With(with) => self.visit_with(with),
1471            }
1472        }
1473
1474        fn visit_block(
1475            &mut self,
1476            node: &'ast crate::statement::Block,
1477        ) -> ControlFlow<Self::BreakTy> {
1478            let continue_labels = self.continue_labels.take();
1479            self.visit_statement_list(node.statement_list())?;
1480            self.continue_labels = continue_labels;
1481            ControlFlow::Continue(())
1482        }
1483
1484        fn visit_break(
1485            &mut self,
1486            node: &'ast crate::statement::Break,
1487        ) -> ControlFlow<Self::BreakTy> {
1488            if let Some(label) = node.label() {
1489                if !self.labels.contains(&label) {
1490                    return ControlFlow::Break(CheckLabelsError::UndefinedBreakTarget(label));
1491                }
1492            } else if !self.iteration && !self.switch {
1493                return ControlFlow::Break(CheckLabelsError::IllegalBreakStatement);
1494            }
1495            ControlFlow::Continue(())
1496        }
1497
1498        fn visit_continue(
1499            &mut self,
1500            node: &'ast crate::statement::Continue,
1501        ) -> ControlFlow<Self::BreakTy> {
1502            if !self.iteration {
1503                return ControlFlow::Break(CheckLabelsError::IllegalContinueStatement);
1504            }
1505
1506            if let Some(label) = node.label()
1507                && !self.continue_iteration_labels.contains(&label)
1508            {
1509                return ControlFlow::Break(CheckLabelsError::UndefinedContinueTarget(label));
1510            }
1511            ControlFlow::Continue(())
1512        }
1513
1514        fn visit_do_while_loop(
1515            &mut self,
1516            node: &'ast crate::statement::DoWhileLoop,
1517        ) -> ControlFlow<Self::BreakTy> {
1518            let continue_labels = self.continue_labels.take();
1519            let continue_iteration_labels = self.continue_iteration_labels.clone();
1520            if let Some(continue_labels) = &continue_labels {
1521                self.continue_iteration_labels.extend(continue_labels);
1522            }
1523            let iteration = self.iteration;
1524            self.iteration = true;
1525            self.visit_statement(node.body())?;
1526            self.continue_iteration_labels = continue_iteration_labels;
1527            self.continue_labels = continue_labels;
1528            self.iteration = iteration;
1529            ControlFlow::Continue(())
1530        }
1531
1532        fn visit_while_loop(
1533            &mut self,
1534            node: &'ast crate::statement::WhileLoop,
1535        ) -> ControlFlow<Self::BreakTy> {
1536            let continue_labels = self.continue_labels.take();
1537            let continue_iteration_labels = self.continue_iteration_labels.clone();
1538            if let Some(continue_labels) = &continue_labels {
1539                self.continue_iteration_labels.extend(continue_labels);
1540            }
1541            let iteration = self.iteration;
1542            self.iteration = true;
1543            self.visit_statement(node.body())?;
1544            self.continue_iteration_labels = continue_iteration_labels;
1545            self.continue_labels = continue_labels;
1546            self.iteration = iteration;
1547            ControlFlow::Continue(())
1548        }
1549
1550        fn visit_for_loop(
1551            &mut self,
1552            node: &'ast crate::statement::ForLoop,
1553        ) -> ControlFlow<Self::BreakTy> {
1554            let continue_labels = self.continue_labels.take();
1555            let continue_iteration_labels = self.continue_iteration_labels.clone();
1556            if let Some(continue_labels) = &continue_labels {
1557                self.continue_iteration_labels.extend(continue_labels);
1558            }
1559            let iteration = self.iteration;
1560            self.iteration = true;
1561            self.visit_statement(node.body())?;
1562            self.continue_iteration_labels = continue_iteration_labels;
1563            self.continue_labels = continue_labels;
1564            self.iteration = iteration;
1565            ControlFlow::Continue(())
1566        }
1567
1568        fn visit_for_in_loop(
1569            &mut self,
1570            node: &'ast crate::statement::ForInLoop,
1571        ) -> ControlFlow<Self::BreakTy> {
1572            let continue_labels = self.continue_labels.take();
1573            let continue_iteration_labels = self.continue_iteration_labels.clone();
1574            if let Some(continue_labels) = &continue_labels {
1575                self.continue_iteration_labels.extend(continue_labels);
1576            }
1577            let iteration = self.iteration;
1578            self.iteration = true;
1579            self.visit_statement(node.body())?;
1580            self.continue_iteration_labels = continue_iteration_labels;
1581            self.continue_labels = continue_labels;
1582            self.iteration = iteration;
1583            ControlFlow::Continue(())
1584        }
1585
1586        fn visit_for_of_loop(
1587            &mut self,
1588            node: &'ast crate::statement::ForOfLoop,
1589        ) -> ControlFlow<Self::BreakTy> {
1590            let continue_labels = self.continue_labels.take();
1591            let continue_iteration_labels = self.continue_iteration_labels.clone();
1592            if let Some(continue_labels) = &continue_labels {
1593                self.continue_iteration_labels.extend(continue_labels);
1594            }
1595            let iteration = self.iteration;
1596            self.iteration = true;
1597            self.visit_statement(node.body())?;
1598            self.continue_iteration_labels = continue_iteration_labels;
1599            self.continue_labels = continue_labels;
1600            self.iteration = iteration;
1601            ControlFlow::Continue(())
1602        }
1603
1604        fn visit_statement_list_item(
1605            &mut self,
1606            node: &'ast StatementListItem,
1607        ) -> ControlFlow<Self::BreakTy> {
1608            let continue_labels = self.continue_labels.take();
1609            if let StatementListItem::Statement(stmt) = node {
1610                self.visit_statement(stmt)?;
1611            }
1612            self.continue_labels = continue_labels;
1613            ControlFlow::Continue(())
1614        }
1615
1616        fn visit_if(&mut self, node: &'ast crate::statement::If) -> ControlFlow<Self::BreakTy> {
1617            let continue_labels = self.continue_labels.take();
1618            self.visit_statement(node.body())?;
1619            if let Some(stmt) = node.else_node() {
1620                self.visit_statement(stmt)?;
1621            }
1622            self.continue_labels = continue_labels;
1623            ControlFlow::Continue(())
1624        }
1625
1626        fn visit_switch(
1627            &mut self,
1628            node: &'ast crate::statement::Switch,
1629        ) -> ControlFlow<Self::BreakTy> {
1630            let continue_labels = self.continue_labels.take();
1631            let switch = self.switch;
1632            self.switch = true;
1633            for case in node.cases() {
1634                self.visit_statement_list(case.body())?;
1635            }
1636            if let Some(default) = node.default() {
1637                self.visit_statement_list(default)?;
1638            }
1639            self.continue_labels = continue_labels;
1640            self.switch = switch;
1641            ControlFlow::Continue(())
1642        }
1643
1644        fn visit_labelled(
1645            &mut self,
1646            node: &'ast crate::statement::Labelled,
1647        ) -> ControlFlow<Self::BreakTy> {
1648            let continue_labels = self.continue_labels.clone();
1649            if let Some(continue_labels) = &mut self.continue_labels {
1650                continue_labels.insert(node.label());
1651            } else {
1652                let mut continue_labels = FxHashSet::default();
1653                continue_labels.insert(node.label());
1654                self.continue_labels = Some(continue_labels);
1655            }
1656
1657            if !self.labels.insert(node.label()) {
1658                return ControlFlow::Break(CheckLabelsError::DuplicateLabel(node.label()));
1659            }
1660            self.visit_labelled_item(node.item())?;
1661            self.labels.remove(&node.label());
1662            self.continue_labels = continue_labels;
1663            ControlFlow::Continue(())
1664        }
1665
1666        fn visit_labelled_item(&mut self, node: &'ast LabelledItem) -> ControlFlow<Self::BreakTy> {
1667            match node {
1668                LabelledItem::Statement(stmt) => self.visit_statement(stmt),
1669                LabelledItem::FunctionDeclaration(_) => ControlFlow::Continue(()),
1670            }
1671        }
1672
1673        fn visit_try(&mut self, node: &'ast crate::statement::Try) -> ControlFlow<Self::BreakTy> {
1674            let continue_labels = self.continue_labels.take();
1675            self.visit_block(node.block())?;
1676            if let Some(catch) = node.catch() {
1677                self.visit_block(catch.block())?;
1678            }
1679            if let Some(finally) = node.finally() {
1680                self.visit_block(finally.block())?;
1681            }
1682            self.continue_labels = continue_labels;
1683            ControlFlow::Continue(())
1684        }
1685
1686        fn visit_module_item_list(
1687            &mut self,
1688            node: &'ast crate::ModuleItemList,
1689        ) -> ControlFlow<Self::BreakTy> {
1690            let continue_labels = self.continue_labels.take();
1691            for item in node.items() {
1692                self.visit_module_item(item)?;
1693            }
1694            self.continue_labels = continue_labels;
1695            ControlFlow::Continue(())
1696        }
1697
1698        fn visit_module_item(&mut self, node: &'ast ModuleItem) -> ControlFlow<Self::BreakTy> {
1699            match node {
1700                ModuleItem::ImportDeclaration(_) | ModuleItem::ExportDeclaration(_) => {
1701                    ControlFlow::Continue(())
1702                }
1703                ModuleItem::StatementListItem(node) => self.visit_statement_list_item(node),
1704            }
1705        }
1706    }
1707
1708    let mut visitor = CheckLabelsResolver {
1709        labels: FxHashSet::default(),
1710        continue_iteration_labels: FxHashSet::default(),
1711        continue_labels: None,
1712        iteration: false,
1713        switch: false,
1714    };
1715
1716    if let ControlFlow::Break(error) = node.visit_with(&mut visitor) {
1717        Err(error)
1718    } else {
1719        Ok(())
1720    }
1721}
1722
1723/// Returns `true` if the given node contains a `CoverInitializedName`.
1724#[must_use]
1725pub fn contains_invalid_object_literal<N>(node: &N) -> bool
1726where
1727    N: VisitWith,
1728{
1729    #[derive(Debug, Clone)]
1730    struct ContainsInvalidObjectLiteral {}
1731
1732    impl<'ast> Visitor<'ast> for ContainsInvalidObjectLiteral {
1733        type BreakTy = ();
1734
1735        fn visit_object_literal(
1736            &mut self,
1737            node: &'ast crate::expression::literal::ObjectLiteral,
1738        ) -> ControlFlow<Self::BreakTy> {
1739            for pd in node.properties() {
1740                if let PropertyDefinition::CoverInitializedName(..) = pd {
1741                    return ControlFlow::Break(());
1742                }
1743                self.visit_property_definition(pd)?;
1744            }
1745            ControlFlow::Continue(())
1746        }
1747    }
1748
1749    let mut visitor = ContainsInvalidObjectLiteral {};
1750
1751    node.visit_with(&mut visitor).is_break()
1752}
1753
1754/// The type of a lexically scoped declaration.
1755#[derive(Copy, Clone, Debug)]
1756pub enum LexicallyScopedDeclaration<'a> {
1757    /// See [`LexicalDeclaration`]
1758    LexicalDeclaration(&'a LexicalDeclaration),
1759
1760    /// See [`FunctionDeclaration`]
1761    FunctionDeclaration(&'a FunctionDeclaration),
1762
1763    /// See [`GeneratorDeclaration`]
1764    GeneratorDeclaration(&'a GeneratorDeclaration),
1765
1766    /// See [`AsyncFunctionDeclaration`]
1767    AsyncFunctionDeclaration(&'a AsyncFunctionDeclaration),
1768
1769    /// See [`AsyncGeneratorDeclaration`]
1770    AsyncGeneratorDeclaration(&'a AsyncGeneratorDeclaration),
1771
1772    /// See [`ClassDeclaration`]
1773    ClassDeclaration(&'a ClassDeclaration),
1774
1775    /// A default assignment expression as an export declaration.
1776    ///
1777    /// Only valid inside module exports.
1778    AssignmentExpression(&'a Expression),
1779}
1780
1781impl LexicallyScopedDeclaration<'_> {
1782    /// Return the bound names of the declaration.
1783    #[must_use]
1784    pub fn bound_names(&self) -> Vec<Sym> {
1785        match *self {
1786            Self::LexicalDeclaration(v) => bound_names(v),
1787            Self::FunctionDeclaration(f) => bound_names(f),
1788            Self::GeneratorDeclaration(g) => bound_names(g),
1789            Self::AsyncFunctionDeclaration(f) => bound_names(f),
1790            Self::AsyncGeneratorDeclaration(g) => bound_names(g),
1791            Self::ClassDeclaration(cl) => bound_names(cl),
1792            Self::AssignmentExpression(expr) => bound_names(expr),
1793        }
1794    }
1795}
1796
1797impl<'ast> From<&'ast Declaration> for LexicallyScopedDeclaration<'ast> {
1798    fn from(value: &'ast Declaration) -> LexicallyScopedDeclaration<'ast> {
1799        match value {
1800            Declaration::FunctionDeclaration(f) => Self::FunctionDeclaration(f),
1801            Declaration::GeneratorDeclaration(g) => Self::GeneratorDeclaration(g),
1802            Declaration::AsyncFunctionDeclaration(af) => Self::AsyncFunctionDeclaration(af),
1803            Declaration::AsyncGeneratorDeclaration(ag) => Self::AsyncGeneratorDeclaration(ag),
1804            Declaration::ClassDeclaration(c) => Self::ClassDeclaration(c),
1805            Declaration::Lexical(lex) => Self::LexicalDeclaration(lex),
1806        }
1807    }
1808}
1809
1810/// Returns a list of lexically scoped declarations of the given node.
1811///
1812/// This is equivalent to the [`LexicallyScopedDeclarations`][spec] syntax operation in the spec.
1813///
1814/// [spec]: https://tc39.es/ecma262/#sec-static-semantics-lexicallyscopeddeclarations
1815#[must_use]
1816pub fn lexically_scoped_declarations<'a, N>(node: &'a N) -> Vec<LexicallyScopedDeclaration<'a>>
1817where
1818    &'a N: Into<NodeRef<'a>>,
1819{
1820    let mut declarations = Vec::new();
1821    let _ = LexicallyScopedDeclarationsVisitor(&mut declarations).visit(node.into());
1822    declarations
1823}
1824
1825/// The [`Visitor`] used to obtain the lexically scoped declarations of a node.
1826#[derive(Debug)]
1827struct LexicallyScopedDeclarationsVisitor<'a, 'ast>(&'a mut Vec<LexicallyScopedDeclaration<'ast>>);
1828
1829impl<'ast> Visitor<'ast> for LexicallyScopedDeclarationsVisitor<'_, 'ast> {
1830    type BreakTy = Infallible;
1831
1832    // ScriptBody : StatementList
1833    fn visit_script(&mut self, node: &'ast Script) -> ControlFlow<Self::BreakTy> {
1834        // 1. Return TopLevelLexicallyScopedDeclarations of StatementList.
1835        TopLevelLexicallyScopedDeclarationsVisitor(self.0).visit_statement_list(node.statements())
1836    }
1837
1838    fn visit_function_body(&mut self, node: &'ast FunctionBody) -> ControlFlow<Self::BreakTy> {
1839        // 1. Return TopLevelVarScopedDeclarations of StatementList.
1840        TopLevelLexicallyScopedDeclarationsVisitor(self.0)
1841            .visit_statement_list(node.statement_list())
1842    }
1843
1844    fn visit_export_declaration(
1845        &mut self,
1846        node: &'ast ExportDeclaration,
1847    ) -> ControlFlow<Self::BreakTy> {
1848        let decl = match node {
1849            // ExportDeclaration :
1850            // export ExportFromClause FromClause ;
1851            // export NamedExports ;
1852            // export VariableStatement
1853            ExportDeclaration::ReExport { .. }
1854            | ExportDeclaration::List(_)
1855            | ExportDeclaration::VarStatement(_) => {
1856                //     1. Return a new empty List.
1857                return ControlFlow::Continue(());
1858            }
1859
1860            // ExportDeclaration : export Declaration
1861            ExportDeclaration::Declaration(decl) => {
1862                // 1. Return a List whose sole element is DeclarationPart of Declaration.
1863                decl.into()
1864            }
1865
1866            // ExportDeclaration : export default HoistableDeclaration
1867            // 1. Return a List whose sole element is DeclarationPart of HoistableDeclaration.
1868            ExportDeclaration::DefaultFunctionDeclaration(f) => {
1869                LexicallyScopedDeclaration::FunctionDeclaration(f)
1870            }
1871            ExportDeclaration::DefaultGeneratorDeclaration(g) => {
1872                LexicallyScopedDeclaration::GeneratorDeclaration(g)
1873            }
1874            ExportDeclaration::DefaultAsyncFunctionDeclaration(af) => {
1875                LexicallyScopedDeclaration::AsyncFunctionDeclaration(af)
1876            }
1877            ExportDeclaration::DefaultAsyncGeneratorDeclaration(ag) => {
1878                LexicallyScopedDeclaration::AsyncGeneratorDeclaration(ag)
1879            }
1880
1881            // ExportDeclaration : export default ClassDeclaration
1882            ExportDeclaration::DefaultClassDeclaration(c) => {
1883                // 1. Return a List whose sole element is ClassDeclaration.
1884                LexicallyScopedDeclaration::ClassDeclaration(c)
1885            }
1886
1887            // ExportDeclaration : export default AssignmentExpression ;
1888            ExportDeclaration::DefaultAssignmentExpression(expr) => {
1889                // 1. Return a List whose sole element is this ExportDeclaration.
1890                LexicallyScopedDeclaration::AssignmentExpression(expr)
1891            }
1892        };
1893
1894        self.0.push(decl);
1895
1896        ControlFlow::Continue(())
1897    }
1898
1899    fn visit_statement_list_item(
1900        &mut self,
1901        node: &'ast StatementListItem,
1902    ) -> ControlFlow<Self::BreakTy> {
1903        match node {
1904            // StatementListItem : Statement
1905            StatementListItem::Statement(statement) => {
1906                // 1. If Statement is Statement : LabelledStatement , return LexicallyScopedDeclarations of LabelledStatement.
1907                if let Statement::Labelled(labelled) = statement.as_ref() {
1908                    self.visit_labelled(labelled)
1909                } else {
1910                    // 2. Return a new empty List.
1911                    ControlFlow::Continue(())
1912                }
1913            }
1914
1915            // StatementListItem : Declaration
1916            StatementListItem::Declaration(declaration) => {
1917                // 1. Return a List whose sole element is DeclarationPart of Declaration.
1918                self.0.push(declaration.as_ref().into());
1919                ControlFlow::Continue(())
1920            }
1921        }
1922    }
1923
1924    fn visit_labelled_item(&mut self, node: &'ast LabelledItem) -> ControlFlow<Self::BreakTy> {
1925        match node {
1926            // LabelledItem : FunctionDeclaration
1927            LabelledItem::FunctionDeclaration(f) => {
1928                // 1. Return « FunctionDeclaration ».
1929                self.0
1930                    .push(LexicallyScopedDeclaration::FunctionDeclaration(f));
1931            }
1932
1933            // LabelledItem : Statement
1934            LabelledItem::Statement(_) => {
1935                // 1. Return a new empty List.
1936            }
1937        }
1938        ControlFlow::Continue(())
1939    }
1940
1941    fn visit_module_item(&mut self, node: &'ast ModuleItem) -> ControlFlow<Self::BreakTy> {
1942        match node {
1943            ModuleItem::StatementListItem(item) => self.visit_statement_list_item(item),
1944            ModuleItem::ExportDeclaration(export) => self.visit_export_declaration(export),
1945
1946            // ModuleItem : ImportDeclaration
1947            ModuleItem::ImportDeclaration(_) => {
1948                // 1. Return a new empty List.
1949                ControlFlow::Continue(())
1950            }
1951        }
1952    }
1953}
1954/// The [`Visitor`] used to obtain the top level lexically scoped declarations of a node.
1955///
1956/// This is equivalent to the [`TopLevelLexicallyScopedDeclarations`][spec] syntax operation in the spec.
1957///
1958/// [spec]: https://tc39.es/ecma262/#sec-static-semantics-toplevellexicallyscopeddeclarations
1959#[derive(Debug)]
1960struct TopLevelLexicallyScopedDeclarationsVisitor<'a, 'ast>(
1961    &'a mut Vec<LexicallyScopedDeclaration<'ast>>,
1962);
1963
1964impl<'ast> Visitor<'ast> for TopLevelLexicallyScopedDeclarationsVisitor<'_, 'ast> {
1965    type BreakTy = Infallible;
1966
1967    fn visit_statement_list_item(
1968        &mut self,
1969        node: &'ast StatementListItem,
1970    ) -> ControlFlow<Self::BreakTy> {
1971        match node {
1972            // StatementListItem : Declaration
1973            StatementListItem::Declaration(d) => match d.as_ref() {
1974                // 1. If Declaration is Declaration : HoistableDeclaration , then
1975                Declaration::FunctionDeclaration(_)
1976                | Declaration::GeneratorDeclaration(_)
1977                | Declaration::AsyncFunctionDeclaration(_)
1978                | Declaration::AsyncGeneratorDeclaration(_) => {
1979                    // a. Return a new empty List.
1980                }
1981
1982                // 2. Return « Declaration ».
1983                Declaration::ClassDeclaration(cl) => {
1984                    self.0
1985                        .push(LexicallyScopedDeclaration::ClassDeclaration(cl));
1986                }
1987                Declaration::Lexical(lex) => {
1988                    self.0
1989                        .push(LexicallyScopedDeclaration::LexicalDeclaration(lex));
1990                }
1991            },
1992
1993            // StatementListItem : Statement
1994            StatementListItem::Statement(_) => {
1995                // 1. Return a new empty List.
1996            }
1997        }
1998
1999        ControlFlow::Continue(())
2000    }
2001}
2002
2003/// The type of a var scoped declaration.
2004#[derive(Clone, Debug)]
2005pub enum VarScopedDeclaration {
2006    /// See [`VarDeclaration`]
2007    VariableDeclaration(Variable),
2008
2009    /// See [`FunctionDeclaration`]
2010    FunctionDeclaration(FunctionDeclaration),
2011
2012    /// See [`GeneratorDeclaration`]
2013    GeneratorDeclaration(GeneratorDeclaration),
2014
2015    /// See [`AsyncFunctionDeclaration`]
2016    AsyncFunctionDeclaration(AsyncFunctionDeclaration),
2017
2018    /// See [`AsyncGeneratorDeclaration`]
2019    AsyncGeneratorDeclaration(AsyncGeneratorDeclaration),
2020}
2021
2022impl VarScopedDeclaration {
2023    /// Return the bound names of the declaration.
2024    #[must_use]
2025    pub fn bound_names(&self) -> Vec<Sym> {
2026        match self {
2027            Self::VariableDeclaration(v) => bound_names(v),
2028            Self::FunctionDeclaration(f) => bound_names(f),
2029            Self::GeneratorDeclaration(g) => bound_names(g),
2030            Self::AsyncFunctionDeclaration(f) => bound_names(f),
2031            Self::AsyncGeneratorDeclaration(g) => bound_names(g),
2032        }
2033    }
2034
2035    /// Return [`LinearSpan`] of this declaration (if there is).
2036    #[must_use]
2037    pub fn linear_span(&self) -> Option<LinearSpan> {
2038        match self {
2039            VarScopedDeclaration::FunctionDeclaration(f) => Some(f.linear_span()),
2040            VarScopedDeclaration::GeneratorDeclaration(f) => Some(f.linear_span()),
2041            VarScopedDeclaration::AsyncFunctionDeclaration(f) => Some(f.linear_span()),
2042            VarScopedDeclaration::AsyncGeneratorDeclaration(f) => Some(f.linear_span()),
2043            VarScopedDeclaration::VariableDeclaration(_) => None,
2044        }
2045    }
2046}
2047
2048/// Returns a list of var scoped declarations of the given node.
2049///
2050/// This is equivalent to the [`VarScopedDeclarations`][spec] syntax operation in the spec.
2051///
2052/// [spec]: https://tc39.es/ecma262/#sec-static-semantics-varscopeddeclarations
2053#[must_use]
2054pub fn var_scoped_declarations<'a, N>(node: &'a N) -> Vec<VarScopedDeclaration>
2055where
2056    &'a N: Into<NodeRef<'a>>,
2057{
2058    let mut declarations = Vec::new();
2059    let _ = VarScopedDeclarationsVisitor(&mut declarations).visit(node.into());
2060    declarations
2061}
2062
2063/// The [`Visitor`] used to obtain the var scoped declarations of a node.
2064#[derive(Debug)]
2065struct VarScopedDeclarationsVisitor<'a>(&'a mut Vec<VarScopedDeclaration>);
2066
2067impl<'ast> Visitor<'ast> for VarScopedDeclarationsVisitor<'_> {
2068    type BreakTy = Infallible;
2069
2070    // ScriptBody : StatementList
2071    fn visit_script(&mut self, node: &'ast Script) -> ControlFlow<Self::BreakTy> {
2072        // 1. Return TopLevelVarScopedDeclarations of StatementList.
2073        TopLevelVarScopedDeclarationsVisitor(self.0).visit_statement_list(node.statements())
2074    }
2075
2076    fn visit_function_body(&mut self, node: &'ast FunctionBody) -> ControlFlow<Self::BreakTy> {
2077        // 1. Return TopLevelVarScopedDeclarations of StatementList.
2078        TopLevelVarScopedDeclarationsVisitor(self.0).visit_statement_list(node.statement_list())
2079    }
2080
2081    fn visit_statement(&mut self, node: &'ast Statement) -> ControlFlow<Self::BreakTy> {
2082        match node {
2083            Statement::Block(s) => self.visit(s),
2084            Statement::Var(s) => self.visit(s),
2085            Statement::If(s) => self.visit(s),
2086            Statement::DoWhileLoop(s) => self.visit(s),
2087            Statement::WhileLoop(s) => self.visit(s),
2088            Statement::ForLoop(s) => self.visit(s),
2089            Statement::ForInLoop(s) => self.visit(s),
2090            Statement::ForOfLoop(s) => self.visit(s),
2091            Statement::Switch(s) => self.visit(s),
2092            Statement::Labelled(s) => self.visit(s),
2093            Statement::Try(s) => self.visit(s),
2094            Statement::With(s) => self.visit(s),
2095            Statement::Empty
2096            | Statement::Debugger
2097            | Statement::Expression(_)
2098            | Statement::Continue(_)
2099            | Statement::Break(_)
2100            | Statement::Return(_)
2101            | Statement::Throw(_) => ControlFlow::Continue(()),
2102        }
2103    }
2104
2105    fn visit_statement_list_item(
2106        &mut self,
2107        node: &'ast StatementListItem,
2108    ) -> ControlFlow<Self::BreakTy> {
2109        match node {
2110            StatementListItem::Declaration(_) => ControlFlow::Continue(()),
2111            StatementListItem::Statement(s) => self.visit(s.as_ref()),
2112        }
2113    }
2114
2115    fn visit_var_declaration(&mut self, node: &'ast VarDeclaration) -> ControlFlow<Self::BreakTy> {
2116        for var in node.0.as_ref() {
2117            self.0
2118                .push(VarScopedDeclaration::VariableDeclaration(var.clone()));
2119        }
2120        ControlFlow::Continue(())
2121    }
2122
2123    fn visit_if(&mut self, node: &'ast crate::statement::If) -> ControlFlow<Self::BreakTy> {
2124        self.visit(node.body())?;
2125        if let Some(else_node) = node.else_node() {
2126            self.visit(else_node)?;
2127        }
2128        ControlFlow::Continue(())
2129    }
2130
2131    fn visit_do_while_loop(
2132        &mut self,
2133        node: &'ast crate::statement::DoWhileLoop,
2134    ) -> ControlFlow<Self::BreakTy> {
2135        self.visit(node.body())?;
2136        ControlFlow::Continue(())
2137    }
2138
2139    fn visit_while_loop(
2140        &mut self,
2141        node: &'ast crate::statement::WhileLoop,
2142    ) -> ControlFlow<Self::BreakTy> {
2143        self.visit(node.body())?;
2144        ControlFlow::Continue(())
2145    }
2146
2147    fn visit_for_loop(
2148        &mut self,
2149        node: &'ast crate::statement::ForLoop,
2150    ) -> ControlFlow<Self::BreakTy> {
2151        if let Some(ForLoopInitializer::Var(v)) = node.init() {
2152            self.visit(v)?;
2153        }
2154        self.visit(node.body())?;
2155        ControlFlow::Continue(())
2156    }
2157
2158    fn visit_for_in_loop(
2159        &mut self,
2160        node: &'ast crate::statement::ForInLoop,
2161    ) -> ControlFlow<Self::BreakTy> {
2162        if let IterableLoopInitializer::Var(var) = node.initializer() {
2163            self.0
2164                .push(VarScopedDeclaration::VariableDeclaration(var.clone()));
2165        }
2166        self.visit(node.body())?;
2167        ControlFlow::Continue(())
2168    }
2169
2170    fn visit_for_of_loop(
2171        &mut self,
2172        node: &'ast crate::statement::ForOfLoop,
2173    ) -> ControlFlow<Self::BreakTy> {
2174        if let IterableLoopInitializer::Var(var) = node.initializer() {
2175            self.0
2176                .push(VarScopedDeclaration::VariableDeclaration(var.clone()));
2177        }
2178        self.visit(node.body())?;
2179        ControlFlow::Continue(())
2180    }
2181
2182    fn visit_with(&mut self, node: &'ast With) -> ControlFlow<Self::BreakTy> {
2183        self.visit(node.statement())?;
2184        ControlFlow::Continue(())
2185    }
2186
2187    fn visit_switch(&mut self, node: &'ast crate::statement::Switch) -> ControlFlow<Self::BreakTy> {
2188        for case in node.cases() {
2189            self.visit(case)?;
2190        }
2191        if let Some(default) = node.default() {
2192            self.visit(default)?;
2193        }
2194        ControlFlow::Continue(())
2195    }
2196
2197    fn visit_case(&mut self, node: &'ast crate::statement::Case) -> ControlFlow<Self::BreakTy> {
2198        self.visit(node.body())?;
2199        ControlFlow::Continue(())
2200    }
2201
2202    fn visit_labelled_item(&mut self, node: &'ast LabelledItem) -> ControlFlow<Self::BreakTy> {
2203        match node {
2204            LabelledItem::Statement(s) => self.visit(s),
2205            LabelledItem::FunctionDeclaration(_) => ControlFlow::Continue(()),
2206        }
2207    }
2208
2209    fn visit_catch(&mut self, node: &'ast crate::statement::Catch) -> ControlFlow<Self::BreakTy> {
2210        self.visit(node.block())?;
2211        ControlFlow::Continue(())
2212    }
2213
2214    fn visit_module_item(&mut self, node: &'ast ModuleItem) -> ControlFlow<Self::BreakTy> {
2215        match node {
2216            // ModuleItem : ExportDeclaration
2217            ModuleItem::ExportDeclaration(decl) => {
2218                if let ExportDeclaration::VarStatement(var) = decl.as_ref() {
2219                    //     1. If ExportDeclaration is export VariableStatement, return VarScopedDeclarations of VariableStatement.
2220                    self.visit_var_declaration(var)?;
2221                }
2222                // 2. Return a new empty List.
2223            }
2224            ModuleItem::StatementListItem(item) => {
2225                self.visit_statement_list_item(item)?;
2226            }
2227            // ModuleItem : ImportDeclaration
2228            ModuleItem::ImportDeclaration(_) => {
2229                // 1. Return a new empty List.
2230            }
2231        }
2232        ControlFlow::Continue(())
2233    }
2234}
2235
2236/// The [`Visitor`] used to obtain the top level var scoped declarations of a node.
2237///
2238/// This is equivalent to the [`TopLevelVarScopedDeclarations`][spec] syntax operation in the spec.
2239///
2240/// [spec]: https://tc39.es/ecma262/#sec-static-semantics-toplevelvarscopeddeclarations
2241#[derive(Debug)]
2242struct TopLevelVarScopedDeclarationsVisitor<'a>(&'a mut Vec<VarScopedDeclaration>);
2243
2244impl<'ast> Visitor<'ast> for TopLevelVarScopedDeclarationsVisitor<'_> {
2245    type BreakTy = Infallible;
2246
2247    fn visit_statement_list_item(
2248        &mut self,
2249        node: &'ast StatementListItem,
2250    ) -> ControlFlow<Self::BreakTy> {
2251        match node {
2252            StatementListItem::Declaration(d) => {
2253                match d.as_ref() {
2254                    Declaration::FunctionDeclaration(f) => {
2255                        self.0
2256                            .push(VarScopedDeclaration::FunctionDeclaration(f.clone()));
2257                    }
2258                    Declaration::GeneratorDeclaration(f) => {
2259                        self.0
2260                            .push(VarScopedDeclaration::GeneratorDeclaration(f.clone()));
2261                    }
2262                    Declaration::AsyncFunctionDeclaration(f) => {
2263                        self.0
2264                            .push(VarScopedDeclaration::AsyncFunctionDeclaration(f.clone()));
2265                    }
2266                    Declaration::AsyncGeneratorDeclaration(f) => {
2267                        self.0
2268                            .push(VarScopedDeclaration::AsyncGeneratorDeclaration(f.clone()));
2269                    }
2270                    _ => {}
2271                }
2272                ControlFlow::Continue(())
2273            }
2274            StatementListItem::Statement(statement) => {
2275                if let Statement::Labelled(labelled) = statement.as_ref() {
2276                    self.visit(labelled)
2277                } else {
2278                    VarScopedDeclarationsVisitor(self.0).visit(statement.as_ref())
2279                }
2280            }
2281        }
2282    }
2283
2284    fn visit_labelled_item(&mut self, node: &'ast LabelledItem) -> ControlFlow<Self::BreakTy> {
2285        match node {
2286            LabelledItem::Statement(Statement::Labelled(s)) => self.visit(s),
2287            LabelledItem::Statement(s) => {
2288                VarScopedDeclarationsVisitor(self.0).visit(s)?;
2289                ControlFlow::Continue(())
2290            }
2291            LabelledItem::FunctionDeclaration(f) => {
2292                self.0
2293                    .push(VarScopedDeclaration::FunctionDeclaration(f.clone()));
2294                ControlFlow::Continue(())
2295            }
2296        }
2297    }
2298}
2299
2300/// Returns a list function declaration names that are directly contained in a statement lists
2301/// `Block`, `CaseClause` or `DefaultClause`.
2302/// If the function declaration would cause an early error it is not included in the list.
2303///
2304/// This behavior is used in the following annexB sections:
2305/// * [B.3.2.1 Changes to FunctionDeclarationInstantiation][spec0]
2306/// * [B.3.2.2 Changes to GlobalDeclarationInstantiation][spec1]
2307/// * [B.3.2.3 Changes to EvalDeclarationInstantiation][spec2]
2308///
2309/// [spec0]: https://tc39.es/ecma262/#sec-web-compat-functiondeclarationinstantiation
2310/// [spec1]: https://tc39.es/ecma262/#sec-web-compat-globaldeclarationinstantiation
2311/// [spec2]: https://tc39.es/ecma262/#sec-web-compat-evaldeclarationinstantiation
2312#[must_use]
2313pub fn annex_b_function_declarations_names<'a, N>(node: &'a N) -> Vec<Sym>
2314where
2315    &'a N: Into<NodeRef<'a>>,
2316{
2317    let mut declarations = Vec::new();
2318    let _ = AnnexBFunctionDeclarationNamesVisitor(&mut declarations).visit(node.into());
2319    declarations
2320}
2321
2322/// The [`Visitor`] used for [`annex_b_function_declarations_names`].
2323#[derive(Debug)]
2324struct AnnexBFunctionDeclarationNamesVisitor<'a>(&'a mut Vec<Sym>);
2325
2326impl<'ast> Visitor<'ast> for AnnexBFunctionDeclarationNamesVisitor<'_> {
2327    type BreakTy = Infallible;
2328
2329    fn visit_statement_list_item(
2330        &mut self,
2331        node: &'ast StatementListItem,
2332    ) -> ControlFlow<Self::BreakTy> {
2333        match node {
2334            StatementListItem::Statement(node) => self.visit(node.as_ref()),
2335            StatementListItem::Declaration(_) => ControlFlow::Continue(()),
2336        }
2337    }
2338
2339    fn visit_statement(&mut self, node: &'ast Statement) -> ControlFlow<Self::BreakTy> {
2340        match node {
2341            Statement::Block(node) => self.visit(node),
2342            Statement::If(node) => self.visit(node),
2343            Statement::DoWhileLoop(node) => self.visit(node),
2344            Statement::WhileLoop(node) => self.visit(node),
2345            Statement::ForLoop(node) => self.visit(node),
2346            Statement::ForInLoop(node) => self.visit(node),
2347            Statement::ForOfLoop(node) => self.visit(node),
2348            Statement::Switch(node) => self.visit(node),
2349            Statement::Labelled(node) => self.visit(node),
2350            Statement::Try(node) => self.visit(node),
2351            Statement::With(node) => self.visit(node),
2352            _ => ControlFlow::Continue(()),
2353        }
2354    }
2355
2356    fn visit_block(&mut self, node: &'ast crate::statement::Block) -> ControlFlow<Self::BreakTy> {
2357        self.visit(node.statement_list())?;
2358        for statement in node.statement_list().statements() {
2359            if let StatementListItem::Declaration(declaration) = statement
2360                && let Declaration::FunctionDeclaration(function) = &**declaration
2361            {
2362                let name = function.name();
2363                self.0.push(name.sym());
2364            }
2365        }
2366
2367        let lexically_declared_names = lexically_declared_names_legacy(node.statement_list());
2368
2369        self.0
2370            .retain(|name| !lexically_declared_names.contains(&(*name, false)));
2371
2372        ControlFlow::Continue(())
2373    }
2374
2375    fn visit_switch(&mut self, node: &'ast crate::statement::Switch) -> ControlFlow<Self::BreakTy> {
2376        for case in node.cases() {
2377            self.visit(case)?;
2378            for statement in case.body().statements() {
2379                if let StatementListItem::Declaration(declaration) = statement
2380                    && let Declaration::FunctionDeclaration(function) = &**declaration
2381                {
2382                    let name = function.name();
2383                    self.0.push(name.sym());
2384                }
2385            }
2386        }
2387        if let Some(default) = node.default() {
2388            self.visit(default)?;
2389            for statement in default.statements() {
2390                if let StatementListItem::Declaration(declaration) = statement
2391                    && let Declaration::FunctionDeclaration(function) = declaration.as_ref()
2392                {
2393                    let name = function.name();
2394                    self.0.push(name.sym());
2395                }
2396            }
2397        }
2398
2399        let lexically_declared_names = lexically_declared_names_legacy(node);
2400
2401        self.0
2402            .retain(|name| !lexically_declared_names.contains(&(*name, false)));
2403
2404        ControlFlow::Continue(())
2405    }
2406
2407    fn visit_try(&mut self, node: &'ast crate::statement::Try) -> ControlFlow<Self::BreakTy> {
2408        self.visit(node.block())?;
2409        if let Some(catch) = node.catch() {
2410            self.visit(catch.block())?;
2411
2412            if let Some(Binding::Pattern(pattern)) = catch.parameter() {
2413                let bound_names = bound_names(pattern);
2414
2415                self.0.retain(|name| !bound_names.contains(name));
2416            }
2417        }
2418        if let Some(finally) = node.finally() {
2419            self.visit(finally.block())?;
2420        }
2421        ControlFlow::Continue(())
2422    }
2423
2424    fn visit_if(&mut self, node: &'ast crate::statement::If) -> ControlFlow<Self::BreakTy> {
2425        if let Some(node) = node.else_node() {
2426            self.visit(node)?;
2427        }
2428        self.visit(node.body())
2429    }
2430
2431    fn visit_do_while_loop(
2432        &mut self,
2433        node: &'ast crate::statement::DoWhileLoop,
2434    ) -> ControlFlow<Self::BreakTy> {
2435        self.visit(node.body())
2436    }
2437
2438    fn visit_while_loop(
2439        &mut self,
2440        node: &'ast crate::statement::WhileLoop,
2441    ) -> ControlFlow<Self::BreakTy> {
2442        self.visit(node.body())
2443    }
2444
2445    fn visit_for_loop(
2446        &mut self,
2447        node: &'ast crate::statement::ForLoop,
2448    ) -> ControlFlow<Self::BreakTy> {
2449        self.visit(node.body())?;
2450
2451        if let Some(ForLoopInitializer::Lexical(node)) = node.init() {
2452            let bound_names = bound_names(&node.declaration);
2453            self.0.retain(|name| !bound_names.contains(name));
2454        }
2455
2456        ControlFlow::Continue(())
2457    }
2458
2459    fn visit_for_in_loop(
2460        &mut self,
2461        node: &'ast crate::statement::ForInLoop,
2462    ) -> ControlFlow<Self::BreakTy> {
2463        self.visit(node.body())?;
2464
2465        if let IterableLoopInitializer::Let(node) = node.initializer() {
2466            let bound_names = bound_names(node);
2467            self.0.retain(|name| !bound_names.contains(name));
2468        }
2469        if let IterableLoopInitializer::Const(node) = node.initializer() {
2470            let bound_names = bound_names(node);
2471            self.0.retain(|name| !bound_names.contains(name));
2472        }
2473
2474        ControlFlow::Continue(())
2475    }
2476
2477    fn visit_for_of_loop(
2478        &mut self,
2479        node: &'ast crate::statement::ForOfLoop,
2480    ) -> ControlFlow<Self::BreakTy> {
2481        self.visit(node.body())?;
2482
2483        if let IterableLoopInitializer::Let(node) = node.initializer() {
2484            let bound_names = bound_names(node);
2485            self.0.retain(|name| !bound_names.contains(name));
2486        }
2487        if let IterableLoopInitializer::Const(node) = node.initializer() {
2488            let bound_names = bound_names(node);
2489            self.0.retain(|name| !bound_names.contains(name));
2490        }
2491
2492        ControlFlow::Continue(())
2493    }
2494
2495    fn visit_labelled(
2496        &mut self,
2497        node: &'ast crate::statement::Labelled,
2498    ) -> ControlFlow<Self::BreakTy> {
2499        if let LabelledItem::Statement(node) = node.item() {
2500            self.visit(node)?;
2501        }
2502        ControlFlow::Continue(())
2503    }
2504
2505    fn visit_with(&mut self, node: &'ast With) -> ControlFlow<Self::BreakTy> {
2506        self.visit(node.statement())
2507    }
2508}
2509
2510/// Returns `true` if the given statement returns a value.
2511#[must_use]
2512pub fn returns_value<'a, N>(node: &'a N) -> bool
2513where
2514    &'a N: Into<NodeRef<'a>>,
2515{
2516    ReturnsValueVisitor.visit(node.into()).is_break()
2517}
2518
2519/// The [`Visitor`] used for [`returns_value`].
2520#[derive(Debug)]
2521struct ReturnsValueVisitor;
2522
2523impl<'ast> Visitor<'ast> for ReturnsValueVisitor {
2524    type BreakTy = ();
2525
2526    fn visit_block(&mut self, node: &'ast crate::statement::Block) -> ControlFlow<Self::BreakTy> {
2527        for statement in node.statement_list().statements() {
2528            match statement {
2529                StatementListItem::Declaration(_) => {}
2530                StatementListItem::Statement(node) => self.visit(node.as_ref())?,
2531            }
2532        }
2533        ControlFlow::Continue(())
2534    }
2535
2536    fn visit_statement(&mut self, node: &'ast Statement) -> ControlFlow<Self::BreakTy> {
2537        match node {
2538            Statement::Empty | Statement::Var(_) => {}
2539            Statement::Block(node) => self.visit(node)?,
2540            Statement::Labelled(node) => self.visit(node)?,
2541            _ => return ControlFlow::Break(()),
2542        }
2543        ControlFlow::Continue(())
2544    }
2545
2546    fn visit_case(&mut self, node: &'ast crate::statement::Case) -> ControlFlow<Self::BreakTy> {
2547        for statement in node.body().statements() {
2548            match statement {
2549                StatementListItem::Declaration(_) => {}
2550                StatementListItem::Statement(node) => self.visit(node.as_ref())?,
2551            }
2552        }
2553        ControlFlow::Continue(())
2554    }
2555
2556    fn visit_labelled(
2557        &mut self,
2558        node: &'ast crate::statement::Labelled,
2559    ) -> ControlFlow<Self::BreakTy> {
2560        match node.item() {
2561            LabelledItem::Statement(node) => self.visit(node)?,
2562            LabelledItem::FunctionDeclaration(_) => {}
2563        }
2564        ControlFlow::Continue(())
2565    }
2566}