syn_solidity/stmt/
try.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
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,
};

/// A try statement: `try fooBar(42) catch { ... }`.
///
/// Solidity reference:
/// <https://docs.soliditylang.org/en/latest/grammar.html#a4.SolidityParser.tryStatement>
#[derive(Clone)]
pub struct StmtTry {
    pub try_token: Token![try],
    pub expr: Box<Expr>,
    pub returns: Option<Returns>,
    /// The try block.
    pub block: Block,
    /// The list of catch clauses. Cannot be parsed empty.
    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);
    }
}

/// A catch clause of a [`StmtTry`]: `catch  { ... }`.
///
/// Solidity reference:
/// <https://docs.soliditylang.org/en/latest/grammar.html#a4.SolidityParser.tryStatement>
#[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);
    }
}