///|
/// The `shrubbery` command.
///
/// Two audiences, and the split is deliberate. `check` and `fmt` are for a
/// person; `tokens`, `parse`, `source`, `print` and `doc` are the other half of
/// the differential harness, and their output formats are shared with
/// `tools/oracle/` rather than chosen for looks. Changing one of those changes
/// what the suite compares.
fn main {
  let args = @env.args()
  if args.length() < 2 {
    usage()
    @sys.exit(2)
  }
  let rest = args[2:].to_owned()
  let code = match args[1] {
    "check" => cmd_check(rest)
    "fmt" => cmd_fmt(rest)
    "tokens" => cmd_tokens(rest)
    "parse" => cmd_parse(rest)
    "source" => cmd_source(rest)
    "print" => cmd_print(rest)
    "doc" => cmd_doc(rest)
    "help" | "--help" | "-h" => {
      usage()
      0
    }
    other => {
      println("shrubbery: unknown command '\{other}'")
      usage()
      2
    }
  }
  if code != 0 {
    @sys.exit(code)
  }
}

///|
fn usage() -> Unit {
  println("usage: shrubbery  [options] FILE...")
  println("")
  println("  check    parse and report any problem, with the source shown")
  println("             --error-format human|short|json   (default: human)")
  println("             --color always|never|auto         (default: auto)")
  println("  fmt      re-format, ignoring how the source was written")
  println("             --style flat|pretty|armoured|multiline")
  println("             --width N        (pretty styles; omit to never break)")
  println("             --write          rewrite the file in place")
  println("")
  println("  The rest drive the differential suite, and their output formats")
  println("  are shared with tools/oracle/:")
  println("")
  println("  tokens   the token stream, one per line")
  println("  parse    the parse tree in canonical form, or `!error `")
  println("  source   the source rebuilt from the tree's metadata")
  println("  print    every layout mode, one per line")
  println("  doc      the layout document, to compare with the reference's")
}

///|
/// Read a file, or report why not.
fn read(path : String) -> String? {
  Some(@fs.read_file_to_string(path)) catch {
    _ => {
      println("shrubbery: cannot read \{path}")
      None
    }
  }
}