///|
fn exception_code(error : ForthError) -> Int {
  match error {
    Thrown(code) => code
    Invalid(message) =>
      if message.contains("stack underflow") {
        -4
      } else if message.contains("division") {
        -10
      } else if message.contains("unknown") {
        -13
      } else if message.contains("unaligned") {
        -23
      } else if message.contains("data space range") ||
        message.contains("execution token") {
        -9
      } else {
        -256
      }
  }
}

///|
pub fn ForthError::code(self : ForthError) -> Int {
  exception_code(self)
}

///|
fn Machine::catch_word(self : Machine, depth : Int) -> Unit raise ForthError {
  let xt = self.pop()
  if xt < 1 || xt > self.execution_tokens.length() {
    raise Invalid("invalid execution token")
  }
  let saved = self.stack.copy()
  let old_leaving = self.leaving
  self.catch_depth += 1
  defer {
    self.catch_depth -= 1
  }
  let result = try {
    self.execute_frame(self.execution_tokens[xt - 1], depth + 1, true)
    0
  } catch {
    error => exception_code(error)
  }
  if result != 0 {
    self.stack.clear()
    for value in saved {
      self.stack.push(value)
    }
    self.leaving = old_leaving
  }
  self.stack.push(result)
}