we (web engine): Experimental web browser project to understand the limits of Claude
2
fork

Configure Feed

Select the types of activity you want to include in your feed.

Implement JS parser: AST and expression/statement parsing

Add a recursive-descent JavaScript parser with Pratt expression parsing
for ECMAScript 2024. Transforms the token stream from the lexer into an
Abstract Syntax Tree.

AST node types cover:
- All expression types (literals, binary, unary, assignment, member access,
call, new, arrow functions, template literals, spread, yield, await)
- All statement types (if, for/for-in/for-of, while, do-while, switch,
try/catch/finally, return, throw, break, continue, labeled, with)
- Variable declarations (var/let/const) with destructuring patterns
- Function declarations (sync, async, generators)
- Class declarations (constructor, methods, getters/setters, static)
- Import/export declarations (default, named, namespace, re-export)

Features:
- Operator precedence via Pratt parsing with binding power table
- Automatic Semicolon Insertion (ASI) using lexer newline tracking
- Arrow function detection with expression-to-pattern reinterpretation
- Destructuring patterns (array, object, default values, rest)
- for-in/for-of disambiguation with allow_in flag
- 73 unit tests covering all grammar productions and error cases

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>

+4070
+504
crates/js/src/ast.rs
··· 1 + //! Abstract Syntax Tree node types for ECMAScript 2024. 2 + 3 + use crate::lexer::Span; 4 + 5 + /// A complete JavaScript program. 6 + #[derive(Debug, Clone, PartialEq)] 7 + pub struct Program { 8 + pub body: Vec<Stmt>, 9 + pub source_type: SourceType, 10 + pub span: Span, 11 + } 12 + 13 + /// Whether the program is a script or module. 14 + #[derive(Debug, Clone, Copy, PartialEq, Eq)] 15 + pub enum SourceType { 16 + Script, 17 + Module, 18 + } 19 + 20 + // ── Statements ────────────────────────────────────────────── 21 + 22 + /// A statement or declaration. 23 + #[derive(Debug, Clone, PartialEq)] 24 + pub struct Stmt { 25 + pub kind: StmtKind, 26 + pub span: Span, 27 + } 28 + 29 + #[derive(Debug, Clone, PartialEq)] 30 + pub enum StmtKind { 31 + /// Expression followed by semicolon. 32 + Expr(Expr), 33 + /// `{ ... }` 34 + Block(Vec<Stmt>), 35 + /// `var`/`let`/`const` declaration. 36 + VarDecl { 37 + kind: VarKind, 38 + declarators: Vec<VarDeclarator>, 39 + }, 40 + /// `function name(...) { ... }` 41 + FunctionDecl(FunctionDef), 42 + /// `class Name { ... }` 43 + ClassDecl(ClassDef), 44 + /// `if (test) consequent else alternate` 45 + If { 46 + test: Expr, 47 + consequent: Box<Stmt>, 48 + alternate: Option<Box<Stmt>>, 49 + }, 50 + /// `for (init; test; update) body` 51 + For { 52 + init: Option<ForInit>, 53 + test: Option<Expr>, 54 + update: Option<Expr>, 55 + body: Box<Stmt>, 56 + }, 57 + /// `for (left in right) body` 58 + ForIn { 59 + left: ForInOfLeft, 60 + right: Expr, 61 + body: Box<Stmt>, 62 + }, 63 + /// `for (left of right) body` 64 + ForOf { 65 + left: ForInOfLeft, 66 + right: Expr, 67 + body: Box<Stmt>, 68 + is_await: bool, 69 + }, 70 + /// `while (test) body` 71 + While { test: Expr, body: Box<Stmt> }, 72 + /// `do body while (test)` 73 + DoWhile { body: Box<Stmt>, test: Expr }, 74 + /// `switch (discriminant) { cases }` 75 + Switch { 76 + discriminant: Expr, 77 + cases: Vec<SwitchCase>, 78 + }, 79 + /// `try { block } catch (param) { handler } finally { finalizer }` 80 + Try { 81 + block: Vec<Stmt>, 82 + handler: Option<CatchClause>, 83 + finalizer: Option<Vec<Stmt>>, 84 + }, 85 + /// `return expr;` 86 + Return(Option<Expr>), 87 + /// `throw expr;` 88 + Throw(Expr), 89 + /// `break label;` 90 + Break(Option<String>), 91 + /// `continue label;` 92 + Continue(Option<String>), 93 + /// `label: stmt` 94 + Labeled { label: String, body: Box<Stmt> }, 95 + /// `with (object) body` 96 + With { object: Expr, body: Box<Stmt> }, 97 + /// `debugger;` 98 + Debugger, 99 + /// `;` 100 + Empty, 101 + /// `import` declaration. 102 + Import { 103 + specifiers: Vec<ImportSpecifier>, 104 + source: String, 105 + }, 106 + /// `export` declaration. 107 + Export(ExportDecl), 108 + } 109 + 110 + // ── Variable declarations ─────────────────────────────────── 111 + 112 + #[derive(Debug, Clone, Copy, PartialEq, Eq)] 113 + pub enum VarKind { 114 + Var, 115 + Let, 116 + Const, 117 + } 118 + 119 + #[derive(Debug, Clone, PartialEq)] 120 + pub struct VarDeclarator { 121 + pub pattern: Pattern, 122 + pub init: Option<Expr>, 123 + pub span: Span, 124 + } 125 + 126 + // ── For-statement helpers ─────────────────────────────────── 127 + 128 + #[derive(Debug, Clone, PartialEq)] 129 + pub enum ForInit { 130 + VarDecl { 131 + kind: VarKind, 132 + declarators: Vec<VarDeclarator>, 133 + }, 134 + Expr(Expr), 135 + } 136 + 137 + #[derive(Debug, Clone, PartialEq)] 138 + pub enum ForInOfLeft { 139 + VarDecl { kind: VarKind, pattern: Pattern }, 140 + Pattern(Pattern), 141 + } 142 + 143 + // ── Switch / Try helpers ──────────────────────────────────── 144 + 145 + #[derive(Debug, Clone, PartialEq)] 146 + pub struct SwitchCase { 147 + /// `None` for `default:`. 148 + pub test: Option<Expr>, 149 + pub consequent: Vec<Stmt>, 150 + pub span: Span, 151 + } 152 + 153 + #[derive(Debug, Clone, PartialEq)] 154 + pub struct CatchClause { 155 + pub param: Option<Pattern>, 156 + pub body: Vec<Stmt>, 157 + pub span: Span, 158 + } 159 + 160 + // ── Import / Export ───────────────────────────────────────── 161 + 162 + #[derive(Debug, Clone, PartialEq)] 163 + pub enum ImportSpecifier { 164 + /// `import defaultExport from "mod"` 165 + Default(String), 166 + /// `import { foo } from "mod"` or `import { foo as bar } from "mod"` 167 + Named { imported: String, local: String }, 168 + /// `import * as ns from "mod"` 169 + Namespace(String), 170 + } 171 + 172 + #[derive(Debug, Clone, PartialEq)] 173 + pub enum ExportDecl { 174 + /// `export default expr` 175 + Default(Expr), 176 + /// `export function/class/var ...` 177 + Declaration(Box<Stmt>), 178 + /// `export { a, b as c }` 179 + Named { 180 + specifiers: Vec<ExportSpecifier>, 181 + source: Option<String>, 182 + }, 183 + /// `export * from "mod"` 184 + AllFrom(String), 185 + } 186 + 187 + #[derive(Debug, Clone, PartialEq)] 188 + pub struct ExportSpecifier { 189 + pub local: String, 190 + pub exported: String, 191 + } 192 + 193 + // ── Expressions ───────────────────────────────────────────── 194 + 195 + #[derive(Debug, Clone, PartialEq)] 196 + pub struct Expr { 197 + pub kind: ExprKind, 198 + pub span: Span, 199 + } 200 + 201 + #[derive(Debug, Clone, PartialEq)] 202 + pub enum ExprKind { 203 + /// Numeric literal. 204 + Number(f64), 205 + /// String literal. 206 + String(String), 207 + /// `true` / `false`. 208 + Bool(bool), 209 + /// `null`. 210 + Null, 211 + /// An identifier reference. 212 + Identifier(String), 213 + /// `this`. 214 + This, 215 + /// `[a, b, c]` 216 + Array(Vec<Option<ArrayElement>>), 217 + /// `{ key: value, ... }` 218 + Object(Vec<Property>), 219 + /// `function name(...) { ... }` expression. 220 + Function(FunctionDef), 221 + /// `(...) => body` 222 + Arrow { 223 + params: Vec<Pattern>, 224 + body: ArrowBody, 225 + is_async: bool, 226 + }, 227 + /// `class Name { ... }` expression. 228 + Class(ClassDef), 229 + /// Prefix unary (`!x`, `-x`, `~x`, `typeof x`, `void x`, `delete x`). 230 + Unary { op: UnaryOp, argument: Box<Expr> }, 231 + /// `++x`, `--x`, `x++`, `x--`. 232 + Update { 233 + op: UpdateOp, 234 + argument: Box<Expr>, 235 + prefix: bool, 236 + }, 237 + /// `a + b`, `a * b`, etc. 238 + Binary { 239 + op: BinaryOp, 240 + left: Box<Expr>, 241 + right: Box<Expr>, 242 + }, 243 + /// `a && b`, `a || b`, `a ?? b`. 244 + Logical { 245 + op: LogicalOp, 246 + left: Box<Expr>, 247 + right: Box<Expr>, 248 + }, 249 + /// `a = b`, `a += b`, etc. 250 + Assignment { 251 + op: AssignOp, 252 + left: Box<Expr>, 253 + right: Box<Expr>, 254 + }, 255 + /// `test ? consequent : alternate` 256 + Conditional { 257 + test: Box<Expr>, 258 + consequent: Box<Expr>, 259 + alternate: Box<Expr>, 260 + }, 261 + /// `callee(arguments)` 262 + Call { 263 + callee: Box<Expr>, 264 + arguments: Vec<Expr>, 265 + }, 266 + /// `new callee(arguments)` 267 + New { 268 + callee: Box<Expr>, 269 + arguments: Vec<Expr>, 270 + }, 271 + /// `object.property` or `object[property]` 272 + Member { 273 + object: Box<Expr>, 274 + property: Box<Expr>, 275 + computed: bool, 276 + }, 277 + /// `obj?.prop`, `obj?.[expr]`, `fn?.(args)` 278 + OptionalChain { base: Box<Expr> }, 279 + /// Template literal: `` `hello ${name}` `` 280 + TemplateLiteral { 281 + quasis: Vec<String>, 282 + expressions: Vec<Expr>, 283 + }, 284 + /// Tagged template: `` tag`string` `` 285 + TaggedTemplate { tag: Box<Expr>, quasi: Box<Expr> }, 286 + /// `a, b, c` 287 + Sequence(Vec<Expr>), 288 + /// `...expr` 289 + Spread(Box<Expr>), 290 + /// `yield expr` / `yield* expr` 291 + Yield { 292 + argument: Option<Box<Expr>>, 293 + delegate: bool, 294 + }, 295 + /// `await expr` 296 + Await(Box<Expr>), 297 + /// `/pattern/flags` 298 + RegExp { pattern: String, flags: String }, 299 + } 300 + 301 + // ── Array element ─────────────────────────────────────────── 302 + 303 + #[derive(Debug, Clone, PartialEq)] 304 + pub enum ArrayElement { 305 + Expr(Expr), 306 + Spread(Expr), 307 + } 308 + 309 + // ── Object literal ────────────────────────────────────────── 310 + 311 + #[derive(Debug, Clone, PartialEq)] 312 + pub struct Property { 313 + pub key: PropertyKey, 314 + pub value: Option<Expr>, 315 + pub kind: PropertyKind, 316 + pub computed: bool, 317 + pub shorthand: bool, 318 + pub method: bool, 319 + pub span: Span, 320 + } 321 + 322 + #[derive(Debug, Clone, PartialEq)] 323 + pub enum PropertyKey { 324 + Identifier(String), 325 + String(String), 326 + Number(f64), 327 + Computed(Expr), 328 + } 329 + 330 + #[derive(Debug, Clone, Copy, PartialEq, Eq)] 331 + pub enum PropertyKind { 332 + Init, 333 + Get, 334 + Set, 335 + } 336 + 337 + // ── Arrow function body ───────────────────────────────────── 338 + 339 + #[derive(Debug, Clone, PartialEq)] 340 + pub enum ArrowBody { 341 + Expr(Box<Expr>), 342 + Block(Vec<Stmt>), 343 + } 344 + 345 + // ── Function definition ───────────────────────────────────── 346 + 347 + #[derive(Debug, Clone, PartialEq)] 348 + pub struct FunctionDef { 349 + pub id: Option<String>, 350 + pub params: Vec<Pattern>, 351 + pub body: Vec<Stmt>, 352 + pub is_async: bool, 353 + pub is_generator: bool, 354 + } 355 + 356 + // ── Class definition ──────────────────────────────────────── 357 + 358 + #[derive(Debug, Clone, PartialEq)] 359 + pub struct ClassDef { 360 + pub id: Option<String>, 361 + pub super_class: Option<Box<Expr>>, 362 + pub body: Vec<ClassMember>, 363 + } 364 + 365 + #[derive(Debug, Clone, PartialEq)] 366 + pub struct ClassMember { 367 + pub kind: ClassMemberKind, 368 + pub span: Span, 369 + } 370 + 371 + #[derive(Debug, Clone, PartialEq)] 372 + pub enum ClassMemberKind { 373 + Method { 374 + key: PropertyKey, 375 + value: FunctionDef, 376 + kind: MethodKind, 377 + is_static: bool, 378 + computed: bool, 379 + }, 380 + Property { 381 + key: PropertyKey, 382 + value: Option<Expr>, 383 + is_static: bool, 384 + computed: bool, 385 + }, 386 + } 387 + 388 + #[derive(Debug, Clone, Copy, PartialEq, Eq)] 389 + pub enum MethodKind { 390 + Method, 391 + Get, 392 + Set, 393 + Constructor, 394 + } 395 + 396 + // ── Patterns (destructuring) ──────────────────────────────── 397 + 398 + #[derive(Debug, Clone, PartialEq)] 399 + pub struct Pattern { 400 + pub kind: PatternKind, 401 + pub span: Span, 402 + } 403 + 404 + #[derive(Debug, Clone, PartialEq)] 405 + pub enum PatternKind { 406 + /// Simple binding: `x` 407 + Identifier(String), 408 + /// Array destructuring: `[a, b, ...rest]` 409 + Array { 410 + elements: Vec<Option<Pattern>>, 411 + rest: Option<Box<Pattern>>, 412 + }, 413 + /// Object destructuring: `{ a, b: c, ...rest }` 414 + Object { 415 + properties: Vec<ObjectPatternProp>, 416 + rest: Option<Box<Pattern>>, 417 + }, 418 + /// Default value: `x = defaultValue` 419 + Assign { 420 + left: Box<Pattern>, 421 + right: Box<Expr>, 422 + }, 423 + } 424 + 425 + #[derive(Debug, Clone, PartialEq)] 426 + pub struct ObjectPatternProp { 427 + pub key: PropertyKey, 428 + pub value: Pattern, 429 + pub computed: bool, 430 + pub shorthand: bool, 431 + pub span: Span, 432 + } 433 + 434 + // ── Operators ─────────────────────────────────────────────── 435 + 436 + #[derive(Debug, Clone, Copy, PartialEq, Eq)] 437 + pub enum UnaryOp { 438 + Minus, 439 + Plus, 440 + Not, 441 + BitwiseNot, 442 + Typeof, 443 + Void, 444 + Delete, 445 + } 446 + 447 + #[derive(Debug, Clone, Copy, PartialEq, Eq)] 448 + pub enum UpdateOp { 449 + Increment, 450 + Decrement, 451 + } 452 + 453 + #[derive(Debug, Clone, Copy, PartialEq, Eq)] 454 + pub enum BinaryOp { 455 + Add, 456 + Sub, 457 + Mul, 458 + Div, 459 + Rem, 460 + Exp, 461 + Eq, 462 + Ne, 463 + StrictEq, 464 + StrictNe, 465 + Lt, 466 + Le, 467 + Gt, 468 + Ge, 469 + Shl, 470 + Shr, 471 + Ushr, 472 + BitAnd, 473 + BitOr, 474 + BitXor, 475 + In, 476 + Instanceof, 477 + } 478 + 479 + #[derive(Debug, Clone, Copy, PartialEq, Eq)] 480 + pub enum LogicalOp { 481 + And, 482 + Or, 483 + Nullish, 484 + } 485 + 486 + #[derive(Debug, Clone, Copy, PartialEq, Eq)] 487 + pub enum AssignOp { 488 + Assign, 489 + AddAssign, 490 + SubAssign, 491 + MulAssign, 492 + DivAssign, 493 + RemAssign, 494 + ExpAssign, 495 + ShlAssign, 496 + ShrAssign, 497 + UshrAssign, 498 + BitAndAssign, 499 + BitOrAssign, 500 + BitXorAssign, 501 + AndAssign, 502 + OrAssign, 503 + NullishAssign, 504 + }
+2
crates/js/src/lib.rs
··· 1 1 //! JavaScript engine — lexer, parser, bytecode, register VM, GC, JIT (AArch64). 2 2 3 + pub mod ast; 3 4 pub mod lexer; 5 + pub mod parser; 4 6 5 7 use std::fmt; 6 8
+3564
crates/js/src/parser.rs
··· 1 + //! Recursive-descent JavaScript parser with Pratt expression parsing. 2 + //! 3 + //! Transforms a token stream from the [`crate::lexer::Lexer`] into an 4 + //! [`crate::ast::Program`] AST. 5 + 6 + use crate::ast::*; 7 + use crate::lexer::{LexError, Lexer, SourcePos, Span, Token, TokenKind}; 8 + use std::fmt; 9 + 10 + // ── Error ─────────────────────────────────────────────────── 11 + 12 + /// An error produced during parsing. 13 + #[derive(Debug, Clone, PartialEq)] 14 + pub struct ParseError { 15 + pub message: String, 16 + pub pos: SourcePos, 17 + } 18 + 19 + impl fmt::Display for ParseError { 20 + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 21 + write!( 22 + f, 23 + "ParseError at {}:{}: {}", 24 + self.pos.line, self.pos.col, self.message 25 + ) 26 + } 27 + } 28 + 29 + impl From<LexError> for ParseError { 30 + fn from(e: LexError) -> Self { 31 + ParseError { 32 + message: e.message, 33 + pos: e.pos, 34 + } 35 + } 36 + } 37 + 38 + // ── Parser ────────────────────────────────────────────────── 39 + 40 + pub struct Parser { 41 + tokens: Vec<Token>, 42 + pos: usize, 43 + /// When false, `in` is not treated as a binary operator (for-init disambiguation). 44 + allow_in: bool, 45 + } 46 + 47 + impl Parser { 48 + /// Parse source as a script. 49 + pub fn parse(source: &str) -> Result<Program, ParseError> { 50 + let tokens = Lexer::tokenize(source)?; 51 + let mut parser = Parser { 52 + tokens, 53 + pos: 0, 54 + allow_in: true, 55 + }; 56 + parser.parse_program(SourceType::Script) 57 + } 58 + 59 + /// Parse source as a module. 60 + pub fn parse_module(source: &str) -> Result<Program, ParseError> { 61 + let tokens = Lexer::tokenize(source)?; 62 + let mut parser = Parser { 63 + tokens, 64 + pos: 0, 65 + allow_in: true, 66 + }; 67 + parser.parse_program(SourceType::Module) 68 + } 69 + 70 + // ── Token navigation ──────────────────────────────────── 71 + 72 + fn peek(&self) -> &Token { 73 + &self.tokens[self.pos.min(self.tokens.len() - 1)] 74 + } 75 + 76 + fn peek_kind(&self) -> &TokenKind { 77 + &self.peek().kind 78 + } 79 + 80 + fn peek_ahead(&self, offset: usize) -> &TokenKind { 81 + let idx = (self.pos + offset).min(self.tokens.len() - 1); 82 + &self.tokens[idx].kind 83 + } 84 + 85 + fn at(&self, kind: &TokenKind) -> bool { 86 + std::mem::discriminant(self.peek_kind()) == std::mem::discriminant(kind) 87 + } 88 + 89 + fn at_eof(&self) -> bool { 90 + matches!(self.peek_kind(), TokenKind::Eof) 91 + } 92 + 93 + fn advance(&mut self) -> Token { 94 + let tok = self.tokens[self.pos.min(self.tokens.len() - 1)].clone(); 95 + if self.pos < self.tokens.len() - 1 { 96 + self.pos += 1; 97 + } 98 + tok 99 + } 100 + 101 + fn eat(&mut self, kind: &TokenKind) -> bool { 102 + if self.at(kind) { 103 + self.advance(); 104 + true 105 + } else { 106 + false 107 + } 108 + } 109 + 110 + fn expect(&mut self, kind: &TokenKind) -> Result<Token, ParseError> { 111 + if self.at(kind) { 112 + Ok(self.advance()) 113 + } else { 114 + Err(self.error(format!("expected {:?}, found {:?}", kind, self.peek_kind()))) 115 + } 116 + } 117 + 118 + fn expect_semicolon(&mut self) -> Result<(), ParseError> { 119 + if self.eat(&TokenKind::Semicolon) { 120 + return Ok(()); 121 + } 122 + // ASI: insert semicolon before `}`, at EOF, or after newline 123 + if matches!(self.peek_kind(), TokenKind::RBrace | TokenKind::Eof) 124 + || self.peek().preceded_by_newline 125 + { 126 + return Ok(()); 127 + } 128 + Err(self.error(format!("expected `;`, found {:?}", self.peek_kind()))) 129 + } 130 + 131 + fn expect_identifier(&mut self) -> Result<String, ParseError> { 132 + match self.peek_kind().clone() { 133 + TokenKind::Identifier(name) => { 134 + self.advance(); 135 + Ok(name) 136 + } 137 + _ => Err(self.error(format!("expected identifier, found {:?}", self.peek_kind()))), 138 + } 139 + } 140 + 141 + fn start_span(&self) -> SourcePos { 142 + self.peek().span.start 143 + } 144 + 145 + fn end_span(&self) -> SourcePos { 146 + if self.pos > 0 { 147 + self.tokens[self.pos - 1].span.end 148 + } else { 149 + self.peek().span.start 150 + } 151 + } 152 + 153 + fn span_from(&self, start: SourcePos) -> Span { 154 + Span { 155 + start, 156 + end: self.end_span(), 157 + } 158 + } 159 + 160 + fn error(&self, message: String) -> ParseError { 161 + ParseError { 162 + message, 163 + pos: self.peek().span.start, 164 + } 165 + } 166 + 167 + // ── Program ───────────────────────────────────────────── 168 + 169 + fn parse_program(&mut self, source_type: SourceType) -> Result<Program, ParseError> { 170 + let start = self.start_span(); 171 + let mut body = Vec::new(); 172 + while !self.at_eof() { 173 + body.push(self.parse_statement_list_item()?); 174 + } 175 + Ok(Program { 176 + body, 177 + source_type, 178 + span: self.span_from(start), 179 + }) 180 + } 181 + 182 + fn parse_statement_list_item(&mut self) -> Result<Stmt, ParseError> { 183 + match self.peek_kind() { 184 + TokenKind::Function => self.parse_function_declaration(), 185 + TokenKind::Class => self.parse_class_declaration(), 186 + TokenKind::Var | TokenKind::Let | TokenKind::Const => { 187 + self.parse_variable_declaration_stmt() 188 + } 189 + TokenKind::Async 190 + if matches!(self.peek_ahead(1), TokenKind::Function) 191 + && !self.tokens[self.pos + 1].preceded_by_newline => 192 + { 193 + self.parse_async_function_declaration() 194 + } 195 + TokenKind::Import 196 + if !matches!(self.peek_ahead(1), TokenKind::LParen | TokenKind::Dot) => 197 + { 198 + self.parse_import_declaration() 199 + } 200 + TokenKind::Export => self.parse_export_declaration(), 201 + _ => self.parse_statement(), 202 + } 203 + } 204 + 205 + // ── Statements ────────────────────────────────────────── 206 + 207 + fn parse_statement(&mut self) -> Result<Stmt, ParseError> { 208 + match self.peek_kind() { 209 + TokenKind::LBrace => self.parse_block_stmt(), 210 + TokenKind::Semicolon => { 211 + let start = self.start_span(); 212 + self.advance(); 213 + Ok(Stmt { 214 + kind: StmtKind::Empty, 215 + span: self.span_from(start), 216 + }) 217 + } 218 + TokenKind::If => self.parse_if(), 219 + TokenKind::For => self.parse_for(), 220 + TokenKind::While => self.parse_while(), 221 + TokenKind::Do => self.parse_do_while(), 222 + TokenKind::Switch => self.parse_switch(), 223 + TokenKind::Try => self.parse_try(), 224 + TokenKind::Return => self.parse_return(), 225 + TokenKind::Throw => self.parse_throw(), 226 + TokenKind::Break => self.parse_break(), 227 + TokenKind::Continue => self.parse_continue(), 228 + TokenKind::With => self.parse_with(), 229 + TokenKind::Debugger => { 230 + let start = self.start_span(); 231 + self.advance(); 232 + self.expect_semicolon()?; 233 + Ok(Stmt { 234 + kind: StmtKind::Debugger, 235 + span: self.span_from(start), 236 + }) 237 + } 238 + // Labeled statement: `ident: stmt` 239 + TokenKind::Identifier(_) if matches!(self.peek_ahead(1), TokenKind::Colon) => { 240 + self.parse_labeled() 241 + } 242 + // Variable declarations can also appear as statements 243 + TokenKind::Var | TokenKind::Let | TokenKind::Const => { 244 + self.parse_variable_declaration_stmt() 245 + } 246 + // Function/class declarations in statement position 247 + TokenKind::Function => self.parse_function_declaration(), 248 + TokenKind::Class => self.parse_class_declaration(), 249 + TokenKind::Async 250 + if matches!(self.peek_ahead(1), TokenKind::Function) 251 + && !self.tokens[self.pos + 1].preceded_by_newline => 252 + { 253 + self.parse_async_function_declaration() 254 + } 255 + _ => self.parse_expression_statement(), 256 + } 257 + } 258 + 259 + fn parse_block_stmt(&mut self) -> Result<Stmt, ParseError> { 260 + let start = self.start_span(); 261 + let body = self.parse_block_body()?; 262 + Ok(Stmt { 263 + kind: StmtKind::Block(body), 264 + span: self.span_from(start), 265 + }) 266 + } 267 + 268 + fn parse_block_body(&mut self) -> Result<Vec<Stmt>, ParseError> { 269 + self.expect(&TokenKind::LBrace)?; 270 + let mut body = Vec::new(); 271 + while !self.at(&TokenKind::RBrace) && !self.at_eof() { 272 + body.push(self.parse_statement_list_item()?); 273 + } 274 + self.expect(&TokenKind::RBrace)?; 275 + Ok(body) 276 + } 277 + 278 + fn parse_expression_statement(&mut self) -> Result<Stmt, ParseError> { 279 + let start = self.start_span(); 280 + let expr = self.parse_expression()?; 281 + self.expect_semicolon()?; 282 + Ok(Stmt { 283 + kind: StmtKind::Expr(expr), 284 + span: self.span_from(start), 285 + }) 286 + } 287 + 288 + fn parse_if(&mut self) -> Result<Stmt, ParseError> { 289 + let start = self.start_span(); 290 + self.expect(&TokenKind::If)?; 291 + self.expect(&TokenKind::LParen)?; 292 + let test = self.parse_expression()?; 293 + self.expect(&TokenKind::RParen)?; 294 + let consequent = Box::new(self.parse_statement()?); 295 + let alternate = if self.eat(&TokenKind::Else) { 296 + Some(Box::new(self.parse_statement()?)) 297 + } else { 298 + None 299 + }; 300 + Ok(Stmt { 301 + kind: StmtKind::If { 302 + test, 303 + consequent, 304 + alternate, 305 + }, 306 + span: self.span_from(start), 307 + }) 308 + } 309 + 310 + fn parse_while(&mut self) -> Result<Stmt, ParseError> { 311 + let start = self.start_span(); 312 + self.expect(&TokenKind::While)?; 313 + self.expect(&TokenKind::LParen)?; 314 + let test = self.parse_expression()?; 315 + self.expect(&TokenKind::RParen)?; 316 + let body = Box::new(self.parse_statement()?); 317 + Ok(Stmt { 318 + kind: StmtKind::While { test, body }, 319 + span: self.span_from(start), 320 + }) 321 + } 322 + 323 + fn parse_do_while(&mut self) -> Result<Stmt, ParseError> { 324 + let start = self.start_span(); 325 + self.expect(&TokenKind::Do)?; 326 + let body = Box::new(self.parse_statement()?); 327 + self.expect(&TokenKind::While)?; 328 + self.expect(&TokenKind::LParen)?; 329 + let test = self.parse_expression()?; 330 + self.expect(&TokenKind::RParen)?; 331 + self.expect_semicolon()?; 332 + Ok(Stmt { 333 + kind: StmtKind::DoWhile { body, test }, 334 + span: self.span_from(start), 335 + }) 336 + } 337 + 338 + fn parse_for(&mut self) -> Result<Stmt, ParseError> { 339 + let start = self.start_span(); 340 + self.expect(&TokenKind::For)?; 341 + self.expect(&TokenKind::LParen)?; 342 + 343 + // Check for for-in/for-of with var/let/const 344 + if matches!( 345 + self.peek_kind(), 346 + TokenKind::Var | TokenKind::Let | TokenKind::Const 347 + ) { 348 + let var_kind = match self.peek_kind() { 349 + TokenKind::Var => VarKind::Var, 350 + TokenKind::Let => VarKind::Let, 351 + TokenKind::Const => VarKind::Const, 352 + _ => unreachable!(), 353 + }; 354 + self.advance(); 355 + let pattern = self.parse_binding_pattern()?; 356 + 357 + if self.eat(&TokenKind::In) { 358 + let right = self.parse_expression()?; 359 + self.expect(&TokenKind::RParen)?; 360 + let body = Box::new(self.parse_statement()?); 361 + return Ok(Stmt { 362 + kind: StmtKind::ForIn { 363 + left: ForInOfLeft::VarDecl { 364 + kind: var_kind, 365 + pattern, 366 + }, 367 + right, 368 + body, 369 + }, 370 + span: self.span_from(start), 371 + }); 372 + } 373 + if self.eat(&TokenKind::Of) { 374 + let right = self.parse_assignment_expression()?; 375 + self.expect(&TokenKind::RParen)?; 376 + let body = Box::new(self.parse_statement()?); 377 + return Ok(Stmt { 378 + kind: StmtKind::ForOf { 379 + left: ForInOfLeft::VarDecl { 380 + kind: var_kind, 381 + pattern, 382 + }, 383 + right, 384 + body, 385 + is_await: false, 386 + }, 387 + span: self.span_from(start), 388 + }); 389 + } 390 + 391 + // Regular for: parse remaining declarators 392 + let mut declarators = vec![VarDeclarator { 393 + span: pattern.span, 394 + init: if self.eat(&TokenKind::Assign) { 395 + Some(self.parse_assignment_expression_no_in()?) 396 + } else { 397 + None 398 + }, 399 + pattern, 400 + }]; 401 + while self.eat(&TokenKind::Comma) { 402 + declarators.push(self.parse_var_declarator_no_in()?); 403 + } 404 + self.expect(&TokenKind::Semicolon)?; 405 + let test = if self.at(&TokenKind::Semicolon) { 406 + None 407 + } else { 408 + Some(self.parse_expression()?) 409 + }; 410 + self.expect(&TokenKind::Semicolon)?; 411 + let update = if self.at(&TokenKind::RParen) { 412 + None 413 + } else { 414 + Some(self.parse_expression()?) 415 + }; 416 + self.expect(&TokenKind::RParen)?; 417 + let body = Box::new(self.parse_statement()?); 418 + return Ok(Stmt { 419 + kind: StmtKind::For { 420 + init: Some(ForInit::VarDecl { 421 + kind: var_kind, 422 + declarators, 423 + }), 424 + test, 425 + update, 426 + body, 427 + }, 428 + span: self.span_from(start), 429 + }); 430 + } 431 + 432 + // No var/let/const 433 + if self.eat(&TokenKind::Semicolon) { 434 + // for(; ...) 435 + let test = if self.at(&TokenKind::Semicolon) { 436 + None 437 + } else { 438 + Some(self.parse_expression()?) 439 + }; 440 + self.expect(&TokenKind::Semicolon)?; 441 + let update = if self.at(&TokenKind::RParen) { 442 + None 443 + } else { 444 + Some(self.parse_expression()?) 445 + }; 446 + self.expect(&TokenKind::RParen)?; 447 + let body = Box::new(self.parse_statement()?); 448 + return Ok(Stmt { 449 + kind: StmtKind::For { 450 + init: None, 451 + test, 452 + update, 453 + body, 454 + }, 455 + span: self.span_from(start), 456 + }); 457 + } 458 + 459 + // Expression init — might be for-in/for-of 460 + let old_allow_in = self.allow_in; 461 + self.allow_in = false; 462 + let init_expr = self.parse_expression()?; 463 + self.allow_in = old_allow_in; 464 + 465 + if self.eat(&TokenKind::In) { 466 + let pattern = self.expr_to_pattern(&init_expr)?; 467 + let right = self.parse_expression()?; 468 + self.expect(&TokenKind::RParen)?; 469 + let body = Box::new(self.parse_statement()?); 470 + return Ok(Stmt { 471 + kind: StmtKind::ForIn { 472 + left: ForInOfLeft::Pattern(pattern), 473 + right, 474 + body, 475 + }, 476 + span: self.span_from(start), 477 + }); 478 + } 479 + if self.eat(&TokenKind::Of) { 480 + let pattern = self.expr_to_pattern(&init_expr)?; 481 + let right = self.parse_assignment_expression()?; 482 + self.expect(&TokenKind::RParen)?; 483 + let body = Box::new(self.parse_statement()?); 484 + return Ok(Stmt { 485 + kind: StmtKind::ForOf { 486 + left: ForInOfLeft::Pattern(pattern), 487 + right, 488 + body, 489 + is_await: false, 490 + }, 491 + span: self.span_from(start), 492 + }); 493 + } 494 + 495 + self.expect(&TokenKind::Semicolon)?; 496 + let test = if self.at(&TokenKind::Semicolon) { 497 + None 498 + } else { 499 + Some(self.parse_expression()?) 500 + }; 501 + self.expect(&TokenKind::Semicolon)?; 502 + let update = if self.at(&TokenKind::RParen) { 503 + None 504 + } else { 505 + Some(self.parse_expression()?) 506 + }; 507 + self.expect(&TokenKind::RParen)?; 508 + let body = Box::new(self.parse_statement()?); 509 + Ok(Stmt { 510 + kind: StmtKind::For { 511 + init: Some(ForInit::Expr(init_expr)), 512 + test, 513 + update, 514 + body, 515 + }, 516 + span: self.span_from(start), 517 + }) 518 + } 519 + 520 + fn parse_switch(&mut self) -> Result<Stmt, ParseError> { 521 + let start = self.start_span(); 522 + self.expect(&TokenKind::Switch)?; 523 + self.expect(&TokenKind::LParen)?; 524 + let discriminant = self.parse_expression()?; 525 + self.expect(&TokenKind::RParen)?; 526 + self.expect(&TokenKind::LBrace)?; 527 + let mut cases = Vec::new(); 528 + while !self.at(&TokenKind::RBrace) && !self.at_eof() { 529 + let case_start = self.start_span(); 530 + let test = if self.eat(&TokenKind::Case) { 531 + Some(self.parse_expression()?) 532 + } else { 533 + self.expect(&TokenKind::Default)?; 534 + None 535 + }; 536 + self.expect(&TokenKind::Colon)?; 537 + let mut consequent = Vec::new(); 538 + while !matches!( 539 + self.peek_kind(), 540 + TokenKind::Case | TokenKind::Default | TokenKind::RBrace 541 + ) && !self.at_eof() 542 + { 543 + consequent.push(self.parse_statement_list_item()?); 544 + } 545 + cases.push(SwitchCase { 546 + test, 547 + consequent, 548 + span: self.span_from(case_start), 549 + }); 550 + } 551 + self.expect(&TokenKind::RBrace)?; 552 + Ok(Stmt { 553 + kind: StmtKind::Switch { 554 + discriminant, 555 + cases, 556 + }, 557 + span: self.span_from(start), 558 + }) 559 + } 560 + 561 + fn parse_try(&mut self) -> Result<Stmt, ParseError> { 562 + let start = self.start_span(); 563 + self.expect(&TokenKind::Try)?; 564 + let block = self.parse_block_body()?; 565 + 566 + let handler = if self.eat(&TokenKind::Catch) { 567 + let catch_start = self.start_span(); 568 + let param = if self.eat(&TokenKind::LParen) { 569 + let pat = self.parse_binding_pattern()?; 570 + self.expect(&TokenKind::RParen)?; 571 + Some(pat) 572 + } else { 573 + None 574 + }; 575 + let body = self.parse_block_body()?; 576 + Some(CatchClause { 577 + param, 578 + body, 579 + span: self.span_from(catch_start), 580 + }) 581 + } else { 582 + None 583 + }; 584 + 585 + let finalizer = if self.eat(&TokenKind::Finally) { 586 + Some(self.parse_block_body()?) 587 + } else { 588 + None 589 + }; 590 + 591 + if handler.is_none() && finalizer.is_none() { 592 + return Err(self.error("try requires catch or finally".into())); 593 + } 594 + 595 + Ok(Stmt { 596 + kind: StmtKind::Try { 597 + block, 598 + handler, 599 + finalizer, 600 + }, 601 + span: self.span_from(start), 602 + }) 603 + } 604 + 605 + fn parse_return(&mut self) -> Result<Stmt, ParseError> { 606 + let start = self.start_span(); 607 + self.expect(&TokenKind::Return)?; 608 + // Restricted production: newline after return inserts semicolon 609 + let argument = if matches!( 610 + self.peek_kind(), 611 + TokenKind::Semicolon | TokenKind::RBrace | TokenKind::Eof 612 + ) || self.peek().preceded_by_newline 613 + { 614 + None 615 + } else { 616 + Some(self.parse_expression()?) 617 + }; 618 + self.expect_semicolon()?; 619 + Ok(Stmt { 620 + kind: StmtKind::Return(argument), 621 + span: self.span_from(start), 622 + }) 623 + } 624 + 625 + fn parse_throw(&mut self) -> Result<Stmt, ParseError> { 626 + let start = self.start_span(); 627 + self.expect(&TokenKind::Throw)?; 628 + if self.peek().preceded_by_newline { 629 + return Err(ParseError { 630 + message: "newline not allowed after throw".into(), 631 + pos: self.peek().span.start, 632 + }); 633 + } 634 + let argument = self.parse_expression()?; 635 + self.expect_semicolon()?; 636 + Ok(Stmt { 637 + kind: StmtKind::Throw(argument), 638 + span: self.span_from(start), 639 + }) 640 + } 641 + 642 + fn parse_break(&mut self) -> Result<Stmt, ParseError> { 643 + let start = self.start_span(); 644 + self.expect(&TokenKind::Break)?; 645 + let label = if !self.peek().preceded_by_newline { 646 + if let TokenKind::Identifier(name) = self.peek_kind().clone() { 647 + self.advance(); 648 + Some(name) 649 + } else { 650 + None 651 + } 652 + } else { 653 + None 654 + }; 655 + self.expect_semicolon()?; 656 + Ok(Stmt { 657 + kind: StmtKind::Break(label), 658 + span: self.span_from(start), 659 + }) 660 + } 661 + 662 + fn parse_continue(&mut self) -> Result<Stmt, ParseError> { 663 + let start = self.start_span(); 664 + self.expect(&TokenKind::Continue)?; 665 + let label = if !self.peek().preceded_by_newline { 666 + if let TokenKind::Identifier(name) = self.peek_kind().clone() { 667 + self.advance(); 668 + Some(name) 669 + } else { 670 + None 671 + } 672 + } else { 673 + None 674 + }; 675 + self.expect_semicolon()?; 676 + Ok(Stmt { 677 + kind: StmtKind::Continue(label), 678 + span: self.span_from(start), 679 + }) 680 + } 681 + 682 + fn parse_labeled(&mut self) -> Result<Stmt, ParseError> { 683 + let start = self.start_span(); 684 + let label = self.expect_identifier()?; 685 + self.expect(&TokenKind::Colon)?; 686 + let body = Box::new(self.parse_statement()?); 687 + Ok(Stmt { 688 + kind: StmtKind::Labeled { label, body }, 689 + span: self.span_from(start), 690 + }) 691 + } 692 + 693 + fn parse_with(&mut self) -> Result<Stmt, ParseError> { 694 + let start = self.start_span(); 695 + self.expect(&TokenKind::With)?; 696 + self.expect(&TokenKind::LParen)?; 697 + let object = self.parse_expression()?; 698 + self.expect(&TokenKind::RParen)?; 699 + let body = Box::new(self.parse_statement()?); 700 + Ok(Stmt { 701 + kind: StmtKind::With { object, body }, 702 + span: self.span_from(start), 703 + }) 704 + } 705 + 706 + // ── Variable declarations ─────────────────────────────── 707 + 708 + fn parse_variable_declaration_stmt(&mut self) -> Result<Stmt, ParseError> { 709 + let start = self.start_span(); 710 + let kind = match self.peek_kind() { 711 + TokenKind::Var => VarKind::Var, 712 + TokenKind::Let => VarKind::Let, 713 + TokenKind::Const => VarKind::Const, 714 + _ => return Err(self.error("expected var, let, or const".into())), 715 + }; 716 + self.advance(); 717 + let mut declarators = vec![self.parse_var_declarator()?]; 718 + while self.eat(&TokenKind::Comma) { 719 + declarators.push(self.parse_var_declarator()?); 720 + } 721 + self.expect_semicolon()?; 722 + Ok(Stmt { 723 + kind: StmtKind::VarDecl { kind, declarators }, 724 + span: self.span_from(start), 725 + }) 726 + } 727 + 728 + fn parse_var_declarator(&mut self) -> Result<VarDeclarator, ParseError> { 729 + let start = self.start_span(); 730 + let pattern = self.parse_binding_pattern()?; 731 + let init = if self.eat(&TokenKind::Assign) { 732 + Some(self.parse_assignment_expression()?) 733 + } else { 734 + None 735 + }; 736 + Ok(VarDeclarator { 737 + pattern, 738 + init, 739 + span: self.span_from(start), 740 + }) 741 + } 742 + 743 + fn parse_var_declarator_no_in(&mut self) -> Result<VarDeclarator, ParseError> { 744 + let start = self.start_span(); 745 + let pattern = self.parse_binding_pattern()?; 746 + let init = if self.eat(&TokenKind::Assign) { 747 + Some(self.parse_assignment_expression_no_in()?) 748 + } else { 749 + None 750 + }; 751 + Ok(VarDeclarator { 752 + pattern, 753 + init, 754 + span: self.span_from(start), 755 + }) 756 + } 757 + 758 + // ── Binding patterns (destructuring) ──────────────────── 759 + 760 + fn parse_binding_pattern(&mut self) -> Result<Pattern, ParseError> { 761 + match self.peek_kind() { 762 + TokenKind::LBracket => self.parse_array_pattern(), 763 + TokenKind::LBrace => self.parse_object_pattern(), 764 + _ => { 765 + let start = self.start_span(); 766 + let name = self.expect_identifier()?; 767 + Ok(Pattern { 768 + kind: PatternKind::Identifier(name), 769 + span: self.span_from(start), 770 + }) 771 + } 772 + } 773 + } 774 + 775 + fn parse_array_pattern(&mut self) -> Result<Pattern, ParseError> { 776 + let start = self.start_span(); 777 + self.expect(&TokenKind::LBracket)?; 778 + let mut elements = Vec::new(); 779 + let mut rest = None; 780 + while !self.at(&TokenKind::RBracket) && !self.at_eof() { 781 + if self.eat(&TokenKind::Comma) { 782 + elements.push(None); 783 + continue; 784 + } 785 + if self.at(&TokenKind::Ellipsis) { 786 + self.advance(); 787 + rest = Some(Box::new(self.parse_binding_pattern()?)); 788 + self.eat(&TokenKind::Comma); // trailing comma after rest 789 + break; 790 + } 791 + let mut pat = self.parse_binding_pattern()?; 792 + if self.eat(&TokenKind::Assign) { 793 + let right = self.parse_assignment_expression()?; 794 + let span = Span { 795 + start: pat.span.start, 796 + end: right.span.end, 797 + }; 798 + pat = Pattern { 799 + kind: PatternKind::Assign { 800 + left: Box::new(pat), 801 + right: Box::new(right), 802 + }, 803 + span, 804 + }; 805 + } 806 + elements.push(Some(pat)); 807 + if !self.eat(&TokenKind::Comma) { 808 + break; 809 + } 810 + } 811 + self.expect(&TokenKind::RBracket)?; 812 + Ok(Pattern { 813 + kind: PatternKind::Array { elements, rest }, 814 + span: self.span_from(start), 815 + }) 816 + } 817 + 818 + fn parse_object_pattern(&mut self) -> Result<Pattern, ParseError> { 819 + let start = self.start_span(); 820 + self.expect(&TokenKind::LBrace)?; 821 + let mut properties = Vec::new(); 822 + let mut rest = None; 823 + while !self.at(&TokenKind::RBrace) && !self.at_eof() { 824 + if self.at(&TokenKind::Ellipsis) { 825 + self.advance(); 826 + rest = Some(Box::new(self.parse_binding_pattern()?)); 827 + self.eat(&TokenKind::Comma); 828 + break; 829 + } 830 + let prop_start = self.start_span(); 831 + let (key, computed) = self.parse_property_name()?; 832 + if self.eat(&TokenKind::Colon) { 833 + // { key: pattern } 834 + let mut value = self.parse_binding_pattern()?; 835 + if self.eat(&TokenKind::Assign) { 836 + let right = self.parse_assignment_expression()?; 837 + let span = Span { 838 + start: value.span.start, 839 + end: right.span.end, 840 + }; 841 + value = Pattern { 842 + kind: PatternKind::Assign { 843 + left: Box::new(value), 844 + right: Box::new(right), 845 + }, 846 + span, 847 + }; 848 + } 849 + properties.push(ObjectPatternProp { 850 + key, 851 + value, 852 + computed, 853 + shorthand: false, 854 + span: self.span_from(prop_start), 855 + }); 856 + } else { 857 + // Shorthand: { name } or { name = default } 858 + let name = match &key { 859 + PropertyKey::Identifier(n) => n.clone(), 860 + _ => return Err(self.error("shorthand properties require identifier".into())), 861 + }; 862 + let ident_span = self.span_from(prop_start); 863 + let mut value = Pattern { 864 + kind: PatternKind::Identifier(name.clone()), 865 + span: ident_span, 866 + }; 867 + if self.eat(&TokenKind::Assign) { 868 + let right = self.parse_assignment_expression()?; 869 + let span = Span { 870 + start: value.span.start, 871 + end: right.span.end, 872 + }; 873 + value = Pattern { 874 + kind: PatternKind::Assign { 875 + left: Box::new(value), 876 + right: Box::new(right), 877 + }, 878 + span, 879 + }; 880 + } 881 + properties.push(ObjectPatternProp { 882 + key, 883 + value, 884 + computed, 885 + shorthand: true, 886 + span: self.span_from(prop_start), 887 + }); 888 + } 889 + if !self.eat(&TokenKind::Comma) { 890 + break; 891 + } 892 + } 893 + self.expect(&TokenKind::RBrace)?; 894 + Ok(Pattern { 895 + kind: PatternKind::Object { properties, rest }, 896 + span: self.span_from(start), 897 + }) 898 + } 899 + 900 + // ── Function declarations ─────────────────────────────── 901 + 902 + fn parse_function_declaration(&mut self) -> Result<Stmt, ParseError> { 903 + let start = self.start_span(); 904 + self.expect(&TokenKind::Function)?; 905 + let is_generator = self.eat(&TokenKind::Star); 906 + let id = Some(self.expect_identifier()?); 907 + let (params, body) = self.parse_function_params_and_body()?; 908 + Ok(Stmt { 909 + kind: StmtKind::FunctionDecl(FunctionDef { 910 + id, 911 + params, 912 + body, 913 + is_async: false, 914 + is_generator, 915 + }), 916 + span: self.span_from(start), 917 + }) 918 + } 919 + 920 + fn parse_async_function_declaration(&mut self) -> Result<Stmt, ParseError> { 921 + let start = self.start_span(); 922 + self.expect(&TokenKind::Async)?; 923 + self.expect(&TokenKind::Function)?; 924 + let is_generator = self.eat(&TokenKind::Star); 925 + let id = Some(self.expect_identifier()?); 926 + let (params, body) = self.parse_function_params_and_body()?; 927 + Ok(Stmt { 928 + kind: StmtKind::FunctionDecl(FunctionDef { 929 + id, 930 + params, 931 + body, 932 + is_async: true, 933 + is_generator, 934 + }), 935 + span: self.span_from(start), 936 + }) 937 + } 938 + 939 + fn parse_function_params_and_body(&mut self) -> Result<(Vec<Pattern>, Vec<Stmt>), ParseError> { 940 + self.expect(&TokenKind::LParen)?; 941 + let params = self.parse_formal_parameters()?; 942 + self.expect(&TokenKind::RParen)?; 943 + let body = self.parse_block_body()?; 944 + Ok((params, body)) 945 + } 946 + 947 + fn parse_formal_parameters(&mut self) -> Result<Vec<Pattern>, ParseError> { 948 + let mut params = Vec::new(); 949 + while !self.at(&TokenKind::RParen) && !self.at_eof() { 950 + if self.at(&TokenKind::Ellipsis) { 951 + self.advance(); 952 + params.push(self.parse_binding_pattern()?); 953 + self.eat(&TokenKind::Comma); 954 + break; 955 + } 956 + let mut pat = self.parse_binding_pattern()?; 957 + if self.eat(&TokenKind::Assign) { 958 + let right = self.parse_assignment_expression()?; 959 + let span = Span { 960 + start: pat.span.start, 961 + end: right.span.end, 962 + }; 963 + pat = Pattern { 964 + kind: PatternKind::Assign { 965 + left: Box::new(pat), 966 + right: Box::new(right), 967 + }, 968 + span, 969 + }; 970 + } 971 + params.push(pat); 972 + if !self.eat(&TokenKind::Comma) { 973 + break; 974 + } 975 + } 976 + Ok(params) 977 + } 978 + 979 + // ── Class declarations ────────────────────────────────── 980 + 981 + fn parse_class_declaration(&mut self) -> Result<Stmt, ParseError> { 982 + let start = self.start_span(); 983 + let class_def = self.parse_class(true)?; 984 + Ok(Stmt { 985 + kind: StmtKind::ClassDecl(class_def), 986 + span: self.span_from(start), 987 + }) 988 + } 989 + 990 + fn parse_class(&mut self, require_name: bool) -> Result<ClassDef, ParseError> { 991 + self.expect(&TokenKind::Class)?; 992 + let id = if require_name { 993 + Some(self.expect_identifier()?) 994 + } else if let TokenKind::Identifier(_) = self.peek_kind() { 995 + Some(self.expect_identifier()?) 996 + } else { 997 + None 998 + }; 999 + let super_class = if self.eat(&TokenKind::Extends) { 1000 + Some(Box::new(self.parse_left_hand_side_expression()?)) 1001 + } else { 1002 + None 1003 + }; 1004 + let body = self.parse_class_body()?; 1005 + Ok(ClassDef { 1006 + id, 1007 + super_class, 1008 + body, 1009 + }) 1010 + } 1011 + 1012 + fn parse_class_body(&mut self) -> Result<Vec<ClassMember>, ParseError> { 1013 + self.expect(&TokenKind::LBrace)?; 1014 + let mut members = Vec::new(); 1015 + while !self.at(&TokenKind::RBrace) && !self.at_eof() { 1016 + if self.eat(&TokenKind::Semicolon) { 1017 + continue; 1018 + } 1019 + members.push(self.parse_class_member()?); 1020 + } 1021 + self.expect(&TokenKind::RBrace)?; 1022 + Ok(members) 1023 + } 1024 + 1025 + fn parse_class_member(&mut self) -> Result<ClassMember, ParseError> { 1026 + let start = self.start_span(); 1027 + let is_static = self.eat(&TokenKind::Static); 1028 + 1029 + // Check for getter/setter 1030 + if let TokenKind::Identifier(ref name) = self.peek_kind().clone() { 1031 + if (name == "get" || name == "set") 1032 + && !matches!( 1033 + self.peek_ahead(1), 1034 + TokenKind::LParen | TokenKind::Assign | TokenKind::Semicolon 1035 + ) 1036 + { 1037 + let kind = if name == "get" { 1038 + MethodKind::Get 1039 + } else { 1040 + MethodKind::Set 1041 + }; 1042 + self.advance(); 1043 + let (key, computed) = self.parse_property_name()?; 1044 + let (params, body) = self.parse_function_params_and_body()?; 1045 + return Ok(ClassMember { 1046 + kind: ClassMemberKind::Method { 1047 + key, 1048 + value: FunctionDef { 1049 + id: None, 1050 + params, 1051 + body, 1052 + is_async: false, 1053 + is_generator: false, 1054 + }, 1055 + kind, 1056 + is_static, 1057 + computed, 1058 + }, 1059 + span: self.span_from(start), 1060 + }); 1061 + } 1062 + } 1063 + 1064 + // Generator method 1065 + let is_generator = self.eat(&TokenKind::Star); 1066 + 1067 + // Async method 1068 + let is_async = if !is_generator 1069 + && matches!(self.peek_kind(), TokenKind::Async) 1070 + && !matches!( 1071 + self.peek_ahead(1), 1072 + TokenKind::LParen | TokenKind::Assign | TokenKind::Semicolon 1073 + ) { 1074 + self.advance(); 1075 + true 1076 + } else { 1077 + false 1078 + }; 1079 + 1080 + let is_generator = is_generator || (is_async && self.eat(&TokenKind::Star)); 1081 + 1082 + let (key, computed) = self.parse_property_name()?; 1083 + 1084 + // Check for constructor 1085 + let method_kind = 1086 + if !is_static && !computed && key == PropertyKey::Identifier("constructor".into()) { 1087 + MethodKind::Constructor 1088 + } else { 1089 + MethodKind::Method 1090 + }; 1091 + 1092 + if self.at(&TokenKind::LParen) { 1093 + let (params, body) = self.parse_function_params_and_body()?; 1094 + Ok(ClassMember { 1095 + kind: ClassMemberKind::Method { 1096 + key, 1097 + value: FunctionDef { 1098 + id: None, 1099 + params, 1100 + body, 1101 + is_async, 1102 + is_generator, 1103 + }, 1104 + kind: method_kind, 1105 + is_static, 1106 + computed, 1107 + }, 1108 + span: self.span_from(start), 1109 + }) 1110 + } else { 1111 + // Class field 1112 + let value = if self.eat(&TokenKind::Assign) { 1113 + Some(self.parse_assignment_expression()?) 1114 + } else { 1115 + None 1116 + }; 1117 + self.expect_semicolon()?; 1118 + Ok(ClassMember { 1119 + kind: ClassMemberKind::Property { 1120 + key, 1121 + value, 1122 + is_static, 1123 + computed, 1124 + }, 1125 + span: self.span_from(start), 1126 + }) 1127 + } 1128 + } 1129 + 1130 + // ── Import / Export ───────────────────────────────────── 1131 + 1132 + fn parse_import_declaration(&mut self) -> Result<Stmt, ParseError> { 1133 + let start = self.start_span(); 1134 + self.expect(&TokenKind::Import)?; 1135 + 1136 + // `import "source"` — side-effect import 1137 + if let TokenKind::String(source) = self.peek_kind().clone() { 1138 + self.advance(); 1139 + self.expect_semicolon()?; 1140 + return Ok(Stmt { 1141 + kind: StmtKind::Import { 1142 + specifiers: vec![], 1143 + source, 1144 + }, 1145 + span: self.span_from(start), 1146 + }); 1147 + } 1148 + 1149 + let mut specifiers = Vec::new(); 1150 + 1151 + // `import * as ns from "source"` 1152 + if self.eat(&TokenKind::Star) { 1153 + self.expect_identifier_matching("as")?; 1154 + let local = self.expect_identifier()?; 1155 + specifiers.push(ImportSpecifier::Namespace(local)); 1156 + } 1157 + // `import { a, b as c } from "source"` 1158 + else if self.at(&TokenKind::LBrace) { 1159 + self.advance(); 1160 + while !self.at(&TokenKind::RBrace) && !self.at_eof() { 1161 + let imported = self.expect_identifier()?; 1162 + let local = if self.eat_identifier_matching("as") { 1163 + self.expect_identifier()? 1164 + } else { 1165 + imported.clone() 1166 + }; 1167 + specifiers.push(ImportSpecifier::Named { imported, local }); 1168 + if !self.eat(&TokenKind::Comma) { 1169 + break; 1170 + } 1171 + } 1172 + self.expect(&TokenKind::RBrace)?; 1173 + } 1174 + // `import defaultExport from "source"` or `import defaultExport, { ... } from "source"` 1175 + else { 1176 + let default_name = self.expect_identifier()?; 1177 + specifiers.push(ImportSpecifier::Default(default_name)); 1178 + 1179 + if self.eat(&TokenKind::Comma) { 1180 + if self.eat(&TokenKind::Star) { 1181 + self.expect_identifier_matching("as")?; 1182 + let local = self.expect_identifier()?; 1183 + specifiers.push(ImportSpecifier::Namespace(local)); 1184 + } else { 1185 + self.expect(&TokenKind::LBrace)?; 1186 + while !self.at(&TokenKind::RBrace) && !self.at_eof() { 1187 + let imported = self.expect_identifier()?; 1188 + let local = if self.eat_identifier_matching("as") { 1189 + self.expect_identifier()? 1190 + } else { 1191 + imported.clone() 1192 + }; 1193 + specifiers.push(ImportSpecifier::Named { imported, local }); 1194 + if !self.eat(&TokenKind::Comma) { 1195 + break; 1196 + } 1197 + } 1198 + self.expect(&TokenKind::RBrace)?; 1199 + } 1200 + } 1201 + } 1202 + 1203 + self.expect_identifier_matching("from")?; 1204 + let source = match self.peek_kind().clone() { 1205 + TokenKind::String(s) => { 1206 + self.advance(); 1207 + s 1208 + } 1209 + _ => return Err(self.error("expected module source string".into())), 1210 + }; 1211 + self.expect_semicolon()?; 1212 + Ok(Stmt { 1213 + kind: StmtKind::Import { specifiers, source }, 1214 + span: self.span_from(start), 1215 + }) 1216 + } 1217 + 1218 + fn parse_export_declaration(&mut self) -> Result<Stmt, ParseError> { 1219 + let start = self.start_span(); 1220 + self.expect(&TokenKind::Export)?; 1221 + 1222 + // `export default ...` 1223 + if self.eat(&TokenKind::Default) { 1224 + if matches!(self.peek_kind(), TokenKind::Function) { 1225 + let decl = self.parse_function_declaration()?; 1226 + return Ok(Stmt { 1227 + kind: StmtKind::Export(ExportDecl::Declaration(Box::new(decl))), 1228 + span: self.span_from(start), 1229 + }); 1230 + } 1231 + if matches!(self.peek_kind(), TokenKind::Class) { 1232 + let decl = self.parse_class_declaration()?; 1233 + return Ok(Stmt { 1234 + kind: StmtKind::Export(ExportDecl::Declaration(Box::new(decl))), 1235 + span: self.span_from(start), 1236 + }); 1237 + } 1238 + let expr = self.parse_assignment_expression()?; 1239 + self.expect_semicolon()?; 1240 + return Ok(Stmt { 1241 + kind: StmtKind::Export(ExportDecl::Default(expr)), 1242 + span: self.span_from(start), 1243 + }); 1244 + } 1245 + 1246 + // `export * from "source"` 1247 + if self.eat(&TokenKind::Star) { 1248 + self.expect_identifier_matching("from")?; 1249 + let source = match self.peek_kind().clone() { 1250 + TokenKind::String(s) => { 1251 + self.advance(); 1252 + s 1253 + } 1254 + _ => return Err(self.error("expected module source string".into())), 1255 + }; 1256 + self.expect_semicolon()?; 1257 + return Ok(Stmt { 1258 + kind: StmtKind::Export(ExportDecl::AllFrom(source)), 1259 + span: self.span_from(start), 1260 + }); 1261 + } 1262 + 1263 + // `export { a, b as c } [from "source"]` 1264 + if self.at(&TokenKind::LBrace) { 1265 + self.advance(); 1266 + let mut specifiers = Vec::new(); 1267 + while !self.at(&TokenKind::RBrace) && !self.at_eof() { 1268 + let local = self.expect_identifier()?; 1269 + let exported = if self.eat_identifier_matching("as") { 1270 + self.expect_identifier()? 1271 + } else { 1272 + local.clone() 1273 + }; 1274 + specifiers.push(ExportSpecifier { local, exported }); 1275 + if !self.eat(&TokenKind::Comma) { 1276 + break; 1277 + } 1278 + } 1279 + self.expect(&TokenKind::RBrace)?; 1280 + let source = if self.eat_identifier_matching("from") { 1281 + match self.peek_kind().clone() { 1282 + TokenKind::String(s) => { 1283 + self.advance(); 1284 + Some(s) 1285 + } 1286 + _ => return Err(self.error("expected module source string".into())), 1287 + } 1288 + } else { 1289 + None 1290 + }; 1291 + self.expect_semicolon()?; 1292 + return Ok(Stmt { 1293 + kind: StmtKind::Export(ExportDecl::Named { specifiers, source }), 1294 + span: self.span_from(start), 1295 + }); 1296 + } 1297 + 1298 + // `export var/let/const/function/class ...` 1299 + let decl = self.parse_statement_list_item()?; 1300 + Ok(Stmt { 1301 + kind: StmtKind::Export(ExportDecl::Declaration(Box::new(decl))), 1302 + span: self.span_from(start), 1303 + }) 1304 + } 1305 + 1306 + // ── Helper for contextual keywords ────────────────────── 1307 + 1308 + fn expect_identifier_matching(&mut self, expected: &str) -> Result<(), ParseError> { 1309 + match self.peek_kind().clone() { 1310 + TokenKind::Identifier(ref name) if name == expected => { 1311 + self.advance(); 1312 + Ok(()) 1313 + } 1314 + _ => Err(self.error(format!("expected '{}'", expected))), 1315 + } 1316 + } 1317 + 1318 + fn eat_identifier_matching(&mut self, expected: &str) -> bool { 1319 + if let TokenKind::Identifier(ref name) = self.peek_kind() { 1320 + if name == expected { 1321 + self.advance(); 1322 + return true; 1323 + } 1324 + } 1325 + false 1326 + } 1327 + 1328 + // ── Expressions ───────────────────────────────────────── 1329 + 1330 + fn parse_expression(&mut self) -> Result<Expr, ParseError> { 1331 + let start = self.start_span(); 1332 + let expr = self.parse_assignment_expression()?; 1333 + if !self.at(&TokenKind::Comma) { 1334 + return Ok(expr); 1335 + } 1336 + let mut exprs = vec![expr]; 1337 + while self.eat(&TokenKind::Comma) { 1338 + exprs.push(self.parse_assignment_expression()?); 1339 + } 1340 + Ok(Expr { 1341 + kind: ExprKind::Sequence(exprs), 1342 + span: self.span_from(start), 1343 + }) 1344 + } 1345 + 1346 + fn parse_assignment_expression(&mut self) -> Result<Expr, ParseError> { 1347 + // Check for arrow function: `x => ...` or `async x => ...` 1348 + if let TokenKind::Identifier(ref name) = self.peek_kind().clone() { 1349 + if matches!(self.peek_ahead(1), TokenKind::Arrow) && !self.peek().preceded_by_newline { 1350 + let param_start = self.start_span(); 1351 + let name = name.clone(); 1352 + self.advance(); // identifier 1353 + self.advance(); // => 1354 + let params = vec![Pattern { 1355 + kind: PatternKind::Identifier(name), 1356 + span: self.span_from(param_start), 1357 + }]; 1358 + return self.parse_arrow_body(param_start, params, false); 1359 + } 1360 + } 1361 + 1362 + // Check for `async x => ...` or `async (...)` arrow 1363 + if matches!(self.peek_kind(), TokenKind::Async) && !self.peek().preceded_by_newline { 1364 + if let TokenKind::Identifier(_) = self.peek_ahead(1) { 1365 + if matches!(self.peek_ahead(2), TokenKind::Arrow) { 1366 + let start = self.start_span(); 1367 + self.advance(); // async 1368 + let param_start = self.start_span(); 1369 + let name = self.expect_identifier()?; 1370 + self.advance(); // => 1371 + let params = vec![Pattern { 1372 + kind: PatternKind::Identifier(name), 1373 + span: self.span_from(param_start), 1374 + }]; 1375 + return self.parse_arrow_body(start, params, true); 1376 + } 1377 + } 1378 + } 1379 + 1380 + let start = self.start_span(); 1381 + let left = self.parse_conditional_expression()?; 1382 + 1383 + // Check for arrow function after parenthesized expr: `(a, b) => ...` 1384 + if matches!(self.peek_kind(), TokenKind::Arrow) && !self.peek().preceded_by_newline { 1385 + self.advance(); // => 1386 + let params = self.expr_to_params(&left)?; 1387 + return self.parse_arrow_body(start, params, false); 1388 + } 1389 + 1390 + // Assignment 1391 + if let Some(op) = self.peek_assign_op() { 1392 + self.advance(); 1393 + let right = self.parse_assignment_expression()?; 1394 + return Ok(Expr { 1395 + span: self.span_from(start), 1396 + kind: ExprKind::Assignment { 1397 + op, 1398 + left: Box::new(left), 1399 + right: Box::new(right), 1400 + }, 1401 + }); 1402 + } 1403 + 1404 + Ok(left) 1405 + } 1406 + 1407 + fn parse_assignment_expression_no_in(&mut self) -> Result<Expr, ParseError> { 1408 + let old = self.allow_in; 1409 + self.allow_in = false; 1410 + let result = self.parse_assignment_expression(); 1411 + self.allow_in = old; 1412 + result 1413 + } 1414 + 1415 + fn parse_arrow_body( 1416 + &mut self, 1417 + start: SourcePos, 1418 + params: Vec<Pattern>, 1419 + is_async: bool, 1420 + ) -> Result<Expr, ParseError> { 1421 + let body = if self.at(&TokenKind::LBrace) { 1422 + ArrowBody::Block(self.parse_block_body()?) 1423 + } else { 1424 + ArrowBody::Expr(Box::new(self.parse_assignment_expression()?)) 1425 + }; 1426 + Ok(Expr { 1427 + kind: ExprKind::Arrow { 1428 + params, 1429 + body, 1430 + is_async, 1431 + }, 1432 + span: self.span_from(start), 1433 + }) 1434 + } 1435 + 1436 + fn parse_conditional_expression(&mut self) -> Result<Expr, ParseError> { 1437 + let start = self.start_span(); 1438 + let expr = self.parse_binary_expression(0)?; 1439 + if !self.eat(&TokenKind::Question) { 1440 + return Ok(expr); 1441 + } 1442 + let consequent = self.parse_assignment_expression()?; 1443 + self.expect(&TokenKind::Colon)?; 1444 + let alternate = self.parse_assignment_expression()?; 1445 + Ok(Expr { 1446 + kind: ExprKind::Conditional { 1447 + test: Box::new(expr), 1448 + consequent: Box::new(consequent), 1449 + alternate: Box::new(alternate), 1450 + }, 1451 + span: self.span_from(start), 1452 + }) 1453 + } 1454 + 1455 + // ── Pratt expression parsing ──────────────────────────── 1456 + 1457 + fn parse_binary_expression(&mut self, min_bp: u8) -> Result<Expr, ParseError> { 1458 + let start = self.start_span(); 1459 + let mut left = self.parse_unary_expression()?; 1460 + 1461 + loop { 1462 + let Some((op, left_bp, right_bp)) = self.peek_binary_op() else { 1463 + break; 1464 + }; 1465 + if left_bp < min_bp { 1466 + break; 1467 + } 1468 + self.advance(); 1469 + 1470 + let right = self.parse_binary_expression(right_bp)?; 1471 + let span = self.span_from(start); 1472 + 1473 + left = match op { 1474 + BinOrLogical::Binary(op) => Expr { 1475 + kind: ExprKind::Binary { 1476 + op, 1477 + left: Box::new(left), 1478 + right: Box::new(right), 1479 + }, 1480 + span, 1481 + }, 1482 + BinOrLogical::Logical(op) => Expr { 1483 + kind: ExprKind::Logical { 1484 + op, 1485 + left: Box::new(left), 1486 + right: Box::new(right), 1487 + }, 1488 + span, 1489 + }, 1490 + }; 1491 + } 1492 + 1493 + Ok(left) 1494 + } 1495 + 1496 + fn parse_unary_expression(&mut self) -> Result<Expr, ParseError> { 1497 + let start = self.start_span(); 1498 + match self.peek_kind() { 1499 + TokenKind::Minus => { 1500 + self.advance(); 1501 + let arg = self.parse_unary_expression()?; 1502 + Ok(Expr { 1503 + kind: ExprKind::Unary { 1504 + op: UnaryOp::Minus, 1505 + argument: Box::new(arg), 1506 + }, 1507 + span: self.span_from(start), 1508 + }) 1509 + } 1510 + TokenKind::Plus => { 1511 + self.advance(); 1512 + let arg = self.parse_unary_expression()?; 1513 + Ok(Expr { 1514 + kind: ExprKind::Unary { 1515 + op: UnaryOp::Plus, 1516 + argument: Box::new(arg), 1517 + }, 1518 + span: self.span_from(start), 1519 + }) 1520 + } 1521 + TokenKind::Not => { 1522 + self.advance(); 1523 + let arg = self.parse_unary_expression()?; 1524 + Ok(Expr { 1525 + kind: ExprKind::Unary { 1526 + op: UnaryOp::Not, 1527 + argument: Box::new(arg), 1528 + }, 1529 + span: self.span_from(start), 1530 + }) 1531 + } 1532 + TokenKind::Tilde => { 1533 + self.advance(); 1534 + let arg = self.parse_unary_expression()?; 1535 + Ok(Expr { 1536 + kind: ExprKind::Unary { 1537 + op: UnaryOp::BitwiseNot, 1538 + argument: Box::new(arg), 1539 + }, 1540 + span: self.span_from(start), 1541 + }) 1542 + } 1543 + TokenKind::Typeof => { 1544 + self.advance(); 1545 + let arg = self.parse_unary_expression()?; 1546 + Ok(Expr { 1547 + kind: ExprKind::Unary { 1548 + op: UnaryOp::Typeof, 1549 + argument: Box::new(arg), 1550 + }, 1551 + span: self.span_from(start), 1552 + }) 1553 + } 1554 + TokenKind::Void => { 1555 + self.advance(); 1556 + let arg = self.parse_unary_expression()?; 1557 + Ok(Expr { 1558 + kind: ExprKind::Unary { 1559 + op: UnaryOp::Void, 1560 + argument: Box::new(arg), 1561 + }, 1562 + span: self.span_from(start), 1563 + }) 1564 + } 1565 + TokenKind::Delete => { 1566 + self.advance(); 1567 + let arg = self.parse_unary_expression()?; 1568 + Ok(Expr { 1569 + kind: ExprKind::Unary { 1570 + op: UnaryOp::Delete, 1571 + argument: Box::new(arg), 1572 + }, 1573 + span: self.span_from(start), 1574 + }) 1575 + } 1576 + TokenKind::PlusPlus => { 1577 + self.advance(); 1578 + let arg = self.parse_unary_expression()?; 1579 + Ok(Expr { 1580 + kind: ExprKind::Update { 1581 + op: UpdateOp::Increment, 1582 + argument: Box::new(arg), 1583 + prefix: true, 1584 + }, 1585 + span: self.span_from(start), 1586 + }) 1587 + } 1588 + TokenKind::MinusMinus => { 1589 + self.advance(); 1590 + let arg = self.parse_unary_expression()?; 1591 + Ok(Expr { 1592 + kind: ExprKind::Update { 1593 + op: UpdateOp::Decrement, 1594 + argument: Box::new(arg), 1595 + prefix: true, 1596 + }, 1597 + span: self.span_from(start), 1598 + }) 1599 + } 1600 + TokenKind::Await => { 1601 + self.advance(); 1602 + let arg = self.parse_unary_expression()?; 1603 + Ok(Expr { 1604 + kind: ExprKind::Await(Box::new(arg)), 1605 + span: self.span_from(start), 1606 + }) 1607 + } 1608 + _ => self.parse_postfix_expression(), 1609 + } 1610 + } 1611 + 1612 + fn parse_postfix_expression(&mut self) -> Result<Expr, ParseError> { 1613 + let start = self.start_span(); 1614 + let mut expr = self.parse_call_expression()?; 1615 + 1616 + if !self.peek().preceded_by_newline { 1617 + if matches!(self.peek_kind(), TokenKind::PlusPlus) { 1618 + self.advance(); 1619 + expr = Expr { 1620 + kind: ExprKind::Update { 1621 + op: UpdateOp::Increment, 1622 + argument: Box::new(expr), 1623 + prefix: false, 1624 + }, 1625 + span: self.span_from(start), 1626 + }; 1627 + } else if matches!(self.peek_kind(), TokenKind::MinusMinus) { 1628 + self.advance(); 1629 + expr = Expr { 1630 + kind: ExprKind::Update { 1631 + op: UpdateOp::Decrement, 1632 + argument: Box::new(expr), 1633 + prefix: false, 1634 + }, 1635 + span: self.span_from(start), 1636 + }; 1637 + } 1638 + } 1639 + 1640 + Ok(expr) 1641 + } 1642 + 1643 + fn parse_call_expression(&mut self) -> Result<Expr, ParseError> { 1644 + let start = self.start_span(); 1645 + 1646 + if matches!(self.peek_kind(), TokenKind::New) { 1647 + return self.parse_new_expression(); 1648 + } 1649 + 1650 + let mut expr = self.parse_primary_expression()?; 1651 + 1652 + loop { 1653 + match self.peek_kind() { 1654 + TokenKind::Dot => { 1655 + self.advance(); 1656 + let prop_start = self.start_span(); 1657 + let name = self.expect_identifier()?; 1658 + expr = Expr { 1659 + kind: ExprKind::Member { 1660 + object: Box::new(expr), 1661 + property: Box::new(Expr { 1662 + kind: ExprKind::Identifier(name), 1663 + span: self.span_from(prop_start), 1664 + }), 1665 + computed: false, 1666 + }, 1667 + span: self.span_from(start), 1668 + }; 1669 + } 1670 + TokenKind::LBracket => { 1671 + self.advance(); 1672 + let prop = self.parse_expression()?; 1673 + self.expect(&TokenKind::RBracket)?; 1674 + expr = Expr { 1675 + kind: ExprKind::Member { 1676 + object: Box::new(expr), 1677 + property: Box::new(prop), 1678 + computed: true, 1679 + }, 1680 + span: self.span_from(start), 1681 + }; 1682 + } 1683 + TokenKind::LParen => { 1684 + let arguments = self.parse_arguments()?; 1685 + expr = Expr { 1686 + kind: ExprKind::Call { 1687 + callee: Box::new(expr), 1688 + arguments, 1689 + }, 1690 + span: self.span_from(start), 1691 + }; 1692 + } 1693 + TokenKind::QuestionDot => { 1694 + self.advance(); 1695 + // ?. can be followed by identifier, [expr], or (args) 1696 + match self.peek_kind() { 1697 + TokenKind::LBracket => { 1698 + self.advance(); 1699 + let prop = self.parse_expression()?; 1700 + self.expect(&TokenKind::RBracket)?; 1701 + expr = Expr { 1702 + kind: ExprKind::Member { 1703 + object: Box::new(Expr { 1704 + kind: ExprKind::OptionalChain { 1705 + base: Box::new(expr.clone()), 1706 + }, 1707 + span: self.span_from(start), 1708 + }), 1709 + property: Box::new(prop), 1710 + computed: true, 1711 + }, 1712 + span: self.span_from(start), 1713 + }; 1714 + } 1715 + TokenKind::LParen => { 1716 + let arguments = self.parse_arguments()?; 1717 + expr = Expr { 1718 + kind: ExprKind::Call { 1719 + callee: Box::new(Expr { 1720 + kind: ExprKind::OptionalChain { 1721 + base: Box::new(expr.clone()), 1722 + }, 1723 + span: self.span_from(start), 1724 + }), 1725 + arguments, 1726 + }, 1727 + span: self.span_from(start), 1728 + }; 1729 + } 1730 + _ => { 1731 + let prop_start = self.start_span(); 1732 + let name = self.expect_identifier()?; 1733 + expr = Expr { 1734 + kind: ExprKind::Member { 1735 + object: Box::new(Expr { 1736 + kind: ExprKind::OptionalChain { 1737 + base: Box::new(expr.clone()), 1738 + }, 1739 + span: self.span_from(start), 1740 + }), 1741 + property: Box::new(Expr { 1742 + kind: ExprKind::Identifier(name), 1743 + span: self.span_from(prop_start), 1744 + }), 1745 + computed: false, 1746 + }, 1747 + span: self.span_from(start), 1748 + }; 1749 + } 1750 + } 1751 + } 1752 + TokenKind::TemplateFull(_) | TokenKind::TemplateHead(_) => { 1753 + let quasi = self.parse_template_literal()?; 1754 + expr = Expr { 1755 + kind: ExprKind::TaggedTemplate { 1756 + tag: Box::new(expr), 1757 + quasi: Box::new(quasi), 1758 + }, 1759 + span: self.span_from(start), 1760 + }; 1761 + } 1762 + _ => break, 1763 + } 1764 + } 1765 + 1766 + Ok(expr) 1767 + } 1768 + 1769 + fn parse_new_expression(&mut self) -> Result<Expr, ParseError> { 1770 + let start = self.start_span(); 1771 + self.expect(&TokenKind::New)?; 1772 + 1773 + // new new Foo() → new (new Foo()) 1774 + if matches!(self.peek_kind(), TokenKind::New) { 1775 + let callee = self.parse_new_expression()?; 1776 + return Ok(Expr { 1777 + kind: ExprKind::New { 1778 + callee: Box::new(callee), 1779 + arguments: vec![], 1780 + }, 1781 + span: self.span_from(start), 1782 + }); 1783 + } 1784 + 1785 + let callee = self.parse_primary_expression()?; 1786 + // Allow member access on the callee 1787 + let callee = self.parse_member_chain(start, callee)?; 1788 + let arguments = if self.at(&TokenKind::LParen) { 1789 + self.parse_arguments()? 1790 + } else { 1791 + vec![] 1792 + }; 1793 + Ok(Expr { 1794 + kind: ExprKind::New { 1795 + callee: Box::new(callee), 1796 + arguments, 1797 + }, 1798 + span: self.span_from(start), 1799 + }) 1800 + } 1801 + 1802 + fn parse_member_chain(&mut self, start: SourcePos, mut expr: Expr) -> Result<Expr, ParseError> { 1803 + loop { 1804 + match self.peek_kind() { 1805 + TokenKind::Dot => { 1806 + self.advance(); 1807 + let prop_start = self.start_span(); 1808 + let name = self.expect_identifier()?; 1809 + expr = Expr { 1810 + kind: ExprKind::Member { 1811 + object: Box::new(expr), 1812 + property: Box::new(Expr { 1813 + kind: ExprKind::Identifier(name), 1814 + span: self.span_from(prop_start), 1815 + }), 1816 + computed: false, 1817 + }, 1818 + span: self.span_from(start), 1819 + }; 1820 + } 1821 + TokenKind::LBracket => { 1822 + self.advance(); 1823 + let prop = self.parse_expression()?; 1824 + self.expect(&TokenKind::RBracket)?; 1825 + expr = Expr { 1826 + kind: ExprKind::Member { 1827 + object: Box::new(expr), 1828 + property: Box::new(prop), 1829 + computed: true, 1830 + }, 1831 + span: self.span_from(start), 1832 + }; 1833 + } 1834 + _ => break, 1835 + } 1836 + } 1837 + Ok(expr) 1838 + } 1839 + 1840 + fn parse_left_hand_side_expression(&mut self) -> Result<Expr, ParseError> { 1841 + self.parse_call_expression() 1842 + } 1843 + 1844 + fn parse_arguments(&mut self) -> Result<Vec<Expr>, ParseError> { 1845 + self.expect(&TokenKind::LParen)?; 1846 + let mut args = Vec::new(); 1847 + while !self.at(&TokenKind::RParen) && !self.at_eof() { 1848 + if self.at(&TokenKind::Ellipsis) { 1849 + let start = self.start_span(); 1850 + self.advance(); 1851 + let arg = self.parse_assignment_expression()?; 1852 + args.push(Expr { 1853 + kind: ExprKind::Spread(Box::new(arg)), 1854 + span: self.span_from(start), 1855 + }); 1856 + } else { 1857 + args.push(self.parse_assignment_expression()?); 1858 + } 1859 + if !self.eat(&TokenKind::Comma) { 1860 + break; 1861 + } 1862 + } 1863 + self.expect(&TokenKind::RParen)?; 1864 + Ok(args) 1865 + } 1866 + 1867 + // ── Primary expressions ───────────────────────────────── 1868 + 1869 + fn parse_primary_expression(&mut self) -> Result<Expr, ParseError> { 1870 + let start = self.start_span(); 1871 + match self.peek_kind().clone() { 1872 + TokenKind::Number(n) => { 1873 + self.advance(); 1874 + Ok(Expr { 1875 + kind: ExprKind::Number(n), 1876 + span: self.span_from(start), 1877 + }) 1878 + } 1879 + TokenKind::String(s) => { 1880 + self.advance(); 1881 + Ok(Expr { 1882 + kind: ExprKind::String(s), 1883 + span: self.span_from(start), 1884 + }) 1885 + } 1886 + TokenKind::True => { 1887 + self.advance(); 1888 + Ok(Expr { 1889 + kind: ExprKind::Bool(true), 1890 + span: self.span_from(start), 1891 + }) 1892 + } 1893 + TokenKind::False => { 1894 + self.advance(); 1895 + Ok(Expr { 1896 + kind: ExprKind::Bool(false), 1897 + span: self.span_from(start), 1898 + }) 1899 + } 1900 + TokenKind::Null => { 1901 + self.advance(); 1902 + Ok(Expr { 1903 + kind: ExprKind::Null, 1904 + span: self.span_from(start), 1905 + }) 1906 + } 1907 + TokenKind::This => { 1908 + self.advance(); 1909 + Ok(Expr { 1910 + kind: ExprKind::This, 1911 + span: self.span_from(start), 1912 + }) 1913 + } 1914 + TokenKind::Identifier(name) => { 1915 + self.advance(); 1916 + Ok(Expr { 1917 + kind: ExprKind::Identifier(name), 1918 + span: self.span_from(start), 1919 + }) 1920 + } 1921 + TokenKind::LParen => self.parse_parenthesized_expression(), 1922 + TokenKind::LBracket => self.parse_array_expression(), 1923 + TokenKind::LBrace => self.parse_object_expression(), 1924 + TokenKind::Function => self.parse_function_expression(), 1925 + TokenKind::Class => self.parse_class_expression(), 1926 + TokenKind::Async => { 1927 + // async function expression 1928 + if matches!(self.peek_ahead(1), TokenKind::Function) 1929 + && !self.tokens[self.pos + 1].preceded_by_newline 1930 + { 1931 + return self.parse_async_function_expression(); 1932 + } 1933 + // Otherwise treat 'async' as an identifier 1934 + self.advance(); 1935 + Ok(Expr { 1936 + kind: ExprKind::Identifier("async".into()), 1937 + span: self.span_from(start), 1938 + }) 1939 + } 1940 + TokenKind::TemplateFull(_) | TokenKind::TemplateHead(_) => { 1941 + self.parse_template_literal() 1942 + } 1943 + TokenKind::RegExp { pattern, flags } => { 1944 + self.advance(); 1945 + Ok(Expr { 1946 + kind: ExprKind::RegExp { pattern, flags }, 1947 + span: self.span_from(start), 1948 + }) 1949 + } 1950 + TokenKind::Yield => { 1951 + self.advance(); 1952 + let delegate = self.eat(&TokenKind::Star); 1953 + let argument = if !self.peek().preceded_by_newline 1954 + && !matches!( 1955 + self.peek_kind(), 1956 + TokenKind::Semicolon 1957 + | TokenKind::RBrace 1958 + | TokenKind::RParen 1959 + | TokenKind::RBracket 1960 + | TokenKind::Colon 1961 + | TokenKind::Comma 1962 + | TokenKind::Eof 1963 + ) { 1964 + Some(Box::new(self.parse_assignment_expression()?)) 1965 + } else { 1966 + None 1967 + }; 1968 + Ok(Expr { 1969 + kind: ExprKind::Yield { argument, delegate }, 1970 + span: self.span_from(start), 1971 + }) 1972 + } 1973 + TokenKind::Super => { 1974 + self.advance(); 1975 + Ok(Expr { 1976 + kind: ExprKind::Identifier("super".into()), 1977 + span: self.span_from(start), 1978 + }) 1979 + } 1980 + TokenKind::Import => { 1981 + // import() call expression 1982 + self.advance(); 1983 + Ok(Expr { 1984 + kind: ExprKind::Identifier("import".into()), 1985 + span: self.span_from(start), 1986 + }) 1987 + } 1988 + _ => Err(self.error(format!("unexpected token {:?}", self.peek_kind()))), 1989 + } 1990 + } 1991 + 1992 + fn parse_parenthesized_expression(&mut self) -> Result<Expr, ParseError> { 1993 + let start = self.start_span(); 1994 + self.expect(&TokenKind::LParen)?; 1995 + 1996 + // Empty parens: `() => ...` 1997 + if self.at(&TokenKind::RParen) { 1998 + self.advance(); 1999 + // Must be arrow 2000 + if !matches!(self.peek_kind(), TokenKind::Arrow) { 2001 + return Err(self.error("unexpected empty parentheses".into())); 2002 + } 2003 + // Arrow will be handled by caller 2004 + return Ok(Expr { 2005 + kind: ExprKind::Sequence(vec![]), 2006 + span: self.span_from(start), 2007 + }); 2008 + } 2009 + 2010 + // `(...rest) => ...` 2011 + if self.at(&TokenKind::Ellipsis) { 2012 + // This must be an arrow parameter list with rest 2013 + let rest_start = self.start_span(); 2014 + self.advance(); 2015 + let rest_pat = self.parse_binding_pattern()?; 2016 + self.expect(&TokenKind::RParen)?; 2017 + // Must be followed by => 2018 + if !matches!(self.peek_kind(), TokenKind::Arrow) { 2019 + return Err(self.error("expected '=>'".into())); 2020 + } 2021 + let _ = rest_pat; // Will be handled as pattern 2022 + // Return a marker that the arrow handler will convert 2023 + return Ok(Expr { 2024 + kind: ExprKind::Spread(Box::new(Expr { 2025 + kind: match rest_pat.kind { 2026 + PatternKind::Identifier(name) => ExprKind::Identifier(name), 2027 + _ => { 2028 + return Err(ParseError { 2029 + message: "complex rest pattern in arrow".into(), 2030 + pos: rest_start, 2031 + }) 2032 + } 2033 + }, 2034 + span: rest_pat.span, 2035 + })), 2036 + span: self.span_from(start), 2037 + }); 2038 + } 2039 + 2040 + let expr = self.parse_expression()?; 2041 + self.expect(&TokenKind::RParen)?; 2042 + Ok(expr) 2043 + } 2044 + 2045 + fn parse_array_expression(&mut self) -> Result<Expr, ParseError> { 2046 + let start = self.start_span(); 2047 + self.expect(&TokenKind::LBracket)?; 2048 + let mut elements = Vec::new(); 2049 + while !self.at(&TokenKind::RBracket) && !self.at_eof() { 2050 + if self.eat(&TokenKind::Comma) { 2051 + elements.push(None); 2052 + continue; 2053 + } 2054 + if self.at(&TokenKind::Ellipsis) { 2055 + let spread_start = self.start_span(); 2056 + self.advance(); 2057 + let arg = self.parse_assignment_expression()?; 2058 + elements.push(Some(ArrayElement::Spread(Expr { 2059 + kind: ExprKind::Spread(Box::new(arg)), 2060 + span: self.span_from(spread_start), 2061 + }))); 2062 + } else { 2063 + let elem = self.parse_assignment_expression()?; 2064 + elements.push(Some(ArrayElement::Expr(elem))); 2065 + } 2066 + if !self.eat(&TokenKind::Comma) { 2067 + break; 2068 + } 2069 + } 2070 + self.expect(&TokenKind::RBracket)?; 2071 + Ok(Expr { 2072 + kind: ExprKind::Array(elements), 2073 + span: self.span_from(start), 2074 + }) 2075 + } 2076 + 2077 + fn parse_object_expression(&mut self) -> Result<Expr, ParseError> { 2078 + let start = self.start_span(); 2079 + self.expect(&TokenKind::LBrace)?; 2080 + let mut properties = Vec::new(); 2081 + while !self.at(&TokenKind::RBrace) && !self.at_eof() { 2082 + let prop = self.parse_object_property()?; 2083 + properties.push(prop); 2084 + if !self.eat(&TokenKind::Comma) { 2085 + break; 2086 + } 2087 + } 2088 + self.expect(&TokenKind::RBrace)?; 2089 + Ok(Expr { 2090 + kind: ExprKind::Object(properties), 2091 + span: self.span_from(start), 2092 + }) 2093 + } 2094 + 2095 + fn parse_object_property(&mut self) -> Result<Property, ParseError> { 2096 + let prop_start = self.start_span(); 2097 + 2098 + // Spread: `...expr` 2099 + if self.at(&TokenKind::Ellipsis) { 2100 + self.advance(); 2101 + let arg = self.parse_assignment_expression()?; 2102 + return Ok(Property { 2103 + key: PropertyKey::Identifier("".into()), 2104 + value: Some(arg), 2105 + kind: PropertyKind::Init, 2106 + computed: false, 2107 + shorthand: false, 2108 + method: false, 2109 + span: self.span_from(prop_start), 2110 + }); 2111 + } 2112 + 2113 + // Getter/setter: `get name() {}` or `set name(v) {}` 2114 + if let TokenKind::Identifier(ref name) = self.peek_kind().clone() { 2115 + if (name == "get" || name == "set") 2116 + && !matches!( 2117 + self.peek_ahead(1), 2118 + TokenKind::Colon 2119 + | TokenKind::Comma 2120 + | TokenKind::RBrace 2121 + | TokenKind::LParen 2122 + | TokenKind::Assign 2123 + ) 2124 + { 2125 + let kind = if name == "get" { 2126 + PropertyKind::Get 2127 + } else { 2128 + PropertyKind::Set 2129 + }; 2130 + self.advance(); 2131 + let (key, computed) = self.parse_property_name()?; 2132 + let (params, body) = self.parse_function_params_and_body()?; 2133 + return Ok(Property { 2134 + key, 2135 + value: Some(Expr { 2136 + kind: ExprKind::Function(FunctionDef { 2137 + id: None, 2138 + params, 2139 + body, 2140 + is_async: false, 2141 + is_generator: false, 2142 + }), 2143 + span: self.span_from(prop_start), 2144 + }), 2145 + kind, 2146 + computed, 2147 + shorthand: false, 2148 + method: true, 2149 + span: self.span_from(prop_start), 2150 + }); 2151 + } 2152 + } 2153 + 2154 + // Generator method: `*name() {}` 2155 + if self.eat(&TokenKind::Star) { 2156 + let (key, computed) = self.parse_property_name()?; 2157 + let (params, body) = self.parse_function_params_and_body()?; 2158 + return Ok(Property { 2159 + key, 2160 + value: Some(Expr { 2161 + kind: ExprKind::Function(FunctionDef { 2162 + id: None, 2163 + params, 2164 + body, 2165 + is_async: false, 2166 + is_generator: true, 2167 + }), 2168 + span: self.span_from(prop_start), 2169 + }), 2170 + kind: PropertyKind::Init, 2171 + computed, 2172 + shorthand: false, 2173 + method: true, 2174 + span: self.span_from(prop_start), 2175 + }); 2176 + } 2177 + 2178 + // Async method: `async name() {}` 2179 + let is_async = if matches!(self.peek_kind(), TokenKind::Async) 2180 + && !matches!( 2181 + self.peek_ahead(1), 2182 + TokenKind::Colon | TokenKind::Comma | TokenKind::RBrace | TokenKind::Assign 2183 + ) 2184 + && !self 2185 + .tokens 2186 + .get(self.pos + 1) 2187 + .is_none_or(|t| t.preceded_by_newline) 2188 + { 2189 + self.advance(); 2190 + true 2191 + } else { 2192 + false 2193 + }; 2194 + 2195 + let is_generator = is_async && self.eat(&TokenKind::Star); 2196 + 2197 + let (key, computed) = self.parse_property_name()?; 2198 + 2199 + // Method shorthand: `name() {}` or `name(params) {}` 2200 + if self.at(&TokenKind::LParen) { 2201 + let (params, body) = self.parse_function_params_and_body()?; 2202 + return Ok(Property { 2203 + key, 2204 + value: Some(Expr { 2205 + kind: ExprKind::Function(FunctionDef { 2206 + id: None, 2207 + params, 2208 + body, 2209 + is_async, 2210 + is_generator, 2211 + }), 2212 + span: self.span_from(prop_start), 2213 + }), 2214 + kind: PropertyKind::Init, 2215 + computed, 2216 + shorthand: false, 2217 + method: true, 2218 + span: self.span_from(prop_start), 2219 + }); 2220 + } 2221 + 2222 + // Shorthand: `{ name }` or `{ name = default }` 2223 + if !computed 2224 + && matches!( 2225 + self.peek_kind(), 2226 + TokenKind::Comma | TokenKind::RBrace | TokenKind::Assign 2227 + ) 2228 + { 2229 + let name = match &key { 2230 + PropertyKey::Identifier(n) => n.clone(), 2231 + _ => return Err(self.error("expected identifier for shorthand property".into())), 2232 + }; 2233 + let value = if self.eat(&TokenKind::Assign) { 2234 + let default = self.parse_assignment_expression()?; 2235 + Some(Expr { 2236 + kind: ExprKind::Assignment { 2237 + op: AssignOp::Assign, 2238 + left: Box::new(Expr { 2239 + kind: ExprKind::Identifier(name.clone()), 2240 + span: self.span_from(prop_start), 2241 + }), 2242 + right: Box::new(default), 2243 + }, 2244 + span: self.span_from(prop_start), 2245 + }) 2246 + } else { 2247 + Some(Expr { 2248 + kind: ExprKind::Identifier(name), 2249 + span: self.span_from(prop_start), 2250 + }) 2251 + }; 2252 + return Ok(Property { 2253 + key, 2254 + value, 2255 + kind: PropertyKind::Init, 2256 + computed, 2257 + shorthand: true, 2258 + method: false, 2259 + span: self.span_from(prop_start), 2260 + }); 2261 + } 2262 + 2263 + // Regular: `key: value` 2264 + self.expect(&TokenKind::Colon)?; 2265 + let value = self.parse_assignment_expression()?; 2266 + Ok(Property { 2267 + key, 2268 + value: Some(value), 2269 + kind: PropertyKind::Init, 2270 + computed, 2271 + shorthand: false, 2272 + method: false, 2273 + span: self.span_from(prop_start), 2274 + }) 2275 + } 2276 + 2277 + fn parse_property_name(&mut self) -> Result<(PropertyKey, bool), ParseError> { 2278 + match self.peek_kind().clone() { 2279 + TokenKind::Identifier(name) => { 2280 + self.advance(); 2281 + Ok((PropertyKey::Identifier(name), false)) 2282 + } 2283 + TokenKind::String(s) => { 2284 + self.advance(); 2285 + Ok((PropertyKey::String(s), false)) 2286 + } 2287 + TokenKind::Number(n) => { 2288 + self.advance(); 2289 + Ok((PropertyKey::Number(n), false)) 2290 + } 2291 + TokenKind::LBracket => { 2292 + self.advance(); 2293 + let expr = self.parse_assignment_expression()?; 2294 + self.expect(&TokenKind::RBracket)?; 2295 + Ok((PropertyKey::Computed(expr), true)) 2296 + } 2297 + // Keywords can also be property names 2298 + _ if is_keyword(self.peek_kind()) => { 2299 + let name = format!("{}", self.peek_kind()); 2300 + self.advance(); 2301 + Ok((PropertyKey::Identifier(name), false)) 2302 + } 2303 + _ => Err(self.error(format!( 2304 + "expected property name, found {:?}", 2305 + self.peek_kind() 2306 + ))), 2307 + } 2308 + } 2309 + 2310 + fn parse_function_expression(&mut self) -> Result<Expr, ParseError> { 2311 + let start = self.start_span(); 2312 + self.expect(&TokenKind::Function)?; 2313 + let is_generator = self.eat(&TokenKind::Star); 2314 + let id = if let TokenKind::Identifier(_) = self.peek_kind() { 2315 + Some(self.expect_identifier()?) 2316 + } else { 2317 + None 2318 + }; 2319 + let (params, body) = self.parse_function_params_and_body()?; 2320 + Ok(Expr { 2321 + kind: ExprKind::Function(FunctionDef { 2322 + id, 2323 + params, 2324 + body, 2325 + is_async: false, 2326 + is_generator, 2327 + }), 2328 + span: self.span_from(start), 2329 + }) 2330 + } 2331 + 2332 + fn parse_async_function_expression(&mut self) -> Result<Expr, ParseError> { 2333 + let start = self.start_span(); 2334 + self.expect(&TokenKind::Async)?; 2335 + self.expect(&TokenKind::Function)?; 2336 + let is_generator = self.eat(&TokenKind::Star); 2337 + let id = if let TokenKind::Identifier(_) = self.peek_kind() { 2338 + Some(self.expect_identifier()?) 2339 + } else { 2340 + None 2341 + }; 2342 + let (params, body) = self.parse_function_params_and_body()?; 2343 + Ok(Expr { 2344 + kind: ExprKind::Function(FunctionDef { 2345 + id, 2346 + params, 2347 + body, 2348 + is_async: true, 2349 + is_generator, 2350 + }), 2351 + span: self.span_from(start), 2352 + }) 2353 + } 2354 + 2355 + fn parse_class_expression(&mut self) -> Result<Expr, ParseError> { 2356 + let start = self.start_span(); 2357 + let class_def = self.parse_class(false)?; 2358 + Ok(Expr { 2359 + kind: ExprKind::Class(class_def), 2360 + span: self.span_from(start), 2361 + }) 2362 + } 2363 + 2364 + fn parse_template_literal(&mut self) -> Result<Expr, ParseError> { 2365 + let start = self.start_span(); 2366 + match self.peek_kind().clone() { 2367 + TokenKind::TemplateFull(s) => { 2368 + self.advance(); 2369 + Ok(Expr { 2370 + kind: ExprKind::TemplateLiteral { 2371 + quasis: vec![s], 2372 + expressions: vec![], 2373 + }, 2374 + span: self.span_from(start), 2375 + }) 2376 + } 2377 + TokenKind::TemplateHead(s) => { 2378 + self.advance(); 2379 + let mut quasis = vec![s]; 2380 + let mut expressions = Vec::new(); 2381 + loop { 2382 + expressions.push(self.parse_expression()?); 2383 + match self.peek_kind().clone() { 2384 + TokenKind::TemplateMiddle(s) => { 2385 + self.advance(); 2386 + quasis.push(s); 2387 + } 2388 + TokenKind::TemplateTail(s) => { 2389 + self.advance(); 2390 + quasis.push(s); 2391 + break; 2392 + } 2393 + _ => { 2394 + return Err(self.error("expected template continuation or tail".into())); 2395 + } 2396 + } 2397 + } 2398 + Ok(Expr { 2399 + kind: ExprKind::TemplateLiteral { 2400 + quasis, 2401 + expressions, 2402 + }, 2403 + span: self.span_from(start), 2404 + }) 2405 + } 2406 + _ => Err(self.error("expected template literal".into())), 2407 + } 2408 + } 2409 + 2410 + // ── Operator tables ───────────────────────────────────── 2411 + 2412 + fn peek_binary_op(&self) -> Option<(BinOrLogical, u8, u8)> { 2413 + let kind = self.peek_kind(); 2414 + let (op, left_bp, right_bp) = match kind { 2415 + TokenKind::Or => (BinOrLogical::Logical(LogicalOp::Or), 2, 3), 2416 + TokenKind::And => (BinOrLogical::Logical(LogicalOp::And), 4, 5), 2417 + TokenKind::Nullish => (BinOrLogical::Logical(LogicalOp::Nullish), 6, 7), 2418 + TokenKind::Pipe => (BinOrLogical::Binary(BinaryOp::BitOr), 8, 9), 2419 + TokenKind::Caret => (BinOrLogical::Binary(BinaryOp::BitXor), 10, 11), 2420 + TokenKind::Amp => (BinOrLogical::Binary(BinaryOp::BitAnd), 12, 13), 2421 + TokenKind::Eq => (BinOrLogical::Binary(BinaryOp::Eq), 14, 15), 2422 + TokenKind::Ne => (BinOrLogical::Binary(BinaryOp::Ne), 14, 15), 2423 + TokenKind::StrictEq => (BinOrLogical::Binary(BinaryOp::StrictEq), 14, 15), 2424 + TokenKind::StrictNe => (BinOrLogical::Binary(BinaryOp::StrictNe), 14, 15), 2425 + TokenKind::Lt => (BinOrLogical::Binary(BinaryOp::Lt), 16, 17), 2426 + TokenKind::Gt => (BinOrLogical::Binary(BinaryOp::Gt), 16, 17), 2427 + TokenKind::Le => (BinOrLogical::Binary(BinaryOp::Le), 16, 17), 2428 + TokenKind::Ge => (BinOrLogical::Binary(BinaryOp::Ge), 16, 17), 2429 + TokenKind::Instanceof => (BinOrLogical::Binary(BinaryOp::Instanceof), 16, 17), 2430 + TokenKind::In if self.allow_in => (BinOrLogical::Binary(BinaryOp::In), 16, 17), 2431 + TokenKind::Shl => (BinOrLogical::Binary(BinaryOp::Shl), 18, 19), 2432 + TokenKind::Shr => (BinOrLogical::Binary(BinaryOp::Shr), 18, 19), 2433 + TokenKind::Ushr => (BinOrLogical::Binary(BinaryOp::Ushr), 18, 19), 2434 + TokenKind::Plus => (BinOrLogical::Binary(BinaryOp::Add), 20, 21), 2435 + TokenKind::Minus => (BinOrLogical::Binary(BinaryOp::Sub), 20, 21), 2436 + TokenKind::Star => (BinOrLogical::Binary(BinaryOp::Mul), 22, 23), 2437 + TokenKind::Slash => (BinOrLogical::Binary(BinaryOp::Div), 22, 23), 2438 + TokenKind::Percent => (BinOrLogical::Binary(BinaryOp::Rem), 22, 23), 2439 + TokenKind::Exp => (BinOrLogical::Binary(BinaryOp::Exp), 25, 24), // right-assoc 2440 + _ => return None, 2441 + }; 2442 + Some((op, left_bp, right_bp)) 2443 + } 2444 + 2445 + fn peek_assign_op(&self) -> Option<AssignOp> { 2446 + match self.peek_kind() { 2447 + TokenKind::Assign => Some(AssignOp::Assign), 2448 + TokenKind::PlusAssign => Some(AssignOp::AddAssign), 2449 + TokenKind::MinusAssign => Some(AssignOp::SubAssign), 2450 + TokenKind::StarAssign => Some(AssignOp::MulAssign), 2451 + TokenKind::SlashAssign => Some(AssignOp::DivAssign), 2452 + TokenKind::PercentAssign => Some(AssignOp::RemAssign), 2453 + TokenKind::ExpAssign => Some(AssignOp::ExpAssign), 2454 + TokenKind::ShlAssign => Some(AssignOp::ShlAssign), 2455 + TokenKind::ShrAssign => Some(AssignOp::ShrAssign), 2456 + TokenKind::UshrAssign => Some(AssignOp::UshrAssign), 2457 + TokenKind::AmpAssign => Some(AssignOp::BitAndAssign), 2458 + TokenKind::PipeAssign => Some(AssignOp::BitOrAssign), 2459 + TokenKind::CaretAssign => Some(AssignOp::BitXorAssign), 2460 + TokenKind::AndAssign => Some(AssignOp::AndAssign), 2461 + TokenKind::OrAssign => Some(AssignOp::OrAssign), 2462 + TokenKind::NullishAssign => Some(AssignOp::NullishAssign), 2463 + _ => None, 2464 + } 2465 + } 2466 + 2467 + // ── Expression ↔ Pattern conversion ───────────────────── 2468 + 2469 + fn expr_to_pattern(&self, expr: &Expr) -> Result<Pattern, ParseError> { 2470 + let span = expr.span; 2471 + match &expr.kind { 2472 + ExprKind::Identifier(name) => Ok(Pattern { 2473 + kind: PatternKind::Identifier(name.clone()), 2474 + span, 2475 + }), 2476 + ExprKind::Array(elements) => { 2477 + let mut pats = Vec::new(); 2478 + let mut rest = None; 2479 + for elem in elements { 2480 + match elem { 2481 + None => pats.push(None), 2482 + Some(ArrayElement::Spread(e)) => { 2483 + if let ExprKind::Spread(inner) = &e.kind { 2484 + rest = Some(Box::new(self.expr_to_pattern(inner)?)); 2485 + } else { 2486 + rest = Some(Box::new(self.expr_to_pattern(e)?)); 2487 + } 2488 + } 2489 + Some(ArrayElement::Expr(e)) => { 2490 + pats.push(Some(self.expr_to_pattern(e)?)); 2491 + } 2492 + } 2493 + } 2494 + Ok(Pattern { 2495 + kind: PatternKind::Array { 2496 + elements: pats, 2497 + rest, 2498 + }, 2499 + span, 2500 + }) 2501 + } 2502 + ExprKind::Object(properties) => { 2503 + let mut pats = Vec::new(); 2504 + let mut rest = None; 2505 + for prop in properties { 2506 + if prop.key == PropertyKey::Identifier("".into()) { 2507 + if let Some(val) = &prop.value { 2508 + // Spread property 2509 + rest = Some(Box::new(self.expr_to_pattern(val)?)); 2510 + } 2511 + continue; 2512 + } 2513 + let value = if let Some(val) = &prop.value { 2514 + self.expr_to_pattern(val)? 2515 + } else { 2516 + continue; 2517 + }; 2518 + pats.push(ObjectPatternProp { 2519 + key: prop.key.clone(), 2520 + value, 2521 + computed: prop.computed, 2522 + shorthand: prop.shorthand, 2523 + span: prop.span, 2524 + }); 2525 + } 2526 + Ok(Pattern { 2527 + kind: PatternKind::Object { 2528 + properties: pats, 2529 + rest, 2530 + }, 2531 + span, 2532 + }) 2533 + } 2534 + ExprKind::Assignment { 2535 + op: AssignOp::Assign, 2536 + left, 2537 + right, 2538 + } => { 2539 + let left_pat = self.expr_to_pattern(left)?; 2540 + Ok(Pattern { 2541 + kind: PatternKind::Assign { 2542 + left: Box::new(left_pat), 2543 + right: right.clone(), 2544 + }, 2545 + span, 2546 + }) 2547 + } 2548 + ExprKind::Spread(inner) => self.expr_to_pattern(inner), 2549 + _ => Err(ParseError { 2550 + message: "invalid destructuring pattern".into(), 2551 + pos: span.start, 2552 + }), 2553 + } 2554 + } 2555 + 2556 + fn expr_to_params(&self, expr: &Expr) -> Result<Vec<Pattern>, ParseError> { 2557 + match &expr.kind { 2558 + ExprKind::Sequence(exprs) if exprs.is_empty() => Ok(vec![]), 2559 + ExprKind::Sequence(exprs) => { 2560 + let mut params = Vec::new(); 2561 + for e in exprs { 2562 + params.push(self.expr_to_pattern(e)?); 2563 + } 2564 + Ok(params) 2565 + } 2566 + ExprKind::Spread(inner) => { 2567 + let pat = self.expr_to_pattern(inner)?; 2568 + Ok(vec![pat]) 2569 + } 2570 + _ => { 2571 + // Single expression as single parameter 2572 + Ok(vec![self.expr_to_pattern(expr)?]) 2573 + } 2574 + } 2575 + } 2576 + } 2577 + 2578 + // ── Helpers ───────────────────────────────────────────────── 2579 + 2580 + /// Distinguishes binary operators from logical operators in Pratt parsing. 2581 + enum BinOrLogical { 2582 + Binary(BinaryOp), 2583 + Logical(LogicalOp), 2584 + } 2585 + 2586 + /// Returns true if the token kind is a keyword (used for property name parsing). 2587 + fn is_keyword(kind: &TokenKind) -> bool { 2588 + matches!( 2589 + kind, 2590 + TokenKind::Await 2591 + | TokenKind::Break 2592 + | TokenKind::Case 2593 + | TokenKind::Catch 2594 + | TokenKind::Class 2595 + | TokenKind::Const 2596 + | TokenKind::Continue 2597 + | TokenKind::Debugger 2598 + | TokenKind::Default 2599 + | TokenKind::Delete 2600 + | TokenKind::Do 2601 + | TokenKind::Else 2602 + | TokenKind::Export 2603 + | TokenKind::Extends 2604 + | TokenKind::Finally 2605 + | TokenKind::For 2606 + | TokenKind::Function 2607 + | TokenKind::If 2608 + | TokenKind::Import 2609 + | TokenKind::In 2610 + | TokenKind::Instanceof 2611 + | TokenKind::Let 2612 + | TokenKind::New 2613 + | TokenKind::Of 2614 + | TokenKind::Return 2615 + | TokenKind::Static 2616 + | TokenKind::Super 2617 + | TokenKind::Switch 2618 + | TokenKind::This 2619 + | TokenKind::Throw 2620 + | TokenKind::Try 2621 + | TokenKind::Typeof 2622 + | TokenKind::Var 2623 + | TokenKind::Void 2624 + | TokenKind::While 2625 + | TokenKind::With 2626 + | TokenKind::Yield 2627 + | TokenKind::Async 2628 + | TokenKind::True 2629 + | TokenKind::False 2630 + | TokenKind::Null 2631 + ) 2632 + } 2633 + 2634 + // ── Tests ─────────────────────────────────────────────────── 2635 + 2636 + #[cfg(test)] 2637 + mod tests { 2638 + use super::*; 2639 + 2640 + fn parse(src: &str) -> Program { 2641 + Parser::parse(src).unwrap() 2642 + } 2643 + 2644 + fn parse_expr(src: &str) -> Expr { 2645 + let prog = parse(src); 2646 + match &prog.body[0].kind { 2647 + StmtKind::Expr(e) => e.clone(), 2648 + _ => panic!("expected expression statement, got {:?}", prog.body[0].kind), 2649 + } 2650 + } 2651 + 2652 + fn parse_stmt(src: &str) -> Stmt { 2653 + let prog = parse(src); 2654 + prog.body[0].clone() 2655 + } 2656 + 2657 + // ── Literals ──────────────────────────────────────── 2658 + 2659 + #[test] 2660 + fn test_number_literal() { 2661 + let expr = parse_expr("42"); 2662 + assert_eq!(expr.kind, ExprKind::Number(42.0)); 2663 + } 2664 + 2665 + #[test] 2666 + fn test_string_literal() { 2667 + let expr = parse_expr("\"hello\""); 2668 + assert_eq!(expr.kind, ExprKind::String("hello".into())); 2669 + } 2670 + 2671 + #[test] 2672 + fn test_boolean_literals() { 2673 + assert_eq!(parse_expr("true").kind, ExprKind::Bool(true)); 2674 + assert_eq!(parse_expr("false").kind, ExprKind::Bool(false)); 2675 + } 2676 + 2677 + #[test] 2678 + fn test_null_literal() { 2679 + assert_eq!(parse_expr("null").kind, ExprKind::Null); 2680 + } 2681 + 2682 + #[test] 2683 + fn test_this() { 2684 + assert_eq!(parse_expr("this").kind, ExprKind::This); 2685 + } 2686 + 2687 + #[test] 2688 + fn test_identifier() { 2689 + assert_eq!(parse_expr("foo").kind, ExprKind::Identifier("foo".into())); 2690 + } 2691 + 2692 + #[test] 2693 + fn test_regexp() { 2694 + let expr = parse_expr("x = /test/gi"); 2695 + match &expr.kind { 2696 + ExprKind::Assignment { right, .. } => { 2697 + assert_eq!( 2698 + right.kind, 2699 + ExprKind::RegExp { 2700 + pattern: "test".into(), 2701 + flags: "gi".into() 2702 + } 2703 + ); 2704 + } 2705 + _ => panic!("expected assignment"), 2706 + } 2707 + } 2708 + 2709 + // ── Binary expressions ────────────────────────────── 2710 + 2711 + #[test] 2712 + fn test_addition() { 2713 + let expr = parse_expr("1 + 2"); 2714 + match expr.kind { 2715 + ExprKind::Binary { op, left, right } => { 2716 + assert_eq!(op, BinaryOp::Add); 2717 + assert_eq!(left.kind, ExprKind::Number(1.0)); 2718 + assert_eq!(right.kind, ExprKind::Number(2.0)); 2719 + } 2720 + _ => panic!("expected binary"), 2721 + } 2722 + } 2723 + 2724 + #[test] 2725 + fn test_precedence() { 2726 + // 1 + 2 * 3 should be 1 + (2 * 3) 2727 + let expr = parse_expr("1 + 2 * 3"); 2728 + match expr.kind { 2729 + ExprKind::Binary { 2730 + op: BinaryOp::Add, 2731 + left, 2732 + right, 2733 + } => { 2734 + assert_eq!(left.kind, ExprKind::Number(1.0)); 2735 + match right.kind { 2736 + ExprKind::Binary { 2737 + op: BinaryOp::Mul, .. 2738 + } => {} 2739 + _ => panic!("expected multiply on right"), 2740 + } 2741 + } 2742 + _ => panic!("expected binary add"), 2743 + } 2744 + } 2745 + 2746 + #[test] 2747 + fn test_exponentiation_right_assoc() { 2748 + // 2 ** 3 ** 2 should be 2 ** (3 ** 2) 2749 + let expr = parse_expr("2 ** 3 ** 2"); 2750 + match expr.kind { 2751 + ExprKind::Binary { 2752 + op: BinaryOp::Exp, 2753 + left, 2754 + right, 2755 + } => { 2756 + assert_eq!(left.kind, ExprKind::Number(2.0)); 2757 + match right.kind { 2758 + ExprKind::Binary { 2759 + op: BinaryOp::Exp, .. 2760 + } => {} 2761 + _ => panic!("expected exp on right"), 2762 + } 2763 + } 2764 + _ => panic!("expected binary exp"), 2765 + } 2766 + } 2767 + 2768 + #[test] 2769 + fn test_comparison() { 2770 + let expr = parse_expr("a === b"); 2771 + match expr.kind { 2772 + ExprKind::Binary { 2773 + op: BinaryOp::StrictEq, 2774 + .. 2775 + } => {} 2776 + _ => panic!("expected strict eq"), 2777 + } 2778 + } 2779 + 2780 + #[test] 2781 + fn test_logical_operators() { 2782 + let expr = parse_expr("a && b || c"); 2783 + // Should be (a && b) || c because && has higher precedence 2784 + match expr.kind { 2785 + ExprKind::Logical { 2786 + op: LogicalOp::Or, .. 2787 + } => {} 2788 + _ => panic!("expected logical or"), 2789 + } 2790 + } 2791 + 2792 + // ── Unary expressions ─────────────────────────────── 2793 + 2794 + #[test] 2795 + fn test_unary_minus() { 2796 + let expr = parse_expr("-x"); 2797 + match expr.kind { 2798 + ExprKind::Unary { 2799 + op: UnaryOp::Minus, 2800 + argument, 2801 + } => { 2802 + assert_eq!(argument.kind, ExprKind::Identifier("x".into())); 2803 + } 2804 + _ => panic!("expected unary minus"), 2805 + } 2806 + } 2807 + 2808 + #[test] 2809 + fn test_typeof() { 2810 + let expr = parse_expr("typeof x"); 2811 + match expr.kind { 2812 + ExprKind::Unary { 2813 + op: UnaryOp::Typeof, 2814 + .. 2815 + } => {} 2816 + _ => panic!("expected typeof"), 2817 + } 2818 + } 2819 + 2820 + #[test] 2821 + fn test_prefix_increment() { 2822 + let expr = parse_expr("++x"); 2823 + match expr.kind { 2824 + ExprKind::Update { 2825 + op: UpdateOp::Increment, 2826 + prefix: true, 2827 + .. 2828 + } => {} 2829 + _ => panic!("expected prefix increment"), 2830 + } 2831 + } 2832 + 2833 + #[test] 2834 + fn test_postfix_decrement() { 2835 + let expr = parse_expr("x--"); 2836 + match expr.kind { 2837 + ExprKind::Update { 2838 + op: UpdateOp::Decrement, 2839 + prefix: false, 2840 + .. 2841 + } => {} 2842 + _ => panic!("expected postfix decrement"), 2843 + } 2844 + } 2845 + 2846 + // ── Conditional expression ────────────────────────── 2847 + 2848 + #[test] 2849 + fn test_ternary() { 2850 + let expr = parse_expr("a ? b : c"); 2851 + match expr.kind { 2852 + ExprKind::Conditional { 2853 + test, 2854 + consequent, 2855 + alternate, 2856 + } => { 2857 + assert_eq!(test.kind, ExprKind::Identifier("a".into())); 2858 + assert_eq!(consequent.kind, ExprKind::Identifier("b".into())); 2859 + assert_eq!(alternate.kind, ExprKind::Identifier("c".into())); 2860 + } 2861 + _ => panic!("expected conditional"), 2862 + } 2863 + } 2864 + 2865 + // ── Assignment ────────────────────────────────────── 2866 + 2867 + #[test] 2868 + fn test_assignment() { 2869 + let expr = parse_expr("x = 42"); 2870 + match expr.kind { 2871 + ExprKind::Assignment { 2872 + op: AssignOp::Assign, 2873 + left, 2874 + right, 2875 + } => { 2876 + assert_eq!(left.kind, ExprKind::Identifier("x".into())); 2877 + assert_eq!(right.kind, ExprKind::Number(42.0)); 2878 + } 2879 + _ => panic!("expected assignment"), 2880 + } 2881 + } 2882 + 2883 + #[test] 2884 + fn test_compound_assignment() { 2885 + let expr = parse_expr("x += 1"); 2886 + match expr.kind { 2887 + ExprKind::Assignment { 2888 + op: AssignOp::AddAssign, 2889 + .. 2890 + } => {} 2891 + _ => panic!("expected add-assign"), 2892 + } 2893 + } 2894 + 2895 + // ── Member expressions ────────────────────────────── 2896 + 2897 + #[test] 2898 + fn test_dot_access() { 2899 + let expr = parse_expr("a.b"); 2900 + match expr.kind { 2901 + ExprKind::Member { 2902 + computed: false, .. 2903 + } => {} 2904 + _ => panic!("expected member access"), 2905 + } 2906 + } 2907 + 2908 + #[test] 2909 + fn test_bracket_access() { 2910 + let expr = parse_expr("a[0]"); 2911 + match expr.kind { 2912 + ExprKind::Member { computed: true, .. } => {} 2913 + _ => panic!("expected computed member"), 2914 + } 2915 + } 2916 + 2917 + // ── Call expressions ──────────────────────────────── 2918 + 2919 + #[test] 2920 + fn test_function_call() { 2921 + let expr = parse_expr("foo(1, 2)"); 2922 + match expr.kind { 2923 + ExprKind::Call { 2924 + callee, arguments, .. 2925 + } => { 2926 + assert_eq!(callee.kind, ExprKind::Identifier("foo".into())); 2927 + assert_eq!(arguments.len(), 2); 2928 + } 2929 + _ => panic!("expected call"), 2930 + } 2931 + } 2932 + 2933 + #[test] 2934 + fn test_method_call() { 2935 + let expr = parse_expr("obj.method()"); 2936 + match expr.kind { 2937 + ExprKind::Call { callee, .. } => match callee.kind { 2938 + ExprKind::Member { .. } => {} 2939 + _ => panic!("expected member callee"), 2940 + }, 2941 + _ => panic!("expected call"), 2942 + } 2943 + } 2944 + 2945 + #[test] 2946 + fn test_new_expression() { 2947 + let expr = parse_expr("new Foo(1)"); 2948 + match expr.kind { 2949 + ExprKind::New { 2950 + callee, arguments, .. 2951 + } => { 2952 + assert_eq!(callee.kind, ExprKind::Identifier("Foo".into())); 2953 + assert_eq!(arguments.len(), 1); 2954 + } 2955 + _ => panic!("expected new"), 2956 + } 2957 + } 2958 + 2959 + // ── Array and object literals ─────────────────────── 2960 + 2961 + #[test] 2962 + fn test_array_literal() { 2963 + let expr = parse_expr("[1, 2, 3]"); 2964 + match expr.kind { 2965 + ExprKind::Array(elements) => { 2966 + assert_eq!(elements.len(), 3); 2967 + } 2968 + _ => panic!("expected array"), 2969 + } 2970 + } 2971 + 2972 + #[test] 2973 + fn test_object_literal() { 2974 + let expr = parse_expr("({a: 1, b: 2})"); 2975 + match expr.kind { 2976 + ExprKind::Object(props) => { 2977 + assert_eq!(props.len(), 2); 2978 + assert_eq!(props[0].key, PropertyKey::Identifier("a".into())); 2979 + } 2980 + _ => panic!("expected object"), 2981 + } 2982 + } 2983 + 2984 + #[test] 2985 + fn test_shorthand_property() { 2986 + let expr = parse_expr("({x, y})"); 2987 + match expr.kind { 2988 + ExprKind::Object(props) => { 2989 + assert!(props[0].shorthand); 2990 + assert!(props[1].shorthand); 2991 + } 2992 + _ => panic!("expected object"), 2993 + } 2994 + } 2995 + 2996 + #[test] 2997 + fn test_computed_property() { 2998 + let expr = parse_expr("({[key]: value})"); 2999 + match expr.kind { 3000 + ExprKind::Object(props) => { 3001 + assert!(props[0].computed); 3002 + } 3003 + _ => panic!("expected object"), 3004 + } 3005 + } 3006 + 3007 + // ── Arrow functions ───────────────────────────────── 3008 + 3009 + #[test] 3010 + fn test_arrow_single_param() { 3011 + let expr = parse_expr("x => x + 1"); 3012 + match expr.kind { 3013 + ExprKind::Arrow { 3014 + params, 3015 + body: ArrowBody::Expr(_), 3016 + is_async: false, 3017 + } => { 3018 + assert_eq!(params.len(), 1); 3019 + } 3020 + _ => panic!("expected arrow"), 3021 + } 3022 + } 3023 + 3024 + #[test] 3025 + fn test_arrow_multi_param() { 3026 + let expr = parse_expr("(a, b) => a + b"); 3027 + match expr.kind { 3028 + ExprKind::Arrow { params, .. } => { 3029 + assert_eq!(params.len(), 2); 3030 + } 3031 + _ => panic!("expected arrow"), 3032 + } 3033 + } 3034 + 3035 + #[test] 3036 + fn test_arrow_body_block() { 3037 + let expr = parse_expr("() => { return 1; }"); 3038 + match expr.kind { 3039 + ExprKind::Arrow { 3040 + body: ArrowBody::Block(stmts), 3041 + .. 3042 + } => { 3043 + assert_eq!(stmts.len(), 1); 3044 + } 3045 + _ => panic!("expected arrow with block body"), 3046 + } 3047 + } 3048 + 3049 + // ── Template literals ─────────────────────────────── 3050 + 3051 + #[test] 3052 + fn test_template_no_subst() { 3053 + let expr = parse_expr("`hello`"); 3054 + match expr.kind { 3055 + ExprKind::TemplateLiteral { 3056 + quasis, 3057 + expressions, 3058 + } => { 3059 + assert_eq!(quasis, vec!["hello"]); 3060 + assert!(expressions.is_empty()); 3061 + } 3062 + _ => panic!("expected template literal"), 3063 + } 3064 + } 3065 + 3066 + #[test] 3067 + fn test_template_with_subst() { 3068 + let expr = parse_expr("`hello ${name}!`"); 3069 + match expr.kind { 3070 + ExprKind::TemplateLiteral { 3071 + quasis, 3072 + expressions, 3073 + } => { 3074 + assert_eq!(quasis, vec!["hello ", "!"]); 3075 + assert_eq!(expressions.len(), 1); 3076 + } 3077 + _ => panic!("expected template literal"), 3078 + } 3079 + } 3080 + 3081 + // ── Spread ────────────────────────────────────────── 3082 + 3083 + #[test] 3084 + fn test_spread_in_call() { 3085 + let expr = parse_expr("foo(...args)"); 3086 + match expr.kind { 3087 + ExprKind::Call { arguments, .. } => { 3088 + assert_eq!(arguments.len(), 1); 3089 + assert!(matches!(arguments[0].kind, ExprKind::Spread(_))); 3090 + } 3091 + _ => panic!("expected call"), 3092 + } 3093 + } 3094 + 3095 + // ── Variable declarations ─────────────────────────── 3096 + 3097 + #[test] 3098 + fn test_var_decl() { 3099 + let stmt = parse_stmt("var x = 42;"); 3100 + match stmt.kind { 3101 + StmtKind::VarDecl { kind, declarators } => { 3102 + assert_eq!(kind, VarKind::Var); 3103 + assert_eq!(declarators.len(), 1); 3104 + assert!(matches!( 3105 + declarators[0].pattern.kind, 3106 + PatternKind::Identifier(ref n) if n == "x" 3107 + )); 3108 + assert!(declarators[0].init.is_some()); 3109 + } 3110 + _ => panic!("expected var decl"), 3111 + } 3112 + } 3113 + 3114 + #[test] 3115 + fn test_const_decl() { 3116 + let stmt = parse_stmt("const [a, b] = arr;"); 3117 + match stmt.kind { 3118 + StmtKind::VarDecl { 3119 + kind: VarKind::Const, 3120 + declarators, 3121 + } => { 3122 + assert!(matches!( 3123 + declarators[0].pattern.kind, 3124 + PatternKind::Array { .. } 3125 + )); 3126 + } 3127 + _ => panic!("expected const decl"), 3128 + } 3129 + } 3130 + 3131 + #[test] 3132 + fn test_destructuring_object() { 3133 + let stmt = parse_stmt("let { a, b: c } = obj;"); 3134 + match stmt.kind { 3135 + StmtKind::VarDecl { declarators, .. } => match &declarators[0].pattern.kind { 3136 + PatternKind::Object { properties, .. } => { 3137 + assert_eq!(properties.len(), 2); 3138 + assert!(properties[0].shorthand); 3139 + assert!(!properties[1].shorthand); 3140 + } 3141 + _ => panic!("expected object pattern"), 3142 + }, 3143 + _ => panic!("expected var decl"), 3144 + } 3145 + } 3146 + 3147 + // ── Function declaration ──────────────────────────── 3148 + 3149 + #[test] 3150 + fn test_function_decl() { 3151 + let stmt = parse_stmt("function add(a, b) { return a + b; }"); 3152 + match stmt.kind { 3153 + StmtKind::FunctionDecl(def) => { 3154 + assert_eq!(def.id, Some("add".into())); 3155 + assert_eq!(def.params.len(), 2); 3156 + assert!(!def.is_async); 3157 + assert!(!def.is_generator); 3158 + assert_eq!(def.body.len(), 1); 3159 + } 3160 + _ => panic!("expected function decl"), 3161 + } 3162 + } 3163 + 3164 + #[test] 3165 + fn test_generator_function() { 3166 + let stmt = parse_stmt("function* gen() { yield 1; }"); 3167 + match stmt.kind { 3168 + StmtKind::FunctionDecl(def) => { 3169 + assert!(def.is_generator); 3170 + } 3171 + _ => panic!("expected function decl"), 3172 + } 3173 + } 3174 + 3175 + #[test] 3176 + fn test_async_function() { 3177 + let stmt = parse_stmt("async function fetch() { await get(); }"); 3178 + match stmt.kind { 3179 + StmtKind::FunctionDecl(def) => { 3180 + assert!(def.is_async); 3181 + } 3182 + _ => panic!("expected function decl"), 3183 + } 3184 + } 3185 + 3186 + #[test] 3187 + fn test_default_params() { 3188 + let stmt = parse_stmt("function f(a, b = 10) {}"); 3189 + match stmt.kind { 3190 + StmtKind::FunctionDecl(def) => { 3191 + assert_eq!(def.params.len(), 2); 3192 + assert!(matches!(def.params[1].kind, PatternKind::Assign { .. })); 3193 + } 3194 + _ => panic!("expected function decl"), 3195 + } 3196 + } 3197 + 3198 + #[test] 3199 + fn test_rest_params() { 3200 + let stmt = parse_stmt("function f(...args) {}"); 3201 + match stmt.kind { 3202 + StmtKind::FunctionDecl(def) => { 3203 + assert_eq!(def.params.len(), 1); 3204 + assert!(matches!( 3205 + def.params[0].kind, 3206 + PatternKind::Identifier(ref n) if n == "args" 3207 + )); 3208 + } 3209 + _ => panic!("expected function decl"), 3210 + } 3211 + } 3212 + 3213 + // ── Class declaration ─────────────────────────────── 3214 + 3215 + #[test] 3216 + fn test_class_decl() { 3217 + let stmt = parse_stmt("class Foo { constructor() {} method() {} }"); 3218 + match stmt.kind { 3219 + StmtKind::ClassDecl(def) => { 3220 + assert_eq!(def.id, Some("Foo".into())); 3221 + assert_eq!(def.body.len(), 2); 3222 + } 3223 + _ => panic!("expected class decl"), 3224 + } 3225 + } 3226 + 3227 + #[test] 3228 + fn test_class_extends() { 3229 + let stmt = parse_stmt("class Bar extends Foo {}"); 3230 + match stmt.kind { 3231 + StmtKind::ClassDecl(def) => { 3232 + assert!(def.super_class.is_some()); 3233 + } 3234 + _ => panic!("expected class decl"), 3235 + } 3236 + } 3237 + 3238 + #[test] 3239 + fn test_class_getter_setter() { 3240 + let stmt = parse_stmt("class C { get x() { return 1; } set x(v) {} }"); 3241 + match stmt.kind { 3242 + StmtKind::ClassDecl(def) => { 3243 + assert_eq!(def.body.len(), 2); 3244 + match &def.body[0].kind { 3245 + ClassMemberKind::Method { kind, .. } => { 3246 + assert_eq!(*kind, MethodKind::Get); 3247 + } 3248 + _ => panic!("expected getter"), 3249 + } 3250 + } 3251 + _ => panic!("expected class decl"), 3252 + } 3253 + } 3254 + 3255 + // ── Control flow statements ───────────────────────── 3256 + 3257 + #[test] 3258 + fn test_if_else() { 3259 + let stmt = parse_stmt("if (x) { a(); } else { b(); }"); 3260 + match stmt.kind { 3261 + StmtKind::If { alternate, .. } => { 3262 + assert!(alternate.is_some()); 3263 + } 3264 + _ => panic!("expected if"), 3265 + } 3266 + } 3267 + 3268 + #[test] 3269 + fn test_for_loop() { 3270 + let stmt = parse_stmt("for (let i = 0; i < 10; i++) {}"); 3271 + match stmt.kind { 3272 + StmtKind::For { 3273 + init, test, update, .. 3274 + } => { 3275 + assert!(init.is_some()); 3276 + assert!(test.is_some()); 3277 + assert!(update.is_some()); 3278 + } 3279 + _ => panic!("expected for"), 3280 + } 3281 + } 3282 + 3283 + #[test] 3284 + fn test_for_in() { 3285 + let stmt = parse_stmt("for (const key in obj) {}"); 3286 + assert!(matches!(stmt.kind, StmtKind::ForIn { .. })); 3287 + } 3288 + 3289 + #[test] 3290 + fn test_for_of() { 3291 + let stmt = parse_stmt("for (const item of arr) {}"); 3292 + assert!(matches!(stmt.kind, StmtKind::ForOf { .. })); 3293 + } 3294 + 3295 + #[test] 3296 + fn test_while_loop() { 3297 + let stmt = parse_stmt("while (true) {}"); 3298 + assert!(matches!(stmt.kind, StmtKind::While { .. })); 3299 + } 3300 + 3301 + #[test] 3302 + fn test_do_while() { 3303 + let stmt = parse_stmt("do {} while (true);"); 3304 + assert!(matches!(stmt.kind, StmtKind::DoWhile { .. })); 3305 + } 3306 + 3307 + #[test] 3308 + fn test_switch() { 3309 + let stmt = parse_stmt("switch (x) { case 1: break; default: break; }"); 3310 + match stmt.kind { 3311 + StmtKind::Switch { cases, .. } => { 3312 + assert_eq!(cases.len(), 2); 3313 + assert!(cases[0].test.is_some()); 3314 + assert!(cases[1].test.is_none()); // default 3315 + } 3316 + _ => panic!("expected switch"), 3317 + } 3318 + } 3319 + 3320 + #[test] 3321 + fn test_try_catch() { 3322 + let stmt = parse_stmt("try { f(); } catch (e) { g(); }"); 3323 + match stmt.kind { 3324 + StmtKind::Try { 3325 + handler, finalizer, .. 3326 + } => { 3327 + assert!(handler.is_some()); 3328 + assert!(finalizer.is_none()); 3329 + } 3330 + _ => panic!("expected try"), 3331 + } 3332 + } 3333 + 3334 + #[test] 3335 + fn test_try_catch_finally() { 3336 + let stmt = parse_stmt("try {} catch (e) {} finally {}"); 3337 + match stmt.kind { 3338 + StmtKind::Try { 3339 + handler, finalizer, .. 3340 + } => { 3341 + assert!(handler.is_some()); 3342 + assert!(finalizer.is_some()); 3343 + } 3344 + _ => panic!("expected try"), 3345 + } 3346 + } 3347 + 3348 + #[test] 3349 + fn test_return() { 3350 + let stmt = parse_stmt("function f() { return 42; }"); 3351 + match stmt.kind { 3352 + StmtKind::FunctionDecl(def) => match &def.body[0].kind { 3353 + StmtKind::Return(Some(expr)) => { 3354 + assert_eq!(expr.kind, ExprKind::Number(42.0)); 3355 + } 3356 + _ => panic!("expected return"), 3357 + }, 3358 + _ => panic!("expected function"), 3359 + } 3360 + } 3361 + 3362 + #[test] 3363 + fn test_throw() { 3364 + let stmt = parse_stmt("function f() { throw new Error(); }"); 3365 + match stmt.kind { 3366 + StmtKind::FunctionDecl(def) => { 3367 + assert!(matches!(def.body[0].kind, StmtKind::Throw(_))); 3368 + } 3369 + _ => panic!("expected function"), 3370 + } 3371 + } 3372 + 3373 + #[test] 3374 + fn test_break_continue() { 3375 + let prog = parse("while (true) { break; continue; }"); 3376 + let while_stmt = &prog.body[0]; 3377 + match &while_stmt.kind { 3378 + StmtKind::While { body, .. } => match &body.kind { 3379 + StmtKind::Block(stmts) => { 3380 + assert!(matches!(stmts[0].kind, StmtKind::Break(None))); 3381 + assert!(matches!(stmts[1].kind, StmtKind::Continue(None))); 3382 + } 3383 + _ => panic!("expected block"), 3384 + }, 3385 + _ => panic!("expected while"), 3386 + } 3387 + } 3388 + 3389 + #[test] 3390 + fn test_labeled_statement() { 3391 + let stmt = parse_stmt("outer: for (;;) {}"); 3392 + match stmt.kind { 3393 + StmtKind::Labeled { label, .. } => { 3394 + assert_eq!(label, "outer"); 3395 + } 3396 + _ => panic!("expected labeled"), 3397 + } 3398 + } 3399 + 3400 + // ── Import / Export ───────────────────────────────── 3401 + 3402 + #[test] 3403 + fn test_import_default() { 3404 + let stmt = parse_stmt("import foo from \"mod\";"); 3405 + match stmt.kind { 3406 + StmtKind::Import { specifiers, source } => { 3407 + assert_eq!(source, "mod"); 3408 + assert_eq!(specifiers.len(), 1); 3409 + assert!(matches!(&specifiers[0], ImportSpecifier::Default(n) if n == "foo")); 3410 + } 3411 + _ => panic!("expected import"), 3412 + } 3413 + } 3414 + 3415 + #[test] 3416 + fn test_import_named() { 3417 + let prog = Parser::parse_module("import { a, b as c } from \"mod\";").unwrap(); 3418 + match &prog.body[0].kind { 3419 + StmtKind::Import { specifiers, .. } => { 3420 + assert_eq!(specifiers.len(), 2); 3421 + } 3422 + _ => panic!("expected import"), 3423 + } 3424 + } 3425 + 3426 + #[test] 3427 + fn test_import_namespace() { 3428 + let prog = Parser::parse_module("import * as ns from \"mod\";").unwrap(); 3429 + match &prog.body[0].kind { 3430 + StmtKind::Import { specifiers, .. } => { 3431 + assert!(matches!(&specifiers[0], ImportSpecifier::Namespace(n) if n == "ns")); 3432 + } 3433 + _ => panic!("expected import"), 3434 + } 3435 + } 3436 + 3437 + #[test] 3438 + fn test_export_default() { 3439 + let prog = Parser::parse_module("export default 42;").unwrap(); 3440 + match &prog.body[0].kind { 3441 + StmtKind::Export(ExportDecl::Default(expr)) => { 3442 + assert_eq!(expr.kind, ExprKind::Number(42.0)); 3443 + } 3444 + _ => panic!("expected export default"), 3445 + } 3446 + } 3447 + 3448 + #[test] 3449 + fn test_export_named() { 3450 + let prog = Parser::parse_module("export { a, b as c };").unwrap(); 3451 + match &prog.body[0].kind { 3452 + StmtKind::Export(ExportDecl::Named { specifiers, .. }) => { 3453 + assert_eq!(specifiers.len(), 2); 3454 + } 3455 + _ => panic!("expected export named"), 3456 + } 3457 + } 3458 + 3459 + #[test] 3460 + fn test_export_declaration() { 3461 + let prog = Parser::parse_module("export const x = 1;").unwrap(); 3462 + match &prog.body[0].kind { 3463 + StmtKind::Export(ExportDecl::Declaration(_)) => {} 3464 + _ => panic!("expected export declaration"), 3465 + } 3466 + } 3467 + 3468 + // ── ASI (Automatic Semicolon Insertion) ───────────── 3469 + 3470 + #[test] 3471 + fn test_asi_newline() { 3472 + let prog = parse("let x = 1\nlet y = 2"); 3473 + assert_eq!(prog.body.len(), 2); 3474 + } 3475 + 3476 + #[test] 3477 + fn test_asi_before_rbrace() { 3478 + let stmt = parse_stmt("function f() { return 1 }"); 3479 + match stmt.kind { 3480 + StmtKind::FunctionDecl(def) => { 3481 + assert_eq!(def.body.len(), 1); 3482 + } 3483 + _ => panic!("expected function"), 3484 + } 3485 + } 3486 + 3487 + // ── Complex programs ──────────────────────────────── 3488 + 3489 + #[test] 3490 + fn test_fibonacci() { 3491 + let src = r#" 3492 + function fib(n) { 3493 + if (n <= 1) return n; 3494 + return fib(n - 1) + fib(n - 2); 3495 + } 3496 + "#; 3497 + let prog = parse(src); 3498 + assert_eq!(prog.body.len(), 1); 3499 + assert!(matches!(prog.body[0].kind, StmtKind::FunctionDecl(_))); 3500 + } 3501 + 3502 + #[test] 3503 + fn test_class_with_methods() { 3504 + let src = r#" 3505 + class Animal { 3506 + constructor(name) { 3507 + this.name = name; 3508 + } 3509 + speak() { 3510 + return this.name; 3511 + } 3512 + static create(name) { 3513 + return new Animal(name); 3514 + } 3515 + } 3516 + "#; 3517 + let prog = parse(src); 3518 + assert_eq!(prog.body.len(), 1); 3519 + match &prog.body[0].kind { 3520 + StmtKind::ClassDecl(def) => { 3521 + assert_eq!(def.body.len(), 3); 3522 + } 3523 + _ => panic!("expected class"), 3524 + } 3525 + } 3526 + 3527 + #[test] 3528 + fn test_for_of_destructuring() { 3529 + let stmt = parse_stmt("for (const [k, v] of map) {}"); 3530 + match stmt.kind { 3531 + StmtKind::ForOf { left, .. } => match left { 3532 + ForInOfLeft::VarDecl { pattern, .. } => { 3533 + assert!(matches!(pattern.kind, PatternKind::Array { .. })); 3534 + } 3535 + _ => panic!("expected var decl"), 3536 + }, 3537 + _ => panic!("expected for-of"), 3538 + } 3539 + } 3540 + 3541 + #[test] 3542 + fn test_multiple_statements() { 3543 + let src = "let x = 1; let y = 2; x + y;"; 3544 + let prog = parse(src); 3545 + assert_eq!(prog.body.len(), 3); 3546 + } 3547 + 3548 + // ── Error cases ───────────────────────────────────── 3549 + 3550 + #[test] 3551 + fn test_error_unexpected_token() { 3552 + assert!(Parser::parse(")").is_err()); 3553 + } 3554 + 3555 + #[test] 3556 + fn test_error_unterminated_block() { 3557 + assert!(Parser::parse("{ let x = 1;").is_err()); 3558 + } 3559 + 3560 + #[test] 3561 + fn test_error_missing_paren() { 3562 + assert!(Parser::parse("if x {}").is_err()); 3563 + } 3564 + }