swc_ecma_parser/parser/
pat.rs

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