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
118
119
120
121
122
123
124
125
126
127
use crate::{kw, SolPath, Type};
use proc_macro2::Span;
use syn::{
    braced,
    parse::{Parse, ParseStream},
    punctuated::Punctuated,
    token::Brace,
    Result, Token,
};

/// A `using` directive: `using { A, B.mul as * } for uint256 global;`
///
/// Solidity reference:
/// <https://docs.soliditylang.org/en/latest/grammar.html#a4.SolidityParser.usingDirective>
#[derive(Clone, Debug)]
pub struct UsingDirective {
    pub using_token: kw::using,
    pub list: UsingList,
    pub for_token: Token![for],
    pub ty: UsingType,
    pub global_token: Option<kw::global>,
    pub semi_token: Token![;],
}

impl Parse for UsingDirective {
    fn parse(input: ParseStream<'_>) -> Result<Self> {
        Ok(Self {
            using_token: input.parse()?,
            list: input.parse()?,
            for_token: input.parse()?,
            ty: input.parse()?,
            global_token: input.parse()?,
            semi_token: input.parse()?,
        })
    }
}

impl UsingDirective {
    pub fn span(&self) -> Span {
        let span = self.using_token.span;
        span.join(self.semi_token.span).unwrap_or(span)
    }

    pub fn set_span(&mut self, span: Span) {
        self.using_token.span = span;
        self.semi_token.span = span;
    }
}

#[derive(Clone, Debug)]
pub enum UsingList {
    Single(SolPath),
    Multiple(Brace, Punctuated<UsingListItem, Token![,]>),
}

impl Parse for UsingList {
    fn parse(input: ParseStream<'_>) -> Result<Self> {
        if input.peek(Brace) {
            let content;
            Ok(Self::Multiple(
                braced!(content in input),
                content.parse_terminated(UsingListItem::parse, Token![,])?,
            ))
        } else {
            input.parse().map(Self::Single)
        }
    }
}

#[derive(Clone, Debug)]
pub struct UsingListItem {
    pub path: SolPath,
    pub op: Option<(Token![as], UserDefinableOperator)>,
}

impl Parse for UsingListItem {
    fn parse(input: ParseStream<'_>) -> Result<Self> {
        Ok(Self {
            path: input.parse()?,
            op: if input.peek(Token![as]) {
                Some((input.parse()?, input.parse()?))
            } else {
                None
            },
        })
    }
}

#[derive(Clone, Debug)]
pub enum UsingType {
    Star(Token![*]),
    Type(Type),
}

impl Parse for UsingType {
    fn parse(input: ParseStream<'_>) -> Result<Self> {
        if input.peek(Token![*]) {
            input.parse().map(Self::Star)
        } else {
            input.parse().map(Self::Type)
        }
    }
}

op_enum! {
    /// A user-definable operator: `+`, `*`, `|`, etc.
    ///
    /// Solidity reference:
    /// <https://docs.soliditylang.org/en/latest/grammar.html#a4.SolidityParser.userDefinableOperator>
    pub enum UserDefinableOperator {
        BitAnd(&),
        BitNot(~),
        BitOr(|),
        BitXor(^),
        Add(+),
        Div(/),
        Rem(%),
        Mul(*),
        Sub(-),
        Eq(==),
        Ge(>=),
        Gt(>),
        Le(<=),
        Lt(<),
        Ne(!=),
    }
}