// Portions adapted from google/go-jsonnet v0.21.0 (Apache-2.0).
// https://github.com/google/go-jsonnet/tree/67968688d9952f50662e979fab1bef889d0d3e57
// Source: ast/location.go
// Source: ast/ast.go
// Copyright 2017 Google Inc. All rights reserved.
// Copyright 2016 Google Inc. All rights reserved.
// Modifications: Adapted source-location contracts to MoonBit UTF-8 ranges and local AST metadata.
// License and retained attribution: LICENSE and NOTICE at the module root.

///|
/// Half-open source range. Lines and UTF-8 byte columns are one-based.
pub(all) struct SourceRange {
  begin : Location
  end : Location
} derive(Debug, Eq)

///|
pub extend SourceRange with @debug.Debug::{to_repr}

///|
pub extend SourceRange with Eq::{equal, not_equal}

///|
/// Return retained source coordinates, or None for a synthetic/unlocated node.
///
/// ```mbt check
/// test {
///   let node = @moonjsonnet.Program::parse("'δΈ­'", filename="example").ast()
///   assert_eq(node.source_range().unwrap().format(), "example:1:1-6")
/// }
/// ```
pub fn Ast::source_range(self : Ast) -> SourceRange? {
  self.end.map(end => { begin: self.loc, end, })
}

///|
/// Render the same-file range using Go's location-range notation.
pub fn SourceRange::format(self : SourceRange) -> String {
  let a = self.begin
  let b = self.end
  let prefix = if a.file.is_empty() { "" } else { a.file + ":" }
  if a.line == b.line {
    if a.column == b.column {
      "\{prefix}\{a.line}:\{a.column}"
    } else {
      "\{prefix}\{a.line}:\{a.column}-\{b.column}"
    }
  } else {
    "\{prefix}(\{a.line}:\{a.column})-(\{b.line}:\{b.column})"
  }
}