forked from Orchid/orchid
Added line:col display to errors
This commit is contained in:
@@ -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)),
|
||||||
}))
|
}))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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 {
|
||||||
|
|||||||
@@ -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()
|
||||||
|
|||||||
@@ -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) }
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user