swc_ecma_fast_parser/parser/
stmt.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
//! Statement parser implementation
//!
//! This module contains methods for parsing JavaScript statements.

use swc_common::{Span, Spanned, SyntaxContext};
use swc_ecma_ast::{BlockStmt, ExprStmt, ReturnStmt, Stmt, VarDecl, VarDeclKind, VarDeclarator};

use crate::{error::Result, parser::Parser, token::TokenType};

impl Parser<'_> {
    /// Parse a statement
    pub fn parse_stmt(&mut self) -> Result<Stmt> {
        match self.current_token_type() {
            TokenType::LBrace => self.parse_block_stmt(),
            TokenType::Return => self.parse_return_stmt(),
            TokenType::Var => self.parse_var_decl_stmt(VarDeclKind::Var),
            TokenType::Let => self.parse_var_decl_stmt(VarDeclKind::Let),
            TokenType::Const => self.parse_var_decl_stmt(VarDeclKind::Const),
            // Other statement types will be added here
            _ => self.parse_expr_stmt(),
        }
    }

    /// Parse a block statement
    fn parse_block_stmt(&mut self) -> Result<Stmt> {
        let start_span = self.current_span();
        self.lexer.next_token()?; // Consume '{'

        let mut stmts = Vec::new();

        // Parse statements until we reach '}'
        while !self.is(TokenType::RBrace) {
            let stmt = self.parse_stmt()?;
            stmts.push(stmt);
        }

        let end_span = self.current_span();
        self.lexer.next_token()?; // Consume '}'

        let span = Span::new(start_span.lo, end_span.hi);
        Ok(Stmt::Block(BlockStmt {
            span,
            stmts,
            ctxt: SyntaxContext::empty(),
        }))
    }

    /// Parse a return statement
    fn parse_return_stmt(&mut self) -> Result<Stmt> {
        let start_span = self.current_span();
        self.lexer.next_token()?; // Consume 'return'

        // Check if there's an expression after 'return'
        let arg = if self.is(TokenType::Semi)
            || self.is(TokenType::RBrace)
            || self.is_line_terminator()
        {
            None
        } else {
            Some(self.parse_expr()?)
        };

        // Consume semicolon if present
        if self.is(TokenType::Semi) {
            self.lexer.next_token()?;
        }

        let end_span = match &arg {
            Some(expr) => expr.span(),
            None => start_span,
        };

        let span = Span::new(start_span.lo, end_span.hi);
        Ok(Stmt::Return(ReturnStmt { span, arg }))
    }

    /// Parse an expression statement
    fn parse_expr_stmt(&mut self) -> Result<Stmt> {
        let expr = self.parse_expr()?;
        let span = expr.span();

        // Consume semicolon if present
        if self.is(TokenType::Semi) {
            self.lexer.next_token()?;
        }

        Ok(Stmt::Expr(ExprStmt { span, expr }))
    }

    /// Parse a variable declaration statement
    fn parse_var_decl_stmt(&mut self, kind: VarDeclKind) -> Result<Stmt> {
        let start_span = self.current_span();
        self.lexer.next_token()?; // Consume 'var', 'let', or 'const'

        let mut decls = Vec::new();

        // Parse variable declarations
        loop {
            let decl = self.parse_var_declarator()?;
            decls.push(decl);

            // Check if there are more declarations
            if self.is(TokenType::Comma) {
                self.lexer.next_token()?; // Consume ','
            } else {
                break;
            }
        }

        // Consume semicolon if present
        if self.is(TokenType::Semi) {
            self.lexer.next_token()?;
        }

        let end_span = match decls.last() {
            Some(decl) => match &decl.init {
                Some(init) => init.span(),
                None => decl.name.span(),
            },
            None => start_span,
        };

        let span = Span::new(start_span.lo, end_span.hi);
        Ok(Stmt::Decl(swc_ecma_ast::Decl::Var(Box::new(VarDecl {
            span,
            kind,
            declare: false,
            decls,
            ctxt: SyntaxContext::empty(),
        }))))
    }

    /// Parse a variable declarator
    fn parse_var_declarator(&mut self) -> Result<VarDeclarator> {
        // Parse the variable name (pattern)
        let name = self.parse_pat()?;
        let name_span = name.span();

        // Check if there's an initializer
        let init = if self.is(TokenType::Eq) {
            self.lexer.next_token()?; // Consume '='
            Some(self.parse_expr()?)
        } else {
            None
        };

        let span = match &init {
            Some(expr) => {
                let expr_span = expr.span();
                Span::new(name_span.lo, expr_span.hi)
            }
            None => name_span,
        };

        Ok(VarDeclarator {
            span,
            name,
            init,
            definite: false,
        })
    }

    /// Check if the current token is a line terminator
    fn is_line_terminator(&self) -> bool {
        // In a real implementation, this would check if there's a line terminator
        // between the current token and the previous token
        false
    }
}