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
use crate::ast;
use crate::{
Parse, ParseError, Parser, Resolve, ResolveError, ResolveErrorKind, ResolveOwned, Spanned,
Storage, ToTokens,
};
use runestick::{Source, Span};
#[derive(Debug, Clone, PartialEq, Eq, ToTokens, Spanned)]
pub struct LitNumber {
pub token: ast::Token,
#[rune(skip)]
pub source: ast::NumberSource,
}
impl Parse for LitNumber {
fn parse(parser: &mut Parser<'_>) -> Result<Self, ParseError> {
let token = parser.next()?;
match token.kind {
K![number(source)] => Ok(LitNumber { source, token }),
_ => Err(ParseError::expected(&token, "number")),
}
}
}
impl<'a> Resolve<'a> for LitNumber {
type Output = ast::Number;
fn resolve(&self, storage: &Storage, source: &'a Source) -> Result<ast::Number, ResolveError> {
use num::Num as _;
use std::str::FromStr as _;
let span = self.token.span();
let text = match self.source {
ast::NumberSource::Synthetic(id) => match storage.get_number(id) {
Some(number) => return Ok(number),
None => {
return Err(ResolveError::new(
span,
ResolveErrorKind::BadSyntheticId { kind: "number", id },
));
}
},
ast::NumberSource::Text(text) => text,
};
let string = source
.source(span)
.ok_or_else(|| ResolveError::new(span, ResolveErrorKind::BadSlice))?;
if text.is_fractional {
let number = f64::from_str(string).map_err(err_span(span))?;
return Ok(ast::Number::Float(number));
}
let (s, radix) = match text.base {
ast::NumberBase::Binary => (2, 2),
ast::NumberBase::Octal => (2, 8),
ast::NumberBase::Hex => (2, 16),
ast::NumberBase::Decimal => (0, 10),
};
let number = num::BigInt::from_str_radix(&string[s..], radix).map_err(err_span(span))?;
return Ok(ast::Number::Integer(number));
fn err_span<E>(span: Span) -> impl Fn(E) -> ResolveError {
move |_| ResolveError::new(span, ResolveErrorKind::BadNumberLiteral)
}
}
}
impl ResolveOwned for LitNumber {
type Owned = ast::Number;
fn resolve_owned(
&self,
storage: &Storage,
source: &Source,
) -> Result<Self::Owned, ResolveError> {
self.resolve(storage, source)
}
}