use crate::parser::scanner::Span;
pub type SourceLocation = Span;
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum SourceType {
Script,
Module,
}
#[derive(Debug, Clone)]
pub struct Program {
pub loc: SourceLocation,
pub source_type: SourceType,
pub body: Vec<ProgramItem>,
pub is_strict: bool,
}
#[derive(Debug, Clone)]
pub enum ProgramItem {
Stmt(Stmt),
ModuleDecl(ModuleDecl),
}
#[derive(Debug, Clone)]
pub struct Ident {
pub loc: SourceLocation,
pub name: String,
}
#[derive(Debug, Clone)]
pub struct PrivateIdent {
pub loc: SourceLocation,
pub name: String,
}
#[derive(Debug, Clone)]
pub struct Param {
pub loc: SourceLocation,
pub pat: Pat,
pub default: Option<Expr>,
}
#[derive(Debug, Clone)]
pub enum Stmt {
Block(BlockStmt),
VarDecl(VarDecl),
FnDecl(Box<FnDecl>),
ClassDecl(Box<ClassDecl>),
Expr(ExprStmt),
If(IfStmt),
For(ForStmt),
ForIn(ForInStmt),
ForOf(ForOfStmt),
While(WhileStmt),
DoWhile(DoWhileStmt),
Switch(SwitchStmt),
Try(TryStmt),
Return(ReturnStmt),
Throw(ThrowStmt),
Break(BreakStmt),
Continue(ContinueStmt),
Labeled(LabeledStmt),
Debugger(DebuggerStmt),
With(WithStmt),
Empty(EmptyStmt),
}
impl Stmt {
pub fn loc(&self) -> SourceLocation {
match self {
Stmt::Block(s) => s.loc,
Stmt::VarDecl(s) => s.loc,
Stmt::FnDecl(s) => s.loc,
Stmt::ClassDecl(s) => s.loc,
Stmt::Expr(s) => s.loc,
Stmt::If(s) => s.loc,
Stmt::For(s) => s.loc,
Stmt::ForIn(s) => s.loc,
Stmt::ForOf(s) => s.loc,
Stmt::While(s) => s.loc,
Stmt::DoWhile(s) => s.loc,
Stmt::Switch(s) => s.loc,
Stmt::Try(s) => s.loc,
Stmt::Return(s) => s.loc,
Stmt::Throw(s) => s.loc,
Stmt::Break(s) => s.loc,
Stmt::Continue(s) => s.loc,
Stmt::Labeled(s) => s.loc,
Stmt::Debugger(s) => s.loc,
Stmt::With(s) => s.loc,
Stmt::Empty(s) => s.loc,
}
}
}
#[derive(Debug, Clone)]
pub struct BlockStmt {
pub loc: SourceLocation,
pub body: Vec<Stmt>,
}
#[derive(Debug, Clone)]
pub struct ExprStmt {
pub loc: SourceLocation,
pub expr: Box<Expr>,
}
#[derive(Debug, Clone)]
pub struct IfStmt {
pub loc: SourceLocation,
pub test: Box<Expr>,
pub consequent: Box<Stmt>,
pub alternate: Option<Box<Stmt>>,
}
#[derive(Debug, Clone)]
pub struct ForStmt {
pub loc: SourceLocation,
pub init: Option<ForInit>,
pub test: Option<Box<Expr>>,
pub update: Option<Box<Expr>>,
pub body: Box<Stmt>,
}
#[derive(Debug, Clone)]
pub enum ForInit {
VarDecl(VarDecl),
Expr(Box<Expr>),
}
#[derive(Debug, Clone)]
pub struct ForInStmt {
pub loc: SourceLocation,
pub left: ForInOfLeft,
pub right: Box<Expr>,
pub body: Box<Stmt>,
}
#[derive(Debug, Clone)]
pub struct ForOfStmt {
pub loc: SourceLocation,
pub is_await: bool,
pub left: ForInOfLeft,
pub right: Box<Expr>,
pub body: Box<Stmt>,
}
#[derive(Debug, Clone)]
pub enum ForInOfLeft {
VarDecl(VarDecl),
Pat(Pat),
Expr(Box<Expr>),
}
#[derive(Debug, Clone)]
pub struct WhileStmt {
pub loc: SourceLocation,
pub test: Box<Expr>,
pub body: Box<Stmt>,
}
#[derive(Debug, Clone)]
pub struct DoWhileStmt {
pub loc: SourceLocation,
pub body: Box<Stmt>,
pub test: Box<Expr>,
}
#[derive(Debug, Clone)]
pub struct SwitchStmt {
pub loc: SourceLocation,
pub discriminant: Box<Expr>,
pub cases: Vec<SwitchCase>,
}
#[derive(Debug, Clone)]
pub struct SwitchCase {
pub loc: SourceLocation,
pub test: Option<Expr>,
pub consequent: Vec<Stmt>,
}
#[derive(Debug, Clone)]
pub struct TryStmt {
pub loc: SourceLocation,
pub block: BlockStmt,
pub handler: Option<CatchClause>,
pub finalizer: Option<BlockStmt>,
}
#[derive(Debug, Clone)]
pub struct CatchClause {
pub loc: SourceLocation,
pub param: Option<Pat>,
pub body: BlockStmt,
}
#[derive(Debug, Clone)]
pub struct ReturnStmt {
pub loc: SourceLocation,
pub argument: Option<Box<Expr>>,
}
#[derive(Debug, Clone)]
pub struct ThrowStmt {
pub loc: SourceLocation,
pub argument: Box<Expr>,
}
#[derive(Debug, Clone)]
pub struct BreakStmt {
pub loc: SourceLocation,
pub label: Option<Ident>,
}
#[derive(Debug, Clone)]
pub struct ContinueStmt {
pub loc: SourceLocation,
pub label: Option<Ident>,
}
#[derive(Debug, Clone)]
pub struct LabeledStmt {
pub loc: SourceLocation,
pub label: Ident,
pub body: Box<Stmt>,
}
#[derive(Debug, Clone)]
pub struct DebuggerStmt {
pub loc: SourceLocation,
}
#[derive(Debug, Clone)]
pub struct WithStmt {
pub loc: SourceLocation,
pub object: Box<Expr>,
pub body: Box<Stmt>,
}
#[derive(Debug, Clone)]
pub struct EmptyStmt {
pub loc: SourceLocation,
}
#[derive(Debug, Clone)]
pub struct VarDecl {
pub loc: SourceLocation,
pub kind: VarKind,
pub declarators: Vec<VarDeclarator>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum VarKind {
Var,
Let,
Const,
Using,
AwaitUsing,
}
#[derive(Debug, Clone)]
pub struct VarDeclarator {
pub loc: SourceLocation,
pub id: Pat,
pub init: Option<Box<Expr>>,
}
#[derive(Debug, Clone)]
pub struct FnDecl {
pub loc: SourceLocation,
pub id: Option<Ident>,
pub is_async: bool,
pub is_generator: bool,
pub params: Vec<Param>,
pub body: BlockStmt,
pub is_strict: bool,
}
#[derive(Debug, Clone)]
pub struct FnExpr {
pub loc: SourceLocation,
pub id: Option<Ident>,
pub is_async: bool,
pub is_generator: bool,
pub params: Vec<Param>,
pub body: BlockStmt,
pub is_strict: bool,
}
#[derive(Debug, Clone)]
pub struct ArrowExpr {
pub loc: SourceLocation,
pub is_async: bool,
pub params: Vec<Param>,
pub body: ArrowBody,
pub is_strict: bool,
}
#[derive(Debug, Clone)]
pub enum ArrowBody {
Block(BlockStmt),
Expr(Box<Expr>),
}
#[derive(Debug, Clone)]
pub struct ClassDecl {
pub loc: SourceLocation,
pub id: Option<Ident>,
pub super_class: Option<Box<Expr>>,
pub body: ClassBody,
}
#[derive(Debug, Clone)]
pub struct ClassExpr {
pub loc: SourceLocation,
pub id: Option<Ident>,
pub super_class: Option<Box<Expr>>,
pub body: ClassBody,
}
#[derive(Debug, Clone)]
pub struct ClassBody {
pub loc: SourceLocation,
pub body: Vec<ClassMember>,
}
#[derive(Debug, Clone)]
pub enum ClassMember {
Method(MethodDef),
Property(PropertyDef),
StaticBlock(StaticBlock),
}
#[derive(Debug, Clone)]
pub struct MethodDef {
pub loc: SourceLocation,
pub is_static: bool,
pub kind: MethodKind,
pub key: PropKey,
pub is_computed: bool,
pub value: FnExpr,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum MethodKind {
Constructor,
Method,
Get,
Set,
}
#[derive(Debug, Clone)]
pub struct PropertyDef {
pub loc: SourceLocation,
pub is_static: bool,
pub key: PropKey,
pub is_computed: bool,
pub value: Option<Box<Expr>>,
}
#[derive(Debug, Clone)]
pub struct StaticBlock {
pub loc: SourceLocation,
pub body: Vec<Stmt>,
}
#[derive(Debug, Clone)]
pub enum ModuleDecl {
Import(ImportDecl),
ExportNamed(ExportNamedDecl),
ExportDefault(ExportDefaultDecl),
ExportAll(ExportAllDecl),
}
#[derive(Debug, Clone)]
pub struct ImportDecl {
pub loc: SourceLocation,
pub specifiers: Vec<ImportSpecifier>,
pub source: StringLit,
pub attributes: Vec<ImportAttribute>,
}
#[derive(Debug, Clone)]
pub enum ImportSpecifier {
Named(ImportNamedSpecifier),
Default(ImportDefaultSpecifier),
Namespace(ImportNamespaceSpecifier),
}
#[derive(Debug, Clone)]
pub struct ImportNamedSpecifier {
pub loc: SourceLocation,
pub imported: ModuleExportName,
pub local: Ident,
}
#[derive(Debug, Clone)]
pub struct ImportDefaultSpecifier {
pub loc: SourceLocation,
pub local: Ident,
}
#[derive(Debug, Clone)]
pub struct ImportNamespaceSpecifier {
pub loc: SourceLocation,
pub local: Ident,
}
#[derive(Debug, Clone)]
pub struct ImportAttribute {
pub loc: SourceLocation,
pub key: Ident,
pub value: StringLit,
}
#[derive(Debug, Clone)]
pub struct ExportNamedDecl {
pub loc: SourceLocation,
pub specifiers: Vec<ExportSpecifier>,
pub source: Option<StringLit>,
pub declaration: Option<Box<Stmt>>,
pub attributes: Vec<ImportAttribute>,
}
#[derive(Debug, Clone)]
pub struct ExportSpecifier {
pub loc: SourceLocation,
pub local: ModuleExportName,
pub exported: ModuleExportName,
}
#[derive(Debug, Clone)]
pub struct ExportDefaultDecl {
pub loc: SourceLocation,
pub declaration: ExportDefaultExpr,
}
#[derive(Debug, Clone)]
pub enum ExportDefaultExpr {
Fn(Box<FnDecl>),
Class(Box<ClassDecl>),
Expr(Box<Expr>),
}
#[derive(Debug, Clone)]
pub struct ExportAllDecl {
pub loc: SourceLocation,
pub exported: Option<ModuleExportName>,
pub source: StringLit,
pub attributes: Vec<ImportAttribute>,
}
#[derive(Debug, Clone)]
pub enum ModuleExportName {
Ident(Ident),
Str(StringLit),
}
#[derive(Debug, Clone)]
pub struct NullLit {
pub loc: SourceLocation,
}
#[derive(Debug, Clone)]
pub struct BoolLit {
pub loc: SourceLocation,
pub value: bool,
}
#[derive(Debug, Clone)]
pub struct NumLit {
pub loc: SourceLocation,
pub value: f64,
pub raw: String,
}
#[derive(Debug, Clone)]
pub struct BigIntLit {
pub loc: SourceLocation,
pub value: String,
}
#[derive(Debug, Clone)]
pub struct StringLit {
pub loc: SourceLocation,
pub value: String,
}
#[derive(Debug, Clone)]
pub struct RegExpLit {
pub loc: SourceLocation,
pub pattern: String,
pub flags: String,
}
#[derive(Debug, Clone)]
pub struct TemplateLit {
pub loc: SourceLocation,
pub quasis: Vec<TemplateElement>,
pub expressions: Vec<Expr>,
}
#[derive(Debug, Clone)]
pub struct TemplateElement {
pub loc: SourceLocation,
pub raw: String,
pub cooked: Option<String>,
pub tail: bool,
}
#[derive(Debug, Clone)]
pub enum Expr {
Null(NullLit),
Bool(BoolLit),
Num(NumLit),
Str(StringLit),
BigInt(BigIntLit),
Regexp(RegExpLit),
Template(Box<TemplateLit>),
Ident(Ident),
This(ThisExpr),
Array(Box<ArrayExpr>),
Object(Box<ObjectExpr>),
Fn(Box<FnExpr>),
Arrow(Box<ArrowExpr>),
Class(Box<ClassExpr>),
Unary(Box<UnaryExpr>),
Update(Box<UpdateExpr>),
Binary(Box<BinaryExpr>),
Logical(Box<LogicalExpr>),
Conditional(Box<ConditionalExpr>),
Assign(Box<AssignExpr>),
Sequence(Box<SequenceExpr>),
Member(Box<MemberExpr>),
OptionalMember(Box<OptionalMemberExpr>),
Call(Box<CallExpr>),
OptionalCall(Box<OptionalCallExpr>),
OptionalChain(Box<Expr>),
New(Box<NewExpr>),
TaggedTemplate(Box<TaggedTemplateExpr>),
Spread(Box<SpreadElement>),
Yield(Box<YieldExpr>),
Await(Box<AwaitExpr>),
Import(Box<ImportExpr>),
MetaProp(MetaPropExpr),
PrivateName(PrivateIdent),
}
impl Expr {
pub fn loc(&self) -> SourceLocation {
match self {
Expr::Null(e) => e.loc,
Expr::Bool(e) => e.loc,
Expr::Num(e) => e.loc,
Expr::Str(e) => e.loc,
Expr::BigInt(e) => e.loc,
Expr::Regexp(e) => e.loc,
Expr::Template(e) => e.loc,
Expr::Ident(e) => e.loc,
Expr::This(e) => e.loc,
Expr::Array(e) => e.loc,
Expr::Object(e) => e.loc,
Expr::Fn(e) => e.loc,
Expr::Arrow(e) => e.loc,
Expr::Class(e) => e.loc,
Expr::Unary(e) => e.loc,
Expr::Update(e) => e.loc,
Expr::Binary(e) => e.loc,
Expr::Logical(e) => e.loc,
Expr::Conditional(e) => e.loc,
Expr::Assign(e) => e.loc,
Expr::Sequence(e) => e.loc,
Expr::Member(e) => e.loc,
Expr::OptionalMember(e) => e.loc,
Expr::Call(e) => e.loc,
Expr::OptionalCall(e) => e.loc,
Expr::OptionalChain(e) => e.loc(),
Expr::New(e) => e.loc,
Expr::TaggedTemplate(e) => e.loc,
Expr::Spread(e) => e.loc,
Expr::Yield(e) => e.loc,
Expr::Await(e) => e.loc,
Expr::Import(e) => e.loc,
Expr::MetaProp(e) => e.loc,
Expr::PrivateName(e) => e.loc,
}
}
}
#[derive(Debug, Clone)]
pub struct ThisExpr {
pub loc: SourceLocation,
}
#[derive(Debug, Clone)]
pub struct ArrayExpr {
pub loc: SourceLocation,
pub elements: Vec<Option<Expr>>,
}
#[derive(Debug, Clone)]
pub struct ObjectExpr {
pub loc: SourceLocation,
pub properties: Vec<ObjectProp>,
}
#[derive(Debug, Clone)]
pub enum ObjectProp {
Prop(Box<Prop>),
Spread(SpreadElement),
}
#[derive(Debug, Clone)]
pub struct Prop {
pub loc: SourceLocation,
pub key: PropKey,
pub is_computed: bool,
pub value: PropValue,
}
#[derive(Debug, Clone)]
pub enum PropKey {
Ident(Ident),
Private(PrivateIdent),
Str(StringLit),
Num(NumLit),
Computed(Box<Expr>),
}
#[derive(Debug, Clone)]
pub enum PropValue {
Value(Box<Expr>),
Shorthand,
Get(FnExpr),
Set(FnExpr),
Method(FnExpr),
}
#[derive(Debug, Clone)]
pub struct SpreadElement {
pub loc: SourceLocation,
pub argument: Box<Expr>,
}
#[derive(Debug, Clone)]
pub struct UnaryExpr {
pub loc: SourceLocation,
pub op: UnaryOp,
pub argument: Box<Expr>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UnaryOp {
Minus,
Plus,
Not,
BitNot,
Typeof,
Void,
Delete,
}
#[derive(Debug, Clone)]
pub struct UpdateExpr {
pub loc: SourceLocation,
pub op: UpdateOp,
pub prefix: bool,
pub argument: Box<Expr>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum UpdateOp {
Increment,
Decrement,
}
#[derive(Debug, Clone)]
pub struct BinaryExpr {
pub loc: SourceLocation,
pub op: BinaryOp,
pub left: Box<Expr>,
pub right: Box<Expr>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum BinaryOp {
Eq,
NotEq,
StrictEq,
StrictNotEq,
Lt,
LtEq,
Gt,
GtEq,
Shl,
Shr,
UShr,
Add,
Sub,
Mul,
Div,
Rem,
Exp,
BitOr,
BitXor,
BitAnd,
In,
Instanceof,
}
#[derive(Debug, Clone)]
pub struct LogicalExpr {
pub loc: SourceLocation,
pub op: LogicalOp,
pub left: Box<Expr>,
pub right: Box<Expr>,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum LogicalOp {
And,
Or,
NullishCoalesce,
}
#[derive(Debug, Clone)]
pub struct ConditionalExpr {
pub loc: SourceLocation,
pub test: Box<Expr>,
pub consequent: Box<Expr>,
pub alternate: Box<Expr>,
}
#[derive(Debug, Clone)]
pub struct AssignExpr {
pub loc: SourceLocation,
pub op: AssignOp,
pub left: AssignTarget,
pub right: Box<Expr>,
}
#[derive(Debug, Clone)]
pub enum AssignTarget {
Expr(Box<Expr>),
Pat(Pat),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum AssignOp {
Assign,
AddAssign,
SubAssign,
MulAssign,
DivAssign,
RemAssign,
ExpAssign,
ShlAssign,
ShrAssign,
UShrAssign,
BitOrAssign,
BitXorAssign,
BitAndAssign,
LogicalAndAssign,
LogicalOrAssign,
NullishAssign,
}
#[derive(Debug, Clone)]
pub struct SequenceExpr {
pub loc: SourceLocation,
pub expressions: Vec<Expr>,
}
#[derive(Debug, Clone)]
pub struct MemberExpr {
pub loc: SourceLocation,
pub object: Box<Expr>,
pub property: MemberProp,
pub is_computed: bool,
}
#[derive(Debug, Clone)]
pub struct OptionalMemberExpr {
pub loc: SourceLocation,
pub object: Box<Expr>,
pub property: MemberProp,
pub is_computed: bool,
}
#[derive(Debug, Clone)]
pub enum MemberProp {
Ident(Ident),
Private(PrivateIdent),
Computed(Box<Expr>),
}
#[derive(Debug, Clone)]
pub struct CallExpr {
pub loc: SourceLocation,
pub callee: Box<Expr>,
pub arguments: Vec<Expr>,
}
#[derive(Debug, Clone)]
pub struct OptionalCallExpr {
pub loc: SourceLocation,
pub callee: Box<Expr>,
pub arguments: Vec<Expr>,
}
#[derive(Debug, Clone)]
pub struct NewExpr {
pub loc: SourceLocation,
pub callee: Box<Expr>,
pub arguments: Vec<Expr>,
}
#[derive(Debug, Clone)]
pub struct TaggedTemplateExpr {
pub loc: SourceLocation,
pub tag: Box<Expr>,
pub quasi: TemplateLit,
}
#[derive(Debug, Clone)]
pub struct YieldExpr {
pub loc: SourceLocation,
pub delegate: bool,
pub argument: Option<Box<Expr>>,
}
#[derive(Debug, Clone)]
pub struct AwaitExpr {
pub loc: SourceLocation,
pub argument: Box<Expr>,
}
#[derive(Debug, Clone)]
pub struct ImportExpr {
pub loc: SourceLocation,
pub source: Box<Expr>,
}
#[derive(Debug, Clone)]
pub struct MetaPropExpr {
pub loc: SourceLocation,
pub meta: Ident,
pub property: Ident,
}
#[derive(Debug, Clone)]
pub enum Pat {
Ident(Ident),
Array(Box<ArrayPat>),
Object(Box<ObjectPat>),
Rest(Box<RestElement>),
Assign(Box<AssignPat>),
Expr(Box<Expr>),
}
impl Pat {
pub fn loc(&self) -> SourceLocation {
match self {
Pat::Ident(p) => p.loc,
Pat::Array(p) => p.loc,
Pat::Object(p) => p.loc,
Pat::Rest(p) => p.loc,
Pat::Assign(p) => p.loc,
Pat::Expr(e) => e.loc(),
}
}
}
#[derive(Debug, Clone)]
pub struct ArrayPat {
pub loc: SourceLocation,
pub elements: Vec<Option<Pat>>,
}
#[derive(Debug, Clone)]
pub struct ObjectPat {
pub loc: SourceLocation,
pub properties: Vec<ObjectPatProp>,
}
#[derive(Debug, Clone)]
pub enum ObjectPatProp {
KeyValue(KeyValuePatProp),
Assign(AssignPatProp),
Rest(RestElement),
}
#[derive(Debug, Clone)]
pub struct KeyValuePatProp {
pub loc: SourceLocation,
pub key: PropKey,
pub is_computed: bool,
pub value: Pat,
}
#[derive(Debug, Clone)]
pub struct AssignPatProp {
pub loc: SourceLocation,
pub key: Ident,
pub value: Option<Box<Expr>>,
}
#[derive(Debug, Clone)]
pub struct RestElement {
pub loc: SourceLocation,
pub argument: Box<Pat>,
}
#[derive(Debug, Clone)]
pub struct AssignPat {
pub loc: SourceLocation,
pub left: Box<Pat>,
pub right: Box<Expr>,
}
#[cfg(test)]
mod tests {
use super::*;
use crate::parser::scanner::{Position, Span};
fn dummy_loc() -> SourceLocation {
Span {
start: Position {
offset: 0,
line: 1,
column: 1,
},
end: Position {
offset: 0,
line: 1,
column: 1,
},
}
}
#[test]
fn test_source_type_variants() {
assert_ne!(SourceType::Script, SourceType::Module);
assert_eq!(SourceType::Script, SourceType::Script);
}
#[test]
fn test_program_empty_script() {
let prog = Program {
loc: dummy_loc(),
source_type: SourceType::Script,
body: vec![],
is_strict: false,
};
assert!(prog.body.is_empty());
assert_eq!(prog.source_type, SourceType::Script);
}
#[test]
fn test_program_module_with_item() {
let stmt = Stmt::Empty(EmptyStmt { loc: dummy_loc() });
let prog = Program {
loc: dummy_loc(),
source_type: SourceType::Module,
body: vec![ProgramItem::Stmt(stmt)],
is_strict: true,
};
assert_eq!(prog.body.len(), 1);
}
#[test]
fn test_stmt_loc_block() {
let s = Stmt::Block(BlockStmt {
loc: dummy_loc(),
body: vec![],
});
let _ = s.loc();
}
#[test]
fn test_stmt_loc_all_variants() {
let loc = dummy_loc();
let ident = || Ident {
loc,
name: "x".into(),
};
let expr = || Box::new(Expr::Null(NullLit { loc }));
let stmts: Vec<Stmt> = vec![
Stmt::Block(BlockStmt { loc, body: vec![] }),
Stmt::VarDecl(VarDecl {
loc,
kind: VarKind::Let,
declarators: vec![],
}),
Stmt::FnDecl(Box::new(FnDecl {
loc,
id: Some(ident()),
is_async: false,
is_generator: false,
params: vec![],
body: BlockStmt { loc, body: vec![] },
is_strict: false,
})),
Stmt::ClassDecl(Box::new(ClassDecl {
loc,
id: Some(ident()),
super_class: None,
body: ClassBody { loc, body: vec![] },
})),
Stmt::Expr(ExprStmt { loc, expr: expr() }),
Stmt::If(IfStmt {
loc,
test: expr(),
consequent: Box::new(Stmt::Empty(EmptyStmt { loc })),
alternate: None,
}),
Stmt::For(ForStmt {
loc,
init: None,
test: None,
update: None,
body: Box::new(Stmt::Empty(EmptyStmt { loc })),
}),
Stmt::ForIn(ForInStmt {
loc,
left: ForInOfLeft::Pat(Pat::Ident(ident())),
right: expr(),
body: Box::new(Stmt::Empty(EmptyStmt { loc })),
}),
Stmt::ForOf(ForOfStmt {
loc,
is_await: false,
left: ForInOfLeft::Pat(Pat::Ident(ident())),
right: expr(),
body: Box::new(Stmt::Empty(EmptyStmt { loc })),
}),
Stmt::While(WhileStmt {
loc,
test: expr(),
body: Box::new(Stmt::Empty(EmptyStmt { loc })),
}),
Stmt::DoWhile(DoWhileStmt {
loc,
body: Box::new(Stmt::Empty(EmptyStmt { loc })),
test: expr(),
}),
Stmt::Switch(SwitchStmt {
loc,
discriminant: expr(),
cases: vec![],
}),
Stmt::Try(TryStmt {
loc,
block: BlockStmt { loc, body: vec![] },
handler: None,
finalizer: None,
}),
Stmt::Return(ReturnStmt {
loc,
argument: None,
}),
Stmt::Throw(ThrowStmt {
loc,
argument: expr(),
}),
Stmt::Break(BreakStmt { loc, label: None }),
Stmt::Continue(ContinueStmt { loc, label: None }),
Stmt::Labeled(LabeledStmt {
loc,
label: ident(),
body: Box::new(Stmt::Empty(EmptyStmt { loc })),
}),
Stmt::Debugger(DebuggerStmt { loc }),
Stmt::With(WithStmt {
loc,
object: expr(),
body: Box::new(Stmt::Empty(EmptyStmt { loc })),
}),
Stmt::Empty(EmptyStmt { loc }),
];
for s in &stmts {
let _ = s.loc();
}
}
#[test]
fn test_var_decl_kinds() {
for kind in [VarKind::Var, VarKind::Let, VarKind::Const] {
let d = VarDecl {
loc: dummy_loc(),
kind,
declarators: vec![],
};
assert_eq!(d.kind, kind);
}
}
#[test]
fn test_expr_loc_null() {
let e = Expr::Null(NullLit { loc: dummy_loc() });
let _ = e.loc();
}
#[test]
fn test_expr_bool_values() {
let t = Expr::Bool(BoolLit {
loc: dummy_loc(),
value: true,
});
let f = Expr::Bool(BoolLit {
loc: dummy_loc(),
value: false,
});
if let Expr::Bool(b) = &t {
assert!(b.value);
}
if let Expr::Bool(b) = &f {
assert!(!b.value);
}
}
#[test]
fn test_expr_loc_all_variants() {
let loc = dummy_loc();
let ident = Ident {
loc,
name: "x".into(),
};
let null = || Box::new(Expr::Null(NullLit { loc }));
let exprs: Vec<Expr> = vec![
Expr::Null(NullLit { loc }),
Expr::Bool(BoolLit { loc, value: true }),
Expr::Num(NumLit {
loc,
value: 1.0,
raw: "1".into(),
}),
Expr::Str(StringLit {
loc,
value: "s".into(),
}),
Expr::BigInt(BigIntLit {
loc,
value: "9007199254740993".into(),
}),
Expr::Regexp(RegExpLit {
loc,
pattern: "x".into(),
flags: "g".into(),
}),
Expr::Template(Box::new(TemplateLit {
loc,
quasis: vec![],
expressions: vec![],
})),
Expr::Ident(ident.clone()),
Expr::This(ThisExpr { loc }),
Expr::Array(Box::new(ArrayExpr {
loc,
elements: vec![],
})),
Expr::Object(Box::new(ObjectExpr {
loc,
properties: vec![],
})),
Expr::Fn(Box::new(FnExpr {
loc,
id: None,
is_async: false,
is_generator: false,
params: vec![],
body: BlockStmt { loc, body: vec![] },
is_strict: false,
})),
Expr::Arrow(Box::new(ArrowExpr {
loc,
is_async: false,
params: vec![],
body: ArrowBody::Expr(null()),
is_strict: false,
})),
Expr::Class(Box::new(ClassExpr {
loc,
id: None,
super_class: None,
body: ClassBody { loc, body: vec![] },
})),
Expr::Unary(Box::new(UnaryExpr {
loc,
op: UnaryOp::Not,
argument: null(),
})),
Expr::Update(Box::new(UpdateExpr {
loc,
op: UpdateOp::Increment,
prefix: true,
argument: null(),
})),
Expr::Binary(Box::new(BinaryExpr {
loc,
op: BinaryOp::Add,
left: null(),
right: null(),
})),
Expr::Logical(Box::new(LogicalExpr {
loc,
op: LogicalOp::And,
left: null(),
right: null(),
})),
Expr::Conditional(Box::new(ConditionalExpr {
loc,
test: null(),
consequent: null(),
alternate: null(),
})),
Expr::Assign(Box::new(AssignExpr {
loc,
op: AssignOp::Assign,
left: AssignTarget::Expr(null()),
right: null(),
})),
Expr::Sequence(Box::new(SequenceExpr {
loc,
expressions: vec![],
})),
Expr::Member(Box::new(MemberExpr {
loc,
object: null(),
property: MemberProp::Ident(ident.clone()),
is_computed: false,
})),
Expr::OptionalMember(Box::new(OptionalMemberExpr {
loc,
object: null(),
property: MemberProp::Ident(ident.clone()),
is_computed: false,
})),
Expr::Call(Box::new(CallExpr {
loc,
callee: null(),
arguments: vec![],
})),
Expr::OptionalCall(Box::new(OptionalCallExpr {
loc,
callee: null(),
arguments: vec![],
})),
Expr::OptionalChain(null()),
Expr::New(Box::new(NewExpr {
loc,
callee: null(),
arguments: vec![],
})),
Expr::TaggedTemplate(Box::new(TaggedTemplateExpr {
loc,
tag: null(),
quasi: TemplateLit {
loc,
quasis: vec![],
expressions: vec![],
},
})),
Expr::Spread(Box::new(SpreadElement {
loc,
argument: null(),
})),
Expr::Yield(Box::new(YieldExpr {
loc,
delegate: false,
argument: None,
})),
Expr::Await(Box::new(AwaitExpr {
loc,
argument: null(),
})),
Expr::Import(Box::new(ImportExpr {
loc,
source: null(),
})),
Expr::MetaProp(MetaPropExpr {
loc,
meta: ident.clone(),
property: ident.clone(),
}),
];
for e in &exprs {
let _ = e.loc();
}
}
#[test]
fn test_pat_loc_all_variants() {
let loc = dummy_loc();
let ident = Ident {
loc,
name: "x".into(),
};
let pats: Vec<Pat> = vec![
Pat::Ident(ident.clone()),
Pat::Array(Box::new(ArrayPat {
loc,
elements: vec![],
})),
Pat::Object(Box::new(ObjectPat {
loc,
properties: vec![],
})),
Pat::Rest(Box::new(RestElement {
loc,
argument: Box::new(Pat::Ident(ident.clone())),
})),
Pat::Assign(Box::new(AssignPat {
loc,
left: Box::new(Pat::Ident(ident.clone())),
right: Box::new(Expr::Null(NullLit { loc })),
})),
Pat::Expr(Box::new(Expr::Ident(ident.clone()))),
];
for p in &pats {
let _ = p.loc();
}
}
#[test]
fn test_import_decl_construction() {
let loc = dummy_loc();
let decl = ImportDecl {
loc,
specifiers: vec![],
source: StringLit {
loc,
value: "./foo.js".into(),
},
attributes: vec![],
};
assert_eq!(decl.source.value, "./foo.js");
}
#[test]
fn test_export_all_decl() {
let loc = dummy_loc();
let decl = ExportAllDecl {
loc,
exported: None,
source: StringLit {
loc,
value: "./bar.js".into(),
},
attributes: vec![],
};
assert!(decl.exported.is_none());
}
#[test]
fn test_binary_op_variants() {
let ops = [
BinaryOp::Eq,
BinaryOp::NotEq,
BinaryOp::StrictEq,
BinaryOp::StrictNotEq,
BinaryOp::Lt,
BinaryOp::LtEq,
BinaryOp::Gt,
BinaryOp::GtEq,
BinaryOp::Add,
BinaryOp::Sub,
BinaryOp::Mul,
BinaryOp::Div,
BinaryOp::Rem,
BinaryOp::Exp,
BinaryOp::BitOr,
BinaryOp::BitXor,
BinaryOp::BitAnd,
BinaryOp::Shl,
BinaryOp::Shr,
BinaryOp::UShr,
BinaryOp::In,
BinaryOp::Instanceof,
];
assert_eq!(ops.len(), 22);
}
#[test]
fn test_assign_op_variants() {
let ops = [
AssignOp::Assign,
AssignOp::AddAssign,
AssignOp::SubAssign,
AssignOp::MulAssign,
AssignOp::DivAssign,
AssignOp::RemAssign,
AssignOp::ExpAssign,
AssignOp::ShlAssign,
AssignOp::ShrAssign,
AssignOp::UShrAssign,
AssignOp::BitOrAssign,
AssignOp::BitXorAssign,
AssignOp::BitAndAssign,
AssignOp::LogicalAndAssign,
AssignOp::LogicalOrAssign,
AssignOp::NullishAssign,
];
assert_eq!(ops.len(), 16);
}
}