syn_solidity/lit/
number.rs

1use crate::{kw, Spanned};
2use proc_macro2::{Literal, Span};
3use std::{fmt, str::FromStr};
4use syn::{
5    parse::{Lookahead1, Parse, ParseStream},
6    LitFloat, LitInt, Result,
7};
8
9// TODO: Fixed point numbers
10
11/// An integer or fixed-point number literal: `1` or `1.0`.
12#[derive(Clone)]
13pub enum LitNumber {
14    Int(LitInt),
15    Float(LitFloat),
16}
17
18impl fmt::Debug for LitNumber {
19    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
20        match self {
21            Self::Int(lit) => lit.fmt(f),
22            Self::Float(lit) => lit.fmt(f),
23        }
24    }
25}
26
27impl Parse for LitNumber {
28    fn parse(input: ParseStream<'_>) -> Result<Self> {
29        let lookahead = input.lookahead1();
30        if lookahead.peek(LitInt) {
31            input.parse().map(Self::Int)
32        } else if lookahead.peek(LitFloat) {
33            input.parse().map(Self::Float)
34        } else {
35            Err(lookahead.error())
36        }
37    }
38}
39
40impl Spanned for LitNumber {
41    fn span(&self) -> Span {
42        match self {
43            Self::Int(lit) => lit.span(),
44            Self::Float(lit) => lit.span(),
45        }
46    }
47
48    fn set_span(&mut self, span: Span) {
49        match self {
50            Self::Int(lit) => lit.set_span(span),
51            Self::Float(lit) => lit.set_span(span),
52        }
53    }
54}
55
56impl LitNumber {
57    pub fn new_int(repr: &str, span: Span) -> Self {
58        Self::Int(LitInt::new(repr, span))
59    }
60
61    pub fn new_fixed(repr: &str, span: Span) -> Self {
62        Self::Float(LitFloat::new(repr, span))
63    }
64
65    pub fn peek(lookahead: &Lookahead1<'_>) -> bool {
66        lookahead.peek(LitInt) || lookahead.peek(LitFloat)
67    }
68
69    /// Returns the base-10 digits of the literal.
70    pub fn base10_digits(&self) -> &str {
71        match self {
72            Self::Int(lit) => lit.base10_digits(),
73            Self::Float(lit) => lit.base10_digits(),
74        }
75    }
76
77    /// Parses the literal into a selected number type.
78    ///
79    /// This is equivalent to `lit.base10_digits().parse()` except that the
80    /// resulting errors will be correctly spanned to point to the literal token
81    /// in the macro input.
82    pub fn base10_parse<N>(&self) -> Result<N>
83    where
84        N: FromStr,
85        N::Err: fmt::Display,
86    {
87        match self {
88            Self::Int(lit) => lit.base10_parse(),
89            Self::Float(lit) => lit.base10_parse(),
90        }
91    }
92
93    pub fn suffix(&self) -> &str {
94        match self {
95            Self::Int(lit) => lit.suffix(),
96            Self::Float(lit) => lit.suffix(),
97        }
98    }
99
100    pub fn token(&self) -> Literal {
101        match self {
102            Self::Int(lit) => lit.token(),
103            Self::Float(lit) => lit.token(),
104        }
105    }
106}
107
108#[derive(Clone, Debug)]
109pub struct LitDenominated {
110    pub number: LitNumber,
111    pub denom: SubDenomination,
112}
113
114impl Parse for LitDenominated {
115    fn parse(input: ParseStream<'_>) -> Result<Self> {
116        Ok(Self { number: input.parse()?, denom: input.parse()? })
117    }
118}
119
120impl Spanned for LitDenominated {
121    fn span(&self) -> Span {
122        let span = self.number.span();
123        span.join(self.denom.span()).unwrap_or(span)
124    }
125
126    fn set_span(&mut self, span: Span) {
127        self.number.set_span(span);
128        self.denom.set_span(span);
129    }
130}
131
132kw_enum! {
133    /// A sub-denomination suffix for a number literal.
134    pub enum SubDenomination {
135        Wei(kw::wei),
136        Gwei(kw::gwei),
137        Ether(kw::ether),
138
139        Seconds(kw::seconds),
140        Minutes(kw::minutes),
141        Hours(kw::hours),
142        Days(kw::days),
143        Weeks(kw::weeks),
144        Years(kw::years),
145    }
146}
147
148impl SubDenomination {
149    /// Returns the value of this sub-denomination.
150    pub const fn value(self) -> u64 {
151        // https://github.com/ethereum/solidity/blob/2a2a9d37ee69ca77ef530fe18524a3dc8b053104/libsolidity/ast/Types.cpp#L973
152        match self {
153            Self::Wei(..) => 1,
154            Self::Gwei(..) => 1_000_000_000,
155            Self::Ether(..) => 1_000_000_000_000_000_000,
156
157            Self::Seconds(..) => 1,
158            Self::Minutes(..) => 60,
159            Self::Hours(..) => 3_600,
160            Self::Days(..) => 86_400,
161            Self::Weeks(..) => 604_800,
162            Self::Years(..) => 31_536_000,
163        }
164    }
165}