diff --git a/Cargo.lock b/Cargo.lock index 98d2095..553344e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4,18 +4,21 @@ version = 4 [[package]] name = "aho-corasick" -version = "1.0.2" +version = "1.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "43f6cb1bf222025340178f382c426f13757b2960e89779dfcb319c32542a5a41" +checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916" dependencies = [ "memchr", ] [[package]] name = "cc" -version = "1.0.79" +version = "1.2.29" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50d30906286121d95be3d479533b458f87493b30a4b5f79a607db8f5d11aa91f" +checksum = "5c1599538de2394445747c8cf7935946e3cc27e9625f889d979bfb2aaf569362" +dependencies = [ + "shlex", +] [[package]] name = "colored" @@ -28,21 +31,21 @@ dependencies = [ [[package]] name = "lazy_static" -version = "1.4.0" +version = "1.5.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +checksum = "bbd2bcb4c963f2ddae06a2efc7e9f3591312473c50c6685e1f298068316e66fe" [[package]] name = "libc" -version = "0.2.147" +version = "0.2.174" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b4668fb0ea861c1df094127ac5f1da3409a82116a4ba74fca2e58ef927159bb3" +checksum = "1171693293099992e19cddea4e8b849964e9846f4acee11b3948bcc337be8776" [[package]] name = "llvm-sys" -version = "160.1.3" +version = "160.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0bf51981ac0622b10fe4790763e3de1f3d68a0ee4222e03accaaab6731bd508d" +checksum = "e73861901245d32e1c3d8b35b639cf100859b4cd0c9da56fe0273040acbb3ea4" dependencies = [ "cc", "lazy_static", @@ -53,33 +56,33 @@ dependencies = [ [[package]] name = "memchr" -version = "2.5.0" +version = "2.7.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2dffe52ecf27772e601905b7522cb4ef790d2cc203488bbd0e2fe85fcb74566d" +checksum = "32a282da65faaf38286cf3be983213fcf1d2e2a58700e808f83f4ea9a4804bc0" [[package]] name = "proc-macro2" -version = "1.0.66" +version = "1.0.95" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "18fb31db3f9bddb2ea821cde30a9f70117e3f119938b5ee630b7403aa6e2ead9" +checksum = "02b3e5e68a3a1a02aad3ec490a98007cbc13c37cbe84a3cd7b8e406d76e7f778" dependencies = [ "unicode-ident", ] [[package]] name = "quote" -version = "1.0.32" +version = "1.0.40" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "50f3b39ccfb720540debaa0164757101c08ecb8d326b15358ce76a62c7e85965" +checksum = "1885c039570dc00dcb4ff087a89e185fd56bae234ddc7f056a945bf36467248d" dependencies = [ "proc-macro2", ] [[package]] name = "regex" -version = "1.9.1" +version = "1.11.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b2eae68fc220f7cf2532e4494aded17545fce192d59cd996e0fe7887f4ceb575" +checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191" dependencies = [ "aho-corasick", "memchr", @@ -89,9 +92,9 @@ dependencies = [ [[package]] name = "regex-automata" -version = "0.3.4" +version = "0.4.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b7b6d6190b7594385f61bd3911cd1be99dfddcfc365a4160cc2ab5bff4aed294" +checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908" dependencies = [ "aho-corasick", "memchr", @@ -100,9 +103,9 @@ dependencies = [ [[package]] name = "regex-syntax" -version = "0.7.4" +version = "0.8.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e5ea92a5b6195c6ef2a0295ea818b312502c6fc94dde986c5553242e18fd4ce2" +checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c" [[package]] name = "reid" @@ -124,15 +127,21 @@ dependencies = [ [[package]] name = "semver" -version = "1.0.18" +version = "1.0.26" 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]] name = "syn" -version = "2.0.28" +version = "2.0.104" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "04361975b3f5e348b2189d8dc55bc942f278b2d482a6a0365de5bdd62d351567" +checksum = "17b6f705963418cdb9927482fa304bc562ece2fdd4f616084c50b7023b435a40" dependencies = [ "proc-macro2", "quote", @@ -141,18 +150,18 @@ dependencies = [ [[package]] name = "thiserror" -version = "1.0.44" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "611040a08a0439f8248d1990b111c95baa9c704c805fa1f62104b39655fd7f90" +checksum = "b6aaf5339b578ea85b50e080feb250a3e8ae8cfcdff9a461c9ec2904bc923f52" dependencies = [ "thiserror-impl", ] [[package]] name = "thiserror-impl" -version = "1.0.44" +version = "1.0.69" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "090198534930841fab3a5d1bb637cde49e339654e606195f8d9c76eeb081dc96" +checksum = "4fee6c4efc90059e10f81e6d42c60a18f76588c3d74cb83a0b242a2b6c7504c1" dependencies = [ "proc-macro2", "quote", @@ -161,9 +170,9 @@ dependencies = [ [[package]] name = "unicode-ident" -version = "1.0.11" +version = "1.0.18" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "301abaae475aa91687eb82514b328ab47a211a533026cb25fc3e519b86adfc3c" +checksum = "5a5f39404a5da50712a4c1eecf25e90dd62b613502b7e925fd4e4d19b5c96512" [[package]] name = "windows-sys" diff --git a/reid/src/error_raporting.rs b/reid/src/error_raporting.rs index 29f7b8a..7556d34 100644 --- a/reid/src/error_raporting.rs +++ b/reid/src/error_raporting.rs @@ -5,7 +5,7 @@ use std::{ use crate::{ ast, - lexer::{self, FullToken, Position}, + lexer::{self, Cursor, FullToken, Position}, mir::{self, pass, Metadata, SourceModuleId}, token_stream::{self, TokenRange}, }; @@ -79,6 +79,7 @@ impl Ord for ErrorKind { pub struct ErrModule { pub name: String, pub tokens: Option>, + pub source: Option, } #[derive(Debug, Clone, PartialEq, Eq, Default)] @@ -95,6 +96,7 @@ impl ModuleMap { ErrModule { name: name.into(), tokens: None, + source: None, }, ); 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> { 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 (position_fmt, line_fmt) = if let Some(tokens) = &module.tokens { let range_tokens = meta.range.into_tokens(&tokens); - let position = get_position(&range_tokens).unwrap(); - let full_lines = get_full_lines(&tokens, position); + let highlight_position = get_position(&range_tokens).unwrap(); + let full_lines = get_full_lines(&tokens, highlight_position); + let lines_position = get_position(&full_lines).unwrap(); ( - fmt_positions(get_position(&full_lines).unwrap()), - Some(fmt_tokens(&full_lines, &range_tokens)), + fmt_positions(highlight_position), + Some(fmt_lines( + module.source.as_ref().unwrap(), + lines_position, + highlight_position, + 8, + )?), ) } else if let Some(position) = meta.position { (fmt_positions((position, position)), None) @@ -209,9 +223,9 @@ impl std::fmt::Display for ReidError { writeln!(f)?; write!(f, " 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 { - writeln!(f, "{:>20}{}", color_warn("")?, line_fmt)?; + writeln!(f, "{}", line_fmt)?; } } Ok(()) @@ -255,26 +269,37 @@ fn get_full_lines<'v>( .collect::>() } -fn fmt_tokens(tokens: &Vec<&FullToken>, highlighted: &Vec<&FullToken>) -> String { - 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(); +fn fmt_lines( + source: &String, + (line_start, line_end): (Position, Position), + (highlight_start, highlight_end): (Position, Position), + ident: usize, +) -> Result { + let mut cursor = Cursor { + position: Position(0, 1), + char_stream: source.chars(), + }; - let mut token_fmt = format!("{}", token.token.to_string()); - if highlighted.contains(token) { - token_fmt = color_underline(token_fmt).unwrap(); + let mut text = String::new(); + + while let Some(c) = cursor.next() { + if cursor.position.1 > line_end.1 { + break; } - text += &token_fmt; - if token.token.is_newline() && i > (tokens.len() - 1) { - text += "\n" + 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 + Ok(text) } 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 { let mut text = format!("{}", elem); @@ -359,7 +336,7 @@ fn color_warn(elem: impl std::fmt::Display) -> Result { Ok(text) } -fn color_underline(elem: impl std::fmt::Display) -> Result { +fn color_highlight(elem: impl std::fmt::Display) -> Result { let mut text = format!("{}", elem); #[cfg(feature = "color")] diff --git a/reid/src/lexer.rs b/reid/src/lexer.rs index 22ba78a..220ae28 100644 --- a/reid/src/lexer.rs +++ b/reid/src/lexer.rs @@ -167,7 +167,7 @@ impl Debug for FullToken { } /// (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); impl Position { @@ -180,13 +180,23 @@ impl Position { } } -struct Cursor<'a> { +impl PartialOrd for Position { + fn partial_cmp(&self, other: &Self) -> Option { + 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, - char_stream: Chars<'a>, + pub char_stream: Chars<'a>, } impl<'a> Cursor<'a> { - fn next(&mut self) -> Option { + pub fn next(&mut self) -> Option { let next = self.char_stream.next(); if let Some('\n') = next { self.position.1 += 1; diff --git a/reid/src/lib.rs b/reid/src/lib.rs index 018f845..bc16550 100644 --- a/reid/src/lib.rs +++ b/reid/src/lib.rs @@ -68,6 +68,7 @@ pub fn parse_module<'map, T: Into>( map: &'map mut ModuleMap, ) -> Result<(mir::SourceModuleId, Vec), ReidError> { 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)?; @@ -137,8 +138,6 @@ pub fn perform_all_passes<'map>( let refs = TypeRefs::default(); - let mut errors = Vec::new(); - let state = context.pass(&mut TypeInference { refs: &refs }); #[cfg(debug_assertions)] @@ -148,13 +147,16 @@ pub fn perform_all_passes<'map>( #[cfg(debug_assertions)] dbg!(&state); - errors.extend( - state - .errors - .iter() - .map(|e| ErrorRapKind::TypeInferenceError(e.clone())) - .collect::>(), - ); + if !state.errors.is_empty() { + return Err(ReidError::from_kind::<()>( + state + .errors + .iter() + .map(|e| ErrorRapKind::TypeInferenceError(e.clone())) + .collect::>(), + module_map.clone(), + )); + } let state = context.pass(&mut TypeCheck { refs: &refs }); @@ -163,16 +165,15 @@ pub fn perform_all_passes<'map>( #[cfg(debug_assertions)] dbg!(&state); - errors.extend( - state - .errors - .iter() - .map(|e| ErrorRapKind::TypeInferenceError(e.clone())) - .collect::>(), - ); - - if !errors.is_empty() { - return Err(ReidError::from_kind::<()>(errors, module_map.clone())); + if !state.errors.is_empty() { + return Err(ReidError::from_kind::<()>( + state + .errors + .iter() + .map(|e| ErrorRapKind::TypeCheckError(e.clone())) + .collect::>(), + module_map.clone(), + )); } Ok(())