@@ -67,23 +67,39 @@ macro_rules! parse_hexadecimal_float {
6767
6868impl_floating_point ! ( 23 , Double Float LongDouble ) ;
6969
70+ /// Trait to try and convert the integer and decimal part inside the mantissa.
71+ ///
72+ /// ``overflow`` is set to true if the value doesn't fix in the mantissa.
7073trait FloatingPoint < T > {
7174 const MANTISSA_SIZE : u32 ;
7275 type Unsigned ;
7376 fn from_unsigned ( val : T , overflow : & mut bool ) -> Self ;
7477 fn from_usize ( val : usize , overflow : & mut bool ) -> Self ;
7578}
7679
80+ /// Stores the data of an hexadecimal constant
7781#[ derive( Default , Debug ) ]
78- struct HexFloatParse {
82+ struct HexFloatData {
83+ /// Decimal part of the constant, between the '.' and the 'p'
7984 decimal_part : String ,
85+ /// Exponent part of the constant, after the 'p'
8086 exponent : String ,
87+ /// Sign if found of the exponent
88+ ///
89+ /// - If a '+' is found after the 'p', ``exponent_neg = Some(false)``;
90+ /// - If a '-' is found after the 'p', ``exponent_neg = Some(true)``;
91+ /// - If a digit is found after the 'p', ``exponent_neg = None``.
8192 exponent_neg : Option < bool > ,
93+ /// Integer part of the constant, before the '.'
8294 int_part : String ,
95+ /// State of the parsing
96+ ///
97+ /// All the fields are set to default at the beginning, and when state
98+ /// changes, the fields begin receiving data, one by one.
8399 state : HexFloatParseState ,
84100}
85101
86- impl HexFloatParse {
102+ impl HexFloatData {
87103 fn push ( & mut self , ch : char ) {
88104 match self . state {
89105 HexFloatParseState :: Int => self . int_part . push ( ch) ,
@@ -103,6 +119,10 @@ impl HexFloatParse {
103119 }
104120}
105121
122+ /// Parsing state of the hexadecimal constant
123+ ///
124+ /// The first part is the integer part, then the decimal part after a full stop,
125+ /// and a exponent part after an exponent character ('p').
106126#[ derive( Default , PartialEq , Eq , Debug ) ]
107127enum HexFloatParseState {
108128 Decimal ,
@@ -111,8 +131,45 @@ enum HexFloatParseState {
111131 Int ,
112132}
113133
114- fn get_hex_float_state ( literal : & str , location : & Location ) -> Result < HexFloatParse , CompileError > {
115- let mut float_parse = HexFloatParse :: default ( ) ;
134+ /// Parses an hexadecimal string by hand
135+ ///
136+ /// # Returns
137+ ///
138+ /// This function returns an [`HexFloatData`], that contains the different parts
139+ /// of the number: the integer part, the decimal part and the exponent part.
140+ ///
141+ /// For an hexadecimal C constant, the decimal part is prefix with the character
142+ /// '.' and the exponent is prefixed with the letter `p`.
143+ ///
144+ /// # Errors
145+ ///
146+ /// This functions returns an error if
147+ /// - multiple signs or full stops were found in the string,
148+ /// - a non decimal digit was found in the exponent part,
149+ ///
150+ /// # Examples
151+ ///
152+ /// ```ignore
153+ /// use crate::errors::location::Location;
154+ ///
155+ /// assert!(
156+ /// get_hex_float_data("fd.ep2", &Location::from(String::new()))
157+ /// == Ok(HexFloatData {
158+ /// int_part: "fd".to_owned(),
159+ /// decimal_part: "e".to_owned(),
160+ /// exponent: "2".to_owned(),
161+ /// exponent_neg: None,
162+ /// state: HexFloatParseState::Exponent
163+ /// })
164+ /// );
165+ ///
166+ /// matches!(
167+ /// get_hex_float_data("fd.ep++2", &Location::from(String::new())),
168+ /// Err(_)
169+ /// );
170+ /// ```
171+ fn get_hex_float_data ( literal : & str , location : & Location ) -> Result < HexFloatData , CompileError > {
172+ let mut float_parse = HexFloatData :: default ( ) ;
116173 for ch in literal. chars ( ) {
117174 match ch {
118175 '+' | '-' if float_parse. state != HexFloatParseState :: Exponent => {
@@ -137,7 +194,7 @@ fn get_hex_float_state(literal: &str, location: &Location) -> Result<HexFloatPar
137194 ) ) )
138195 }
139196 '.' if float_parse. state == HexFloatParseState :: Exponent => {
140- return Err ( location. to_error ( format ! ( "{ERR_PREFIX}exponent must be an integer, but found a period ." ) ) )
197+ return Err ( location. to_error ( format ! ( "{ERR_PREFIX}exponent must be an integer, but found a full stop ." ) ) )
141198 }
142199 'p' | 'P' if float_parse. state == HexFloatParseState :: Exponent => {
143200 return Err ( location. to_error ( format ! (
@@ -153,6 +210,21 @@ fn get_hex_float_state(literal: &str, location: &Location) -> Result<HexFloatPar
153210 Ok ( float_parse)
154211}
155212
213+ /// Converts a hexadecimal digit to its value.
214+ ///
215+ /// # Panics
216+ ///
217+ /// This function panics if the char is not a valid hexadecimal digits.
218+ ///
219+ /// # Examples
220+ ///
221+ /// ```ignore
222+ /// assert!(hex_char_to_int('f') == 15);
223+ /// ```
224+ ///
225+ /// ```ignore,should_panic
226+ /// hex_char_to_int('p'); // this panics
227+ /// ```
156228fn hex_char_to_int ( ch : char ) -> u8 {
157229 match ch {
158230 '0' => 0 ,
@@ -175,15 +247,56 @@ fn hex_char_to_int(ch: char) -> u8 {
175247 }
176248}
177249
250+ /// Parses a binary value.
251+ ///
252+ /// The input doesn't contain the prefix ('0x') or the suffix (e.g. 'ULL').
253+ ///
254+ /// # Returns
255+ ///
256+ /// A [`OverParseRes`]. It contains one or more of the following:
257+ ///
258+ /// - the value, if the parsing succeeded
259+ /// - errors, if there are some
260+ /// - overflow warning if a value was crapped to fit in the specified type.
261+ ///
262+ ///
263+ /// # Examples
264+ ///
265+ /// ```ignore
266+ /// use crate::errors::location::Location;
267+ /// use crate::lexer::numbers::parse::OverParseRes;
268+ /// use crate::lexer::numbers::types::{Number, NumberType};
269+ ///
270+ /// assert!(
271+ /// to_hex_value("f20", &NumberType::Int, &Location::from(String::new()))
272+ /// == OverParseRes::Value(Number::Int(3872))
273+ /// );
274+ /// assert!(
275+ /// to_hex_value("ffffffff", &NumberType::Int, &Location::from(String::new()))
276+ /// == OverParseRes::ValueOverflow(2i32.pow(31) - 1)
277+ /// );
278+ /// assert!(matches!(
279+ /// to_hex_value("1o3", &NumberType::Int, &Location::from(String::new())),
280+ /// OverParseRes::Err(_)
281+ /// ));
282+ /// ```
178283pub fn to_hex_value (
179284 literal : & str ,
180285 nb_type : & NumberType ,
181286 location : & Location ,
182287) -> OverParseRes < Number > {
183- let float_parse = match get_hex_float_state ( literal, location) {
288+ let float_data = match get_hex_float_data ( literal, location) {
184289 Err ( err) => return OverParseRes :: from ( err) ,
185290 Ok ( parsed) => parsed,
186291 } ;
292+ if float_data. exponent . is_empty ( )
293+ && ( float_data. exponent_neg . is_some ( ) || float_data. state == HexFloatParseState :: Exponent )
294+ {
295+ return OverParseRes :: from (
296+ location
297+ . to_error ( format ! ( "{ERR_PREFIX}Illegal floating point constant: found empty exponent, but at least one digit was expected." ) ) ,
298+ ) ;
299+ }
187300 if nb_type. is_int ( ) {
188301 parse_int_from_radix ! ( location,
189302 nb_type, literal, "never fails" , 16 , Int Long LongLong UInt ULong ULongLong
@@ -192,7 +305,7 @@ pub fn to_hex_value(
192305 let mut overflow = false ;
193306 #[ expect( clippy:: float_arithmetic) ]
194307 let res =
195- parse_hexadecimal_float ! ( & mut overflow, nb_type, float_parse , Float Double LongDouble ) ;
308+ parse_hexadecimal_float ! ( & mut overflow, nb_type, float_data , Float Double LongDouble ) ;
196309 if overflow {
197310 res. add_overflow ( )
198311 } else {
0 commit comments