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)
}
}
}