compiler, cli: Support Nice Compilation Error Messages

Signed-off-by: Will Hawkins <hawkinsw@obs.cr>
This commit is contained in:
Will Hawkins
2026-05-22 02:37:33 -04:00
parent 5845cb75cc
commit e53c32f802
9 changed files with 115 additions and 4 deletions
+22
View File
@@ -39,7 +39,29 @@ public struct Error: Errorable, Equatable, CustomStringConvertible {
}
}
extension String {
public func trimmingPostfix(_ in_: String.Element) -> String {
return String(self.reversed().drop { $0 == in_ }.reversed())
}
}
public struct ErrorWithLocation: Errorable, Equatable, CustomStringConvertible {
public func format(_ formatter: any Formattable, _ sc: SourceCode) -> String {
guard let (fp, source, prior, after) = sc.getSourceSnippet(location: self.location, context: 5)
else {
return self.format(formatter)
}
let prior_snipped = prior.trimmingPrefix(["\n"])
let after_snipped = after.prefix { $0 != "\n" }
return formatter.formatWithStyle("Error: ", Style(StyleColor.Red))
+ "In \(fp), there was an error: \n..." + prior_snipped
+ formatter.formatWithStyle(source, Style(.none, [StyleFormat.Underline])) + after_snipped
+ "...\n"
+ self._msg
}
public func format(_ formatter: any Formattable) -> String {
let bold_red = Style(StyleColor.Red, [StyleFormat.Bold])
let formatted_location = formatter.formatWithStyle(self.location.description, bold_red)
+4
View File
@@ -72,6 +72,7 @@ public protocol ProgramExecutionEvaluator {
public protocol Errorable: CustomStringConvertible {
func format(_ formatter: Formattable) -> String
func format(_ formatter: Formattable, _ sc: SourceCode) -> String
func msg() -> String
func append(error: any Errorable) -> any Errorable
func eq(_ rhs: any Errorable) -> Bool
@@ -81,6 +82,9 @@ extension Errorable {
public func eq(_ rhs: any Errorable) -> Bool {
return self.msg() == rhs.msg()
}
public func format(_ formatter: Formattable, _ sc: SourceCode) -> String {
return self.format(formatter)
}
}
public protocol Formattable {
+27
View File
@@ -210,6 +210,33 @@ public struct SourceCode {
return self.code
}
public func getSourceSnippet(
location: SourceLocation, context: Int = 0
) -> (FilePath, String, String, String)? {
guard let path = self.pathForLocation(location.range.lowerBound) else {
return .none
}
let lower = String.UTF8View.Index(utf16Offset: location.range.lowerBound, in: self.code)
let upper = String.UTF8View.Index(utf16Offset: location.range.upperBound, in: self.code)
let prior_start =
if location.range.lowerBound - context >= 0 {
String.UTF8View.Index(utf16Offset: location.range.lowerBound - context, in: self.code)
} else {
String.UTF8View.Index(utf16Offset: location.range.lowerBound, in: self.code)
}
let after_end =
if location.range.upperBound + context < self.code.count {
String.UTF8View.Index(utf16Offset: location.range.upperBound + context, in: self.code)
} else {
String.UTF8View.Index(utf16Offset: location.range.upperBound, in: self.code)
}
let result = String(self.code.utf16[lower..<upper])!
let prior = String(self.code.utf16[prior_start..<lower])!
let after = String(self.code.utf16[upper...after_end])!
return (path, result, prior, after)
}
public func getLocations() -> FileSourceLocation {
return self.locations
}