swc_ecma_lexer/common/parser/
expr.rs

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    // TODO(kdy1): !this.state.containsEsc &&
102    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    // Spec says
111    // YieldExpression cannot be used within the FormalParameters of a generator
112    // function because any expressions that are part of FormalParameters are
113    // evaluated before the resulting generator object is in a resumable state.
114    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/// Parse `Arguments[Yield, Await]`
278#[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                // Handle trailing comma.
298                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///`parseMaybeAssign` (overridden)
316#[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        // Note: When the JSX plugin is on, type assertions (`<T> x`) aren't valid
325        // syntax.
326
327        let cur_context = p.input().token_context().current();
328        debug_assert_eq!(cur_context, Some(TokenContext::JSXOpeningTag));
329        // Only time j_oTag is pushed is right after j_expr.
330        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/// Parse an assignment expression. This includes applications of
356/// operators like `+=`.
357///
358/// `parseMaybeAssign`
359#[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    // Try to parse conditional expression.
429    let cond = parse_cond_expr(p)?;
430
431    return_if_arrow!(p, cond);
432
433    match *cond {
434        // if cond is conditional expression but not left-hand-side expression,
435        // just return it.
436        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            // It is an early Reference Error if IsValidSimpleAssignmentTarget of
460            // LeftHandSideExpression is false.
461            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            // TODO
478            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            // TODO:
492            left,
493            right,
494        }
495        .into())
496    } else {
497        Ok(cond)
498    }
499}
500
501/// Spec: 'ConditionalExpression'
502#[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/// returned bool is true if this method should be called again.
558#[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            // tsTryParseAndCatch is expensive, so avoid if not necessary.
605            // There are number of things we are going to "maybe" parse, like type arguments
606            // on tagged template expressions. If any of them fail, walk it back and
607            // continue.
608
609            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                        // Almost certainly this is a generic async function `async <T>() => ...
623                        // But it might be a call with a type argument `async<T>();`
624                        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                        // possibleAsync always false here, because we would have handled it
636                        // above. (won't be any undefined arguments)
637                        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    // $obj[name()]
735    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    // member expression
872    // $obj.name
873    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            // MemberExpression[?Yield, ?Await] TemplateLiteral[?Yield, ?Await, +Tagged]
994            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/// `is_new_expr`: true iff we are parsing production 'NewExpression'.
1065#[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        // 'NewExpression' allows new call without paren.
1110        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            // Parsed with 'MemberExpression' production.
1157            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            // We should parse subscripts for MemberExpression.
1171            // Because it's left recursive.
1172            return parse_subscripts(p, new_expr, true, false);
1173        }
1174
1175        // Parsed with 'NewExpression' production.
1176
1177        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/// Parse `NewExpression`.
1219/// This includes `MemberExpression`.
1220#[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
1226/// Name from spec: 'LogicalORExpression'
1227pub 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
1255/// Parse binary operators with the operator precedence parsing
1256/// algorithm. `left` is the left-hand side of the operator.
1257/// `minPrec` provides context that allows the function to stop and
1258/// defer further parser to one of its callers when it encounters an
1259/// operator that has a lower precedence than the set it is parsing.
1260///
1261/// `parseExprOp`
1262pub 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
1299/// Returns `(left, Some(next_prec))` or `(expr, None)`.
1300fn 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(); // as
1313                p.bump(); // const
1314                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    // Return left on eof
1348    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        // This is invalid syntax.
1383        Expr::Unary { .. } | Expr::Await(..) if op == op!("**") => {
1384            // Correct implementation would be returning Ok(left) and
1385            // returning "unexpected token '**'" on next.
1386            // But it's not useful error message.
1387
1388            syntax_error!(
1389                p,
1390                SyntaxError::UnaryInExp {
1391                    // FIXME: Use display
1392                    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                // exponential operator is right associative
1407                op.precedence() - 1
1408            } else {
1409                op.precedence()
1410            },
1411        )?
1412    };
1413    /* this check is for all ?? operators
1414     * a ?? b && c for this example
1415     * b && c => This is considered as a logical expression in the ast tree
1416     * a => Identifier
1417     * so for ?? operator we need to check in this case the right expression to
1418     * have parenthesis second case a && b ?? c
1419     * here a && b => This is considered as a logical expression in the ast tree
1420     * c => identifier
1421     * so now here for ?? operator we need to check the left expression to have
1422     * parenthesis if the parenthesis is missing we raise an error and
1423     * throw it
1424     */
1425    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
1452/// Parse unary expression and update expression.
1453///
1454/// spec: 'UnaryExpression'
1455pub(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(); // consume `<`
1464        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        // Parse update expression
1479        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        // Parse unary expression
1506        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    // UpdateExpression
1552    let expr = p.parse_lhs_expr()?;
1553    return_if_arrow!(p, expr);
1554
1555    // Line terminator isn't allowed here.
1556    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    // This has been checked if start_of_await_token == true,
1615    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/// Parse call, dot, and `[]`-subscript expressions.
1643#[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    // parse jsx
1651    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            // In case we encounter an lt token here it will always be the start of
1671            // jsx as the lt sign is not allowed in places that expect an expression
1672
1673            // FIXME:
1674            // p.finishToken(tt.jsxTagStart);
1675
1676            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    // `super()` can't be handled from parse_new_expr()
1685    if cur.is_super() {
1686        p.bump(); // eat `super`
1687        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(); // eat `import`
1693        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 this is parsed using 'NewExpression' rule, just return it.
1718        // Because it's not left-recursive.
1719        if type_args.is_some() {
1720            // This fails with `expected (`
1721            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    // 'CallExpr' rule contains 'MemberExpr (...)',
1730    // and 'MemberExpr' rule contains 'new MemberExpr (...)'
1731
1732    if p.input().is(&P::Token::LPAREN) {
1733        // This is parsed using production MemberExpression,
1734        // which is left-recursive.
1735        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        // This fails
1775        expect!(p, &P::Token::LPAREN);
1776    }
1777
1778    // This is parsed using production 'NewExpression', which contains
1779    // 'MemberExpression'
1780    Ok(callee)
1781}
1782
1783// Returns (args_or_pats, trailing_comma)
1784#[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    // TODO(kdy1): optimize (once we parsed a pattern, we can parse everything else
1805    // as a pattern instead of reparsing)
1806    while !p.input().is(&P::Token::RPAREN) {
1807        // https://github.com/swc-project/swc/issues/410
1808        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                // At here, we use parse_bin_expr() instead of parse_assignment_expr()
1830                // because `x?: number` should not be parsed as a conditional expression
1831                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            // TODO: `async(...args?: any[]) : any => {}`
1908            //
1909            // if p.input().syntax().typescript() && optional && arg.spread.is_some() {
1910            //     p.emit_err(p.input().prev_span(), SyntaxError::TS1047)
1911            // }
1912
1913            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                    // We don't have to panic here.
1959                    // See: https://github.com/swc-project/swc/issues/1170
1960                    //
1961                    // Also, as an exact error is added to the errors while
1962                    // creating `Invalid`, we don't have to emit a new
1963                    // error.
1964                }
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        // https://github.com/swc-project/swc/issues/433
1991        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    // At this point, we can't know if it's parenthesized
2055    // expression or head of arrow function.
2056    // But as all patterns of javascript is subset of
2057    // expressions, we can parse both as expression.
2058
2059    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    // This is slow path. We handle arrow in conditional expression.
2070    if p.syntax().typescript()
2071        && p.ctx().contains(Context::InCondExpr)
2072        && p.input().is(&P::Token::COLON)
2073    {
2074        // TODO: Remove clone
2075        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    // we parse arrow function at here, to handle it efficiently.
2132    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                // ) is required
2163                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                    // ; is required
2168                    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        // If there's no arrow function, we have to check there's no
2177        // AssignProp in lhs to check against assignment in object literals
2178        // like (a, {b = 1});
2179        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        // It's a call expression
2205        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    // It was not head of arrow function.
2217
2218    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    // TODO: Verify that invalid expression like {a = 1} does not exists.
2227
2228    // ParenthesizedExpression cannot contain spread.
2229    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        // span of sequence expression should not include '(', ')'
2258        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                // see https://github.com/tc39/ecma262/issues/2034
2296                // ```js
2297                // for(async of
2298                // for(async of x);
2299                // for(async of =>{};;);
2300                // ```
2301                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                    // ```spec https://tc39.es/ecma262/#prod-ForInOfStatement
2307                    // for ( [lookahead ∉ { let, async of }] LeftHandSideExpression[?Yield, ?Await] of AssignmentExpression[+In, ?Yield, ?Await] ) Statement[?Yield, ?Await, ?Return]
2308                    // [+Await] for await ( [lookahead ≠ let] LeftHandSideExpression[?Yield, ?Await] of AssignmentExpression[+In, ?Yield, ?Await] ) Statement[?Yield, ?Await, ?Return]
2309                    // ```
2310
2311                    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                    // async as type
2324                    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                // async a => body
2334                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(); // consume `#`
2393        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    // Regexp
2418    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(); // `/` or `/=`
2423
2424    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                        // https://tc39.es/ecma262/#sec-isvalidregularexpressionliteral
2436                        'd' | 'g' | 'i' | 'm' | 's' | 'u' | 'v' | 'y' => flag,
2437                        _ => '\u{0000}', // special marker for unknown flags
2438                    };
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        // handle `async function` expression
2465        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        // try parsing `async<T>() => {}`
2473        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/// Parse a primary expression or arrow function
2510#[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        // Literals
2546        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        // parse template literal
2555        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}