mxmlextrema_as3parser/tree/
numeric_literal.rs

1use crate::ns::*;
2use num_bigint::BigInt;
3use serde::{Serialize, Deserialize};
4use std::str::FromStr;
5use conv::ValueFrom;
6use num_traits::ToPrimitive;
7
8#[derive(Debug, Clone, Serialize, Deserialize)]
9pub struct NumericLiteral {
10    pub location: Location,
11    /// The numeric value in character representation. Such representation may be parsed
12    /// through data type specific methods such as [`NumericLiteral::parse_double()`].
13    pub value: String,
14    pub suffix: NumberSuffix,
15}
16
17#[derive(Debug, Copy, Clone, Serialize, Deserialize, PartialEq)]
18pub enum NumberSuffix {
19    None,
20    F,
21}
22
23impl NumericLiteral {
24    /// Parses a double-precision floating point either in
25    /// decimal, binary (`0b`) or hexadecimal (`0x`) notation.
26    pub fn parse_double(&self, negative: bool) -> Result<f64, ParserError> {
27        let s = self.value.replace('_', "");
28        if s.starts_with('0') {
29            if s[1..].starts_with('x') || s[1..].starts_with('X') {
30                let n = u64::from_str_radix(&(if negative { "-" } else { "" }.to_owned() + &s[2..]), 16);
31                return n.map_err(|_| ParserError::Common)
32                    .and_then(|n| f64::value_from(n).map_err(|_| ParserError::Common));
33            } else if s[1..].starts_with('b') || s[1..].starts_with('B') {
34                let n = u64::from_str_radix(&(if negative { "-" } else { "" }.to_owned() + &s[2..]), 2);
35                return n.map_err(|_| ParserError::Common)
36                    .and_then(|n| f64::value_from(n).map_err(|_| ParserError::Common));
37            }
38        }
39        f64::from_str(&(if negative { "-" } else { "" }.to_owned() + &s)).map_err(|_| ParserError::Common)
40    }
41
42    /// Parses a single-precision floating point either in
43    /// decimal, binary (`0b`) or hexadecimal (`0x`) notation.
44    pub fn parse_float(&self, negative: bool) -> Result<f32, ParserError> {
45        let s = self.value.replace('_', "");
46        if s.starts_with('0') {
47            if s[1..].starts_with('x') || s[1..].starts_with('X') {
48                let n = u64::from_str_radix(&(if negative { "-" } else { "" }.to_owned() + &s[2..]), 16);
49                return n.map_err(|_| ParserError::Common)
50                    .and_then(|n| f32::value_from(n).map_err(|_| ParserError::Common));
51            } else if s[1..].starts_with('b') || s[1..].starts_with('B') {
52                let n = u64::from_str_radix(&(if negative { "-" } else { "" }.to_owned() + &s[2..]), 2);
53                return n.map_err(|_| ParserError::Common)
54                    .and_then(|n| f32::value_from(n).map_err(|_| ParserError::Common));
55            }
56        }
57        f32::from_str(&(if negative { "-" } else { "" }.to_owned() + &s)).map_err(|_| ParserError::Common)
58    }
59
60    /// Parses a signed long either in
61    /// decimal, binary (`0b`) or hexadecimal (`0x`) notation.
62    pub fn parse_long(&self, negative: bool) -> Result<i64, ParserError> {
63        let s = self.value.replace('_', "");
64        if s.starts_with('0') {
65            if s[1..].starts_with('x') || s[1..].starts_with('X') {
66                let n = i64::from_str_radix(&(if negative { "-" } else { "" }.to_owned() + &s[2..]), 16);
67                return n.map_err(|_| ParserError::Common);
68            } else if s[1..].starts_with('b') || s[1..].starts_with('B') {
69                let n = i64::from_str_radix(&(if negative { "-" } else { "" }.to_owned() + &s[2..]), 2);
70                return n.map_err(|_| ParserError::Common);
71            }
72        }
73        i64::from_str(&s).map_err(|_| ParserError::Common)
74    }
75
76    /// Parses a signed integer either in
77    /// decimal, binary (`0b`) or hexadecimal (`0x`) notation.
78    pub fn parse_int(&self, negative: bool) -> Result<i32, ParserError> {
79        let s = self.value.replace('_', "");
80        if s.starts_with('0') {
81            if s[1..].starts_with('x') || s[1..].starts_with('X') {
82                let n = i32::from_str_radix(&(if negative { "-" } else { "" }.to_owned() + &s[2..]), 16);
83                return n.map_err(|_| ParserError::Common);
84            } else if s[1..].starts_with('b') || s[1..].starts_with('B') {
85                let n = i32::from_str_radix(&(if negative { "-" } else { "" }.to_owned() + &s[2..]), 2);
86                return n.map_err(|_| ParserError::Common);
87            }
88        }
89        i32::from_str(&s).map_err(|_| ParserError::Common)
90    }
91
92    /// Parses an unsigned integer either in
93    /// decimal, binary (`0b`) or hexadecimal (`0x`) notation.
94    pub fn parse_uint(&self) -> Result<u32, ParserError> {
95        let s = self.value.replace('_', "");
96        if s.starts_with('0') {
97            if s[1..].starts_with('x') || s[1..].starts_with('X') {
98                let n = u32::from_str_radix(&s[2..], 16);
99                return n.map_err(|_| ParserError::Common);
100            } else if s[1..].starts_with('b') || s[1..].starts_with('B') {
101                let n = u32::from_str_radix(&s[2..], 2);
102                return n.map_err(|_| ParserError::Common);
103            }
104        }
105        u32::from_str(&s).map_err(|_| ParserError::Common)
106    }
107
108    /// Parses a big integer either in
109    /// decimal, binary (`0b`) or hexadecimal (`0x`) notation.
110    pub fn parse_big_int(&self, negative: bool) -> Result<BigInt, ParserError> {
111        let s = self.value.replace('_', "");
112        if s.starts_with('0') {
113            if s[1..].starts_with('x') || s[1..].starts_with('X') {
114                let mut digits: Vec<u8> = vec![];
115                for ch in s[2..].chars() {
116                    digits.push(CharacterValidator::hex_digit_mv(ch).unwrap().to_u8().unwrap());
117                }
118                let n = BigInt::from_radix_be(if negative { num_bigint::Sign::Minus } else { num_bigint::Sign::Plus }, &digits, 16);
119                return n.map_or(Err(ParserError::Common), |n| Ok(n));
120            } else if s[1..].starts_with('b') || s[1..].starts_with('B') {
121                let mut digits: Vec<u8> = vec![];
122                for ch in s[2..].chars() {
123                    digits.push(CharacterValidator::bin_digit_mv(ch).unwrap().to_u8().unwrap());
124                }
125                let n = BigInt::from_radix_be(if negative { num_bigint::Sign::Minus } else { num_bigint::Sign::Plus }, &digits, 2);
126                return n.map_or(Err(ParserError::Common), |n| Ok(n));
127            }
128        }
129        BigInt::from_str(&s).map_err(|_| ParserError::Common)
130    }
131}
132
133mod tests {
134    #[allow(unused)]
135    use crate::ns::*;
136    #[allow(unused)]
137    use std::rc::Rc;
138
139    #[test]
140    fn test_minimum_maximum() {
141        // Long.MIN_VALUE
142        let literal = NumericLiteral {
143            location: Location::with_offset(&Rc::new(CompilationUnit::default()), 0),
144            value: "0x8000_0000_0000_0000".to_owned(),
145            suffix: NumberSuffix::None,
146        };
147        assert_eq!(i64::MIN, literal.parse_long(true).unwrap());
148
149        // Long.MAX_VALUE
150        let literal = NumericLiteral {
151            location: Location::with_offset(&Rc::new(CompilationUnit::default()), 0),
152            value: "0x7FFF_FFFF_FFFF_FFFF".to_owned(),
153            suffix: NumberSuffix::None,
154        };
155        assert_eq!(i64::MAX, literal.parse_long(false).unwrap());
156    }
157}