///|
fn list_edit(
  text : TclValue,
  indices : Array[String],
  replacement : TclValue,
  depth : Int,
) -> TclValue raise TclError {
  if depth > 64 {
    raise Invalid("nested list limit")
  }
  if indices.is_empty() {
    return replacement
  }
  let values = text.as_list()
  let index = list_index(indices[0], values.length())
  if index < 0 || index > values.length() {
    raise Invalid("list index out of range")
  }
  if index == values.length() {
    values.push(text_value(""))
  }
  values[index] = list_edit(
    values[index],
    indices[1:].to_owned(),
    replacement,
    depth + 1,
  )
  list_value(values)
}

///|
fn Interpreter::extended_list_command(
  self : Interpreter,
  input : Array[TclValue],
  depth : Int,
) -> TclValue raise TclError {
  let args = input.map(v => v.text)
  let n = args.length()
  match args[0] {
    "lset" => {
      if n < 3 {
        raise Invalid("lset arity")
      }
      let indices = if n == 4 {
        parse_list(args[2])
      } else {
        args[2:n - 1].to_owned()
      }
      let result = list_edit(self.read_value(args[1]), indices, input[n - 1], 0)
      self.set_value(args[1], result)
      return result
    }
    "linsert" => {
      if n < 3 {
        raise Invalid("linsert arity")
      }
      let values = input[1].as_list()
      let index = list_index(args[2], values.length() + 1)
        .max(0)
        .min(values.length())
      return list_value(
        values[:index].to_owned() +
        input[3:].to_owned() +
        values[index:].to_owned(),
      )
    }
    "lreplace" => {
      if n < 4 {
        raise Invalid("lreplace arity")
      }
      let values = input[1].as_list()
      let first = list_index(args[2], values.length())
        .max(0)
        .min(values.length())
      let last = list_index(args[3], values.length())
        .max(first - 1)
        .min(values.length() - 1)
      return list_value(
        values[:first].to_owned() +
        input[4:].to_owned() +
        values[last + 1:].to_owned(),
      )
    }
    "lsearch" => return self.lsearch_command(input)
    "lsort" => return self.lsort_command(input, depth)
    _ => raise Invalid("unsupported list command")
  }
}