Skip to content

Commit 6db6eb7

Browse files
committed
(lexer) add: doc
1 parent 30f6ea1 commit 6db6eb7

File tree

11 files changed

+373
-27
lines changed

11 files changed

+373
-27
lines changed

.github/workflows/rust.yml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -56,4 +56,4 @@ jobs:
5656
steps:
5757
- uses: actions/checkout@v4
5858
- name: Check doc
59-
run: cargo doc --document-private-items --all --verbose
59+
run: cargo doc --document-private-items --all --verbose --release

src/errors/result.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ type PublicRes<T> = (T, Vec<CompileError>);
99
///
1010
/// This struct is meant as a [`Result`], but with the were it is possible to
1111
/// have a value and some errors at the same time. It is for example the case
12-
/// for warnings and suggestions (see
12+
/// for warnings and suggestions (cf.
1313
/// [`CompileError`] for more information), that must be stored, and at the
1414
/// same time, the compiler continues to work.
1515
#[derive(Debug)]
@@ -43,7 +43,7 @@ impl<T> Res<T> {
4343
/// ";
4444
///
4545
/// assert!(errors == expected, "!{errors}!\n!{expected}!");
46-
/// ```
46+
/// ```
4747
///
4848
/// # Panics
4949
///

src/lexer/end_state.rs

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,10 @@ fn end_ident(literal: &mut Ident, lex_data: &mut LexingData, location: &Location
3131
let possible_number = literal_to_number(lex_data, literal, location);
3232
match possible_number {
3333
None => {
34-
let token = Token::from_identifier(lex_data, literal, location);
35-
lex_data.push_token(token);
34+
if !literal.first().unwrap_or('0').is_ascii_digit() {
35+
let token = Token::from_identifier(lex_data, literal, location);
36+
lex_data.push_token(token);
37+
}
3638
}
3739
Some(nb) => {
3840
let token = Token::from_number(nb, location);

src/lexer/numbers/base/binary.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,42 @@ use super::super::types::arch_types::*;
55
use super::super::types::{Number, NumberType, ERR_PREFIX};
66
use crate::errors::api::Location;
77

8+
/// Parses a binary value.
9+
///
10+
/// The input doesn't contain the prefix ('0b') or the suffix (e.g. 'ULL').
11+
///
12+
/// # Returns
13+
///
14+
/// A [`OverParseRes`]. It contains one or more of the following:
15+
///
16+
/// - the value, if the parsing succeeded
17+
/// - errors, if there are some
18+
/// - overflow warning if a value was crapped to fit in the specified type.
19+
///
20+
///
21+
/// # Examples
22+
///
23+
/// ```ignore
24+
/// use crate::errors::location::Location;
25+
/// use crate::lexer::numbers::parse::OverParseRes;
26+
/// use crate::lexer::numbers::types::{Number, NumberType};
27+
///
28+
/// assert!(
29+
/// to_bin_value("1010", &NumberType::Int, &Location::from(String::new()))
30+
/// == OverParseRes::Value(Number::Int(10))
31+
/// );
32+
/// assert!(
33+
/// to_bin_value(
34+
/// "11111111111111111111111111111111",
35+
/// &NumberType::Int,
36+
/// &Location::from(String::new())
37+
/// ) == OverParseRes::ValueOverflow(2i32.pow(31) - 1)
38+
/// );
39+
/// assert!(matches!(
40+
/// to_bin_value("123", &NumberType::Int, &Location::from(String::new())),
41+
/// OverParseRes::Err(_)
42+
/// ));
43+
/// ```
844
pub fn to_bin_value(
945
literal: &str,
1046
nb_type: &NumberType,

src/lexer/numbers/base/decimal.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,42 @@ where
2727
.map_err(|_err| location.to_error(format!("{ERR_PREFIX}invalid decimal float number.")))
2828
}
2929

30+
/// Parses a binary value.
31+
///
32+
/// The input doesn't contain the suffix (e.g. 'ULL').
33+
///
34+
/// # Returns
35+
///
36+
/// A [`OverParseRes`]. It contains one or more of the following:
37+
///
38+
/// - the value, if the parsing succeeded
39+
/// - errors, if there are some
40+
/// - overflow warning if a value was crapped to fit in the specified type.
41+
///
42+
///
43+
/// # Examples
44+
///
45+
/// ```ignore
46+
/// use crate::errors::location::Location;
47+
/// use crate::lexer::numbers::parse::OverParseRes;
48+
/// use crate::lexer::numbers::types::{Number, NumberType};
49+
///
50+
/// assert!(
51+
/// to_decimal_value("123", &NumberType::Int, &Location::from(String::new()))
52+
/// == OverParseRes::Value(Number::Int(123))
53+
/// );
54+
/// assert!(
55+
/// to_decimal_value(
56+
/// "1e33",
57+
/// &NumberType::Int,
58+
/// &Location::from(String::new())
59+
/// ) == OverParseRes::ValueOverflow(2i32.pow(31) - 1)
60+
/// );
61+
/// assert!(matches!(
62+
/// to_decimal_value("1fe3", &NumberType::Int, &Location::from(String::new())),
63+
/// OverParseRes::Err(_)
64+
/// ));
65+
/// ```
3066
pub fn to_decimal_value(
3167
literal: &str,
3268
nb_type: &NumberType,

src/lexer/numbers/base/hexadecimal.rs

Lines changed: 120 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -67,23 +67,39 @@ macro_rules! parse_hexadecimal_float {
6767

6868
impl_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.
7073
trait 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)]
107127
enum 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+
/// ```
156228
fn 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+
/// ```
178283
pub 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 {

src/lexer/numbers/base/octal.rs

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,42 @@ use super::super::types::arch_types::*;
55
use super::super::types::{Number, NumberType, ERR_PREFIX};
66
use crate::errors::api::Location;
77

8+
/// Parses an octal value.
9+
///
10+
/// The input doesn't contain the prefix ('0') or the suffix (e.g. 'ULL').
11+
///
12+
/// # Returns
13+
///
14+
/// A [`OverParseRes`]. It contains one or more of the following:
15+
///
16+
/// - the value, if the parsing succeeded
17+
/// - errors, if there are some
18+
/// - overflow warning if a value was crapped to fit in the specified type.
19+
///
20+
///
21+
/// # Examples
22+
///
23+
/// ```ignore
24+
/// use crate::errors::location::Location;
25+
/// use crate::lexer::numbers::parse::OverParseRes;
26+
/// use crate::lexer::numbers::types::{Number, NumberType};
27+
///
28+
/// assert!(
29+
/// to_oct_value("123", &NumberType::Int, &Location::from(String::new()))
30+
/// == OverParseRes::Value(Number::Int(83))
31+
/// );
32+
/// assert!(
33+
/// to_oct_value(
34+
/// "377",
35+
/// &NumberType::Int,
36+
/// &Location::from(String::new())
37+
/// ) == OverParseRes::ValueOverflow(2i32.pow(31) - 1)
38+
/// );
39+
/// assert!(matches!(
40+
/// to_oct_value("1f3", &NumberType::Int, &Location::from(String::new())),
41+
/// OverParseRes::Err(_)
42+
/// ));
43+
/// ```
844
pub fn to_oct_value(
945
literal: &str,
1046
nb_type: &NumberType,

0 commit comments

Comments
 (0)