1use std::ops::RangeInclusive;
2
3use nom8::branch::alt;
4use nom8::bytes::one_of;
5use nom8::bytes::tag;
6use nom8::bytes::take;
7use nom8::combinator::cut;
8use nom8::combinator::opt;
9use nom8::combinator::peek;
10use nom8::combinator::rest;
11use nom8::multi::many0_count;
12use nom8::sequence::preceded;
13
14use crate::parser::prelude::*;
15use crate::parser::trivia::from_utf8_unchecked;
16
17#[allow(dead_code)] pub(crate) fn boolean(input: Input<'_>) -> IResult<Input<'_>, bool, ParserError<'_>> {
22 alt((true_, false_)).parse(input)
23}
24
25pub(crate) fn true_(input: Input<'_>) -> IResult<Input<'_>, bool, ParserError<'_>> {
26 (peek(TRUE[0]), cut(TRUE)).value(true).parse(input)
27}
28const TRUE: &[u8] = b"true";
29
30pub(crate) fn false_(input: Input<'_>) -> IResult<Input<'_>, bool, ParserError<'_>> {
31 (peek(FALSE[0]), cut(FALSE)).value(false).parse(input)
32}
33const FALSE: &[u8] = b"false";
34
35pub(crate) fn integer(input: Input<'_>) -> IResult<Input<'_>, i64, ParserError<'_>> {
39 dispatch! {peek(opt::<_, &[u8], _, _>(take(2usize)));
40 Some(b"0x") => cut(hex_int.map_res(|s| i64::from_str_radix(&s.replace('_', ""), 16))),
41 Some(b"0o") => cut(oct_int.map_res(|s| i64::from_str_radix(&s.replace('_', ""), 8))),
42 Some(b"0b") => cut(bin_int.map_res(|s| i64::from_str_radix(&s.replace('_', ""), 2))),
43 _ => dec_int.and_then(cut(rest
44 .map_res(|s: &str| s.replace('_', "").parse())))
45 }
46 .parse(input)
47}
48
49pub(crate) fn dec_int(input: Input<'_>) -> IResult<Input<'_>, &str, ParserError<'_>> {
52 (
53 opt(one_of((b'+', b'-'))),
54 alt((
55 (
56 one_of(DIGIT1_9),
57 many0_count(alt((
58 digit.value(()),
59 (
60 one_of(b'_'),
61 cut(digit).context(Context::Expected(ParserValue::Description("digit"))),
62 )
63 .value(()),
64 ))),
65 )
66 .value(()),
67 digit.value(()),
68 )),
69 )
70 .recognize()
71 .map(|b: &[u8]| unsafe { from_utf8_unchecked(b, "`digit` and `_` filter out non-ASCII") })
72 .context(Context::Expression("integer"))
73 .parse(input)
74}
75const DIGIT1_9: RangeInclusive<u8> = b'1'..=b'9';
76
77pub(crate) fn hex_int(input: Input<'_>) -> IResult<Input<'_>, &str, ParserError<'_>> {
80 preceded(
81 HEX_PREFIX,
82 cut((
83 hexdig,
84 many0_count(alt((
85 hexdig.value(()),
86 (
87 one_of(b'_'),
88 cut(hexdig).context(Context::Expected(ParserValue::Description("digit"))),
89 )
90 .value(()),
91 ))),
92 ))
93 .recognize(),
94 )
95 .map(|b| unsafe { from_utf8_unchecked(b, "`hexdig` and `_` filter out non-ASCII") })
96 .context(Context::Expression("hexadecimal integer"))
97 .parse(input)
98}
99const HEX_PREFIX: &[u8] = b"0x";
100
101pub(crate) fn oct_int(input: Input<'_>) -> IResult<Input<'_>, &str, ParserError<'_>> {
104 preceded(
105 OCT_PREFIX,
106 cut((
107 one_of(DIGIT0_7),
108 many0_count(alt((
109 one_of(DIGIT0_7).value(()),
110 (
111 one_of(b'_'),
112 cut(one_of(DIGIT0_7))
113 .context(Context::Expected(ParserValue::Description("digit"))),
114 )
115 .value(()),
116 ))),
117 ))
118 .recognize(),
119 )
120 .map(|b| unsafe { from_utf8_unchecked(b, "`DIGIT0_7` and `_` filter out non-ASCII") })
121 .context(Context::Expression("octal integer"))
122 .parse(input)
123}
124const OCT_PREFIX: &[u8] = b"0o";
125const DIGIT0_7: RangeInclusive<u8> = b'0'..=b'7';
126
127pub(crate) fn bin_int(input: Input<'_>) -> IResult<Input<'_>, &str, ParserError<'_>> {
130 preceded(
131 BIN_PREFIX,
132 cut((
133 one_of(DIGIT0_1),
134 many0_count(alt((
135 one_of(DIGIT0_1).value(()),
136 (
137 one_of(b'_'),
138 cut(one_of(DIGIT0_1))
139 .context(Context::Expected(ParserValue::Description("digit"))),
140 )
141 .value(()),
142 ))),
143 ))
144 .recognize(),
145 )
146 .map(|b| unsafe { from_utf8_unchecked(b, "`DIGIT0_1` and `_` filter out non-ASCII") })
147 .context(Context::Expression("binary integer"))
148 .parse(input)
149}
150const BIN_PREFIX: &[u8] = b"0b";
151const DIGIT0_1: RangeInclusive<u8> = b'0'..=b'1';
152
153pub(crate) fn float(input: Input<'_>) -> IResult<Input<'_>, f64, ParserError<'_>> {
159 alt((
160 float_.and_then(cut(rest
161 .map_res(|s: &str| s.replace('_', "").parse())
162 .verify(|f: &f64| *f != f64::INFINITY))),
163 special_float,
164 ))
165 .context(Context::Expression("floating-point number"))
166 .parse(input)
167}
168
169pub(crate) fn float_(input: Input<'_>) -> IResult<Input<'_>, &str, ParserError<'_>> {
170 (dec_int, alt((exp, (frac, opt(exp)).map(|_| ""))))
171 .recognize()
172 .map(|b: &[u8]| unsafe {
173 from_utf8_unchecked(
174 b,
175 "`dec_int`, `one_of`, `exp`, and `frac` filter out non-ASCII",
176 )
177 })
178 .parse(input)
179}
180
181pub(crate) fn frac(input: Input<'_>) -> IResult<Input<'_>, &str, ParserError<'_>> {
184 (
185 b'.',
186 cut(zero_prefixable_int).context(Context::Expected(ParserValue::Description("digit"))),
187 )
188 .recognize()
189 .map(|b: &[u8]| unsafe {
190 from_utf8_unchecked(
191 b,
192 "`.` and `parse_zero_prefixable_int` filter out non-ASCII",
193 )
194 })
195 .parse(input)
196}
197
198pub(crate) fn zero_prefixable_int(input: Input<'_>) -> IResult<Input<'_>, &str, ParserError<'_>> {
200 (
201 digit,
202 many0_count(alt((
203 digit.value(()),
204 (
205 one_of(b'_'),
206 cut(digit).context(Context::Expected(ParserValue::Description("digit"))),
207 )
208 .value(()),
209 ))),
210 )
211 .recognize()
212 .map(|b: &[u8]| unsafe { from_utf8_unchecked(b, "`digit` and `_` filter out non-ASCII") })
213 .parse(input)
214}
215
216pub(crate) fn exp(input: Input<'_>) -> IResult<Input<'_>, &str, ParserError<'_>> {
219 (
220 one_of((b'e', b'E')),
221 opt(one_of([b'+', b'-'])),
222 cut(zero_prefixable_int),
223 )
224 .recognize()
225 .map(|b: &[u8]| unsafe {
226 from_utf8_unchecked(
227 b,
228 "`one_of` and `parse_zero_prefixable_int` filter out non-ASCII",
229 )
230 })
231 .parse(input)
232}
233
234pub(crate) fn special_float(input: Input<'_>) -> IResult<Input<'_>, f64, ParserError<'_>> {
236 (opt(one_of((b'+', b'-'))), alt((inf, nan)))
237 .map(|(s, f)| match s {
238 Some(b'+') | None => f,
239 Some(b'-') => -f,
240 _ => unreachable!("one_of should prevent this"),
241 })
242 .parse(input)
243}
244pub(crate) fn inf(input: Input<'_>) -> IResult<Input<'_>, f64, ParserError<'_>> {
246 tag(INF).value(f64::INFINITY).parse(input)
247}
248const INF: &[u8] = b"inf";
249pub(crate) fn nan(input: Input<'_>) -> IResult<Input<'_>, f64, ParserError<'_>> {
251 tag(NAN).value(f64::NAN).parse(input)
252}
253const NAN: &[u8] = b"nan";
254
255pub(crate) fn digit(input: Input<'_>) -> IResult<Input<'_>, u8, ParserError<'_>> {
257 one_of(DIGIT).parse(input)
258}
259const DIGIT: RangeInclusive<u8> = b'0'..=b'9';
260
261pub(crate) fn hexdig(input: Input<'_>) -> IResult<Input<'_>, u8, ParserError<'_>> {
263 one_of(HEXDIG).parse(input)
264}
265pub(crate) const HEXDIG: (RangeInclusive<u8>, RangeInclusive<u8>, RangeInclusive<u8>) =
266 (DIGIT, b'A'..=b'F', b'a'..=b'f');
267
268#[cfg(test)]
269mod test {
270 use super::*;
271
272 #[test]
273 fn integers() {
274 let cases = [
275 ("+99", 99),
276 ("42", 42),
277 ("0", 0),
278 ("-17", -17),
279 ("1_000", 1_000),
280 ("5_349_221", 5_349_221),
281 ("1_2_3_4_5", 1_2_3_4_5),
282 ("0xF", 15),
283 ("0o0_755", 493),
284 ("0b1_0_1", 5),
285 (&std::i64::MIN.to_string()[..], std::i64::MIN),
286 (&std::i64::MAX.to_string()[..], std::i64::MAX),
287 ];
288 for &(input, expected) in &cases {
289 dbg!(input);
290 let parsed = integer.parse(new_input(input)).finish();
291 assert_eq!(parsed, Ok(expected), "Parsing {input:?}");
292 }
293
294 let overflow = "1000000000000000000000000000000000";
295 let parsed = integer.parse(new_input(overflow)).finish();
296 assert!(parsed.is_err());
297 }
298
299 #[track_caller]
300 fn assert_float_eq(actual: f64, expected: f64) {
301 if expected.is_nan() {
302 assert!(actual.is_nan());
303 } else if expected.is_infinite() {
304 assert!(actual.is_infinite());
305 assert_eq!(expected.is_sign_positive(), actual.is_sign_positive());
306 } else {
307 dbg!(expected);
308 dbg!(actual);
309 assert!((expected - actual).abs() < std::f64::EPSILON);
310 }
311 }
312
313 #[test]
314 fn floats() {
315 let cases = [
316 ("+1.0", 1.0),
317 ("3.1419", 3.1419),
318 ("-0.01", -0.01),
319 ("5e+22", 5e+22),
320 ("1e6", 1e6),
321 ("-2E-2", -2E-2),
322 ("6.626e-34", 6.626e-34),
323 ("9_224_617.445_991_228_313", 9_224_617.445_991_227),
324 ("-1.7976931348623157e+308", std::f64::MIN),
325 ("1.7976931348623157e+308", std::f64::MAX),
326 ("nan", f64::NAN),
327 ("+nan", f64::NAN),
328 ("-nan", f64::NAN),
329 ("inf", f64::INFINITY),
330 ("+inf", f64::INFINITY),
331 ("-inf", f64::NEG_INFINITY),
332 ];
334 for &(input, expected) in &cases {
335 dbg!(input);
336 let parsed = float.parse(new_input(input)).finish().unwrap();
337 assert_float_eq(parsed, expected);
338
339 let overflow = "9e99999";
340 let parsed = float.parse(new_input(overflow)).finish();
341 assert!(parsed.is_err(), "{:?}", parsed);
342 }
343 }
344}