swc_ecma_lexer/common/parser/
stmt.rs

1use swc_common::{BytePos, Span, Spanned};
2use swc_ecma_ast::*;
3
4use super::{
5    buffer::Buffer,
6    class_and_fn::parse_fn_decl,
7    expr::parse_assignment_expr,
8    is_directive::IsDirective,
9    pat::parse_binding_pat_or_ident,
10    typescript::{try_parse_ts_type_ann, ts_look_ahead},
11    PResult, Parser,
12};
13use crate::{
14    common::{
15        context::Context,
16        lexer::token::TokenFactory,
17        parser::{
18            class_and_fn::{parse_async_fn_decl, parse_class_decl, parse_decorators},
19            eof_error,
20            expr::{parse_await_expr, parse_bin_op_recursively, parse_for_head_prefix},
21            ident::{parse_binding_ident, parse_label_ident},
22            pat::reparse_expr_as_pat,
23            pat_type::PatType,
24            typescript::{
25                parse_ts_enum_decl, parse_ts_expr_stmt, parse_ts_interface_decl, parse_ts_type,
26                parse_ts_type_alias_decl,
27            },
28            TokenAndSpan,
29        },
30    },
31    error::{Error, SyntaxError},
32};
33
34#[allow(clippy::enum_variant_names)]
35pub enum TempForHead {
36    For {
37        init: Option<VarDeclOrExpr>,
38        test: Option<Box<Expr>>,
39        update: Option<Box<Expr>>,
40    },
41    ForIn {
42        left: ForHead,
43        right: Box<Expr>,
44    },
45    ForOf {
46        left: ForHead,
47        right: Box<Expr>,
48    },
49}
50
51fn parse_normal_for_head<'a, P: Parser<'a>>(
52    p: &mut P,
53    init: Option<VarDeclOrExpr>,
54) -> PResult<TempForHead> {
55    let test = if p.input_mut().eat(&P::Token::SEMI) {
56        None
57    } else {
58        let test = p.allow_in_expr(|p| p.parse_expr()).map(Some)?;
59        p.input_mut().eat(&P::Token::SEMI);
60        test
61    };
62
63    let update = if p.input().is(&P::Token::RPAREN) {
64        None
65    } else {
66        p.allow_in_expr(|p| p.parse_expr()).map(Some)?
67    };
68
69    Ok(TempForHead::For { init, test, update })
70}
71
72fn parse_for_each_head<'a, P: Parser<'a>>(p: &mut P, left: ForHead) -> PResult<TempForHead> {
73    let is_of = p.input().cur().is_of();
74    p.bump();
75    if is_of {
76        let right = p.allow_in_expr(parse_assignment_expr)?;
77        Ok(TempForHead::ForOf { left, right })
78    } else {
79        if let ForHead::UsingDecl(d) = &left {
80            p.emit_err(d.span, SyntaxError::UsingDeclNotAllowedForForInLoop)
81        }
82        let right = p.allow_in_expr(|p| p.parse_expr())?;
83        Ok(TempForHead::ForIn { left, right })
84    }
85}
86
87pub fn parse_return_stmt<'a, P: Parser<'a>>(p: &mut P) -> PResult<Stmt> {
88    let start = p.cur_pos();
89
90    p.assert_and_bump(&P::Token::RETURN);
91
92    let arg = if p.is_general_semi() {
93        None
94    } else {
95        p.allow_in_expr(|p| p.parse_expr()).map(Some)?
96    };
97    p.expect_general_semi()?;
98    let stmt = Ok(ReturnStmt {
99        span: p.span(start),
100        arg,
101    }
102    .into());
103
104    if !p.ctx().contains(Context::InFunction) && !p.input().syntax().allow_return_outside_function()
105    {
106        p.emit_err(p.span(start), SyntaxError::ReturnNotAllowed);
107    }
108
109    stmt
110}
111
112fn parse_var_declarator<'a, P: Parser<'a>>(
113    p: &mut P,
114    for_loop: bool,
115    kind: VarDeclKind,
116) -> PResult<VarDeclarator> {
117    let start = p.cur_pos();
118
119    let is_let_or_const = matches!(kind, VarDeclKind::Let | VarDeclKind::Const);
120
121    let mut name = parse_binding_pat_or_ident(p, is_let_or_const)?;
122
123    let definite = if p.input().syntax().typescript() {
124        match name {
125            Pat::Ident(..) => p.input_mut().eat(&P::Token::BANG),
126            _ => false,
127        }
128    } else {
129        false
130    };
131
132    // Typescript extension
133    if p.input().syntax().typescript() && p.input().is(&P::Token::COLON) {
134        let type_annotation = try_parse_ts_type_ann(p)?;
135        match name {
136            Pat::Array(ArrayPat {
137                ref mut type_ann, ..
138            })
139            | Pat::Ident(BindingIdent {
140                ref mut type_ann, ..
141            })
142            | Pat::Object(ObjectPat {
143                ref mut type_ann, ..
144            })
145            | Pat::Rest(RestPat {
146                ref mut type_ann, ..
147            }) => {
148                *type_ann = type_annotation;
149            }
150            _ => unreachable!("invalid syntax: Pat: {:?}", name),
151        }
152    }
153
154    //FIXME: This is wrong. Should check in/of only on first loop.
155    let cur = p.input().cur();
156    let init = if !for_loop || !(cur.is_in() || cur.is_of()) {
157        if p.input_mut().eat(&P::Token::EQUAL) {
158            let expr = parse_assignment_expr(p)?;
159            let expr = p.verify_expr(expr)?;
160
161            Some(expr)
162        } else {
163            // Destructuring bindings require initializers, but
164            // typescript allows `declare` vars not to have initializers.
165            if p.ctx().contains(Context::InDeclare) {
166                None
167            } else if kind == VarDeclKind::Const
168                && !for_loop
169                && !p.ctx().contains(Context::InDeclare)
170            {
171                p.emit_err(
172                    p.span(start),
173                    SyntaxError::ConstDeclarationsRequireInitialization,
174                );
175
176                None
177            } else {
178                match name {
179                    Pat::Ident(..) => None,
180                    _ => {
181                        syntax_error!(p, p.span(start), SyntaxError::PatVarWithoutInit)
182                    }
183                }
184            }
185        }
186    } else {
187        // e.g. for(let a;;)
188        None
189    };
190
191    Ok(VarDeclarator {
192        span: p.span(start),
193        name,
194        init,
195        definite,
196    })
197}
198
199pub fn parse_var_stmt<'a, P: Parser<'a>>(p: &mut P, for_loop: bool) -> PResult<Box<VarDecl>> {
200    let start = p.cur_pos();
201    let t = p.input().cur();
202    let kind = if t.is_const() {
203        VarDeclKind::Const
204    } else if t.is_let() {
205        VarDeclKind::Let
206    } else if t.is_var() {
207        VarDeclKind::Var
208    } else {
209        unreachable!()
210    };
211    p.bump();
212    let var_span = p.span(start);
213    let should_include_in = kind != VarDeclKind::Var || !for_loop;
214
215    if p.syntax().typescript() && for_loop {
216        let cur = p.input().cur();
217        let res: PResult<bool> = if cur.is_in() || cur.is_of() {
218            ts_look_ahead(p, |p| {
219                //
220                if !p.input_mut().eat(&P::Token::OF) && !p.input_mut().eat(&P::Token::IN) {
221                    return Ok(false);
222                }
223
224                parse_assignment_expr(p)?;
225                expect!(p, &P::Token::RPAREN);
226
227                Ok(true)
228            })
229        } else {
230            Ok(false)
231        };
232
233        match res {
234            Ok(true) => {
235                let pos = var_span.hi();
236                let span = Span::new_with_checked(pos, pos);
237                p.emit_err(span, SyntaxError::TS1123);
238
239                return Ok(Box::new(VarDecl {
240                    span: p.span(start),
241                    kind,
242                    declare: false,
243                    decls: Vec::new(),
244                    ..Default::default()
245                }));
246            }
247            Err(..) => {}
248            _ => {}
249        }
250    }
251
252    let mut decls = Vec::with_capacity(4);
253    loop {
254        // Handle
255        //      var a,;
256        //
257        // NewLine is ok
258        if p.input().is(&P::Token::SEMI) {
259            let prev_span = p.input().prev_span();
260            let span = if prev_span == var_span {
261                Span::new_with_checked(prev_span.hi, prev_span.hi)
262            } else {
263                prev_span
264            };
265            p.emit_err(span, SyntaxError::TS1009);
266            break;
267        }
268
269        let decl = if should_include_in {
270            p.do_inside_of_context(Context::IncludeInExpr, |p| {
271                parse_var_declarator(p, for_loop, kind)
272            })
273        } else {
274            parse_var_declarator(p, for_loop, kind)
275        }?;
276
277        decls.push(decl);
278
279        if !p.input_mut().eat(&P::Token::COMMA) {
280            break;
281        }
282    }
283
284    if !for_loop && !p.eat_general_semi() {
285        p.emit_err(p.input().cur_span(), SyntaxError::TS1005);
286
287        let _ = p.parse_expr();
288
289        while !p.eat_general_semi() {
290            p.bump();
291
292            if p.input().cur().is_error() {
293                break;
294            }
295        }
296    }
297
298    Ok(Box::new(VarDecl {
299        span: p.span(start),
300        declare: false,
301        kind,
302        decls,
303        ..Default::default()
304    }))
305}
306
307pub fn parse_using_decl<'a, P: Parser<'a>>(
308    p: &mut P,
309    start: BytePos,
310    is_await: bool,
311) -> PResult<Option<Box<UsingDecl>>> {
312    // using
313    // reader = init()
314
315    // is two statements
316    if p.input_mut().has_linebreak_between_cur_and_peeked() {
317        return Ok(None);
318    }
319
320    if !p.peek_is_ident_ref() {
321        return Ok(None);
322    }
323
324    p.assert_and_bump(&P::Token::USING);
325
326    let mut decls = Vec::new();
327    loop {
328        // Handle
329        //      var a,;
330        //
331        // NewLine is ok
332        if p.input().is(&P::Token::SEMI) {
333            let span = p.input().prev_span();
334            p.emit_err(span, SyntaxError::TS1009);
335            break;
336        }
337
338        decls.push(parse_var_declarator(p, false, VarDeclKind::Var)?);
339        if !p.input_mut().eat(&P::Token::COMMA) {
340            break;
341        }
342    }
343
344    if !p.syntax().explicit_resource_management() {
345        p.emit_err(p.span(start), SyntaxError::UsingDeclNotEnabled);
346    }
347
348    if !p.ctx().contains(Context::AllowUsingDecl) {
349        p.emit_err(p.span(start), SyntaxError::UsingDeclNotAllowed);
350    }
351
352    for decl in &decls {
353        match decl.name {
354            Pat::Ident(..) => {}
355            _ => {
356                p.emit_err(p.span(start), SyntaxError::InvalidNameInUsingDecl);
357            }
358        }
359
360        if decl.init.is_none() {
361            p.emit_err(p.span(start), SyntaxError::InitRequiredForUsingDecl);
362        }
363    }
364
365    p.expect_general_semi()?;
366
367    Ok(Some(Box::new(UsingDecl {
368        span: p.span(start),
369        is_await,
370        decls,
371    })))
372}
373
374pub fn parse_for_head<'a, P: Parser<'a>>(p: &mut P) -> PResult<TempForHead> {
375    // let strict = p.ctx().contains(Context::Strict);
376
377    let cur = p.input().cur();
378    if cur.is_const()
379        || cur.is_var()
380        || (p.input().is(&P::Token::LET) && peek!(p).map_or(false, |v| v.follows_keyword_let()))
381    {
382        let decl = parse_var_stmt(p, true)?;
383
384        let cur = p.input().cur();
385        if cur.is_of() || cur.is_in() {
386            if decl.decls.len() != 1 {
387                for d in decl.decls.iter().skip(1) {
388                    p.emit_err(d.name.span(), SyntaxError::TooManyVarInForInHead);
389                }
390            } else {
391                if (p.ctx().contains(Context::Strict) || p.input().is(&P::Token::OF))
392                    && decl.decls[0].init.is_some()
393                {
394                    p.emit_err(
395                        decl.decls[0].name.span(),
396                        SyntaxError::VarInitializerInForInHead,
397                    );
398                }
399
400                if p.syntax().typescript() {
401                    let type_ann = match decl.decls[0].name {
402                        Pat::Ident(ref v) => Some(&v.type_ann),
403                        Pat::Array(ref v) => Some(&v.type_ann),
404                        Pat::Rest(ref v) => Some(&v.type_ann),
405                        Pat::Object(ref v) => Some(&v.type_ann),
406                        _ => None,
407                    };
408
409                    if let Some(type_ann) = type_ann {
410                        if type_ann.is_some() {
411                            p.emit_err(decl.decls[0].name.span(), SyntaxError::TS2483);
412                        }
413                    }
414                }
415            }
416
417            return parse_for_each_head(p, ForHead::VarDecl(decl));
418        }
419
420        expect!(p, &P::Token::SEMI);
421        return parse_normal_for_head(p, Some(VarDeclOrExpr::VarDecl(decl)));
422    }
423
424    if p.input_mut().eat(&P::Token::SEMI) {
425        return parse_normal_for_head(p, None);
426    }
427
428    let start = p.cur_pos();
429    let init = p.disallow_in_expr(parse_for_head_prefix)?;
430
431    let mut is_using_decl = false;
432    let mut is_await_using_decl = false;
433
434    if p.input().syntax().explicit_resource_management() {
435        // using foo
436        let mut maybe_using_decl = init.is_ident_ref_to("using");
437        let mut maybe_await_using_decl = false;
438
439        // await using foo
440        if !maybe_using_decl
441            && init
442                .as_await_expr()
443                .filter(|e| e.arg.is_ident_ref_to("using"))
444                .is_some()
445        {
446            maybe_using_decl = true;
447            maybe_await_using_decl = true;
448        }
449
450        if maybe_using_decl
451            && !p.input().is(&P::Token::OF)
452            && (peek!(p).is_some_and(|peek| peek.is_of() || peek.is_in()))
453        {
454            is_using_decl = maybe_using_decl;
455            is_await_using_decl = maybe_await_using_decl;
456        }
457    }
458
459    if is_using_decl {
460        let name = parse_binding_ident(p, false)?;
461        let decl = VarDeclarator {
462            name: name.into(),
463            span: p.span(start),
464            init: None,
465            definite: false,
466        };
467
468        let pat = Box::new(UsingDecl {
469            span: p.span(start),
470            is_await: is_await_using_decl,
471            decls: vec![decl],
472        });
473
474        let cur = p.input().cur();
475        if cur.is_error() {
476            let err = p.input_mut().expect_error_token_and_bump();
477            return Err(err);
478        } else if cur.is_eof() {
479            return Err(eof_error(p));
480        }
481
482        return parse_for_each_head(p, ForHead::UsingDecl(pat));
483    }
484
485    // for (a of b)
486    let cur = p.input().cur();
487    if cur.is_of() || cur.is_in() {
488        let is_in = p.input().is(&P::Token::IN);
489
490        let pat = reparse_expr_as_pat(p, PatType::AssignPat, init)?;
491
492        // for ({} in foo) is invalid
493        if p.input().syntax().typescript() && is_in {
494            match pat {
495                Pat::Ident(..) => {}
496                Pat::Expr(..) => {}
497                ref v => p.emit_err(v.span(), SyntaxError::TS2491),
498            }
499        }
500
501        return parse_for_each_head(p, ForHead::Pat(Box::new(pat)));
502    }
503
504    expect!(p, &P::Token::SEMI);
505
506    let init = p.verify_expr(init)?;
507    parse_normal_for_head(p, Some(VarDeclOrExpr::Expr(init)))
508}
509
510fn parse_for_stmt<'a, P: Parser<'a>>(p: &mut P) -> PResult<Stmt> {
511    let start = p.cur_pos();
512
513    p.assert_and_bump(&P::Token::FOR);
514    let await_start = p.cur_pos();
515    let await_token = if p.input_mut().eat(&P::Token::AWAIT) {
516        Some(p.span(await_start))
517    } else {
518        None
519    };
520    expect!(p, &P::Token::LPAREN);
521
522    let head = p.do_inside_of_context(Context::ForLoopInit, |p| {
523        if await_token.is_some() {
524            p.do_inside_of_context(Context::ForAwaitLoopInit, parse_for_head)
525        } else {
526            p.do_outside_of_context(Context::ForAwaitLoopInit, parse_for_head)
527        }
528    })?;
529
530    expect!(p, &P::Token::RPAREN);
531
532    let body = p
533        .do_inside_of_context(
534            Context::IsBreakAllowed.union(Context::IsContinueAllowed),
535            |p| p.do_outside_of_context(Context::TopLevel, parse_stmt),
536        )
537        .map(Box::new)?;
538
539    let span = p.span(start);
540    Ok(match head {
541        TempForHead::For { init, test, update } => {
542            if let Some(await_token) = await_token {
543                syntax_error!(p, await_token, SyntaxError::AwaitForStmt);
544            }
545
546            ForStmt {
547                span,
548                init,
549                test,
550                update,
551                body,
552            }
553            .into()
554        }
555        TempForHead::ForIn { left, right } => {
556            if let Some(await_token) = await_token {
557                syntax_error!(p, await_token, SyntaxError::AwaitForStmt);
558            }
559
560            ForInStmt {
561                span,
562                left,
563                right,
564                body,
565            }
566            .into()
567        }
568        TempForHead::ForOf { left, right } => ForOfStmt {
569            span,
570            is_await: await_token.is_some(),
571            left,
572            right,
573            body,
574        }
575        .into(),
576    })
577}
578
579pub fn parse_stmt<'a>(p: &mut impl Parser<'a>) -> PResult<Stmt> {
580    trace_cur!(p, parse_stmt);
581    parse_stmt_like(p, false, handle_import_export)
582}
583
584/// Utility function used to parse large if else statements iteratively.
585///
586/// THis function is recursive, but it is very cheap so stack overflow will
587/// not occur.
588fn adjust_if_else_clause<'a, P: Parser<'a>>(p: &mut P, cur: &mut IfStmt, alt: Box<Stmt>) {
589    cur.span = p.span(cur.span.lo);
590
591    if let Some(Stmt::If(prev_alt)) = cur.alt.as_deref_mut() {
592        adjust_if_else_clause(p, prev_alt, alt)
593    } else {
594        debug_assert_eq!(cur.alt, None);
595        cur.alt = Some(alt);
596    }
597}
598
599fn parse_if_stmt<'a, P: Parser<'a>>(p: &mut P) -> PResult<IfStmt> {
600    let start = p.cur_pos();
601
602    p.assert_and_bump(&P::Token::IF);
603    let if_token = p.input().prev_span();
604
605    expect!(p, &P::Token::LPAREN);
606
607    let test = p
608        .do_outside_of_context(Context::IgnoreElseClause, |p| {
609            p.allow_in_expr(|p| p.parse_expr())
610        })
611        .map_err(|err| {
612            Error::new(
613                err.span(),
614                SyntaxError::WithLabel {
615                    inner: Box::new(err),
616                    span: if_token,
617                    note: "Tried to parse the condition for an if statement",
618                },
619            )
620        })?;
621
622    expect!(p, &P::Token::RPAREN);
623
624    let cons = {
625        // Prevent stack overflow
626        crate::maybe_grow(256 * 1024, 1024 * 1024, || {
627            // // Annex B
628            // if !p.ctx().contains(Context::Strict) && p.input().is(&P::Token::FUNCTION) {
629            //     // TODO: report error?
630            // }
631            p.do_outside_of_context(
632                Context::IgnoreElseClause.union(Context::TopLevel),
633                parse_stmt,
634            )
635            .map(Box::new)
636        })?
637    };
638
639    // We parse `else` branch iteratively, to avoid stack overflow
640    // See https://github.com/swc-project/swc/pull/3961
641
642    let alt = if p.ctx().contains(Context::IgnoreElseClause) {
643        None
644    } else {
645        let mut cur = None;
646
647        let last = loop {
648            if !p.input_mut().eat(&P::Token::ELSE) {
649                break None;
650            }
651
652            if !p.input().is(&P::Token::IF) {
653                // As we eat `else` above, we need to parse statement once.
654                let last = p.do_outside_of_context(
655                    Context::IgnoreElseClause.union(Context::TopLevel),
656                    parse_stmt,
657                )?;
658                break Some(last);
659            }
660
661            // We encountered `else if`
662
663            let alt = p.do_inside_of_context(Context::IgnoreElseClause, parse_if_stmt)?;
664
665            match &mut cur {
666                Some(cur) => {
667                    adjust_if_else_clause(p, cur, Box::new(alt.into()));
668                }
669                _ => {
670                    cur = Some(alt);
671                }
672            }
673        };
674
675        match cur {
676            Some(mut cur) => {
677                if let Some(last) = last {
678                    adjust_if_else_clause(p, &mut cur, Box::new(last));
679                }
680                Some(cur.into())
681            }
682            _ => last,
683        }
684    }
685    .map(Box::new);
686
687    let span = p.span(start);
688    Ok(IfStmt {
689        span,
690        test,
691        cons,
692        alt,
693    })
694}
695
696fn parse_throw_stmt<'a, P: Parser<'a>>(p: &mut P) -> PResult<Stmt> {
697    let start = p.cur_pos();
698
699    p.assert_and_bump(&P::Token::THROW);
700
701    if p.input().had_line_break_before_cur() {
702        // TODO: Suggest throw arg;
703        syntax_error!(p, SyntaxError::LineBreakInThrow);
704    }
705
706    let arg = p.allow_in_expr(|p| p.parse_expr())?;
707    p.expect_general_semi()?;
708
709    let span = p.span(start);
710    Ok(ThrowStmt { span, arg }.into())
711}
712
713fn parse_with_stmt<'a, P: Parser<'a>>(p: &mut P) -> PResult<Stmt> {
714    if p.syntax().typescript() {
715        let span = p.input().cur_span();
716        p.emit_err(span, SyntaxError::TS2410);
717    }
718
719    {
720        let span = p.input().cur_span();
721        p.emit_strict_mode_err(span, SyntaxError::WithInStrict);
722    }
723
724    let start = p.cur_pos();
725
726    p.assert_and_bump(&P::Token::WITH);
727
728    expect!(p, &P::Token::LPAREN);
729    let obj = p.allow_in_expr(|p| p.parse_expr())?;
730    expect!(p, &P::Token::RPAREN);
731
732    let body = p
733        .do_inside_of_context(Context::InFunction, |p| {
734            p.do_outside_of_context(Context::TopLevel, parse_stmt)
735        })
736        .map(Box::new)?;
737
738    let span = p.span(start);
739    Ok(WithStmt { span, obj, body }.into())
740}
741
742fn parse_while_stmt<'a, P: Parser<'a>>(p: &mut P) -> PResult<Stmt> {
743    let start = p.cur_pos();
744
745    p.assert_and_bump(&P::Token::WHILE);
746
747    expect!(p, &P::Token::LPAREN);
748    let test = p.allow_in_expr(|p| p.parse_expr())?;
749    expect!(p, &P::Token::RPAREN);
750
751    let body = p
752        .do_inside_of_context(
753            Context::IsBreakAllowed.union(Context::IsContinueAllowed),
754            |p| p.do_outside_of_context(Context::TopLevel, parse_stmt),
755        )
756        .map(Box::new)?;
757
758    let span = p.span(start);
759    Ok(WhileStmt { span, test, body }.into())
760}
761
762/// It's optional since es2019
763fn parse_catch_param<'a, P: Parser<'a>>(p: &mut P) -> PResult<Option<Pat>> {
764    if p.input_mut().eat(&P::Token::LPAREN) {
765        let mut pat = parse_binding_pat_or_ident(p, false)?;
766
767        let type_ann_start = p.cur_pos();
768
769        if p.syntax().typescript() && p.input_mut().eat(&P::Token::COLON) {
770            let ty = p.do_inside_of_context(Context::InType, parse_ts_type)?;
771            // p.emit_err(ty.span(), SyntaxError::TS1196);
772
773            match &mut pat {
774                Pat::Ident(BindingIdent { type_ann, .. })
775                | Pat::Array(ArrayPat { type_ann, .. })
776                | Pat::Rest(RestPat { type_ann, .. })
777                | Pat::Object(ObjectPat { type_ann, .. }) => {
778                    *type_ann = Some(Box::new(TsTypeAnn {
779                        span: p.span(type_ann_start),
780                        type_ann: ty,
781                    }));
782                }
783                Pat::Assign(..) => {}
784                Pat::Invalid(_) => {}
785                Pat::Expr(_) => {}
786                #[cfg(swc_ast_unknown)]
787                _ => {}
788            }
789        }
790        expect!(p, &P::Token::RPAREN);
791        Ok(Some(pat))
792    } else {
793        Ok(None)
794    }
795}
796
797fn parse_do_stmt<'a, P: Parser<'a>>(p: &mut P) -> PResult<Stmt> {
798    let start = p.cur_pos();
799
800    p.assert_and_bump(&P::Token::DO);
801
802    let body = p
803        .do_inside_of_context(
804            Context::IsBreakAllowed.union(Context::IsContinueAllowed),
805            |p| p.do_outside_of_context(Context::TopLevel, parse_stmt),
806        )
807        .map(Box::new)?;
808
809    expect!(p, &P::Token::WHILE);
810    expect!(p, &P::Token::LPAREN);
811
812    let test = p.allow_in_expr(|p| p.parse_expr())?;
813
814    expect!(p, &P::Token::RPAREN);
815
816    // We *may* eat semicolon.
817    let _ = p.eat_general_semi();
818
819    let span = p.span(start);
820
821    Ok(DoWhileStmt { span, test, body }.into())
822}
823
824fn parse_labelled_stmt<'a, P: Parser<'a>>(p: &mut P, l: Ident) -> PResult<Stmt> {
825    p.do_inside_of_context(Context::IsBreakAllowed, |p| {
826        p.do_outside_of_context(Context::AllowUsingDecl, |p| {
827            let start = l.span.lo();
828
829            let mut errors = Vec::new();
830            for lb in &p.state().labels {
831                if l.sym == *lb {
832                    errors.push(Error::new(
833                        l.span,
834                        SyntaxError::DuplicateLabel(l.sym.clone()),
835                    ));
836                }
837            }
838            p.state_mut().labels.push(l.sym.clone());
839
840            let body = Box::new(if p.input().is(&P::Token::FUNCTION) {
841                let f = parse_fn_decl(p, Vec::new())?;
842                if let Decl::Fn(FnDecl { function, .. }) = &f {
843                    if p.ctx().contains(Context::Strict) {
844                        p.emit_err(function.span, SyntaxError::LabelledFunctionInStrict)
845                    }
846                    if function.is_generator || function.is_async {
847                        p.emit_err(function.span, SyntaxError::LabelledGeneratorOrAsync)
848                    }
849                }
850
851                f.into()
852            } else {
853                p.do_outside_of_context(Context::TopLevel, parse_stmt)?
854            });
855
856            for err in errors {
857                p.emit_error(err);
858            }
859
860            {
861                let pos = p.state().labels.iter().position(|v| v == &l.sym);
862                if let Some(pos) = pos {
863                    p.state_mut().labels.remove(pos);
864                }
865            }
866
867            Ok(LabeledStmt {
868                span: p.span(start),
869                label: l,
870                body,
871            }
872            .into())
873        })
874    })
875}
876
877pub fn parse_block<'a, P: Parser<'a>>(p: &mut P, allow_directives: bool) -> PResult<BlockStmt> {
878    let start = p.cur_pos();
879
880    expect!(p, &P::Token::LBRACE);
881
882    let stmts = p.do_outside_of_context(Context::TopLevel, |p| {
883        parse_stmt_block_body(p, allow_directives, Some(&P::Token::RBRACE))
884    })?;
885
886    let span = p.span(start);
887    Ok(BlockStmt {
888        span,
889        stmts,
890        ctxt: Default::default(),
891    })
892}
893
894fn parse_finally_block<'a, P: Parser<'a>>(p: &mut P) -> PResult<Option<BlockStmt>> {
895    Ok(if p.input_mut().eat(&P::Token::FINALLY) {
896        parse_block(p, false).map(Some)?
897    } else {
898        None
899    })
900}
901
902fn parse_catch_clause<'a, P: Parser<'a>>(p: &mut P) -> PResult<Option<CatchClause>> {
903    let start = p.cur_pos();
904    Ok(if p.input_mut().eat(&P::Token::CATCH) {
905        let param = parse_catch_param(p)?;
906        parse_block(p, false)
907            .map(|body| CatchClause {
908                span: p.span(start),
909                param,
910                body,
911            })
912            .map(Some)?
913    } else {
914        None
915    })
916}
917
918fn parse_try_stmt<'a, P: Parser<'a>>(p: &mut P) -> PResult<Stmt> {
919    let start = p.cur_pos();
920    p.assert_and_bump(&P::Token::TRY);
921
922    let block = parse_block(p, false)?;
923
924    let catch_start = p.cur_pos();
925    let handler = parse_catch_clause(p)?;
926    let finalizer = parse_finally_block(p)?;
927
928    if handler.is_none() && finalizer.is_none() {
929        p.emit_err(
930            Span::new_with_checked(catch_start, catch_start),
931            SyntaxError::TS1005,
932        );
933    }
934
935    let span = p.span(start);
936    Ok(TryStmt {
937        span,
938        block,
939        handler,
940        finalizer,
941    }
942    .into())
943}
944
945fn parse_switch_stmt<'a, P: Parser<'a>>(p: &mut P) -> PResult<Stmt> {
946    let switch_start = p.cur_pos();
947
948    p.assert_and_bump(&P::Token::SWITCH);
949
950    expect!(p, &P::Token::LPAREN);
951    let discriminant = p.allow_in_expr(|p| p.parse_expr())?;
952    expect!(p, &P::Token::RPAREN);
953
954    let mut cases = Vec::new();
955    let mut span_of_previous_default = None;
956
957    expect!(p, &P::Token::LBRACE);
958
959    p.do_inside_of_context(Context::IsBreakAllowed, |p| {
960        while {
961            let cur = p.input().cur();
962            cur.is_case() || cur.is_default()
963        } {
964            let mut cons = Vec::new();
965            let is_case = p.input().is(&P::Token::CASE);
966            let case_start = p.cur_pos();
967            p.bump();
968            let test = if is_case {
969                p.allow_in_expr(|p| p.parse_expr()).map(Some)?
970            } else {
971                if let Some(previous) = span_of_previous_default {
972                    syntax_error!(p, SyntaxError::MultipleDefault { previous });
973                }
974                span_of_previous_default = Some(p.span(case_start));
975
976                None
977            };
978            expect!(p, &P::Token::COLON);
979
980            while {
981                let cur = p.input().cur();
982                !(cur.is_case() || cur.is_default() || cur.is_rbrace())
983            } {
984                cons.push(p.do_outside_of_context(Context::TopLevel, parse_stmt_list_item)?);
985            }
986
987            cases.push(SwitchCase {
988                span: Span::new_with_checked(case_start, p.input().prev_span().hi),
989                test,
990                cons,
991            });
992        }
993
994        Ok(())
995    })?;
996
997    // eof or rbrace
998    expect!(p, &P::Token::RBRACE);
999
1000    Ok(SwitchStmt {
1001        span: p.span(switch_start),
1002        discriminant,
1003        cases,
1004    }
1005    .into())
1006}
1007
1008/// Parse a statement and maybe a declaration.
1009pub fn parse_stmt_list_item<'a>(p: &mut impl Parser<'a>) -> PResult<Stmt> {
1010    trace_cur!(p, parse_stmt_list_item);
1011    parse_stmt_like(p, true, handle_import_export)
1012}
1013
1014/// Parse a statement, declaration or module item.
1015pub fn parse_stmt_like<'a, P: Parser<'a>, Type: IsDirective + From<Stmt>>(
1016    p: &mut P,
1017    include_decl: bool,
1018    handle_import_export: impl Fn(&mut P, Vec<Decorator>) -> PResult<Type>,
1019) -> PResult<Type> {
1020    trace_cur!(p, parse_stmt_like);
1021
1022    debug_tracing!(p, "parse_stmt_like");
1023
1024    let start = p.cur_pos();
1025    let decorators = if p.input().get_cur().token() == &P::Token::AT {
1026        parse_decorators(p, true)?
1027    } else {
1028        vec![]
1029    };
1030
1031    let cur = p.input().cur();
1032    if cur.is_import() || cur.is_export() {
1033        return handle_import_export(p, decorators);
1034    }
1035
1036    p.do_outside_of_context(Context::WillExpectColonForCond, |p| {
1037        p.do_inside_of_context(Context::AllowUsingDecl, |p| {
1038            parse_stmt_internal(p, start, include_decl, decorators)
1039        })
1040    })
1041    .map(From::from)
1042}
1043
1044fn handle_import_export<'a, P: Parser<'a>>(p: &mut P, _: Vec<Decorator>) -> PResult<Stmt> {
1045    let start = p.cur_pos();
1046    if p.input().is(&P::Token::IMPORT) && peek!(p).is_some_and(|peek| peek.is_lparen()) {
1047        let expr = p.parse_expr()?;
1048
1049        p.eat_general_semi();
1050
1051        return Ok(ExprStmt {
1052            span: p.span(start),
1053            expr,
1054        }
1055        .into());
1056    }
1057
1058    if p.input().is(&P::Token::IMPORT) && peek!(p).is_some_and(|peek| peek.is_dot()) {
1059        let expr = p.parse_expr()?;
1060
1061        p.eat_general_semi();
1062
1063        return Ok(ExprStmt {
1064            span: p.span(start),
1065            expr,
1066        }
1067        .into());
1068    }
1069
1070    syntax_error!(p, SyntaxError::ImportExportInScript);
1071}
1072
1073/// `parseStatementContent`
1074fn parse_stmt_internal<'a, P: Parser<'a>>(
1075    p: &mut P,
1076    start: BytePos,
1077    include_decl: bool,
1078    decorators: Vec<Decorator>,
1079) -> PResult<Stmt> {
1080    trace_cur!(p, parse_stmt_internal);
1081
1082    let is_typescript = p.input().syntax().typescript();
1083
1084    if is_typescript
1085        && p.input().is(&P::Token::CONST)
1086        && peek!(p).is_some_and(|peek| peek.is_enum())
1087    {
1088        p.assert_and_bump(&P::Token::CONST);
1089        p.assert_and_bump(&P::Token::ENUM);
1090        return parse_ts_enum_decl(p, start, true)
1091            .map(Decl::from)
1092            .map(Stmt::from);
1093    }
1094
1095    let top_level = p.ctx().contains(Context::TopLevel);
1096
1097    let cur = p.input().cur().clone();
1098
1099    if cur.is_await() && (include_decl || top_level) {
1100        if top_level {
1101            p.mark_found_module_item();
1102            if !p.ctx().contains(Context::CanBeModule) {
1103                p.emit_err(p.input().cur_span(), SyntaxError::TopLevelAwaitInScript);
1104            }
1105        }
1106
1107        if peek!(p).is_some_and(|peek| peek.is_using()) {
1108            let eaten_await = Some(p.input().cur_pos());
1109            p.assert_and_bump(&P::Token::AWAIT);
1110            let v = parse_using_decl(p, start, true)?;
1111            if let Some(v) = v {
1112                return Ok(v.into());
1113            }
1114
1115            let expr = parse_await_expr(p, eaten_await)?;
1116            let expr = p.allow_in_expr(|p| parse_bin_op_recursively(p, expr, 0))?;
1117            p.eat_general_semi();
1118
1119            let span = p.span(start);
1120            return Ok(ExprStmt { span, expr }.into());
1121        }
1122    } else if cur.is_break() || cur.is_continue() {
1123        let is_break = p.input().is(&P::Token::BREAK);
1124        p.bump();
1125        let label = if p.eat_general_semi() {
1126            None
1127        } else {
1128            let i = parse_label_ident(p).map(Some)?;
1129            p.expect_general_semi()?;
1130            i
1131        };
1132        let span = p.span(start);
1133        if is_break {
1134            if label.is_some() && !p.state().labels.contains(&label.as_ref().unwrap().sym) {
1135                p.emit_err(span, SyntaxError::TS1116);
1136            } else if !p.ctx().contains(Context::IsBreakAllowed) {
1137                p.emit_err(span, SyntaxError::TS1105);
1138            }
1139        } else if !p.ctx().contains(Context::IsContinueAllowed) {
1140            p.emit_err(span, SyntaxError::TS1115);
1141        } else if label.is_some() && !p.state().labels.contains(&label.as_ref().unwrap().sym) {
1142            p.emit_err(span, SyntaxError::TS1107);
1143        }
1144        return Ok(if is_break {
1145            BreakStmt { span, label }.into()
1146        } else {
1147            ContinueStmt { span, label }.into()
1148        });
1149    } else if cur.is_debugger() {
1150        p.bump();
1151        p.expect_general_semi()?;
1152        return Ok(DebuggerStmt {
1153            span: p.span(start),
1154        }
1155        .into());
1156    } else if cur.is_do() {
1157        return parse_do_stmt(p);
1158    } else if cur.is_for() {
1159        return parse_for_stmt(p);
1160    } else if cur.is_function() {
1161        if !include_decl {
1162            p.emit_err(p.input().cur_span(), SyntaxError::DeclNotAllowed);
1163        }
1164        return parse_fn_decl(p, decorators).map(Stmt::from);
1165    } else if cur.is_class() {
1166        if !include_decl {
1167            p.emit_err(p.input().cur_span(), SyntaxError::DeclNotAllowed);
1168        }
1169        return parse_class_decl(p, start, start, decorators, false).map(Stmt::from);
1170    } else if cur.is_if() {
1171        return parse_if_stmt(p).map(Stmt::If);
1172    } else if cur.is_return() {
1173        return parse_return_stmt(p);
1174    } else if cur.is_switch() {
1175        return parse_switch_stmt(p);
1176    } else if cur.is_throw() {
1177        return parse_throw_stmt(p);
1178    } else if cur.is_catch() {
1179        // Error recovery
1180        let span = p.input().cur_span();
1181        p.emit_err(span, SyntaxError::TS1005);
1182
1183        let _ = parse_catch_clause(p);
1184        let _ = parse_finally_block(p);
1185
1186        return Ok(ExprStmt {
1187            span,
1188            expr: Invalid { span }.into(),
1189        }
1190        .into());
1191    } else if cur.is_finally() {
1192        // Error recovery
1193        let span = p.input().cur_span();
1194        p.emit_err(span, SyntaxError::TS1005);
1195
1196        let _ = parse_finally_block(p);
1197
1198        return Ok(ExprStmt {
1199            span,
1200            expr: Invalid { span }.into(),
1201        }
1202        .into());
1203    } else if cur.is_try() {
1204        return parse_try_stmt(p);
1205    } else if cur.is_with() {
1206        return parse_with_stmt(p);
1207    } else if cur.is_while() {
1208        return parse_while_stmt(p);
1209    } else if cur.is_var() || (cur.is_const() && include_decl) {
1210        let v = parse_var_stmt(p, false)?;
1211        return Ok(v.into());
1212    } else if cur.is_let() && include_decl {
1213        // 'let' can start an identifier reference.
1214        let is_keyword = match peek!(p) {
1215            Some(t) => t.follows_keyword_let(),
1216            _ => false,
1217        };
1218
1219        if is_keyword {
1220            let v = parse_var_stmt(p, false)?;
1221            return Ok(v.into());
1222        }
1223    } else if cur.is_using() && include_decl {
1224        let v = parse_using_decl(p, start, false)?;
1225        if let Some(v) = v {
1226            return Ok(v.into());
1227        }
1228    } else if cur.is_interface()
1229        && is_typescript
1230        && peek!(p).is_some_and(|peek| peek.is_word())
1231        && !p.input_mut().has_linebreak_between_cur_and_peeked()
1232    {
1233        let start = p.input().cur_pos();
1234        p.bump();
1235        return Ok(parse_ts_interface_decl(p, start)?.into());
1236    } else if cur.is_type()
1237        && is_typescript
1238        && peek!(p).is_some_and(|peek| peek.is_word())
1239        && !p.input_mut().has_linebreak_between_cur_and_peeked()
1240    {
1241        let start = p.input().cur_pos();
1242        p.bump();
1243        return Ok(parse_ts_type_alias_decl(p, start)?.into());
1244    } else if cur.is_enum()
1245        && is_typescript
1246        && peek!(p).is_some_and(|peek| peek.is_word())
1247        && !p.input_mut().has_linebreak_between_cur_and_peeked()
1248    {
1249        let start = p.input().cur_pos();
1250        p.bump();
1251        return Ok(parse_ts_enum_decl(p, start, false)?.into());
1252    } else if cur.is_lbrace() {
1253        return p
1254            .do_inside_of_context(Context::AllowUsingDecl, |p| parse_block(p, false))
1255            .map(Stmt::Block);
1256    } else if cur.is_semi() {
1257        p.bump();
1258        return Ok(EmptyStmt {
1259            span: p.span(start),
1260        }
1261        .into());
1262    }
1263
1264    // Handle async function foo() {}
1265    if p.input().is(&P::Token::ASYNC)
1266        && peek!(p).is_some_and(|peek| peek.is_function())
1267        && !p.input_mut().has_linebreak_between_cur_and_peeked()
1268    {
1269        return parse_async_fn_decl(p, decorators).map(From::from);
1270    }
1271
1272    // If the statement does not start with a statement keyword or a
1273    // brace, it's an ExpressionStatement or LabeledStatement. We
1274    // simply start parsing an expression, and afterwards, if the
1275    // next token is a colon and the expression was a simple
1276    // Identifier node, we switch to interpreting it as a label.
1277    let expr = p.allow_in_expr(|p| p.parse_expr())?;
1278
1279    let expr = match *expr {
1280        Expr::Ident(ident) => {
1281            if p.input_mut().eat(&P::Token::COLON) {
1282                return parse_labelled_stmt(p, ident);
1283            }
1284            ident.into()
1285        }
1286        _ => p.verify_expr(expr)?,
1287    };
1288    if let Expr::Ident(ref ident) = *expr {
1289        if &*ident.sym == "interface" && p.input().had_line_break_before_cur() {
1290            p.emit_strict_mode_err(
1291                ident.span,
1292                SyntaxError::InvalidIdentInStrict(ident.sym.clone()),
1293            );
1294
1295            p.eat_general_semi();
1296
1297            return Ok(ExprStmt {
1298                span: p.span(start),
1299                expr,
1300            }
1301            .into());
1302        }
1303
1304        if p.input().syntax().typescript() {
1305            if let Some(decl) = parse_ts_expr_stmt(p, decorators, ident.clone())? {
1306                return Ok(decl.into());
1307            }
1308        }
1309    }
1310
1311    if p.syntax().typescript() {
1312        if let Expr::Ident(ref i) = *expr {
1313            match &*i.sym {
1314                "public" | "static" | "abstract" => {
1315                    if p.input_mut().eat(&P::Token::INTERFACE) {
1316                        p.emit_err(i.span, SyntaxError::TS2427);
1317                        return parse_ts_interface_decl(p, start)
1318                            .map(Decl::from)
1319                            .map(Stmt::from);
1320                    }
1321                }
1322                _ => {}
1323            }
1324        }
1325    }
1326
1327    if p.eat_general_semi() {
1328        Ok(ExprStmt {
1329            span: p.span(start),
1330            expr,
1331        }
1332        .into())
1333    } else {
1334        let cur = p.input().cur();
1335        if cur.is_bin_op() {
1336            p.emit_err(p.input().cur_span(), SyntaxError::TS1005);
1337            let expr = parse_bin_op_recursively(p, expr, 0)?;
1338            return Ok(ExprStmt {
1339                span: p.span(start),
1340                expr,
1341            }
1342            .into());
1343        }
1344
1345        syntax_error!(
1346            p,
1347            SyntaxError::ExpectedSemiForExprStmt { expr: expr.span() }
1348        );
1349    }
1350}
1351
1352pub fn parse_stmt_block_body<'a, P: Parser<'a>>(
1353    p: &mut P,
1354    allow_directives: bool,
1355    end: Option<&P::Token>,
1356) -> PResult<Vec<Stmt>> {
1357    parse_block_body(p, allow_directives, end, handle_import_export)
1358}
1359
1360pub(super) fn parse_block_body<'a, P: Parser<'a>, Type: IsDirective + From<Stmt>>(
1361    p: &mut P,
1362    allow_directives: bool,
1363    end: Option<&P::Token>,
1364    handle_import_export: impl Fn(&mut P, Vec<Decorator>) -> PResult<Type>,
1365) -> PResult<Vec<Type>> {
1366    trace_cur!(p, parse_block_body);
1367
1368    let mut stmts = Vec::with_capacity(8);
1369
1370    let has_strict_directive = allow_directives
1371        && (p
1372            .input()
1373            .cur()
1374            .is_str_raw_content("\"use strict\"", p.input())
1375            || p.input()
1376                .cur()
1377                .is_str_raw_content("'use strict'", p.input()));
1378
1379    let parse_stmts = |p: &mut P, stmts: &mut Vec<Type>| -> PResult<()> {
1380        let is_stmt_start = |p: &mut P| {
1381            let cur = p.input().cur();
1382            match end {
1383                Some(end) => {
1384                    if cur.is_eof() {
1385                        let eof_text = p.input_mut().dump_cur();
1386                        p.emit_err(
1387                            p.input().cur_span(),
1388                            SyntaxError::Expected(format!("{end:?}"), eof_text),
1389                        );
1390                        false
1391                    } else {
1392                        cur != end
1393                    }
1394                }
1395                None => !cur.is_eof(),
1396            }
1397        };
1398        while is_stmt_start(p) {
1399            let stmt = parse_stmt_like(p, true, &handle_import_export)?;
1400            stmts.push(stmt);
1401        }
1402        Ok(())
1403    };
1404
1405    if has_strict_directive {
1406        p.do_inside_of_context(Context::Strict, |p| parse_stmts(p, &mut stmts))?;
1407    } else {
1408        parse_stmts(p, &mut stmts)?;
1409    };
1410
1411    if !p.input().cur().is_eof() && end.is_some() {
1412        p.bump();
1413    }
1414
1415    Ok(stmts)
1416}