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
use crate::error::{ParseError, Result};
use crate::parser::Parser;
use crate::source::Source;
use crate::token::{self, Kind, Token};
use crate::traits::{Parse, Resolve};
use runestick::unit::Span;
pub enum Number {
Float(f64),
Integer(i64),
}
#[derive(Debug, Clone)]
pub struct LitNumber {
is_negative: bool,
is_fractional: bool,
number: token::LitNumber,
token: Token,
}
impl LitNumber {
pub fn span(&self) -> Span {
self.token.span
}
}
impl Parse for LitNumber {
fn parse(parser: &mut Parser<'_>) -> Result<Self, ParseError> {
let token = parser.token_next()?;
Ok(match token.kind {
Kind::LitNumber {
is_negative,
is_fractional,
number,
..
} => LitNumber {
is_negative,
is_fractional,
number,
token,
},
_ => {
return Err(ParseError::ExpectedNumber {
actual: token.kind,
span: token.span,
})
}
})
}
}
impl<'a> Resolve<'a> for LitNumber {
type Output = Number;
fn resolve(&self, source: Source<'a>) -> Result<Number, ParseError> {
use num::{Num as _, ToPrimitive as _};
use std::ops::Neg as _;
use std::str::FromStr as _;
let span = self.token.span;
let string = source.source(span)?;
let string = if self.is_negative {
&string[1..]
} else {
string
};
if self.is_fractional {
let number = f64::from_str(string).map_err(err_span(span))?;
return Ok(Number::Float(number));
}
let (s, radix) = match self.number {
token::LitNumber::Binary => (2, 2),
token::LitNumber::Octal => (2, 8),
token::LitNumber::Hex => (2, 16),
token::LitNumber::Decimal => (0, 10),
};
let number = num::BigUint::from_str_radix(&string[s..], radix).map_err(err_span(span))?;
let number = if self.is_negative {
num::BigInt::from(number).neg().to_i64()
} else {
number.to_i64()
};
let number = match number {
Some(n) => n,
None => return Err(ParseError::BadNumberOutOfBounds { span }),
};
return Ok(Number::Integer(number));
fn err_span<E>(span: Span) -> impl Fn(E) -> ParseError {
move |_| ParseError::BadNumberLiteral { span }
}
}
}