Use true source for error formatting

This commit is contained in:
Sofia 2025-07-17 19:34:54 +03:00
parent df4febf1ef
commit 6dfd98eba3
4 changed files with 123 additions and 126 deletions

73
Cargo.lock generated
View File

@ -4,18 +4,21 @@ version = 4
[[package]] [[package]]
name = "aho-corasick" name = "aho-corasick"
version = "1.0.2" version = "1.1.3"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
dependencies = [ dependencies = [
"memchr", "memchr",
] ]
[[package]] [[package]]
name = "cc" name = "cc"
version = "1.0.79" version = "1.2.29"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362"
dependencies = [
"shlex",
]
[[package]] [[package]]
name = "colored" name = "colored"
@ -28,21 +31,21 @@ dependencies = [
[[package]] [[package]]
name = "lazy_static" name = "lazy_static"
version = "1.4.0" version = "1.5.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.147" version = "0.2.174"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776"
[[package]] [[package]]
name = "llvm-sys" name = "llvm-sys"
version = "160.1.3" version = "160.2.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0bf51981ac0622b10fe4790763e3de1f3d68a0ee4222e03accaaab6731bd508d" checksum = "e73861901245d32e1c3d8b35b639cf100859b4cd0c9da56fe0273040acbb3ea4"
dependencies = [ dependencies = [
"cc", "cc",
"lazy_static", "lazy_static",
@ -53,33 +56,33 @@ dependencies = [
[[package]] [[package]]
name = "memchr" name = "memchr"
version = "2.5.0" version = "2.7.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0"
[[package]] [[package]]
name = "proc-macro2" name = "proc-macro2"
version = "1.0.66" version = "1.0.95"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778"
dependencies = [ dependencies = [
"unicode-ident", "unicode-ident",
] ]
[[package]] [[package]]
name = "quote" name = "quote"
version = "1.0.32" version = "1.0.40"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
] ]
[[package]] [[package]]
name = "regex" name = "regex"
version = "1.9.1" version = "1.11.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@ -89,9 +92,9 @@ dependencies = [
[[package]] [[package]]
name = "regex-automata" name = "regex-automata"
version = "0.3.4" version = "0.4.9"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b7b6d6190b7594385f61bd3911cd1be99dfddcfc365a4160cc2ab5bff4aed294" checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
dependencies = [ dependencies = [
"aho-corasick", "aho-corasick",
"memchr", "memchr",
@ -100,9 +103,9 @@ dependencies = [
[[package]] [[package]]
name = "regex-syntax" name = "regex-syntax"
version = "0.7.4" version = "0.8.5"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
[[package]] [[package]]
name = "reid" name = "reid"
@ -124,15 +127,21 @@ dependencies = [
[[package]] [[package]]
name = "semver" name = "semver"
version = "1.0.18" version = "1.0.26"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b0293b4b29daaf487284529cc2f5675b8e57c61f70167ba415a463651fd6a918" checksum = "56e6fa9c48d24d85fb3de5ad847117517440f6beceb7798af16b4a87d616b8d0"
[[package]]
name = "shlex"
version = "1.3.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0fda2ff0d084019ba4d7c6f371c95d8fd75ce3524c3cb8fb653a3023f6323e64"
[[package]] [[package]]
name = "syn" name = "syn"
version = "2.0.28" version = "2.0.104"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -141,18 +150,18 @@ dependencies = [
[[package]] [[package]]
name = "thiserror" name = "thiserror"
version = "1.0.44" version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52"
dependencies = [ dependencies = [
"thiserror-impl", "thiserror-impl",
] ]
[[package]] [[package]]
name = "thiserror-impl" name = "thiserror-impl"
version = "1.0.44" version = "1.0.69"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -161,9 +170,9 @@ dependencies = [
[[package]] [[package]]
name = "unicode-ident" name = "unicode-ident"
version = "1.0.11" version = "1.0.18"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512"
[[package]] [[package]]
name = "windows-sys" name = "windows-sys"

View File

@ -5,7 +5,7 @@ use std::{
use crate::{ use crate::{
ast, ast,
lexer::{self, FullToken, Position}, lexer::{self, Cursor, FullToken, Position},
mir::{self, pass, Metadata, SourceModuleId}, mir::{self, pass, Metadata, SourceModuleId},
token_stream::{self, TokenRange}, token_stream::{self, TokenRange},
}; };
@ -79,6 +79,7 @@ impl Ord for ErrorKind {
pub struct ErrModule { pub struct ErrModule {
pub name: String, pub name: String,
pub tokens: Option<Vec<FullToken>>, pub tokens: Option<Vec<FullToken>>,
pub source: Option<String>,
} }
#[derive(Debug, Clone, PartialEq, Eq, Default)] #[derive(Debug, Clone, PartialEq, Eq, Default)]
@ -95,6 +96,7 @@ impl ModuleMap {
ErrModule { ErrModule {
name: name.into(), name: name.into(),
tokens: None, tokens: None,
source: None,
}, },
); );
Some(id) Some(id)
@ -106,6 +108,12 @@ impl ModuleMap {
} }
} }
pub fn set_source(&mut self, id: mir::SourceModuleId, source: String) {
if let Some(module) = self.module_map.get_mut(&id) {
module.source = Some(source);
}
}
pub fn get_module(&self, id: &mir::SourceModuleId) -> Option<&ErrModule> { pub fn get_module(&self, id: &mir::SourceModuleId) -> Option<&ErrModule> {
self.module_map.get(id) self.module_map.get(id)
} }
@ -179,11 +187,17 @@ impl std::fmt::Display for ReidError {
let module = self.map.get_module(&meta.source_module_id).unwrap(); let module = self.map.get_module(&meta.source_module_id).unwrap();
let (position_fmt, line_fmt) = if let Some(tokens) = &module.tokens { let (position_fmt, line_fmt) = if let Some(tokens) = &module.tokens {
let range_tokens = meta.range.into_tokens(&tokens); let range_tokens = meta.range.into_tokens(&tokens);
let position = get_position(&range_tokens).unwrap(); let highlight_position = get_position(&range_tokens).unwrap();
let full_lines = get_full_lines(&tokens, position); let full_lines = get_full_lines(&tokens, highlight_position);
let lines_position = get_position(&full_lines).unwrap();
( (
fmt_positions(get_position(&full_lines).unwrap()), fmt_positions(highlight_position),
Some(fmt_tokens(&full_lines, &range_tokens)), Some(fmt_lines(
module.source.as_ref().unwrap(),
lines_position,
highlight_position,
8,
)?),
) )
} else if let Some(position) = meta.position { } else if let Some(position) = meta.position {
(fmt_positions((position, position)), None) (fmt_positions((position, position)), None)
@ -209,9 +223,9 @@ impl std::fmt::Display for ReidError {
writeln!(f)?; writeln!(f)?;
write!(f, " Error: ")?; write!(f, " Error: ")?;
writeln!(f, "{}", color_err(format!("{}", error))?)?; writeln!(f, "{}", color_err(format!("{}", error))?)?;
writeln!(f, "{:>20}{}", color_warn("At: ")?, position_fmt)?; write!(f, "{:>20}{}", color_warn("At: ")?, position_fmt)?;
if let Some(line_fmt) = line_fmt { if let Some(line_fmt) = line_fmt {
writeln!(f, "{:>20}{}", color_warn("")?, line_fmt)?; writeln!(f, "{}", line_fmt)?;
} }
} }
Ok(()) Ok(())
@ -255,26 +269,37 @@ fn get_full_lines<'v>(
.collect::<Vec<_>>() .collect::<Vec<_>>()
} }
fn fmt_tokens(tokens: &Vec<&FullToken>, highlighted: &Vec<&FullToken>) -> String { fn fmt_lines(
source: &String,
(line_start, line_end): (Position, Position),
(highlight_start, highlight_end): (Position, Position),
ident: usize,
) -> Result<String, std::fmt::Error> {
let mut cursor = Cursor {
position: Position(0, 1),
char_stream: source.chars(),
};
let mut text = String::new(); let mut text = String::new();
let mut last_likes_space = false;
for (i, token) in tokens.iter().enumerate() {
if token.token.needs_space() || (token.token.likes_space() && last_likes_space) {
text += " ";
}
last_likes_space = token.token.likes_space();
let mut token_fmt = format!("{}", token.token.to_string()); while let Some(c) = cursor.next() {
if highlighted.contains(token) { if cursor.position.1 > line_end.1 {
token_fmt = color_underline(token_fmt).unwrap(); break;
}
if cursor.position.1 >= line_start.1 {
if c == '\n' {
write!(text, "\n{}", " ".repeat(ident))?;
} else {
if cursor.position > highlight_start && cursor.position <= highlight_end {
write!(text, "{}", color_highlight(c)?)?;
} else {
text.write_char(c)?;
}
} }
text += &token_fmt;
if token.token.is_newline() && i > (tokens.len() - 1) {
text += "\n"
} }
} }
text Ok(text)
} }
fn fmt_positions((start, end): (Position, Position)) -> String { fn fmt_positions((start, end): (Position, Position)) -> String {
@ -287,54 +312,6 @@ fn fmt_positions((start, end): (Position, Position)) -> String {
} }
} }
impl lexer::Token {
fn likes_space(&self) -> bool {
match self {
lexer::Token::Identifier(_) => true,
lexer::Token::DecimalValue(_) => true,
lexer::Token::StringLit(_) => true,
lexer::Token::LetKeyword => true,
lexer::Token::MutKeyword => true,
lexer::Token::ImportKeyword => true,
lexer::Token::ReturnKeyword => true,
lexer::Token::FnKeyword => true,
lexer::Token::PubKeyword => true,
lexer::Token::Arrow => true,
lexer::Token::If => true,
lexer::Token::Else => true,
lexer::Token::True => true,
lexer::Token::False => true,
lexer::Token::Extern => true,
lexer::Token::Struct => true,
lexer::Token::Equals => true,
_ => false,
}
}
fn needs_space(&self) -> bool {
match self {
lexer::Token::LetKeyword => true,
lexer::Token::MutKeyword => true,
lexer::Token::ImportKeyword => true,
lexer::Token::ReturnKeyword => true,
lexer::Token::FnKeyword => true,
lexer::Token::PubKeyword => true,
lexer::Token::Arrow => true,
lexer::Token::Equals => true,
_ => false,
}
}
fn is_newline(&self) -> bool {
match self {
lexer::Token::Semi => true,
lexer::Token::BraceOpen => true,
lexer::Token::BraceClose => true,
_ => false,
}
}
}
fn color_err(elem: impl std::fmt::Display) -> Result<String, std::fmt::Error> { fn color_err(elem: impl std::fmt::Display) -> Result<String, std::fmt::Error> {
let mut text = format!("{}", elem); let mut text = format!("{}", elem);
@ -359,7 +336,7 @@ fn color_warn(elem: impl std::fmt::Display) -> Result<String, std::fmt::Error> {
Ok(text) Ok(text)
} }
fn color_underline(elem: impl std::fmt::Display) -> Result<String, std::fmt::Error> { fn color_highlight(elem: impl std::fmt::Display) -> Result<String, std::fmt::Error> {
let mut text = format!("{}", elem); let mut text = format!("{}", elem);
#[cfg(feature = "color")] #[cfg(feature = "color")]

View File

@ -167,7 +167,7 @@ impl Debug for FullToken {
} }
/// (Column, Line) /// (Column, Line)
#[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, PartialOrd, Ord)] #[derive(Clone, Copy, Debug, Hash, PartialEq, Eq, Ord)]
pub struct Position(pub u32, pub u32); pub struct Position(pub u32, pub u32);
impl Position { impl Position {
@ -180,13 +180,23 @@ impl Position {
} }
} }
struct Cursor<'a> { impl PartialOrd for Position {
fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
match self.1.partial_cmp(&other.1) {
Some(core::cmp::Ordering::Equal) => {}
ord => return ord,
}
self.0.partial_cmp(&other.0)
}
}
pub struct Cursor<'a> {
pub position: Position, pub position: Position,
char_stream: Chars<'a>, pub char_stream: Chars<'a>,
} }
impl<'a> Cursor<'a> { impl<'a> Cursor<'a> {
fn next(&mut self) -> Option<char> { pub fn next(&mut self) -> Option<char> {
let next = self.char_stream.next(); let next = self.char_stream.next();
if let Some('\n') = next { if let Some('\n') = next {
self.position.1 += 1; self.position.1 += 1;

View File

@ -68,6 +68,7 @@ pub fn parse_module<'map, T: Into<String>>(
map: &'map mut ModuleMap, map: &'map mut ModuleMap,
) -> Result<(mir::SourceModuleId, Vec<FullToken>), ReidError> { ) -> Result<(mir::SourceModuleId, Vec<FullToken>), ReidError> {
let id = map.add_module(name.into()).unwrap(); let id = map.add_module(name.into()).unwrap();
map.set_source(id, source.to_owned());
let tokens = ReidError::from_lexer(lexer::tokenize(source), map.clone(), id)?; let tokens = ReidError::from_lexer(lexer::tokenize(source), map.clone(), id)?;
@ -137,8 +138,6 @@ pub fn perform_all_passes<'map>(
let refs = TypeRefs::default(); let refs = TypeRefs::default();
let mut errors = Vec::new();
let state = context.pass(&mut TypeInference { refs: &refs }); let state = context.pass(&mut TypeInference { refs: &refs });
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
@ -148,13 +147,16 @@ pub fn perform_all_passes<'map>(
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
dbg!(&state); dbg!(&state);
errors.extend( if !state.errors.is_empty() {
return Err(ReidError::from_kind::<()>(
state state
.errors .errors
.iter() .iter()
.map(|e| ErrorRapKind::TypeInferenceError(e.clone())) .map(|e| ErrorRapKind::TypeInferenceError(e.clone()))
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
); module_map.clone(),
));
}
let state = context.pass(&mut TypeCheck { refs: &refs }); let state = context.pass(&mut TypeCheck { refs: &refs });
@ -163,16 +165,15 @@ pub fn perform_all_passes<'map>(
#[cfg(debug_assertions)] #[cfg(debug_assertions)]
dbg!(&state); dbg!(&state);
errors.extend( if !state.errors.is_empty() {
return Err(ReidError::from_kind::<()>(
state state
.errors .errors
.iter() .iter()
.map(|e| ErrorRapKind::TypeInferenceError(e.clone())) .map(|e| ErrorRapKind::TypeCheckError(e.clone()))
.collect::<Vec<_>>(), .collect::<Vec<_>>(),
); module_map.clone(),
));
if !errors.is_empty() {
return Err(ReidError::from_kind::<()>(errors, module_map.clone()));
} }
Ok(()) Ok(())