Skip to main content

boa_ast/statement/iteration/
break.rs

1use boa_interner::{Interner, Sym, ToInternedString};
2use core::ops::ControlFlow;
3
4use crate::Statement;
5use crate::visitor::{VisitWith, Visitor, VisitorMut};
6
7/// The `break` statement terminates the current loop, switch, or label statement and transfers
8/// program control to the statement following the terminated statement.
9///
10/// The break statement includes an optional label that allows the program to break out of a
11/// labeled statement. The break statement needs to be nested within the referenced label. The
12/// labeled statement can be any block statement; it does not have to be preceded by a loop
13/// statement.
14///
15/// More information:
16///  - [ECMAScript reference][spec]
17///  - [MDN documentation][mdn]
18///
19/// [spec]: https://tc39.es/ecma262/#prod-BreakStatement
20/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/break
21#[cfg_attr(feature = "serde", derive(serde::Serialize, serde::Deserialize))]
22#[cfg_attr(feature = "arbitrary", derive(arbitrary::Arbitrary))]
23#[derive(Debug, Clone, Copy, PartialEq, Eq)]
24pub struct Break {
25    label: Option<Sym>,
26}
27
28impl Break {
29    /// Creates a `Break` AST node.
30    #[must_use]
31    pub const fn new(label: Option<Sym>) -> Self {
32        Self { label }
33    }
34
35    /// Gets the label of the break statement, if any.
36    #[must_use]
37    pub const fn label(&self) -> Option<Sym> {
38        self.label
39    }
40}
41
42impl ToInternedString for Break {
43    fn to_interned_string(&self, interner: &Interner) -> String {
44        self.label.map_or_else(
45            || "break".to_owned(),
46            |label| format!("break {}", interner.resolve_expect(label)),
47        )
48    }
49}
50
51impl From<Break> for Statement {
52    fn from(break_smt: Break) -> Self {
53        Self::Break(break_smt)
54    }
55}
56
57impl VisitWith for Break {
58    fn visit_with<'a, V>(&'a self, visitor: &mut V) -> ControlFlow<V::BreakTy>
59    where
60        V: Visitor<'a>,
61    {
62        if let Some(sym) = &self.label {
63            visitor.visit_sym(sym)
64        } else {
65            ControlFlow::Continue(())
66        }
67    }
68
69    fn visit_with_mut<'a, V>(&'a mut self, visitor: &mut V) -> ControlFlow<V::BreakTy>
70    where
71        V: VisitorMut<'a>,
72    {
73        if let Some(sym) = &mut self.label {
74            visitor.visit_sym_mut(sym)
75        } else {
76            ControlFlow::Continue(())
77        }
78    }
79}