boa/syntax/parser/expression/assignment/
arrow_function.rs

1//! Arrow function parsing.
2//!
3//! More information:
4//!  - [MDN documentation][mdn]
5//!  - [ECMAScript specification][spec]
6//!
7//! [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
8//! [spec]: https://tc39.es/ecma262/#sec-arrow-function-definitions
9
10use super::AssignmentExpression;
11use crate::{
12    syntax::{
13        ast::{
14            node::{ArrowFunctionDecl, FormalParameter, Node, Return, StatementList},
15            Punctuator,
16        },
17        lexer::{Error as LexError, Position, TokenKind},
18        parser::{
19            error::{ErrorContext, ParseError, ParseResult},
20            function::{FormalParameters, FunctionBody},
21            statement::BindingIdentifier,
22            AllowAwait, AllowIn, AllowYield, Cursor, TokenParser,
23        },
24    },
25    BoaProfiler,
26};
27
28use std::io::Read;
29
30/// Arrow function parsing.
31///
32/// More information:
33///  - [MDN documentation][mdn]
34///  - [ECMAScript specification][spec]
35///
36/// [mdn]: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Functions/Arrow_functions
37/// [spec]: https://tc39.es/ecma262/#prod-ArrowFunction
38#[derive(Debug, Clone, Copy)]
39pub(in crate::syntax::parser) struct ArrowFunction {
40    allow_in: AllowIn,
41    allow_yield: AllowYield,
42    allow_await: AllowAwait,
43}
44
45impl ArrowFunction {
46    /// Creates a new `ArrowFunction` parser.
47    pub(in crate::syntax::parser) fn new<I, Y, A>(
48        allow_in: I,
49        allow_yield: Y,
50        allow_await: A,
51    ) -> Self
52    where
53        I: Into<AllowIn>,
54        Y: Into<AllowYield>,
55        A: Into<AllowAwait>,
56    {
57        Self {
58            allow_in: allow_in.into(),
59            allow_yield: allow_yield.into(),
60            allow_await: allow_await.into(),
61        }
62    }
63}
64
65impl<R> TokenParser<R> for ArrowFunction
66where
67    R: Read,
68{
69    type Output = ArrowFunctionDecl;
70
71    fn parse(self, cursor: &mut Cursor<R>) -> Result<Self::Output, ParseError> {
72        let _timer = BoaProfiler::global().start_event("ArrowFunction", "Parsing");
73        let next_token = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?;
74
75        let params = if let TokenKind::Punctuator(Punctuator::OpenParen) = &next_token.kind() {
76            // CoverParenthesizedExpressionAndArrowParameterList
77            cursor.expect(Punctuator::OpenParen, "arrow function")?;
78
79            let params = FormalParameters::new(self.allow_yield, self.allow_await).parse(cursor)?;
80            cursor.expect(Punctuator::CloseParen, "arrow function")?;
81            params
82        } else {
83            let param = BindingIdentifier::new(self.allow_yield, self.allow_await)
84                .parse(cursor)
85                .context("arrow function")?;
86            Box::new([FormalParameter::new(param, None, false)])
87        };
88
89        cursor.peek_expect_no_lineterminator(0, "arrow function")?;
90
91        cursor.expect(TokenKind::Punctuator(Punctuator::Arrow), "arrow function")?;
92        let body = ConciseBody::new(self.allow_in).parse(cursor)?;
93
94        // It is a Syntax Error if any element of the BoundNames of ArrowParameters
95        // also occurs in the LexicallyDeclaredNames of ConciseBody.
96        // https://tc39.es/ecma262/#sec-arrow-function-definitions-static-semantics-early-errors
97        {
98            let lexically_declared_names = body.lexically_declared_names();
99            for param in params.as_ref() {
100                if lexically_declared_names.contains(param.name()) {
101                    return Err(ParseError::lex(LexError::Syntax(
102                        format!("Redeclaration of formal parameter `{}`", param.name()).into(),
103                        match cursor.peek(0)? {
104                            Some(token) => token.span().end(),
105                            None => Position::new(1, 1),
106                        },
107                    )));
108                }
109            }
110        }
111
112        Ok(ArrowFunctionDecl::new(params, body))
113    }
114}
115
116/// <https://tc39.es/ecma262/#prod-ConciseBody>
117#[derive(Debug, Clone, Copy)]
118struct ConciseBody {
119    allow_in: AllowIn,
120}
121
122impl ConciseBody {
123    /// Creates a new `ConcideBody` parser.
124    fn new<I>(allow_in: I) -> Self
125    where
126        I: Into<AllowIn>,
127    {
128        Self {
129            allow_in: allow_in.into(),
130        }
131    }
132}
133
134impl<R> TokenParser<R> for ConciseBody
135where
136    R: Read,
137{
138    type Output = StatementList;
139
140    fn parse(self, cursor: &mut Cursor<R>) -> Result<Self::Output, ParseError> {
141        match cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?.kind() {
142            TokenKind::Punctuator(Punctuator::OpenBlock) => {
143                let _ = cursor.next();
144                let body = FunctionBody::new(false, false).parse(cursor)?;
145                cursor.expect(Punctuator::CloseBlock, "arrow function")?;
146                Ok(body)
147            }
148            _ => Ok(StatementList::from(vec![Return::new(
149                ExpressionBody::new(self.allow_in, false).parse(cursor)?,
150                None,
151            )
152            .into()])),
153        }
154    }
155}
156
157/// <https://tc39.es/ecma262/#prod-ExpressionBody>
158#[derive(Debug, Clone, Copy)]
159struct ExpressionBody {
160    allow_in: AllowIn,
161    allow_await: AllowAwait,
162}
163
164impl ExpressionBody {
165    /// Creates a new `ExpressionBody` parser.
166    fn new<I, A>(allow_in: I, allow_await: A) -> Self
167    where
168        I: Into<AllowIn>,
169        A: Into<AllowAwait>,
170    {
171        Self {
172            allow_in: allow_in.into(),
173            allow_await: allow_await.into(),
174        }
175    }
176}
177
178impl<R> TokenParser<R> for ExpressionBody
179where
180    R: Read,
181{
182    type Output = Node;
183
184    fn parse(self, cursor: &mut Cursor<R>) -> ParseResult {
185        AssignmentExpression::new(self.allow_in, false, self.allow_await).parse(cursor)
186    }
187}