///|
/// Phase that reported a diagnostic.
pub(all) enum DiagnosticPhase {
Scan
Parse
Resolve
Runtime
} derive(Eq, Debug)
///|
pub extend DiagnosticPhase with Eq::{equal, not_equal}
///|
pub extend DiagnosticPhase with Debug::{to_repr}
///|
/// Stable category for programmatic handling of failures.
pub(all) enum DiagnosticCode {
UnexpectedCharacter
UnterminatedString
UnterminatedComment
InvalidEscape
InvalidNumber
UnexpectedToken
ExpectedExpression
ExpectedToken
DuplicateVariable
DuplicateMethod
InvalidSuperclass
UndefinedVariable
UndefinedMethod
InvalidArity
InvalidOperand
InvalidIndex
IndexOutOfBounds
InvalidMapKey
ModuleNotFound
CircularImport
UndefinedExport
DivisionByZero
ExecutionLimit
CallStackLimit
ReturnOutsideFunction
BreakOutsideLoop
ContinueOutsideLoop
ForeignBindingMissing
ForeignClassBindingMissing
ForeignObjectAllocationFailed
ForeignCallFailed
InvalidFiberState
FiberAborted
DebugTerminated
UnsupportedFeature
} derive(Eq, Debug)
///|
pub extend DiagnosticCode with Eq::{equal, not_equal}
///|
pub extend DiagnosticCode with Debug::{to_repr}
///|
/// Structured interpreter diagnostic carrying an actionable source span.
pub(all) struct Diagnostic {
phase : DiagnosticPhase
code : DiagnosticCode
message : String
span : SourceSpan
source_name : String
frames : Array[CallFrame]
}
///|
/// One caller location retained while an error unwinds through the runtime.
pub(all) struct CallFrame {
callable : String
source_name : String
span : SourceSpan
} derive(Eq, Debug)
///|
pub extend CallFrame with Eq::{equal, not_equal}
///|
pub extend CallFrame with Debug::{to_repr}
///|
pub fn CallFrame::new(
callable : String,
source_name : String,
span : SourceSpan,
) -> CallFrame {
{ callable, source_name, span, }
}
///|
pub fn Diagnostic::new(
phase : DiagnosticPhase,
code : DiagnosticCode,
message : String,
span : SourceSpan,
) -> Diagnostic {
{ phase, code, message, span, source_name: "", frames: [], }
}
///|
pub fn Diagnostic::with_source(
self : Diagnostic,
source_name : String,
) -> Diagnostic {
{
phase: self.phase,
code: self.code,
message: self.message,
span: self.span,
source_name: if self.source_name == "" {
source_name
} else {
self.source_name
},
frames: self.frames,
}
}
///|
pub fn Diagnostic::with_frame(
self : Diagnostic,
frame : CallFrame,
) -> Diagnostic {
self.frames.push(frame)
self
}
///|
pub fn Diagnostic::render(self : Diagnostic, source_name : String) -> String {
let origin = if self.source_name == "" {
source_name
} else {
self.source_name
}
let mut rendered = "\{origin}:\{self.span.line()}:\{self.span.column()}: \{self.message}"
for frame in self.frames {
let frame_source = if frame.source_name == "" {
source_name
} else {
frame.source_name
}
rendered = rendered +
"\n at \{frame.callable} (\{frame_source}:\{frame.span.line()}:\{frame.span.column()})"
}
rendered
}