///|
/// A logical source position. Lines and columns are one-based; columns count
/// Unicode scalar values rather than UTF-16 code units.
pub(all) struct SourceLocation {
  path : String
  line : Int
  column : Int
} derive(Debug, Eq)

///|
/// A half-open source range. `end_` is the first position after the range.
pub(all) struct SourceSpan {
  start : SourceLocation
  end_ : SourceLocation
} derive(Debug, Eq)

///|
/// A decoded directive argument together with its source range.
///
/// `Directive.arguments` remains available for callers that only need values;
/// use `argument_infos` when diagnostics must point at an individual argument.
/// This syntax model is not lossless: blank lines, standalone comments, and
/// section-header trivia are intentionally not retained.
pub(all) struct Argument {
  value : String
  span : SourceSpan
} derive(Debug, Eq)

///|
/// One SSH configuration directive. Keywords are canonical ASCII lowercase.
pub(all) struct Directive {
  keyword : String
  arguments : Array[String]
  argument_infos : Array[Argument]
  location : SourceLocation
  span : SourceSpan
  raw : String?
} derive(Debug, Eq)

///|
/// A `Host` section. `patterns` and directives have already been decoded, but
/// their meaning is deliberately left to the pattern and resolver packages.
pub(all) struct HostBlock {
  patterns : Array[String]
  directives : Array[Directive]
  location : SourceLocation
  span : SourceSpan
} derive(Debug, Eq)

///|
/// A `Match` section. Conditions are retained verbatim (after lexical
/// decoding) so a later evaluator can support new OpenSSH predicates without
/// changing the parser.
pub(all) struct MatchBlock {
  conditions : Array[String]
  directives : Array[Directive]
  location : SourceLocation
  span : SourceSpan
} derive(Debug, Eq)

///|
/// An input-order configuration item.
///
/// `Global` is a normalized leading item. `Include` remains an ordinary
/// directive in the item where it was written; the loader expands it in place.
pub(all) enum ConfigItem {
  Global(Array[Directive])
  Host(HostBlock)
  Match(MatchBlock)
} derive(Debug, Eq)

///|
/// Parsed OpenSSH client configuration.
///
/// `items` is the authoritative, ordered syntax model. `blocks` is a
/// backwards-compatible projection containing a synthetic `Host *` block for
/// global directives followed by each `Host` block; it intentionally excludes
/// `Match` blocks.
pub(all) struct Config {
  items : Array[ConfigItem]
  blocks : Array[HostBlock]
} derive(Debug, Eq)

///|
/// A parser diagnostic returned by `parse_recovering`.
pub(all) struct Diagnostic {
  error : ParseError
  location : SourceLocation
  summary : String
} derive(Debug, Eq)

///|
/// The result of parsing in recovery mode. Invalid lines are omitted from the
/// syntax tree and represented by one diagnostic each.
pub(all) struct ParseResult {
  config : Config
  diagnostics : Array[Diagnostic]
} derive(Debug, Eq)

///|
/// A structured syntax error. Diagnostic messages intentionally describe only
/// syntax and never include a directive's potentially sensitive value.
pub(all) suberror ParseError {
  MissingArgument(location~ : SourceLocation, keyword~ : String)
  UnterminatedQuote(location~ : SourceLocation)
  DanglingEscape(location~ : SourceLocation)
  UnexpectedNul(location~ : SourceLocation)
  LineTooLong(location~ : SourceLocation, limit~ : Int)
  SourceTooLarge(location~ : SourceLocation, limit~ : Int)
  InvalidBlockHeader(location~ : SourceLocation, keyword~ : String)
  InvalidDirective(location~ : SourceLocation, message~ : String)
} derive(Debug, Eq)