///|
struct Handler {
  code : Int
  pattern : Array[String]?
  variables : Array[String]
  script : TclValue
} derive(Debug)

///|
fn Interpreter::try_command(
  self : Interpreter,
  input : Array[TclValue],
  depth : Int,
) -> TclValue raise TclError {
  let args = input.map(v => v.text)
  if args.length() < 2 {
    raise Invalid("try body required")
  }
  let handlers : Array[Handler] = []
  let mut finalizer : TclValue? = None
  let mut index = 2
  while index < args.length() {
    let kind = args[index]
    if kind == "finally" {
      if index != args.length() - 2 {
        raise Invalid("finally must be last with one script")
      }
      finalizer = Some(input[index + 1])
      break
    }
    if (kind != "on" && kind != "trap") || index + 3 >= args.length() {
      raise Invalid("invalid try handler")
    }
    let code = if kind == "on" { completion_code(args[index + 1]) } else { 1 }
    let pattern = if kind == "trap" {
      Some(parse_list(args[index + 1]))
    } else {
      None
    }
    let variables = parse_list(args[index + 2])
    handlers.push({ code, pattern, variables, script: input[index + 3], })
    index += 4
  }
  if handlers.last() is Some(handler) && handler.script.text == "-" {
    raise Invalid("last try handler has no script")
  }
  let original = self.capture_value(input[1], depth + 1)
  let mut result = original
  try {
    let mut selected = -1
    for i in 0.. true
        Some(pattern) => {
          let code = parse_list(
            option_get(original.options, "-errorcode").unwrap_or("NONE"),
          )
          let mut matched = pattern.length() <= code.length()
          if matched {
            for j in 0..= 0 {
      while handlers[selected].script.text == "-" {
        selected += 1
      }
      let handler = handlers[selected]
      if handler.variables.length() >= 1 && !handler.variables[0].is_empty() {
        self.set_value(handler.variables[0], original.value)
      }
      if handler.variables.length() >= 2 && !handler.variables[1].is_empty() {
        self.set_value(handler.variables[1], original.option_value())
      }
      result = self.capture_value(handler.script, depth + 1)
      if result.actual_code() == 1 {
        let options = result.options.copy()
        option_set_value(options, "-during", original.option_value())
        result = { ..result, options, }
      }
    }
  } catch {
    error => {
      result = outcome(error)
      if result.actual_code() == 1 {
        let options = result.options.copy()
        option_set_value(options, "-during", original.option_value())
        result = { ..result, options, }
      }
    }
  }
  if finalizer is Some(script) {
    let finished = self.capture_value(script, depth + 1)
    if finished.actual_code() != 0 {
      if finished.actual_code() == 1 {
        let options = finished.options.copy()
        option_set_value(options, "-during", result.option_value())
        result = { ..finished, options, }
      } else {
        result = finished
      }
    }
  }
  self.propagate_value(result)
}