1use 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 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 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 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 }
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 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 }
109
110 _ => match *expr {
111 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 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 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 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 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 let idx_of_rest_not_allowed = if count_of_trailing_comma == 0 {
295 len - 1
296 } else {
297 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 Some(ExprOrSpread {
319 spread: Some(dot3_token),
320 expr,
321 }) => {
322 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 self.reparse_expr_as_pat(pat_ty.element(), expr).map(Some)?
346 }
347 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 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 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 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(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(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 }
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 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 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}