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 };
590 return Ok((
591 TsNonNullExpr {
592 span: p.span(start),
593 expr,
594 }
595 .into(),
596 true,
597 ));
598 }
599
600 if matches!(obj, Callee::Expr(..)) && p.input().is(&P::Token::LESS) {
601 let is_dynamic_import = obj.is_import();
602
603 let mut obj_opt = Some(obj);
604 let mut_obj_opt = &mut obj_opt;
610
611 let result = p.do_inside_of_context(Context::ShouldNotLexLtOrGtAsType, |p| {
612 try_parse_ts(p, |p| {
613 if !no_call
614 && at_possible_async(
615 p,
616 match &mut_obj_opt {
617 Some(Callee::Expr(ref expr)) => expr,
618 _ => unreachable!(),
619 },
620 )
621 {
622 let async_arrow_fn = try_parse_ts_generic_async_arrow_fn(p, start)?;
625 if let Some(async_arrow_fn) = async_arrow_fn {
626 return Ok(Some((async_arrow_fn.into(), true)));
627 }
628 }
629
630 let type_args = parse_ts_type_args(p)?;
631 p.assert_and_bump(&P::Token::GREATER);
632 let cur = p.input().cur();
633
634 if !no_call && cur.is_lparen() {
635 let args = parse_args(p, is_dynamic_import)?;
638
639 let obj = mut_obj_opt.take().unwrap();
640
641 if let Callee::Expr(callee) = &obj {
642 if let Expr::OptChain(..) = &**callee {
643 return Ok(Some((
644 OptChainExpr {
645 span: p.span(start),
646 base: Box::new(OptChainBase::Call(OptCall {
647 span: p.span(start),
648 callee: obj.expect_expr(),
649 type_args: Some(type_args),
650 args,
651 ..Default::default()
652 })),
653 optional: false,
654 }
655 .into(),
656 true,
657 )));
658 }
659 }
660
661 Ok(Some((
662 CallExpr {
663 span: p.span(start),
664 callee: obj,
665 type_args: Some(type_args),
666 args,
667 ..Default::default()
668 }
669 .into(),
670 true,
671 )))
672 } else if cur.is_no_substitution_template_literal()
673 || cur.is_template_head()
674 || cur.is_backquote()
675 {
676 p.parse_tagged_tpl(
677 match mut_obj_opt {
678 Some(Callee::Expr(obj)) => obj.take(),
679 _ => unreachable!(),
680 },
681 Some(type_args),
682 )
683 .map(|expr| (expr.into(), true))
684 .map(Some)
685 } else if cur.is_equal() || cur.is_as() || cur.is_satisfies() {
686 Ok(Some((
687 TsInstantiation {
688 span: p.span(start),
689 expr: match mut_obj_opt {
690 Some(Callee::Expr(obj)) => obj.take(),
691 _ => unreachable!(),
692 },
693 type_args,
694 }
695 .into(),
696 false,
697 )))
698 } else if no_call {
699 unexpected!(p, "`")
700 } else {
701 unexpected!(p, "( or `")
702 }
703 })
704 });
705 if let Some(result) = result {
706 return Ok(result);
707 }
708
709 obj = obj_opt.unwrap();
710 }
711 }
712
713 let type_args = if p.syntax().typescript() && p.input().is(&P::Token::LESS) {
714 try_parse_ts_type_args(p)
715 } else {
716 None
717 };
718
719 let cur = p.input().cur();
720
721 if obj.is_import() && !(cur.is_dot() || cur.is_lparen()) {
722 unexpected!(p, "`.` or `(`")
723 }
724
725 let question_dot_token =
726 if p.input().is(&P::Token::QUESTION) && peek!(p).is_some_and(|peek| peek.is_dot()) {
727 let start = p.cur_pos();
728 expect!(p, &P::Token::QUESTION);
729 Some(p.span(start))
730 } else {
731 None
732 };
733
734 if !no_computed_member
736 && ((question_dot_token.is_some()
737 && p.input().is(&P::Token::DOT)
738 && peek!(p).is_some_and(|peek| peek.is_lbracket())
739 && p.input_mut().eat(&P::Token::DOT)
740 && p.input_mut().eat(&P::Token::LBRACKET))
741 || p.input_mut().eat(&P::Token::LBRACKET))
742 {
743 let bracket_lo = p.input().prev_span().lo;
744 let prop = p.allow_in_expr(|p| p.parse_expr())?;
745 expect!(p, &P::Token::RBRACKET);
746 let span = Span::new_with_checked(obj.span_lo(), p.input().last_pos());
747 debug_assert_eq!(obj.span_lo(), span.lo());
748 let prop = ComputedPropName {
749 span: Span::new_with_checked(bracket_lo, p.input().last_pos()),
750 expr: prop,
751 };
752
753 let type_args = if p.syntax().typescript() && p.input().is(&P::Token::LESS) {
754 try_parse_ts_type_args(p)
755 } else {
756 None
757 };
758
759 return Ok((
760 Box::new(match obj {
761 Callee::Import(..) => unreachable!(),
762 Callee::Super(obj) => {
763 if !p.ctx().contains(Context::AllowDirectSuper)
764 && !p.input().syntax().allow_super_outside_method()
765 {
766 syntax_error!(p, obj.span, SyntaxError::InvalidSuper);
767 } else if question_dot_token.is_some() {
768 if no_call {
769 syntax_error!(p, obj.span, SyntaxError::InvalidSuperCall);
770 } else {
771 syntax_error!(p, obj.span, SyntaxError::InvalidSuper);
772 }
773 } else {
774 SuperPropExpr {
775 span,
776 obj,
777 prop: SuperProp::Computed(prop),
778 }
779 .into()
780 }
781 }
782 Callee::Expr(obj) => {
783 let is_opt_chain = unwrap_ts_non_null(&obj).is_opt_chain();
784 let expr = MemberExpr {
785 span,
786 obj,
787 prop: MemberProp::Computed(prop),
788 };
789 let expr = if is_opt_chain || question_dot_token.is_some() {
790 OptChainExpr {
791 span,
792 optional: question_dot_token.is_some(),
793 base: Box::new(OptChainBase::Member(expr)),
794 }
795 .into()
796 } else {
797 expr.into()
798 };
799
800 if let Some(type_args) = type_args {
801 TsInstantiation {
802 expr: Box::new(expr),
803 type_args,
804 span: p.span(start),
805 }
806 .into()
807 } else {
808 expr
809 }
810 }
811 }),
812 true,
813 ));
814 }
815
816 if (question_dot_token.is_some()
817 && p.input().is(&P::Token::DOT)
818 && (peek!(p).is_some_and(|peek| peek.is_lparen())
819 || (p.syntax().typescript() && peek!(p).is_some_and(|peek| peek.is_less())))
820 && p.input_mut().eat(&P::Token::DOT))
821 || (!no_call && p.input().is(&P::Token::LPAREN))
822 {
823 let type_args = if p.syntax().typescript() && p.input().is(&P::Token::LESS) {
824 let ret = parse_ts_type_args(p)?;
825 p.assert_and_bump(&P::Token::GREATER);
826 Some(ret)
827 } else {
828 None
829 };
830 let args = parse_args(p, obj.is_import())?;
831 let span = p.span(start);
832 return if question_dot_token.is_some()
833 || match &obj {
834 Callee::Expr(obj) => unwrap_ts_non_null(obj).is_opt_chain(),
835 _ => false,
836 } {
837 match obj {
838 Callee::Super(_) | Callee::Import(_) => {
839 syntax_error!(p, p.input().cur_span(), SyntaxError::SuperCallOptional)
840 }
841 Callee::Expr(callee) => Ok((
842 OptChainExpr {
843 span,
844 optional: question_dot_token.is_some(),
845 base: Box::new(OptChainBase::Call(OptCall {
846 span: p.span(start),
847 callee,
848 args,
849 type_args,
850 ..Default::default()
851 })),
852 }
853 .into(),
854 true,
855 )),
856 }
857 } else {
858 Ok((
859 CallExpr {
860 span: p.span(start),
861 callee: obj,
862 args,
863 ..Default::default()
864 }
865 .into(),
866 true,
867 ))
868 };
869 }
870
871 if p.input_mut().eat(&P::Token::DOT) {
874 let prop = parse_maybe_private_name(p).map(|e| match e {
875 Either::Left(p) => MemberProp::PrivateName(p),
876 Either::Right(i) => MemberProp::Ident(i),
877 })?;
878 let span = p.span(obj.span_lo());
879 debug_assert_eq!(obj.span_lo(), span.lo());
880 debug_assert_eq!(prop.span_hi(), span.hi());
881
882 let type_args = if p.syntax().typescript() && p.input().is(&P::Token::LESS) {
883 try_parse_ts_type_args(p)
884 } else {
885 None
886 };
887
888 return Ok((
889 Box::new(match obj {
890 callee @ Callee::Import(_) => match prop {
891 MemberProp::Ident(IdentName { sym, .. }) => {
892 if !p.ctx().contains(Context::CanBeModule) {
893 let span = p.span(start);
894 p.emit_err(span, SyntaxError::ImportMetaInScript);
895 }
896 match &*sym {
897 "meta" => MetaPropExpr {
898 span,
899 kind: MetaPropKind::ImportMeta,
900 }
901 .into(),
902 _ => {
903 let args = parse_args(p, true)?;
904
905 CallExpr {
906 span,
907 callee,
908 args,
909 type_args: None,
910 ..Default::default()
911 }
912 .into()
913 }
914 }
915 }
916 _ => {
917 unexpected!(p, "meta");
918 }
919 },
920 Callee::Super(obj) => {
921 if !p.ctx().contains(Context::AllowDirectSuper)
922 && !p.input().syntax().allow_super_outside_method()
923 {
924 syntax_error!(p, obj.span, SyntaxError::InvalidSuper);
925 } else if question_dot_token.is_some() {
926 if no_call {
927 syntax_error!(p, obj.span, SyntaxError::InvalidSuperCall);
928 } else {
929 syntax_error!(p, obj.span, SyntaxError::InvalidSuper);
930 }
931 } else {
932 match prop {
933 MemberProp::Ident(ident) => SuperPropExpr {
934 span,
935 obj,
936 prop: SuperProp::Ident(ident),
937 }
938 .into(),
939 MemberProp::PrivateName(..) => {
940 syntax_error!(
941 p,
942 p.input().cur_span(),
943 SyntaxError::InvalidSuperCall
944 )
945 }
946 MemberProp::Computed(..) => unreachable!(),
947 }
948 }
949 }
950 Callee::Expr(obj) => {
951 let expr = MemberExpr { span, obj, prop };
952 let expr = if unwrap_ts_non_null(&expr.obj).is_opt_chain()
953 || question_dot_token.is_some()
954 {
955 OptChainExpr {
956 span: p.span(start),
957 optional: question_dot_token.is_some(),
958 base: Box::new(OptChainBase::Member(expr)),
959 }
960 .into()
961 } else {
962 expr.into()
963 };
964 if let Some(type_args) = type_args {
965 TsInstantiation {
966 expr: Box::new(expr),
967 type_args,
968 span: p.span(start),
969 }
970 .into()
971 } else {
972 expr
973 }
974 }
975 }),
976 true,
977 ));
978 }
979
980 match obj {
981 Callee::Expr(expr) => {
982 let expr = if let Some(type_args) = type_args {
983 TsInstantiation {
984 expr,
985 type_args,
986 span: p.span(start),
987 }
988 .into()
989 } else {
990 expr
991 };
992
993 let cur = p.input().cur();
995 if cur.is_template_head()
996 || cur.is_no_substitution_template_literal()
997 || cur.is_backquote()
998 {
999 let tpl = p.do_outside_of_context(Context::WillExpectColonForCond, |p| {
1000 p.parse_tagged_tpl(expr, None)
1001 })?;
1002 return Ok((tpl.into(), true));
1003 }
1004
1005 Ok((expr, false))
1006 }
1007 Callee::Super(..) => {
1008 if no_call {
1009 syntax_error!(p, p.input().cur_span(), SyntaxError::InvalidSuperCall);
1010 }
1011 syntax_error!(p, p.input().cur_span(), SyntaxError::InvalidSuper);
1012 }
1013 Callee::Import(..) => {
1014 syntax_error!(p, p.input().cur_span(), SyntaxError::InvalidImport);
1015 }
1016 }
1017}
1018
1019pub fn parse_dynamic_import_or_import_meta<'a, P: Parser<'a>>(
1020 p: &mut P,
1021 start: BytePos,
1022 no_call: bool,
1023) -> PResult<Box<Expr>> {
1024 if p.input_mut().eat(&P::Token::DOT) {
1025 p.mark_found_module_item();
1026
1027 let ident = parse_ident_name(p)?;
1028
1029 match &*ident.sym {
1030 "meta" => {
1031 let span = p.span(start);
1032 if !p.ctx().contains(Context::CanBeModule) {
1033 p.emit_err(span, SyntaxError::ImportMetaInScript);
1034 }
1035 let expr = MetaPropExpr {
1036 span,
1037 kind: MetaPropKind::ImportMeta,
1038 };
1039 parse_subscripts(p, Callee::Expr(expr.into()), no_call, false)
1040 }
1041 "defer" => parse_dynamic_import_call(p, start, no_call, ImportPhase::Defer),
1042 "source" => parse_dynamic_import_call(p, start, no_call, ImportPhase::Source),
1043 _ => unexpected!(p, "meta"),
1044 }
1045 } else {
1046 parse_dynamic_import_call(p, start, no_call, ImportPhase::Evaluation)
1047 }
1048}
1049
1050fn parse_dynamic_import_call<'a>(
1051 p: &mut impl Parser<'a>,
1052 start: BytePos,
1053 no_call: bool,
1054 phase: ImportPhase,
1055) -> PResult<Box<Expr>> {
1056 let import = Callee::Import(Import {
1057 span: p.span(start),
1058 phase,
1059 });
1060
1061 parse_subscripts(p, import, no_call, false)
1062}
1063
1064#[cfg_attr(
1066 feature = "tracing-spans",
1067 tracing::instrument(level = "debug", skip_all)
1068)]
1069pub fn parse_member_expr_or_new_expr<'a>(
1070 p: &mut impl Parser<'a>,
1071 is_new_expr: bool,
1072) -> PResult<Box<Expr>> {
1073 p.do_inside_of_context(Context::ShouldNotLexLtOrGtAsType, |p| {
1074 parse_member_expr_or_new_expr_inner(p, is_new_expr)
1075 })
1076}
1077
1078fn parse_member_expr_or_new_expr_inner<'a, P: Parser<'a>>(
1079 p: &mut P,
1080 is_new_expr: bool,
1081) -> PResult<Box<Expr>> {
1082 trace_cur!(p, parse_member_expr_or_new_expr);
1083
1084 let start = p.cur_pos();
1085 if p.input_mut().eat(&P::Token::NEW) {
1086 if p.input_mut().eat(&P::Token::DOT) {
1087 if p.input_mut().eat(&P::Token::TARGET) {
1088 let span = p.span(start);
1089 let expr = MetaPropExpr {
1090 span,
1091 kind: MetaPropKind::NewTarget,
1092 }
1093 .into();
1094
1095 let ctx = p.ctx();
1096 if !ctx.contains(Context::InsideNonArrowFunctionScope)
1097 && !ctx.contains(Context::InParameters)
1098 && !ctx.contains(Context::InClass)
1099 {
1100 p.emit_err(span, SyntaxError::InvalidNewTarget);
1101 }
1102
1103 return parse_subscripts(p, Callee::Expr(expr), true, false);
1104 }
1105
1106 unexpected!(p, "target")
1107 }
1108
1109 let callee = parse_member_expr_or_new_expr(p, is_new_expr)?;
1111 return_if_arrow!(p, callee);
1112
1113 if is_new_expr {
1114 match *callee {
1115 Expr::OptChain(OptChainExpr {
1116 span,
1117 optional: true,
1118 ..
1119 }) => {
1120 syntax_error!(p, span, SyntaxError::OptChainCannotFollowConstructorCall)
1121 }
1122 Expr::Member(MemberExpr { ref obj, .. }) => {
1123 if let Expr::OptChain(OptChainExpr {
1124 span,
1125 optional: true,
1126 ..
1127 }) = **obj
1128 {
1129 syntax_error!(p, span, SyntaxError::OptChainCannotFollowConstructorCall)
1130 }
1131 }
1132 _ => {}
1133 }
1134 }
1135
1136 let type_args = if p.input().syntax().typescript() && {
1137 let cur = p.input().cur();
1138 cur.is_less() || cur.is_lshift()
1139 } {
1140 try_parse_ts(p, |p| {
1141 let args =
1142 p.do_outside_of_context(Context::ShouldNotLexLtOrGtAsType, parse_ts_type_args)?;
1143 p.assert_and_bump(&P::Token::GREATER);
1144 if !p.input().is(&P::Token::LPAREN) {
1145 let span = p.input().cur_span();
1146 let cur = p.input_mut().dump_cur();
1147 syntax_error!(p, span, SyntaxError::Expected('('.to_string(), cur))
1148 }
1149 Ok(Some(args))
1150 })
1151 } else {
1152 None
1153 };
1154
1155 if !is_new_expr || p.input().is(&P::Token::LPAREN) {
1156 let args = parse_args(p, false).map(Some)?;
1158
1159 let new_expr = Callee::Expr(
1160 NewExpr {
1161 span: p.span(start),
1162 callee,
1163 args,
1164 type_args,
1165 ..Default::default()
1166 }
1167 .into(),
1168 );
1169
1170 return parse_subscripts(p, new_expr, true, false);
1173 }
1174
1175 return Ok(NewExpr {
1178 span: p.span(start),
1179 callee,
1180 args: None,
1181 type_args,
1182 ..Default::default()
1183 }
1184 .into());
1185 }
1186
1187 if p.input_mut().eat(&P::Token::SUPER) {
1188 let base = Callee::Super(Super {
1189 span: p.span(start),
1190 });
1191 return parse_subscripts(p, base, true, false);
1192 } else if p.input_mut().eat(&P::Token::IMPORT) {
1193 return parse_dynamic_import_or_import_meta(p, start, true);
1194 }
1195 let obj = p.parse_primary_expr()?;
1196 return_if_arrow!(p, obj);
1197
1198 let type_args = if p.syntax().typescript() && p.input().is(&P::Token::LESS) {
1199 try_parse_ts_type_args(p)
1200 } else {
1201 None
1202 };
1203 let obj = if let Some(type_args) = type_args {
1204 trace_cur!(p, parse_member_expr_or_new_expr__with_type_args);
1205 TsInstantiation {
1206 expr: obj,
1207 type_args,
1208 span: p.span(start),
1209 }
1210 .into()
1211 } else {
1212 obj
1213 };
1214
1215 parse_subscripts(p, Callee::Expr(obj), true, false)
1216}
1217
1218#[cfg_attr(feature = "tracing-spans", tracing::instrument(skip_all))]
1221pub fn parse_new_expr<'a>(p: &mut impl Parser<'a>) -> PResult<Box<Expr>> {
1222 trace_cur!(p, parse_new_expr);
1223 parse_member_expr_or_new_expr(p, true)
1224}
1225
1226pub fn parse_bin_expr<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<Expr>> {
1228 trace_cur!(p, parse_bin_expr);
1229
1230 let left = match p.parse_unary_expr() {
1231 Ok(v) => v,
1232 Err(err) => {
1233 trace_cur!(p, parse_bin_expr__recovery_unary_err);
1234
1235 let cur = p.input().cur();
1236 if cur.is_error() {
1237 let err = p.input_mut().expect_error_token_and_bump();
1238 return Err(err);
1239 } else if (cur.is_in() && p.ctx().contains(Context::IncludeInExpr))
1240 || cur.is_instanceof()
1241 || cur.is_bin_op()
1242 {
1243 p.emit_err(p.input().cur_span(), SyntaxError::TS1109);
1244 Invalid { span: err.span() }.into()
1245 } else {
1246 return Err(err);
1247 }
1248 }
1249 };
1250
1251 return_if_arrow!(p, left);
1252 parse_bin_op_recursively(p, left, 0)
1253}
1254
1255pub fn parse_bin_op_recursively<'a>(
1263 p: &mut impl Parser<'a>,
1264 mut left: Box<Expr>,
1265 mut min_prec: u8,
1266) -> PResult<Box<Expr>> {
1267 loop {
1268 let (next_left, next_prec) = parse_bin_op_recursively_inner(p, left, min_prec)?;
1269
1270 match &*next_left {
1271 Expr::Bin(BinExpr {
1272 span,
1273 left,
1274 op: op!("&&"),
1275 ..
1276 })
1277 | Expr::Bin(BinExpr {
1278 span,
1279 left,
1280 op: op!("||"),
1281 ..
1282 }) => {
1283 if let Expr::Bin(BinExpr { op: op!("??"), .. }) = &**left {
1284 p.emit_err(*span, SyntaxError::NullishCoalescingWithLogicalOp);
1285 }
1286 }
1287 _ => {}
1288 }
1289
1290 min_prec = match next_prec {
1291 Some(v) => v,
1292 None => return Ok(next_left),
1293 };
1294
1295 left = next_left;
1296 }
1297}
1298
1299fn parse_bin_op_recursively_inner<'a, P: Parser<'a>>(
1301 p: &mut P,
1302 left: Box<Expr>,
1303 min_prec: u8,
1304) -> PResult<(Box<Expr>, Option<u8>)> {
1305 const PREC_OF_IN: u8 = 7;
1306
1307 if p.input().syntax().typescript() && !p.input().had_line_break_before_cur() {
1308 if PREC_OF_IN > min_prec && p.input().is(&P::Token::AS) {
1309 let start = left.span_lo();
1310 let expr = left;
1311 let node = if peek!(p).is_some_and(|cur| cur.is_const()) {
1312 p.bump(); p.bump(); TsConstAssertion {
1315 span: p.span(start),
1316 expr,
1317 }
1318 .into()
1319 } else {
1320 let type_ann = next_then_parse_ts_type(p)?;
1321 TsAsExpr {
1322 span: p.span(start),
1323 expr,
1324 type_ann,
1325 }
1326 .into()
1327 };
1328
1329 return parse_bin_op_recursively_inner(p, node, min_prec);
1330 } else if p.input().is(&P::Token::SATISFIES) {
1331 let start = left.span_lo();
1332 let expr = left;
1333 let node = {
1334 let type_ann = next_then_parse_ts_type(p)?;
1335 TsSatisfiesExpr {
1336 span: p.span(start),
1337 expr,
1338 type_ann,
1339 }
1340 .into()
1341 };
1342
1343 return parse_bin_op_recursively_inner(p, node, min_prec);
1344 }
1345 }
1346
1347 let cur = p.input().cur();
1349 let op = if cur.is_in() && p.ctx().contains(Context::IncludeInExpr) {
1350 op!("in")
1351 } else if cur.is_instanceof() {
1352 op!("instanceof")
1353 } else if let Some(op) = cur.as_bin_op() {
1354 op
1355 } else {
1356 return Ok((left, None));
1357 };
1358
1359 if op.precedence() <= min_prec {
1360 if cfg!(feature = "debug") {
1361 tracing::trace!(
1362 "returning {:?} without parsing {:?} because min_prec={}, prec={}",
1363 left,
1364 op,
1365 min_prec,
1366 op.precedence()
1367 );
1368 }
1369
1370 return Ok((left, None));
1371 }
1372 p.bump();
1373 if cfg!(feature = "debug") {
1374 tracing::trace!(
1375 "parsing binary op {:?} min_prec={}, prec={}",
1376 op,
1377 min_prec,
1378 op.precedence()
1379 );
1380 }
1381 match *left {
1382 Expr::Unary { .. } | Expr::Await(..) if op == op!("**") => {
1384 syntax_error!(
1389 p,
1390 SyntaxError::UnaryInExp {
1391 left: format!("{left:?}"),
1393 left_span: left.span(),
1394 }
1395 )
1396 }
1397 _ => {}
1398 }
1399
1400 let right = {
1401 let left_of_right = p.parse_unary_expr()?;
1402 parse_bin_op_recursively(
1403 p,
1404 left_of_right,
1405 if op == op!("**") {
1406 op.precedence() - 1
1408 } else {
1409 op.precedence()
1410 },
1411 )?
1412 };
1413 if op == op!("??") {
1426 match *left {
1427 Expr::Bin(BinExpr { span, op, .. }) if op == op!("&&") || op == op!("||") => {
1428 p.emit_err(span, SyntaxError::NullishCoalescingWithLogicalOp);
1429 }
1430 _ => {}
1431 }
1432
1433 match *right {
1434 Expr::Bin(BinExpr { span, op, .. }) if op == op!("&&") || op == op!("||") => {
1435 p.emit_err(span, SyntaxError::NullishCoalescingWithLogicalOp);
1436 }
1437 _ => {}
1438 }
1439 }
1440
1441 let node = BinExpr {
1442 span: Span::new_with_checked(left.span_lo(), right.span_hi()),
1443 op,
1444 left,
1445 right,
1446 }
1447 .into();
1448
1449 Ok((node, Some(min_prec)))
1450}
1451
1452pub(crate) fn parse_unary_expr<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<Expr>> {
1456 trace_cur!(p, parse_unary_expr);
1457
1458 let token_and_span = p.input().get_cur();
1459 let start = token_and_span.span().lo;
1460 let cur = token_and_span.token();
1461
1462 if !p.input().syntax().jsx() && p.input().syntax().typescript() && cur.is_less() {
1463 p.bump(); if p.input_mut().eat(&P::Token::CONST) {
1465 expect!(p, &P::Token::GREATER);
1466 let expr = p.parse_unary_expr()?;
1467 return Ok(TsConstAssertion {
1468 span: p.span(start),
1469 expr,
1470 }
1471 .into());
1472 }
1473
1474 return parse_ts_type_assertion(p, start)
1475 .map(Expr::from)
1476 .map(Box::new);
1477 } else if cur.is_plus_plus() || cur.is_minus_minus() {
1478 let op = if cur.is_plus_plus() {
1480 op!("++")
1481 } else {
1482 op!("--")
1483 };
1484 p.bump();
1485
1486 let arg = p.parse_unary_expr()?;
1487 let span = Span::new_with_checked(start, arg.span_hi());
1488 p.check_assign_target(&arg, false);
1489
1490 return Ok(UpdateExpr {
1491 span,
1492 prefix: true,
1493 op,
1494 arg,
1495 }
1496 .into());
1497 } else if cur.is_delete()
1498 || cur.is_void()
1499 || cur.is_typeof()
1500 || cur.is_plus()
1501 || cur.is_minus()
1502 || cur.is_tilde()
1503 || cur.is_bang()
1504 {
1505 let op = if cur.is_delete() {
1507 op!("delete")
1508 } else if cur.is_void() {
1509 op!("void")
1510 } else if cur.is_typeof() {
1511 op!("typeof")
1512 } else if cur.is_plus() {
1513 op!(unary, "+")
1514 } else if cur.is_minus() {
1515 op!(unary, "-")
1516 } else if cur.is_tilde() {
1517 op!("~")
1518 } else {
1519 debug_assert!(cur.is_bang());
1520 op!("!")
1521 };
1522 p.bump();
1523 let arg_start = p.cur_pos() - BytePos(1);
1524 let arg = match p.parse_unary_expr() {
1525 Ok(expr) => expr,
1526 Err(err) => {
1527 p.emit_error(err);
1528 Invalid {
1529 span: Span::new_with_checked(arg_start, arg_start),
1530 }
1531 .into()
1532 }
1533 };
1534
1535 if op == op!("delete") {
1536 if let Expr::Ident(ref i) = *arg {
1537 p.emit_strict_mode_err(i.span, SyntaxError::TS1102)
1538 }
1539 }
1540
1541 return Ok(UnaryExpr {
1542 span: Span::new_with_checked(start, arg.span_hi()),
1543 op,
1544 arg,
1545 }
1546 .into());
1547 } else if cur.is_await() {
1548 return parse_await_expr(p, None);
1549 }
1550
1551 let expr = p.parse_lhs_expr()?;
1553 return_if_arrow!(p, expr);
1554
1555 if p.input().had_line_break_before_cur() {
1557 return Ok(expr);
1558 }
1559
1560 let cur = p.input().cur();
1561 if cur.is_plus_plus() || cur.is_minus_minus() {
1562 let op = if cur.is_plus_plus() {
1563 op!("++")
1564 } else {
1565 op!("--")
1566 };
1567 p.check_assign_target(&expr, false);
1568 p.bump();
1569
1570 return Ok(UpdateExpr {
1571 span: p.span(expr.span_lo()),
1572 prefix: false,
1573 op,
1574 arg: expr,
1575 }
1576 .into());
1577 }
1578 Ok(expr)
1579}
1580
1581pub fn parse_await_expr<'a, P: Parser<'a>>(
1582 p: &mut P,
1583 start_of_await_token: Option<BytePos>,
1584) -> PResult<Box<Expr>> {
1585 let start = start_of_await_token.unwrap_or_else(|| p.cur_pos());
1586
1587 if start_of_await_token.is_none() {
1588 p.assert_and_bump(&P::Token::AWAIT);
1589 }
1590
1591 let await_token = p.span(start);
1592
1593 if p.input().is(&P::Token::MUL) {
1594 syntax_error!(p, SyntaxError::AwaitStar);
1595 }
1596
1597 let ctx = p.ctx();
1598
1599 let span = p.span(start);
1600
1601 if !ctx.contains(Context::InAsync)
1602 && (p.is_general_semi() || {
1603 let cur = p.input().cur();
1604 cur.is_rparen() || cur.is_rbracket() || cur.is_comma()
1605 })
1606 {
1607 if ctx.contains(Context::Module) {
1608 p.emit_err(span, SyntaxError::InvalidIdentInAsync);
1609 }
1610
1611 return Ok(Ident::new_no_ctxt(atom!("await"), span).into());
1612 }
1613
1614 if start_of_await_token.is_none() && ctx.contains(Context::TopLevel) {
1616 p.mark_found_module_item();
1617 if !ctx.contains(Context::CanBeModule) {
1618 p.emit_err(await_token, SyntaxError::TopLevelAwaitInScript);
1619 }
1620 }
1621
1622 if ctx.contains(Context::InFunction) && !ctx.contains(Context::InAsync) {
1623 p.emit_err(await_token, SyntaxError::AwaitInFunction);
1624 }
1625
1626 if ctx.contains(Context::InParameters) && !ctx.contains(Context::InFunction) {
1627 p.emit_err(span, SyntaxError::AwaitParamInAsync);
1628 }
1629
1630 let arg = p.parse_unary_expr()?;
1631 Ok(AwaitExpr {
1632 span: p.span(start),
1633 arg,
1634 }
1635 .into())
1636}
1637
1638pub(super) fn parse_for_head_prefix<'a>(p: &mut impl Parser<'a>) -> PResult<Box<Expr>> {
1639 p.parse_expr()
1640}
1641
1642#[cfg_attr(
1644 feature = "tracing-spans",
1645 tracing::instrument(level = "debug", skip_all)
1646)]
1647pub fn parse_lhs_expr<'a, P: Parser<'a>, const PARSE_JSX: bool>(p: &mut P) -> PResult<Box<Expr>> {
1648 trace_cur!(p, parse_lhs_expr);
1649
1650 if PARSE_JSX && p.input().syntax().jsx() {
1652 fn into_expr(e: Either<JSXFragment, JSXElement>) -> Box<Expr> {
1653 match e {
1654 Either::Left(l) => l.into(),
1655 Either::Right(r) => r.into(),
1656 }
1657 }
1658 let token_and_span = p.input().get_cur();
1659 let cur = token_and_span.token();
1660 if cur.is_jsx_text() {
1661 return Ok(Box::new(Expr::Lit(Lit::JSXText(parse_jsx_text(p)))));
1662 } else if cur.is_jsx_tag_start() {
1663 return parse_jsx_element(p).map(into_expr);
1664 } else if cur.is_error() {
1665 let err = p.input_mut().expect_error_token_and_bump();
1666 return Err(err);
1667 }
1668
1669 if p.input().is(&P::Token::LESS) && !peek!(p).is_some_and(|peek| peek.is_bang()) {
1670 return parse_jsx_element(p).map(into_expr);
1677 }
1678 }
1679
1680 let token_and_span = p.input().get_cur();
1681 let start = token_and_span.span().lo;
1682 let cur = token_and_span.token();
1683
1684 if cur.is_super() {
1686 p.bump(); let obj = Callee::Super(Super {
1688 span: p.span(start),
1689 });
1690 return parse_subscripts(p, obj, false, false);
1691 } else if cur.is_import() {
1692 p.bump(); return parse_dynamic_import_or_import_meta(p, start, false);
1694 }
1695
1696 let callee = parse_new_expr(p)?;
1697 return_if_arrow!(p, callee);
1698
1699 let type_args = if p.input().syntax().typescript() && {
1700 let cur = p.input().cur();
1701 cur.is_less() || cur.is_lshift()
1702 } {
1703 try_parse_ts(p, |p| {
1704 let type_args = parse_ts_type_args(p)?;
1705 p.assert_and_bump(&P::Token::GREATER);
1706 if p.input().is(&P::Token::LPAREN) {
1707 Ok(Some(type_args))
1708 } else {
1709 Ok(None)
1710 }
1711 })
1712 } else {
1713 None
1714 };
1715
1716 if let Expr::New(ne @ NewExpr { args: None, .. }) = *callee {
1717 if type_args.is_some() {
1720 expect!(p, &P::Token::LPAREN);
1722 }
1723 debug_assert!(
1724 !p.input().cur().is_lparen(),
1725 "parse_new_expr() should eat paren if it exists"
1726 );
1727 return Ok(NewExpr { type_args, ..ne }.into());
1728 }
1729 if p.input().is(&P::Token::LPAREN) {
1733 let (callee, is_import) = match callee {
1736 _ if callee.is_ident_ref_to("import") => (
1737 Callee::Import(Import {
1738 span: callee.span(),
1739 phase: Default::default(),
1740 }),
1741 true,
1742 ),
1743 _ => (Callee::Expr(callee), false),
1744 };
1745 let args = parse_args(p, is_import)?;
1746
1747 let call_expr = match callee {
1748 Callee::Expr(e) if unwrap_ts_non_null(&e).is_opt_chain() => OptChainExpr {
1749 span: p.span(start),
1750 base: Box::new(OptChainBase::Call(OptCall {
1751 span: p.span(start),
1752 callee: e,
1753 args,
1754 type_args,
1755 ..Default::default()
1756 })),
1757 optional: false,
1758 }
1759 .into(),
1760 _ => CallExpr {
1761 span: p.span(start),
1762
1763 callee,
1764 args,
1765 type_args,
1766 ..Default::default()
1767 }
1768 .into(),
1769 };
1770
1771 return parse_subscripts(p, Callee::Expr(call_expr), false, false);
1772 }
1773 if type_args.is_some() {
1774 expect!(p, &P::Token::LPAREN);
1776 }
1777
1778 Ok(callee)
1781}
1782
1783#[cfg_attr(
1785 feature = "tracing-spans",
1786 tracing::instrument(level = "debug", skip_all)
1787)]
1788pub fn parse_args_or_pats<'a, P: Parser<'a>>(
1789 p: &mut P,
1790) -> PResult<(Vec<AssignTargetOrSpread>, Option<Span>)> {
1791 p.do_outside_of_context(Context::WillExpectColonForCond, parse_args_or_pats_inner)
1792}
1793
1794fn parse_args_or_pats_inner<'a, P: Parser<'a>>(
1795 p: &mut P,
1796) -> PResult<(Vec<AssignTargetOrSpread>, Option<Span>)> {
1797 trace_cur!(p, parse_args_or_pats);
1798
1799 expect!(p, &P::Token::LPAREN);
1800
1801 let mut items = Vec::new();
1802 let mut trailing_comma = None;
1803
1804 while !p.input().is(&P::Token::RPAREN) {
1807 let is_async = p.input().is(&P::Token::ASYNC)
1809 && peek!(p).is_some_and(|t| t.is_lparen() || t.is_word() || t.is_function());
1810
1811 let start = p.cur_pos();
1812 p.state_mut().potential_arrow_start = Some(start);
1813 let modifier_start = start;
1814
1815 let has_modifier = eat_any_ts_modifier(p)?;
1816 let pat_start = p.cur_pos();
1817
1818 let mut arg = {
1819 if p.input().syntax().typescript()
1820 && (p.is_ident_ref()
1821 || (p.input().is(&P::Token::DOTDOTDOT) && p.peek_is_ident_ref()))
1822 {
1823 let spread = if p.input_mut().eat(&P::Token::DOTDOTDOT) {
1824 Some(p.input().prev_span())
1825 } else {
1826 None
1827 };
1828
1829 let expr = if spread.is_some() {
1832 parse_bin_expr(p)?
1833 } else {
1834 let mut expr = parse_bin_expr(p)?;
1835
1836 if p.input().cur().is_assign_op() {
1837 expr = finish_assignment_expr(p, start, expr)?
1838 }
1839
1840 expr
1841 };
1842
1843 ExprOrSpread { spread, expr }
1844 } else {
1845 p.allow_in_expr(|p| p.parse_expr_or_spread())?
1846 }
1847 };
1848
1849 let optional = if p.input().syntax().typescript() {
1850 if p.input().is(&P::Token::QUESTION) {
1851 if peek!(p).is_some_and(|peek| {
1852 peek.is_comma() || peek.is_equal() || peek.is_rparen() || peek.is_colon()
1853 }) {
1854 p.assert_and_bump(&P::Token::QUESTION);
1855 if arg.spread.is_some() {
1856 p.emit_err(p.input().prev_span(), SyntaxError::TS1047);
1857 }
1858 match *arg.expr {
1859 Expr::Ident(..) => {}
1860 _ => {
1861 syntax_error!(p, arg.span(), SyntaxError::TsBindingPatCannotBeOptional)
1862 }
1863 }
1864 true
1865 } else if matches!(arg, ExprOrSpread { spread: None, .. }) {
1866 expect!(p, &P::Token::QUESTION);
1867 let test = arg.expr;
1868
1869 let cons = p.do_inside_of_context(
1870 Context::InCondExpr
1871 .union(Context::WillExpectColonForCond)
1872 .union(Context::IncludeInExpr),
1873 parse_assignment_expr,
1874 )?;
1875 expect!(p, &P::Token::COLON);
1876
1877 let alt = p.do_inside_of_context(Context::InCondExpr, |p| {
1878 p.do_outside_of_context(
1879 Context::WillExpectColonForCond,
1880 parse_assignment_expr,
1881 )
1882 })?;
1883
1884 arg = ExprOrSpread {
1885 spread: None,
1886 expr: CondExpr {
1887 span: Span::new_with_checked(start, alt.span_hi()),
1888 test,
1889 cons,
1890 alt,
1891 }
1892 .into(),
1893 };
1894
1895 false
1896 } else {
1897 false
1898 }
1899 } else {
1900 false
1901 }
1902 } else {
1903 false
1904 };
1905
1906 if optional || (p.input().syntax().typescript() && p.input().is(&P::Token::COLON)) {
1907 let mut pat = reparse_expr_as_pat(p, PatType::BindingPat, arg.expr)?;
1914 if optional {
1915 match pat {
1916 Pat::Ident(ref mut i) => i.optional = true,
1917 _ => unreachable!(),
1918 }
1919 }
1920 if let Some(span) = arg.spread {
1921 pat = RestPat {
1922 span: p.span(pat_start),
1923 dot3_token: span,
1924 arg: Box::new(pat),
1925 type_ann: None,
1926 }
1927 .into();
1928 }
1929 match pat {
1930 Pat::Ident(BindingIdent {
1931 id: Ident { ref mut span, .. },
1932 ref mut type_ann,
1933 ..
1934 })
1935 | Pat::Array(ArrayPat {
1936 ref mut type_ann,
1937 ref mut span,
1938 ..
1939 })
1940 | Pat::Object(ObjectPat {
1941 ref mut type_ann,
1942 ref mut span,
1943 ..
1944 })
1945 | Pat::Rest(RestPat {
1946 ref mut type_ann,
1947 ref mut span,
1948 ..
1949 }) => {
1950 let new_type_ann = try_parse_ts_type_ann(p)?;
1951 if new_type_ann.is_some() {
1952 *span = Span::new_with_checked(pat_start, p.input().prev_span().hi);
1953 }
1954 *type_ann = new_type_ann;
1955 }
1956 Pat::Expr(ref expr) => unreachable!("invalid pattern: Expr({:?})", expr),
1957 Pat::Assign(..) | Pat::Invalid(..) => {
1958 }
1965 }
1966
1967 if p.input_mut().eat(&P::Token::EQUAL) {
1968 let right = parse_assignment_expr(p)?;
1969 pat = AssignPat {
1970 span: p.span(pat_start),
1971 left: Box::new(pat),
1972 right,
1973 }
1974 .into();
1975 }
1976
1977 if has_modifier {
1978 p.emit_err(p.span(modifier_start), SyntaxError::TS2369);
1979 }
1980
1981 items.push(AssignTargetOrSpread::Pat(pat))
1982 } else {
1983 if has_modifier {
1984 p.emit_err(p.span(modifier_start), SyntaxError::TS2369);
1985 }
1986
1987 items.push(AssignTargetOrSpread::ExprOrSpread(arg));
1988 }
1989
1990 if p.input_mut().eat(&P::Token::ARROW) && {
1992 debug_assert_eq!(items.len(), 1);
1993 match items[0] {
1994 AssignTargetOrSpread::ExprOrSpread(ExprOrSpread { ref expr, .. })
1995 | AssignTargetOrSpread::Pat(Pat::Expr(ref expr)) => {
1996 matches!(**expr, Expr::Ident(..))
1997 }
1998 AssignTargetOrSpread::Pat(Pat::Ident(..)) => true,
1999 _ => false,
2000 }
2001 } {
2002 let params: Vec<Pat> = parse_paren_items_as_params(p, items.clone(), None)?;
2003
2004 let body: Box<BlockStmtOrExpr> = parse_fn_block_or_expr_body(
2005 p,
2006 false,
2007 false,
2008 true,
2009 params.is_simple_parameter_list(),
2010 )?;
2011 let span = p.span(start);
2012
2013 items.push(AssignTargetOrSpread::ExprOrSpread(ExprOrSpread {
2014 expr: Box::new(
2015 ArrowExpr {
2016 span,
2017 body,
2018 is_async,
2019 is_generator: false,
2020 params,
2021 ..Default::default()
2022 }
2023 .into(),
2024 ),
2025 spread: None,
2026 }));
2027 }
2028
2029 if !p.input().is(&P::Token::RPAREN) {
2030 expect!(p, &P::Token::COMMA);
2031 if p.input().is(&P::Token::RPAREN) {
2032 trailing_comma = Some(p.input().prev_span());
2033 }
2034 }
2035 }
2036
2037 expect!(p, &P::Token::RPAREN);
2038 Ok((items, trailing_comma))
2039}
2040
2041#[cfg_attr(
2042 feature = "tracing-spans",
2043 tracing::instrument(level = "debug", skip_all)
2044)]
2045pub fn parse_paren_expr_or_arrow_fn<'a, P: Parser<'a>>(
2046 p: &mut P,
2047 can_be_arrow: bool,
2048 async_span: Option<Span>,
2049) -> PResult<Box<Expr>> {
2050 trace_cur!(p, parse_paren_expr_or_arrow_fn);
2051
2052 let expr_start = async_span.map(|x| x.lo()).unwrap_or_else(|| p.cur_pos());
2053
2054 let (paren_items, trailing_comma) = p
2060 .do_outside_of_context(Context::WillExpectColonForCond, |p| {
2061 p.allow_in_expr(parse_args_or_pats)
2062 })?;
2063
2064 let has_pattern = paren_items
2065 .iter()
2066 .any(|item| matches!(item, AssignTargetOrSpread::Pat(..)));
2067
2068 let will_expect_colon_for_cond = p.ctx().contains(Context::WillExpectColonForCond);
2069 if p.syntax().typescript()
2071 && p.ctx().contains(Context::InCondExpr)
2072 && p.input().is(&P::Token::COLON)
2073 {
2074 let items_ref = &paren_items;
2076 if let Some(expr) = try_parse_ts(p, |p| {
2077 let return_type = parse_ts_type_or_type_predicate_ann(p, &P::Token::COLON)?;
2078
2079 expect!(p, &P::Token::ARROW);
2080
2081 let params: Vec<Pat> =
2082 parse_paren_items_as_params(p, items_ref.clone(), trailing_comma)?;
2083
2084 let body: Box<BlockStmtOrExpr> = parse_fn_block_or_expr_body(
2085 p,
2086 async_span.is_some(),
2087 false,
2088 true,
2089 params.is_simple_parameter_list(),
2090 )?;
2091
2092 if will_expect_colon_for_cond && !p.input().is(&P::Token::COLON) {
2093 trace_cur!(p, parse_arrow_in_cond__fail);
2094 unexpected!(p, "fail")
2095 }
2096
2097 Ok(Some(
2098 ArrowExpr {
2099 span: p.span(expr_start),
2100 is_async: async_span.is_some(),
2101 is_generator: false,
2102 params,
2103 body,
2104 return_type: Some(return_type),
2105 ..Default::default()
2106 }
2107 .into(),
2108 ))
2109 }) {
2110 return Ok(expr);
2111 }
2112 }
2113
2114 let return_type = if !p.ctx().contains(Context::WillExpectColonForCond)
2115 && p.input().syntax().typescript()
2116 && p.input().is(&P::Token::COLON)
2117 {
2118 try_parse_ts(p, |p| {
2119 let return_type = parse_ts_type_or_type_predicate_ann(p, &P::Token::COLON)?;
2120
2121 if !p.input().is(&P::Token::ARROW) {
2122 unexpected!(p, "fail")
2123 }
2124
2125 Ok(Some(return_type))
2126 })
2127 } else {
2128 None
2129 };
2130
2131 if has_pattern || return_type.is_some() || p.input().is(&P::Token::ARROW) {
2133 if p.input().had_line_break_before_cur() {
2134 syntax_error!(p, p.span(expr_start), SyntaxError::LineBreakBeforeArrow);
2135 }
2136
2137 if !can_be_arrow {
2138 syntax_error!(p, p.span(expr_start), SyntaxError::ArrowNotAllowed);
2139 }
2140 expect!(p, &P::Token::ARROW);
2141
2142 let params: Vec<Pat> = parse_paren_items_as_params(p, paren_items, trailing_comma)?;
2143
2144 let body: Box<BlockStmtOrExpr> = parse_fn_block_or_expr_body(
2145 p,
2146 async_span.is_some(),
2147 false,
2148 true,
2149 params.is_simple_parameter_list(),
2150 )?;
2151 let arrow_expr = ArrowExpr {
2152 span: p.span(expr_start),
2153 is_async: async_span.is_some(),
2154 is_generator: false,
2155 params,
2156 body,
2157 return_type,
2158 ..Default::default()
2159 };
2160 if let BlockStmtOrExpr::BlockStmt(..) = &*arrow_expr.body {
2161 if p.input().cur().is_bin_op() {
2162 p.emit_err(p.input().cur_span(), SyntaxError::TS1005);
2164 let errorred_expr = parse_bin_op_recursively(p, Box::new(arrow_expr.into()), 0)?;
2165
2166 if !p.is_general_semi() {
2167 p.emit_err(p.input().cur_span(), SyntaxError::TS1005);
2169 }
2170
2171 return Ok(errorred_expr);
2172 }
2173 }
2174 return Ok(arrow_expr.into());
2175 } else {
2176 for expr_or_spread in paren_items.iter() {
2180 if let AssignTargetOrSpread::ExprOrSpread(e) = expr_or_spread {
2181 if let Expr::Object(o) = &*e.expr {
2182 for prop in o.props.iter() {
2183 if let PropOrSpread::Prop(prop) = prop {
2184 if let Prop::Assign(..) = **prop {
2185 p.emit_err(prop.span(), SyntaxError::AssignProperty);
2186 }
2187 }
2188 }
2189 }
2190 }
2191 }
2192 }
2193
2194 let expr_or_spreads = paren_items
2195 .into_iter()
2196 .map(|item| -> PResult<_> {
2197 match item {
2198 AssignTargetOrSpread::ExprOrSpread(e) => Ok(e),
2199 _ => syntax_error!(p, item.span(), SyntaxError::InvalidExpr),
2200 }
2201 })
2202 .collect::<Result<Vec<_>, _>>()?;
2203 if let Some(async_span) = async_span {
2204 return Ok(CallExpr {
2206 span: p.span(async_span.lo()),
2207 callee: Callee::Expr(Box::new(
2208 Ident::new_no_ctxt(atom!("async"), async_span).into(),
2209 )),
2210 args: expr_or_spreads,
2211 ..Default::default()
2212 }
2213 .into());
2214 }
2215
2216 if expr_or_spreads.is_empty() {
2219 syntax_error!(
2220 p,
2221 Span::new_with_checked(expr_start, p.last_pos()),
2222 SyntaxError::EmptyParenExpr
2223 );
2224 }
2225
2226 if expr_or_spreads.len() == 1 {
2230 let expr = match expr_or_spreads.into_iter().next().unwrap() {
2231 ExprOrSpread {
2232 spread: Some(..),
2233 ref expr,
2234 } => syntax_error!(p, expr.span(), SyntaxError::SpreadInParenExpr),
2235 ExprOrSpread { expr, .. } => expr,
2236 };
2237 Ok(ParenExpr {
2238 span: p.span(expr_start),
2239 expr,
2240 }
2241 .into())
2242 } else {
2243 debug_assert!(expr_or_spreads.len() >= 2);
2244
2245 let mut exprs = Vec::with_capacity(expr_or_spreads.len());
2246 for expr in expr_or_spreads {
2247 match expr {
2248 ExprOrSpread {
2249 spread: Some(..),
2250 ref expr,
2251 } => syntax_error!(p, expr.span(), SyntaxError::SpreadInParenExpr),
2252 ExprOrSpread { expr, .. } => exprs.push(expr),
2253 }
2254 }
2255 debug_assert!(exprs.len() >= 2);
2256
2257 let seq_expr = SeqExpr {
2259 span: Span::new_with_checked(
2260 exprs.first().unwrap().span_lo(),
2261 exprs.last().unwrap().span_hi(),
2262 ),
2263 exprs,
2264 }
2265 .into();
2266 Ok(ParenExpr {
2267 span: p.span(expr_start),
2268 expr: seq_expr,
2269 }
2270 .into())
2271 }
2272}
2273
2274pub fn parse_primary_expr_rest<'a, P: Parser<'a>>(
2275 p: &mut P,
2276 start: BytePos,
2277 can_be_arrow: bool,
2278) -> PResult<Box<Expr>> {
2279 let decorators = if p.input().is(&P::Token::AT) {
2280 Some(parse_decorators(p, false)?)
2281 } else {
2282 None
2283 };
2284
2285 let token_and_span = p.input().get_cur();
2286 let cur = token_and_span.token();
2287
2288 if cur.is_class() {
2289 return parse_class_expr(p, start, decorators.unwrap_or_default());
2290 }
2291
2292 let try_parse_arrow_expr = |p: &mut P, id: Ident, id_is_async| -> PResult<Box<Expr>> {
2293 if can_be_arrow && !p.input().had_line_break_before_cur() {
2294 if id_is_async && p.is_ident_ref() {
2295 let ctx = p.ctx();
2302 if ctx.contains(Context::ForLoopInit)
2303 && p.input().is(&P::Token::OF)
2304 && !peek!(p).is_some_and(|peek| peek.is_arrow())
2305 {
2306 if !ctx.contains(Context::ForAwaitLoopInit) {
2312 p.emit_err(p.input().prev_span(), SyntaxError::TS1106);
2313 }
2314
2315 return Ok(id.into());
2316 }
2317
2318 let ident = parse_binding_ident(p, false)?;
2319 if p.input().syntax().typescript()
2320 && ident.sym == "as"
2321 && !p.input().is(&P::Token::ARROW)
2322 {
2323 let type_ann = p.in_type(parse_ts_type)?;
2325 return Ok(TsAsExpr {
2326 span: p.span(start),
2327 expr: Box::new(id.into()),
2328 type_ann,
2329 }
2330 .into());
2331 }
2332
2333 let arg = ident.into();
2335 let params = vec![arg];
2336 expect!(p, &P::Token::ARROW);
2337 let body = parse_fn_block_or_expr_body(
2338 p,
2339 true,
2340 false,
2341 true,
2342 params.is_simple_parameter_list(),
2343 )?;
2344
2345 return Ok(ArrowExpr {
2346 span: p.span(start),
2347 body,
2348 params,
2349 is_async: true,
2350 is_generator: false,
2351 ..Default::default()
2352 }
2353 .into());
2354 } else if p.input_mut().eat(&P::Token::ARROW) {
2355 if p.ctx().contains(Context::Strict) && id.is_reserved_in_strict_bind() {
2356 p.emit_strict_mode_err(id.span, SyntaxError::EvalAndArgumentsInStrict)
2357 }
2358 let params = vec![id.into()];
2359 let body = parse_fn_block_or_expr_body(
2360 p,
2361 false,
2362 false,
2363 true,
2364 params.is_simple_parameter_list(),
2365 )?;
2366
2367 return Ok(ArrowExpr {
2368 span: p.span(start),
2369 body,
2370 params,
2371 is_async: false,
2372 is_generator: false,
2373 ..Default::default()
2374 }
2375 .into());
2376 }
2377 }
2378
2379 Ok(id.into())
2380 };
2381
2382 let token_start = token_and_span.span().lo;
2383 if cur.is_let() || (p.input().syntax().typescript() && cur.is_await()) {
2384 let ctx = p.ctx();
2385 let id = parse_ident(
2386 p,
2387 !ctx.contains(Context::InGenerator),
2388 !ctx.contains(Context::InAsync),
2389 )?;
2390 try_parse_arrow_expr(p, id, false)
2391 } else if cur.is_hash() {
2392 p.bump(); let id = parse_ident_name(p)?;
2394 Ok(PrivateName {
2395 span: p.span(start),
2396 name: id.sym,
2397 }
2398 .into())
2399 } else if cur.is_unknown_ident() {
2400 let word = p.input_mut().expect_word_token_and_bump();
2401 if p.ctx().contains(Context::InClassField) && word == atom!("arguments") {
2402 p.emit_err(p.input().prev_span(), SyntaxError::ArgumentsInClassField)
2403 };
2404 let id = Ident::new_no_ctxt(word, p.span(token_start));
2405 try_parse_arrow_expr(p, id, false)
2406 } else if p.is_ident_ref() {
2407 let id_is_async = p.input().cur().is_async();
2408 let word = p.input_mut().expect_word_token_and_bump();
2409 let id = Ident::new_no_ctxt(word, p.span(token_start));
2410 try_parse_arrow_expr(p, id, id_is_async)
2411 } else {
2412 syntax_error!(p, p.input().cur_span(), SyntaxError::TS1109)
2413 }
2414}
2415
2416pub fn try_parse_regexp<'a, P: Parser<'a>>(p: &mut P, start: BytePos) -> Option<Box<Expr>> {
2417 debug_assert!(p.input().cur().is_slash() || p.input().cur().is_slash_eq());
2419
2420 p.input_mut().set_next_regexp(Some(start));
2421
2422 p.bump(); let cur = p.input().cur();
2425 if cur.is_regexp() {
2426 p.input_mut().set_next_regexp(None);
2427 let (exp, flags) = p.input_mut().expect_regex_token_and_bump();
2428 let span = p.span(start);
2429
2430 let mut flags_count =
2431 flags
2432 .chars()
2433 .fold(FxHashMap::<char, usize>::default(), |mut map, flag| {
2434 let key = match flag {
2435 'd' | 'g' | 'i' | 'm' | 's' | 'u' | 'v' | 'y' => flag,
2437 _ => '\u{0000}', };
2439 map.entry(key).and_modify(|count| *count += 1).or_insert(1);
2440 map
2441 });
2442
2443 if flags_count.remove(&'\u{0000}').is_some() {
2444 p.emit_err(span, SyntaxError::UnknownRegExpFlags);
2445 }
2446
2447 if let Some((flag, _)) = flags_count.iter().find(|(_, count)| **count > 1) {
2448 p.emit_err(span, SyntaxError::DuplicatedRegExpFlags(*flag));
2449 }
2450
2451 Some(Lit::Regex(Regex { span, exp, flags }).into())
2452 } else {
2453 None
2454 }
2455}
2456
2457pub fn try_parse_async_start<'a, P: Parser<'a>>(
2458 p: &mut P,
2459 can_be_arrow: bool,
2460) -> Option<PResult<Box<Expr>>> {
2461 if peek!(p).is_some_and(|peek| peek.is_function())
2462 && !p.input_mut().has_linebreak_between_cur_and_peeked()
2463 {
2464 return Some(parse_async_fn_expr(p));
2466 }
2467
2468 if can_be_arrow
2469 && p.input().syntax().typescript()
2470 && peek!(p).is_some_and(|peek| peek.is_less())
2471 {
2472 if let Some(res) = try_parse_ts(p, |p| {
2474 let start = p.cur_pos();
2475 p.assert_and_bump(&P::Token::ASYNC);
2476 try_parse_ts_generic_async_arrow_fn(p, start)
2477 }) {
2478 return Some(Ok(res.into()));
2479 }
2480 }
2481
2482 if can_be_arrow
2483 && peek!(p).is_some_and(|peek| peek.is_lparen())
2484 && !p.input_mut().has_linebreak_between_cur_and_peeked()
2485 {
2486 if let Err(e) = p.expect(&P::Token::ASYNC) {
2487 return Some(Err(e));
2488 }
2489 let async_span = p.input().prev_span();
2490 return Some(parse_paren_expr_or_arrow_fn(
2491 p,
2492 can_be_arrow,
2493 Some(async_span),
2494 ));
2495 }
2496
2497 None
2498}
2499
2500pub fn parse_this_expr<'a>(p: &mut impl Parser<'a>, start: BytePos) -> PResult<Box<Expr>> {
2501 debug_assert!(p.input().cur().is_this());
2502 p.input_mut().bump();
2503 Ok(ThisExpr {
2504 span: p.span(start),
2505 }
2506 .into())
2507}
2508
2509#[cfg_attr(
2511 feature = "tracing-spans",
2512 tracing::instrument(level = "debug", skip_all)
2513)]
2514pub(crate) fn parse_primary_expr<'a, P: Parser<'a>>(p: &mut P) -> PResult<Box<Expr>> {
2515 trace_cur!(p, parse_primary_expr);
2516
2517 let start = p.cur_pos();
2518
2519 let can_be_arrow = p
2520 .state_mut()
2521 .potential_arrow_start
2522 .map(|s| s == start)
2523 .unwrap_or(false);
2524
2525 let token = p.input().cur();
2526 if token.is_this() {
2527 return parse_this_expr(p, start);
2528 } else if token.is_async() {
2529 if let Some(res) = try_parse_async_start(p, can_be_arrow) {
2530 return res;
2531 }
2532 } else if token.is_lbracket() {
2533 return p.do_outside_of_context(Context::WillExpectColonForCond, parse_array_lit);
2534 } else if token.is_lbrace() {
2535 return parse_object_expr(p).map(Box::new);
2536 } else if token.is_function() {
2537 return parse_fn_expr(p);
2538 } else if token.is_null()
2539 || token.is_true()
2540 || token.is_false()
2541 || token.is_num()
2542 || token.is_bigint()
2543 || token.is_str()
2544 {
2545 return Ok(parse_lit(p)?.into());
2547 } else if token.is_slash() || token.is_slash_eq() {
2548 if let Some(res) = try_parse_regexp(p, start) {
2549 return Ok(res);
2550 }
2551 } else if token.is_lparen() {
2552 return parse_paren_expr_or_arrow_fn(p, can_be_arrow, None);
2553 } else if token.is_backquote() {
2554 return Ok((p
2556 .do_outside_of_context(Context::WillExpectColonForCond, |p| parse_tpl(p, false)))?
2557 .into());
2558 }
2559
2560 parse_primary_expr_rest(p, start, can_be_arrow)
2561}