Skip to content

Commit 0d07bc5

Browse files
committed
(errors+lexer) fix: length of tokens not kept for parser errors
1 parent aec116f commit 0d07bc5

File tree

9 files changed

+36
-74
lines changed

9 files changed

+36
-74
lines changed

src/errors/compile.rs

Lines changed: 4 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -24,8 +24,6 @@ use crate::errors::api::Location;
2424
pub struct CompileError {
2525
/// Severity of the error
2626
err_lvl: ErrorLevel,
27-
/// Length of the erroneous token or expression
28-
length: usize,
2927
/// Location of the error in the C source file
3028
location: Location,
3129
/// Error message to be displayed to the user
@@ -34,46 +32,23 @@ pub struct CompileError {
3432

3533
impl CompileError {
3634
/// Returns the owned data of a `CompileError`.
37-
pub(super) fn into_values(self) -> (Location, String, String, usize) {
38-
(
39-
self.location,
40-
self.message,
41-
self.err_lvl.to_string(),
42-
self.length,
43-
)
35+
pub(super) fn into_values(self) -> (Location, String, String) {
36+
(self.location, self.message, self.err_lvl.to_string())
4437
}
4538

4639
/// Checks if the error is of severity [`ErrorLevel::Error`].
4740
pub(crate) fn is_error(&self) -> bool {
4841
self.err_lvl == ErrorLevel::Error
4942
}
50-
51-
// Replaces length of the token or expression concerned by the `CompileError`.
52-
pub(crate) fn specify_length(&mut self, length: usize) {
53-
self.length = length;
54-
}
55-
}
56-
57-
impl From<(Location, String, ErrorLevel, usize)> for CompileError {
58-
#[inline]
59-
fn from((location, message, err_lvl, length): (Location, String, ErrorLevel, usize)) -> Self {
60-
Self {
61-
err_lvl,
62-
length,
63-
location,
64-
message,
65-
}
66-
}
6743
}
6844

6945
impl From<(Location, String, ErrorLevel)> for CompileError {
7046
#[inline]
7147
fn from((location, message, err_lvl): (Location, String, ErrorLevel)) -> Self {
7248
Self {
73-
message,
74-
length: 0,
75-
location,
7649
err_lvl,
50+
location,
51+
message,
7752
}
7853
}
7954
}

src/errors/display.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,8 @@ pub(super) fn display_errors(
1818
files_state.insert(filename.to_owned(), content.lines().collect());
1919
}
2020
for error in errors {
21-
let (location, message, err_lvl, length) = error.into_values();
22-
let (filename, line_nb, column_nb) = location.into_values();
21+
let (location, message, err_lvl) = error.into_values();
22+
let (filename, line_nb, column_nb, length) = location.into_values();
2323
let code_lines = files_state
2424
.get(&filename)
2525
.expect("Never happens: File of error doesn't exist");
@@ -30,7 +30,7 @@ pub(super) fn display_errors(
3030
res,
3131
"{filename}:{line_nb}:{column_nb}: {err_type} {err_lvl}: {message}\n{line_nb:5} | {code_line}\n{}^{}",
3232
" ".repeat(8 + column_nb - 1),
33-
"~".repeat(length)
33+
"~".repeat(length - 1)
3434
)
3535
.map_err(|_| ())?;
3636
}

src/errors/location.rs

Lines changed: 8 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
use core::fmt;
2-
31
use super::compile::{CompileError, ErrorLevel};
42

53
/// Struct to pinpoint a precise character in the C source file.
@@ -16,6 +14,7 @@ use super::compile::{CompileError, ErrorLevel};
1614
pub struct Location {
1715
col: usize,
1816
file: String,
17+
length: usize,
1918
line: usize,
2019
}
2120

@@ -44,16 +43,17 @@ impl Location {
4443
///
4544
/// If the offset is too big, the column is set to minimal (1) without any
4645
/// warnings or errors.
47-
pub(crate) fn into_past(self, offset: usize) -> Self {
46+
pub(crate) fn into_past_with_length(self, len: usize) -> Self {
4847
Self {
49-
col: self.col.checked_sub(offset).unwrap_or(1),
48+
col: self.col.checked_sub(len).unwrap_or(1),
49+
length: len,
5050
..self
5151
}
5252
}
5353

5454
/// Returns the owned data of a `Location`.
55-
pub(crate) fn into_values(self) -> (String, usize, usize) {
56-
(self.file, self.line, self.col)
55+
pub(crate) fn into_values(self) -> (String, usize, usize, usize) {
56+
(self.file, self.line, self.col, self.length)
5757
}
5858

5959
/// Creates an error by cloning the location.
@@ -83,6 +83,7 @@ impl From<&str> for Location {
8383
file: value.to_owned(),
8484
line: 1,
8585
col: 1,
86+
length: 1,
8687
}
8788
}
8889
}
@@ -94,14 +95,7 @@ impl From<String> for Location {
9495
file: value,
9596
line: 1,
9697
col: 1,
98+
length: 1,
9799
}
98100
}
99101
}
100-
101-
#[expect(clippy::min_ident_chars)]
102-
impl fmt::Display for Location {
103-
#[inline]
104-
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
105-
write!(f, "{}:{}:{}", self.file, self.line, self.col)
106-
}
107-
}

src/errors/result.rs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -36,8 +36,7 @@ impl<T> Res<T> {
3636
/// let content = "int m@in() { }";
3737
/// let res = lex_file(&content, &mut Location::from("filename.c"));
3838
/// let errors = res.get_displayed_errors(&[("filename.c".to_owned(), content)], "lexer");
39-
/// let expected =
40-
/// "filename.c:1:6: lexer error: Character '@' not supported in context of a 'identifier'.
39+
/// let expected = "filename.c:1:6: lexer error: Character '@' not supported.
4140
/// 1 | int m@in() { }
4241
/// ^
4342
/// ";

src/lexer/lex_content.rs

Lines changed: 5 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -130,23 +130,20 @@ fn lex_char(
130130
// dbg!("there", &val);
131131
}
132132
(_, state, _) if ch.is_alphanumeric() || matches!(ch, '_') => {
133-
if let Symbols(symb) = state
134-
&& symb.last() == Some('.')
133+
if let Symbols(symbol) = state
134+
&& symbol.last() == Some('.')
135135
&& ch.is_ascii_digit()
136136
{
137-
symb.clear_last();
137+
symbol.clear_last();
138138
end_current(state, lex_data, location);
139139
state.new_ident_str(format!("0.{ch}"));
140140
} else {
141141
end_current(state, lex_data, location);
142142
state.new_ident(ch);
143143
}
144144
}
145-
(_, state, _) => {
146-
lex_data.push_err(location.to_error(format!(
147-
"Character '{ch}' not supported in context of a '{}'.",
148-
state.repr(),
149-
)));
145+
(_, _, _) => {
146+
lex_data.push_err(location.to_error(format!("Character '{ch}' not supported.")));
150147
}
151148
}
152149
}

src/lexer/numbers/from_literal.rs

Lines changed: 2 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -182,11 +182,9 @@ pub fn literal_to_number(
182182
.map_or_else(|_| None, |x| Some(Number::Int(x)));
183183
};
184184

185-
let begin_location = location.to_owned().into_past(literal.len() - 1);
185+
let begin_location = location.to_owned().into_past_with_length(literal.len());
186186

187-
let mut res = literal_to_number_err(literal.value(), begin_location, lex_data.last_is_minus());
188-
res.edit_err(|err| err.specify_length(literal.len() - 1));
189-
match res {
187+
match literal_to_number_err(literal.value(), begin_location, lex_data.last_is_minus()) {
190188
ParseRes::Value(val) => Some(val),
191189
ParseRes::Err(err) => {
192190
lex_data.push_err(err);

src/lexer/numbers/parse.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -124,15 +124,6 @@ pub enum ParseRes<T> {
124124
}
125125

126126
impl<T> ParseRes<T> {
127-
/// Apply a function on the error if it exists.
128-
#[expect(clippy::min_ident_chars)]
129-
pub fn edit_err<F: Fn(&mut CompileError)>(&mut self, f: F) {
130-
match self {
131-
Self::Value(_) => (),
132-
Self::Err(err) | Self::ValueErr(_, err) => f(err),
133-
}
134-
}
135-
136127
/// Returns the values of the parse result.
137128
fn into_elts(self) -> (Option<T>, Option<CompileError>) {
138129
match self {

src/lexer/types/tokens.rs

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -69,7 +69,7 @@ impl Token {
6969
pub(crate) fn from_char(ch: char, location: &Location) -> Self {
7070
Self {
7171
value: TokenValue::Char(ch),
72-
location: location.to_owned().into_past(1),
72+
location: location.to_owned().into_past_with_length(1),
7373
}
7474
}
7575

@@ -95,13 +95,13 @@ impl Token {
9595
}
9696
})
9797
.collect::<String>();
98-
lex_data.push_err(location.to_owned().into_past(len).to_warning(format!("Underscore operators are deprecated since C23. Consider using the new keyword: {new_keyword}")));
98+
lex_data.push_err(location.to_owned().into_past_with_length(len).to_warning(format!("Underscore operators are deprecated since C23. Consider using the new keyword: {new_keyword}")));
9999
TokenValue::Keyword(keyword)
100100
}
101101
TryKeywordType::Failure => TokenValue::Identifier(value),
102102
};
103103
Self {
104-
location: location.to_owned().into_past(len),
104+
location: location.to_owned().into_past_with_length(len),
105105
value: token_value,
106106
}
107107
}
@@ -115,15 +115,15 @@ impl Token {
115115

116116
pub(crate) fn from_str(str: String, location: &Location) -> Self {
117117
Self {
118-
location: location.to_owned().into_past(str.len()),
118+
location: location.to_owned().into_past_with_length(str.len()),
119119
value: TokenValue::Str(str),
120120
}
121121
}
122122

123123
pub(crate) fn from_symbol(symbol: Symbol, size: usize, location: &Location) -> Self {
124124
Self {
125125
value: TokenValue::Symbol(symbol),
126-
location: location.to_owned().into_past(size),
126+
location: location.to_owned().into_past_with_length(size),
127127
}
128128
}
129129

tests/strings.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -180,6 +180,14 @@ macro_rules! make_string_error_tests {
180180

181181
make_string_error_tests!(
182182

183+
lengths:
184+
"x = \"blob\" bob;"
185+
=>
186+
":1:12: parser error: Found 2 consecutive literals: block [(x = \"blob\")..] followed by bob.
187+
1 | x = \"blob\" bob;
188+
^~~
189+
"
190+
183191
// digraphs:
184192
// "%:include <stdio.h>"
185193
// =>

0 commit comments

Comments
 (0)