stuff
This commit is contained in:
+106
@@ -0,0 +1,106 @@
|
||||
#[derive(Debug, Clone, Copy)]
|
||||
pub struct Span {
|
||||
pub file: usize,
|
||||
pub start: usize,
|
||||
pub end: usize,
|
||||
}
|
||||
|
||||
pub struct Spanned<T> {
|
||||
pub inner: T,
|
||||
pub span: Span,
|
||||
}
|
||||
|
||||
impl<T> std::ops::Deref for Spanned<T> {
|
||||
type Target = T;
|
||||
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.inner
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> std::ops::DerefMut for Spanned<T> {
|
||||
fn deref_mut(&mut self) -> &mut Self::Target {
|
||||
&mut self.inner
|
||||
}
|
||||
}
|
||||
|
||||
pub struct CompilerMsg {
|
||||
pub spans: Vec<Span>,
|
||||
pub msg: String,
|
||||
}
|
||||
|
||||
#[derive(Default)]
|
||||
pub struct CompilerOutput {
|
||||
pub errors: Vec<CompilerMsg>,
|
||||
pub files: Vec<String>,
|
||||
}
|
||||
|
||||
impl CompilerOutput {
|
||||
pub fn new() -> Self {
|
||||
Self::default()
|
||||
}
|
||||
pub fn error(&mut self, msg: impl Into<CompilerMsg>) {
|
||||
self.errors.push(msg.into());
|
||||
}
|
||||
pub fn write(&self, w: &mut impl std::io::Write) {
|
||||
let files: Vec<_> = self
|
||||
.files
|
||||
.iter()
|
||||
.map(|path| std::fs::read_to_string(path).unwrap())
|
||||
.collect();
|
||||
for error in &self.errors {
|
||||
writeln!(w, "Error: {}", error.msg).unwrap();
|
||||
for span in &error.spans {
|
||||
span.write(w, &files[span.file]).unwrap();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl Span {
|
||||
pub fn write(&self, w: &mut impl std::io::Write, text: &str) -> std::io::Result<()> {
|
||||
let mut line_start = 0;
|
||||
let mut found = false;
|
||||
let mut line = 1;
|
||||
let mut spans = Vec::new();
|
||||
for (i, c) in text.char_indices() {
|
||||
if i == self.start {
|
||||
found = true;
|
||||
}
|
||||
if i == self.end {
|
||||
found = true;
|
||||
}
|
||||
if c == '\n' {
|
||||
if found {
|
||||
spans.push((line, line_start..i));
|
||||
}
|
||||
line_start = i + 1;
|
||||
line += 1;
|
||||
found = false;
|
||||
}
|
||||
}
|
||||
let start_chars = text[self.start..].lines().next().unwrap().len();
|
||||
let underline = "\x1b[4:3m";
|
||||
let underline_color = "\x1b[58;5;1m";
|
||||
let end = "\x1b[0m";
|
||||
if let [(line, range)] = &spans[..] {
|
||||
writeln!(
|
||||
w,
|
||||
" {line:3} | {}{underline}{underline_color}{}{end}{}",
|
||||
&text[range.start..self.start],
|
||||
&text[self.start..=self.end],
|
||||
&text[(self.end + 1)..range.end]
|
||||
)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl From<String> for CompilerMsg {
|
||||
fn from(value: String) -> Self {
|
||||
Self {
|
||||
spans: Vec::new(),
|
||||
msg: value.to_string(),
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user