boa_parser/parser/statement/labelled_stm/
mod.rs

1use crate::{
2    Error,
3    lexer::TokenKind,
4    parser::{
5        AllowYield, OrAbrupt, ParseResult, TokenParser,
6        cursor::Cursor,
7        expression::LabelIdentifier,
8        statement::{AllowAwait, AllowReturn, Statement, declaration::FunctionDeclaration},
9    },
10    source::ReadChar,
11};
12use boa_ast::{self as ast, Keyword, Punctuator, Spanned};
13use boa_interner::Interner;
14
15/// Labelled Statement Parsing
16///
17/// More information
18/// - [MDN documentation][mdn]
19/// - [ECMAScript specification][spec]
20///
21/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Statements/label
22/// [spec]: https://tc39.es/ecma262/#sec-labelled-statements
23#[derive(Debug, Clone, Copy)]
24pub(super) struct LabelledStatement {
25    allow_yield: AllowYield,
26    allow_await: AllowAwait,
27    allow_return: AllowReturn,
28}
29
30impl LabelledStatement {
31    pub(super) fn new<Y, A, R>(allow_yield: Y, allow_await: A, allow_return: R) -> Self
32    where
33        Y: Into<AllowYield>,
34        A: Into<AllowAwait>,
35        R: Into<AllowReturn>,
36    {
37        Self {
38            allow_yield: allow_yield.into(),
39            allow_await: allow_await.into(),
40            allow_return: allow_return.into(),
41        }
42    }
43}
44
45impl<R> TokenParser<R> for LabelledStatement
46where
47    R: ReadChar,
48{
49    type Output = ast::statement::Labelled;
50
51    fn parse(self, cursor: &mut Cursor<R>, interner: &mut Interner) -> ParseResult<Self::Output> {
52        let label = LabelIdentifier::new(self.allow_yield, self.allow_await)
53            .parse(cursor, interner)?
54            .sym();
55
56        cursor.expect(Punctuator::Colon, "Labelled Statement", interner)?;
57
58        let strict = cursor.strict();
59        let next_token = cursor.peek(0, interner).or_abrupt()?;
60
61        let labelled_item = match next_token.kind() {
62            // Early Error: It is a Syntax Error if any strict mode source code matches this rule.
63            // https://tc39.es/ecma262/#sec-labelled-statements-static-semantics-early-errors
64            // https://tc39.es/ecma262/#sec-labelled-function-declarations
65            TokenKind::Keyword((Keyword::Function, _))
66                if cfg!(not(feature = "annex-b")) || strict =>
67            {
68                return Err(Error::misplaced_function_declaration(
69                    next_token.span().start(),
70                    strict,
71                ));
72            }
73            TokenKind::Keyword((Keyword::Function, _)) => {
74                FunctionDeclaration::new(self.allow_yield, self.allow_await, false)
75                    .parse(cursor, interner)?
76                    .into()
77            }
78            _ => Statement::new(self.allow_yield, self.allow_await, self.allow_return)
79                .parse(cursor, interner)?
80                .into(),
81        };
82
83        Ok(ast::statement::Labelled::new(labelled_item, label))
84    }
85}