Skip to main content

boa_ast/statement/
labelled.rs

1use crate::{
2    Statement,
3    function::FunctionDeclaration,
4    visitor::{VisitWith, Visitor, VisitorMut},
5};
6use boa_interner::{Interner, Sym, ToIndentedString, ToInternedString};
7use core::ops::ControlFlow;
8
9/// The set of Parse Nodes that can be preceded by a label, as defined by the [spec].
10///
11/// Semantically, a [`Labelled`] statement should only wrap [`Statement`] nodes. However,
12/// old ECMAScript implementations supported [labelled function declarations][label-fn] as an extension
13/// of the grammar. In the ECMAScript 2015 spec, the production of `LabelledStatement` was
14/// modified to include labelled [`FunctionDeclaration`]s as a valid node.
15///
16/// [spec]: https://tc39.es/ecma262/#prod-LabelledItem
17/// [label-fn]: https://tc39.es/ecma262/#sec-labelled-function-declarations
18#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
19#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
20#[derive(Clone, Debug, PartialEq)]
21#[allow(clippy::large_enum_variant)]
22pub enum LabelledItem {
23    /// A labelled [`FunctionDeclaration`].
24    FunctionDeclaration(FunctionDeclaration),
25
26    /// A labelled [`Statement`].
27    Statement(Statement),
28}
29
30impl LabelledItem {
31    pub(crate) fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
32        match self {
33            Self::FunctionDeclaration(f) => f.to_indented_string(interner, indentation),
34            Self::Statement(stmt) => stmt.to_indented_string(interner, indentation),
35        }
36    }
37}
38
39impl ToInternedString for LabelledItem {
40    fn to_interned_string(&self, interner: &Interner) -> String {
41        self.to_indented_string(interner, 0)
42    }
43}
44
45impl From<FunctionDeclaration> for LabelledItem {
46    fn from(f: FunctionDeclaration) -> Self {
47        Self::FunctionDeclaration(f)
48    }
49}
50
51impl From<Statement> for LabelledItem {
52    fn from(stmt: Statement) -> Self {
53        Self::Statement(stmt)
54    }
55}
56
57impl VisitWith for LabelledItem {
58    fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
59    where
60        V: Visitor<'a>,
61    {
62        match self {
63            Self::FunctionDeclaration(f) => visitor.visit_function_declaration(f),
64            Self::Statement(s) => visitor.visit_statement(s),
65        }
66    }
67
68    fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
69    where
70        V: VisitorMut<'a>,
71    {
72        match self {
73            Self::FunctionDeclaration(f) => visitor.visit_function_declaration_mut(f),
74            Self::Statement(s) => visitor.visit_statement_mut(s),
75        }
76    }
77}
78
79/// Labelled statement nodes, as defined by the [spec].
80///
81/// The method [`Labelled::item`] doesn't return a [`Statement`] for compatibility reasons.
82/// See [`LabelledItem`] for more information.
83///
84/// [spec]: https://tc39.es/ecma262/#sec-labelled-statements
85#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
86#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
87#[derive(Clone, Debug, PartialEq)]
88pub struct Labelled {
89    item: Box<LabelledItem>,
90    label: Sym,
91}
92
93impl Labelled {
94    /// Creates a new `Labelled` statement.
95    #[inline]
96    #[must_use]
97    pub fn new(item: LabelledItem, label: Sym) -> Self {
98        Self {
99            item: Box::new(item),
100            label,
101        }
102    }
103
104    /// Gets the labelled item.
105    #[inline]
106    #[must_use]
107    pub const fn item(&self) -> &LabelledItem {
108        &self.item
109    }
110
111    /// Gets the label name.
112    #[inline]
113    #[must_use]
114    pub const fn label(&self) -> Sym {
115        self.label
116    }
117
118    pub(crate) fn to_indented_string(&self, interner: &Interner, indentation: usize) -> String {
119        format!(
120            "{}: {}",
121            interner.resolve_expect(self.label),
122            self.item.to_indented_string(interner, indentation)
123        )
124    }
125}
126
127impl ToInternedString for Labelled {
128    fn to_interned_string(&self, interner: &Interner) -> String {
129        self.to_indented_string(interner, 0)
130    }
131}
132
133impl From<Labelled> for Statement {
134    fn from(labelled: Labelled) -> Self {
135        Self::Labelled(labelled)
136    }
137}
138
139impl VisitWith for Labelled {
140    fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
141    where
142        V: Visitor<'a>,
143    {
144        visitor.visit_labelled_item(&self.item)?;
145        visitor.visit_sym(&self.label)
146    }
147
148    fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
149    where
150        V: VisitorMut<'a>,
151    {
152        visitor.visit_labelled_item_mut(&mut self.item)?;
153        visitor.visit_sym_mut(&mut self.label)
154    }
155}