swc_ecma_lexer/common/parser/
object.rs

1use swc_common::{Span, Spanned, DUMMY_SP};
2use swc_ecma_ast::*;
3
4use super::{
5    expr::parse_assignment_expr,
6    pat::{parse_binding_element, parse_binding_pat_or_ident},
7    PResult, Parser,
8};
9use crate::{
10    common::{
11        context::Context,
12        lexer::token::TokenFactory,
13        parser::{
14            buffer::Buffer,
15            class_and_fn::parse_fn_args_body,
16            is_not_this,
17            pat::{parse_formal_params, parse_unique_formal_params},
18            typescript::eat_any_ts_modifier,
19        },
20    },
21    error::SyntaxError,
22};
23
24fn parse_object<'a, P: Parser<'a>, Object, ObjectProp>(
25    p: &mut P,
26    parse_prop: impl Fn(&mut P) -> PResult<ObjectProp>,
27    make_object: impl Fn(&mut P, Span, Vec<ObjectProp>, Option<Span>) -> PResult<Object>,
28) -> PResult<Object> {
29    p.do_outside_of_context(Context::WillExpectColonForCond, |p| {
30        trace_cur!(p, parse_object);
31
32        let start = p.cur_pos();
33        let mut trailing_comma = None;
34        p.assert_and_bump(&P::Token::LBRACE);
35
36        let mut props = Vec::with_capacity(8);
37
38        while !p.input_mut().eat(&P::Token::RBRACE) {
39            props.push(parse_prop(p)?);
40
41            if !p.input().is(&P::Token::RBRACE) {
42                expect!(p, &P::Token::COMMA);
43                if p.input().is(&P::Token::RBRACE) {
44                    trailing_comma = Some(p.input().prev_span());
45                }
46            }
47        }
48
49        let span = p.span(start);
50        make_object(p, span, props, trailing_comma)
51    })
52}
53
54/// Production 'BindingProperty'
55fn parse_binding_object_prop<'a, P: Parser<'a>>(p: &mut P) -> PResult<ObjectPatProp> {
56    let start = p.cur_pos();
57
58    if p.input_mut().eat(&P::Token::DOTDOTDOT) {
59        // spread element
60        let dot3_token = p.span(start);
61
62        let arg = Box::new(parse_binding_pat_or_ident(p, false)?);
63
64        return Ok(ObjectPatProp::Rest(RestPat {
65            span: p.span(start),
66            dot3_token,
67            arg,
68            type_ann: None,
69        }));
70    }
71
72    let key = p.parse_prop_name()?;
73    if p.input_mut().eat(&P::Token::COLON) {
74        let value = Box::new(parse_binding_element(p)?);
75
76        return Ok(ObjectPatProp::KeyValue(KeyValuePatProp { key, value }));
77    }
78    let key = match key {
79        PropName::Ident(ident) => ident,
80        _ => unexpected!(p, "an identifier"),
81    };
82
83    let value = if p.input_mut().eat(&P::Token::EQUAL) {
84        p.allow_in_expr(parse_assignment_expr).map(Some)?
85    } else {
86        if p.ctx().is_reserved_word(&key.sym) {
87            p.emit_err(key.span, SyntaxError::ReservedWordInObjShorthandOrPat);
88        }
89
90        None
91    };
92
93    Ok(ObjectPatProp::Assign(AssignPatProp {
94        span: p.span(start),
95        key: key.into(),
96        value,
97    }))
98}
99
100fn make_binding_object<'a, P: Parser<'a>>(
101    p: &mut P,
102    span: Span,
103    props: Vec<ObjectPatProp>,
104    trailing_comma: Option<Span>,
105) -> PResult<Pat> {
106    let len = props.len();
107    for (i, prop) in props.iter().enumerate() {
108        if i == len - 1 {
109            if let ObjectPatProp::Rest(ref rest) = prop {
110                match *rest.arg {
111                    Pat::Ident(..) => {
112                        if let Some(trailing_comma) = trailing_comma {
113                            p.emit_err(trailing_comma, SyntaxError::CommaAfterRestElement);
114                        }
115                    }
116                    _ => syntax_error!(p, prop.span(), SyntaxError::DotsWithoutIdentifier),
117                }
118            }
119            continue;
120        }
121
122        if let ObjectPatProp::Rest(..) = prop {
123            p.emit_err(prop.span(), SyntaxError::NonLastRestParam)
124        }
125    }
126
127    let optional = (p.input().syntax().dts() || p.ctx().contains(Context::InDeclare))
128        && p.input_mut().eat(&P::Token::QUESTION);
129
130    Ok(ObjectPat {
131        span,
132        props,
133        optional,
134        type_ann: None,
135    }
136    .into())
137}
138
139pub(super) fn parse_object_pat<'a, P: Parser<'a>>(p: &mut P) -> PResult<Pat> {
140    parse_object(p, parse_binding_object_prop, make_binding_object)
141}
142
143fn make_expr_object<'a, P: Parser<'a>>(
144    p: &mut P,
145    span: Span,
146    props: Vec<PropOrSpread>,
147    trailing_comma: Option<Span>,
148) -> PResult<Expr> {
149    if let Some(trailing_comma) = trailing_comma {
150        p.state_mut()
151            .trailing_commas
152            .insert(span.lo, trailing_comma);
153    }
154    Ok(ObjectLit { span, props }.into())
155}
156
157fn parse_expr_object_prop<'a, P: Parser<'a>>(p: &mut P) -> PResult<PropOrSpread> {
158    trace_cur!(p, parse_object_prop);
159
160    let start = p.cur_pos();
161    // Parse as 'MethodDefinition'
162
163    if p.input_mut().eat(&P::Token::DOTDOTDOT) {
164        // spread element
165        let dot3_token = p.span(start);
166
167        let expr = p.allow_in_expr(parse_assignment_expr)?;
168
169        return Ok(PropOrSpread::Spread(SpreadElement { dot3_token, expr }));
170    }
171
172    if p.input_mut().eat(&P::Token::MUL) {
173        let name = p.parse_prop_name()?;
174        return p
175            .do_inside_of_context(Context::AllowDirectSuper, |p| {
176                p.do_outside_of_context(Context::InClassField, |p| {
177                    parse_fn_args_body(
178                        p,
179                        // no decorator in an object literal
180                        Vec::new(),
181                        start,
182                        parse_unique_formal_params,
183                        false,
184                        true,
185                    )
186                })
187            })
188            .map(|function| {
189                PropOrSpread::Prop(Box::new(Prop::Method(MethodProp {
190                    key: name,
191                    function,
192                })))
193            });
194    }
195
196    let has_modifiers = eat_any_ts_modifier(p)?;
197    let modifiers_span = p.input().prev_span();
198
199    let key = p.parse_prop_name()?;
200
201    let cur = p.input().cur();
202    if p.input().syntax().typescript()
203        && !(cur.is_lparen()
204            || cur.is_lbracket()
205            || cur.is_colon()
206            || cur.is_comma()
207            || cur.is_question()
208            || cur.is_equal()
209            || cur.is_star()
210            || cur.is_str()
211            || cur.is_num()
212            || cur.is_word())
213        && !(p.input().syntax().typescript() && p.input().is(&P::Token::LESS))
214        && !(p.input().is(&P::Token::RBRACE) && matches!(key, PropName::Ident(..)))
215    {
216        trace_cur!(p, parse_object_prop_error);
217
218        p.emit_err(p.input().cur_span(), SyntaxError::TS1005);
219        return Ok(PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
220            key,
221            value: Invalid {
222                span: p.span(start),
223            }
224            .into(),
225        }))));
226    }
227    //
228    // {[computed()]: a,}
229    // { 'a': a, }
230    // { 0: 1, }
231    // { a: expr, }
232    if p.input_mut().eat(&P::Token::COLON) {
233        let value = p.allow_in_expr(parse_assignment_expr)?;
234        return Ok(PropOrSpread::Prop(Box::new(Prop::KeyValue(KeyValueProp {
235            key,
236            value,
237        }))));
238    }
239
240    // Handle `a(){}` (and async(){} / get(){} / set(){})
241    if (p.input().syntax().typescript() && p.input().is(&P::Token::LESS))
242        || p.input().is(&P::Token::LPAREN)
243    {
244        return p
245            .do_inside_of_context(Context::AllowDirectSuper, |p| {
246                p.do_outside_of_context(Context::InClassField, |p| {
247                    parse_fn_args_body(
248                        p,
249                        // no decorator in an object literal
250                        Vec::new(),
251                        start,
252                        parse_unique_formal_params,
253                        false,
254                        false,
255                    )
256                })
257            })
258            .map(|function| Box::new(Prop::Method(MethodProp { key, function })))
259            .map(PropOrSpread::Prop);
260    }
261
262    let ident = match key {
263        PropName::Ident(ident) => ident,
264        // TODO
265        _ => unexpected!(p, "identifier"),
266    };
267
268    if p.input_mut().eat(&P::Token::QUESTION) {
269        p.emit_err(p.input().prev_span(), SyntaxError::TS1162);
270    }
271
272    // `ident` from parse_prop_name is parsed as 'IdentifierName'
273    // It means we should check for invalid expressions like { for, }
274    let cur = p.input().cur();
275    if cur.is_equal() || cur.is_comma() || cur.is_rbrace() {
276        if p.ctx().is_reserved_word(&ident.sym) {
277            p.emit_err(ident.span, SyntaxError::ReservedWordInObjShorthandOrPat);
278        }
279
280        if p.input_mut().eat(&P::Token::EQUAL) {
281            let value = p.allow_in_expr(parse_assignment_expr)?;
282            let span = p.span(start);
283            return Ok(PropOrSpread::Prop(Box::new(Prop::Assign(AssignProp {
284                span,
285                key: ident.into(),
286                value,
287            }))));
288        }
289
290        return Ok(PropOrSpread::Prop(Box::new(Prop::from(ident))));
291    }
292
293    // get a(){}
294    // set a(v){}
295    // async a(){}
296
297    match &*ident.sym {
298        "get" | "set" | "async" => {
299            trace_cur!(p, parse_object_prop__after_accessor);
300
301            if has_modifiers {
302                p.emit_err(modifiers_span, SyntaxError::TS1042);
303            }
304
305            let is_generator = ident.sym == "async" && p.input_mut().eat(&P::Token::MUL);
306            let key = p.parse_prop_name()?;
307            let key_span = key.span();
308            p.do_inside_of_context(Context::AllowDirectSuper, |p| {
309                p.do_outside_of_context(Context::InClassField, |parser| {
310                    match &*ident.sym {
311                        "get" => parse_fn_args_body(
312                            parser,
313                            // no decorator in an object literal
314                            Vec::new(),
315                            start,
316                            |p| {
317                                let params = parse_formal_params(p)?;
318
319                                if params.iter().any(is_not_this) {
320                                    p.emit_err(key_span, SyntaxError::GetterParam);
321                                }
322
323                                Ok(params)
324                            },
325                            false,
326                            false,
327                        )
328                        .map(|v| *v)
329                        .map(
330                            |Function {
331                                 body, return_type, ..
332                             }| {
333                                if parser.input().syntax().typescript()
334                                    && parser.input().target() == EsVersion::Es3
335                                {
336                                    parser.emit_err(key_span, SyntaxError::TS1056);
337                                }
338
339                                PropOrSpread::Prop(Box::new(Prop::Getter(GetterProp {
340                                    span: parser.span(start),
341                                    key,
342                                    type_ann: return_type,
343                                    body,
344                                })))
345                            },
346                        ),
347                        "set" => {
348                            parse_fn_args_body(
349                                parser,
350                                // no decorator in an object literal
351                                Vec::new(),
352                                start,
353                                |p| {
354                                    let params = parse_formal_params(p)?;
355
356                                    if params.iter().filter(|p| is_not_this(p)).count() != 1 {
357                                        p.emit_err(key_span, SyntaxError::SetterParam);
358                                    }
359
360                                    if !params.is_empty() {
361                                        if let Pat::Rest(..) = params[0].pat {
362                                            p.emit_err(
363                                                params[0].span(),
364                                                SyntaxError::RestPatInSetter,
365                                            );
366                                        }
367                                    }
368
369                                    if p.input().syntax().typescript()
370                                        && p.input().target() == EsVersion::Es3
371                                    {
372                                        p.emit_err(key_span, SyntaxError::TS1056);
373                                    }
374
375                                    Ok(params)
376                                },
377                                false,
378                                false,
379                            )
380                            .map(|v| *v)
381                            .map(
382                                |Function {
383                                     mut params, body, ..
384                                 }| {
385                                    let mut this = None;
386                                    if params.len() >= 2 {
387                                        this = Some(params.remove(0).pat);
388                                    }
389
390                                    let param = Box::new(
391                                        params.into_iter().next().map(|v| v.pat).unwrap_or_else(
392                                            || {
393                                                parser.emit_err(key_span, SyntaxError::SetterParam);
394
395                                                Invalid { span: DUMMY_SP }.into()
396                                            },
397                                        ),
398                                    );
399
400                                    // debug_assert_eq!(params.len(), 1);
401                                    PropOrSpread::Prop(Box::new(Prop::Setter(SetterProp {
402                                        span: parser.span(start),
403                                        key,
404                                        body,
405                                        param,
406                                        this_param: this,
407                                    })))
408                                },
409                            )
410                        }
411                        "async" => parse_fn_args_body(
412                            parser,
413                            // no decorator in an object literal
414                            Vec::new(),
415                            start,
416                            parse_unique_formal_params,
417                            true,
418                            is_generator,
419                        )
420                        .map(|function| {
421                            PropOrSpread::Prop(Box::new(Prop::Method(MethodProp { key, function })))
422                        }),
423                        _ => unreachable!(),
424                    }
425                })
426            })
427        }
428        _ => {
429            if p.input().syntax().typescript() {
430                unexpected!(
431                    p,
432                    "... , *,  (, [, :, , ?, =, an identifier, public, protected, private, \
433                     readonly, <."
434                )
435            } else {
436                unexpected!(p, "... , *,  (, [, :, , ?, = or an identifier")
437            }
438        }
439    }
440}
441
442pub fn parse_object_expr<'a, P: Parser<'a>>(p: &mut P) -> PResult<Expr> {
443    parse_object(p, parse_expr_object_prop, make_expr_object)
444}