swc_ecma_fast_parser/parser/
mod.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
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
//! High-performance parser for ECMAScript/TypeScript
//!
//! This parser is designed for maximum performance and memory efficiency,
//! operating at the token level for optimal throughput.

#![allow(clippy::redundant_closure_call)]

mod expr;
mod pat;
mod stmt;
#[cfg(test)]
mod tests;
mod util;

use std::rc::Rc;

use swc_atoms::Atom;
use swc_common::Span;
use swc_ecma_ast::{Module, ModuleItem, Program, Script, Stmt};

use crate::{
    error::{Error, ErrorKind, Result},
    lexer::Lexer,
    token::{Token, TokenType},
    JscTarget, SingleThreadedComments, Syntax,
};

/// High-performance parser for ECMAScript/TypeScript
///
/// This parser processes tokens from the lexer to build an AST.
#[repr(C)] // Ensure predictable memory layout
pub struct Parser<'a> {
    /// Lexer instance
    lexer: Lexer<'a>,

    /// Syntax configuration
    pub syntax: Syntax,

    /// Target ECMAScript version
    pub target: JscTarget,

    /// Whether the parser is in strict mode
    pub strict_mode: bool,

    /// Whether the parser is in module mode
    pub is_module: bool,

    /// Whether the parser is in a function context
    pub in_function: bool,

    /// Whether the parser is in a generator function
    pub in_generator: bool,

    /// Whether the parser is in an async function
    pub in_async: bool,

    /// Whether the parser is in a loop
    pub in_loop: bool,

    /// Whether the parser is in a switch statement
    pub in_switch: bool,

    /// Whether the parser is in a class context
    pub in_class: bool,

    /// Whether the parser is in a static block
    pub in_static_block: bool,

    /// Label set for break/continue statements
    pub labels: Vec<Atom>,

    /// Comments storage
    pub comments: Option<Rc<SingleThreadedComments>>,
}

impl<'a> Parser<'a> {
    /// Create a new parser from a string input
    #[inline]
    pub fn new(
        input: &'a str,
        target: JscTarget,
        syntax: Syntax,
        is_module: bool,
        comments: Option<Rc<SingleThreadedComments>>,
    ) -> Self {
        let lexer = Lexer::new(input, target, syntax, comments.clone());

        Self {
            lexer,
            syntax,
            target,
            strict_mode: is_module, // Modules are always in strict mode
            is_module,
            in_function: false,
            in_generator: false,
            in_async: false,
            in_loop: false,
            in_switch: false,
            in_class: false,
            in_static_block: false,
            labels: Vec::new(),
            comments,
        }
    }

    /// Parse a complete program (script or module)
    pub fn parse_program(&mut self) -> Result<Program> {
        if self.is_module {
            let module = self.parse_module()?;
            Ok(Program::Module(module))
        } else {
            let script = self.parse_script()?;
            Ok(Program::Script(script))
        }
    }

    /// Parse a script
    fn parse_script(&mut self) -> Result<Script> {
        let span_start = self.current_span().lo;
        let body = self.parse_statements()?;
        let span = Span::new(span_start, self.current_span().hi);

        Ok(Script {
            span,
            body,
            shebang: None, // TODO: Handle shebang
        })
    }

    /// Parse a module
    fn parse_module(&mut self) -> Result<Module> {
        let span_start = self.current_span().lo;
        let body = self.parse_module_items()?;
        let span = Span::new(span_start, self.current_span().hi);

        Ok(Module {
            span,
            body,
            shebang: None, // TODO: Handle shebang
        })
    }

    /// Parse statements until end of input or closing brace
    fn parse_statements(&mut self) -> Result<Vec<Stmt>> {
        let mut stmts = Vec::new();

        while !self.is(TokenType::EOF) && !self.is(TokenType::RBrace) {
            let stmt = self.parse_stmt()?;
            stmts.push(stmt);
        }

        Ok(stmts)
    }

    /// Parse module items until end of input
    fn parse_module_items(&mut self) -> Result<Vec<ModuleItem>> {
        let mut items = Vec::new();

        while !self.is(TokenType::EOF) {
            // For now, just parse statements as module items
            // TODO: Add support for import/export declarations
            let stmt = self.parse_stmt()?;
            items.push(ModuleItem::Stmt(stmt));
        }

        Ok(items)
    }

    /// Get the current token
    #[inline(always)]
    pub fn current(&self) -> &Token {
        &self.lexer.current
    }

    /// Get the current token type
    #[inline(always)]
    pub fn current_token_type(&self) -> TokenType {
        self.lexer.current.token_type
    }

    /// Get the current token span
    #[inline(always)]
    pub fn current_span(&self) -> Span {
        self.lexer.current.span
    }

    /// Check if the current token is of the specified type
    #[inline(always)]
    pub fn is(&self, token_type: TokenType) -> bool {
        self.current_token_type() == token_type
    }

    /// Check if the current token is one of the specified types
    #[inline(always)]
    pub fn is_one_of(&self, token_types: &[TokenType]) -> bool {
        token_types.contains(&self.current_token_type())
    }

    /// Expect a specific token type and advance to the next token
    #[inline]
    pub fn expect(&mut self, token_type: TokenType) -> Result<()> {
        if self.is(token_type) {
            self.lexer.next_token()?;
            Ok(())
        } else {
            let span = self.current_span();
            Err(Error {
                kind: ErrorKind::UnexpectedToken {
                    expected: Some(token_type.as_str()),
                    got: self.current_token_type().as_str().to_string(),
                },
                span,
            })
        }
    }

    /// Consume the current token if it matches the specified type
    #[inline]
    pub fn eat(&mut self, token_type: TokenType) -> Result<bool> {
        if self.is(token_type) {
            self.lexer.next_token()?;
            Ok(true)
        } else {
            Ok(false)
        }
    }
}