///|
/// Stable structured error model. Context strings never include raw input.
pub struct SdpError {
  stage : String
  kind : String
  line : Int
  column : Int
  context : String
  message : String
}

///|
pub fn sdp_error(
  stage : String,
  kind : String,
  line : Int,
  column : Int,
  context : String,
  message : String,
) -> SdpError {
  { stage, kind, line, column, context, message }
}

///|
pub fn SdpError::stage(self : SdpError) -> String {
  self.stage
}

///|
pub fn SdpError::kind(self : SdpError) -> String {
  self.kind
}

///|
pub fn SdpError::line(self : SdpError) -> Int {
  self.line
}

///|
pub fn SdpError::column(self : SdpError) -> Int {
  self.column
}

///|
pub fn SdpError::context(self : SdpError) -> String {
  self.context
}

///|
pub fn SdpError::message(self : SdpError) -> String {
  self.message
}

///|
pub fn SdpError::to_display(self : SdpError) -> String {
  "\{self.stage}/\{self.kind} at \{self.line}:\{self.column} [\{self.context}]: \{self.message}"
}

///|
/// A parser result bundles the document with non-fatal compatibility notices.
pub struct ParseReport {
  document : SessionDescription
  warnings : Array[SdpError]
}

///|
pub fn parse_report(
  document : SessionDescription,
  warnings : Array[SdpError],
) -> ParseReport {
  { document, warnings }
}

///|
pub fn ParseReport::document(self : ParseReport) -> SessionDescription {
  self.document
}

///|
pub fn ParseReport::warnings(self : ParseReport) -> Array[SdpError] {
  self.warnings
}

///|
pub fn ParseReport::warning_count(self : ParseReport) -> Int {
  self.warnings.length()
}