use crate::{ident::Ident, span::Span};
use super::{
attribute::Annotation,
lit::Lit,
op::{AssignOpToken, BinOpToken, UnaryOp},
pat::Pattern,
path::{Path, TypeArguments},
stmt::Block,
ty::Type,
};
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum Expr {
Literal(Lit),
Ident(Ident),
This(Span),
Super(Span),
Paren {
paren_span: (Span, Span),
expr: Box<Expr>,
},
ClassLit {
type_expr: Box<Type>,
dot_span: Span,
class_span: Span,
},
FieldAccess(FieldAccessExpr),
MethodCall(MethodCallExpr),
ArrayAccess(ArrayAccessExpr),
MethodRef(MethodRefExpr),
ArrayNew(ArrayNewExpr),
Cast(CastExpr),
Binary(BinaryExpr),
Unary(UnaryExpr),
Instanceof(InstanceofExpr),
Assign(AssignExpr),
Conditional(ConditionalExpr),
Lambda(LambdaExpr),
Switch(SwitchExpr),
NewClass(NewClassExpr),
ArrayInit(ArrayInitExpr),
}
impl Expr {
pub fn span(&self) -> Span {
match self {
Self::Literal(lit) => lit.span(),
Self::Ident(ident) => ident.span(),
Self::This(s) => *s,
Self::Super(s) => *s,
Self::Paren { paren_span, .. } => paren_span.0.join(paren_span.1),
Self::ClassLit {
type_expr,
class_span,
..
} => type_expr.span().join(*class_span),
Self::FieldAccess(e) => e.span(),
Self::MethodCall(e) => e.span(),
Self::ArrayAccess(e) => e.span(),
Self::MethodRef(e) => e.span(),
Self::ArrayNew(e) => e.span(),
Self::Cast(e) => e.span(),
Self::Binary(e) => e.span(),
Self::Unary(e) => e.span(),
Self::Instanceof(e) => e.span(),
Self::Assign(e) => e.span(),
Self::Conditional(e) => e.span(),
Self::Lambda(e) => e.span,
Self::Switch(e) => e.span(),
Self::NewClass(e) => e.span(),
Self::ArrayInit(e) => e.brace_span.0.join(e.brace_span.1),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct FieldAccessExpr {
pub target: Box<Expr>,
pub dot_span: Span,
pub field: Ident,
}
impl FieldAccessExpr {
pub fn span(&self) -> Span {
self.target.span().join(self.field.span())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MethodCallExpr {
pub receiver: Option<Box<Expr>>,
pub type_args: Option<TypeArguments>,
pub method: Ident,
pub paren_span: (Span, Span),
pub args: Vec<Expr>,
}
impl MethodCallExpr {
pub fn span(&self) -> Span {
let start = match &self.receiver {
Some(r) => r.span(),
None => self.method.span(),
};
start.join(self.paren_span.1)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ArrayAccessExpr {
pub array: Box<Expr>,
pub index: Box<Expr>,
pub bracket_span: (Span, Span),
}
impl ArrayAccessExpr {
pub fn span(&self) -> Span {
self.array.span().join(self.bracket_span.1)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct MethodRefExpr {
pub target: MethodRefTarget,
pub colon_colon_span: Span,
pub type_args: Option<TypeArguments>,
pub method_name: Ident,
}
impl MethodRefExpr {
pub fn span(&self) -> Span {
let start = self.target.span();
start.join(self.method_name.span())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum MethodRefTarget {
Type(Path),
Expr(Box<Expr>),
Super(Span),
SuperFromType {
type_name: Path,
dot_span: Span,
super_span: Span,
},
}
impl MethodRefTarget {
pub fn span(&self) -> Span {
match self {
Self::Type(p) => p.span,
Self::Expr(e) => e.span(),
Self::Super(s) => *s,
Self::SuperFromType {
type_name,
super_span,
..
} => type_name.span.join(*super_span),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct NewClassExpr {
pub new_span: Span,
pub type_args: Option<TypeArguments>,
pub class_type: Path,
pub paren_span: (Span, Span),
pub args: Vec<Expr>,
pub body: Option<super::item::ClassBodyDeclList>,
}
impl NewClassExpr {
pub fn span(&self) -> Span {
let end = match &self.body {
Some(b) => b.brace_span.1,
None => self.paren_span.1,
};
self.new_span.join(end)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ArrayNewExpr {
pub new_span: Span,
pub elem_type: Type,
pub dim_exprs: Vec<ArrayDimExpr>,
pub dims: Vec<super::ty::ArrayDim>,
pub initializer: Option<ArrayInitExpr>,
}
impl ArrayNewExpr {
pub fn span(&self) -> Span {
let end = match &self.initializer {
Some(init) => init.brace_span.1,
None => {
if let Some(dim) = self.dims.last() {
dim.bracket_span.1
} else if let Some(dim_expr) = self.dim_exprs.last() {
dim_expr.bracket_span.1
} else {
self.elem_type.span()
}
}
};
self.new_span.join(end)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ArrayDimExpr {
pub annotations: Vec<Annotation>,
pub bracket_span: (Span, Span),
pub expr: Box<Expr>,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ArrayInitExpr {
pub brace_span: (Span, Span),
pub elements: Vec<Expr>,
pub trailing_comma: bool,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct CastExpr {
pub paren_span: (Span, Span),
pub target_type: Type,
pub expr: Box<Expr>,
}
impl CastExpr {
pub fn span(&self) -> Span {
self.paren_span.0.join(self.expr.span())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct BinaryExpr {
pub left: Box<Expr>,
pub op: BinOpToken,
pub right: Box<Expr>,
}
impl BinaryExpr {
pub fn span(&self) -> Span {
self.left.span().join(self.right.span())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct UnaryExpr {
pub op: UnaryOp,
pub op_span: Span,
pub expr: Box<Expr>,
pub is_postfix: bool,
}
impl UnaryExpr {
pub fn span(&self) -> Span {
if self.is_postfix {
self.expr.span().join(self.op_span)
} else {
self.op_span.join(self.expr.span())
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct InstanceofExpr {
pub expr: Box<Expr>,
pub instanceof_span: Span,
pub pattern: InstanceofPattern,
}
impl InstanceofExpr {
pub fn span(&self) -> Span {
match &self.pattern {
InstanceofPattern::Type(t) => self.expr.span().join(t.span()),
InstanceofPattern::Pattern(p) => self.expr.span().join(p.span()),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum InstanceofPattern {
Type(Type),
Pattern(Pattern),
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct AssignExpr {
pub target: AssignTarget,
pub op: AssignOpToken,
pub value: Box<Expr>,
}
impl AssignExpr {
pub fn span(&self) -> Span {
self.target.span().join(self.value.span())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum AssignTarget {
Ident(Ident),
FieldAccess(FieldAccessExpr),
ArrayAccess(ArrayAccessExpr),
}
impl AssignTarget {
pub fn span(&self) -> Span {
match self {
Self::Ident(i) => i.span(),
Self::FieldAccess(f) => f.span(),
Self::ArrayAccess(a) => a.span(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct ConditionalExpr {
pub cond: Box<Expr>,
pub question_span: Span,
pub then_expr: Box<Expr>,
pub colon_span: Span,
pub else_expr: Box<Expr>,
}
impl ConditionalExpr {
pub fn span(&self) -> Span {
self.cond.span().join(self.else_expr.span())
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct LambdaExpr {
pub params: LambdaParams,
pub arrow_span: Span,
pub body: LambdaBody,
pub span: Span,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum LambdaParams {
List {
paren_span: (Span, Span),
params: Vec<LambdaParam>,
},
IdentList {
paren_span: (Span, Span),
idents: Vec<Ident>,
},
Single(Ident),
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct LambdaParam {
pub modifiers: Vec<super::item::Modifier>,
pub ty: Type,
pub name: Ident,
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum LambdaBody {
Expr(Box<Expr>),
Block(Block),
}
impl LambdaBody {
pub fn span(&self) -> Span {
match self {
Self::Expr(e) => e.span(),
Self::Block(b) => b.span(),
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct SwitchExpr {
pub switch_span: Span,
pub paren_span: (Span, Span),
pub selector: Box<Expr>,
pub brace_span: (Span, Span),
pub cases: Vec<SwitchArm>,
}
impl SwitchExpr {
pub fn span(&self) -> Span {
self.switch_span.join(self.brace_span.1)
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum SwitchArm {
Expr(SwitchCase, Span, Expr),
Block(SwitchCase, Span, Block),
Throw(SwitchCase, Span, Expr),
Colon(SwitchCase, Vec<super::stmt::Stmt>),
}
impl SwitchArm {
pub fn span(&self) -> Span {
match self {
Self::Expr(case, _arrow, expr) => case.span().join(expr.span()),
Self::Block(case, _arrow, block) => case.span().join(block.brace_span.1),
Self::Throw(case, _arrow, expr) => case.span().join(expr.span()),
Self::Colon(case, stmts) => {
let end = stmts.last().map(|s| s.span()).unwrap_or(case.span());
case.span().join(end)
}
}
}
}
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub enum SwitchCase {
CaseValues { case_span: Span, values: Vec<Expr> },
CaseNull { case_span: Span, null_span: Span },
CaseNullDefault {
case_span: Span,
null_span: Span,
default_span: Span,
},
CasePattern {
case_span: Span,
pattern: Pattern,
guard: Box<Option<super::pat::Guard>>,
},
Default { default_span: Span },
}
impl SwitchCase {
pub fn span(&self) -> Span {
match self {
Self::CaseValues { case_span, values } => {
let end = values.last().map(|v| v.span()).unwrap_or(*case_span);
case_span.join(end)
}
Self::CaseNull {
case_span,
null_span,
} => case_span.join(*null_span),
Self::CaseNullDefault {
case_span,
default_span,
..
} => case_span.join(*default_span),
Self::CasePattern {
case_span,
pattern,
guard,
} => {
let end = match guard.as_ref() {
Some(g) => g.expr.span(),
None => pattern.span(),
};
case_span.join(end)
}
Self::Default { default_span } => *default_span,
}
}
}