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            }
787        }
788        expect!(p, &P::Token::RPAREN);
789        Ok(Some(pat))
790    } else {
791        Ok(None)
792    }
793}
794
795fn parse_do_stmt<'a, P: Parser<'a>>(p: &mut P) -> PResult<Stmt> {
796    let start = p.cur_pos();
797
798    p.assert_and_bump(&P::Token::DO);
799
800    let body = p
801        .do_inside_of_context(
802            Context::IsBreakAllowed.union(Context::IsContinueAllowed),
803            |p| p.do_outside_of_context(Context::TopLevel, parse_stmt),
804        )
805        .map(Box::new)?;
806
807    expect!(p, &P::Token::WHILE);
808    expect!(p, &P::Token::LPAREN);
809
810    let test = p.allow_in_expr(|p| p.parse_expr())?;
811
812    expect!(p, &P::Token::RPAREN);
813
814    // We *may* eat semicolon.
815    let _ = p.eat_general_semi();
816
817    let span = p.span(start);
818
819    Ok(DoWhileStmt { span, test, body }.into())
820}
821
822fn parse_labelled_stmt<'a, P: Parser<'a>>(p: &mut P, l: Ident) -> PResult<Stmt> {
823    p.do_inside_of_context(Context::IsBreakAllowed, |p| {
824        p.do_outside_of_context(Context::AllowUsingDecl, |p| {
825            let start = l.span.lo();
826
827            let mut errors = Vec::new();
828            for lb in &p.state().labels {
829                if l.sym == *lb {
830                    errors.push(Error::new(
831                        l.span,
832                        SyntaxError::DuplicateLabel(l.sym.clone()),
833                    ));
834                }
835            }
836            p.state_mut().labels.push(l.sym.clone());
837
838            let body = Box::new(if p.input().is(&P::Token::FUNCTION) {
839                let f = parse_fn_decl(p, Vec::new())?;
840                if let Decl::Fn(FnDecl { function, .. }) = &f {
841                    if p.ctx().contains(Context::Strict) {
842                        p.emit_err(function.span, SyntaxError::LabelledFunctionInStrict)
843                    }
844                    if function.is_generator || function.is_async {
845                        p.emit_err(function.span, SyntaxError::LabelledGeneratorOrAsync)
846                    }
847                }
848
849                f.into()
850            } else {
851                p.do_outside_of_context(Context::TopLevel, parse_stmt)?
852            });
853
854            for err in errors {
855                p.emit_error(err);
856            }
857
858            {
859                let pos = p.state().labels.iter().position(|v| v == &l.sym);
860                if let Some(pos) = pos {
861                    p.state_mut().labels.remove(pos);
862                }
863            }
864
865            Ok(LabeledStmt {
866                span: p.span(start),
867                label: l,
868                body,
869            }
870            .into())
871        })
872    })
873}
874
875pub fn parse_block<'a, P: Parser<'a>>(p: &mut P, allow_directives: bool) -> PResult<BlockStmt> {
876    let start = p.cur_pos();
877
878    expect!(p, &P::Token::LBRACE);
879
880    let stmts = p.do_outside_of_context(Context::TopLevel, |p| {
881        parse_stmt_block_body(p, allow_directives, Some(&P::Token::RBRACE))
882    })?;
883
884    let span = p.span(start);
885    Ok(BlockStmt {
886        span,
887        stmts,
888        ctxt: Default::default(),
889    })
890}
891
892fn parse_finally_block<'a, P: Parser<'a>>(p: &mut P) -> PResult<Option<BlockStmt>> {
893    Ok(if p.input_mut().eat(&P::Token::FINALLY) {
894        parse_block(p, false).map(Some)?
895    } else {
896        None
897    })
898}
899
900fn parse_catch_clause<'a, P: Parser<'a>>(p: &mut P) -> PResult<Option<CatchClause>> {
901    let start = p.cur_pos();
902    Ok(if p.input_mut().eat(&P::Token::CATCH) {
903        let param = parse_catch_param(p)?;
904        parse_block(p, false)
905            .map(|body| CatchClause {
906                span: p.span(start),
907                param,
908                body,
909            })
910            .map(Some)?
911    } else {
912        None
913    })
914}
915
916fn parse_try_stmt<'a, P: Parser<'a>>(p: &mut P) -> PResult<Stmt> {
917    let start = p.cur_pos();
918    p.assert_and_bump(&P::Token::TRY);
919
920    let block = parse_block(p, false)?;
921
922    let catch_start = p.cur_pos();
923    let handler = parse_catch_clause(p)?;
924    let finalizer = parse_finally_block(p)?;
925
926    if handler.is_none() && finalizer.is_none() {
927        p.emit_err(
928            Span::new_with_checked(catch_start, catch_start),
929            SyntaxError::TS1005,
930        );
931    }
932
933    let span = p.span(start);
934    Ok(TryStmt {
935        span,
936        block,
937        handler,
938        finalizer,
939    }
940    .into())
941}
942
943fn parse_switch_stmt<'a, P: Parser<'a>>(p: &mut P) -> PResult<Stmt> {
944    let switch_start = p.cur_pos();
945
946    p.assert_and_bump(&P::Token::SWITCH);
947
948    expect!(p, &P::Token::LPAREN);
949    let discriminant = p.allow_in_expr(|p| p.parse_expr())?;
950    expect!(p, &P::Token::RPAREN);
951
952    let mut cases = Vec::new();
953    let mut span_of_previous_default = None;
954
955    expect!(p, &P::Token::LBRACE);
956
957    p.do_inside_of_context(Context::IsBreakAllowed, |p| {
958        while {
959            let cur = p.input().cur();
960            cur.is_case() || cur.is_default()
961        } {
962            let mut cons = Vec::new();
963            let is_case = p.input().is(&P::Token::CASE);
964            let case_start = p.cur_pos();
965            p.bump();
966            let test = if is_case {
967                p.allow_in_expr(|p| p.parse_expr()).map(Some)?
968            } else {
969                if let Some(previous) = span_of_previous_default {
970                    syntax_error!(p, SyntaxError::MultipleDefault { previous });
971                }
972                span_of_previous_default = Some(p.span(case_start));
973
974                None
975            };
976            expect!(p, &P::Token::COLON);
977
978            while {
979                let cur = p.input().cur();
980                !(cur.is_case() || cur.is_default() || cur.is_rbrace())
981            } {
982                cons.push(p.do_outside_of_context(Context::TopLevel, parse_stmt_list_item)?);
983            }
984
985            cases.push(SwitchCase {
986                span: Span::new_with_checked(case_start, p.input().prev_span().hi),
987                test,
988                cons,
989            });
990        }
991
992        Ok(())
993    })?;
994
995    // eof or rbrace
996    expect!(p, &P::Token::RBRACE);
997
998    Ok(SwitchStmt {
999        span: p.span(switch_start),
1000        discriminant,
1001        cases,
1002    }
1003    .into())
1004}
1005
1006/// Parse a statement and maybe a declaration.
1007pub fn parse_stmt_list_item<'a>(p: &mut impl Parser<'a>) -> PResult<Stmt> {
1008    trace_cur!(p, parse_stmt_list_item);
1009    parse_stmt_like(p, true, handle_import_export)
1010}
1011
1012/// Parse a statement, declaration or module item.
1013pub fn parse_stmt_like<'a, P: Parser<'a>, Type: IsDirective + From<Stmt>>(
1014    p: &mut P,
1015    include_decl: bool,
1016    handle_import_export: impl Fn(&mut P, Vec<Decorator>) -> PResult<Type>,
1017) -> PResult<Type> {
1018    trace_cur!(p, parse_stmt_like);
1019
1020    debug_tracing!(p, "parse_stmt_like");
1021
1022    let start = p.cur_pos();
1023    let decorators = if p.input().get_cur().token() == &P::Token::AT {
1024        parse_decorators(p, true)?
1025    } else {
1026        vec![]
1027    };
1028
1029    let cur = p.input().cur();
1030    if cur.is_import() || cur.is_export() {
1031        return handle_import_export(p, decorators);
1032    }
1033
1034    p.do_outside_of_context(Context::WillExpectColonForCond, |p| {
1035        p.do_inside_of_context(Context::AllowUsingDecl, |p| {
1036            parse_stmt_internal(p, start, include_decl, decorators)
1037        })
1038    })
1039    .map(From::from)
1040}
1041
1042fn handle_import_export<'a, P: Parser<'a>>(p: &mut P, _: Vec<Decorator>) -> PResult<Stmt> {
1043    let start = p.cur_pos();
1044    if p.input().is(&P::Token::IMPORT) && peek!(p).is_some_and(|peek| peek.is_lparen()) {
1045        let expr = p.parse_expr()?;
1046
1047        p.eat_general_semi();
1048
1049        return Ok(ExprStmt {
1050            span: p.span(start),
1051            expr,
1052        }
1053        .into());
1054    }
1055
1056    if p.input().is(&P::Token::IMPORT) && peek!(p).is_some_and(|peek| peek.is_dot()) {
1057        let expr = p.parse_expr()?;
1058
1059        p.eat_general_semi();
1060
1061        return Ok(ExprStmt {
1062            span: p.span(start),
1063            expr,
1064        }
1065        .into());
1066    }
1067
1068    syntax_error!(p, SyntaxError::ImportExportInScript);
1069}
1070
1071/// `parseStatementContent`
1072fn parse_stmt_internal<'a, P: Parser<'a>>(
1073    p: &mut P,
1074    start: BytePos,
1075    include_decl: bool,
1076    decorators: Vec<Decorator>,
1077) -> PResult<Stmt> {
1078    trace_cur!(p, parse_stmt_internal);
1079
1080    let is_typescript = p.input().syntax().typescript();
1081
1082    if is_typescript
1083        && p.input().is(&P::Token::CONST)
1084        && peek!(p).is_some_and(|peek| peek.is_enum())
1085    {
1086        p.assert_and_bump(&P::Token::CONST);
1087        p.assert_and_bump(&P::Token::ENUM);
1088        return parse_ts_enum_decl(p, start, true)
1089            .map(Decl::from)
1090            .map(Stmt::from);
1091    }
1092
1093    let top_level = p.ctx().contains(Context::TopLevel);
1094
1095    let cur = p.input().cur().clone();
1096
1097    if cur.is_await() && (include_decl || top_level) {
1098        if top_level {
1099            p.mark_found_module_item();
1100            if !p.ctx().contains(Context::CanBeModule) {
1101                p.emit_err(p.input().cur_span(), SyntaxError::TopLevelAwaitInScript);
1102            }
1103        }
1104
1105        if peek!(p).is_some_and(|peek| peek.is_using()) {
1106            let eaten_await = Some(p.input().cur_pos());
1107            p.assert_and_bump(&P::Token::AWAIT);
1108            let v = parse_using_decl(p, start, true)?;
1109            if let Some(v) = v {
1110                return Ok(v.into());
1111            }
1112
1113            let expr = parse_await_expr(p, eaten_await)?;
1114            let expr = p.allow_in_expr(|p| parse_bin_op_recursively(p, expr, 0))?;
1115            p.eat_general_semi();
1116
1117            let span = p.span(start);
1118            return Ok(ExprStmt { span, expr }.into());
1119        }
1120    } else if cur.is_break() || cur.is_continue() {
1121        let is_break = p.input().is(&P::Token::BREAK);
1122        p.bump();
1123        let label = if p.eat_general_semi() {
1124            None
1125        } else {
1126            let i = parse_label_ident(p).map(Some)?;
1127            p.expect_general_semi()?;
1128            i
1129        };
1130        let span = p.span(start);
1131        if is_break {
1132            if label.is_some() && !p.state().labels.contains(&label.as_ref().unwrap().sym) {
1133                p.emit_err(span, SyntaxError::TS1116);
1134            } else if !p.ctx().contains(Context::IsBreakAllowed) {
1135                p.emit_err(span, SyntaxError::TS1105);
1136            }
1137        } else if !p.ctx().contains(Context::IsContinueAllowed) {
1138            p.emit_err(span, SyntaxError::TS1115);
1139        } else if label.is_some() && !p.state().labels.contains(&label.as_ref().unwrap().sym) {
1140            p.emit_err(span, SyntaxError::TS1107);
1141        }
1142        return Ok(if is_break {
1143            BreakStmt { span, label }.into()
1144        } else {
1145            ContinueStmt { span, label }.into()
1146        });
1147    } else if cur.is_debugger() {
1148        p.bump();
1149        p.expect_general_semi()?;
1150        return Ok(DebuggerStmt {
1151            span: p.span(start),
1152        }
1153        .into());
1154    } else if cur.is_do() {
1155        return parse_do_stmt(p);
1156    } else if cur.is_for() {
1157        return parse_for_stmt(p);
1158    } else if cur.is_function() {
1159        if !include_decl {
1160            p.emit_err(p.input().cur_span(), SyntaxError::DeclNotAllowed);
1161        }
1162        return parse_fn_decl(p, decorators).map(Stmt::from);
1163    } else if cur.is_class() {
1164        if !include_decl {
1165            p.emit_err(p.input().cur_span(), SyntaxError::DeclNotAllowed);
1166        }
1167        return parse_class_decl(p, start, start, decorators, false).map(Stmt::from);
1168    } else if cur.is_if() {
1169        return parse_if_stmt(p).map(Stmt::If);
1170    } else if cur.is_return() {
1171        return parse_return_stmt(p);
1172    } else if cur.is_switch() {
1173        return parse_switch_stmt(p);
1174    } else if cur.is_throw() {
1175        return parse_throw_stmt(p);
1176    } else if cur.is_catch() {
1177        // Error recovery
1178        let span = p.input().cur_span();
1179        p.emit_err(span, SyntaxError::TS1005);
1180
1181        let _ = parse_catch_clause(p);
1182        let _ = parse_finally_block(p);
1183
1184        return Ok(ExprStmt {
1185            span,
1186            expr: Invalid { span }.into(),
1187        }
1188        .into());
1189    } else if cur.is_finally() {
1190        // Error recovery
1191        let span = p.input().cur_span();
1192        p.emit_err(span, SyntaxError::TS1005);
1193
1194        let _ = parse_finally_block(p);
1195
1196        return Ok(ExprStmt {
1197            span,
1198            expr: Invalid { span }.into(),
1199        }
1200        .into());
1201    } else if cur.is_try() {
1202        return parse_try_stmt(p);
1203    } else if cur.is_with() {
1204        return parse_with_stmt(p);
1205    } else if cur.is_while() {
1206        return parse_while_stmt(p);
1207    } else if cur.is_var() || (cur.is_const() && include_decl) {
1208        let v = parse_var_stmt(p, false)?;
1209        return Ok(v.into());
1210    } else if cur.is_let() && include_decl {
1211        // 'let' can start an identifier reference.
1212        let is_keyword = match peek!(p) {
1213            Some(t) => t.follows_keyword_let(),
1214            _ => false,
1215        };
1216
1217        if is_keyword {
1218            let v = parse_var_stmt(p, false)?;
1219            return Ok(v.into());
1220        }
1221    } else if cur.is_using() && include_decl {
1222        let v = parse_using_decl(p, start, false)?;
1223        if let Some(v) = v {
1224            return Ok(v.into());
1225        }
1226    } else if cur.is_interface()
1227        && is_typescript
1228        && peek!(p).is_some_and(|peek| peek.is_word())
1229        && !p.input_mut().has_linebreak_between_cur_and_peeked()
1230    {
1231        let start = p.input().cur_pos();
1232        p.bump();
1233        return Ok(parse_ts_interface_decl(p, start)?.into());
1234    } else if cur.is_type()
1235        && is_typescript
1236        && peek!(p).is_some_and(|peek| peek.is_word())
1237        && !p.input_mut().has_linebreak_between_cur_and_peeked()
1238    {
1239        let start = p.input().cur_pos();
1240        p.bump();
1241        return Ok(parse_ts_type_alias_decl(p, start)?.into());
1242    } else if cur.is_enum()
1243        && is_typescript
1244        && peek!(p).is_some_and(|peek| peek.is_word())
1245        && !p.input_mut().has_linebreak_between_cur_and_peeked()
1246    {
1247        let start = p.input().cur_pos();
1248        p.bump();
1249        return Ok(parse_ts_enum_decl(p, start, false)?.into());
1250    } else if cur.is_lbrace() {
1251        return p
1252            .do_inside_of_context(Context::AllowUsingDecl, |p| parse_block(p, false))
1253            .map(Stmt::Block);
1254    } else if cur.is_semi() {
1255        p.bump();
1256        return Ok(EmptyStmt {
1257            span: p.span(start),
1258        }
1259        .into());
1260    }
1261
1262    // Handle async function foo() {}
1263    if p.input().is(&P::Token::ASYNC)
1264        && peek!(p).is_some_and(|peek| peek.is_function())
1265        && !p.input_mut().has_linebreak_between_cur_and_peeked()
1266    {
1267        return parse_async_fn_decl(p, decorators).map(From::from);
1268    }
1269
1270    // If the statement does not start with a statement keyword or a
1271    // brace, it's an ExpressionStatement or LabeledStatement. We
1272    // simply start parsing an expression, and afterwards, if the
1273    // next token is a colon and the expression was a simple
1274    // Identifier node, we switch to interpreting it as a label.
1275    let expr = p.allow_in_expr(|p| p.parse_expr())?;
1276
1277    let expr = match *expr {
1278        Expr::Ident(ident) => {
1279            if p.input_mut().eat(&P::Token::COLON) {
1280                return parse_labelled_stmt(p, ident);
1281            }
1282            ident.into()
1283        }
1284        _ => p.verify_expr(expr)?,
1285    };
1286    if let Expr::Ident(ref ident) = *expr {
1287        if &*ident.sym == "interface" && p.input().had_line_break_before_cur() {
1288            p.emit_strict_mode_err(
1289                ident.span,
1290                SyntaxError::InvalidIdentInStrict(ident.sym.clone()),
1291            );
1292
1293            p.eat_general_semi();
1294
1295            return Ok(ExprStmt {
1296                span: p.span(start),
1297                expr,
1298            }
1299            .into());
1300        }
1301
1302        if p.input().syntax().typescript() {
1303            if let Some(decl) = parse_ts_expr_stmt(p, decorators, ident.clone())? {
1304                return Ok(decl.into());
1305            }
1306        }
1307    }
1308
1309    if p.syntax().typescript() {
1310        if let Expr::Ident(ref i) = *expr {
1311            match &*i.sym {
1312                "public" | "static" | "abstract" => {
1313                    if p.input_mut().eat(&P::Token::INTERFACE) {
1314                        p.emit_err(i.span, SyntaxError::TS2427);
1315                        return parse_ts_interface_decl(p, start)
1316                            .map(Decl::from)
1317                            .map(Stmt::from);
1318                    }
1319                }
1320                _ => {}
1321            }
1322        }
1323    }
1324
1325    if p.eat_general_semi() {
1326        Ok(ExprStmt {
1327            span: p.span(start),
1328            expr,
1329        }
1330        .into())
1331    } else {
1332        let cur = p.input().cur();
1333        if cur.is_bin_op() {
1334            p.emit_err(p.input().cur_span(), SyntaxError::TS1005);
1335            let expr = parse_bin_op_recursively(p, expr, 0)?;
1336            return Ok(ExprStmt {
1337                span: p.span(start),
1338                expr,
1339            }
1340            .into());
1341        }
1342
1343        syntax_error!(
1344            p,
1345            SyntaxError::ExpectedSemiForExprStmt { expr: expr.span() }
1346        );
1347    }
1348}
1349
1350pub fn parse_stmt_block_body<'a, P: Parser<'a>>(
1351    p: &mut P,
1352    allow_directives: bool,
1353    end: Option<&P::Token>,
1354) -> PResult<Vec<Stmt>> {
1355    parse_block_body(p, allow_directives, end, handle_import_export)
1356}
1357
1358pub(super) fn parse_block_body<'a, P: Parser<'a>, Type: IsDirective + From<Stmt>>(
1359    p: &mut P,
1360    allow_directives: bool,
1361    end: Option<&P::Token>,
1362    handle_import_export: impl Fn(&mut P, Vec<Decorator>) -> PResult<Type>,
1363) -> PResult<Vec<Type>> {
1364    trace_cur!(p, parse_block_body);
1365
1366    let mut stmts = Vec::with_capacity(8);
1367
1368    let has_strict_directive = allow_directives
1369        && (p
1370            .input()
1371            .cur()
1372            .is_str_raw_content("\"use strict\"", p.input())
1373            || p.input()
1374                .cur()
1375                .is_str_raw_content("'use strict'", p.input()));
1376
1377    let parse_stmts = |p: &mut P, stmts: &mut Vec<Type>| -> PResult<()> {
1378        let is_stmt_start = |p: &mut P| {
1379            let cur = p.input().cur();
1380            match end {
1381                Some(end) => {
1382                    if cur.is_eof() {
1383                        let eof_text = p.input_mut().dump_cur();
1384                        p.emit_err(
1385                            p.input().cur_span(),
1386                            SyntaxError::Expected(format!("{end:?}"), eof_text),
1387                        );
1388                        false
1389                    } else {
1390                        cur != end
1391                    }
1392                }
1393                None => !cur.is_eof(),
1394            }
1395        };
1396        while is_stmt_start(p) {
1397            let stmt = parse_stmt_like(p, true, &handle_import_export)?;
1398            stmts.push(stmt);
1399        }
1400        Ok(())
1401    };
1402
1403    if has_strict_directive {
1404        p.do_inside_of_context(Context::Strict, |p| parse_stmts(p, &mut stmts))?;
1405    } else {
1406        parse_stmts(p, &mut stmts)?;
1407    };
1408
1409    if !p.input().cur().is_eof() && end.is_some() {
1410        p.bump();
1411    }
1412
1413    Ok(stmts)
1414}