-
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.
- Loading branch information
Showing
12 changed files
with
574 additions
and
349 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
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,161 @@ | ||
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, | ||
}, | ||
} | ||
} | ||
} | ||
|
||
#[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
enum Severity { | ||
Error, | ||
Warning, | ||
Note, | ||
Help, | ||
} | ||
|
||
#[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||
enum Label { | ||
Primary, | ||
Secondary, | ||
} | ||
|
||
impl Into<codespan_reporting::diagnostic::Severity> for Severity { | ||
fn into(self) -> codespan_reporting::diagnostic::Severity { | ||
match self { | ||
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> Into<codespan_reporting::diagnostic::Diagnostic<&'a str>> for Diagnostic<'a> { | ||
fn into(self) -> codespan_reporting::diagnostic::Diagnostic<&'a str> { | ||
codespan_reporting::diagnostic::Diagnostic::<&'a str>::new(self.severity.into()) | ||
.with_labels(self.errors.into_iter().map(|error| error.into()).collect()) | ||
} | ||
} | ||
|
||
impl<'a> Into<codespan_reporting::diagnostic::Label<&'a str>> for Error<'a> { | ||
fn into(self) -> codespan_reporting::diagnostic::Label<&'a str> { | ||
codespan_reporting::diagnostic::Label::new( | ||
self.label.into(), | ||
self.range.file_id, | ||
self.range.position..self.range.position + self.range.length, | ||
) | ||
.with_message(self.message) | ||
} | ||
} | ||
|
||
impl Into<codespan_reporting::diagnostic::LabelStyle> for Label { | ||
fn into(self) -> codespan_reporting::diagnostic::LabelStyle { | ||
match self { | ||
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,114 @@ | ||
use std::collections::HashMap; | ||
|
||
pub struct Files<'a> { | ||
pub files: HashMap<&'a str, &'a str>, | ||
} | ||
|
||
impl<'a> Files<'a> { | ||
pub fn new() -> Self { | ||
Self { | ||
files: HashMap::new(), | ||
} | ||
} | ||
|
||
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 | ||
.get(id) | ||
.ok_or(codespan_reporting::files::Error::FileMissing) | ||
.copied() | ||
} | ||
|
||
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> { | ||
let source = self.source(id)?; | ||
let mut line_index = 0; | ||
let mut byte_count = 0; | ||
|
||
for (index, character) in source.char_indices() { | ||
if index == byte_index { | ||
return Ok(line_index); | ||
} | ||
|
||
if character == '\n' { | ||
line_index += 1; | ||
} | ||
|
||
byte_count = index; | ||
} | ||
|
||
if byte_index == byte_count { | ||
Ok(line_index) | ||
} else { | ||
Err(codespan_reporting::files::Error::IndexTooLarge { | ||
given: byte_index, | ||
max: byte_count, | ||
}) | ||
} | ||
} | ||
|
||
fn line_range( | ||
&'a self, | ||
id: Self::FileId, | ||
line_index: usize, | ||
) -> Result<std::ops::Range<usize>, codespan_reporting::files::Error> { | ||
let source = self.source(id)?; | ||
let mut start = 0; | ||
let mut end = 0; | ||
let mut current_line_index = 0; | ||
|
||
for (index, character) in source.char_indices() { | ||
if current_line_index == line_index { | ||
start = index; | ||
} | ||
|
||
if character == '\n' { | ||
if current_line_index == line_index { | ||
end = index; | ||
break; | ||
} | ||
|
||
current_line_index += 1; | ||
} | ||
} | ||
|
||
if current_line_index == line_index { | ||
Ok(start..end) | ||
} else { | ||
Err(codespan_reporting::files::Error::IndexTooLarge { | ||
given: line_index, | ||
max: current_line_index, | ||
}) | ||
} | ||
} | ||
} |
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
Oops, something went wrong.