1use either::Either;
2use rustc_hash::FxHashMap;
3use swc_atoms::atom;
4use swc_common::{util::take::Take, BytePos, Span, Spanned};
5use swc_ecma_ast::*;
6
7use super::{
8 assign_target_or_spread::AssignTargetOrSpread, buffer::Buffer, ident::parse_ident_name,
9 PResult, Parser,
10};
11use crate::{
12 common::{
13 context::Context,
14 lexer::token::TokenFactory,
15 parser::{
16 class_and_fn::{
17 parse_async_fn_expr, parse_class_expr, parse_decorators,
18 parse_fn_block_or_expr_body, parse_fn_expr,
19 },
20 eof_error,
21 expr_ext::ExprExt,
22 ident::{parse_binding_ident, parse_ident, parse_maybe_private_name},
23 is_simple_param_list::IsSimpleParameterList,
24 jsx::{parse_jsx_element, parse_jsx_text},
25 object::parse_object_expr,
26 pat::{parse_paren_items_as_params, reparse_expr_as_pat},
27 pat_type::PatType,
28 token_and_span::TokenAndSpan,
29 typescript::*,
30 unwrap_ts_non_null,
31 },
32 },
33 error::{Error, SyntaxError},
34 TokenContext,
35};
36
37pub(super) fn is_start_of_left_hand_side_expr<'a>(p: &mut impl Parser<'a>) -> bool {
38 let cur = p.input().cur();
39 cur.is_this()
40 || cur.is_null()
41 || cur.is_super()
42 || cur.is_true()
43 || cur.is_false()
44 || cur.is_num()
45 || cur.is_bigint()
46 || cur.is_str()
47 || cur.is_no_substitution_template_literal()
48 || cur.is_template_head()
49 || cur.is_lparen()
50 || cur.is_lbrace()
51 || cur.is_lbracket()
52 || cur.is_function()
53 || cur.is_class()
54 || cur.is_new()
55 || cur.is_regexp()
56 || cur.is_import()
57 || cur.is_ident_ref(p.ctx())
58 || cur.is_backquote() && {
59 peek!(p).is_some_and(|peek| peek.is_lparen() || peek.is_less() || peek.is_dot())
60 }
61}
62
63#[cfg_attr(
64 feature = "tracing-spans",
65 tracing::instrument(level = "debug", skip_all)
66)]
67pub fn parse_array_lit<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<Expr>> {
68 trace_cur!(p, parse_array_lit);
69
70 let start = p.input().cur_pos();
71
72 p.assert_and_bump(&P::Token::LBRACKET);
73
74 let mut elems = Vec::with_capacity(8);
75
76 while !p.input().is(&P::Token::RBRACKET) {
77 if p.input().is(&P::Token::COMMA) {
78 expect!(p, &P::Token::COMMA);
79 elems.push(None);
80 continue;
81 }
82
83 elems.push(p.allow_in_expr(|p| p.parse_expr_or_spread()).map(Some)?);
84
85 if !p.input().is(&P::Token::RBRACKET) {
86 expect!(p, &P::Token::COMMA);
87 if p.input().is(&P::Token::RBRACKET) {
88 let prev_span = p.input().prev_span();
89 p.state_mut().trailing_commas.insert(start, prev_span);
90 }
91 }
92 }
93
94 expect!(p, &P::Token::RBRACKET);
95
96 let span = p.span(start);
97 Ok(ArrayLit { span, elems }.into())
98}
99
100pub fn at_possible_async<'a, P: Parser<'a>>(p: &P, expr: &Expr) -> bool {
101 p.state().potential_arrow_start == Some(expr.span_lo()) && expr.is_ident_ref_to("async")
103}
104
105fn parse_yield_expr<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<Expr>> {
106 let start = p.input().cur_pos();
107 p.assert_and_bump(&P::Token::YIELD);
108 debug_assert!(p.ctx().contains(Context::InGenerator));
109
110 if p.ctx().contains(Context::InParameters) && !p.ctx().contains(Context::InFunction) {
115 syntax_error!(p, p.input().prev_span(), SyntaxError::YieldParamInGen)
116 }
117
118 let parse_with_arg = |p: &mut P| {
119 let has_star = p.input_mut().eat(&P::Token::MUL);
120 let err_span = p.span(start);
121 let arg = parse_assignment_expr(p).map_err(|err| {
122 Error::new(
123 err.span(),
124 SyntaxError::WithLabel {
125 inner: Box::new(err),
126 span: err_span,
127 note: "Tried to parse an argument of yield",
128 },
129 )
130 })?;
131 Ok(YieldExpr {
132 span: p.span(start),
133 arg: Some(arg),
134 delegate: has_star,
135 }
136 .into())
137 };
138
139 if p.is_general_semi() || {
140 let cur = p.input().cur();
141 !cur.is_less()
142 && !cur.is_star()
143 && !cur.is_slash()
144 && !cur.is_slash_eq()
145 && !cur.starts_expr()
146 } {
147 Ok(YieldExpr {
148 span: p.span(start),
149 arg: None,
150 delegate: false,
151 }
152 .into())
153 } else {
154 parse_with_arg(p)
155 }
156}
157
158fn parse_tpl_elements<'a, P: Parser<'a>>(
159 p: &mut P,
160 is_tagged_tpl: bool,
161) -> PResult<(Vec<Box<Expr>>, Vec<TplElement>)> {
162 trace_cur!(p, parse_tpl_elements);
163
164 let mut exprs = Vec::new();
165
166 let cur_elem = p.parse_tpl_element(is_tagged_tpl)?;
167 let mut is_tail = cur_elem.tail;
168 let mut quasis = vec![cur_elem];
169
170 while !is_tail {
171 expect!(p, &P::Token::DOLLAR_LBRACE);
172 exprs.push(p.allow_in_expr(|p| p.parse_expr())?);
173 expect!(p, &P::Token::RBRACE);
174 let elem = p.parse_tpl_element(is_tagged_tpl)?;
175 is_tail = elem.tail;
176 quasis.push(elem);
177 }
178
179 Ok((exprs, quasis))
180}
181
182fn parse_tpl<'a, P: Parser<'a>>(p: &mut P, is_tagged_tpl: bool) -> PResult<Tpl> {
183 trace_cur!(p, parse_tpl);
184 let start = p.input().cur_pos();
185
186 p.assert_and_bump(&P::Token::BACKQUOTE);
187
188 let (exprs, quasis) = parse_tpl_elements(p, is_tagged_tpl)?;
189
190 expect!(p, &P::Token::BACKQUOTE);
191
192 let span = p.span(start);
193 Ok(Tpl {
194 span,
195 exprs,
196 quasis,
197 })
198}
199
200pub(crate) fn parse_tagged_tpl<'a, P: Parser<'a>>(
201 p: &mut P,
202 tag: Box<Expr>,
203 type_params: Option<Box<TsTypeParamInstantiation>>,
204) -> PResult<TaggedTpl> {
205 let tagged_tpl_start = tag.span_lo();
206 trace_cur!(p, parse_tagged_tpl);
207
208 let tpl = Box::new(parse_tpl(p, true)?);
209
210 let span = p.span(tagged_tpl_start);
211
212 if tag.is_opt_chain() {
213 p.emit_err(span, SyntaxError::TaggedTplInOptChain);
214 }
215
216 Ok(TaggedTpl {
217 span,
218 tag,
219 type_params,
220 tpl,
221 ..Default::default()
222 })
223}
224
225pub fn parse_str_lit<'a>(p: &mut impl Parser<'a>) -> swc_ecma_ast::Str {
226 debug_assert!(p.input().cur().is_str());
227 let token_and_span = p.input().get_cur();
228 let start = token_and_span.span().lo;
229 let (value, raw) = p.input_mut().expect_string_token_and_bump();
230 swc_ecma_ast::Str {
231 span: p.span(start),
232 value,
233 raw: Some(raw),
234 }
235}
236
237pub fn parse_lit<'a, P: Parser<'a>>(p: &mut P) -> PResult<Lit> {
238 let token_and_span = p.input().get_cur();
239 let start = token_and_span.span().lo;
240 let cur = token_and_span.token();
241 let v = if cur.is_null() {
242 p.bump();
243 let span = p.span(start);
244 Lit::Null(swc_ecma_ast::Null { span })
245 } else if cur.is_true() || cur.is_false() {
246 let value = cur.is_true();
247 p.bump();
248 let span = p.span(start);
249 Lit::Bool(swc_ecma_ast::Bool { span, value })
250 } else if cur.is_str() {
251 Lit::Str(parse_str_lit(p))
252 } else if cur.is_num() {
253 let (value, raw) = p.input_mut().expect_number_token_and_bump();
254 Lit::Num(swc_ecma_ast::Number {
255 span: p.span(start),
256 value,
257 raw: Some(raw),
258 })
259 } else if cur.is_bigint() {
260 let (value, raw) = p.input_mut().expect_bigint_token_and_bump();
261 Lit::BigInt(swc_ecma_ast::BigInt {
262 span: p.span(start),
263 value,
264 raw: Some(raw),
265 })
266 } else if cur.is_error() {
267 let err = p.input_mut().expect_error_token_and_bump();
268 return Err(err);
269 } else if cur.is_eof() {
270 return Err(eof_error(p));
271 } else {
272 unreachable!("parse_lit should not be called for {:?}", cur)
273 };
274 Ok(v)
275}
276
277#[cfg_attr(feature = "tracing-spans", tracing::instrument(skip_all))]
279pub fn parse_args<'a, P: Parser<'a>>(
280 p: &mut P,
281 is_dynamic_import: bool,
282) -> PResult<Vec<ExprOrSpread>> {
283 trace_cur!(p, parse_args);
284
285 p.do_outside_of_context(Context::WillExpectColonForCond, |p| {
286 let start = p.cur_pos();
287 expect!(p, &P::Token::LPAREN);
288
289 let mut first = true;
290 let mut expr_or_spreads = Vec::with_capacity(2);
291
292 while !p.input().is(&P::Token::RPAREN) {
293 if first {
294 first = false;
295 } else {
296 expect!(p, &P::Token::COMMA);
297 if p.input().is(&P::Token::RPAREN) {
299 if is_dynamic_import && !p.input().syntax().import_attributes() {
300 syntax_error!(p, p.span(start), SyntaxError::TrailingCommaInsideImport)
301 }
302
303 break;
304 }
305 }
306
307 expr_or_spreads.push(p.allow_in_expr(|p| p.parse_expr_or_spread())?);
308 }
309
310 expect!(p, &P::Token::RPAREN);
311 Ok(expr_or_spreads)
312 })
313}
314
315#[cfg_attr(
317 feature = "tracing-spans",
318 tracing::instrument(level = "debug", skip_all)
319)]
320pub fn parse_assignment_expr<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<Expr>> {
321 trace_cur!(p, parse_assignment_expr);
322
323 if p.input().syntax().typescript() && p.input().is(&P::Token::JSX_TAG_START) {
324 let cur_context = p.input().token_context().current();
328 debug_assert_eq!(cur_context, Some(TokenContext::JSXOpeningTag));
329 debug_assert_eq!(
331 p.input().token_context().0[p.input().token_context().len() - 2],
332 TokenContext::JSXExpr
333 );
334
335 let res = try_parse_ts(p, |p| parse_assignment_expr_base(p).map(Some));
336 if let Some(res) = res {
337 return Ok(res);
338 } else {
339 debug_assert_eq!(
340 p.input_mut().token_context().current(),
341 Some(TokenContext::JSXOpeningTag)
342 );
343 p.input_mut().token_context_mut().pop();
344 debug_assert_eq!(
345 p.input_mut().token_context().current(),
346 Some(TokenContext::JSXExpr)
347 );
348 p.input_mut().token_context_mut().pop();
349 }
350 }
351
352 parse_assignment_expr_base(p)
353}
354
355#[cfg_attr(feature = "tracing-spans", tracing::instrument(skip_all))]
360fn parse_assignment_expr_base<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<Expr>> {
361 trace_cur!(p, parse_assignment_expr_base);
362 let start = p.input().cur_span();
363
364 if p.input().syntax().typescript()
365 && (p.input().cur().is_less() || p.input().cur().is_jsx_tag_start())
366 && (peek!(p).is_some_and(|peek| peek.is_word() || peek.is_jsx_name()))
367 {
368 let res = p.do_outside_of_context(Context::WillExpectColonForCond, |p| {
369 try_parse_ts(p, |p| {
370 if p.input().cur().is_jsx_tag_start() {
371 if let Some(TokenContext::JSXOpeningTag) =
372 p.input_mut().token_context().current()
373 {
374 p.input_mut().token_context_mut().pop();
375
376 debug_assert_eq!(
377 p.input_mut().token_context().current(),
378 Some(TokenContext::JSXExpr)
379 );
380 p.input_mut().token_context_mut().pop();
381 }
382 }
383
384 let type_parameters = parse_ts_type_params(p, false, true)?;
385 let mut arrow = parse_assignment_expr_base(p)?;
386 match *arrow {
387 Expr::Arrow(ArrowExpr {
388 ref mut span,
389 ref mut type_params,
390 ..
391 }) => {
392 *span = Span::new_with_checked(type_parameters.span.lo, span.hi);
393 *type_params = Some(type_parameters);
394 }
395 _ => unexpected!(p, "("),
396 }
397 Ok(Some(arrow))
398 })
399 });
400 if let Some(res) = res {
401 if p.input().syntax().disallow_ambiguous_jsx_like() {
402 p.emit_err(start, SyntaxError::ReservedArrowTypeParam);
403 }
404 return Ok(res);
405 }
406 }
407
408 if p.ctx().contains(Context::InGenerator) && p.input().is(&P::Token::YIELD) {
409 return parse_yield_expr(p);
410 }
411
412 let cur = p.input().cur();
413
414 if cur.is_error() {
415 let err = p.input_mut().expect_error_token_and_bump();
416 return Err(err);
417 }
418
419 p.state_mut().potential_arrow_start =
420 if cur.is_known_ident() || cur.is_unknown_ident() || cur.is_yield() || cur.is_lparen() {
421 Some(p.cur_pos())
422 } else {
423 None
424 };
425
426 let start = p.cur_pos();
427
428 let cond = parse_cond_expr(p)?;
430
431 return_if_arrow!(p, cond);
432
433 match *cond {
434 Expr::Cond(..) | Expr::Bin(..) | Expr::Unary(..) | Expr::Update(..) => return Ok(cond),
437 _ => {}
438 }
439
440 finish_assignment_expr(p, start, cond)
441}
442
443pub fn finish_assignment_expr<'a, P: Parser<'a>>(
444 p: &mut P,
445 start: BytePos,
446 cond: Box<Expr>,
447) -> PResult<Box<Expr>> {
448 trace_cur!(p, finish_assignment_expr);
449
450 if let Some(op) = p.input().cur().as_assign_op() {
451 let left = if op == AssignOp::Assign {
452 match AssignTarget::try_from(reparse_expr_as_pat(p, PatType::AssignPat, cond)?) {
453 Ok(pat) => pat,
454 Err(expr) => {
455 syntax_error!(p, expr.span(), SyntaxError::InvalidAssignTarget)
456 }
457 }
458 } else {
459 if !cond.is_valid_simple_assignment_target(p.ctx().contains(Context::Strict)) {
462 if p.input().syntax().typescript() {
463 p.emit_err(cond.span(), SyntaxError::TS2406);
464 } else {
465 p.emit_err(cond.span(), SyntaxError::NotSimpleAssign)
466 }
467 }
468 if p.input().syntax().typescript()
469 && cond
470 .as_ident()
471 .map(|i| i.is_reserved_in_strict_bind())
472 .unwrap_or(false)
473 {
474 p.emit_strict_mode_err(cond.span(), SyntaxError::TS1100);
475 }
476
477 match AssignTarget::try_from(cond) {
479 Ok(v) => v,
480 Err(v) => {
481 syntax_error!(p, v.span(), SyntaxError::InvalidAssignTarget);
482 }
483 }
484 };
485
486 p.bump();
487 let right = parse_assignment_expr(p)?;
488 Ok(AssignExpr {
489 span: p.span(start),
490 op,
491 left,
493 right,
494 }
495 .into())
496 } else {
497 Ok(cond)
498 }
499}
500
501#[cfg_attr(
503 feature = "tracing-spans",
504 tracing::instrument(level = "debug", skip_all)
505)]
506fn parse_cond_expr<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<Expr>> {
507 trace_cur!(p, parse_cond_expr);
508
509 let start = p.cur_pos();
510
511 let test = parse_bin_expr(p)?;
512 return_if_arrow!(p, test);
513
514 if p.input_mut().eat(&P::Token::QUESTION) {
515 let cons = p.do_inside_of_context(
516 Context::InCondExpr
517 .union(Context::WillExpectColonForCond)
518 .union(Context::IncludeInExpr),
519 parse_assignment_expr,
520 )?;
521
522 expect!(p, &P::Token::COLON);
523
524 let alt = p.do_inside_of_context(Context::InCondExpr, |p| {
525 p.do_outside_of_context(Context::WillExpectColonForCond, parse_assignment_expr)
526 })?;
527
528 let span = Span::new_with_checked(start, alt.span_hi());
529 Ok(CondExpr {
530 span,
531 test,
532 cons,
533 alt,
534 }
535 .into())
536 } else {
537 Ok(test)
538 }
539}
540
541#[cfg_attr(feature = "tracing-spans", tracing::instrument(skip_all))]
542pub fn parse_subscripts<'a>(
543 p: &mut impl Parser<'a>,
544 mut obj: Callee,
545 no_call: bool,
546 no_computed_member: bool,
547) -> PResult<Box<Expr>> {
548 let start = obj.span().lo;
549 loop {
550 obj = match parse_subscript(p, start, obj, no_call, no_computed_member)? {
551 (expr, false) => return Ok(expr),
552 (expr, true) => Callee::Expr(expr),
553 }
554 }
555}
556
557#[cfg_attr(feature = "tracing-spans", tracing::instrument(skip_all))]
559fn parse_subscript<'a, P: Parser<'a>>(
560 p: &mut P,
561 start: BytePos,
562 mut obj: Callee,
563 no_call: bool,
564 no_computed_member: bool,
565) -> PResult<(Box<Expr>, bool)> {
566 trace_cur!(p, parse_subscript);
567
568 if p.input().syntax().typescript() {
569 if !p.input().had_line_break_before_cur() && p.input().is(&P::Token::BANG) {
570 p.input_mut().set_expr_allowed(false);
571 p.assert_and_bump(&P::Token::BANG);
572
573 let expr = match obj {
574 Callee::Super(..) => {
575 syntax_error!(
576 p,
577 p.input().cur_span(),
578 SyntaxError::TsNonNullAssertionNotAllowed(atom!("super"))
579 )
580 }
581 Callee::Import(..) => {
582 syntax_error!(
583 p,
584 p.input().cur_span(),
585 SyntaxError::TsNonNullAssertionNotAllowed(atom!("import"))
586 )
587 }
588 Callee::Expr(expr) => expr,
589 #[cfg(swc_ast_unknown)]
590 _ => unreachable!(),
591 };
592 return Ok((
593 TsNonNullExpr {
594 span: p.span(start),
595 expr,
596 }
597 .into(),
598 true,
599 ));
600 }
601
602 if matches!(obj, Callee::Expr(..)) && p.input().is(&P::Token::LESS) {
603 let is_dynamic_import = obj.is_import();
604
605 let mut obj_opt = Some(obj);
606 let mut_obj_opt = &mut obj_opt;
612
613 let result = p.do_inside_of_context(Context::ShouldNotLexLtOrGtAsType, |p| {
614 try_parse_ts(p, |p| {
615 if !no_call
616 && at_possible_async(
617 p,
618 match &mut_obj_opt {
619 Some(Callee::Expr(ref expr)) => expr,
620 _ => unreachable!(),
621 },
622 )
623 {
624 let async_arrow_fn = try_parse_ts_generic_async_arrow_fn(p, start)?;
627 if let Some(async_arrow_fn) = async_arrow_fn {
628 return Ok(Some((async_arrow_fn.into(), true)));
629 }
630 }
631
632 let type_args = parse_ts_type_args(p)?;
633 p.assert_and_bump(&P::Token::GREATER);
634 let cur = p.input().cur();
635
636 if !no_call && cur.is_lparen() {
637 let args = parse_args(p, is_dynamic_import)?;
640
641 let obj = mut_obj_opt.take().unwrap();
642
643 if let Callee::Expr(callee) = &obj {
644 if let Expr::OptChain(..) = &**callee {
645 return Ok(Some((
646 OptChainExpr {
647 span: p.span(start),
648 base: Box::new(OptChainBase::Call(OptCall {
649 span: p.span(start),
650 callee: obj.expect_expr(),
651 type_args: Some(type_args),
652 args,
653 ..Default::default()
654 })),
655 optional: false,
656 }
657 .into(),
658 true,
659 )));
660 }
661 }
662
663 Ok(Some((
664 CallExpr {
665 span: p.span(start),
666 callee: obj,
667 type_args: Some(type_args),
668 args,
669 ..Default::default()
670 }
671 .into(),
672 true,
673 )))
674 } else if cur.is_no_substitution_template_literal()
675 || cur.is_template_head()
676 || cur.is_backquote()
677 {
678 p.parse_tagged_tpl(
679 match mut_obj_opt {
680 Some(Callee::Expr(obj)) => obj.take(),
681 _ => unreachable!(),
682 },
683 Some(type_args),
684 )
685 .map(|expr| (expr.into(), true))
686 .map(Some)
687 } else if cur.is_equal() || cur.is_as() || cur.is_satisfies() {
688 Ok(Some((
689 TsInstantiation {
690 span: p.span(start),
691 expr: match mut_obj_opt {
692 Some(Callee::Expr(obj)) => obj.take(),
693 _ => unreachable!(),
694 },
695 type_args,
696 }
697 .into(),
698 false,
699 )))
700 } else if no_call {
701 unexpected!(p, "`")
702 } else {
703 unexpected!(p, "( or `")
704 }
705 })
706 });
707 if let Some(result) = result {
708 return Ok(result);
709 }
710
711 obj = obj_opt.unwrap();
712 }
713 }
714
715 let type_args = if p.syntax().typescript() && p.input().is(&P::Token::LESS) {
716 try_parse_ts_type_args(p)
717 } else {
718 None
719 };
720
721 let cur = p.input().cur();
722
723 if obj.is_import() && !(cur.is_dot() || cur.is_lparen()) {
724 unexpected!(p, "`.` or `(`")
725 }
726
727 let question_dot_token =
728 if p.input().is(&P::Token::QUESTION) && peek!(p).is_some_and(|peek| peek.is_dot()) {
729 let start = p.cur_pos();
730 expect!(p, &P::Token::QUESTION);
731 Some(p.span(start))
732 } else {
733 None
734 };
735
736 if !no_computed_member
738 && ((question_dot_token.is_some()
739 && p.input().is(&P::Token::DOT)
740 && peek!(p).is_some_and(|peek| peek.is_lbracket())
741 && p.input_mut().eat(&P::Token::DOT)
742 && p.input_mut().eat(&P::Token::LBRACKET))
743 || p.input_mut().eat(&P::Token::LBRACKET))
744 {
745 let bracket_lo = p.input().prev_span().lo;
746 let prop = p.allow_in_expr(|p| p.parse_expr())?;
747 expect!(p, &P::Token::RBRACKET);
748 let span = Span::new_with_checked(obj.span_lo(), p.input().last_pos());
749 debug_assert_eq!(obj.span_lo(), span.lo());
750 let prop = ComputedPropName {
751 span: Span::new_with_checked(bracket_lo, p.input().last_pos()),
752 expr: prop,
753 };
754
755 let type_args = if p.syntax().typescript() && p.input().is(&P::Token::LESS) {
756 try_parse_ts_type_args(p)
757 } else {
758 None
759 };
760
761 return Ok((
762 Box::new(match obj {
763 Callee::Import(..) => unreachable!(),
764 Callee::Super(obj) => {
765 if !p.ctx().contains(Context::AllowDirectSuper)
766 && !p.input().syntax().allow_super_outside_method()
767 {
768 syntax_error!(p, obj.span, SyntaxError::InvalidSuper);
769 } else if question_dot_token.is_some() {
770 if no_call {
771 syntax_error!(p, obj.span, SyntaxError::InvalidSuperCall);
772 } else {
773 syntax_error!(p, obj.span, SyntaxError::InvalidSuper);
774 }
775 } else {
776 SuperPropExpr {
777 span,
778 obj,
779 prop: SuperProp::Computed(prop),
780 }
781 .into()
782 }
783 }
784 Callee::Expr(obj) => {
785 let is_opt_chain = unwrap_ts_non_null(&obj).is_opt_chain();
786 let expr = MemberExpr {
787 span,
788 obj,
789 prop: MemberProp::Computed(prop),
790 };
791 let expr = if is_opt_chain || question_dot_token.is_some() {
792 OptChainExpr {
793 span,
794 optional: question_dot_token.is_some(),
795 base: Box::new(OptChainBase::Member(expr)),
796 }
797 .into()
798 } else {
799 expr.into()
800 };
801
802 if let Some(type_args) = type_args {
803 TsInstantiation {
804 expr: Box::new(expr),
805 type_args,
806 span: p.span(start),
807 }
808 .into()
809 } else {
810 expr
811 }
812 }
813 #[cfg(swc_ast_unknown)]
814 _ => unreachable!(),
815 }),
816 true,
817 ));
818 }
819
820 if (question_dot_token.is_some()
821 && p.input().is(&P::Token::DOT)
822 && (peek!(p).is_some_and(|peek| peek.is_lparen())
823 || (p.syntax().typescript() && peek!(p).is_some_and(|peek| peek.is_less())))
824 && p.input_mut().eat(&P::Token::DOT))
825 || (!no_call && p.input().is(&P::Token::LPAREN))
826 {
827 let type_args = if p.syntax().typescript() && p.input().is(&P::Token::LESS) {
828 let ret = parse_ts_type_args(p)?;
829 p.assert_and_bump(&P::Token::GREATER);
830 Some(ret)
831 } else {
832 None
833 };
834 let args = parse_args(p, obj.is_import())?;
835 let span = p.span(start);
836 return if question_dot_token.is_some()
837 || match &obj {
838 Callee::Expr(obj) => unwrap_ts_non_null(obj).is_opt_chain(),
839 _ => false,
840 } {
841 match obj {
842 Callee::Super(_) | Callee::Import(_) => {
843 syntax_error!(p, p.input().cur_span(), SyntaxError::SuperCallOptional)
844 }
845 Callee::Expr(callee) => Ok((
846 OptChainExpr {
847 span,
848 optional: question_dot_token.is_some(),
849 base: Box::new(OptChainBase::Call(OptCall {
850 span: p.span(start),
851 callee,
852 args,
853 type_args,
854 ..Default::default()
855 })),
856 }
857 .into(),
858 true,
859 )),
860 #[cfg(swc_ast_unknown)]
861 _ => unreachable!(),
862 }
863 } else {
864 Ok((
865 CallExpr {
866 span: p.span(start),
867 callee: obj,
868 args,
869 ..Default::default()
870 }
871 .into(),
872 true,
873 ))
874 };
875 }
876
877 if p.input_mut().eat(&P::Token::DOT) {
880 let prop = parse_maybe_private_name(p).map(|e| match e {
881 Either::Left(p) => MemberProp::PrivateName(p),
882 Either::Right(i) => MemberProp::Ident(i),
883 })?;
884 let span = p.span(obj.span_lo());
885 debug_assert_eq!(obj.span_lo(), span.lo());
886 debug_assert_eq!(prop.span_hi(), span.hi());
887
888 let type_args = if p.syntax().typescript() && p.input().is(&P::Token::LESS) {
889 try_parse_ts_type_args(p)
890 } else {
891 None
892 };
893
894 return Ok((
895 Box::new(match obj {
896 callee @ Callee::Import(_) => match prop {
897 MemberProp::Ident(IdentName { sym, .. }) => {
898 if !p.ctx().contains(Context::CanBeModule) {
899 let span = p.span(start);
900 p.emit_err(span, SyntaxError::ImportMetaInScript);
901 }
902 match &*sym {
903 "meta" => MetaPropExpr {
904 span,
905 kind: MetaPropKind::ImportMeta,
906 }
907 .into(),
908 _ => {
909 let args = parse_args(p, true)?;
910
911 CallExpr {
912 span,
913 callee,
914 args,
915 type_args: None,
916 ..Default::default()
917 }
918 .into()
919 }
920 }
921 }
922 _ => {
923 unexpected!(p, "meta");
924 }
925 },
926 Callee::Super(obj) => {
927 if !p.ctx().contains(Context::AllowDirectSuper)
928 && !p.input().syntax().allow_super_outside_method()
929 {
930 syntax_error!(p, obj.span, SyntaxError::InvalidSuper);
931 } else if question_dot_token.is_some() {
932 if no_call {
933 syntax_error!(p, obj.span, SyntaxError::InvalidSuperCall);
934 } else {
935 syntax_error!(p, obj.span, SyntaxError::InvalidSuper);
936 }
937 } else {
938 match prop {
939 MemberProp::Ident(ident) => SuperPropExpr {
940 span,
941 obj,
942 prop: SuperProp::Ident(ident),
943 }
944 .into(),
945 MemberProp::PrivateName(..) => {
946 syntax_error!(
947 p,
948 p.input().cur_span(),
949 SyntaxError::InvalidSuperCall
950 )
951 }
952 MemberProp::Computed(..) => unreachable!(),
953 #[cfg(swc_ast_unknown)]
954 _ => unreachable!(),
955 }
956 }
957 }
958 Callee::Expr(obj) => {
959 let expr = MemberExpr { span, obj, prop };
960 let expr = if unwrap_ts_non_null(&expr.obj).is_opt_chain()
961 || question_dot_token.is_some()
962 {
963 OptChainExpr {
964 span: p.span(start),
965 optional: question_dot_token.is_some(),
966 base: Box::new(OptChainBase::Member(expr)),
967 }
968 .into()
969 } else {
970 expr.into()
971 };
972 if let Some(type_args) = type_args {
973 TsInstantiation {
974 expr: Box::new(expr),
975 type_args,
976 span: p.span(start),
977 }
978 .into()
979 } else {
980 expr
981 }
982 }
983 #[cfg(swc_ast_unknown)]
984 _ => unreachable!(),
985 }),
986 true,
987 ));
988 }
989
990 match obj {
991 Callee::Expr(expr) => {
992 let expr = if let Some(type_args) = type_args {
993 TsInstantiation {
994 expr,
995 type_args,
996 span: p.span(start),
997 }
998 .into()
999 } else {
1000 expr
1001 };
1002
1003 let cur = p.input().cur();
1005 if cur.is_template_head()
1006 || cur.is_no_substitution_template_literal()
1007 || cur.is_backquote()
1008 {
1009 let tpl = p.do_outside_of_context(Context::WillExpectColonForCond, |p| {
1010 p.parse_tagged_tpl(expr, None)
1011 })?;
1012 return Ok((tpl.into(), true));
1013 }
1014
1015 Ok((expr, false))
1016 }
1017 Callee::Super(..) => {
1018 if no_call {
1019 syntax_error!(p, p.input().cur_span(), SyntaxError::InvalidSuperCall);
1020 }
1021 syntax_error!(p, p.input().cur_span(), SyntaxError::InvalidSuper);
1022 }
1023 Callee::Import(..) => {
1024 syntax_error!(p, p.input().cur_span(), SyntaxError::InvalidImport);
1025 }
1026 #[cfg(swc_ast_unknown)]
1027 _ => unreachable!(),
1028 }
1029}
1030
1031pub fn parse_dynamic_import_or_import_meta<'a, P: Parser<'a>>(
1032 p: &mut P,
1033 start: BytePos,
1034 no_call: bool,
1035) -> PResult<Box<Expr>> {
1036 if p.input_mut().eat(&P::Token::DOT) {
1037 p.mark_found_module_item();
1038
1039 let ident = parse_ident_name(p)?;
1040
1041 match &*ident.sym {
1042 "meta" => {
1043 let span = p.span(start);
1044 if !p.ctx().contains(Context::CanBeModule) {
1045 p.emit_err(span, SyntaxError::ImportMetaInScript);
1046 }
1047 let expr = MetaPropExpr {
1048 span,
1049 kind: MetaPropKind::ImportMeta,
1050 };
1051 parse_subscripts(p, Callee::Expr(expr.into()), no_call, false)
1052 }
1053 "defer" => parse_dynamic_import_call(p, start, no_call, ImportPhase::Defer),
1054 "source" => parse_dynamic_import_call(p, start, no_call, ImportPhase::Source),
1055 _ => unexpected!(p, "meta"),
1056 }
1057 } else {
1058 parse_dynamic_import_call(p, start, no_call, ImportPhase::Evaluation)
1059 }
1060}
1061
1062fn parse_dynamic_import_call<'a>(
1063 p: &mut impl Parser<'a>,
1064 start: BytePos,
1065 no_call: bool,
1066 phase: ImportPhase,
1067) -> PResult<Box<Expr>> {
1068 let import = Callee::Import(Import {
1069 span: p.span(start),
1070 phase,
1071 });
1072
1073 parse_subscripts(p, import, no_call, false)
1074}
1075
1076#[cfg_attr(
1078 feature = "tracing-spans",
1079 tracing::instrument(level = "debug", skip_all)
1080)]
1081pub fn parse_member_expr_or_new_expr<'a>(
1082 p: &mut impl Parser<'a>,
1083 is_new_expr: bool,
1084) -> PResult<Box<Expr>> {
1085 p.do_inside_of_context(Context::ShouldNotLexLtOrGtAsType, |p| {
1086 parse_member_expr_or_new_expr_inner(p, is_new_expr)
1087 })
1088}
1089
1090fn parse_member_expr_or_new_expr_inner<'a, P: Parser<'a>>(
1091 p: &mut P,
1092 is_new_expr: bool,
1093) -> PResult<Box<Expr>> {
1094 trace_cur!(p, parse_member_expr_or_new_expr);
1095
1096 let start = p.cur_pos();
1097 if p.input_mut().eat(&P::Token::NEW) {
1098 if p.input_mut().eat(&P::Token::DOT) {
1099 if p.input_mut().eat(&P::Token::TARGET) {
1100 let span = p.span(start);
1101 let expr = MetaPropExpr {
1102 span,
1103 kind: MetaPropKind::NewTarget,
1104 }
1105 .into();
1106
1107 let ctx = p.ctx();
1108 if !ctx.contains(Context::InsideNonArrowFunctionScope)
1109 && !ctx.contains(Context::InParameters)
1110 && !ctx.contains(Context::InClass)
1111 {
1112 p.emit_err(span, SyntaxError::InvalidNewTarget);
1113 }
1114
1115 return parse_subscripts(p, Callee::Expr(expr), true, false);
1116 }
1117
1118 unexpected!(p, "target")
1119 }
1120
1121 let callee = parse_member_expr_or_new_expr(p, is_new_expr)?;
1123 return_if_arrow!(p, callee);
1124
1125 if is_new_expr {
1126 match *callee {
1127 Expr::OptChain(OptChainExpr {
1128 span,
1129 optional: true,
1130 ..
1131 }) => {
1132 syntax_error!(p, span, SyntaxError::OptChainCannotFollowConstructorCall)
1133 }
1134 Expr::Member(MemberExpr { ref obj, .. }) => {
1135 if let Expr::OptChain(OptChainExpr {
1136 span,
1137 optional: true,
1138 ..
1139 }) = **obj
1140 {
1141 syntax_error!(p, span, SyntaxError::OptChainCannotFollowConstructorCall)
1142 }
1143 }
1144 _ => {}
1145 }
1146 }
1147
1148 let type_args = if p.input().syntax().typescript() && {
1149 let cur = p.input().cur();
1150 cur.is_less() || cur.is_lshift()
1151 } {
1152 try_parse_ts(p, |p| {
1153 let args =
1154 p.do_outside_of_context(Context::ShouldNotLexLtOrGtAsType, parse_ts_type_args)?;
1155 p.assert_and_bump(&P::Token::GREATER);
1156 if !p.input().is(&P::Token::LPAREN) {
1157 let span = p.input().cur_span();
1158 let cur = p.input_mut().dump_cur();
1159 syntax_error!(p, span, SyntaxError::Expected('('.to_string(), cur))
1160 }
1161 Ok(Some(args))
1162 })
1163 } else {
1164 None
1165 };
1166
1167 if !is_new_expr || p.input().is(&P::Token::LPAREN) {
1168 let args = parse_args(p, false).map(Some)?;
1170
1171 let new_expr = Callee::Expr(
1172 NewExpr {
1173 span: p.span(start),
1174 callee,
1175 args,
1176 type_args,
1177 ..Default::default()
1178 }
1179 .into(),
1180 );
1181
1182 return parse_subscripts(p, new_expr, true, false);
1185 }
1186
1187 return Ok(NewExpr {
1190 span: p.span(start),
1191 callee,
1192 args: None,
1193 type_args,
1194 ..Default::default()
1195 }
1196 .into());
1197 }
1198
1199 if p.input_mut().eat(&P::Token::SUPER) {
1200 let base = Callee::Super(Super {
1201 span: p.span(start),
1202 });
1203 return parse_subscripts(p, base, true, false);
1204 } else if p.input_mut().eat(&P::Token::IMPORT) {
1205 return parse_dynamic_import_or_import_meta(p, start, true);
1206 }
1207 let obj = p.parse_primary_expr()?;
1208 return_if_arrow!(p, obj);
1209
1210 let type_args = if p.syntax().typescript() && p.input().is(&P::Token::LESS) {
1211 try_parse_ts_type_args(p)
1212 } else {
1213 None
1214 };
1215 let obj = if let Some(type_args) = type_args {
1216 trace_cur!(p, parse_member_expr_or_new_expr__with_type_args);
1217 TsInstantiation {
1218 expr: obj,
1219 type_args,
1220 span: p.span(start),
1221 }
1222 .into()
1223 } else {
1224 obj
1225 };
1226
1227 parse_subscripts(p, Callee::Expr(obj), true, false)
1228}
1229
1230#[cfg_attr(feature = "tracing-spans", tracing::instrument(skip_all))]
1233pub fn parse_new_expr<'a>(p: &mut impl Parser<'a>) -> PResult<Box<Expr>> {
1234 trace_cur!(p, parse_new_expr);
1235 parse_member_expr_or_new_expr(p, true)
1236}
1237
1238pub fn parse_bin_expr<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<Expr>> {
1240 trace_cur!(p, parse_bin_expr);
1241
1242 let left = match p.parse_unary_expr() {
1243 Ok(v) => v,
1244 Err(err) => {
1245 trace_cur!(p, parse_bin_expr__recovery_unary_err);
1246
1247 let cur = p.input().cur();
1248 if cur.is_error() {
1249 let err = p.input_mut().expect_error_token_and_bump();
1250 return Err(err);
1251 } else if (cur.is_in() && p.ctx().contains(Context::IncludeInExpr))
1252 || cur.is_instanceof()
1253 || cur.is_bin_op()
1254 {
1255 p.emit_err(p.input().cur_span(), SyntaxError::TS1109);
1256 Invalid { span: err.span() }.into()
1257 } else {
1258 return Err(err);
1259 }
1260 }
1261 };
1262
1263 return_if_arrow!(p, left);
1264 parse_bin_op_recursively(p, left, 0)
1265}
1266
1267pub fn parse_bin_op_recursively<'a>(
1275 p: &mut impl Parser<'a>,
1276 mut left: Box<Expr>,
1277 mut min_prec: u8,
1278) -> PResult<Box<Expr>> {
1279 loop {
1280 let (next_left, next_prec) = parse_bin_op_recursively_inner(p, left, min_prec)?;
1281
1282 match &*next_left {
1283 Expr::Bin(BinExpr {
1284 span,
1285 left,
1286 op: op!("&&"),
1287 ..
1288 })
1289 | Expr::Bin(BinExpr {
1290 span,
1291 left,
1292 op: op!("||"),
1293 ..
1294 }) => {
1295 if let Expr::Bin(BinExpr { op: op!("??"), .. }) = &**left {
1296 p.emit_err(*span, SyntaxError::NullishCoalescingWithLogicalOp);
1297 }
1298 }
1299 _ => {}
1300 }
1301
1302 min_prec = match next_prec {
1303 Some(v) => v,
1304 None => return Ok(next_left),
1305 };
1306
1307 left = next_left;
1308 }
1309}
1310
1311fn parse_bin_op_recursively_inner<'a, P: Parser<'a>>(
1313 p: &mut P,
1314 left: Box<Expr>,
1315 min_prec: u8,
1316) -> PResult<(Box<Expr>, Option<u8>)> {
1317 const PREC_OF_IN: u8 = 7;
1318
1319 if p.input().syntax().typescript() && !p.input().had_line_break_before_cur() {
1320 if PREC_OF_IN > min_prec && p.input().is(&P::Token::AS) {
1321 let start = left.span_lo();
1322 let expr = left;
1323 let node = if peek!(p).is_some_and(|cur| cur.is_const()) {
1324 p.bump(); p.bump(); TsConstAssertion {
1327 span: p.span(start),
1328 expr,
1329 }
1330 .into()
1331 } else {
1332 let type_ann = next_then_parse_ts_type(p)?;
1333 TsAsExpr {
1334 span: p.span(start),
1335 expr,
1336 type_ann,
1337 }
1338 .into()
1339 };
1340
1341 return parse_bin_op_recursively_inner(p, node, min_prec);
1342 } else if p.input().is(&P::Token::SATISFIES) {
1343 let start = left.span_lo();
1344 let expr = left;
1345 let node = {
1346 let type_ann = next_then_parse_ts_type(p)?;
1347 TsSatisfiesExpr {
1348 span: p.span(start),
1349 expr,
1350 type_ann,
1351 }
1352 .into()
1353 };
1354
1355 return parse_bin_op_recursively_inner(p, node, min_prec);
1356 }
1357 }
1358
1359 let cur = p.input().cur();
1361 let op = if cur.is_in() && p.ctx().contains(Context::IncludeInExpr) {
1362 op!("in")
1363 } else if cur.is_instanceof() {
1364 op!("instanceof")
1365 } else if let Some(op) = cur.as_bin_op() {
1366 op
1367 } else {
1368 return Ok((left, None));
1369 };
1370
1371 if op.precedence() <= min_prec {
1372 if cfg!(feature = "debug") {
1373 tracing::trace!(
1374 "returning {:?} without parsing {:?} because min_prec={}, prec={}",
1375 left,
1376 op,
1377 min_prec,
1378 op.precedence()
1379 );
1380 }
1381
1382 return Ok((left, None));
1383 }
1384 p.bump();
1385 if cfg!(feature = "debug") {
1386 tracing::trace!(
1387 "parsing binary op {:?} min_prec={}, prec={}",
1388 op,
1389 min_prec,
1390 op.precedence()
1391 );
1392 }
1393 match *left {
1394 Expr::Unary { .. } | Expr::Await(..) if op == op!("**") => {
1396 syntax_error!(
1401 p,
1402 SyntaxError::UnaryInExp {
1403 left: format!("{left:?}"),
1405 left_span: left.span(),
1406 }
1407 )
1408 }
1409 _ => {}
1410 }
1411
1412 let right = {
1413 let left_of_right = p.parse_unary_expr()?;
1414 parse_bin_op_recursively(
1415 p,
1416 left_of_right,
1417 if op == op!("**") {
1418 op.precedence() - 1
1420 } else {
1421 op.precedence()
1422 },
1423 )?
1424 };
1425 if op == op!("??") {
1438 match *left {
1439 Expr::Bin(BinExpr { span, op, .. }) if op == op!("&&") || op == op!("||") => {
1440 p.emit_err(span, SyntaxError::NullishCoalescingWithLogicalOp);
1441 }
1442 _ => {}
1443 }
1444
1445 match *right {
1446 Expr::Bin(BinExpr { span, op, .. }) if op == op!("&&") || op == op!("||") => {
1447 p.emit_err(span, SyntaxError::NullishCoalescingWithLogicalOp);
1448 }
1449 _ => {}
1450 }
1451 }
1452
1453 let node = BinExpr {
1454 span: Span::new_with_checked(left.span_lo(), right.span_hi()),
1455 op,
1456 left,
1457 right,
1458 }
1459 .into();
1460
1461 Ok((node, Some(min_prec)))
1462}
1463
1464pub(crate) fn parse_unary_expr<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<Expr>> {
1468 trace_cur!(p, parse_unary_expr);
1469
1470 let token_and_span = p.input().get_cur();
1471 let start = token_and_span.span().lo;
1472 let cur = token_and_span.token();
1473
1474 if !p.input().syntax().jsx() && p.input().syntax().typescript() && cur.is_less() {
1475 p.bump(); if p.input_mut().eat(&P::Token::CONST) {
1477 expect!(p, &P::Token::GREATER);
1478 let expr = p.parse_unary_expr()?;
1479 return Ok(TsConstAssertion {
1480 span: p.span(start),
1481 expr,
1482 }
1483 .into());
1484 }
1485
1486 return parse_ts_type_assertion(p, start)
1487 .map(Expr::from)
1488 .map(Box::new);
1489 } else if cur.is_plus_plus() || cur.is_minus_minus() {
1490 let op = if cur.is_plus_plus() {
1492 op!("++")
1493 } else {
1494 op!("--")
1495 };
1496 p.bump();
1497
1498 let arg = p.parse_unary_expr()?;
1499 let span = Span::new_with_checked(start, arg.span_hi());
1500 p.check_assign_target(&arg, false);
1501
1502 return Ok(UpdateExpr {
1503 span,
1504 prefix: true,
1505 op,
1506 arg,
1507 }
1508 .into());
1509 } else if cur.is_delete()
1510 || cur.is_void()
1511 || cur.is_typeof()
1512 || cur.is_plus()
1513 || cur.is_minus()
1514 || cur.is_tilde()
1515 || cur.is_bang()
1516 {
1517 let op = if cur.is_delete() {
1519 op!("delete")
1520 } else if cur.is_void() {
1521 op!("void")
1522 } else if cur.is_typeof() {
1523 op!("typeof")
1524 } else if cur.is_plus() {
1525 op!(unary, "+")
1526 } else if cur.is_minus() {
1527 op!(unary, "-")
1528 } else if cur.is_tilde() {
1529 op!("~")
1530 } else {
1531 debug_assert!(cur.is_bang());
1532 op!("!")
1533 };
1534 p.bump();
1535 let arg_start = p.cur_pos() - BytePos(1);
1536 let arg = match p.parse_unary_expr() {
1537 Ok(expr) => expr,
1538 Err(err) => {
1539 p.emit_error(err);
1540 Invalid {
1541 span: Span::new_with_checked(arg_start, arg_start),
1542 }
1543 .into()
1544 }
1545 };
1546
1547 if op == op!("delete") {
1548 if let Expr::Ident(ref i) = *arg {
1549 p.emit_strict_mode_err(i.span, SyntaxError::TS1102)
1550 }
1551 }
1552
1553 return Ok(UnaryExpr {
1554 span: Span::new_with_checked(start, arg.span_hi()),
1555 op,
1556 arg,
1557 }
1558 .into());
1559 } else if cur.is_await() {
1560 return parse_await_expr(p, None);
1561 }
1562
1563 let expr = p.parse_lhs_expr()?;
1565 return_if_arrow!(p, expr);
1566
1567 if p.input().had_line_break_before_cur() {
1569 return Ok(expr);
1570 }
1571
1572 let cur = p.input().cur();
1573 if cur.is_plus_plus() || cur.is_minus_minus() {
1574 let op = if cur.is_plus_plus() {
1575 op!("++")
1576 } else {
1577 op!("--")
1578 };
1579 p.check_assign_target(&expr, false);
1580 p.bump();
1581
1582 return Ok(UpdateExpr {
1583 span: p.span(expr.span_lo()),
1584 prefix: false,
1585 op,
1586 arg: expr,
1587 }
1588 .into());
1589 }
1590 Ok(expr)
1591}
1592
1593pub fn parse_await_expr<'a, P: Parser<'a>>(
1594 p: &mut P,
1595 start_of_await_token: Option<BytePos>,
1596) -> PResult<Box<Expr>> {
1597 let start = start_of_await_token.unwrap_or_else(|| p.cur_pos());
1598
1599 if start_of_await_token.is_none() {
1600 p.assert_and_bump(&P::Token::AWAIT);
1601 }
1602
1603 let await_token = p.span(start);
1604
1605 if p.input().is(&P::Token::MUL) {
1606 syntax_error!(p, SyntaxError::AwaitStar);
1607 }
1608
1609 let ctx = p.ctx();
1610
1611 let span = p.span(start);
1612
1613 if !ctx.contains(Context::InAsync)
1614 && (p.is_general_semi() || {
1615 let cur = p.input().cur();
1616 cur.is_rparen() || cur.is_rbracket() || cur.is_comma()
1617 })
1618 {
1619 if ctx.contains(Context::Module) {
1620 p.emit_err(span, SyntaxError::InvalidIdentInAsync);
1621 }
1622
1623 return Ok(Ident::new_no_ctxt(atom!("await"), span).into());
1624 }
1625
1626 if start_of_await_token.is_none() && ctx.contains(Context::TopLevel) {
1628 p.mark_found_module_item();
1629 if !ctx.contains(Context::CanBeModule) {
1630 p.emit_err(await_token, SyntaxError::TopLevelAwaitInScript);
1631 }
1632 }
1633
1634 if ctx.contains(Context::InFunction) && !ctx.contains(Context::InAsync) {
1635 p.emit_err(await_token, SyntaxError::AwaitInFunction);
1636 }
1637
1638 if ctx.contains(Context::InParameters) && !ctx.contains(Context::InFunction) {
1639 p.emit_err(span, SyntaxError::AwaitParamInAsync);
1640 }
1641
1642 let arg = p.parse_unary_expr()?;
1643 Ok(AwaitExpr {
1644 span: p.span(start),
1645 arg,
1646 }
1647 .into())
1648}
1649
1650pub(super) fn parse_for_head_prefix<'a>(p: &mut impl Parser<'a>) -> PResult<Box<Expr>> {
1651 p.parse_expr()
1652}
1653
1654#[cfg_attr(
1656 feature = "tracing-spans",
1657 tracing::instrument(level = "debug", skip_all)
1658)]
1659pub fn parse_lhs_expr<'a, P: Parser<'a>, const PARSE_JSX: bool>(p: &mut P) -> PResult<Box<Expr>> {
1660 trace_cur!(p, parse_lhs_expr);
1661
1662 if PARSE_JSX && p.input().syntax().jsx() {
1664 fn into_expr(e: Either<JSXFragment, JSXElement>) -> Box<Expr> {
1665 match e {
1666 Either::Left(l) => l.into(),
1667 Either::Right(r) => r.into(),
1668 }
1669 }
1670 let token_and_span = p.input().get_cur();
1671 let cur = token_and_span.token();
1672 if cur.is_jsx_text() {
1673 return Ok(Box::new(Expr::Lit(Lit::JSXText(parse_jsx_text(p)))));
1674 } else if cur.is_jsx_tag_start() {
1675 return parse_jsx_element(p).map(into_expr);
1676 } else if cur.is_error() {
1677 let err = p.input_mut().expect_error_token_and_bump();
1678 return Err(err);
1679 }
1680
1681 if p.input().is(&P::Token::LESS) && !peek!(p).is_some_and(|peek| peek.is_bang()) {
1682 return parse_jsx_element(p).map(into_expr);
1689 }
1690 }
1691
1692 let token_and_span = p.input().get_cur();
1693 let start = token_and_span.span().lo;
1694 let cur = token_and_span.token();
1695
1696 if cur.is_super() {
1698 p.bump(); let obj = Callee::Super(Super {
1700 span: p.span(start),
1701 });
1702 return parse_subscripts(p, obj, false, false);
1703 } else if cur.is_import() {
1704 p.bump(); return parse_dynamic_import_or_import_meta(p, start, false);
1706 }
1707
1708 let callee = parse_new_expr(p)?;
1709 return_if_arrow!(p, callee);
1710
1711 let type_args = if p.input().syntax().typescript() && {
1712 let cur = p.input().cur();
1713 cur.is_less() || cur.is_lshift()
1714 } {
1715 try_parse_ts(p, |p| {
1716 let type_args = parse_ts_type_args(p)?;
1717 p.assert_and_bump(&P::Token::GREATER);
1718 if p.input().is(&P::Token::LPAREN) {
1719 Ok(Some(type_args))
1720 } else {
1721 Ok(None)
1722 }
1723 })
1724 } else {
1725 None
1726 };
1727
1728 if let Expr::New(ne @ NewExpr { args: None, .. }) = *callee {
1729 if type_args.is_some() {
1732 expect!(p, &P::Token::LPAREN);
1734 }
1735 debug_assert!(
1736 !p.input().cur().is_lparen(),
1737 "parse_new_expr() should eat paren if it exists"
1738 );
1739 return Ok(NewExpr { type_args, ..ne }.into());
1740 }
1741 if p.input().is(&P::Token::LPAREN) {
1745 let (callee, is_import) = match callee {
1748 _ if callee.is_ident_ref_to("import") => (
1749 Callee::Import(Import {
1750 span: callee.span(),
1751 phase: Default::default(),
1752 }),
1753 true,
1754 ),
1755 _ => (Callee::Expr(callee), false),
1756 };
1757 let args = parse_args(p, is_import)?;
1758
1759 let call_expr = match callee {
1760 Callee::Expr(e) if unwrap_ts_non_null(&e).is_opt_chain() => OptChainExpr {
1761 span: p.span(start),
1762 base: Box::new(OptChainBase::Call(OptCall {
1763 span: p.span(start),
1764 callee: e,
1765 args,
1766 type_args,
1767 ..Default::default()
1768 })),
1769 optional: false,
1770 }
1771 .into(),
1772 _ => CallExpr {
1773 span: p.span(start),
1774
1775 callee,
1776 args,
1777 type_args,
1778 ..Default::default()
1779 }
1780 .into(),
1781 };
1782
1783 return parse_subscripts(p, Callee::Expr(call_expr), false, false);
1784 }
1785 if type_args.is_some() {
1786 expect!(p, &P::Token::LPAREN);
1788 }
1789
1790 Ok(callee)
1793}
1794
1795#[cfg_attr(
1797 feature = "tracing-spans",
1798 tracing::instrument(level = "debug", skip_all)
1799)]
1800pub fn parse_args_or_pats<'a, P: Parser<'a>>(
1801 p: &mut P,
1802) -> PResult<(Vec<AssignTargetOrSpread>, Option<Span>)> {
1803 p.do_outside_of_context(Context::WillExpectColonForCond, parse_args_or_pats_inner)
1804}
1805
1806fn parse_args_or_pats_inner<'a, P: Parser<'a>>(
1807 p: &mut P,
1808) -> PResult<(Vec<AssignTargetOrSpread>, Option<Span>)> {
1809 trace_cur!(p, parse_args_or_pats);
1810
1811 expect!(p, &P::Token::LPAREN);
1812
1813 let mut items = Vec::new();
1814 let mut trailing_comma = None;
1815
1816 while !p.input().is(&P::Token::RPAREN) {
1819 let is_async = p.input().is(&P::Token::ASYNC)
1821 && peek!(p).is_some_and(|t| t.is_lparen() || t.is_word() || t.is_function());
1822
1823 let start = p.cur_pos();
1824 p.state_mut().potential_arrow_start = Some(start);
1825 let modifier_start = start;
1826
1827 let has_modifier = eat_any_ts_modifier(p)?;
1828 let pat_start = p.cur_pos();
1829
1830 let mut arg = {
1831 if p.input().syntax().typescript()
1832 && (p.is_ident_ref()
1833 || (p.input().is(&P::Token::DOTDOTDOT) && p.peek_is_ident_ref()))
1834 {
1835 let spread = if p.input_mut().eat(&P::Token::DOTDOTDOT) {
1836 Some(p.input().prev_span())
1837 } else {
1838 None
1839 };
1840
1841 let expr = if spread.is_some() {
1844 parse_bin_expr(p)?
1845 } else {
1846 let mut expr = parse_bin_expr(p)?;
1847
1848 if p.input().cur().is_assign_op() {
1849 expr = finish_assignment_expr(p, start, expr)?
1850 }
1851
1852 expr
1853 };
1854
1855 ExprOrSpread { spread, expr }
1856 } else {
1857 p.allow_in_expr(|p| p.parse_expr_or_spread())?
1858 }
1859 };
1860
1861 let optional = if p.input().syntax().typescript() {
1862 if p.input().is(&P::Token::QUESTION) {
1863 if peek!(p).is_some_and(|peek| {
1864 peek.is_comma() || peek.is_equal() || peek.is_rparen() || peek.is_colon()
1865 }) {
1866 p.assert_and_bump(&P::Token::QUESTION);
1867 if arg.spread.is_some() {
1868 p.emit_err(p.input().prev_span(), SyntaxError::TS1047);
1869 }
1870 match *arg.expr {
1871 Expr::Ident(..) => {}
1872 _ => {
1873 syntax_error!(p, arg.span(), SyntaxError::TsBindingPatCannotBeOptional)
1874 }
1875 }
1876 true
1877 } else if matches!(arg, ExprOrSpread { spread: None, .. }) {
1878 expect!(p, &P::Token::QUESTION);
1879 let test = arg.expr;
1880
1881 let cons = p.do_inside_of_context(
1882 Context::InCondExpr
1883 .union(Context::WillExpectColonForCond)
1884 .union(Context::IncludeInExpr),
1885 parse_assignment_expr,
1886 )?;
1887 expect!(p, &P::Token::COLON);
1888
1889 let alt = p.do_inside_of_context(Context::InCondExpr, |p| {
1890 p.do_outside_of_context(
1891 Context::WillExpectColonForCond,
1892 parse_assignment_expr,
1893 )
1894 })?;
1895
1896 arg = ExprOrSpread {
1897 spread: None,
1898 expr: CondExpr {
1899 span: Span::new_with_checked(start, alt.span_hi()),
1900 test,
1901 cons,
1902 alt,
1903 }
1904 .into(),
1905 };
1906
1907 false
1908 } else {
1909 false
1910 }
1911 } else {
1912 false
1913 }
1914 } else {
1915 false
1916 };
1917
1918 if optional || (p.input().syntax().typescript() && p.input().is(&P::Token::COLON)) {
1919 let mut pat = reparse_expr_as_pat(p, PatType::BindingPat, arg.expr)?;
1926 if optional {
1927 match pat {
1928 Pat::Ident(ref mut i) => i.optional = true,
1929 _ => unreachable!(),
1930 }
1931 }
1932 if let Some(span) = arg.spread {
1933 pat = RestPat {
1934 span: p.span(pat_start),
1935 dot3_token: span,
1936 arg: Box::new(pat),
1937 type_ann: None,
1938 }
1939 .into();
1940 }
1941 match pat {
1942 Pat::Ident(BindingIdent {
1943 id: Ident { ref mut span, .. },
1944 ref mut type_ann,
1945 ..
1946 })
1947 | Pat::Array(ArrayPat {
1948 ref mut type_ann,
1949 ref mut span,
1950 ..
1951 })
1952 | Pat::Object(ObjectPat {
1953 ref mut type_ann,
1954 ref mut span,
1955 ..
1956 })
1957 | Pat::Rest(RestPat {
1958 ref mut type_ann,
1959 ref mut span,
1960 ..
1961 }) => {
1962 let new_type_ann = try_parse_ts_type_ann(p)?;
1963 if new_type_ann.is_some() {
1964 *span = Span::new_with_checked(pat_start, p.input().prev_span().hi);
1965 }
1966 *type_ann = new_type_ann;
1967 }
1968 Pat::Expr(ref expr) => unreachable!("invalid pattern: Expr({:?})", expr),
1969 Pat::Assign(..) | Pat::Invalid(..) => {
1970 }
1977 #[cfg(swc_ast_unknown)]
1978 _ => (),
1979 }
1980
1981 if p.input_mut().eat(&P::Token::EQUAL) {
1982 let right = parse_assignment_expr(p)?;
1983 pat = AssignPat {
1984 span: p.span(pat_start),
1985 left: Box::new(pat),
1986 right,
1987 }
1988 .into();
1989 }
1990
1991 if has_modifier {
1992 p.emit_err(p.span(modifier_start), SyntaxError::TS2369);
1993 }
1994
1995 items.push(AssignTargetOrSpread::Pat(pat))
1996 } else {
1997 if has_modifier {
1998 p.emit_err(p.span(modifier_start), SyntaxError::TS2369);
1999 }
2000
2001 items.push(AssignTargetOrSpread::ExprOrSpread(arg));
2002 }
2003
2004 if p.input_mut().eat(&P::Token::ARROW) && {
2006 debug_assert_eq!(items.len(), 1);
2007 match items[0] {
2008 AssignTargetOrSpread::ExprOrSpread(ExprOrSpread { ref expr, .. })
2009 | AssignTargetOrSpread::Pat(Pat::Expr(ref expr)) => {
2010 matches!(**expr, Expr::Ident(..))
2011 }
2012 AssignTargetOrSpread::Pat(Pat::Ident(..)) => true,
2013 _ => false,
2014 }
2015 } {
2016 let params: Vec<Pat> = parse_paren_items_as_params(p, items.clone(), None)?;
2017
2018 let body: Box<BlockStmtOrExpr> = parse_fn_block_or_expr_body(
2019 p,
2020 false,
2021 false,
2022 true,
2023 params.is_simple_parameter_list(),
2024 )?;
2025 let span = p.span(start);
2026
2027 items.push(AssignTargetOrSpread::ExprOrSpread(ExprOrSpread {
2028 expr: Box::new(
2029 ArrowExpr {
2030 span,
2031 body,
2032 is_async,
2033 is_generator: false,
2034 params,
2035 ..Default::default()
2036 }
2037 .into(),
2038 ),
2039 spread: None,
2040 }));
2041 }
2042
2043 if !p.input().is(&P::Token::RPAREN) {
2044 expect!(p, &P::Token::COMMA);
2045 if p.input().is(&P::Token::RPAREN) {
2046 trailing_comma = Some(p.input().prev_span());
2047 }
2048 }
2049 }
2050
2051 expect!(p, &P::Token::RPAREN);
2052 Ok((items, trailing_comma))
2053}
2054
2055#[cfg_attr(
2056 feature = "tracing-spans",
2057 tracing::instrument(level = "debug", skip_all)
2058)]
2059pub fn parse_paren_expr_or_arrow_fn<'a, P: Parser<'a>>(
2060 p: &mut P,
2061 can_be_arrow: bool,
2062 async_span: Option<Span>,
2063) -> PResult<Box<Expr>> {
2064 trace_cur!(p, parse_paren_expr_or_arrow_fn);
2065
2066 let expr_start = async_span.map(|x| x.lo()).unwrap_or_else(|| p.cur_pos());
2067
2068 let (paren_items, trailing_comma) = p
2074 .do_outside_of_context(Context::WillExpectColonForCond, |p| {
2075 p.allow_in_expr(parse_args_or_pats)
2076 })?;
2077
2078 let has_pattern = paren_items
2079 .iter()
2080 .any(|item| matches!(item, AssignTargetOrSpread::Pat(..)));
2081
2082 let will_expect_colon_for_cond = p.ctx().contains(Context::WillExpectColonForCond);
2083 if p.syntax().typescript()
2085 && p.ctx().contains(Context::InCondExpr)
2086 && p.input().is(&P::Token::COLON)
2087 {
2088 let items_ref = &paren_items;
2090 if let Some(expr) = try_parse_ts(p, |p| {
2091 let return_type = parse_ts_type_or_type_predicate_ann(p, &P::Token::COLON)?;
2092
2093 expect!(p, &P::Token::ARROW);
2094
2095 let params: Vec<Pat> =
2096 parse_paren_items_as_params(p, items_ref.clone(), trailing_comma)?;
2097
2098 let body: Box<BlockStmtOrExpr> = parse_fn_block_or_expr_body(
2099 p,
2100 async_span.is_some(),
2101 false,
2102 true,
2103 params.is_simple_parameter_list(),
2104 )?;
2105
2106 if will_expect_colon_for_cond && !p.input().is(&P::Token::COLON) {
2107 trace_cur!(p, parse_arrow_in_cond__fail);
2108 unexpected!(p, "fail")
2109 }
2110
2111 Ok(Some(
2112 ArrowExpr {
2113 span: p.span(expr_start),
2114 is_async: async_span.is_some(),
2115 is_generator: false,
2116 params,
2117 body,
2118 return_type: Some(return_type),
2119 ..Default::default()
2120 }
2121 .into(),
2122 ))
2123 }) {
2124 return Ok(expr);
2125 }
2126 }
2127
2128 let return_type = if !p.ctx().contains(Context::WillExpectColonForCond)
2129 && p.input().syntax().typescript()
2130 && p.input().is(&P::Token::COLON)
2131 {
2132 try_parse_ts(p, |p| {
2133 let return_type = parse_ts_type_or_type_predicate_ann(p, &P::Token::COLON)?;
2134
2135 if !p.input().is(&P::Token::ARROW) {
2136 unexpected!(p, "fail")
2137 }
2138
2139 Ok(Some(return_type))
2140 })
2141 } else {
2142 None
2143 };
2144
2145 if has_pattern || return_type.is_some() || p.input().is(&P::Token::ARROW) {
2147 if p.input().had_line_break_before_cur() {
2148 syntax_error!(p, p.span(expr_start), SyntaxError::LineBreakBeforeArrow);
2149 }
2150
2151 if !can_be_arrow {
2152 syntax_error!(p, p.span(expr_start), SyntaxError::ArrowNotAllowed);
2153 }
2154 expect!(p, &P::Token::ARROW);
2155
2156 let params: Vec<Pat> = parse_paren_items_as_params(p, paren_items, trailing_comma)?;
2157
2158 let body: Box<BlockStmtOrExpr> = parse_fn_block_or_expr_body(
2159 p,
2160 async_span.is_some(),
2161 false,
2162 true,
2163 params.is_simple_parameter_list(),
2164 )?;
2165 let arrow_expr = ArrowExpr {
2166 span: p.span(expr_start),
2167 is_async: async_span.is_some(),
2168 is_generator: false,
2169 params,
2170 body,
2171 return_type,
2172 ..Default::default()
2173 };
2174 if let BlockStmtOrExpr::BlockStmt(..) = &*arrow_expr.body {
2175 if p.input().cur().is_bin_op() {
2176 p.emit_err(p.input().cur_span(), SyntaxError::TS1005);
2178 let errorred_expr = parse_bin_op_recursively(p, Box::new(arrow_expr.into()), 0)?;
2179
2180 if !p.is_general_semi() {
2181 p.emit_err(p.input().cur_span(), SyntaxError::TS1005);
2183 }
2184
2185 return Ok(errorred_expr);
2186 }
2187 }
2188 return Ok(arrow_expr.into());
2189 } else {
2190 for expr_or_spread in paren_items.iter() {
2194 if let AssignTargetOrSpread::ExprOrSpread(e) = expr_or_spread {
2195 if let Expr::Object(o) = &*e.expr {
2196 for prop in o.props.iter() {
2197 if let PropOrSpread::Prop(prop) = prop {
2198 if let Prop::Assign(..) = **prop {
2199 p.emit_err(prop.span(), SyntaxError::AssignProperty);
2200 }
2201 }
2202 }
2203 }
2204 }
2205 }
2206 }
2207
2208 let expr_or_spreads = paren_items
2209 .into_iter()
2210 .map(|item| -> PResult<_> {
2211 match item {
2212 AssignTargetOrSpread::ExprOrSpread(e) => Ok(e),
2213 _ => syntax_error!(p, item.span(), SyntaxError::InvalidExpr),
2214 }
2215 })
2216 .collect::<Result<Vec<_>, _>>()?;
2217 if let Some(async_span) = async_span {
2218 return Ok(CallExpr {
2220 span: p.span(async_span.lo()),
2221 callee: Callee::Expr(Box::new(
2222 Ident::new_no_ctxt(atom!("async"), async_span).into(),
2223 )),
2224 args: expr_or_spreads,
2225 ..Default::default()
2226 }
2227 .into());
2228 }
2229
2230 if expr_or_spreads.is_empty() {
2233 syntax_error!(
2234 p,
2235 Span::new_with_checked(expr_start, p.last_pos()),
2236 SyntaxError::EmptyParenExpr
2237 );
2238 }
2239
2240 if expr_or_spreads.len() == 1 {
2244 let expr = match expr_or_spreads.into_iter().next().unwrap() {
2245 ExprOrSpread {
2246 spread: Some(..),
2247 ref expr,
2248 } => syntax_error!(p, expr.span(), SyntaxError::SpreadInParenExpr),
2249 ExprOrSpread { expr, .. } => expr,
2250 };
2251 Ok(ParenExpr {
2252 span: p.span(expr_start),
2253 expr,
2254 }
2255 .into())
2256 } else {
2257 debug_assert!(expr_or_spreads.len() >= 2);
2258
2259 let mut exprs = Vec::with_capacity(expr_or_spreads.len());
2260 for expr in expr_or_spreads {
2261 match expr {
2262 ExprOrSpread {
2263 spread: Some(..),
2264 ref expr,
2265 } => syntax_error!(p, expr.span(), SyntaxError::SpreadInParenExpr),
2266 ExprOrSpread { expr, .. } => exprs.push(expr),
2267 }
2268 }
2269 debug_assert!(exprs.len() >= 2);
2270
2271 let seq_expr = SeqExpr {
2273 span: Span::new_with_checked(
2274 exprs.first().unwrap().span_lo(),
2275 exprs.last().unwrap().span_hi(),
2276 ),
2277 exprs,
2278 }
2279 .into();
2280 Ok(ParenExpr {
2281 span: p.span(expr_start),
2282 expr: seq_expr,
2283 }
2284 .into())
2285 }
2286}
2287
2288pub fn parse_primary_expr_rest<'a, P: Parser<'a>>(
2289 p: &mut P,
2290 start: BytePos,
2291 can_be_arrow: bool,
2292) -> PResult<Box<Expr>> {
2293 let decorators = if p.input().is(&P::Token::AT) {
2294 Some(parse_decorators(p, false)?)
2295 } else {
2296 None
2297 };
2298
2299 let token_and_span = p.input().get_cur();
2300 let cur = token_and_span.token();
2301
2302 if cur.is_class() {
2303 return parse_class_expr(p, start, decorators.unwrap_or_default());
2304 }
2305
2306 let try_parse_arrow_expr = |p: &mut P, id: Ident, id_is_async| -> PResult<Box<Expr>> {
2307 if can_be_arrow && !p.input().had_line_break_before_cur() {
2308 if id_is_async && p.is_ident_ref() {
2309 let ctx = p.ctx();
2316 if ctx.contains(Context::ForLoopInit)
2317 && p.input().is(&P::Token::OF)
2318 && !peek!(p).is_some_and(|peek| peek.is_arrow())
2319 {
2320 if !ctx.contains(Context::ForAwaitLoopInit) {
2326 p.emit_err(p.input().prev_span(), SyntaxError::TS1106);
2327 }
2328
2329 return Ok(id.into());
2330 }
2331
2332 let ident = parse_binding_ident(p, false)?;
2333 if p.input().syntax().typescript()
2334 && ident.sym == "as"
2335 && !p.input().is(&P::Token::ARROW)
2336 {
2337 let type_ann = p.in_type(parse_ts_type)?;
2339 return Ok(TsAsExpr {
2340 span: p.span(start),
2341 expr: Box::new(id.into()),
2342 type_ann,
2343 }
2344 .into());
2345 }
2346
2347 let arg = ident.into();
2349 let params = vec![arg];
2350 expect!(p, &P::Token::ARROW);
2351 let body = parse_fn_block_or_expr_body(
2352 p,
2353 true,
2354 false,
2355 true,
2356 params.is_simple_parameter_list(),
2357 )?;
2358
2359 return Ok(ArrowExpr {
2360 span: p.span(start),
2361 body,
2362 params,
2363 is_async: true,
2364 is_generator: false,
2365 ..Default::default()
2366 }
2367 .into());
2368 } else if p.input_mut().eat(&P::Token::ARROW) {
2369 if p.ctx().contains(Context::Strict) && id.is_reserved_in_strict_bind() {
2370 p.emit_strict_mode_err(id.span, SyntaxError::EvalAndArgumentsInStrict)
2371 }
2372 let params = vec![id.into()];
2373 let body = parse_fn_block_or_expr_body(
2374 p,
2375 false,
2376 false,
2377 true,
2378 params.is_simple_parameter_list(),
2379 )?;
2380
2381 return Ok(ArrowExpr {
2382 span: p.span(start),
2383 body,
2384 params,
2385 is_async: false,
2386 is_generator: false,
2387 ..Default::default()
2388 }
2389 .into());
2390 }
2391 }
2392
2393 Ok(id.into())
2394 };
2395
2396 let token_start = token_and_span.span().lo;
2397 if cur.is_let() || (p.input().syntax().typescript() && cur.is_await()) {
2398 let ctx = p.ctx();
2399 let id = parse_ident(
2400 p,
2401 !ctx.contains(Context::InGenerator),
2402 !ctx.contains(Context::InAsync),
2403 )?;
2404 try_parse_arrow_expr(p, id, false)
2405 } else if cur.is_hash() {
2406 p.bump(); let id = parse_ident_name(p)?;
2408 Ok(PrivateName {
2409 span: p.span(start),
2410 name: id.sym,
2411 }
2412 .into())
2413 } else if cur.is_unknown_ident() {
2414 let word = p.input_mut().expect_word_token_and_bump();
2415 if p.ctx().contains(Context::InClassField) && word == atom!("arguments") {
2416 p.emit_err(p.input().prev_span(), SyntaxError::ArgumentsInClassField)
2417 };
2418 let id = Ident::new_no_ctxt(word, p.span(token_start));
2419 try_parse_arrow_expr(p, id, false)
2420 } else if p.is_ident_ref() {
2421 let id_is_async = p.input().cur().is_async();
2422 let word = p.input_mut().expect_word_token_and_bump();
2423 let id = Ident::new_no_ctxt(word, p.span(token_start));
2424 try_parse_arrow_expr(p, id, id_is_async)
2425 } else {
2426 syntax_error!(p, p.input().cur_span(), SyntaxError::TS1109)
2427 }
2428}
2429
2430pub fn try_parse_regexp<'a, P: Parser<'a>>(p: &mut P, start: BytePos) -> Option<Box<Expr>> {
2431 debug_assert!(p.input().cur().is_slash() || p.input().cur().is_slash_eq());
2433
2434 p.input_mut().set_next_regexp(Some(start));
2435
2436 p.bump(); let cur = p.input().cur();
2439 if cur.is_regexp() {
2440 p.input_mut().set_next_regexp(None);
2441 let (exp, flags) = p.input_mut().expect_regex_token_and_bump();
2442 let span = p.span(start);
2443
2444 let mut flags_count =
2445 flags
2446 .chars()
2447 .fold(FxHashMap::<char, usize>::default(), |mut map, flag| {
2448 let key = match flag {
2449 'd' | 'g' | 'i' | 'm' | 's' | 'u' | 'v' | 'y' => flag,
2451 _ => '\u{0000}', };
2453 map.entry(key).and_modify(|count| *count += 1).or_insert(1);
2454 map
2455 });
2456
2457 if flags_count.remove(&'\u{0000}').is_some() {
2458 p.emit_err(span, SyntaxError::UnknownRegExpFlags);
2459 }
2460
2461 if let Some((flag, _)) = flags_count.iter().find(|(_, count)| **count > 1) {
2462 p.emit_err(span, SyntaxError::DuplicatedRegExpFlags(*flag));
2463 }
2464
2465 Some(Lit::Regex(Regex { span, exp, flags }).into())
2466 } else {
2467 None
2468 }
2469}
2470
2471pub fn try_parse_async_start<'a, P: Parser<'a>>(
2472 p: &mut P,
2473 can_be_arrow: bool,
2474) -> Option<PResult<Box<Expr>>> {
2475 if peek!(p).is_some_and(|peek| peek.is_function())
2476 && !p.input_mut().has_linebreak_between_cur_and_peeked()
2477 {
2478 return Some(parse_async_fn_expr(p));
2480 }
2481
2482 if can_be_arrow
2483 && p.input().syntax().typescript()
2484 && peek!(p).is_some_and(|peek| peek.is_less())
2485 {
2486 if let Some(res) = try_parse_ts(p, |p| {
2488 let start = p.cur_pos();
2489 p.assert_and_bump(&P::Token::ASYNC);
2490 try_parse_ts_generic_async_arrow_fn(p, start)
2491 }) {
2492 return Some(Ok(res.into()));
2493 }
2494 }
2495
2496 if can_be_arrow
2497 && peek!(p).is_some_and(|peek| peek.is_lparen())
2498 && !p.input_mut().has_linebreak_between_cur_and_peeked()
2499 {
2500 if let Err(e) = p.expect(&P::Token::ASYNC) {
2501 return Some(Err(e));
2502 }
2503 let async_span = p.input().prev_span();
2504 return Some(parse_paren_expr_or_arrow_fn(
2505 p,
2506 can_be_arrow,
2507 Some(async_span),
2508 ));
2509 }
2510
2511 None
2512}
2513
2514pub fn parse_this_expr<'a>(p: &mut impl Parser<'a>, start: BytePos) -> PResult<Box<Expr>> {
2515 debug_assert!(p.input().cur().is_this());
2516 p.input_mut().bump();
2517 Ok(ThisExpr {
2518 span: p.span(start),
2519 }
2520 .into())
2521}
2522
2523#[cfg_attr(
2525 feature = "tracing-spans",
2526 tracing::instrument(level = "debug", skip_all)
2527)]
2528pub(crate) fn parse_primary_expr<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<Expr>> {
2529 trace_cur!(p, parse_primary_expr);
2530
2531 let start = p.cur_pos();
2532
2533 let can_be_arrow = p
2534 .state_mut()
2535 .potential_arrow_start
2536 .map(|s| s == start)
2537 .unwrap_or(false);
2538
2539 let token = p.input().cur();
2540 if token.is_this() {
2541 return parse_this_expr(p, start);
2542 } else if token.is_async() {
2543 if let Some(res) = try_parse_async_start(p, can_be_arrow) {
2544 return res;
2545 }
2546 } else if token.is_lbracket() {
2547 return p.do_outside_of_context(Context::WillExpectColonForCond, parse_array_lit);
2548 } else if token.is_lbrace() {
2549 return parse_object_expr(p).map(Box::new);
2550 } else if token.is_function() {
2551 return parse_fn_expr(p);
2552 } else if token.is_null()
2553 || token.is_true()
2554 || token.is_false()
2555 || token.is_num()
2556 || token.is_bigint()
2557 || token.is_str()
2558 {
2559 return Ok(parse_lit(p)?.into());
2561 } else if token.is_slash() || token.is_slash_eq() {
2562 if let Some(res) = try_parse_regexp(p, start) {
2563 return Ok(res);
2564 }
2565 } else if token.is_lparen() {
2566 return parse_paren_expr_or_arrow_fn(p, can_be_arrow, None);
2567 } else if token.is_backquote() {
2568 return Ok((p
2570 .do_outside_of_context(Context::WillExpectColonForCond, |p| parse_tpl(p, false)))?
2571 .into());
2572 }
2573
2574 parse_primary_expr_rest(p, start, can_be_arrow)
2575}