Added line:col display to errors

This commit is contained in:
2023-08-18 22:53:38 +01:00
parent c9cb1b205f
commit ab0b57b1b8
4 changed files with 53 additions and 18 deletions

View File

@@ -237,6 +237,7 @@ impl ProjectError for GlobExport {
pub struct LexError { pub struct LexError {
pub errors: Vec<Simple<char>>, pub errors: Vec<Simple<char>>,
pub source: Rc<String>,
pub file: Rc<Vec<String>>, pub file: Rc<Vec<String>>,
} }
impl ProjectError for LexError { impl ProjectError for LexError {
@@ -246,7 +247,11 @@ impl ProjectError for LexError {
fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> { fn positions(&self, _i: &Interner) -> BoxedIter<ErrorPosition> {
let file = self.file.clone(); let file = self.file.clone();
Box::new(self.errors.iter().map(move |s| ErrorPosition { Box::new(self.errors.iter().map(move |s| ErrorPosition {
location: Location::Range { file: file.clone(), range: s.span() }, location: Location::Range {
file: file.clone(),
range: s.span(),
source: self.source.clone(),
},
message: Some(format!("{}", s)), message: Some(format!("{}", s)),
})) }))
} }

View File

@@ -1,3 +1,5 @@
use std::rc::Rc;
use chumsky::Parser; use chumsky::Parser;
use super::context::Context; use super::context::Context;
@@ -9,9 +11,11 @@ use crate::error::{ParseErrorWithTokens, ProjectError, ProjectResult};
use crate::representations::sourcefile::FileEntry; use crate::representations::sourcefile::FileEntry;
pub fn parse2(data: &str, ctx: impl Context) -> ProjectResult<Vec<FileEntry>> { pub fn parse2(data: &str, ctx: impl Context) -> ProjectResult<Vec<FileEntry>> {
let lexie = lexer(ctx.clone()); let source = Rc::new(data.to_string());
let tokens = (lexie.parse(data)) let lexie = lexer(ctx.clone(), source.clone());
.map_err(|errors| LexError { errors, file: ctx.file() }.rc())?; let tokens = (lexie.parse(data)).map_err(|errors| {
LexError { errors, file: ctx.file(), source: source.clone() }.rc()
})?;
if tokens.is_empty() { if tokens.is_empty() {
Ok(Vec::new()) Ok(Vec::new())
} else { } else {

View File

@@ -209,6 +209,7 @@ pub static BASE_OPS: &[&str] = &[",", ".", "..", "..."];
pub fn lexer<'a>( pub fn lexer<'a>(
ctx: impl Context + 'a, ctx: impl Context + 'a,
source: Rc<String>,
) -> impl SimpleParser<char, Vec<Entry>> + 'a { ) -> impl SimpleParser<char, Vec<Entry>> + 'a {
let all_ops = ctx let all_ops = ctx
.ops() .ops()
@@ -247,7 +248,11 @@ pub fn lexer<'a>(
)) ))
.map_with_span(move |lexeme, range| Entry { .map_with_span(move |lexeme, range| Entry {
lexeme, lexeme,
location: Location::Range { range, file: ctx.file() }, location: Location::Range {
range,
file: ctx.file(),
source: source.clone(),
},
}) })
.padded_by(one_of(" \t").repeated()) .padded_by(one_of(" \t").repeated())
.repeated() .repeated()

View File

@@ -18,6 +18,8 @@ pub enum Location {
file: Rc<Vec<String>>, file: Rc<Vec<String>>,
/// Index of the unicode code points associated with the code /// Index of the unicode code points associated with the code
range: Range<usize>, range: Range<usize>,
/// The full source code as received by the parser
source: Rc<String>,
}, },
} }
@@ -40,6 +42,15 @@ impl Location {
} }
} }
/// Associated source code, if known
pub fn source(&self) -> Option<Rc<String>> {
if let Self::Range { source, .. } = self {
Some(source.clone())
} else {
None
}
}
/// If the two locations are ranges in the same file, connect them. /// If the two locations are ranges in the same file, connect them.
/// Otherwise choose the more accurate, preferring lhs if equal. /// Otherwise choose the more accurate, preferring lhs if equal.
pub fn to(self, other: Self) -> Self { pub fn to(self, other: Self) -> Self {
@@ -49,13 +60,13 @@ impl Location {
Location::Range { .. } => other, Location::Range { .. } => other,
_ => Location::File(f), _ => Location::File(f),
}, },
Location::Range { file: f1, range: r1 } => Location::Range { Location::Range { file, range: r1, source } => {
range: match other { let range = match other {
Location::Range { file: f2, range: r2 } if f1 == f2 => Location::Range { file: f2, range: r2, .. } if file == f2 =>
r1.start..r2.end, r1.start..r2.end,
_ => r1, _ => r1,
}, };
file: f1, Location::Range { file, source, range }
}, },
} }
} }
@@ -65,7 +76,7 @@ impl Location {
pub fn or(self, alt: Self) -> Self { pub fn or(self, alt: Self) -> Self {
match (&self, &alt) { match (&self, &alt) {
(Self::Unknown, _) => alt, (Self::Unknown, _) => alt,
(Self::File(_), Self::Range { .. }) => alt, (Self::File { .. }, Self::Range { .. }) => alt,
_ => self, _ => self,
} }
} }
@@ -76,13 +87,23 @@ impl Display for Location {
match self { match self {
Self::Unknown => write!(f, "unknown"), Self::Unknown => write!(f, "unknown"),
Self::File(file) => write!(f, "{}.orc", file.iter().join("/")), Self::File(file) => write!(f, "{}.orc", file.iter().join("/")),
Self::Range { file, range } => write!( Self::Range { file, range, source } => {
f, let (sl, sc) = pos2lc(source, range.start);
"{}.orc:{}..{}", let (el, ec) = pos2lc(source, range.end);
file.iter().join("/"), write!(f, "{}.orc ", file.iter().join("/"))?;
range.start, write!(f, "{sl}:{sc}")?;
range.end if el == sl {
), if sc + 1 == ec { Ok(()) } else { write!(f, "..{ec}") }
} else {
write!(f, "..{el}:{ec}")
}
},
} }
} }
} }
fn pos2lc(s: &str, i: usize) -> (usize, usize) {
s.chars().take(i).fold((1, 1), |(line, col), char| {
if char == '\n' { (line + 1, 1) } else { (line, col + 1) }
})
}