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