//! Abstract Syntax Tree node types for ECMAScript 2024. use crate::lexer::Span; /// A complete JavaScript program. #[derive(Debug, Clone, PartialEq)] pub struct Program { pub body: Vec, pub source_type: SourceType, pub span: Span, } /// Whether the program is a script or module. #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum SourceType { Script, Module, } // ── Statements ────────────────────────────────────────────── /// A statement or declaration. #[derive(Debug, Clone, PartialEq)] pub struct Stmt { pub kind: StmtKind, pub span: Span, } #[derive(Debug, Clone, PartialEq)] pub enum StmtKind { /// Expression followed by semicolon. Expr(Expr), /// `{ ... }` Block(Vec), /// `var`/`let`/`const` declaration. VarDecl { kind: VarKind, declarators: Vec, }, /// `function name(...) { ... }` FunctionDecl(FunctionDef), /// `class Name { ... }` ClassDecl(ClassDef), /// `if (test) consequent else alternate` If { test: Expr, consequent: Box, alternate: Option>, }, /// `for (init; test; update) body` For { init: Option, test: Option, update: Option, body: Box, }, /// `for (left in right) body` ForIn { left: ForInOfLeft, right: Expr, body: Box, }, /// `for (left of right) body` ForOf { left: ForInOfLeft, right: Expr, body: Box, is_await: bool, }, /// `while (test) body` While { test: Expr, body: Box }, /// `do body while (test)` DoWhile { body: Box, test: Expr }, /// `switch (discriminant) { cases }` Switch { discriminant: Expr, cases: Vec, }, /// `try { block } catch (param) { handler } finally { finalizer }` Try { block: Vec, handler: Option, finalizer: Option>, }, /// `return expr;` Return(Option), /// `throw expr;` Throw(Expr), /// `break label;` Break(Option), /// `continue label;` Continue(Option), /// `label: stmt` Labeled { label: String, body: Box }, /// `with (object) body` With { object: Expr, body: Box }, /// `debugger;` Debugger, /// `;` Empty, /// `import` declaration. Import { specifiers: Vec, source: String, }, /// `export` declaration. Export(ExportDecl), } // ── Variable declarations ─────────────────────────────────── #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum VarKind { Var, Let, Const, } #[derive(Debug, Clone, PartialEq)] pub struct VarDeclarator { pub pattern: Pattern, pub init: Option, pub span: Span, } // ── For-statement helpers ─────────────────────────────────── #[derive(Debug, Clone, PartialEq)] pub enum ForInit { VarDecl { kind: VarKind, declarators: Vec, }, Expr(Expr), } #[derive(Debug, Clone, PartialEq)] pub enum ForInOfLeft { VarDecl { kind: VarKind, pattern: Pattern }, Pattern(Pattern), } // ── Switch / Try helpers ──────────────────────────────────── #[derive(Debug, Clone, PartialEq)] pub struct SwitchCase { /// `None` for `default:`. pub test: Option, pub consequent: Vec, pub span: Span, } #[derive(Debug, Clone, PartialEq)] pub struct CatchClause { pub param: Option, pub body: Vec, pub span: Span, } // ── Import / Export ───────────────────────────────────────── #[derive(Debug, Clone, PartialEq)] pub enum ImportSpecifier { /// `import defaultExport from "mod"` Default(String), /// `import { foo } from "mod"` or `import { foo as bar } from "mod"` Named { imported: String, local: String }, /// `import * as ns from "mod"` Namespace(String), } #[derive(Debug, Clone, PartialEq)] pub enum ExportDecl { /// `export default expr` Default(Expr), /// `export function/class/var ...` Declaration(Box), /// `export { a, b as c }` Named { specifiers: Vec, source: Option, }, /// `export * from "mod"` AllFrom(String), } #[derive(Debug, Clone, PartialEq)] pub struct ExportSpecifier { pub local: String, pub exported: String, } // ── Expressions ───────────────────────────────────────────── #[derive(Debug, Clone, PartialEq)] pub struct Expr { pub kind: ExprKind, pub span: Span, } #[derive(Debug, Clone, PartialEq)] pub enum ExprKind { /// Numeric literal. Number(f64), /// String literal. String(String), /// `true` / `false`. Bool(bool), /// `null`. Null, /// An identifier reference. Identifier(String), /// `this`. This, /// `[a, b, c]` Array(Vec>), /// `{ key: value, ... }` Object(Vec), /// `function name(...) { ... }` expression. Function(FunctionDef), /// `(...) => body` Arrow { params: Vec, body: ArrowBody, is_async: bool, }, /// `class Name { ... }` expression. Class(ClassDef), /// Prefix unary (`!x`, `-x`, `~x`, `typeof x`, `void x`, `delete x`). Unary { op: UnaryOp, argument: Box }, /// `++x`, `--x`, `x++`, `x--`. Update { op: UpdateOp, argument: Box, prefix: bool, }, /// `a + b`, `a * b`, etc. Binary { op: BinaryOp, left: Box, right: Box, }, /// `a && b`, `a || b`, `a ?? b`. Logical { op: LogicalOp, left: Box, right: Box, }, /// `a = b`, `a += b`, etc. Assignment { op: AssignOp, left: Box, right: Box, }, /// `test ? consequent : alternate` Conditional { test: Box, consequent: Box, alternate: Box, }, /// `callee(arguments)` Call { callee: Box, arguments: Vec, }, /// `new callee(arguments)` New { callee: Box, arguments: Vec, }, /// `object.property` or `object[property]` Member { object: Box, property: Box, computed: bool, }, /// `obj?.prop`, `obj?.[expr]`, `fn?.(args)` OptionalChain { base: Box }, /// Template literal: `` `hello ${name}` `` TemplateLiteral { quasis: Vec, expressions: Vec, }, /// Tagged template: `` tag`string` `` TaggedTemplate { tag: Box, quasi: Box }, /// `a, b, c` Sequence(Vec), /// `...expr` Spread(Box), /// `yield expr` / `yield* expr` Yield { argument: Option>, delegate: bool, }, /// `await expr` Await(Box), /// `/pattern/flags` RegExp { pattern: String, flags: String }, } // ── Array element ─────────────────────────────────────────── #[derive(Debug, Clone, PartialEq)] pub enum ArrayElement { Expr(Expr), Spread(Expr), } // ── Object literal ────────────────────────────────────────── #[derive(Debug, Clone, PartialEq)] pub struct Property { pub key: PropertyKey, pub value: Option, pub kind: PropertyKind, pub computed: bool, pub shorthand: bool, pub method: bool, pub span: Span, } #[derive(Debug, Clone, PartialEq)] pub enum PropertyKey { Identifier(String), String(String), Number(f64), Computed(Expr), } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum PropertyKind { Init, Get, Set, } // ── Arrow function body ───────────────────────────────────── #[derive(Debug, Clone, PartialEq)] pub enum ArrowBody { Expr(Box), Block(Vec), } // ── Function definition ───────────────────────────────────── #[derive(Debug, Clone, PartialEq)] pub struct FunctionDef { pub id: Option, pub params: Vec, pub body: Vec, pub is_async: bool, pub is_generator: bool, } // ── Class definition ──────────────────────────────────────── #[derive(Debug, Clone, PartialEq)] pub struct ClassDef { pub id: Option, pub super_class: Option>, pub body: Vec, } #[derive(Debug, Clone, PartialEq)] pub struct ClassMember { pub kind: ClassMemberKind, pub span: Span, } #[derive(Debug, Clone, PartialEq)] pub enum ClassMemberKind { Method { key: PropertyKey, value: FunctionDef, kind: MethodKind, is_static: bool, computed: bool, }, Property { key: PropertyKey, value: Option, is_static: bool, computed: bool, }, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum MethodKind { Method, Get, Set, Constructor, } // ── Patterns (destructuring) ──────────────────────────────── #[derive(Debug, Clone, PartialEq)] pub struct Pattern { pub kind: PatternKind, pub span: Span, } #[derive(Debug, Clone, PartialEq)] pub enum PatternKind { /// Simple binding: `x` Identifier(String), /// Array destructuring: `[a, b, ...rest]` Array { elements: Vec>, rest: Option>, }, /// Object destructuring: `{ a, b: c, ...rest }` Object { properties: Vec, rest: Option>, }, /// Default value: `x = defaultValue` Assign { left: Box, right: Box, }, } #[derive(Debug, Clone, PartialEq)] pub struct ObjectPatternProp { pub key: PropertyKey, pub value: Pattern, pub computed: bool, pub shorthand: bool, pub span: Span, } // ── Operators ─────────────────────────────────────────────── #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum UnaryOp { Minus, Plus, Not, BitwiseNot, Typeof, Void, Delete, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum UpdateOp { Increment, Decrement, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum BinaryOp { Add, Sub, Mul, Div, Rem, Exp, Eq, Ne, StrictEq, StrictNe, Lt, Le, Gt, Ge, Shl, Shr, Ushr, BitAnd, BitOr, BitXor, In, Instanceof, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum LogicalOp { And, Or, Nullish, } #[derive(Debug, Clone, Copy, PartialEq, Eq)] pub enum AssignOp { Assign, AddAssign, SubAssign, MulAssign, DivAssign, RemAssign, ExpAssign, ShlAssign, ShrAssign, UshrAssign, BitAndAssign, BitOrAssign, BitXorAssign, AndAssign, OrAssign, NullishAssign, }