use crate::{kw, Block, Expr, ParameterList, Returns, SolIdent, Spanned};
use proc_macro2::Span;
use std::fmt;
use syn::{
    parenthesized,
    parse::{Parse, ParseStream},
    token::Paren,
    Result, Token,
};
#[derive(Clone)]
pub struct StmtTry {
    pub try_token: Token![try],
    pub expr: Box<Expr>,
    pub returns: Option<Returns>,
    pub block: Block,
    pub catch: Vec<CatchClause>,
}
impl fmt::Debug for StmtTry {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("StmtTry")
            .field("expr", &self.expr)
            .field("returns", &self.returns)
            .field("block", &self.block)
            .field("catch", &self.catch)
            .finish()
    }
}
impl Parse for StmtTry {
    fn parse(input: ParseStream<'_>) -> Result<Self> {
        Ok(Self {
            try_token: input.parse()?,
            expr: input.parse()?,
            returns: input.call(Returns::parse_opt)?,
            block: input.parse()?,
            catch: {
                let mut catch = Vec::new();
                let mut first = true;
                while first || input.peek(kw::catch) {
                    first = false;
                    catch.push(input.parse()?);
                }
                catch
            },
        })
    }
}
impl Spanned for StmtTry {
    fn span(&self) -> Span {
        let span = self.try_token.span;
        span.join(self.block.span()).unwrap_or(span)
    }
    fn set_span(&mut self, span: Span) {
        self.try_token.span = span;
        self.block.set_span(span);
    }
}
#[derive(Clone)]
pub struct CatchClause {
    pub catch_token: kw::catch,
    pub name: Option<SolIdent>,
    pub paren_token: Option<Paren>,
    pub list: ParameterList,
    pub block: Block,
}
impl fmt::Debug for CatchClause {
    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
        f.debug_struct("CatchClause")
            .field("name", &self.name)
            .field("list", &self.list)
            .field("block", &self.block)
            .finish()
    }
}
impl Parse for CatchClause {
    fn parse(input: ParseStream<'_>) -> Result<Self> {
        let catch_token = input.parse()?;
        let name = input.call(SolIdent::parse_opt)?;
        let (paren_token, list) = if input.peek(Paren) {
            let content;
            (Some(parenthesized!(content in input)), content.parse()?)
        } else {
            (None, ParameterList::new())
        };
        let block = input.parse()?;
        Ok(Self { catch_token, name, paren_token, list, block })
    }
}
impl Spanned for CatchClause {
    fn span(&self) -> Span {
        let span = self.catch_token.span;
        span.join(self.block.span()).unwrap_or(span)
    }
    fn set_span(&mut self, span: Span) {
        self.catch_token.span = span;
        self.block.set_span(span);
    }
}