///|
pub enum DiagnosticSeverity {
Note
Warning
Error
} derive(Debug, Eq)
///|
pub struct SourceLocation {
line : Int
column : Int
offset : Int
} derive(Debug, Eq)
///|
pub fn SourceLocation::new(
line : Int,
column : Int,
offset : Int,
) -> SourceLocation {
{ line, column, offset }
}
///|
pub struct Diagnostic {
severity : DiagnosticSeverity
path : String
message : String
location : SourceLocation?
} derive(Debug, Eq)
///|
pub struct DiagnosticBag {
items : Array[Diagnostic]
} derive(Debug, Eq)
///|
pub fn Diagnostic::note(path : String, message : String) -> Diagnostic {
{ severity: Note, path, message, location: None }
}
///|
pub fn Diagnostic::warning(
path : String,
message : String,
location : SourceLocation?,
) -> Diagnostic {
{ severity: Warning, path, message, location }
}
///|
pub fn Diagnostic::error(
path : String,
message : String,
location : SourceLocation?,
) -> Diagnostic {
{ severity: Error, path, message, location }
}
///|
pub fn DiagnosticSeverity::label(self : DiagnosticSeverity) -> String {
match self {
Note => "note"
Warning => "warning"
Error => "error"
}
}
///|
pub fn DiagnosticBag::empty() -> DiagnosticBag {
{ items: [] }
}
///|
pub fn DiagnosticBag::push(
self : DiagnosticBag,
diagnostic : Diagnostic,
) -> DiagnosticBag {
let items : Array[Diagnostic] = []
for item in self.items {
items.push(item)
}
items.push(diagnostic)
{ items, }
}
///|
pub fn DiagnosticBag::merge(
self : DiagnosticBag,
other : DiagnosticBag,
) -> DiagnosticBag {
let result = self
let mut merged = result
for item in other.items {
merged = merged.push(item)
}
merged
}
///|
pub fn DiagnosticBag::has_errors(self : DiagnosticBag) -> Bool {
self.items.any(fn(item) { item.severity == Error })
}
///|
pub fn DiagnosticBag::sorted(self : DiagnosticBag) -> DiagnosticBag {
let result : Array[Diagnostic] = []
for item in self.items {
let mut position = result.length()
for i, existing in result {
if compare_diagnostics(item, existing) < 0 {
position = i
break
}
}
result.push(item)
let last = result.length() - 1
let mut j = last
while j > position {
let previous = result[j - 1]
result[j] = previous
j -= 1
}
result[position] = item
}
{ items: result }
}
///|
pub fn DiagnosticBag::summary(self : DiagnosticBag) -> String {
let mut notes = 0
let mut warnings = 0
let mut errors = 0
for item in self.items {
match item.severity {
Note => notes += 1
Warning => warnings += 1
Error => errors += 1
}
}
"\{errors} errors, \{warnings} warnings, \{notes} notes"
}
///|
fn compare_diagnostics(left : Diagnostic, right : Diagnostic) -> Int {
match (left.location, right.location) {
(None, None) => compare_stable_names(left.path, right.path)
(None, Some(_)) => -1
(Some(_), None) => 1
(Some(a), Some(b)) =>
if a.line != b.line {
a.line - b.line
} else if a.column != b.column {
a.column - b.column
} else if a.offset != b.offset {
a.offset - b.offset
} else {
compare_stable_names(left.path, right.path)
}
}
}