swc_ecma_parser/parser/
pat.rs

1//! 13.3.3 Destructuring Binding Patterns
2
3use swc_ecma_lexer::common::parser::pat::parse_binding_pat_or_ident;
4
5use super::*;
6use crate::parser::Parser;
7
8impl<I: Tokens> Parser<I> {
9    pub fn parse_pat(&mut self) -> PResult<Pat> {
10        parse_binding_pat_or_ident(self, false)
11    }
12}
13
14#[cfg(test)]
15mod tests {
16    use swc_atoms::atom;
17    use swc_common::DUMMY_SP as span;
18    use swc_ecma_lexer::common::parser::pat::parse_array_binding_pat;
19    use swc_ecma_visit::assert_eq_ignore_span;
20
21    use super::*;
22
23    fn array_pat(s: &'static str) -> Pat {
24        test_parser(s, Syntax::default(), |p| parse_array_binding_pat(p))
25    }
26
27    fn object_pat(s: &'static str) -> Pat {
28        test_parser(s, Syntax::default(), |p| {
29            parse_binding_pat_or_ident(p, false)
30        })
31    }
32
33    fn ident(s: &str) -> Ident {
34        Ident::new_no_ctxt(s.into(), span)
35    }
36
37    fn ident_name(s: &str) -> IdentName {
38        IdentName::new(s.into(), span)
39    }
40
41    fn rest() -> Option<Pat> {
42        Some(
43            RestPat {
44                span,
45                dot3_token: span,
46                type_ann: None,
47                arg: ident("tail").into(),
48            }
49            .into(),
50        )
51    }
52
53    #[test]
54    fn array_pat_simple() {
55        assert_eq_ignore_span!(
56            array_pat("[a, [b], [c]]"),
57            Pat::Array(ArrayPat {
58                span,
59                optional: false,
60                elems: vec![
61                    Some(Pat::Ident(ident("a").into())),
62                    Some(Pat::Array(ArrayPat {
63                        span,
64                        optional: false,
65                        elems: vec![Some(Pat::Ident(ident("b").into()))],
66                        type_ann: None
67                    })),
68                    Some(Pat::Array(ArrayPat {
69                        span,
70                        optional: false,
71                        elems: vec![Some(Pat::Ident(ident("c").into()))],
72                        type_ann: None
73                    }))
74                ],
75                type_ann: None
76            })
77        );
78    }
79
80    #[test]
81    fn array_pat_empty_start() {
82        assert_eq_ignore_span!(
83            array_pat("[, a, [b], [c]]"),
84            Pat::Array(ArrayPat {
85                span,
86                optional: false,
87                elems: vec![
88                    None,
89                    Some(Pat::Ident(ident("a").into())),
90                    Some(Pat::Array(ArrayPat {
91                        span,
92                        optional: false,
93                        elems: vec![Some(Pat::Ident(ident("b").into()))],
94                        type_ann: None
95                    })),
96                    Some(Pat::Array(ArrayPat {
97                        span,
98                        optional: false,
99                        elems: vec![Some(Pat::Ident(ident("c").into()))],
100                        type_ann: None
101                    }))
102                ],
103                type_ann: None
104            })
105        );
106    }
107
108    #[test]
109    fn array_pat_empty() {
110        assert_eq_ignore_span!(
111            array_pat("[a, , [b], [c]]"),
112            Pat::Array(ArrayPat {
113                span,
114                optional: false,
115                elems: vec![
116                    Some(Pat::Ident(ident("a").into())),
117                    None,
118                    Some(Pat::Array(ArrayPat {
119                        span,
120                        optional: false,
121                        elems: vec![Some(Pat::Ident(ident("b").into()))],
122                        type_ann: None
123                    })),
124                    Some(Pat::Array(ArrayPat {
125                        span,
126                        optional: false,
127                        elems: vec![Some(Pat::Ident(ident("c").into()))],
128                        type_ann: None
129                    }))
130                ],
131                type_ann: None
132            })
133        );
134    }
135
136    #[test]
137    fn array_pat_empty_end() {
138        assert_eq_ignore_span!(
139            array_pat("[a, ,]"),
140            Pat::Array(ArrayPat {
141                span,
142                optional: false,
143                elems: vec![Some(Pat::Ident(ident("a").into())), None,],
144                type_ann: None
145            })
146        );
147    }
148
149    #[test]
150    fn array_binding_pattern_tail() {
151        assert_eq_ignore_span!(
152            array_pat("[...tail]"),
153            Pat::Array(ArrayPat {
154                span,
155                optional: false,
156                elems: vec![rest()],
157                type_ann: None
158            })
159        );
160    }
161
162    #[test]
163    fn array_binding_pattern_assign() {
164        assert_eq_ignore_span!(
165            array_pat("[,a=1,]"),
166            Pat::Array(ArrayPat {
167                span,
168                optional: false,
169                elems: vec![
170                    None,
171                    Some(Pat::Assign(AssignPat {
172                        span,
173                        left: Box::new(Pat::Ident(ident("a").into())),
174                        right: Box::new(Expr::Lit(Lit::Num(Number {
175                            span,
176                            value: 1.0,
177                            raw: Some(atom!("1"))
178                        })))
179                    }))
180                ],
181                type_ann: None
182            })
183        );
184    }
185
186    #[test]
187    fn array_binding_pattern_tail_with_elems() {
188        assert_eq_ignore_span!(
189            array_pat("[,,,...tail]"),
190            Pat::Array(ArrayPat {
191                span,
192                optional: false,
193                elems: vec![None, None, None, rest()],
194                type_ann: None
195            })
196        );
197    }
198
199    #[test]
200    fn array_binding_pattern_tail_inside_tail() {
201        assert_eq_ignore_span!(
202            array_pat("[,,,...[...tail]]"),
203            Pat::Array(ArrayPat {
204                span,
205                optional: false,
206                elems: vec![
207                    None,
208                    None,
209                    None,
210                    Some(Pat::Rest(RestPat {
211                        span,
212                        dot3_token: span,
213                        type_ann: None,
214                        arg: Box::new(Pat::Array(ArrayPat {
215                            span,
216                            optional: false,
217                            elems: vec![rest()],
218                            type_ann: None
219                        }))
220                    }))
221                ],
222                type_ann: None
223            })
224        );
225    }
226
227    #[test]
228    fn object_binding_pattern_tail() {
229        assert_eq_ignore_span!(
230            object_pat("{...obj}"),
231            Pat::Object(ObjectPat {
232                span,
233                type_ann: None,
234                optional: false,
235                props: vec![ObjectPatProp::Rest(RestPat {
236                    span,
237                    dot3_token: span,
238                    type_ann: None,
239                    arg: Box::new(Pat::Ident(ident("obj").into()))
240                })]
241            })
242        );
243    }
244
245    #[test]
246    fn object_binding_pattern_with_prop() {
247        assert_eq_ignore_span!(
248            object_pat("{prop = 10 }"),
249            Pat::Object(ObjectPat {
250                span,
251                type_ann: None,
252                optional: false,
253                props: vec![ObjectPatProp::Assign(AssignPatProp {
254                    span,
255                    key: ident("prop").into(),
256                    value: Some(Box::new(Expr::Lit(Lit::Num(Number {
257                        span,
258                        value: 10.0,
259                        raw: Some(atom!("10"))
260                    }))))
261                })]
262            })
263        );
264    }
265
266    #[test]
267    fn object_binding_pattern_with_prop_and_label() {
268        fn prop(key: PropName, assign_name: &str, expr: Expr) -> PropOrSpread {
269            PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
270                key,
271                value: AssignExpr {
272                    span,
273                    op: AssignOp::Assign,
274                    left: ident(assign_name).into(),
275                    right: Box::new(expr),
276                }
277                .into(),
278            })))
279        }
280
281        assert_eq_ignore_span!(
282            object_pat(
283                "{obj = {$: num = 10, '': sym = '', \" \": quote = \" \", _: under = [...tail],}}"
284            ),
285            Pat::Object(ObjectPat {
286                span,
287                type_ann: None,
288                optional: false,
289                props: vec![ObjectPatProp::Assign(AssignPatProp {
290                    span,
291                    key: ident("obj").into(),
292                    value: Some(Box::new(Expr::Object(ObjectLit {
293                        span,
294                        props: vec![
295                            prop(
296                                PropName::Ident(ident_name("$")),
297                                "num",
298                                Expr::Lit(Lit::Num(Number {
299                                    span,
300                                    value: 10.0,
301                                    raw: Some(atom!("10"))
302                                }))
303                            ),
304                            prop(
305                                PropName::Str(Str {
306                                    span,
307                                    value: atom!(""),
308                                    raw: Some(atom!("''")),
309                                }),
310                                "sym",
311                                Expr::Lit(Lit::Str(Str {
312                                    span,
313                                    value: atom!(""),
314                                    raw: Some(atom!("''")),
315                                }))
316                            ),
317                            prop(
318                                PropName::Str(Str {
319                                    span,
320                                    value: atom!(" "),
321                                    raw: Some(atom!("\" \"")),
322                                }),
323                                "quote",
324                                Expr::Lit(Lit::Str(Str {
325                                    span,
326                                    value: atom!(" "),
327                                    raw: Some(atom!("\" \"")),
328                                }))
329                            ),
330                            prop(
331                                PropName::Ident(ident_name("_")),
332                                "under",
333                                Expr::Array(ArrayLit {
334                                    span,
335                                    elems: vec![Some(ExprOrSpread {
336                                        spread: Some(span),
337                                        expr: Box::new(Expr::Ident(ident("tail")))
338                                    })]
339                                })
340                            ),
341                        ]
342                    })))
343                })]
344            })
345        );
346    }
347}