///|
/// Everything moonyaml reads, in one file.
///
///     moon run src/examples/tour
#coverage.skip
fn main {
  run() catch {
    e => println("refused: \{e}")
  }
}

///|
fn run() -> Unit raise {
  // A configuration file, of the shape one is actually written in: block
  // collections, a literal scalar that keeps its line breaks, and an anchor
  // reused further down.
  let config =
    #|server:
    #|  host: 0.0.0.0
    #|  port: 12000
    #|  motd: |
    #|    welcome
    #|    to the party
    #|limits: &shared {files: 1000, bytes: 1048576}
    #|upload: *shared
    #|tags: [http, native]
    #|
  let tree = @moonyaml.loads(config)
  println("read as JSON:")
  println("  \{tree.stringify()}")
  println("written back:")
  for line in @moonyaml.dumps(tree).split("\n") {
    if line.length() > 0 {
      println("  \{line}")
    }
  }

  // The core schema decides what an unquoted scalar is; quoting it makes it a
  // string whatever it looks like.
  let scalars =
    #|[1, 1.5, 0x1f, true, ~, yes, "1"]
    #|
  println("resolution:")
  println("  \{@moonyaml.loads(scalars).stringify()}")

  // A stream is several documents, and each is read in its own right.
  let stream =
    #|---
    #|first: 1
    #|---
    #|second: 2
    #|...
    #|
  let docs = @moonyaml.loads_all(stream)
  println("stream of \{docs.length()} documents:")
  for d in docs {
    println("  \{d.stringify()}")
  }

  // Ambiguity is refused with a position rather than guessed at.
  show_refusal("a: [1, 2")
  show_refusal("a: *nope")
  show_refusal("a: 1\na: 2", flavor=@moonyaml.Flavor::new(duplicates=Reject))

  // A tag from a vocabulary this reader does not have is not a fault: §10.4 says
  // the node resolves as if it carried no tag, and refusing it would refuse the
  // `!!python/object` in a file somebody else wrote.
  println("  a: !!nope 1 => \{@moonyaml.loads("a: !!nope 1").stringify()}")

  // And an alias that expands past its budget is refused too, which is what
  // stops a dozen lines from becoming billions of nodes.
  show_refusal(
    "a: &a [x, x]\nb: &b [*a, *a]\nc: &c [*b, *b]\nd: [*c, *c]\n",
    flavor=@moonyaml.Flavor::new(budget=8),
  )
}

///|
/// Read a document that will not load, and print why.
fn show_refusal(
  src : String,
  flavor~ : @moonyaml.Flavor = @moonyaml.strict,
) -> Unit {
  let one_line = src.replace_all(old="\n", new=" ⏎ ")
  let said = @moonyaml.loads(src, flavor~).stringify() catch {
    e => e.to_string()
  }
  println("  \{one_line} => \{said}")
}