-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
♻️ (diagnostics): Refactor diagnostics
commit dd18997 Author: Lucas <[email protected]> Date: Sat Jun 15 14:31:12 2024 +0200 📝 Update readme semver: chore commit 5e4c2bc Author: Lucas <[email protected]> Date: Fri Jun 14 21:02:51 2024 +0200 🚨 (parser): Fix compiler warnings semver: chore commit 34c9146 Author: Lucas <[email protected]> Date: Fri Jun 14 21:01:18 2024 +0200 🚧 (diagnostics): Finish rewrite commit 4ad6e9e Author: Lucas <[email protected]> Date: Fri Jun 14 15:52:03 2024 +0200 🚧 (diagnostics): Start rewrite
- Loading branch information
Showing
13 changed files
with
703 additions
and
523 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,167 @@ | ||
use crate::scanner::lexeme::Lexeme; | ||
|
||
#[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
pub struct Diagnostic<'a> { | ||
pub severity: Severity, | ||
pub title: String, | ||
pub errors: Vec<Error<'a>>, | ||
} | ||
|
||
#[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
pub struct Error<'a> { | ||
pub message: String, | ||
pub label: Label, | ||
pub range: Range<'a>, | ||
} | ||
|
||
impl<'a> Error<'a> { | ||
pub fn primary( | ||
file_id: impl Into<&'a str>, | ||
position: usize, | ||
length: usize, | ||
message: impl Into<String>, | ||
) -> Error<'a> { | ||
Error::new(file_id, Label::Primary, position, length, message) | ||
} | ||
|
||
pub fn secondary( | ||
file_id: impl Into<&'a str>, | ||
position: usize, | ||
length: usize, | ||
message: impl Into<String>, | ||
) -> Error<'a> { | ||
Error::new(file_id, Label::Secondary, position, length, message) | ||
} | ||
|
||
pub fn new( | ||
file_id: impl Into<&'a str>, | ||
label: Label, | ||
position: usize, | ||
length: usize, | ||
message: impl Into<String>, | ||
) -> Error<'a> { | ||
Error { | ||
message: message.into(), | ||
label, | ||
range: Range { | ||
file_id: file_id.into(), | ||
position, | ||
length, | ||
}, | ||
} | ||
} | ||
|
||
pub(crate) fn transform_range(mut self, lexemes: &'a [Lexeme<'a>]) -> Error { | ||
self.range = self.range.to_source_code_range(lexemes); | ||
self | ||
} | ||
} | ||
|
||
#[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
pub enum Severity { | ||
Error, | ||
Warning, | ||
Note, | ||
Help, | ||
} | ||
|
||
#[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
pub enum Label { | ||
Primary, | ||
Secondary, | ||
} | ||
|
||
impl From<Severity> for codespan_reporting::diagnostic::Severity { | ||
fn from(val: Severity) -> Self { | ||
match val { | ||
Severity::Error => codespan_reporting::diagnostic::Severity::Error, | ||
Severity::Warning => codespan_reporting::diagnostic::Severity::Warning, | ||
Severity::Note => codespan_reporting::diagnostic::Severity::Note, | ||
Severity::Help => codespan_reporting::diagnostic::Severity::Help, | ||
} | ||
} | ||
} | ||
|
||
impl<'a> Diagnostic<'a> { | ||
pub fn error(message: impl Into<String>) -> Diagnostic<'a> { | ||
Diagnostic::new(Severity::Error, message) | ||
} | ||
|
||
pub fn warning(message: impl Into<String>) -> Diagnostic<'a> { | ||
Diagnostic::new(Severity::Warning, message) | ||
} | ||
|
||
pub fn new(severity: Severity, message: impl Into<String>) -> Diagnostic<'a> { | ||
Diagnostic { | ||
severity, | ||
title: message.into(), | ||
errors: vec![], | ||
} | ||
} | ||
|
||
pub fn with_error(mut self, error: Error<'a>) -> Self { | ||
self.errors.push(error); | ||
self | ||
} | ||
} | ||
|
||
impl<'a> From<Diagnostic<'a>> for codespan_reporting::diagnostic::Diagnostic<&'a str> { | ||
fn from(val: Diagnostic<'a>) -> Self { | ||
codespan_reporting::diagnostic::Diagnostic::<&'a str>::new(val.severity.into()) | ||
.with_message(val.title) | ||
.with_labels(val.errors.into_iter().map(|error| error.into()).collect()) | ||
} | ||
} | ||
|
||
impl<'a> From<Error<'a>> for codespan_reporting::diagnostic::Label<&'a str> { | ||
fn from(val: Error<'a>) -> Self { | ||
codespan_reporting::diagnostic::Label::new( | ||
val.label.into(), | ||
val.range.file_id, | ||
val.range.position..val.range.position + val.range.length, | ||
) | ||
.with_message(val.message) | ||
} | ||
} | ||
|
||
impl From<Label> for codespan_reporting::diagnostic::LabelStyle { | ||
fn from(val: Label) -> Self { | ||
match val { | ||
Label::Primary => codespan_reporting::diagnostic::LabelStyle::Primary, | ||
Label::Secondary => codespan_reporting::diagnostic::LabelStyle::Secondary, | ||
} | ||
} | ||
} | ||
|
||
#[derive(Debug, Clone, Hash, PartialEq, Eq)] | ||
pub struct Range<'a> { | ||
pub file_id: &'a str, | ||
pub position: usize, | ||
pub length: usize, | ||
} | ||
|
||
impl<'a> Range<'a> { | ||
pub fn to_source_code_range(self, lexemes: &[Lexeme]) -> Self { | ||
let start = if self.position >= lexemes.len() { | ||
let last_lexeme = lexemes[lexemes.len() - 1].range(); | ||
last_lexeme.position + 1 | ||
} else { | ||
let start_lexeme = lexemes[self.position].range(); | ||
start_lexeme.position | ||
}; | ||
|
||
let end = if self.position + self.length >= lexemes.len() { | ||
let last_lexeme = lexemes[lexemes.len() - 1].range(); | ||
last_lexeme.position + last_lexeme.length | ||
} else { | ||
let end_lexeme = lexemes[self.position + self.length].range(); | ||
end_lexeme.position + end_lexeme.length | ||
}; | ||
|
||
Range { | ||
file_id: self.file_id, | ||
position: start, | ||
length: end - start, | ||
} | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,84 @@ | ||
use std::collections::HashMap; | ||
|
||
#[derive(Default)] | ||
pub struct Files<'a> { | ||
pub files: HashMap<&'a str, &'a str>, | ||
} | ||
|
||
impl<'a> Files<'a> { | ||
pub fn insert(&mut self, file_id: impl Into<&'a str>, source: impl Into<&'a str>) { | ||
self.files.insert(file_id.into(), source.into()); | ||
} | ||
|
||
pub fn file_ids(&self) -> Vec<&'a str> { | ||
self.files.keys().copied().collect() | ||
} | ||
|
||
pub fn get(&self, file_id: impl Into<&'a str>) -> Option<&'a str> { | ||
self.files.get(file_id.into()).copied() | ||
} | ||
} | ||
|
||
impl<'a> codespan_reporting::files::Files<'a> for Files<'a> { | ||
type FileId = &'a str; | ||
type Name = &'a str; | ||
type Source = &'a str; | ||
|
||
fn name(&'a self, id: Self::FileId) -> Result<Self::Name, codespan_reporting::files::Error> { | ||
self.files | ||
.keys() | ||
.find(|key| **key == id) | ||
.copied() | ||
.ok_or(codespan_reporting::files::Error::FileMissing) | ||
} | ||
|
||
fn source( | ||
&'a self, | ||
id: Self::FileId, | ||
) -> Result<Self::Source, codespan_reporting::files::Error> { | ||
self.files | ||
.get(id) | ||
.ok_or(codespan_reporting::files::Error::FileMissing) | ||
.copied() | ||
} | ||
|
||
fn line_index( | ||
&'a self, | ||
id: Self::FileId, | ||
byte_index: usize, | ||
) -> Result<usize, codespan_reporting::files::Error> { | ||
self.get(id) | ||
.ok_or(codespan_reporting::files::Error::FileMissing) | ||
.map(|source| { | ||
source | ||
.char_indices() | ||
.take_while(|(index, _)| *index < byte_index) | ||
.filter(|(_, character)| *character == '\n') | ||
.count() | ||
}) | ||
} | ||
|
||
fn line_range( | ||
&'a self, | ||
id: Self::FileId, | ||
line_index: usize, | ||
) -> Result<std::ops::Range<usize>, codespan_reporting::files::Error> { | ||
self.get(id) | ||
.ok_or(codespan_reporting::files::Error::FileMissing) | ||
.map(|source| { | ||
let start = source | ||
.lines() | ||
.take(line_index) | ||
.map(|line| line.len() + 1) | ||
.sum::<usize>(); | ||
|
||
let end = source | ||
.lines() | ||
.take(line_index + 1) | ||
.map(|line| line.len() + 1) | ||
.sum::<usize>(); | ||
|
||
start..end | ||
}) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.