1use std::fmt::{Display, Formatter, Result as FmtResult};
2use std::str::FromStr;
3
4use crate::nodes::{Token, Trivia};
5
6#[derive(Clone, Debug, PartialEq)]
7pub struct DecimalNumber {
8 float: f64,
9 exponent: Option<(i64, bool)>,
10 token: Option<Token>,
11}
12
13impl Eq for DecimalNumber {}
14
15impl DecimalNumber {
16 pub fn new(value: f64) -> Self {
17 Self {
18 float: value,
19 exponent: None,
20 token: None,
21 }
22 }
23
24 pub fn with_token(mut self, token: Token) -> Self {
25 self.token = Some(token);
26 self
27 }
28
29 #[inline]
30 pub fn set_token(&mut self, token: Token) {
31 self.token = Some(token);
32 }
33
34 #[inline]
35 fn get_token(&self) -> Option<&Token> {
36 self.token.as_ref()
37 }
38
39 pub fn with_exponent(mut self, exponent: i64, is_uppercase: bool) -> Self {
40 self.exponent.replace((exponent, is_uppercase));
41 self
42 }
43
44 #[inline]
45 pub fn set_uppercase(&mut self, is_uppercase: bool) {
46 self.exponent = self.exponent.map(|(exponent, _)| (exponent, is_uppercase));
47 }
48
49 #[inline]
50 pub(crate) fn get_raw_float(&self) -> f64 {
51 self.float
52 }
53
54 #[inline]
55 pub fn is_uppercase(&self) -> Option<bool> {
56 self.exponent.map(|(_, uppercase)| uppercase)
57 }
58
59 #[inline]
60 pub fn get_exponent(&self) -> Option<i64> {
61 self.exponent.map(|(exponent, _)| exponent)
62 }
63
64 pub fn compute_value(&self) -> f64 {
65 self.float
66 }
67
68 super::impl_token_fns!(iter = [token]);
69}
70
71#[derive(Clone, Debug, PartialEq, Eq)]
72pub struct HexNumber {
73 integer: u64,
74 exponent: Option<(u32, bool)>,
75 is_x_uppercase: bool,
76 token: Option<Token>,
77}
78
79impl HexNumber {
80 pub fn new(integer: u64, is_x_uppercase: bool) -> Self {
81 Self {
82 integer,
83 exponent: None,
84 is_x_uppercase,
85 token: None,
86 }
87 }
88
89 pub fn with_token(mut self, token: Token) -> Self {
90 self.token = Some(token);
91 self
92 }
93
94 #[inline]
95 pub fn set_token(&mut self, token: Token) {
96 self.token = Some(token);
97 }
98
99 #[inline]
100 fn get_token(&self) -> Option<&Token> {
101 self.token.as_ref()
102 }
103
104 pub fn with_exponent(mut self, exponent: u32, is_uppercase: bool) -> Self {
105 self.exponent.replace((exponent, is_uppercase));
106 self
107 }
108
109 pub fn set_uppercase(&mut self, is_uppercase: bool) {
110 self.exponent = self.exponent.map(|(value, _)| (value, is_uppercase));
111 self.is_x_uppercase = is_uppercase;
112 }
113
114 #[inline]
115 pub fn is_x_uppercase(&self) -> bool {
116 self.is_x_uppercase
117 }
118
119 #[inline]
120 pub fn is_exponent_uppercase(&self) -> Option<bool> {
121 self.exponent.map(|(_, uppercase)| uppercase)
122 }
123
124 #[inline]
125 pub fn get_raw_integer(&self) -> u64 {
126 self.integer
127 }
128
129 #[inline]
130 pub fn get_exponent(&self) -> Option<u32> {
131 self.exponent.map(|(value, _)| value)
132 }
133
134 pub fn compute_value(&self) -> f64 {
135 if let Some((exponent, _)) = self.exponent {
136 (self.integer * 2_u64.pow(exponent)) as f64
137 } else {
138 self.integer as f64
139 }
140 }
141
142 super::impl_token_fns!(iter = [token]);
143}
144
145#[derive(Clone, Debug, PartialEq, Eq)]
146pub struct BinaryNumber {
147 value: u64,
148 is_b_uppercase: bool,
149 token: Option<Token>,
150}
151
152impl BinaryNumber {
153 pub fn new(value: u64, is_b_uppercase: bool) -> Self {
154 Self {
155 value,
156 is_b_uppercase,
157 token: None,
158 }
159 }
160
161 pub fn with_token(mut self, token: Token) -> Self {
162 self.token = Some(token);
163 self
164 }
165
166 #[inline]
167 pub fn set_token(&mut self, token: Token) {
168 self.token = Some(token);
169 }
170
171 #[inline]
172 fn get_token(&self) -> Option<&Token> {
173 self.token.as_ref()
174 }
175
176 pub fn set_uppercase(&mut self, is_uppercase: bool) {
177 self.is_b_uppercase = is_uppercase;
178 }
179
180 #[inline]
181 pub fn is_b_uppercase(&self) -> bool {
182 self.is_b_uppercase
183 }
184
185 pub fn compute_value(&self) -> f64 {
186 self.value as f64
187 }
188
189 #[inline]
190 pub fn get_raw_value(&self) -> u64 {
191 self.value
192 }
193
194 super::impl_token_fns!(iter = [token]);
195}
196
197#[derive(Clone, Debug, PartialEq, Eq)]
198pub enum NumberExpression {
199 Decimal(DecimalNumber),
200 Hex(HexNumber),
201 Binary(BinaryNumber),
202}
203
204impl NumberExpression {
205 pub fn set_uppercase(&mut self, is_uppercase: bool) {
206 match self {
207 Self::Decimal(number) => number.set_uppercase(is_uppercase),
208 Self::Hex(number) => number.set_uppercase(is_uppercase),
209 Self::Binary(number) => number.set_uppercase(is_uppercase),
210 }
211 }
212
213 pub fn compute_value(&self) -> f64 {
214 match self {
215 Self::Decimal(decimal) => decimal.compute_value(),
216 Self::Hex(hex) => hex.compute_value(),
217 Self::Binary(binary) => binary.compute_value(),
218 }
219 }
220
221 pub fn with_token(mut self, token: Token) -> Self {
222 match &mut self {
223 NumberExpression::Decimal(number) => number.set_token(token),
224 NumberExpression::Hex(number) => number.set_token(token),
225 NumberExpression::Binary(number) => number.set_token(token),
226 }
227 self
228 }
229
230 #[inline]
231 pub fn set_token(&mut self, token: Token) {
232 match self {
233 NumberExpression::Decimal(number) => number.set_token(token),
234 NumberExpression::Hex(number) => number.set_token(token),
235 NumberExpression::Binary(number) => number.set_token(token),
236 }
237 }
238
239 #[inline]
240 pub fn get_token(&self) -> Option<&Token> {
241 match self {
242 NumberExpression::Decimal(number) => number.get_token(),
243 NumberExpression::Hex(number) => number.get_token(),
244 NumberExpression::Binary(number) => number.get_token(),
245 }
246 }
247
248 pub fn clear_comments(&mut self) {
249 match self {
250 NumberExpression::Decimal(number) => number.clear_comments(),
251 NumberExpression::Hex(number) => number.clear_comments(),
252 NumberExpression::Binary(number) => number.clear_comments(),
253 }
254 }
255
256 pub fn clear_whitespaces(&mut self) {
257 match self {
258 NumberExpression::Decimal(number) => number.clear_whitespaces(),
259 NumberExpression::Hex(number) => number.clear_whitespaces(),
260 NumberExpression::Binary(number) => number.clear_whitespaces(),
261 }
262 }
263
264 pub(crate) fn replace_referenced_tokens(&mut self, code: &str) {
265 match self {
266 NumberExpression::Decimal(number) => number.replace_referenced_tokens(code),
267 NumberExpression::Hex(number) => number.replace_referenced_tokens(code),
268 NumberExpression::Binary(number) => number.replace_referenced_tokens(code),
269 }
270 }
271
272 pub(crate) fn shift_token_line(&mut self, amount: isize) {
273 match self {
274 NumberExpression::Decimal(number) => number.shift_token_line(amount),
275 NumberExpression::Hex(number) => number.shift_token_line(amount),
276 NumberExpression::Binary(number) => number.shift_token_line(amount),
277 }
278 }
279
280 pub(crate) fn filter_comments(&mut self, filter: impl Fn(&Trivia) -> bool) {
281 match self {
282 NumberExpression::Decimal(number) => number.filter_comments(filter),
283 NumberExpression::Hex(number) => number.filter_comments(filter),
284 NumberExpression::Binary(number) => number.filter_comments(filter),
285 }
286 }
287}
288
289impl From<DecimalNumber> for NumberExpression {
290 fn from(number: DecimalNumber) -> Self {
291 Self::Decimal(number)
292 }
293}
294
295impl From<HexNumber> for NumberExpression {
296 fn from(number: HexNumber) -> Self {
297 Self::Hex(number)
298 }
299}
300
301impl From<BinaryNumber> for NumberExpression {
302 fn from(number: BinaryNumber) -> Self {
303 Self::Binary(number)
304 }
305}
306
307#[derive(Debug, Clone, PartialEq, Eq)]
308pub enum NumberParsingError {
309 InvalidHexadecimalNumber,
310 InvalidHexadecimalExponent,
311 InvalidDecimalNumber,
312 InvalidDecimalExponent,
313 InvalidBinaryNumber,
314}
315
316impl Display for NumberParsingError {
317 fn fmt(&self, f: &mut Formatter<'_>) -> FmtResult {
318 use NumberParsingError::*;
319
320 match self {
321 InvalidHexadecimalNumber => write!(f, "could not parse hexadecimal number"),
322 InvalidHexadecimalExponent => write!(f, "could not parse hexadecimal exponent"),
323 InvalidDecimalNumber => write!(f, "could not parse decimal number"),
324 InvalidDecimalExponent => write!(f, "could not parse decimal exponent"),
325 InvalidBinaryNumber => write!(f, "could not parse binary number"),
326 }
327 }
328}
329
330fn filter_underscore(number: &str) -> String {
331 number.chars().filter(|c| c != &'_').collect()
332}
333
334impl FromStr for NumberExpression {
335 type Err = NumberParsingError;
336
337 fn from_str(value: &str) -> Result<Self, Self::Err> {
338 let notation_prefix = value
339 .char_indices()
340 .filter(|(_, c)| *c != '_')
341 .take(2)
342 .nth(1);
343 let starts_with_zero = value.starts_with('0');
344
345 let number = match (starts_with_zero, notation_prefix) {
346 (true, Some((position, notation))) if matches!(notation, 'x' | 'X' | 'b' | 'B') => {
347 let is_uppercase = notation.is_uppercase();
348
349 if notation == 'x' || notation == 'X' {
350 if let Some((exponent_is_uppercase, index)) = value
351 .find('p')
352 .map(|index| (false, index))
353 .or_else(|| value.find('P').map(|index| (true, index)))
354 {
355 let exponent = value
356 .get(index + 1..)
357 .and_then(|string| string.parse().ok())
358 .ok_or(Self::Err::InvalidHexadecimalExponent)?;
359 let before_exponent = value.get(position + 1..index).unwrap();
360 let number = u64::from_str_radix(before_exponent, 16)
361 .map_err(|_| Self::Err::InvalidHexadecimalNumber)?;
362
363 HexNumber::new(number, is_uppercase)
364 .with_exponent(exponent, exponent_is_uppercase)
365 } else {
366 let filtered = filter_underscore(value.get(position + 1..).unwrap());
367 let number = u64::from_str_radix(&filtered, 16)
368 .map_err(|_| Self::Err::InvalidHexadecimalNumber)?;
369
370 HexNumber::new(number, is_uppercase)
371 }
372 .into()
373 } else if notation == 'b' || notation == 'B' {
374 let filtered = filter_underscore(value.get(position + 1..).unwrap());
375 let number = u64::from_str_radix(&filtered, 2)
376 .map_err(|_| Self::Err::InvalidBinaryNumber)?;
377
378 BinaryNumber::new(number, is_uppercase).into()
379 } else {
380 unreachable!()
381 }
382 }
383 _ => {
384 if value.starts_with("._") {
387 return Err(Self::Err::InvalidDecimalNumber);
388 }
389
390 if let Some((exponent_is_uppercase, index)) = value
391 .find('e')
392 .map(|index| (false, index))
393 .or_else(|| value.find('E').map(|index| (true, index)))
394 {
395 if value.contains("_-") || value.contains("_+") {
397 return Err(Self::Err::InvalidDecimalExponent);
398 }
399
400 let exponent = value
401 .get(index + 1..)
402 .map(filter_underscore)
403 .and_then(|string| string.parse().ok())
404 .ok_or(Self::Err::InvalidDecimalExponent)?;
405 let _number: f64 = value
406 .get(0..index)
407 .map(filter_underscore)
408 .and_then(|string| string.parse().ok())
409 .ok_or(Self::Err::InvalidDecimalNumber)?;
410
411 DecimalNumber::new(
412 filter_underscore(value)
413 .parse::<f64>()
414 .map_err(|_| Self::Err::InvalidDecimalNumber)?,
415 )
416 .with_exponent(exponent, exponent_is_uppercase)
417 } else {
418 let number = filter_underscore(value)
419 .parse::<f64>()
420 .map_err(|_| Self::Err::InvalidDecimalNumber)?;
421
422 DecimalNumber::new(number)
423 }
424 .into()
425 }
426 };
427
428 Ok(number)
429 }
430}
431
432#[cfg(test)]
433mod test {
434 use super::*;
435
436 mod decimal {
437 use super::*;
438
439 #[test]
440 fn can_set_uppercase_to_number_without_exponent() {
441 let mut number = DecimalNumber::new(1.0);
442 number.set_uppercase(true);
443 number.set_uppercase(false);
444
445 assert_eq!(number.is_uppercase(), None);
446 }
447
448 #[test]
449 fn set_uppercase_change() {
450 let initial_case = true;
451 let modified_case = !initial_case;
452 let mut number = DecimalNumber::new(1.0).with_exponent(2, initial_case);
453
454 number.set_uppercase(modified_case);
455
456 assert_eq!(number.is_uppercase(), Some(modified_case));
457 }
458 }
459
460 mod hex {
461 use super::*;
462
463 #[test]
464 fn set_uppercase_change() {
465 let initial_case = true;
466 let modified_case = !initial_case;
467 let mut number = HexNumber::new(1, initial_case);
468
469 number.set_uppercase(modified_case);
470
471 assert_eq!(number.is_x_uppercase(), modified_case);
472 }
473 }
474
475 mod binary {
476 use super::*;
477
478 #[test]
479 fn set_uppercase_change() {
480 let initial_case = true;
481 let modified_case = !initial_case;
482 let mut number = BinaryNumber::new(1, initial_case);
483
484 number.set_uppercase(modified_case);
485
486 assert_eq!(number.is_b_uppercase(), modified_case);
487 }
488 }
489
490 mod parse_number {
491 use super::*;
492
493 macro_rules! test_numbers {
494 ($($name:ident($input:literal) => $expect:expr),+ $(,)?) => {
495 $(
496 #[test]
497 fn $name() {
498 let result: NumberExpression = $input.parse()
499 .expect("should be a valid number");
500
501 let expect: NumberExpression = $expect.into();
502
503 assert_eq!(result, expect);
504 }
505 )+
506 };
507 }
508
509 macro_rules! test_parse_errors {
510 ($($name:ident($input:literal) => $expect:expr),+ $(,)?) => {
511 $(
512 #[test]
513 fn $name() {
514 let result = $input.parse::<NumberExpression>()
515 .expect_err("should be an invalid number");
516
517 assert_eq!(result, $expect);
518 }
519 )+
520 };
521 }
522
523 test_numbers!(
524 parse_zero("0") => DecimalNumber::new(0_f64),
525 parse_integer("123") => DecimalNumber::new(123_f64),
526 parse_integer_with_underscore_delimiter("123_456") => DecimalNumber::new(123_456_f64),
527 parse_multiple_decimal("123.24") => DecimalNumber::new(123.24_f64),
528 parse_multiple_decimal_with_underscore("123.245_6") => DecimalNumber::new(123.245_6_f64),
529 parse_multiple_decimal_with_underscore_after_point("0._24") => DecimalNumber::new(0.24_f64),
530 parse_float_with_trailing_dot("123.") => DecimalNumber::new(123_f64),
531 parse_starting_with_dot(".123") => DecimalNumber::new(0.123_f64),
532 parse_digit_with_exponent("1e10") => DecimalNumber::new(1e10_f64).with_exponent(10, false),
533 parse_digit_with_exponent_and_underscore("1e_10") => DecimalNumber::new(1e10_f64).with_exponent(10, false),
534 parse_number_with_exponent("123e101") => DecimalNumber::new(123e101_f64).with_exponent(101, false),
535 parse_number_with_exponent_and_plus_symbol("123e+121") => DecimalNumber::new(123e121_f64).with_exponent(121, false),
536 parse_number_with_negative_exponent("123e-456") => DecimalNumber::new(123e-456_f64).with_exponent(-456, false),
537 parse_number_with_upper_exponent("123E4") => DecimalNumber::new(123e4_f64).with_exponent(4, true),
538 parse_number_with_upper_negative_exponent("123E-456") => DecimalNumber::new(123e-456_f64).with_exponent(-456, true),
539 parse_float_with_exponent("10.12e8") => DecimalNumber::new(10.12e8_f64).with_exponent(8, false),
540 parse_float_with_exponent_and_underscores("10_0.12_e_8") => DecimalNumber::new(100.12e8_f64).with_exponent(8, false),
541 parse_float_with_exponent_2("4.6982573308436185e159") => DecimalNumber::new(4.6982573308436185e159_f64).with_exponent(159, false),
542 parse_trailing_dot_with_exponent("10.e8") => DecimalNumber::new(10e8_f64).with_exponent(8, false),
543 parse_hex_number("0x12") => HexNumber::new(18, false),
544 parse_hex_number_with_underscore_before_x("0_x12") => HexNumber::new(18, false),
545 parse_hex_number_with_underscores_around_x("0_x_12") => HexNumber::new(18, false),
546 parse_hex_number_with_underscore("0x12_13") => HexNumber::new(0x1213, false),
547 parse_uppercase_hex_number("0X12") => HexNumber::new(18, true),
548 parse_uppercase_hex_number_with_underscore_before_x("0_X13") => HexNumber::new(19, true),
549 parse_hex_number_with_lowercase("0x12a") => HexNumber::new(298, false),
550 parse_hex_number_with_uppercase("0x12A") => HexNumber::new(298, false),
551 parse_hex_number_with_mixed_case("0x1bF2A") => HexNumber::new(114_474, false),
552 parse_hex_with_exponent("0x12p4") => HexNumber::new(18, false).with_exponent(4, false),
553 parse_hex_with_exponent_uppercase("0xABP3") => HexNumber::new(171, false).with_exponent(3, true),
554 parse_binary_zero("0b0") => BinaryNumber::new(0, false),
555 parse_binary_zero_with_underscore_before_b("0_b1") => BinaryNumber::new(1, false),
556 parse_binary_zero_with_underscore("0b1010_1100") => BinaryNumber::new(0b1010_1100, false),
557 parse_binary_zero_uppercase("0B0") => BinaryNumber::new(0, true),
558 parse_binary_zero_uppercase_with_underscore_before_b("0_B1") => BinaryNumber::new(1, true),
559 );
560
561 test_parse_errors!(
562 parse_empty_string("") => NumberParsingError::InvalidDecimalNumber,
563 missing_exponent_value("1e") => NumberParsingError::InvalidDecimalExponent,
564 missing_exponent_value_uppercase("1E") => NumberParsingError::InvalidDecimalExponent,
565 invalid_underscore_position("._1") => NumberParsingError::InvalidDecimalNumber,
566 missing_negative_exponent_value("1e-") => NumberParsingError::InvalidDecimalExponent,
567 missing_negative_exponent_value_uppercase("1E-") => NumberParsingError::InvalidDecimalExponent,
568 invalid_underscore_before_negative_exponent("1e_-1") => NumberParsingError::InvalidDecimalExponent,
569 invalid_underscore_before_positive_exponent("1e_+1") => NumberParsingError::InvalidDecimalExponent,
570 invalid_underscore_before_negative_exponent_uppercase("1E_-1") => NumberParsingError::InvalidDecimalExponent,
571 invalid_underscore_before_positive_exponent_uppercase("1E_+1") => NumberParsingError::InvalidDecimalExponent,
572 missing_hex_exponent_value("0x1p") => NumberParsingError::InvalidHexadecimalExponent,
573 negative_hex_exponent_value("0x1p-3") => NumberParsingError::InvalidHexadecimalExponent,
574 missing_hex_exponent_value_uppercase("0x1P") => NumberParsingError::InvalidHexadecimalExponent,
575 invalid_hex_exponent_value("0x1p1Z") => NumberParsingError::InvalidHexadecimalExponent,
576 invalid_hex_exponent_value_uppercase("0x1P1Z") => NumberParsingError::InvalidHexadecimalExponent,
577 negative_hex_exponent_value_uppercase("0x1P-3") => NumberParsingError::InvalidHexadecimalExponent,
578 invalid_digit_in_binary("0b190") => NumberParsingError::InvalidBinaryNumber,
579 invalid_digit_in_binary_uppercase("0B190") => NumberParsingError::InvalidBinaryNumber,
580 );
581 }
582
583 mod compute_value {
584 use super::*;
585
586 macro_rules! test_compute_value {
587 ($($name:ident($input:literal) => $value:expr),* $(,)?) => {
588 $(
589 #[test]
590 fn $name() {
591 let number = NumberExpression::from_str($input)
592 .expect(&format!("unable to parse `{}`", $input));
593 assert!((number.compute_value() - $value as f64).abs() < f64::EPSILON);
594 }
595 )*
596 };
597 }
598
599 test_compute_value!(
600 zero("0") => 0,
601 one("1") => 1,
602 integer("123") => 123,
603 multiple_decimal("0.512") => 0.512,
604 integer_with_multiple_decimal("54.512") => 54.512,
605 digit_with_exponent("1e5") => 1e5,
606 number_with_exponent("123e4") => 123e4,
607 number_with_negative_exponent("123e-4") => 123e-4,
608 float_with_exponent("10.5e2") => 10.5e2,
609 hex_number("0x12") => 0x12,
610 hex_number_with_letter("0x12a") => 0x12a,
611 hex_with_exponent("0x12p4") => 0x120,
612 binary_zero("0b0") => 0b0,
613 binary_ten("0b1010") => 0b1010,
614 );
615 }
616}