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
54fn 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 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 if p.input_mut().eat(&P::Token::DOTDOTDOT) {
164 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 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 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 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 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 _ => 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 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 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 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 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 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 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}