swc_ecma_parser/parser/
pat.rs

1//! 13.3.3 Destructuring Binding Patterns
2
3use swc_common::Spanned;
4
5use super::*;
6use crate::parser::{expr::AssignTargetOrSpread, Parser};
7
8#[derive(Debug, Clone, Copy, PartialEq, Eq)]
9pub(crate) enum PatType {
10    BindingPat,
11    BindingElement,
12    /// AssignmentPattern
13    AssignPat,
14    AssignElement,
15}
16
17impl PatType {
18    fn element(self) -> Self {
19        match self {
20            PatType::BindingPat | PatType::BindingElement => PatType::BindingElement,
21            PatType::AssignPat | PatType::AssignElement => PatType::AssignElement,
22        }
23    }
24}
25
26impl<I: Tokens> Parser<I> {
27    pub fn parse_pat(&mut self) -> PResult<Pat> {
28        self.parse_binding_pat_or_ident(false)
29    }
30
31    /// argument of arrow is pattern, although idents in pattern is already
32    /// checked if is a keyword, it should also be checked if is arguments or
33    /// eval
34    fn pat_is_valid_argument_in_strict(&mut self, pat: &Pat) {
35        debug_assert!(self.ctx().contains(Context::Strict));
36        match pat {
37            Pat::Ident(i) => {
38                if i.is_reserved_in_strict_bind() {
39                    self.emit_strict_mode_err(i.span, SyntaxError::EvalAndArgumentsInStrict)
40                }
41            }
42            Pat::Array(arr) => {
43                for pat in arr.elems.iter().flatten() {
44                    self.pat_is_valid_argument_in_strict(pat)
45                }
46            }
47            Pat::Rest(r) => self.pat_is_valid_argument_in_strict(&r.arg),
48            Pat::Object(obj) => {
49                for prop in obj.props.iter() {
50                    match prop {
51                        ObjectPatProp::KeyValue(KeyValuePatProp { value, .. })
52                        | ObjectPatProp::Rest(RestPat { arg: value, .. }) => {
53                            self.pat_is_valid_argument_in_strict(value)
54                        }
55                        ObjectPatProp::Assign(AssignPatProp { key, .. }) => {
56                            if key.is_reserved_in_strict_bind() {
57                                self.emit_strict_mode_err(
58                                    key.span,
59                                    SyntaxError::EvalAndArgumentsInStrict,
60                                )
61                            }
62                        }
63                        #[cfg(swc_ast_unknown)]
64                        _ => unreachable!(),
65                    }
66                }
67            }
68            Pat::Assign(a) => self.pat_is_valid_argument_in_strict(&a.left),
69            Pat::Invalid(_) | Pat::Expr(_) => (),
70            #[cfg(swc_ast_unknown)]
71            _ => unreachable!(),
72        }
73    }
74
75    /// This does not return 'rest' pattern because non-last parameter cannot be
76    /// rest.
77    pub(super) fn reparse_expr_as_pat(&mut self, pat_ty: PatType, expr: Box<Expr>) -> PResult<Pat> {
78        if let Expr::Invalid(i) = *expr {
79            return Ok(i.into());
80        }
81        if pat_ty == PatType::AssignPat {
82            match *expr {
83                Expr::Object(..) | Expr::Array(..) => {
84                    // It is a Syntax Error if LeftHandSideExpression is either
85                    // an ObjectLiteral or an ArrayLiteral
86                    // and LeftHandSideExpression cannot
87                    // be reparsed as an AssignmentPattern.
88                }
89                _ => {
90                    self.check_assign_target(&expr, true);
91                }
92            }
93        }
94        self.reparse_expr_as_pat_inner(pat_ty, expr)
95    }
96
97    fn reparse_expr_as_pat_inner(&mut self, pat_ty: PatType, expr: Box<Expr>) -> PResult<Pat> {
98        // In dts, we do not reparse.
99        debug_assert!(!self.input().syntax().dts());
100        let span = expr.span();
101        if pat_ty == PatType::AssignPat {
102            match *expr {
103                Expr::Object(..) | Expr::Array(..) => {
104                    // It is a Syntax Error if LeftHandSideExpression is either
105                    // an ObjectLiteral or an ArrayLiteral
106                    // and LeftHandSideExpression cannot
107                    // be reparsed as an AssignmentPattern.
108                }
109
110                _ => match *expr {
111                    // It is a Syntax Error if the LeftHandSideExpression is
112                    // CoverParenthesizedExpressionAndArrowParameterList:(Expression) and
113                    // Expression derives a phrase that would produce a Syntax Error according
114                    // to these rules if that phrase were substituted for
115                    // LeftHandSideExpression. This rule is recursively applied.
116                    Expr::Paren(..) => {
117                        return Ok(expr.into());
118                    }
119                    Expr::Ident(i) => return Ok(i.into()),
120                    _ => {
121                        return Ok(expr.into());
122                    }
123                },
124            }
125        }
126
127        // AssignmentElement:
128        //      DestructuringAssignmentTarget Initializer[+In]?
129        //
130        // DestructuringAssignmentTarget:
131        //      LeftHandSideExpression
132        if pat_ty == PatType::AssignElement {
133            match *expr {
134                Expr::Array(..) | Expr::Object(..) => {}
135                Expr::Member(..)
136                | Expr::SuperProp(..)
137                | Expr::Call(..)
138                | Expr::New(..)
139                | Expr::Lit(..)
140                | Expr::Ident(..)
141                | Expr::Fn(..)
142                | Expr::Class(..)
143                | Expr::Paren(..)
144                | Expr::Tpl(..)
145                | Expr::TsAs(..) => {
146                    if !expr.is_valid_simple_assignment_target(self.ctx().contains(Context::Strict))
147                    {
148                        self.emit_err(span, SyntaxError::NotSimpleAssign)
149                    }
150                    match *expr {
151                        Expr::Ident(i) => return Ok(i.into()),
152                        _ => {
153                            return Ok(expr.into());
154                        }
155                    }
156                }
157                // It's special because of optional initializer
158                Expr::Assign(..) => {}
159                _ => self.emit_err(span, SyntaxError::InvalidPat),
160            }
161        }
162
163        match *expr {
164            Expr::Paren(..) => {
165                self.emit_err(span, SyntaxError::InvalidPat);
166                Ok(Invalid { span }.into())
167            }
168            Expr::Assign(
169                assign_expr @ AssignExpr {
170                    op: AssignOp::Assign,
171                    ..
172                },
173            ) => {
174                let AssignExpr {
175                    span, left, right, ..
176                } = assign_expr;
177                Ok(AssignPat {
178                    span,
179                    left: match left {
180                        AssignTarget::Simple(left) => {
181                            Box::new(self.reparse_expr_as_pat(pat_ty, left.into())?)
182                        }
183                        AssignTarget::Pat(pat) => pat.into(),
184                        #[cfg(swc_ast_unknown)]
185                        _ => unreachable!(),
186                    },
187                    right,
188                }
189                .into())
190            }
191            Expr::Object(ObjectLit {
192                span: object_span,
193                props,
194            }) => {
195                // {}
196                let len = props.len();
197                Ok(ObjectPat {
198                    span: object_span,
199                    props: props
200                        .into_iter()
201                        .enumerate()
202                        .map(|(idx, prop)| {
203                            let span = prop.span();
204                            match prop {
205                                PropOrSpread::Prop(prop) => match *prop {
206                                    Prop::Shorthand(id) => {
207                                        Ok(ObjectPatProp::Assign(AssignPatProp {
208                                            span: id.span(),
209                                            key: id.into(),
210                                            value: None,
211                                        }))
212                                    }
213                                    Prop::KeyValue(kv_prop) => {
214                                        Ok(ObjectPatProp::KeyValue(KeyValuePatProp {
215                                            key: kv_prop.key,
216                                            value: Box::new(self.reparse_expr_as_pat(
217                                                pat_ty.element(),
218                                                kv_prop.value,
219                                            )?),
220                                        }))
221                                    }
222                                    Prop::Assign(assign_prop) => {
223                                        Ok(ObjectPatProp::Assign(AssignPatProp {
224                                            span,
225                                            key: assign_prop.key.into(),
226                                            value: Some(assign_prop.value),
227                                        }))
228                                    }
229                                    _ => syntax_error!(self, prop.span(), SyntaxError::InvalidPat),
230                                },
231
232                                PropOrSpread::Spread(SpreadElement { dot3_token, expr }) => {
233                                    if idx != len - 1 {
234                                        self.emit_err(span, SyntaxError::NonLastRestParam)
235                                    } else if let Some(trailing_comma) =
236                                        self.state().trailing_commas.get(&object_span.lo)
237                                    {
238                                        self.emit_err(
239                                            *trailing_comma,
240                                            SyntaxError::CommaAfterRestElement,
241                                        );
242                                    };
243
244                                    let element_pat_ty = pat_ty.element();
245                                    let pat = if let PatType::BindingElement = element_pat_ty {
246                                        if let Expr::Ident(i) = *expr {
247                                            i.into()
248                                        } else {
249                                            self.emit_err(span, SyntaxError::DotsWithoutIdentifier);
250                                            Pat::Invalid(Invalid { span })
251                                        }
252                                    } else {
253                                        self.reparse_expr_as_pat(element_pat_ty, expr)?
254                                    };
255                                    if let Pat::Assign(_) = pat {
256                                        self.emit_err(span, SyntaxError::TS1048)
257                                    };
258                                    Ok(ObjectPatProp::Rest(RestPat {
259                                        span,
260                                        dot3_token,
261                                        arg: Box::new(pat),
262                                        type_ann: None,
263                                    }))
264                                }
265                                #[cfg(swc_ast_unknown)]
266                                _ => unreachable!(),
267                            }
268                        })
269                        .collect::<PResult<_>>()?,
270                    optional: false,
271                    type_ann: None,
272                }
273                .into())
274            }
275            Expr::Ident(ident) => Ok(ident.into()),
276            Expr::Array(ArrayLit {
277                elems: mut exprs, ..
278            }) => {
279                if exprs.is_empty() {
280                    return Ok(ArrayPat {
281                        span,
282                        elems: Vec::new(),
283                        optional: false,
284                        type_ann: None,
285                    }
286                    .into());
287                }
288                // Trailing comma may exist. We should remove those commas.
289                let count_of_trailing_comma =
290                    exprs.iter().rev().take_while(|e| e.is_none()).count();
291                let len = exprs.len();
292                let mut params = Vec::with_capacity(exprs.len() - count_of_trailing_comma);
293                // Comma or other pattern cannot follow a rest pattern.
294                let idx_of_rest_not_allowed = if count_of_trailing_comma == 0 {
295                    len - 1
296                } else {
297                    // last element is comma, so rest is not allowed for every pattern element.
298                    len - count_of_trailing_comma
299                };
300                for expr in exprs.drain(..idx_of_rest_not_allowed) {
301                    match expr {
302                        Some(
303                            expr @ ExprOrSpread {
304                                spread: Some(..), ..
305                            },
306                        ) => self.emit_err(expr.span(), SyntaxError::NonLastRestParam),
307                        Some(ExprOrSpread { expr, .. }) => {
308                            params.push(self.reparse_expr_as_pat(pat_ty.element(), expr).map(Some)?)
309                        }
310                        None => params.push(None),
311                    }
312                }
313                if count_of_trailing_comma == 0 {
314                    let expr = exprs.into_iter().next().unwrap();
315                    let outer_expr_span = expr.span();
316                    let last = match expr {
317                        // Rest
318                        Some(ExprOrSpread {
319                            spread: Some(dot3_token),
320                            expr,
321                        }) => {
322                            // TODO: is BindingPat correct?
323                            if let Expr::Assign(_) = *expr {
324                                self.emit_err(outer_expr_span, SyntaxError::TS1048);
325                            };
326                            if let Some(trailing_comma) = self.state().trailing_commas.get(&span.lo)
327                            {
328                                self.emit_err(*trailing_comma, SyntaxError::CommaAfterRestElement);
329                            }
330                            let expr_span = expr.span();
331                            self.reparse_expr_as_pat(pat_ty.element(), expr)
332                                .map(|pat| {
333                                    RestPat {
334                                        span: expr_span,
335                                        dot3_token,
336                                        arg: Box::new(pat),
337                                        type_ann: None,
338                                    }
339                                    .into()
340                                })
341                                .map(Some)?
342                        }
343                        Some(ExprOrSpread { expr, .. }) => {
344                            // TODO: is BindingPat correct?
345                            self.reparse_expr_as_pat(pat_ty.element(), expr).map(Some)?
346                        }
347                        // TODO: syntax error if last element is ellison and ...rest exists.
348                        None => None,
349                    };
350                    params.push(last);
351                }
352                Ok(ArrayPat {
353                    span,
354                    elems: params,
355                    optional: false,
356                    type_ann: None,
357                }
358                .into())
359            }
360
361            // Invalid patterns.
362            // Note that assignment expression with '=' is valid, and handled above.
363            Expr::Lit(..) | Expr::Assign(..) => {
364                self.emit_err(span, SyntaxError::InvalidPat);
365                Ok(Invalid { span }.into())
366            }
367
368            Expr::Yield(..) if self.ctx().contains(Context::InGenerator) => {
369                self.emit_err(span, SyntaxError::InvalidPat);
370                Ok(Invalid { span }.into())
371            }
372
373            _ => {
374                self.emit_err(span, SyntaxError::InvalidPat);
375
376                Ok(Invalid { span }.into())
377            }
378        }
379    }
380
381    pub(super) fn parse_binding_element(&mut self) -> PResult<Pat> {
382        trace_cur!(self, parse_binding_element);
383
384        let start = self.cur_pos();
385        let left = self.parse_binding_pat_or_ident(false)?;
386
387        if self.input_mut().eat(Token::Eq) {
388            let right = self.allow_in_expr(Self::parse_assignment_expr)?;
389
390            if self.ctx().contains(Context::InDeclare) {
391                self.emit_err(self.span(start), SyntaxError::TS2371);
392            }
393
394            return Ok(AssignPat {
395                span: self.span(start),
396                left: Box::new(left),
397                right,
398            }
399            .into());
400        }
401
402        Ok(left)
403    }
404
405    pub(crate) fn parse_binding_pat_or_ident(&mut self, disallow_let: bool) -> PResult<Pat> {
406        trace_cur!(self, parse_binding_pat_or_ident);
407
408        let cur = self.input().cur();
409        if cur.is_word() {
410            self.parse_binding_ident(disallow_let).map(Pat::from)
411        } else if cur == Token::LBracket {
412            self.parse_array_binding_pat()
413        } else if cur == Token::LBrace {
414            self.parse_object_pat()
415        } else if cur == Token::Error {
416            let err = self.input_mut().expect_error_token_and_bump();
417            Err(err)
418        } else {
419            unexpected!(self, "yield, an identifier, [ or {")
420        }
421    }
422
423    fn parse_array_binding_pat(&mut self) -> PResult<Pat> {
424        let start = self.cur_pos();
425
426        self.assert_and_bump(Token::LBracket);
427
428        let mut elems = Vec::new();
429
430        let mut rest_span = Span::default();
431
432        while !self.input().is(Token::RBracket) {
433            if self.input_mut().eat(Token::Comma) {
434                elems.push(None);
435                continue;
436            }
437
438            if !rest_span.is_dummy() {
439                self.emit_err(rest_span, SyntaxError::NonLastRestParam);
440            }
441
442            let start = self.cur_pos();
443
444            let mut is_rest = false;
445            if self.input_mut().eat(Token::DotDotDot) {
446                is_rest = true;
447                let dot3_token = self.span(start);
448
449                let pat = self.parse_binding_pat_or_ident(false)?;
450                rest_span = self.span(start);
451                let pat = RestPat {
452                    span: rest_span,
453                    dot3_token,
454                    arg: Box::new(pat),
455                    type_ann: None,
456                }
457                .into();
458                elems.push(Some(pat));
459            } else {
460                elems.push(self.parse_binding_element().map(Some)?);
461            }
462
463            if !self.input().is(Token::RBracket) {
464                expect!(self, Token::Comma);
465                if is_rest && self.input().is(Token::RBracket) {
466                    self.emit_err(self.input().prev_span(), SyntaxError::CommaAfterRestElement);
467                }
468            }
469        }
470
471        expect!(self, Token::RBracket);
472        let optional = (self.input().syntax().dts() || self.ctx().contains(Context::InDeclare))
473            && self.input_mut().eat(Token::QuestionMark);
474
475        Ok(ArrayPat {
476            span: self.span(start),
477            elems,
478            optional,
479            type_ann: None,
480        }
481        .into())
482    }
483
484    /// spec: 'FormalParameter'
485    ///
486    /// babel: `parseAssignableListItem`
487    fn parse_formal_param_pat(&mut self) -> PResult<Pat> {
488        let start = self.cur_pos();
489
490        let has_modifier = self.eat_any_ts_modifier()?;
491
492        let pat_start = self.cur_pos();
493        let mut pat = self.parse_binding_element()?;
494        let mut opt = false;
495
496        if self.input().syntax().typescript() {
497            if self.input_mut().eat(Token::QuestionMark) {
498                match pat {
499                    Pat::Ident(BindingIdent {
500                        id:
501                            Ident {
502                                ref mut optional, ..
503                            },
504                        ..
505                    })
506                    | Pat::Array(ArrayPat {
507                        ref mut optional, ..
508                    })
509                    | Pat::Object(ObjectPat {
510                        ref mut optional, ..
511                    }) => {
512                        *optional = true;
513                        opt = true;
514                    }
515                    _ if self.input().syntax().dts() || self.ctx().contains(Context::InDeclare) => {
516                    }
517                    _ => {
518                        syntax_error!(
519                            self,
520                            self.input().prev_span(),
521                            SyntaxError::TsBindingPatCannotBeOptional
522                        );
523                    }
524                }
525            }
526
527            match pat {
528                Pat::Array(ArrayPat {
529                    ref mut type_ann,
530                    ref mut span,
531                    ..
532                })
533                | Pat::Object(ObjectPat {
534                    ref mut type_ann,
535                    ref mut span,
536                    ..
537                })
538                | Pat::Rest(RestPat {
539                    ref mut type_ann,
540                    ref mut span,
541                    ..
542                }) => {
543                    let new_type_ann = self.try_parse_ts_type_ann()?;
544                    if new_type_ann.is_some() {
545                        *span = Span::new_with_checked(pat_start, self.input().prev_span().hi);
546                    }
547                    *type_ann = new_type_ann;
548                }
549
550                Pat::Ident(BindingIdent {
551                    ref mut type_ann, ..
552                }) => {
553                    let new_type_ann = self.try_parse_ts_type_ann()?;
554                    *type_ann = new_type_ann;
555                }
556
557                Pat::Assign(AssignPat { ref mut span, .. }) => {
558                    if (self.try_parse_ts_type_ann()?).is_some() {
559                        *span = Span::new_with_checked(pat_start, self.input().prev_span().hi);
560                        self.emit_err(*span, SyntaxError::TSTypeAnnotationAfterAssign);
561                    }
562                }
563                Pat::Invalid(..) => {}
564                _ => unreachable!("invalid syntax: Pat: {:?}", pat),
565            }
566        }
567
568        let pat = if self.input_mut().eat(Token::Eq) {
569            // `=` cannot follow optional parameter.
570            if opt {
571                self.emit_err(pat.span(), SyntaxError::TS1015);
572            }
573
574            let right = self.parse_assignment_expr()?;
575            if self.ctx().contains(Context::InDeclare) {
576                self.emit_err(self.span(start), SyntaxError::TS2371);
577            }
578
579            AssignPat {
580                span: self.span(start),
581                left: Box::new(pat),
582                right,
583            }
584            .into()
585        } else {
586            pat
587        };
588
589        if has_modifier {
590            self.emit_err(self.span(start), SyntaxError::TS2369);
591            return Ok(pat);
592        }
593
594        Ok(pat)
595    }
596
597    fn parse_constructor_param(
598        &mut self,
599        param_start: BytePos,
600        decorators: Vec<Decorator>,
601    ) -> PResult<ParamOrTsParamProp> {
602        let (accessibility, is_override, readonly) = if self.input().syntax().typescript() {
603            let accessibility = self.parse_access_modifier()?;
604            (
605                accessibility,
606                self.parse_ts_modifier(&["override"], false)?.is_some(),
607                self.parse_ts_modifier(&["readonly"], false)?.is_some(),
608            )
609        } else {
610            (None, false, false)
611        };
612        if accessibility.is_none() && !is_override && !readonly {
613            let pat = self.parse_formal_param_pat()?;
614            Ok(ParamOrTsParamProp::Param(Param {
615                span: self.span(param_start),
616                decorators,
617                pat,
618            }))
619        } else {
620            let param = match self.parse_formal_param_pat()? {
621                Pat::Ident(i) => TsParamPropParam::Ident(i),
622                Pat::Assign(a) => TsParamPropParam::Assign(a),
623                node => syntax_error!(self, node.span(), SyntaxError::TsInvalidParamPropPat),
624            };
625            Ok(ParamOrTsParamProp::TsParamProp(TsParamProp {
626                span: self.span(param_start),
627                accessibility,
628                is_override,
629                readonly,
630                decorators,
631                param,
632            }))
633        }
634    }
635
636    pub(crate) fn parse_constructor_params(&mut self) -> PResult<Vec<ParamOrTsParamProp>> {
637        let mut params = Vec::new();
638        let mut rest_span = Span::default();
639
640        while !self.input().is(Token::RParen) {
641            if !rest_span.is_dummy() {
642                self.emit_err(rest_span, SyntaxError::TS1014);
643            }
644
645            let param_start = self.cur_pos();
646            let decorators = self.parse_decorators(false)?;
647            let pat_start = self.cur_pos();
648
649            let mut is_rest = false;
650            if self.input_mut().eat(Token::DotDotDot) {
651                is_rest = true;
652                let dot3_token = self.span(pat_start);
653
654                let pat = self.parse_binding_pat_or_ident(false)?;
655                let type_ann =
656                    if self.input().syntax().typescript() && self.input().is(Token::Colon) {
657                        let cur_pos = self.cur_pos();
658                        Some(self.parse_ts_type_ann(/* eat_colon */ true, cur_pos)?)
659                    } else {
660                        None
661                    };
662
663                rest_span = self.span(pat_start);
664                let pat = RestPat {
665                    span: rest_span,
666                    dot3_token,
667                    arg: Box::new(pat),
668                    type_ann,
669                }
670                .into();
671                params.push(ParamOrTsParamProp::Param(Param {
672                    span: self.span(param_start),
673                    decorators,
674                    pat,
675                }));
676            } else {
677                params.push(self.parse_constructor_param(param_start, decorators)?);
678            }
679
680            if !self.input().is(Token::RParen) {
681                expect!(self, Token::Comma);
682                if self.input().is(Token::RParen) && is_rest {
683                    self.emit_err(self.input().prev_span(), SyntaxError::CommaAfterRestElement);
684                }
685            }
686        }
687
688        Ok(params)
689    }
690
691    pub(crate) fn parse_formal_params(&mut self) -> PResult<Vec<Param>> {
692        let mut params = Vec::new();
693        let mut rest_span = Span::default();
694
695        while !self.input().is(Token::RParen) {
696            if !rest_span.is_dummy() {
697                self.emit_err(rest_span, SyntaxError::TS1014);
698            }
699
700            let param_start = self.cur_pos();
701            let decorators = self.parse_decorators(false)?;
702            let pat_start = self.cur_pos();
703
704            let pat = if self.input_mut().eat(Token::DotDotDot) {
705                let dot3_token = self.span(pat_start);
706
707                let mut pat = self.parse_binding_pat_or_ident(false)?;
708
709                if self.input_mut().eat(Token::Eq) {
710                    let right = self.parse_assignment_expr()?;
711                    self.emit_err(pat.span(), SyntaxError::TS1048);
712                    pat = AssignPat {
713                        span: self.span(pat_start),
714                        left: Box::new(pat),
715                        right,
716                    }
717                    .into();
718                }
719
720                let type_ann =
721                    if self.input().syntax().typescript() && self.input().is(Token::Colon) {
722                        let cur_pos = self.cur_pos();
723                        let ty = self.parse_ts_type_ann(/* eat_colon */ true, cur_pos)?;
724                        Some(ty)
725                    } else {
726                        None
727                    };
728
729                rest_span = self.span(pat_start);
730                let pat = RestPat {
731                    span: rest_span,
732                    dot3_token,
733                    arg: Box::new(pat),
734                    type_ann,
735                }
736                .into();
737
738                if self.syntax().typescript() && self.input_mut().eat(Token::QuestionMark) {
739                    self.emit_err(self.input().prev_span(), SyntaxError::TS1047);
740                    //
741                }
742
743                pat
744            } else {
745                self.parse_formal_param_pat()?
746            };
747            let is_rest = matches!(pat, Pat::Rest(_));
748
749            params.push(Param {
750                span: self.span(param_start),
751                decorators,
752                pat,
753            });
754
755            if !self.input().is(Token::RParen) {
756                expect!(self, Token::Comma);
757                if is_rest && self.input().is(Token::RParen) {
758                    self.emit_err(self.input().prev_span(), SyntaxError::CommaAfterRestElement);
759                }
760            }
761        }
762
763        Ok(params)
764    }
765
766    pub(crate) fn parse_unique_formal_params(&mut self) -> PResult<Vec<Param>> {
767        // FIXME: This is wrong
768        self.parse_formal_params()
769    }
770
771    pub(super) fn parse_paren_items_as_params(
772        &mut self,
773        mut exprs: Vec<AssignTargetOrSpread>,
774        trailing_comma: Option<Span>,
775    ) -> PResult<Vec<Pat>> {
776        let pat_ty = PatType::BindingPat;
777
778        let len = exprs.len();
779        if len == 0 {
780            return Ok(Vec::new());
781        }
782
783        let mut params = Vec::with_capacity(len);
784
785        for expr in exprs.drain(..len - 1) {
786            match expr {
787                AssignTargetOrSpread::ExprOrSpread(ExprOrSpread {
788                    spread: Some(..), ..
789                })
790                | AssignTargetOrSpread::Pat(Pat::Rest(..)) => {
791                    self.emit_err(expr.span(), SyntaxError::TS1014)
792                }
793                AssignTargetOrSpread::ExprOrSpread(ExprOrSpread {
794                    spread: None, expr, ..
795                }) => params.push(self.reparse_expr_as_pat(pat_ty, expr)?),
796                AssignTargetOrSpread::Pat(pat) => params.push(pat),
797            }
798        }
799
800        debug_assert_eq!(exprs.len(), 1);
801        let expr = exprs.pop().unwrap();
802        let outer_expr_span = expr.span();
803        let last = match expr {
804            // Rest
805            AssignTargetOrSpread::ExprOrSpread(ExprOrSpread {
806                spread: Some(dot3_token),
807                expr,
808            }) => {
809                if let Expr::Assign(_) = *expr {
810                    self.emit_err(outer_expr_span, SyntaxError::TS1048)
811                };
812                if let Some(trailing_comma) = trailing_comma {
813                    self.emit_err(trailing_comma, SyntaxError::CommaAfterRestElement);
814                }
815                let expr_span = expr.span();
816                self.reparse_expr_as_pat(pat_ty, expr).map(|pat| {
817                    RestPat {
818                        span: expr_span,
819                        dot3_token,
820                        arg: Box::new(pat),
821                        type_ann: None,
822                    }
823                    .into()
824                })?
825            }
826            AssignTargetOrSpread::ExprOrSpread(ExprOrSpread { expr, .. }) => {
827                self.reparse_expr_as_pat(pat_ty, expr)?
828            }
829            AssignTargetOrSpread::Pat(pat) => {
830                if let Some(trailing_comma) = trailing_comma {
831                    if let Pat::Rest(..) = pat {
832                        self.emit_err(trailing_comma, SyntaxError::CommaAfterRestElement);
833                    }
834                }
835                pat
836            }
837        };
838        params.push(last);
839
840        if self.ctx().contains(Context::Strict) {
841            for param in params.iter() {
842                self.pat_is_valid_argument_in_strict(param)
843            }
844        }
845        Ok(params)
846    }
847}
848
849#[cfg(test)]
850mod tests {
851    use swc_atoms::atom;
852    use swc_common::DUMMY_SP as span;
853    use swc_ecma_visit::assert_eq_ignore_span;
854
855    use super::*;
856
857    fn array_pat(s: &'static str) -> Pat {
858        test_parser(s, Syntax::default(), |p| p.parse_array_binding_pat())
859    }
860
861    fn object_pat(s: &'static str) -> Pat {
862        test_parser(s, Syntax::default(), |p| {
863            p.parse_binding_pat_or_ident(false)
864        })
865    }
866
867    fn ident(s: &str) -> Ident {
868        Ident::new_no_ctxt(s.into(), span)
869    }
870
871    fn ident_name(s: &str) -> IdentName {
872        IdentName::new(s.into(), span)
873    }
874
875    fn rest() -> Option<Pat> {
876        Some(
877            RestPat {
878                span,
879                dot3_token: span,
880                type_ann: None,
881                arg: ident("tail").into(),
882            }
883            .into(),
884        )
885    }
886
887    #[test]
888    fn array_pat_simple() {
889        assert_eq_ignore_span!(
890            array_pat("[a, [b], [c]]"),
891            Pat::Array(ArrayPat {
892                span,
893                optional: false,
894                elems: vec![
895                    Some(Pat::Ident(ident("a").into())),
896                    Some(Pat::Array(ArrayPat {
897                        span,
898                        optional: false,
899                        elems: vec![Some(Pat::Ident(ident("b").into()))],
900                        type_ann: None
901                    })),
902                    Some(Pat::Array(ArrayPat {
903                        span,
904                        optional: false,
905                        elems: vec![Some(Pat::Ident(ident("c").into()))],
906                        type_ann: None
907                    }))
908                ],
909                type_ann: None
910            })
911        );
912    }
913
914    #[test]
915    fn array_pat_empty_start() {
916        assert_eq_ignore_span!(
917            array_pat("[, a, [b], [c]]"),
918            Pat::Array(ArrayPat {
919                span,
920                optional: false,
921                elems: vec![
922                    None,
923                    Some(Pat::Ident(ident("a").into())),
924                    Some(Pat::Array(ArrayPat {
925                        span,
926                        optional: false,
927                        elems: vec![Some(Pat::Ident(ident("b").into()))],
928                        type_ann: None
929                    })),
930                    Some(Pat::Array(ArrayPat {
931                        span,
932                        optional: false,
933                        elems: vec![Some(Pat::Ident(ident("c").into()))],
934                        type_ann: None
935                    }))
936                ],
937                type_ann: None
938            })
939        );
940    }
941
942    #[test]
943    fn array_pat_empty() {
944        assert_eq_ignore_span!(
945            array_pat("[a, , [b], [c]]"),
946            Pat::Array(ArrayPat {
947                span,
948                optional: false,
949                elems: vec![
950                    Some(Pat::Ident(ident("a").into())),
951                    None,
952                    Some(Pat::Array(ArrayPat {
953                        span,
954                        optional: false,
955                        elems: vec![Some(Pat::Ident(ident("b").into()))],
956                        type_ann: None
957                    })),
958                    Some(Pat::Array(ArrayPat {
959                        span,
960                        optional: false,
961                        elems: vec![Some(Pat::Ident(ident("c").into()))],
962                        type_ann: None
963                    }))
964                ],
965                type_ann: None
966            })
967        );
968    }
969
970    #[test]
971    fn array_pat_empty_end() {
972        assert_eq_ignore_span!(
973            array_pat("[a, ,]"),
974            Pat::Array(ArrayPat {
975                span,
976                optional: false,
977                elems: vec![Some(Pat::Ident(ident("a").into())), None,],
978                type_ann: None
979            })
980        );
981    }
982
983    #[test]
984    fn array_binding_pattern_tail() {
985        assert_eq_ignore_span!(
986            array_pat("[...tail]"),
987            Pat::Array(ArrayPat {
988                span,
989                optional: false,
990                elems: vec![rest()],
991                type_ann: None
992            })
993        );
994    }
995
996    #[test]
997    fn array_binding_pattern_assign() {
998        assert_eq_ignore_span!(
999            array_pat("[,a=1,]"),
1000            Pat::Array(ArrayPat {
1001                span,
1002                optional: false,
1003                elems: vec![
1004                    None,
1005                    Some(Pat::Assign(AssignPat {
1006                        span,
1007                        left: Box::new(Pat::Ident(ident("a").into())),
1008                        right: Box::new(Expr::Lit(Lit::Num(Number {
1009                            span,
1010                            value: 1.0,
1011                            raw: Some(atom!("1"))
1012                        })))
1013                    }))
1014                ],
1015                type_ann: None
1016            })
1017        );
1018    }
1019
1020    #[test]
1021    fn array_binding_pattern_tail_with_elems() {
1022        assert_eq_ignore_span!(
1023            array_pat("[,,,...tail]"),
1024            Pat::Array(ArrayPat {
1025                span,
1026                optional: false,
1027                elems: vec![None, None, None, rest()],
1028                type_ann: None
1029            })
1030        );
1031    }
1032
1033    #[test]
1034    fn array_binding_pattern_tail_inside_tail() {
1035        assert_eq_ignore_span!(
1036            array_pat("[,,,...[...tail]]"),
1037            Pat::Array(ArrayPat {
1038                span,
1039                optional: false,
1040                elems: vec![
1041                    None,
1042                    None,
1043                    None,
1044                    Some(Pat::Rest(RestPat {
1045                        span,
1046                        dot3_token: span,
1047                        type_ann: None,
1048                        arg: Box::new(Pat::Array(ArrayPat {
1049                            span,
1050                            optional: false,
1051                            elems: vec![rest()],
1052                            type_ann: None
1053                        }))
1054                    }))
1055                ],
1056                type_ann: None
1057            })
1058        );
1059    }
1060
1061    #[test]
1062    fn object_binding_pattern_tail() {
1063        assert_eq_ignore_span!(
1064            object_pat("{...obj}"),
1065            Pat::Object(ObjectPat {
1066                span,
1067                type_ann: None,
1068                optional: false,
1069                props: vec![ObjectPatProp::Rest(RestPat {
1070                    span,
1071                    dot3_token: span,
1072                    type_ann: None,
1073                    arg: Box::new(Pat::Ident(ident("obj").into()))
1074                })]
1075            })
1076        );
1077    }
1078
1079    #[test]
1080    fn object_binding_pattern_with_prop() {
1081        assert_eq_ignore_span!(
1082            object_pat("{prop = 10 }"),
1083            Pat::Object(ObjectPat {
1084                span,
1085                type_ann: None,
1086                optional: false,
1087                props: vec![ObjectPatProp::Assign(AssignPatProp {
1088                    span,
1089                    key: ident("prop").into(),
1090                    value: Some(Box::new(Expr::Lit(Lit::Num(Number {
1091                        span,
1092                        value: 10.0,
1093                        raw: Some(atom!("10"))
1094                    }))))
1095                })]
1096            })
1097        );
1098    }
1099
1100    #[test]
1101    fn object_binding_pattern_with_prop_and_label() {
1102        fn prop(key: PropName, assign_name: &str, expr: Expr) -> PropOrSpread {
1103            PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
1104                key,
1105                value: AssignExpr {
1106                    span,
1107                    op: AssignOp::Assign,
1108                    left: ident(assign_name).into(),
1109                    right: Box::new(expr),
1110                }
1111                .into(),
1112            })))
1113        }
1114
1115        assert_eq_ignore_span!(
1116            object_pat(
1117                "{obj = {$: num = 10, '': sym = '', \" \": quote = \" \", _: under = [...tail],}}"
1118            ),
1119            Pat::Object(ObjectPat {
1120                span,
1121                type_ann: None,
1122                optional: false,
1123                props: vec![ObjectPatProp::Assign(AssignPatProp {
1124                    span,
1125                    key: ident("obj").into(),
1126                    value: Some(Box::new(Expr::Object(ObjectLit {
1127                        span,
1128                        props: vec![
1129                            prop(
1130                                PropName::Ident(ident_name("$")),
1131                                "num",
1132                                Expr::Lit(Lit::Num(Number {
1133                                    span,
1134                                    value: 10.0,
1135                                    raw: Some(atom!("10"))
1136                                }))
1137                            ),
1138                            prop(
1139                                PropName::Str(Str {
1140                                    span,
1141                                    value: atom!("").into(),
1142                                    raw: Some(atom!("''")),
1143                                }),
1144                                "sym",
1145                                Expr::Lit(Lit::Str(Str {
1146                                    span,
1147                                    value: atom!("").into(),
1148                                    raw: Some(atom!("''")),
1149                                }))
1150                            ),
1151                            prop(
1152                                PropName::Str(Str {
1153                                    span,
1154                                    value: atom!(" ").into(),
1155                                    raw: Some(atom!("\" \"")),
1156                                }),
1157                                "quote",
1158                                Expr::Lit(Lit::Str(Str {
1159                                    span,
1160                                    value: atom!(" ").into(),
1161                                    raw: Some(atom!("\" \"")),
1162                                }))
1163                            ),
1164                            prop(
1165                                PropName::Ident(ident_name("_")),
1166                                "under",
1167                                Expr::Array(ArrayLit {
1168                                    span,
1169                                    elems: vec![Some(ExprOrSpread {
1170                                        spread: Some(span),
1171                                        expr: Box::new(Expr::Ident(ident("tail")))
1172                                    })]
1173                                })
1174                            ),
1175                        ]
1176                    })))
1177                })]
1178            })
1179        );
1180    }
1181}