use crate::{SourceCodeSpan, SourceSpan, source_code_span_impl};
use super::expr::Expr;
use super::item::{Ident, Item};
use super::ty::Type;
#[derive(Debug, Clone, PartialEq)]
pub struct Block<'de> {
pub stmts: Vec<Stmt<'de>>,
}
source_code_span_impl!(Block, stmts);
#[derive(Debug, Clone, PartialEq)]
pub enum Stmt<'de> {
Local(StmtLocal<'de>),
Item(Item<'de>),
Expr(StmtExpr<'de>),
Return(StmtReturn<'de>),
Break(StmtBreak<'de>),
Continue(StmtContinue<'de>),
Goto(StmtGoto<'de>),
Label(StmtLabel<'de>),
If(StmtIf<'de>),
While(StmtWhile<'de>),
DoWhile(StmtDoWhile<'de>),
For(StmtFor<'de>),
ForRange(StmtForRange<'de>),
Switch(StmtSwitch<'de>),
Case(StmtCase<'de>),
Default(StmtDefault<'de>),
TryCatch(StmtTryCatch<'de>),
Block(Block<'de>),
Empty,
}
impl<'de> SourceCodeSpan<'de> for Stmt<'de> {
fn span(&self) -> Option<SourceSpan<'de>> {
match self {
Stmt::Local(stmt_local) => stmt_local.span(),
Stmt::Item(item) => item.span(),
Stmt::Expr(stmt_expr) => stmt_expr.span(),
Stmt::Return(stmt_return) => stmt_return.span(),
Stmt::Break(stmt_break) => stmt_break.span(),
Stmt::Continue(stmt_continue) => stmt_continue.span(),
Stmt::Goto(stmt_goto) => stmt_goto.span(),
Stmt::Label(stmt_label) => stmt_label.span(),
Stmt::If(stmt_if) => stmt_if.span(),
Stmt::While(stmt_while) => stmt_while.span(),
Stmt::DoWhile(stmt_do_while) => stmt_do_while.span(),
Stmt::For(stmt_for) => stmt_for.span(),
Stmt::ForRange(stmt_for_range) => stmt_for_range.span(),
Stmt::Switch(stmt_switch) => stmt_switch.span(),
Stmt::Case(stmt_case) => stmt_case.span(),
Stmt::Default(stmt_default) => stmt_default.span(),
Stmt::TryCatch(stmt_try_catch) => stmt_try_catch.span(),
Stmt::Block(block) => block.span(),
Stmt::Empty => None,
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct StmtLocal<'de> {
pub ty: Type<'de>,
pub ident: Ident<'de>,
pub init: Option<Expr<'de>>,
}
source_code_span_impl!(StmtLocal, ty, ident, and_then, init);
#[derive(Debug, Clone, PartialEq)]
pub struct StmtExpr<'de> {
pub expr: Expr<'de>,
}
source_code_span_impl!(StmtExpr, expr);
#[derive(Debug, Clone, PartialEq)]
pub struct StmtReturn<'de> {
pub expr: Option<Expr<'de>>,
}
source_code_span_impl!(StmtReturn, and_then, expr);
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct StmtBreak<'de> {
pub span: crate::SourceSpan<'de>,
}
source_code_span_impl!(StmtBreak, Some, span);
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct StmtContinue<'de> {
pub span: crate::SourceSpan<'de>,
}
source_code_span_impl!(StmtContinue, Some, span);
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct StmtGoto<'de> {
pub label: Ident<'de>,
}
source_code_span_impl!(StmtGoto, label);
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct StmtLabel<'de> {
pub label: Ident<'de>,
}
source_code_span_impl!(StmtLabel, label);
#[derive(Debug, Clone, PartialEq)]
pub struct StmtIf<'de> {
pub init: Option<Box<Stmt<'de>>>,
pub condition: Expr<'de>,
pub then_body: Box<Stmt<'de>>,
pub else_body: Option<Box<Stmt<'de>>>,
}
source_code_span_impl!(
StmtIf, and_then, init, condition, then_body, and_then, else_body
);
#[derive(Debug, Clone, PartialEq)]
pub struct StmtWhile<'de> {
pub condition: Expr<'de>,
pub body: Box<Stmt<'de>>,
}
source_code_span_impl!(StmtWhile, condition, body);
#[derive(Debug, Clone, PartialEq)]
pub struct StmtDoWhile<'de> {
pub body: Box<Stmt<'de>>,
pub condition: Expr<'de>,
}
source_code_span_impl!(StmtDoWhile, body, condition);
#[derive(Debug, Clone, PartialEq)]
pub struct StmtFor<'de> {
pub init: Option<Box<Stmt<'de>>>,
pub condition: Option<Expr<'de>>,
pub increment: Option<Expr<'de>>,
pub body: Box<Stmt<'de>>,
}
source_code_span_impl!(
StmtFor, and_then, init, and_then, condition, and_then, increment, body
);
#[derive(Debug, Clone, PartialEq)]
pub enum ForRangeBinding<'de> {
Ident(Ident<'de>),
Structured(Vec<Ident<'de>>),
}
impl<'de> SourceCodeSpan<'de> for ForRangeBinding<'de> {
fn span(&self) -> Option<SourceSpan<'de>> {
match self {
ForRangeBinding::Ident(ident) => ident.span(),
ForRangeBinding::Structured(idents) => idents.span(),
}
}
}
#[derive(Debug, Clone, PartialEq)]
pub struct StmtForRange<'de> {
pub ty: Type<'de>,
pub binding: ForRangeBinding<'de>,
pub range: Expr<'de>,
pub body: Box<Stmt<'de>>,
}
source_code_span_impl!(StmtForRange, ty, binding, range, body);
#[derive(Debug, Clone, PartialEq)]
pub struct StmtSwitch<'de> {
pub expr: Expr<'de>,
pub body: Block<'de>,
}
source_code_span_impl!(StmtSwitch, expr, body);
#[derive(Debug, Clone, PartialEq)]
pub struct StmtCase<'de> {
pub value: Expr<'de>,
}
source_code_span_impl!(StmtCase, value);
#[derive(Debug, Clone, Copy, PartialEq)]
pub struct StmtDefault<'de> {
pub span: crate::SourceSpan<'de>,
}
source_code_span_impl!(StmtDefault, Some, span);
#[derive(Debug, Clone, PartialEq)]
pub struct StmtTryCatch<'de> {
pub try_body: Block<'de>,
pub catches: Vec<CatchClause<'de>>,
}
source_code_span_impl!(StmtTryCatch, try_body, catches);
#[derive(Debug, Clone, PartialEq)]
pub struct CatchClause<'de> {
pub param: CatchParam<'de>,
pub body: Block<'de>,
}
source_code_span_impl!(CatchClause, param, body);
#[derive(Debug, Clone, PartialEq)]
pub enum CatchParam<'de> {
Typed {
ty: Type<'de>,
ident: Option<Ident<'de>>,
},
Ellipsis,
}
impl<'de> SourceCodeSpan<'de> for CatchParam<'de> {
fn span(&self) -> Option<SourceSpan<'de>> {
if let CatchParam::Typed { ty, ident } = &self {
if let Some(ty_span) = ty.span() {
if let Some(ident_span) = ident.map(|i| i.span) {
Some(ty_span.extend(ident_span))
} else {
Some(ty_span)
}
} else {
None
}
} else {
None
}
}
}