boa/syntax/parser/function/
mod.rs1#[cfg(test)]
11mod tests;
12
13use crate::{
14 syntax::{
15 ast::{node, Punctuator},
16 lexer::{InputElement, TokenKind},
17 parser::{
18 expression::Initializer,
19 statement::{BindingIdentifier, StatementList},
20 AllowAwait, AllowYield, Cursor, ParseError, TokenParser,
21 },
22 },
23 BoaProfiler,
24};
25use std::{collections::HashSet, io::Read};
26
27#[derive(Debug, Clone, Copy)]
36pub(in crate::syntax::parser) struct FormalParameters {
37 allow_yield: AllowYield,
38 allow_await: AllowAwait,
39}
40
41impl FormalParameters {
42 pub(in crate::syntax::parser) fn new<Y, A>(allow_yield: Y, allow_await: A) -> Self
44 where
45 Y: Into<AllowYield>,
46 A: Into<AllowAwait>,
47 {
48 Self {
49 allow_yield: allow_yield.into(),
50 allow_await: allow_await.into(),
51 }
52 }
53}
54
55impl<R> TokenParser<R> for FormalParameters
56where
57 R: Read,
58{
59 type Output = Box<[node::FormalParameter]>;
60
61 fn parse(self, cursor: &mut Cursor<R>) -> Result<Self::Output, ParseError> {
62 let _timer = BoaProfiler::global().start_event("FormalParameters", "Parsing");
63 cursor.set_goal(InputElement::RegExp);
64
65 let mut params = Vec::new();
66 let mut param_names = HashSet::new();
67
68 if cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?.kind()
69 == &TokenKind::Punctuator(Punctuator::CloseParen)
70 {
71 return Ok(params.into_boxed_slice());
72 }
73
74 loop {
75 let mut rest_param = false;
76
77 let position = cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?.span().start();
78 let next_param = match cursor.peek(0)? {
79 Some(tok) if tok.kind() == &TokenKind::Punctuator(Punctuator::Spread) => {
80 rest_param = true;
81 FunctionRestParameter::new(self.allow_yield, self.allow_await).parse(cursor)?
82 }
83 _ => FormalParameter::new(self.allow_yield, self.allow_await).parse(cursor)?,
84 };
85 if param_names.contains(next_param.name()) {
86 return Err(ParseError::general("duplicate parameter name", position));
87 }
88
89 param_names.insert(Box::from(next_param.name()));
90 params.push(next_param);
91
92 if cursor.peek(0)?.ok_or(ParseError::AbruptEnd)?.kind()
93 == &TokenKind::Punctuator(Punctuator::CloseParen)
94 {
95 break;
96 }
97
98 if rest_param {
99 return Err(ParseError::unexpected(
100 cursor.next()?.expect("peeked token disappeared"),
101 "rest parameter must be the last formal parameter",
102 ));
103 }
104
105 cursor.expect(Punctuator::Comma, "parameter list")?;
106 }
107
108 Ok(params.into_boxed_slice())
109 }
110}
111
112type FunctionRestParameter = BindingRestElement;
121
122#[derive(Debug, Clone, Copy)]
131struct BindingRestElement {
132 allow_yield: AllowYield,
133 allow_await: AllowAwait,
134}
135
136impl BindingRestElement {
137 fn new<Y, A>(allow_yield: Y, allow_await: A) -> Self
139 where
140 Y: Into<AllowYield>,
141 A: Into<AllowAwait>,
142 {
143 Self {
144 allow_yield: allow_yield.into(),
145 allow_await: allow_await.into(),
146 }
147 }
148}
149
150impl<R> TokenParser<R> for BindingRestElement
151where
152 R: Read,
153{
154 type Output = node::FormalParameter;
155
156 fn parse(self, cursor: &mut Cursor<R>) -> Result<Self::Output, ParseError> {
157 let _timer = BoaProfiler::global().start_event("BindingRestElement", "Parsing");
158 cursor.expect(Punctuator::Spread, "rest parameter")?;
159
160 let param = BindingIdentifier::new(self.allow_yield, self.allow_await).parse(cursor)?;
161 Ok(Self::Output::new(param, None, true))
164 }
165}
166
167#[derive(Debug, Clone, Copy)]
176struct FormalParameter {
177 allow_yield: AllowYield,
178 allow_await: AllowAwait,
179}
180
181impl FormalParameter {
182 fn new<Y, A>(allow_yield: Y, allow_await: A) -> Self
184 where
185 Y: Into<AllowYield>,
186 A: Into<AllowAwait>,
187 {
188 Self {
189 allow_yield: allow_yield.into(),
190 allow_await: allow_await.into(),
191 }
192 }
193}
194
195impl<R> TokenParser<R> for FormalParameter
196where
197 R: Read,
198{
199 type Output = node::FormalParameter;
200
201 fn parse(self, cursor: &mut Cursor<R>) -> Result<Self::Output, ParseError> {
202 let _timer = BoaProfiler::global().start_event("FormalParameter", "Parsing");
203
204 let param = BindingIdentifier::new(self.allow_yield, self.allow_await).parse(cursor)?;
207
208 let init = if let Some(t) = cursor.peek(0)? {
209 if *t.kind() == TokenKind::Punctuator(Punctuator::Assign) {
211 Some(Initializer::new(true, self.allow_yield, self.allow_await).parse(cursor)?)
212 } else {
213 None
214 }
215 } else {
216 None
217 };
218
219 Ok(Self::Output::new(param, init, false))
220 }
221}
222
223pub(in crate::syntax::parser) type FunctionBody = FunctionStatementList;
230
231const FUNCTION_BREAK_TOKENS: [TokenKind; 1] = [TokenKind::Punctuator(Punctuator::CloseBlock)];
233
234#[derive(Debug, Clone, Copy)]
241pub(in crate::syntax::parser) struct FunctionStatementList {
242 allow_yield: AllowYield,
243 allow_await: AllowAwait,
244}
245
246impl FunctionStatementList {
247 pub(in crate::syntax::parser) fn new<Y, A>(allow_yield: Y, allow_await: A) -> Self
249 where
250 Y: Into<AllowYield>,
251 A: Into<AllowAwait>,
252 {
253 Self {
254 allow_yield: allow_yield.into(),
255 allow_await: allow_await.into(),
256 }
257 }
258}
259
260impl<R> TokenParser<R> for FunctionStatementList
261where
262 R: Read,
263{
264 type Output = node::StatementList;
265
266 fn parse(self, cursor: &mut Cursor<R>) -> Result<Self::Output, ParseError> {
267 let _timer = BoaProfiler::global().start_event("FunctionStatementList", "Parsing");
268
269 let global_strict_mode = cursor.strict_mode();
270 let mut strict = false;
271
272 if let Some(tk) = cursor.peek(0)? {
273 match tk.kind() {
274 TokenKind::Punctuator(Punctuator::CloseBlock) => {
275 return Ok(Vec::new().into());
276 }
277 TokenKind::StringLiteral(string) if string.as_ref() == "use strict" => {
278 cursor.set_strict_mode(true);
279 strict = true;
280 }
281 _ => {}
282 }
283 }
284
285 let statement_list = StatementList::new(
286 self.allow_yield,
287 self.allow_await,
288 true,
289 true,
290 &FUNCTION_BREAK_TOKENS,
291 )
292 .parse(cursor);
293
294 cursor.set_strict_mode(global_strict_mode);
296
297 let mut statement_list = statement_list?;
298 statement_list.set_strict(strict);
299 Ok(statement_list)
300 }
301}